Ingeniería de software

Cadena de herramientas o «Tool Chain»

La cadena de herramientas es el conjunto de herramientas que se utilizan a lo largo del ciclo de vida para promocionar por los entornos intermedios, validar, aprobar e instalar en Producción una aplicación.

Dentro de lo que es la cadena de herramientas, habitualmente existen los siguientes servicios:

Control y gestión de las entregas

El principal objetivo es que todos los equipos involucrados en la instalación colaboren, es decir, puedan responder rápidamente, estén orientados a la acción y tomen decisiones basándose en información precisa y actualizada, de forma que se reduzca la espera, se comparta el conocimiento y se reduzcan las emergencias de última hora.

Es posible alcanzar este objetivo ya que los equipos que planifican conjuntamente tienen un mejor entendimiento de las dependencias y pueden identificar cuellos de botella antes que aparezcan, y pueden priorizar adecuadamente antes los conflictos que puedan surgir.

Repositorio de fuentes repo fuentes

El repositorio de fuentes permite almacenar en una misma ubicación todos los elementos que se utilizarán durante la construcción, siendo éste el único punto desde el que los motores de construcción recuperaran las fuentes para construir.

Además, los repositorios de fuentes y las técnicas adecuadas de desarrollo en paralelo permiten acelerar el desarrollo de múltiples cambios simultáneos en las aplicaciones.

Repositorio de ejecutables

El repositorio de ejecutabRepositorioles es la piedra angular de la implantación ya que será de éste de donde se recuperará todos los artefactos que se deben de instalar.

Estos artefactos pueden ser entregados por los equipos de Desarrollo o por los motores de construcción, y serán recuperados de éste por el motor de automatización de implantación.

Integración continua CI

La integración continua es la encargada de recuperar del repositorio de fuentes los elementos necesarios para generar de forma controlada y automatizada los artefactos, que almacenará en el repositorio de ejecutables, y serán instalados posteriormente en los entornos de ejecución.

Motor de despliegue

El motor de despliegue es el deployque se encarga de recuperar los artefactos del repositorio de ejecutables y de su distribución a las máquinas donde son necesarios para que una aplicación pueda utilizarse.

El motor de despliegue debe ofrecer aumentar la frecuencia de implantación garantizando la consistencia de las implantaciones. Dicho de otra manera, la instalación de una aplicación tiene que ser aburrida, ya que debiera de realizarse frecuente, ser predecible ya que se instala cada vez de la misma manera y fiable.

El motor de instalación además de los mecanismos de instalación debe ofrecer mecanismos de trazabilidad, registros de auditoría y la capacidad de escalar conforme las necesidades de la organización crecen.

Controles de Calidad (QA)

Los equipos de calidad teóricamente debieran colaborar con los equipos de desarrollo para escribir los casos de pruebas automáticos desde el comienzo del desarrollo. Estos casos de prueba deberán demostrar que la aplicación implementa la funcionalidad solicitada qapor Negocio.

Los casos de prueba deben ejecutarse cada vez que se realiza una modificación en el código, tanto de cara a validar que cada nueva versión implementa las nuevas funcionalidades como para asegurar está libre de regresiones, es decir, que las funcionalidades existentes siguen funcionando de igual forma.

Por lo que dentro de la cadena de herramientas deben de existir puntos donde se realizarán estas validaciones, estos puntos pueden estarán definidos a lo largo del ciclo de vida por lo que pueden estar presentes en la fase de desarrollo, en tiempo de promoción en entornos intermedios, como antes de la puesta en Producción.

Monitorización

La monitorización consiste en la vigilancia de todos los servicios activos que una máquina ofrece, por lo que es vital dentro de la cadena de herramientas puesto que cada vez que se despliegue una nueva versión de la aplicación se debe supervisar la información generada por la monitorización de cara a identificar posibles problemas antes de que se despliegue en Producción.

De esta forma aseguramos que la nueva versión de la aplicación no genera problemas en las infraestructuras existentes y evita posibles impactos en Producción. Ya que su objetivo principal es detectar posibles interferencias y dar lugar a medidas correctivas antes de llegar a Producción.

Vista de conjunto de la “cadena de herramientas”

Como se ha comentado anteriormente la cadena de herramientas está formada por una serie de herramientas que utilizadas en su conjunto proporcionan consistencia, eficiencia, seguridad y visibilidad.

Consistencia:

  • Todos los procedimientos son comunes para todos los entornos.
  • Todas las tareas necesarias para implantar están identificadas en un único lugar.
  • Se utilizan procedimientos de construcción homogéneos y controlados.
  • Se utiliza las mismas herramientas de implantación para todos los entornos.
  • Se utiliza las mismas herramientas de infraestructura para todos los entornos.

