La Integración continua: Netscape, la NASA, XP y dos mayordomos

En el artículo “La Integración Continua reduce el riesgo en proyectos software” comentábamos un poco el contenido del artículo de Martin Fowler que sacó en el 2005 sobre este mismo tema. En este artículo Fowler explicaba que la CI tenía un beneficio directo en los proyectos software reduciendo el riesgo, y  tuvo el efecto  añadido de  ayudar a que se difundiera con aún más fuerza.  Haciendo un guiño nostálgico a un anuncio del 2001 que decía “Si no sabes programar no sabes informática”, hoy en día “si no practicas la integración continua, no desarrollas software”. Volviéndome a ponerme nostálgico, ya lo decían en un anuncio de los 80: “la informática es mucho más que unas palabras”. Porque desarrollar software es mucho más que sentarse durante horas a escribir líneas de código.

programador3

Los que conozcan Extreme programming me dirán, “integración continua es una de las prácticas de XP”. Sí que lo es, es una de las 12 prácticas de XP, pero ¿cómo fue su evolución? y ¿a quién se le ocurrió por primera vez que debían hacerse integraciones automáticas lo más a menudo posible para reducir el riesgo en los proyectos? ¿Un día se levantó Kent Beck de la cama y dijo: “¡¡¡Eureka!!!”? y uno de los doce mandamientos será: integración continua. Nada más lejos de la realidad.

Os Dez Mandamentos 1

La CI fue propuesta y nombrada por primera vez en 1991 por Grady Booch en su método (Método Booch). En este caso Booch no hablaba en ningún caso de integrar varias veces al día. Grady Booch es conocido por desarrollar UML junto con James Rumbaugh. En 1991/94 desarrolló el método Booch. Se trataba de una técnica usada en ingeniería software para el diseño de objetos (predecesor de UML y RUP). Este método hablaba de uso de objetos, métricas, QA, patrones de diseño, formalismo, madurez de procesos y una notación robusta. Habla de sacar releases de arquitectura hasta llegar al sistema final (evolutivos)…si, es el precursor de RUP también, evidentemente.

image-83472-full

En los años 90 del siglo XX se producían dos temas importantes para el surgimiento de la integración continua. Uno fue que contrataron a Kent Beck (uno de los creadores de XP) en Chrysler con el objetivo de llevar un proyecto (El C3) de gestión de nominas, en el cual los requisitos eran un gran problema (¡¡¡no me lo esperaba!!!…). Parece ser que el sistema legacy de nóminas era bastante infumable (más de lo habitual supongo), se trataban de varias aplicaciones, cada uno de su padre y de su madre, que hacían lo mismo en algunos casos pero de forma diferente y donde los requisitos, como no, brillaban por su ausencia. El primer año que sacaron la primera release fue muy duro. Tan duro,  que  cliente, punto de contacto de Chrysler con el proyecto, tuvo que pedir la baja por estrés.

liberar-estress

Por otro lado, mientras se cocía la historia de Chrysler y XP, ocurre una historia paralela. Los ingenieros de calidad de Netscape, tuvieron una gran ocurrencia. Estos llegaron a la conclusión de que sería bueno poder realizar construcciones del código automáticamente de forma periódica. Tenían bastantes problemas con CVS (que acaba de surgir en los 90), ya que cada vez que iban a sacar una release, el código no compilaba correctamente: “en mi máquina funciona” decían los desarrolladores.

fz1t19.jpg

Se pusieron manos a la obra y crearon una herramienta muy sencilla llamada Tinderbox que les permitía realizar una construcción diaria de su software de forma que sabían en el mismo día si había habido un problema con la construcción del mismo (la build). En poco menos de un año, se dieron cuenta que bajando la cadencia de los builds, eran capaces de saber cuál había sido el problema de integración que había roto la build (a menos tiempo, menos commits realizados y más fácil detectar el problema de fallo). Progresivamente bajaron la cadencia hasta  realizar builds automáticos cada hora. Cuando en 1998 el código de Netscape es liberado, también es difundida su forma de trabajo a la comunidad de open-source. De esta manera la construcción frecuente de tu código de forma automática pronto se convirtió en una buena práctica en el mundillo del desarrollo software.

best-practices.jpg

