Ingeniería de Software en la Era DevOps

Este el título de la charla/tutorial que dí la semana pasada en el contexto de CIbSE. En Zoom hubo unas 80 personas conectadas pero de las actividades interactivas que propuse, participaron alrededor de 30, un buen número de todas formas.

El punto central de mi de charla fue el hecho de que los escenarios que enfrentamos actualmente en la entrega de software nos llevan a tener que lidiar con ciertas cuestiones que tradicionalmente la ingeniería de software no ha atendido presentes. Al mismo tiempo, dichas cuestiones son centrales dentro del movimiento DevOps. Esto plantea un dilema: ¿es DevOps una disciplina distinta a la Ingeniería de Software? Pues yo creo que no. A mi parecer la Ingeniería de Software debe incluir DevOps. De hecho algunas de prácticas DevOps no son nuevas, sino que han sido parte de la Ingeniería de Software desde hace mucho tiempo. Ejemplo: Integración Continua.

En línea con esta idea, durante mi disertación mencioné varios libros que deberíamos tener presentes a la hora de plantear una Ingeniería de Software que incluya la temática DevOps:

Actualización: ya está disponible el video de la sesión, aquí.

Inversión de Dependencias

Este el quinto principio de los principios SOLID y personalmente creo que es el que mayor impacto tiene a la hora de hacer soluciones testeables. Pero curiosamente me encuentro recurrentemente con una importante cantidad de gente que no lo usa o que lo interpreta incorrectamente. Es por esto que decidí hacer un video al respecto.

Me quedó un video bastante corto, ~10 minutos, en el que explico el principio utilizando código y diagramas. Espero les resulte útil.

Lecciones aprendidas automatizando pruebas en ambientes corporativos (parte 1)

En los últimos años he participado en un par de iniciativas para automatizar pruebas en «ambientes corporativos». Cuando digo ambientes corporativos me refiero a organizaciones cuyo core de sistemas está implementado por algún  tipo de enlatado con cierto grado de customización (ERP, CRM, Core bancario, etc). Alrededor de este core la organización desarrolla aplicaciones satelitales que suelen actuar como canales implementado alguna funcionalidad complementaria al core. Estas aplicaciones satelitales/canales suelen tener una gran cantidad de requerimientos y cambios ya que son uno de los medios principales en la actualidad para permitir la innovación del negocio. A la hora de desarrollar estas aplicaciones aparece la necesidad de poder testearlas y que dicha prueba sea (al menos en parte) automatizada.

En particular he tenido la oportunidad de trabajar en contextos de instituciones bancarias y también del ámbito de las telecomunicaciones y en ambos casos he detectado situaciones/desafíos comunes que me parece son habituales en entornos corporativos.

En mi experiencia he identificado dos tipos de desafíos: los técnicos y los humanos.

En lo que respecta a desafíos técnicos el principal pasa por la dificultad de contar con un ambiente de pruebas sobre el cual uno pueda tener control de estados/datos.  En el escenario ideal yo quisiera poder contar con una instancia exclusiva y on-demand del core, cuyo estado pueda manipular a mi gusto sin impactar en otros equipos. Esto no es simple, ya que muchas veces el setup de estos sistemas core es bastante complejo y poco automatizado. Lamentablemente en ninguno de los casos que he trabajo he tenido esta posibilidad, lo cual me ha llevado a buscar soluciones alternativas.

Una situación que me he encontrado en todos los casos que participé es la presencia de un de ESB (enterprise service bus) que funciona como orquestador/integrador de mensajes entre los diversos sistemas de la organización incluido el core. De hecho es común que la interacción de los canales/satélites con el core se haga por medio de un ESB.  Si bien esto puede interpretarse como una complejización de la arquitectura, se supone que en general la simplifica. Al mismo tiempo representa una posible salida al problema del testing.

Escenario corporativo

Entonces ante la imposibilidad de contar con un core para las pruebas (y también para el desarrollo) tenemos dos opciones. Una primera opción es mockear «a la salida» las interacciones con el core.

Opción 1. Mock «a la salida»

La otra opción sería hacer que el ESB devuelva respuestas mockeadas.

Opción 2. Mock en el ESB

Algunos puntos a tener presente independientemente de la estrategia utilizada:

  • Al utilizar una estrategia de mocking en este contexto es necesario tener algún mecanismo para detectar potenciales cambiamos en el sistema que estamos mockeando/emulando. Una estrategia posible es hace contract testing del sistema que estamos mockeando de manera que los tests de contrato se ejecuten periódicamente y nos alerten de eventuales cambios.
  • En algún punto, previo al pasaje al ambiente productivo es necesario poder correr algún tests contra una instancia del core real.  En uno de los casos que me toco participar, la instancia de test del sistema core era tan inestable y distinta al core productivo que lo que se decidió hacer un despliegue canary a un servidor productivo, accesible solo internamente, y de esa forma probar directamente en producción.  Una vez realizada la validación, entonces se completaba el despliegue al resto de los servidores habilitando la aplicación al público en general.