Eficiencia:

  • Reducción de las tareas manuales.
  • Reducción de tareas redundantes y por lo tanto innecesarias.
  • La información estará siempre accesible.
  • Reducción de la dependencia del conocimiento de una persona.

Seguridad:

  • Minimización del ratio de error manual
  • Mismo despliegue en todos los entornos

Visibilidad:

  • Inventario de los artefactos que forman las aplicaciones.
  • Instalación controlada y gestionada
  • Simplicidad en las auditorias

Integración continua (CI), Entrega continua (CD) y Despliegue Continuo (CD)

Uno de los objetivos de DEVOPS es reducir los tiempos de cada ciclo de desarrollo, es decir, reducir el tiempo necesario para que cada uno de los requisitos solicitados por los usuarios finales llegue a sus manos.

Para que esto pueda ocurrir tiene que pasar por todas las etapas del ciclo de vida de la aplicación, es decir, debe realizar el análisis y diseño de la solución, se debe codificar y probar de forma aislada, se tiene que integrar con el resto de modificaciones, se tiene que implantar en los distintos entornos para que se realicen las pruebas oportunas hasta que finalmente es validado y liberado a Producción.

Para reducir el tiempo necesario en cada uno de estos pasos, DEVOPS propone la máxima automatización de cada uno de ellos, de forma que la intervención humana sea mínima y cuando realmente sea necesaria. En este sentido hay que destacar las técnicas de desarrollo en paralelo, integración continua y entrega continua y despliegue continuo.

Desarrollo en paralelo

Como trato en mi post “¿Qué es el desarrollo en paralelo o concurrente?”, el desarrollo en paralelo aporta a los equipos de desarrollo la posibilidad de aislar una versión con todos los fuentes permitiendo realizar modificaciones a esta sin alterar otras versiones que puedan estar siendo desarrolladas también en ese momento.

branch

Es interesante tener en cuenta que el uso de entornos virtuales y “cloud” ha eliminado o minimizado una de las limitaciones históricas en este sentido ya que este enfoque requiere múltiples entornos de desarrollo (compartido), no el entorno local de cada desarrollador, de cara a realizar las pruebas iniciales.

Integración continua

Es un modelo propuesto por Martin Fowler que se basa en compilar, realizar el análisis de código estático y ejecutar pruebas automáticas de todo el proyecto lo más a menudo posible de cara a la detección temprana de errores.

El proceso se ejecuta de forma periódica, o bien según ciertos disparadores, y suele ser de la siguiente forma:

  • Se descarga del control de versiones las últimas fuentes con los cambios implementados a un directorio de trabajo.
  • Se realiza la compilación de estas fuentes.
  • Se lanza el análisis estático y de cobertura de las fuentes.
  • Se instala en el entorno (compartido) de Desarrollo.
  • Se lanzan las pruebas automáticas.
  • Se generan los informes.

ci

Si alguno de estos pasos falla se da por errónea la ejecución y se notifica a los responsables oportunos.

Este enfoque permite la identificación temprana de errores ya que no se ha salido de la propia fase de desarrollo cuando se están encontrando posibles fallos o carencias en el código, por lo que es mucho más sencillo proceder a la subsanación de estos y se evita los cambios de última hora antes de la entrega.

Entrega continua y despliegue continuo

El objetivo es facilitar a los usuarios finales lo antes posible las modificaciones que ha realizado desarrollo en la aplicación. Por lo que la entrega continua y el despliegue continuo pueden interpretarse como aplicar el concepto de integración continua al despliegue de aplicaciones.

Es importante tener en cuenta, que la entrega continua no consiste en desplegar en Producción cada cambio lo antes posible, sino que cada cambio debe de estar disponible para ser desplegado en cualquier momento.

Comienza una vez que la aplicación está construida y hay que implantarla en los siguientes entornos del ciclo de vida. Por ejemplo, entregar la nueva versión de la aplicación para QA para que pueda realizar las pruebas y finalmente entregarla a Operaciones para que pueda hacer su implantación en Producción.

El paradigma tanto de la entrega continua como del despliegue continuo es automatizar lo máximo posible todas las acciones necesarias para implantar una nueva versión de la aplicación y todas las tareas necesarias para validar esa nueva versión. Por lo que cada vez que se obtiene una nueva versión de la aplicación desde la integración continua se validan los criterios de liberación para el siguiente entorno y así sucesivamente.

La diferencia principal entre la entrega continua y el despliegue continuo es que el primero requiere de una aprobación manual antes de implanta en Producción, mientras que el segundo incluso la puesta en producción se realiza de forma automática una vez que se cubren todos los criterios definidos para la entrada en Producción para una aplicación.

cd

Conclusiones