XP lleva las mejores prácticas a niveles extremos. Por ejemplo la práctica de hacer test antes de desarrollar fue usada por la NASA en el programa Mercury Space por primera vez para tarjetas perforadas en 1960. XP la llevo al extremo con TDD. Aunque Kent beck no se considera a sí mismo el creador de Test Driven Development, fue el que implemento SUnit, un framework de tests unitarios para Smalltalk que fueron las bases de la familia xUnit (conjunto de frameworks basados en sus premisas como nUnit, phpUnit, junit, MsUnit, etc). Este framework se pensó para realizar TDD basándose en ideas de Gerard Weinberg y Leeds, Herbert D. en su libro (Computer Programming Fundamentals – 1960). Sí, he de afirmar que es curioso que en la portada original Weingberg no aparezca. Pero eso es otra historia.

51+GmuMoPYL._SX331_BO1,204,203,200_

Otra de las prácticas que se lleva al extremo es la integración continua. Kent Beck tomó la idea de Booch, las nuevas buenas prácticas de los build automáticos con las ideas de los servidores de builds automáticos emergentes y la inclusión del framework de test automáticos que había creado para dar forma a una de las prácticas de XP: Si aquellos tipos de Netscape podrían hacer construcciones del código cada hora, ¿por qué no íbamos a poder hacerlos en cada commit y además pasar automáticamente baterías de test automáticamente con sUnit? En 1999 Kent beck publica el primer libro sobre XP donde incluye el concepto como una de sus 12 prácticas.

circles.jpg

La integración continua ha ido evolucionando a medida de que han ido apareciendo nuevas tecnologías y herramientas. Si tenemos que pensar en cual fue la primera herramienta construida para este propósito, podemos pensar que fue Cruise Control que surgió en el 2001 como servidor de builds extensible. Esta herramienta estaba pensada para realizar builds automáticos usando Ant o Maven. Funcionaba (y funciona) a través de plugins que extendían su funcionalidad. Se trata de una herramienta gratuita y open-source.  Existe una herramienta para .NET similar denominada Cruisecontrol.NET que aparece en el 2003 con su versión 0.3.1 pero no es hasta 2005 que aparece la primera versión 1.0 estable. Es decir, que la integración continua basada en herramientas específicas (no el concepto como tal), tampoco es tan lejano. Fue cuando se estrenó “Batman begins”.

Batman-Begins-batman-555782_1024_768.jpg

Hudson es otra herramienta de integración continua escrita en Java que se ejecuta en un Apache Tomcat o en el servidor de aplicaciones GlassFish. Trabaja con CVS, Svn, Git y clearcase, y puede ejecutar Apache Ant y Maven así como procesos Windows. Hudson surgió en 2008 y se convirtió en una alternativa a Cruise control y otros servidores de builds de código abierto.  El desarrollador principal de Hudson fue Kohsuke Kawaguchi que actualmente es empleado de Sun Microsystems. Si dejas a un montón de desarrolladores software el código de una herramienta como esta, pasa lo que pasa: crean una comunidad y la llevan “hasta el infinito y más allá”.

kohsuke.jpg

Cuando más adelante Oracle compró Sun, este declaró que quería registrar el nombre de Hudson y desarrollar una versión comercial. Esto enfadó mucho a la comunidad de desarrollo de Hudson, la cual decidió, junto con Kawaguchi hacer un fork del código de Hudson y llamarlo Jenkins en 2011 (ambos son nombres típicos de mayordomos). Al final Oracle se da por vencido y en 2012 dona Hudson a la fundación Eclipse. En 2013 llevan muchos commits de Jenkins a Hudson. Lo que decía yo… “hasta el infinito y más allá”.

jenkins vs Hudson java

El caso es que los conceptos han cambiado poco desde final del siglo XX, ya que siguen siendo prácticamente los mismos. Si han aparecido nuevos, es porque han aparecido herramientas que ahora lo permiten y anteriormente no, o no con la misma facilidad. De la integración continúa se pasa a la entrega continua y de ahí al despliegue automático en producción. Hoy en día existen muchas herramientas y plugins desarrollados que están trayendo nuevos conceptos y capacidades de automatización, o quizá ya no tan nuevos en el momento de publicación de este post. Algunas organizaciones, hoy en día, son lo suficientemente maduras para automatizar tanto el desarrollo software y las pruebas, que con cada commit despliegan directamente en los servidores de producción  con seguridad (pocas son) (continuous deployment). Pero eso amigos, eso, es otra historia.

continuos deployment vs delivery.jpg

PDFicono EXTENDIDO

REFERENCIAS:

[1] Continuous Integration – Martin Fowler
[2] Continuous delivery  – Martin Fowler
[3] Extreme Programing Explanined:Embrace change – Kent Beck

La Integración Continua reduce el riesgo en proyectos software