Continuará…..
(en un futuro artículo me referiré a los «desafíos humanos de esta problemática»)

Cierre de cuatrimestre en Ingeniería @ UNTreF

La semana pasada cerramos el cuatrimestre en la materia Ingeniería de Software en UNTreF. Fue mi tercer cuatrimestre en la materia y personalmente estoy muy conforme con el resultado. Algunas particularidades de este cuatrimestre fueron:

  • Tuvimos un cambio en el equipo docente, Diego Marcet (@diemarcet) reemplazó a Pablito Tortorella (@pablitux)
  • Cambiamos el campus virtual que usamos como herramienta de soporte, pasamos de Eliademy a Canvas.
  • Hicimos algunos ajustes en el programa, incluyendo algunos temas nuevos relacionados principalmente a cuestiones de control de calidad y gestión de la operación
  • Tuvimos dos clases especiales: una sobre modelos de calidad dictada por Sergio Villagra y otra dictada por Fernando Pelliccioni quien compartió la forma de trabajo de su equipo de desarrollo en Bitprim

En términos estadísticos:

  • 8 inscriptos, 1 abandono, 7 aprobados
  • La nota promedio de cierre de cursada fue 8,9
  • La evaluación general de la materia realizada por los alumnos (vía encuesta anónima) fue 8,3

Entre los puntos a mejorar que identificamos en el cierre de la materia destacamos:

  • Mejorar la consigna de la tarea de performance testing
  • Agregar un video introductorio a JMeter
  • Revisar el envió de notificaciones del campus (varios reportaron que la notificaciones les llegaban con mucho retraso)
  • Repetir el ejercicio del elefante carpaccio que fue de las mejores actividades de la materia
  • Comenzar antes con el desarrollo del trabajo final
  • Intentar que las tareas individuales se hagan sobre la misma base de código que el trabajo final
  • Hacer una introducción técnica a Padrino
  • Probar haciendo que las iteraciones del trabajo final sean de 2 semanas

Historia de una primera salida a producción

Finalmente luego de 9 iteraciones(~4 meses) llegamos a producción. Mmmm, no, en realidad fue casi un año de trabajo. El proyecto comenzó con un sistema legacy desarrollado en Asia durante 6 años [1]. Sobre dicha plataforma hicimos una reingeniería para reemplazar algunos módulos y agregar uno totalmente nuevo. En ese contexto se comenzó a trabajar con un equipo de 4 personas que fue creciendo a lo largo del año hasta llegar a ser más de 25 personas (yo me sumé cuando rondábamos las 10).

A medida que la cantidad de personas se fue incrementando fuimos partiendo el proyecto/equipo en sub-proyectos/sub-equipos hasta llegar a ser 5 sub-equipos/sub-proyectos [2].

En Enero tuvimos el release del primer módulo que reconstruimos de cero [3]. En Mayo fue el release del segundo módulo y finalmente el viernes pasado tuvimos el release de 3 módulos más. Los primeros dos módulos había sido producto del trabajo de 2 sub-equipos, mientras que los módulos liberados el pasado viernes fueron resultado del trabajo del «big-team», o sea, el release incluyó productos de todos los sub-equipos.

En este año de trabajo he compartido experiencias muy enriquecedoras con un excelente grupo de trabajo. Siendo alrededor de 30 personas, hubo algunos con los que compartí muchas situaciones y otros con los que apenas hablé. Entre todas las cuestiones acontecidas durante este año me parece importante destacar:

  • El foco en la mejora
  • El espíritu colaborativo
  • La especial atención a las personas
  • La disciplina en la forma de trabajo
  • El manejo de los esfuerzo extraordinarios (horas extra)
  • El manejo de las situaciones «no tan felices»

[1] En el artículo Aplicaciones legacy, monolitos y microservicios escribí más detalladamente sobre esta situación.

[2] En el artículo team.split() & project.new(), conté sobre la creación de uno de los sub-equipos/sub-proyectos

[3] En el artículo projifm, estadísticas del primer release compartí algunas estadísticas de ese primer release.

Nueva aventura: proyecto de investigación