Como puede observarse el uso adecuado de estas técnicas ofrecen la máxima flexibilidad ya que por un lado permite desarrollar cualquier necesidad de forma independiente para posteriormente integrarla con otras funcionalidades, construir, validar el código, desplegar en los distintos entornos intermedios, realizar las pruebas y finalmente implantar en Producción, poniendo en manos de los usuarios finales en el menor tiempo posible y con la mayor calidad las nuevas funcionalidades implementadas y garantizando las funcionalidades anteriores.

Revisión de código

La revisión de código o “peer review” es una técnica promovida por las metodologías ágiles que se basa en el aprendizaje sobre el código y fomentar la confianza en el equipo.

Las revisiones de código o revisiones por pares deben de servir para:

  • Compartir y distribuir el conocimiento, desarrolladores con mayor experiencia ayudan a desarrolladores noveles.
  • Identificar problemas de lógica o de negocio, se valida que el desarrollador ha entendido correctamente la necesidad y la ha implementado correctamente.
  • Abrir un canal de comunicación basado en el respeto y la confianza dentro del equipo de trabajo en el que todo el mundo puede aportar algo.

Su principal objetivo es comprender qué es lo que se quiere implementar y cómo se ha hecho, dicho de otra manera, es entender el problema y cómo se resuelve.

Revision CodigoPara evitar crear rechazo dentro del equipo de desarrollo estas revisiones no deben de utilizarse como si se tratase de un examen o de una búsqueda de problemas y culpables, de ser así, se obtendría justo lo contrario de lo que se persigue, aumentar la calidad del código mediante el aprendizaje de todas las partes fomentando el trabajo en equipo.

Para ello, durante una revisión de código hay que evitar:

  • Hacer comparaciones o calificar a los desarrolladores.
  • Intentar cambiar el estilo de codificación de un desarrollador.
  • Hacer críticas o comentarios negativos.

La revisión de código debe realizarse rápidamente, básicamente consiste en echar un vistazo para ver que todo está bien, no es necesario hacer una búsqueda detallada de posibles errores. Para esto están los pasos posteriores en el ciclo de vida en las que se analizará el código fuente al detalle.

Linus Torvalds plantea que «dado un número suficientemente elevado de ojos, todos los errores se convierten en obvios», Eric S. Raymond bautizó esta frase como la Ley de Linus. Se puede interpretar como que con suficientes revisores cualquier problema puede resolverse fácilmente.

La revisión de código permite a los equipos de desarrollo encontrar defectos mucho más rápidamente que QA o por los usuarios finales, lo que aporta una mejora en la calidad de las aplicaciones, una reducción tiempo y esfuerzo y, por su puesto de costes.

¿Qué es el desarrollo en paralelo o concurrente?

El desarrollo concurrente o en paralelo provee de los mecanismos necesarios para aislar una versión de un desarrollo software con el objeto de realizar modificaciones a esta sin alterar otras versiones que puedan coexistir en ese momento, puesto que cubre la necesidad de realizar cambios simultáneos con distintos objetivos en una misma aplicación. Un ejemplo típico de desarrollo en paralelo es el desarrollo correctivo o mantenimiento y el desarrollo evolutivo.

El valor de esta técnica no está en la capacidad de abrir múltiples líneas de desarrollo en paralelo, ya que no aporta ningún valor una línea de desarrollo que diverge indefinidamente respecto a su línea principal sin propagar cambio alguno, si no, que está en la integración o fusión de los cambios implementados en su línea principal de desarrollo.

Pero esta integración no es gratuita y tiene costes y tareas implícitas que muchas veces se omiten a la hora de definir una política de desarrollo en paralelo.

Esta forma de trabajo se basa en la utilización de ramas, líneas base y en procesos de integración y promoción de software.

  • Una rama es una instancia aislada o línea de desarrollo con un objetivo definido que parte de una línea base existente.
  • Una línea base es un conjunto de elementos de configuración en un punto del tiempo. (vista estática)
  • La consolidación es la integración de dos líneas de desarrollo o ramas.
  • La promoción consiste en desplegar o implantar software en un entorno físico.

De cara a definir la política de desarrollo en paralelo que realmente cubra nuestras necesidades hay que considerar estos aspectos:

  • Tiempo: Es el factor que mayor influencia tiene ya que conforme más tiempo pase entre integraciones la posibilidad de encontrar más cambios será mayor, por lo tanto la integración será más compleja y requerirá mayor esfuerzo.
  • Riesgo en la estabilidad: Cuando se integra una modificación implementada en una rama de desarrollo provoca que la línea principal de esa aplicación no sea estable, ya que hasta que no se haya probado completamente e implantado en Producción se tendrá que considerar como una versión del software en vuelo.