Hace tiempo alguien me preguntó que como configuraría un TFS (Team Foundation Server) para poder pasar pruebas unitarias automáticamente. Le comenté que implantaría integración continua (IC), realizando compilaciones automáticas en el servidor con cada subida de código, desplegando la solución, ejecutando los test unitarios y generando los reportes. Se quedó sorprendido y me preguntó ¿para qué querríamos hacer eso tan a menudo? A veces hay conceptos que cuando los escuchas por primera vez te chocan pero cuando los pruebas acabas mirando al infinito sonriendo y con las palmas de las manos en volandas diciendo  “¡¡como he podido vivir antes sin esto!!”. La integración continua es uno de esos conceptos.

ninos-felices-viendo-la-pantalla_438-19316458 - free

La IC es un modelo informático que consiste en hacer integraciones automáticas en un proyecto lo más a menudo posible para detectar fallos lo antes posible. En este caso se entiende “integración” como la compilación y ejecución de pruebas. Este proceso se puede producir cada cierto tiempo en el servidor o tras un evento como puede ser una subida de código por parte de un desarrollador. La IC automáticamente descarga el código fuente del control de versiones, lo compila, ejecuta las pruebas automáticas y por último genera un informe. También puede incluirse una generación de un instalador para poder realizar pruebas manuales.

source control

IC es una de las prácticas fundamentales de XP. Esta técnica fue propuesta por Martin Fowler y se empezó a difundir con más fuerza fuera de XP a raíz de un artículo que pùblicó en Mayo del 2006 dedicado por completo a la IC. Se trata de un artículo que habla con detalle de la IC y donde al final del mismo, hablando de los beneficios, comenta que quizá el mayor beneficio es reducir el riesgo. Esta reducción se debe a que:

  • Detectamos fallos de forma temprana. Recordemos que un error detectado en fases tempranas de desarrollo nos va a ahorrar siempre mucho tiempo en el proyecto y consecuentemente dinero.
  • Vamos a saber en todo momento cual es el estado de nuestro código, por lo que a diario podemos tener un informe sobre la salud de la misma. De esta manera vamos a tener muchas pequeñas integraciones y no una única normalmente impredecible al final del desarrollo.
  • El efecto psicológico que produce la CI conduce a una disminución de bugs.

Pero desarrollemos un poco más estas ideas para saber realmente por qué IC reduce el riesgo en nuestros proyectos software.

Manage Your Risk in a dangerous world, company, workplace or ent

Martin Fowler comenta en su artículo que la idea de la IC le surgió durante un antiguo proyecto en el que trabajaba de QA manager donde se dedicaba entre otras cosas a sacar informes OLAP con el objetivo de predecir cuánto tiempo les iba a llevar integrar el software que estaban desarrollando. Cuenta que en este proyecto aprendió que la integración “suele ser larga e impredecible”. Se dio cuenta de que otros proyectos no trataban la integración como un evento aislado que se producía una vez recibida una release, sino que podían en cualquier momento pasar a integración el código actual en la rama de desarrollo en cuestión de minutos. Cualquier error de integración era encontrado rápidamente y arreglado. Comenta también que cuando intentaba explicar en otros sitios el concepto, se sorprendió del rechazo. Cualquier cambio que pone a prueba nuestro sistema de creencias siempre va a tener una resistencia asociada: si atamos a un elefante de pequeño a una estaca y cree que no puede escapar, seguirá atrapado toda su vida.

elephant

Una de las cosas que más cuesta entender es que tener IC implantada en nuestro desarrollo con una buena cobertura de tests no nos va a librar de tener bugs. Mucha gente piensa, que con un juego de pruebas adecuado y con una buena estrategia vamos a conseguir proteger nuestro código de esos molestos bugs, y este no es el objetivo de ningún tipo de prueba automática o manual. El objetivo de un conjunto de pruebas es aumentar la probabilidad de capturar errores en nuestro sistema. Por lo que en el caso de las pruebas unitarias y de integración automáticas, si las ejecutamos cada vez que hacemos un cambio en la rama de desarrollo, aumentamos la probabilidad de detectar errores debidos al cambio que hemos realizado. Diciéndolo de otro modo, si nuestro código es una novela, aumenta la probabilidad de que se detecte alguna incoherencia en un nuevo párrafo incluido con el resto de la misma.

taller-escritura

En resumen IC no nos va a librar de tener errores en el código pero si va a tratar de minimizar el número de los mismos. Algunos no prestan demasiada atención al número de bugs durante la fase de desarrollo. Se da por hecho de que es normal que surjan bugs porque la funcionalidad no está terminada y siempre se reserva un tiempo antes de la entrega para poder corregir esos bugs y realizar una entrega con calidad. Estos periodos de corrección de bugs suelen ser apocalípticos porque se pretende limpiar los bugs generados tras varios meses de desarrollo en 1 mes de corrección. Este tipo de desarrollos se caracterizan por subidas y bajadas del número de bugs justo antes de la finalización de hitos. Lo más curioso es que normalmente suele haber un tope mínimo de bugs que no se corrigen nunca: suelen ser aquellos que supondrían realizar cambios muy costosos en arquitectura… y claro si los dejas para el final, evidentemente nunca se corrigen.