Luego de algunas discretas expediciones esporádicas al mundo de la investigación, este año voy a embarcarme formalmente en un proyecto de investigación junto a Diego Fontdevila y Alejandro Oliveros.

Si bien aún estamos en etapa de definiciones nuestro trabajo entra en la temática ingeniería de software y más específicamente en el área de prácticas y procesos.

Hemos decidido intentar gestionar este proyecto de investigación de forma similar a como gestionamos cotidianamente nuestros proyectos de desarrollo software. En ese sentido hemos bautizado el proyecto con un nombre clave: Paladine (nombre del líder de los hechiceros en el mundo DrangonLance).

Como parte de mi formación para llevar adelante este trabajo estoy cursando un seminario de Introducción a los métodos experimentales de investigación en Ingeniería de Software. Hasta el momento llevamos tan solo dos encuentros y ambos me han resultado extremadamente enriquecedores.

Continuará…

Las dos cuestiones más desafiantes del desarrollo de software

Desarrollamos software para aportar valor a un negocio/organización. En ese sentido el desarrollo de software tiene dos cuestiones centrales que son la fuente de sus mayores complejidades: determinar lo que hay que construir y manejar de forma eficiente las necesidades de cambio. Si bien yo he enumerado estos dos temas como cuestiones disjuntas la realidad es que tienen una íntima relación. Determinar lo que hay que construir debe gran parte de su complejidad al hecho de que una vez determinado lo que se debe construir, lo mismo suele cambiar. De todas todas vayamos por parte.

Determinar lo que hay que construir

Este es un tema que se ha tratado bastante, a punto tal que se ha generado un disciplina alrededor del tema: Ingeniería de requerimientos. Hoy por hoy, luego de haber leido, reflexionado y experimentado creo que el tema puede simplificarse a dos escenarios:

1) requerimientos conocidos y estables
2) requerimientos no-conocidos y/o no estables

Nunca en 15 años de trabajo en la industria me encontré con el caso (1), pero curiosamente creo que gran parte de la bibliografía, técnicas y conocimientos de la ingeniería de requerimientos está enfocada en este tipo de escenarios. Se me ocurre que en estos escenarios puede ameritarse hacer un trabajo intenso sobre los requerimientos antes de comenzar con el desarrollo (digo esto sin estar muy convencido).

Todos mis proyectos se enmarcan en escenarios del tipo (2), en algunos casos me ha tocado desarrollar software sin tener requerimientos conocidos, simplemente teniendo una visión y un objetivo de negocio y debiendo «experimentar sobre los requerimientos». En la gran mayoría de los proyectos en los que he participado me he encontrado con un conjunto de requerimientos cambiantes a satisfacer y ha sido precisamente esa propiedad «cambiante» la fuente de las principales fricciones del proyecto.
Para estos escenarios del tipo 2, no considero que sea útil, ni conveniente realizar un trabajo intenso sobre los requerimientos antes de comenzar el desarrollo. Al contrario, creo que la cuestión pasa por «probar» de una forma sistemática siguiendo 4 premisas:

  • Trabajo iterativo
  • Involucramiento del usuario
  • Entrega frecuente
  • Feedback continuo

Manejar de forma eficiente las necesidades de cambio

A mi parecer este solo punto justifica la gran mayoría de las prácticas técnicas de la ingeniería de software (arquitectura, diseño OO, automatización, integración continua, etc). Si uno tuviera la certeza de poder escribir una pieza de código y nunca más modificarla podría no preocuparse por escribir código claro, mantenible y testeable. Curiosamente creo que en la formación académica se hace foco en la enseñanza de las prácticas técnicas pero sin hacer suficiente foco en el por qué de su importancia. Al construir software buscamos cumplir ciertas propiedades para facilitar la evolución/cambios que el software deberá soportar. El no cumplir con dichas propiedades suele generar diversos tipos de perjuicios para el negocio.

Obviamente más allá de estas dos cuestiones hay otras miles que también son relevantes (trabajo en equipo, planificación, etc), pero a mi parecer estas dos son las que están en los primeros puestos de complejidad.

Reflexiones sobre la Enseñanza de la Ingeniería de software

En mi actividad profesional cotidiana me desempeño como ingeniero de software ocupando distintos roles y realizando distintas tareas dependiendo de las particularidades del proyecto de turno. Por ello cuando en 2011 tomé a mi cargo la materia Elementos de Ingeniería de Software en la Universidad Nacional de Quilmes busqué una dinámica de dictado de la materia que efectivamente pudiera preparar a los alumnos para desempeñarse profesionalmente en esta disciplina.

