binario único

Artículo

La importancia del binario único. Parte II

Aunque existe consenso en la comunidad de desarrolladores, existe bibliografía muy popular que lo menciona, y las tecnologías más innovadoras del momento nos ofrecen mecanismos para explotarlo, es posible que el enfoque del binario único no se haya difundido con la suficiente contundencia. ¿Cómo se implementa el concepto del binario único?

En la primera parte de este artículo mencioné las 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 (normalmente desarrollo, pre-producción y producción). En esta segunda parte profundizaremos en el enfoque del binario único y veremos algunos ejemplos de cómo se implementa.

Aunque existe consenso en la comunidad de desarrolladores, existe bibliografía muy popular que lo menciona, y las tecnologías más innovadoras del momento nos ofrecen mecanismos para explotarlo, es posible que el enfoque del binario único no se haya difundido con la suficiente contundencia.

¿Cómo se implementa el concepto del binario único? Existen soluciones generales, pero la solución óptima en cada caso podría depender de la tecnología que estemos utilizando en nuestro proyecto. En general, el concepto del binario único está implícito en la contraposición de las siguientes estrategias de diseño, quizás más conocidas:

  • Configuración interna VS configuración externa.
  • Configuración en tiempo de compilación/empaquetado VS configuración en tiempo de ejecución.

Ambas estrategias son las dos caras de una misma moneda, y están directamente relacionadas con conceptos tan importantes (y muchas veces olvidados) como la portabilidad y la separación de conceptos (SOC - Separation Of Concerns). El concepto del binario único satisface perfectamente ambos:

  • El binario único es portable por definición; se trata del mismo binario, desplegado en los diferentes entornos.
  • El binario único, lleva al extremo la separación de conceptos; los parámetros de configuración susceptibles de cambiar entre entornos, están separados del código binario (son recursos independientes).

No es casual que varios de los frameworks más populares y plataformas de despliegue en la actualidad contemplen este escenario, y propongan soluciones nativas que nos permitan generar binarios más portables y genéricos. Pongo algunos ejemplos:

  • En Spring Boot (Pivotal), uno de los frameworks más populares en la industria del Software Libre, existe desde hace años el concepto de “configuración externalizada” (https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html), cuyo propósito es definir/redefinir parámetros de configuración durante el arranque de la aplicación.
  • En Kubernetes (Google), la plataforma de orquestación de contenedores por excelencia, existe el concepto de ConfigMap, cuyo único propósito es “inyectar” configuración en tiempo de ejecución a los contenedores que se ejecutan en la plataforma, promoviendo así la implementación de “Imágenes genéricas y portables” (https://cloud.google.com/kubernetes-engine/docs/concepts/configmap).
  • En Docker (Docker), la tecnología de contenedores más popular, existe el concepto de Docker Configs cuando se utiliza en la modalidad Swarm. Su propósito es el mismo que los ConfigMaps en Kubernetes: permitir a los desarrolladores el despliegue de imágenes Docker portables, genéricas, sin necesidad de que éstas contengan en su interior ficheros o variables con configuración dependiente del entorno (https://docs.docker.com/engine/swarm/configs/).
  • En Amazon AWS, probablemente el servicio de Cloud más avanzado del momento, existe un producto denominado “AWS Systems Manager Parameter Store” cuyo propósito es proporcionar a los sistemas de información un repositorio centralizado de almacenamiento para datos de configuración, permitiendo así la separación de los mismos del código.

Así pues, el problema de la externalización de la configuración podemos reducirlo a la siguiente pregunta: “¿cómo conseguimos que nuestras aplicaciones obtengan la configuración dependiente del entorno en el que se ejecutan, en tiempo de ejecución?”

binario único

Binario Único Img1

Veamos cómo podría implementarse el escenario de la figura anterior en algunas de las tecnologías más populares:

- En .NET Framework se proporcionan de manera nativa las clases ConfigurationManager y WebConfigurationManager que facilitan al desarrollador la carga de parámetros de configuración dependientes del entorno en tiempo de ejecución.

- En Java, si utilizamos Spring Boot, tendríamos de manera nativa, y sin tener en cuenta ningún detalle de implementación adicional, un mecanismo de carga de configuración externalizada, tal y como se comentó en párrafos anteriores. En el caso de una aplicación JEE tradicional, una opción válida podría ser proporcionar los parámetros de configuración dependientes del entorno utilizando variables de entorno del SO (esta opción, de hecho, es la recomendada si nuestras aplicaciones corren dentro de contenedores Docker).

- En tecnologías de front-end web, como por ejemplo Angular, el problema se reduce a cargar la configuración desde un fichero externo, en tiempo de carga del Javascript transpilado en el navegador del usuario. Uno de los mejores enfoques, pasa por la utilización de la función APP_INITIALIZER, tal y como se explica en el siguiente artículo: https://davembush.github.io/where-to-store-angular-configurations/.

Binario Único Img2

En definitiva, si diseñamos nuestras soluciones para que tengan la capacidad de "consultar" los detalles de configuración dependientes del entorno, en tiempo de despliegue/arranque/ejecución (y no en tiempo de compilación/empaquetado), tendremos mejores soluciones, más genéricas, más portables, más adaptadas a los nuevos tiempos… Porque como todos sabemos, las estrategias y patrones de diseño son independientes del lenguaje de programación o tecnología que los implementen, ya sean de front-end o de back-end.

Al comienzo de la primera parte del artículo, mencionaba que el enfoque del binario único debería adoptarse como un estándar de referencia para nuestros procesos de entrega y despliegue continuo, pero aún más para aquellos proyectos con tecnologías “legacy” en los que no existen procesos automatizados de construcción, testeo y despliegue. Creo que el esfuerzo merece la pena, y nosotros, como profesionales, debemos perseguir siempre (en la medida de lo posible) la solución más óptima, más excelente.

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).