costofdefects

Tratar de corregir bugs durante el desarrollo ayuda a controlar los picos altos de errores, pero sin una buena cobertura de test unitarios, es muy difícil mantener una rama de desarrollo sana. Esto es debido a que se sigue subiendo código simultáneamente a medida que los bugs se corrigen, de forma que al no existir una “alarma” que diga que una subida de código ha afectado a otra parte del sistema, cada subida de código contiene alta probabilidad de causar daños en otras partes del sistema. Hay que decir que la probabilidad de daño en cada subida es menor en arquitecturas con alta cohesión y bajo acoplamiento entre sus componentes que en aquellas donde existe un alto acoplamiento y baja cohesión (código espagueti). Tener una buena cobertura de test unitarios es un indicador de que tu arquitectura tiene alta cohesión y bajo acoplamiento. Por este motivo aplicar técnicas como TDD es más efectivo que realizar los test unitarios a posteriori ya que primero se crean las pruebas y luego el diseño, con lo que estamos forzados a crear componentes separados por interfaces y bien definidos si queremos conseguir una buena cobertura y unas pruebas realmente eficaces.

DevBranch

Como decía anteriormente, muchos creen que no merece la pena realizar el esfuerzo de corregir bugs durante el desarrollo porque de todos modos siempre hay que hacer ese esfuerzo al final del mismo (con test unitarios un esfuerzo muchísimo menor). Existe un fenómeno psicológico que dice que la gente pone menos esfuerzo en localizar bugs cuando hay muchos que cuando hay pocos. Este fenómeno se estudia en criminología y se denomina “Teoría de las ventanas rotas (Broken Window syndrome)”: Esta teoría dice que si consideras un edificio con una ventana rota, si la ventana no se repara, muy probablemente los vándalos tenderán a romper unas cuantas ventanas más. Cuando estén rotas, posiblemente irrumpan en el edificio, y si está abandonado, es posible que sea ocupado y prendan fuego dentro.

300px-Kristallnacht_example_of_physical_damage

La IC, intenta dar tolerancia cero a la rotura de ventanas mediante la detección temprana de bugs y la prioridad máxima para su corrección. Debido a esto, los desarrollos que tienen integración continua, tienen tendencia a tener menos bugs. No evitas tener seguramente un periodo de pruebas de regresión a final del desarrollo, pero si maximizas la corrección en el periodo establecido, habrá menos bugs, estarán más controlados y su corrección será mucho más sencilla.

Disciplina

Las herramientas que podemos utilizar para poder implantar integración continua en nuestro desarrollo software son muy variadas. Por si tenéis interés os enumero algunas con sus links: TFS – Team Foundation Server, Cruise control, Jenkins y  Atalassian Bamboo. Además de ayudarnos de estas herramientas, existen una serie de prácticas que maximizan la eficacia de IC. Estas son explicadas con detalle en el artículo de Martin Fowler por lo que sólo las listaremos:

  • Mantén un único repositorio de código fuente
  • Automatiza los build
  • Haz tu build autotesteable
  • Todo el mundo sube código diariamente
  • En cada subida de código se debería ejecutar la IC en una máquina limpia
  • Arregla los bugs cuanto antes
  • Testea manualmente en un clon de un enviroment de producción
  • Hazlo visible a todo el mundo el estado de la rama de desarrollo
  • Automatiza el despliegue

gear

Volviendo a inicio del artículo, cuando me preguntaron ¿para qué querríamos pasar los test en el servidor de TFS cada vez que alguien sube código? Contesté que  la integración continua minimiza el riesgo en tu proyecto gracias al aumento de calidad (tanto externa como interna) de tu producto y a la posibilidad de tener una alarma que te dice cual es el estado de salud del código desarrollado en todo momento. Parece ser que capté su atención, por lo que su siguiente pregunta era de esperar: ¿y eso cómo se produce? Le dije que se pusiera cómodo porque la respuesta podría ser perfectamente un artículo de ingeniería del software y me llevaría un rato exponerla.

PDFicono EXTENDIDO

REFERENCIAS:

[1] Continuous Integration – Martin Fowler
[2] Foundation of Software Testing  –ISTQB CERTIFICATION
[3] Implantar integración continua  – Javier Garzas