Personalmente considero que la ingeniería de software es una actividad naturalmente industrial, y en este sentido me parece fundamental que su enseñanza tenga un enfoque práctico puesto que la ingeniería de software teórica resulta insuficiente para el ejercicio profesional de la disciplina.

Curiosamente mi formación  en Fiuba no tuvo este enfoque. Como alumno tuve un conjunto de materias de índole más bien teórica y  tiempo después otras materias de tipo taller donde se suponía ponía en práctica la teoría aprendida tiempo atrás. Esto me parece perjudicial para el alumno, pues a la hora de estudiar la teoría, la misma se aprende «en el aire» sin ponerla en práctica. Luego, tiempo más tarde se cursa un taller, pero al llegar al taller uno ya se olvidó de la teoría «supuestamente aprendida». Exactamente esto me pasó con el tema de estimación: en una materia me enseñaron los diversos métodos de estimación pero nunca me pidieron estimar, simplemente me pidieron describirlos en un examen escrito. Tiempo después cuando cursé el taller y tuve que estimar, tuve que volver a estudiar los métodos y fue ahí, a la hora de aplicarlos, que me surgieron mil dudas. Algo similar me ocurrió con las cuestiones de testing y calidad.

Otra curiosidad de mi carrera (y que también se repite en otras casas de estudio) es que cursé en primera instancia una materia de análisis y luego una de diseño, como si fueran dos actividades disjuntas (un punto sin duda debatible). Hasta ese momento carecía de una visión general del proceso de desarrollo de software, cosa que aprendí tiempo más tarde en la materia de gestión. Creo que resulta muy dificil (y poco conveniente) enseñar técnicas de análisis y diseño sin contar con el marco general de un proceso de desarrollo. En este sentido me parece interesante el enfoque de la Universidad Nacional de Quilmes, donde primero se ofrece una materia introductoria a la Ingeniería de Software que brinda al alumno una visión general de la disciplina, con un enfoque muy práctico y luego en siguientes cuatrimestres se ofrecen materias específicas para cada actividad: Ingeniería de requerimientos, Gestión de proyectos, Arquitectura de software, etc, etc.

Respecto del enfoque práctico, en concreto creo que es necesario hacer el ejercicio de construir/extender un pieza de software de cara a poner en práctica toda la teoría y técnicas enseñadas, tengo la sensación que enseñar ingeniería de software a partir de lecturas, cuestionarios y ejercicios conceptuales es insuficiente para formar profesionales de la informática y como dije antes el hacer estas actividades en materias separadas no me parece apropiado.

Creo que algunas de estas cuestiones han sido consideradas en el nuevo plan de la Licenciatura en Sistemas de la FIUBA (aunque no estoy seguro de hasta que punto). Espero también que estas cuestiones sean consideradas en el próximo plan de estudios de la carrera de Ingeniería Informática de FIUBA.

 

 

 

Ejercicio: interpretación de métricas de test y cobertura

Amo las métricas, creo que es un efecto colateral de la búsqueda de la mejora continua. Para mejorar es necesario medir, pero con medir no basta, hay que saber qué medir y luego hay que interpretar lo medido para poder accionar al respecto.

Hoy quiero compartir un actividad que hicimos esta semana con mis alumnos de Ingeniería de software en UNTreF. La dinámica fue simple, dado un proyecto tomamos los gráficos de evolución de tests y cobertura generados por Jenkins y los analizamos para generar hipótesis a partir de ellos. Invito a los lectores a sumarse a este ejercicio, analicen los gráficos e intenten extraer información de ellos. Comparto un poco de contexto que les puede resultar útil para el análisis: el proyecto en cuestión es un modelo (o sea pura lógica, sin UI ni base de datos), los desarrolladores son alumnos universitarios que tenían que trabajar con 2 consignas:

  1. Hacer el desarrollo usando TDD
  2. Hacer integración commiteando al repositorio central (en el mainline) luego de cada nuevo test verde.
  3. Si el build se rompe, se para la línea hasta que sea arreglado

analisis_1

