GitHub Actions está matando lentamente a los equipos de ingeniería
(iankduncan.com)- Aunque se usa ampliamente por ser un CI incluido por defecto en el repo, su ineficiencia estructural y experiencia de usuario inestable reducen la productividad de los desarrolladores
- La carga lenta del visor de logs y los fallos del navegador, junto con la sintaxis compleja de YAML y los errores de expresiones, provocan depuración repetitiva
- Debido a una arquitectura donde no se posee el recurso de cómputo, muestra límites en rendimiento, escalabilidad y control del entorno
- Al intentar esquivar muchos de estos problemas, se repite la situación de volver a construir el propio CI con YAML complejo o enormes scripts de Bash
- En comparación, Buildkite ofrece una alternativa de CI sostenible a largo plazo gracias a una estructura YAML simple, agentes autohospedables y una experiencia de logs práctica
Problemas de GitHub Actions
- El visor de logs de GitHub Actions es ineficiente: incluso para revisar un error simple hacen falta varios clics y cargas de página
- Cuando falla un build, hay que pasar por la página de resumen de checks → página de ejecución del workflow → página del job → clic en el step plegado, lo que requiere 3 o 4 cambios de página y una carga separada en cada paso
- Hace fallar repetidamente el navegador con logs de builds grandes, y al usar la búsqueda el congelamiento de Chrome es reproducible
- En logs largos, ni siquiera funciona el scroll, así que al final hay que descargar el artefacto del log crudo y abrirlo en un editor de texto
- El botón de volver no lleva a la página original del PR, sino a una página impredecible de la UI de GitHub Actions, y el historial del navegador termina lleno de URLs de Actions
- Improductividad en el proceso de depuración
- Para revisar variables de entorno, agregar un step
run: envy volver a hacer push genera un ciclo de feedback de 20 minutos, y ese proceso acaba repitiéndose más de diez veces por un cambio de una sola línea - La repetición de ciclos de feedback de 20 minutos consume la jornada entera esperando al CI
- Para revisar variables de entorno, agregar un step
- Limitaciones estructurales de YAML
- El YAML de GitHub Actions es una forma especial que combina su propio lenguaje de expresiones, modelo de objetos de contexto y reglas de interpolación de cadenas
- Si usas mal una sola comilla en una expresión
${{ }}, solo descubres que la cadena se rompió después de esperar 4 minutos a que arranque el runner - La sintaxis de expresiones existe en un espacio liminal: demasiado compleja para usarse como configuración y demasiado limitada para usarse como lenguaje de programación formal
- Es una estructura que te obliga a aprender la sintaxis a través de fallas, no de la documentación
- Riesgos de seguridad del Marketplace
- Al cargar acciones externas con la sintaxis
uses:, se otorgan a terceros no verificados permisos de acceso al repositorio, secretos y entorno de build - Se puede fijar por SHA, pero casi nadie lo hace, y aun fijándolo el modelo sigue ejecutando código opaco que no has leído con acceso a
GITHUB_TOKEN - El Marketplace mezcla acciones mantenidas por la comunidad con calidades muy distintas, y la mayoría está compuesta por scripts de shell y Dockerfile
- La gestión de dependencias es opaca y existe la posibilidad de ejecutar código inseguro
- Al cargar acciones externas con la sintaxis
- Restricciones del entorno de cómputo
- Los runners por defecto de GitHub Actions son runners compartidos propiedad de Microsoft, lentos, con recursos limitados y sin posibilidad de personalización significativa
- El costo de runners más grandes llega al punto de provocar una solicitud de reunión de “tenemos que hablar” por parte de finanzas, y aun así no se obtiene control del entorno
- Existen al menos seis startups, como Namespace, Blacksmith, Actuated, Runs-on y BuildJet, especializadas solo en resolver la lentitud de los runners de GitHub Actions, lo que por sí mismo demuestra las carencias del entorno de cómputo base
- Configurar un self-hosted runner resuelve el problema del cómputo, pero deja intactos los demás: expresiones YAML, modelo de permisos, Marketplace, visor de logs, etc.
Problemas detallados pero acumulativos
actions/cache: las claves de caché son confusas, los fallos de caché ocurren silenciosamente y la expulsión de caché es opaca, por lo que se termina gastando más tiempo depurando el caché que el que se ahorra con él- Workflows reutilizables: no pueden anidarse más allá de cierta profundidad, no permiten acceder limpiamente al contexto del workflow llamador y no pueden probarse de forma aislada
- Modelo de permisos de
GITHUB_TOKEN:permissions: write-alles demasiado amplio, y los permisos granulares forman un laberinto por la interacción entre configuraciones a nivel de repositorio, workflow y job - Control de concurrencia (
concurrency): cancelar ejecuciones en curso sobre la misma rama puede hacerse con una línea, pero no hay soporte para un control más fino que eso - Imposibilidad de usar secretos en condiciones
if: no se puede hacer ejecución condicional con algo comoif: secrets.DEPLOY_KEY != ''; aunque es razonable por seguridad, obliga a buscar soluciones alternativas al escribir workflows que funcionen tanto en forks como en el repositorio principal
La trampa de “mejor usemos scripts de Bash”
- Para ingenieros cansados del YAML del CI existe la tentación de reemplazar todo con scripts de Bash en
run:, pero con el tiempo se agregan condicionales, funciones, parsing de argumentos y procesamiento en paralelo - Tres meses después, tienes 800 líneas de bash reimplementando la paralelización de jobs con
waity archivos PID, junto con lógica propia de reintentos y parsing de salida - Al final no escapaste del sistema de CI, sino que construiste tú mismo en Bash un sistema de CI peor, sin framework de pruebas y que nadie puede seguir
- Bash funciona bien como pegamento, pero usarlo como sistema de build o test harness solo mueve la complejidad de un lugar con barandales a otro que no los tiene
El enfoque alternativo de Buildkite
-
Visor de logs estable
- El visor de logs de Buildkite muestra los logs correctamente sin hacer fallar el navegador, y renderiza tal cual los colores ANSI y el formato de los frameworks de pruebas
- Con la función Annotation, un step de build puede imprimir directamente en la página del build en Markdown un resumen de fallas de pruebas, reportes de cobertura, enlaces de despliegue, etc.
- Como los agentes se ejecutan en infraestructura propia, es posible conectarse por SSH a la máquina del build para depurar directamente
-
Estructura YAML simple
- El YAML de Buildkite es una estructura de datos pura que describe el pipeline, y solo declara steps, comandos y plugins
- Si hace falta lógica real, se escriben scripts en un lenguaje de programación real que pueda ejecutarse localmente
- Mantiene con claridad el límite de “la orquestación en la configuración, la lógica en el código”, justo el límite que GitHub Actions difumina
-
Control total del entorno de cómputo
- Los agentes de Buildkite pueden ejecutarse como un único binario en tu propia nube, on-premise o hardware personalizado
- Se puede controlar por completo el tipo de instancia, caché, almacenamiento local y red, desde grandes instancias de EC2 con discos NVMe y caché de capas Docker de 20 GB hasta una Raspberry Pi
- No existe una industria de terceros de “Buildkite, pero más rápido”; simplemente pones a correr una máquina más grande
- Para un maintainer individual que mantiene una pequeña librería open source, el nivel gratuito de repos públicos de GitHub Actions sigue teniendo valor
- El público principal de este texto son equipos que operan sistemas de producción, donde el tiempo del CI se mide como pérdida semanal de horas de ingeniería y un build de 45 minutos genera costos tanto de cómputo como de mano de obra
- En ese entorno, el overhead de operar agentes de Buildkite recupera su costo rápidamente
-
Soporte para pipelines dinámicos
- En Buildkite, los steps del pipeline son datos, y un script puede generar dinámicamente (emit) steps adicionales en tiempo de ejecución y subirlos
- En un monorepo, esto permite generar exactamente los steps de build y pruebas necesarios según los archivos modificados, sin matrices hardcodeadas ni espagueti de
if: contains(...) matrix, las condicionesify los workflows reutilizables de GitHub Actions intentan aproximar esto, pero terminan convirtiéndote en constructor de una máquina de Rube Goldberg con un lenguaje declarativo de poca expresividad
-
Simplicidad de la estructura de plugins
- Estructuralmente, es similar al Marketplace de GitHub Actions en el sentido de traer código desde repositorios de terceros
- La diferencia es que los plugins de Buildkite suelen ser thin shell hooks, no imágenes Docker, así que la superficie es pequeña y se pueden leer completos en pocos minutos
- Como se ejecutan en infraestructura propia, el usuario puede controlar el blast radius
-
Funciones pequeñas centradas en la experiencia de usuario
- Buildkite permite mostrar emojis personalizados (
:parrot:,:docker:, etc.) junto a los steps del pipeline; puede parecer menor, pero demuestra una atención cuidadosa a la experiencia de uso del producto - GitHub Actions parece un producto diseñado por comité que nunca se preguntó “¿esto es agradable de usar?”
- Buildkite permite mostrar emojis personalizados (
Conclusión: criterios para elegir un sistema de CI
- GitHub Actions dominó el mercado por la ventaja de venir incluido por defecto, con repos públicos gratis, integración en una plataforma que ya todos usan y un nivel de “suficientemente bueno”
- Es como el Internet Explorer del CI, y se sigue usando porque el costo de cambiar es real y el tiempo es finito
- Buildkite es superior en usabilidad sostenida y experiencia de desarrollador
- Para proyectos open source simples, GitHub Actions basta, pero en entornos de producción a gran escala, Buildkite encaja mejor
- En la historia de los sistemas de CI, quien gana cuota de mercado no es el mejor sistema, sino el sistema con el que es más fácil empezar
- GitHub Actions es el CI más fácil para arrancar y Buildkite es el CI más conveniente para seguir usando; a largo plazo, eso último importa más
- Si la herramienta de CI está estructurada para consumir el tiempo del desarrollador, el problema no es el desarrollador, sino la propia herramienta
3 comentarios
Parece que el problema es que el CI en sí se está volviendo demasiado complejo.
Parece que subieron el mismo texto dos veces. Pero últimamente da la impresión de que es una combinación bastante buena para que la arme la IA..
Comentarios en Hacker News
He usado varios sistemas de CI. He usado mucho CircleCI y GitHub Actions, pero llego a una conclusión distinta a la del autor
Antes Jenkins era para Java y Travis para Rails, pero ese tipo de CI especializada al final era un callejón sin salida. Ahora el CI evolucionó a ser simplemente un orquestador de flujos de trabajo
También me cambié de CircleCI 2 a GitHub Actions porque CircleCI no hizo bien esa transición. GHA tenía suficiente capacidad expresiva
El navegador de logs o la sintaxis de YAML son problemas menores. Lo importante es la propiedad de los recursos de cómputo y los pipelines dinámicos; lo primero es posible en cualquier CI y lo segundo es la ventaja de Buildkite
Mi conclusión es que Actions en la práctica está bastante bien, y si empezara una empresa nueva usaría Buildkite; para open source usaría Actions
Si no entiendes el grafo de build, tienes que mantener el estado de los builds incrementales, y eso provoca bugs intermitentes. Por eso se necesitan sistemas como UnrealEngine Horde o UBA, que entienden a fondo la estructura del build
Si usas un CI generalizado, un build puede tardar más de un día
Yo suelo usar solo las partes buenas de GHA. Por ejemplo, GitHub es excelente como despachador de eventos, pero no tanto como orquestador de workflows, así que esa parte la delego a otro sistema
Si los logs que ves decenas de veces al día son incómodos, la productividad cae. Leer logs crudos ignorando códigos de escape es realmente doloroso
Yo mantengo todo simple. Pongo toda la orquestación en un script deploy.sh y lo ejecuto en una Mac local o en AWS CodeBuild
El YAML es solo una línea:
bash deploy.sh. Mientras haya un contenedor Docker, funciona igual en Azure, GitHub Actions o donde seaLa estrategia clave en cualquier entorno de CI es tener un sistema de build igual al local
Yo siempre empiezo con un Makefile. Docker, builds de CI, linting, todo lo dispara el Makefile. Cuando el proyecto crece, a veces paso a otras herramientas, pero la base es una sola herramienta disparadora
En móvil uso mucho Fastlane, porque reduce boilerplate y aporta estructura. Al final es Ruby, así que si hace falta también puedes salirte
(Enlace a la documentación de GNU Make)
En el fondo es como decir “mejor usa un script de Bash”, pero con complejidad innecesaria añadida
Incluso en mi empresa actual, como ya no podemos correr todo el pipeline localmente, terminamos con una infraestructura de CI gigantesca donde para probar un solo MR se lanzan builds diez veces
Sentí que este artículo era como publicidad de Nix/Buildkite
El CI debería limitarse a ejecutar scripts o targets de build. El CI solo tendría que aportar el entorno y la configuración; la lógica debe estar en el código
Así obtienes independencia del CI y es más fácil moverse entre sistemas
GitLab CI maneja relativamente bien esa complejidad. Sus plantillas y funciones de composición de jobs son excelentes, pero depurar es difícil y la lógica condicional a veces falla de maneras inesperadas
.shlo hicieron muy fácilmenteEn cambio, los equipos que habían fragmentado todo en la UI sí sufrieron
El problema no es el CI/CD en sí, sino la cultura de programar en archivos de configuración
El bucle de
git commit -m "try fix"y esperar 10 minutos es demasiado común. Sigue faltando un entorno de CI reproducible en localSi estableces el aislamiento de entornos como política, da igual qué herramienta uses. Al final, la clave es la armonía entre herramientas y metodología
actayudan muchísimo a reproducir el CI en localEl título de que “está matando a los equipos de ingeniería” es exagerado. GitHub Actions está bastante bien
Lo prefiero sobre Bitbucket o GitLab
Últimamente la confiabilidad de GitHub ha caído mucho
actions/checkoutfalla sin motivo, los jobs de release se ejecutan dos veces, o a veces se quedan esperando 40 minutosLo he usado por años, pero la estabilidad básica está empeorando. Me arrepiento de no haber elegido Buildkite
GitHub Actions es una de las peores herramientas de CI que he usado (al nivel de Jenkins)
En cambio, Buildkite es de lo mejor. Gracias a los pipelines dinámicos, puedes generar automáticamente pasos de reintento cuando falla una prueba, o ajustar las pruebas en paralelo según los cambios en el código
Otra gran ventaja es poder usar una configuración de máquina distinta para cada job de CI. Lo recomiendo mucho
La gente que defiende un CI simple basado en scripts probablemente no tiene experiencia con proyectos reales a gran escala