Importancia Binario único

Artículo

Las claves de la importancia del BINARIO ÚNICO. Parte I

Han pasado ya más de 10 años desde que leí por primera vez acerca de las bondades del enfoque del binario único. Pero, ¿de qué se trata y qué nos aporta este enfoque?

Después de una década participando en discusiones técnicas acerca del binario único, son muchos los profesionales del sector, que desconocen, o bien no comparten (e incluso critican) los beneficios del mismo. Pero, ¿en qué consiste y en qué contribuye este enfoque?

Steve Freeman, coautor de "Growing Object Oriented Software, Guided by Tests (Addison-Wesley)", y experto en Agile Software Development, lo describió muy bien en el capítulo titulado "One Binary" que escribió como colaborador en el libro "97 Things Every Programmer Should Know":

The rule is simple: Build a single binary that you can identify and promote through all the stages in the release pipeline. Hold environment-specific details in the environment.

O lo que es lo mismo: sólo debería existir un único binario (entendiendo por binario, el código compilado/transpilado) por cada versión liberada (de cada módulo software de nuestro proyecto) en nuestros ciclos de desarrollo (por cada incremento, en terminología Scrum), y es este binario el que debería promocionar entre los diferentes entornos de despliegue existentes (normalmente desarrollo, pre-producción y producción). Los detalles de configuración, dependientes del entorno, deberían permanecer, e incluso estar ubicados y custodiados de forma segura, en los entornos correspondientes.

Esta idea tan sencilla y eficaz, motivo de controversia en algún que otro foro en el que he participado recientemente, debería adoptarse, en mi opinión, como un estándar de referencia para nuestros procesos de entrega y despliegue continuo (DevOps). Es más, debería considerarse como un patrón de diseño/despliegue.

Antes de analizar los beneficios del enfoque propuesto, enumeraré brevemente algunas razones por las que no soy partidario de empaquetar, por cada versión liberada de nuestros módulos software, una versión para cada entorno. Para ello, supongamos un proyecto en el que se está desarrollando un servicio REST con operaciones de consulta de datos, con tecnología JEE, utilizando metodología Scrum. Estos podrían ser, por ejemplo, los productos obtenidos al finalizar el séptimo Sprint:

Importancia Binario único

One Binary - Cuadro - Parte 1