Por lo que antes de definir nuestra política de desarrollo concurrente o en paralelo tendremos en cuenta estas buenas prácticas:

  • No abrir ramas, esta debe de ser la mentalidad del equipo de trabajo, es decir, como objetivo no se debe abrir una rama salvo que exista un motivo que justifique su creación. Lo importante es tener claro que si necesitamos llevar a cabo dos o más propósitos debemos aislarlos en líneas de desarrollo independientes que se hayan creado a partir de la misma línea base. Estos propósitos pueden ser:
    • Trabajar en dos o más “releases” al mismo tiempo.
    • Trabajar en una nueva “release” al mismo tiempo que en arreglos de incidencias o parches para releases anteriores.
    • Trabajar con otros “sites” (“site specific branch”)
    • Trabajo concurrente sobre el mismo “site” (“shared branch”)
    • Trabajo dentro de workspaces privados(“user specific private branch”)
  • Consolidar a menudo y lo antes posible las ramas entre sí de forma que evitemos que la complejidad aumente, el esfuerzo disminuya y la estabilidad aumente, ya que habrá menos cambios por lo que las modificaciones a integrar serán menos y normalmente más sencillas.
  • Hacer uso de un motor de “Integración Continua” ya que reduce significativamente el tiempo necesario para validar una versión del software integrada, lo que nos permite reducir el tiempo de inestabilidad.
  • Identificar los motivos por los cuales se actualizan ficheros y crear las líneas base en función de estas peticiones.

Es imprescindible el uso de una herramienta que ofrezca un buen soporte a esta técnica de ingeniería de software ya que será la que permita realizar la integración o fusión de múltiples líneas de desarrollo de forma sencilla y segura.

Esta herramienta debe de ofrecer, como mínimo, los siguientes mecanismos para garantizar la integración de los cambios.

  • Creación de ramas y su independencia.
  • Comparación de ramas identificado las siguientes casuísticas:
    • Creación de elementos en alguna o en ambas de las ramas.
    • Borrado de elementos en alguna o en ambas de las ramas.
    • Movimiento de elementos en alguna o en ambas de las ramas.
    • Borrado de elementos en alguna o en ambas de las ramas.
  • Integración automática y manual de los cambios, tanto a nivel de rama como de fichero.

Recomendaciones

Para definir una política de desarrollo en paralelo hay que especificar claramente cuándo y cómo se van a realizar los “check-out”, “check-in”, la integración de los cambios e y su implantación.

Dentro de estas definiciones es conveniente tener en cuenta los siguientes aspectos:

  • “Mainline” o línea principal de desarrollo: El resto de líneas de desarrollo acabarán integrándose contra esta línea principal que contendrá todos los cambios.

uno

  • Propiedad de las líneas de desarrollo: Asignar a un responsable para cada línea que sea capaz de asegurar la integridad y la consistencia de dicha línea.
  • Integrar pronto y frecuentemente: Integrar los cambios de una rama a su línea de desarrollo tan pronto como los cambios en la rama se hayan completado y probado

dos

  • Restringir el acceso a las líneas: Al determinar la política de ramas se debe plantear el control de acceso a ésta.
  • Control de ejecutables o artefactos a implantar:
    • “Vault” o librería de medios: Repositorio en el que se almacenará todos los artefactos generados que son susceptibles de ser instalados en Producción.
    • Bill of Materials: Se puede construir un ejecutable correctamente, pero puede ser necesario generar exactamente el mismo ejecutable en el futuro, por lo que será necesario identificar todos los elementos que participaron en la construcción.
    • Build Reproducible: Todos aquellos procesos de compilación que se utilizan, deben poder ser reproducidos en el futuro, por lo que habrá que almacenar cómo se construyen los artefactos.
    • Caché de Objetos Compartidos: Permite a los desarrolladores llevar a cabo builds locales basados en archivos extraídos del repositorio y un conjunto común de archivos objeto o librerías.
  • Código Fuente Compartido: Mantener y soportar un conjunto común de código utilizado por más de un proyecto.

Patrones de CM

En el libro “Software Configuration Management Patterns: Effective Teamwork, Practical Integration” de Steve Berczuk y Brad Appleton (http://www.scmpatterns.com/book/) se detallan los patrones a aplicar durante la definición de la política de desarrollo en paralelo que se adapte a nuestras necesidades.

En el siguiente link se puede descargar una guía rápida de estos patrones: Quick Reference Card for the Software Configuration Management Pattern Language

Conclusiones

El desarrollo en paralelo es una de los mecanismos más potentes de cara al desarrollo de software ya que permite a una organización trabajar simultáneamente en varios cambios y decidir posteriormente cuando se implantará estos en Producción.