Aquí va mi análisis y con mis hipótesis/conclusiones (=>):

  • En el build #10 se agregaron 10 tests => no respetaron la consigna 2
  • Pero a pesar del agregado de tests la cobertura disminuyó => posiblemente por el agregado de código de dominio sin los correspondientes tests => violación de la consigna 1
  • En los siguientes builds (#11,#12 y #13) la cantidad de test aumenta de a uno y también se evidencia un aumento en la cobertura.
  • En los builds #14 y #15 se evidencian nuevamente saltos grandes en la cantidad de tests y de la mano de ello también un aumento de la cobertura.
  • Entre los builds #15 y #18 la cantidad de tests se mantiene constante y lo mismo ocurre con la cobertura => esto podría indicar pasos de refactoring.
  • En el build #19 disminuye la cantidad de tests y con ello la cobertura => esto podría deberse a un cambio en el código de dominio que no fue acompañado completamente por la correspondiente actualización de test.
  • Finalmente la cantidad de tests se mantiene constante en los últimos builds pero la cobertura disminuye => me hace pensar en agregado de código sin los correspondientes tests.

¿algo que agregar?

Combinando métodos de estimación

Quiero compartir un método de estimación que suelo utilizar con buenos resultados (buen resultado = estimación muy cercana al resultado real, ojo que esto no es consecuencia exclusiva de una buena estimación, sino también de una buena ejecución).

Este método es un mezcla de PERT y Wideband Delphi, por ello voy a describir en forma resumida las partes que uso de cada uno de los estos métodos y luego voy a explicar cómo las combino.

Program Evaluation and Review Technique (PERT)

Este método fue desarrollado por la Armada de EEUU durante la década de 1950. El mismo asume que la duración de una tarea obedece a una distribución probabilística Beta y en base a ello propone que cada tarea sea estimada a partir de tres escenarios: optimista, normal y pesimista. En base a esto el tiempo esperado para completar una tarea puede calcularse como:

Tiempo esperado = (optimista + (4*normal) + pesimista) / 6

Si bien el método PERT dice muchas más cosas, esta premisa es la que puntualmente nos interesa.

Wideband Delphi

Este método fue desarrollado por Boehm y Farquhar en la década de 1970. Es un método de estimación grupal basado en la opinión de expertos. Propone que la estimación sea realizada por un grupo de al menos 3 expertos. Se toma como entrada la lista de ítems a estimar, se establecen algunas premisas (como ser unidad de estimación y generalidades relacionadas al contexto como podría ser la arquitectura de base sobre la que se trabajará) y  se procede de la siguiente manera:

  1. Se discute el alcance de cada ítem para despejar dudas y ambigüedades de manera de asegurar que todos los estimadores esten estimando lo mismo.
  2. Cada estimador estima en forma privada.
  3. Se comparten las estimaciones y se analiza la convergencia/divergencia de los resultados. En caso de divergencia, los estimadores explican como fue que llegaron a los valores dados. Para realizar este análisis es común volcar los número en una hoja de cálculo y ver la media y la desviación de los mismos.
  4. Se repiten los pasos 2 y 3 hasta lograr convergencia.

Mi propuesta

Conceptualmente la propuesta es simple, básicamente consiste en aplicar la dinámica de Wideband Delphi pero asumiendo la premisa de PERT y pidiendo por ello que cada estimador brinde 3 valores para cada item. Adicionalmente agrego algunas pequeñas variantes a la dinámica de Wideband Delphi como por ejemplo la participación explícita de un moderador. Esto resulta en el siguiente procedimiento:

  1. Los ítems a estimar se cargan en la planilla del moderador y se le reparte un planilla impresa a cada estimador.
  2. Se discuten alguna generalidades de la estimación (alcance de los ítems, arquitectura de base, unidad de estimación, etc) y el moderador toma nota de todas ellas.
  3. Se discute el alcance de cada ítem para despejar dudas y ambigüedades de manera de asegurar que todos los estimadores esten estimando lo mismo. El moderador también toma nota de esto
  4. Cada estimador estima en forma privada y al finalizar entrega su planilla al estimador.
  5. El moderador carga la información provista por cada estimador y al finalizar comparte con los estimadores la media y el desvío obtenido para cada ítem.
  6. Mientras que haya ítems con un desvío mayor al buscado (este es un parámetro que debe definirse de antemano), los estimadores explican cómo fue que llegaron a los valores dados y se repiten los pasos 4 y 5.

Algunas consideraciones adicionales de mi gusto:

  • Generalmente propongo estimar la construcción y luego en base a ello derivar la estimación de otras actividades asumiendo un % particular para cada una de ellas  (10 % control de la configuración, 10% prueba exploratoria, 15% gestión, etc)
  • Siempre estimo esfuerzo, no tiempo ya que el tiempo depende de cómo se planifique el proyecto y la cantidad de gente que participe del mismo.
  • Suelo buscar que el desvió en cada ítem no supere el 20%
  • Me gusta utilizar este método principalmente al comienzo de los proyectos (etapa de preventa) para obtener un estimación de orden de magnitud y poder jugar con los intervalos de confianza y generar distintos escenarios para la propuesta formal al cliente.

Aquí les comparto la hoja de cálculo que suelo utilizar para aplicar este método.