A continuación, enumero algunos de los aspectos negativos de este enfoque:

  1. Incumple el tercer punto de la metodología "The twelve-factor app", relativo a configuraciones (https://12factor.net/es/config).
  2. Añade riesgos de inconsistencia entre entornos, normalmente acentuados cuando los despliegues los realiza un equipo distinto al equipo de desarrollo (en más de una ocasión he sido testigo de los problemas que supone desplegar el binario equivocado en el entorno de producción).
  3. Cualquier cambio de configuración que desee realizarse en cualquiera de los entornos, implica que debemos reconstruir y redesplegar nuestra aplicación (porque a nadie se le ocurriría desempaquetar a mano, modificar, y re-empaquetar en el entorno de producción… ¿verdad?).
  4. Si se dispone de un repositorio de artefactos para almacenar no sólo las dependencias, sino también las releases de nuestros módulos (Artifactory o Nexus, por poner dos ejemplos concretos), observaríamos que estamos almacenando 3 binarios "casi idénticos" por cada release (en el ejemplo, 150 MB por cada release).

En mis años de experiencia profesional, he escuchado algunas contra-argumentaciones a los aspectos negativos anteriormente mencionados. Podría resumirlas en las siguientes:

  1. "¿The twelve-factor qué?" Eso no aplica a mi proyecto…
  2. "No existe tal riesgo", o "tengo un proceso de integración continua que reduce a cero el riesgo".
  3. "Se tarda 1 minuto en recompilar y redesplegar".
  4. "Mis releases ocupan 3 MB; es una exageración sugerir que estamos desaprovechando capacidad de almacenamiento siendo redundantes".

Esta última frase se la escuché a un profesional especializado en tecnologías de front-end refiriéndose, en este caso, a las releases de una aplicación desarrollada en Angular. En mi opinión, no se trata de minimizar el espacio ocupado en disco en nuestro repositorio de artefactos para cada nueva versión de nuestros módulos software (aunque, personalmente, he trabajado con clientes a los que no les gustaba la idea de que cada release supusiera 150 MB de espacio en su repositorio de artefactos), ni del tiempo que se tarda en reconstruirlos y redesplegarlos cuando se nos solicita un cambio en la configuración en un entorno determinado (por no mencionar que construir un Pipeline de Entrega Continua con 3 procesos de construcción/empaquetado, uno por entorno, es una violación directa del principio DRY – "Don’t repeat yourself"), ni de señalar con el dedo a los miembros del equipo responsable de los diferentes entornos (en el caso de organizaciones que no disponen de procesos de entrega continua automatizados) presuponiendo que se equivocarán en algún momento al realizar los despliegues (porque todos nos equivocamos, sin excepción), ni de estar a la última en metodologías de desarrollo, simplemente porque sí.

Si nuestro ciclo de entrega es susceptible de sufrir inconsistencias entre los diferentes entornos a causa del factor humano, o necesitamos recompilar y redesplegar nuestros módulos para cambiar un parámetro de configuración en un entorno concreto, o estamos generando varias versiones "casi idénticas" de nuestros módulos software, en los que sólo varía el 0,01% del binario correspondiente a parámetros de configuración dependientes del entorno en el que se despliegue, significa que nuestra solución no es óptima; sencillamente no es la mejor solución.

Esta afirmación, aunque polémica para algunos, no sólo está basada en mi experiencia personal, ni en numerosas conversaciones con excelentes desarrolladores, arquitectos software y administradores de sistemas de diferentes empresas del sector. Está fundamentada en la experiencia y en el consenso colectivo de los más importantes Ingenieros de Software, recogidos en el fantástico libro "Continuous Delivery. Reliable Software Releases through Build, Test, and Deployment Automation (Addison-Wesley)" de Jez Humble y Dave Farley, y recomendado por, probablemente, el Ingeniero de Software más influyente de los últimos 20 años, Martin Fowler.

Todos sabemos que, en el mundo del software, existen infinidad de casos de uso, diferentes requisitos funcionales y no funcionales, diferentes arquitecturas, diferentes clientes, diferentes tecnologías… Una combinación infinita de aspectos que podrían llevar a pensar que "no todo es blanco o negro" en la cuestión que se plantea en este artículo. Sin embargo, difícilmente se me ocurren argumentos de peso en contra del principio del binario único, aun cuando hablemos de desarrollo de software a medida para clientes específicos.

En la segunda parte de este artículo profundizaremos en los beneficios de la adopción del enfoque del binario único en nuestros desarrollos (no sólo para desarrollos en los que se hayan implementado procesos DevOps), qué estrategias existen a nivel de diseño para implementarlo (ya sea en módulos de frontend o de backend) y cómo algunas de las tecnologías más innovadoras del momento (Docker, Kubernetes) nos invitan a la construcción de binarios únicos y portables a través de mecanismos de inyección de configuración en tiempo de ejecución.

Ernesto Salgado
Jefe de Proyecto de Consultoría en DXD

En estos años de carrera profesional, Ernesto ha trabajado en diferentes áreas, aunque principalmente en el sector público y con tecnologías web de código abierto (Java). Ha colaborado en diferentes proyectos con diferentes roles: programador, analista funcional, arquitecto y consultor. Actualmente, las tecnologías que despiertan mayor interés en Ernesto son las relacionadas con la integración (Oracle OSB, WSO2 y Red Hat Fuse), desarrollo de aplicaciones móviles (Android), contenedores (Docker), Container Orchestrators (Kubernetes, OpenShift), Cloud (Amazon AWS y Google Cloud Platform) y entrega continua (Jenkins).