Desde que hace una década se pusieran de moda las metodologías ágiles hemos visto cómo toda su jerga ha sido, y es, empleada a lo ancho y largo del panorama tecnológico.


Empresas que ya disfrutaban de dicha cultura desde su nacimiento, como Paradigma Digital; empresas que, con un ADN más tradicional, han comenzado el complejo camino de la transformación cultural; incluso, empresas no tan ambiciosas, al menos, han comenzado la adopción de sus métodos y terminología en un intento de maquillar con modernidad su día a día.

Cada compañía tiene su realidad y sus necesidades, pero no hay ninguna donde no haya permeado el movimiento agilista.

¿Qué es ser ágil?

Esto, como es natural, ha dado lugar a múltiples interpretaciones del propio movimiento cultural y, también, de su jerga. A pesar de existir el Manifiesto Ágil, la percepción o entendimiento que cada uno tiene sobre qué es realmente depende notoriamente cada persona y, por tanto, lo mismo ocurre en el seno de cada compañía.

En este post no hablaremos de qué es agilidad, uno de los términos más manidos durante los últimos años, ya que existen infinidad de explicaciones.

Independientemente de los matices en la definición de agilidad, lo que está claro es que para ser ágiles, todos los engranajes y resortes de nuestro proceso o sistema deben serlo.

Así, en el mundo del desarrollo de software cada parte involucrada debe permitir y favorecer la agilidad. Esto se traduce en que la cultura debe ser ágil, pero también los procesos de desarrollo y despliegue, así como la organización del trabajo y los equipos y, por supuesto, la tecnología sobre la que desarrollamos y la arquitectura de software que diseñamos.

La arquitectura de software es la disciplina focalizada en garantizar que el software disfrute de las cualidades esperadas. Estas son múltiples: la disponibilidad, la escalabilidad, la modularidad, la portabilidad, la mantenibilidad, la observabilidad, la interoperabilidad, la extensibilidad, la adaptabilidad, la estabilidad, etc.

Es importante tener en cuenta que poner esfuerzo en unas cualidades implica descuidar otras. Por ejemplo, para el software de control que va a ser embarcado en un avión probablemente la cualidad de la estabilidad es más preciada que la de la extensibilidad o la interoperabilidad.

En las sesiones de estrategia de producto es importante revisar hacía qué cualidades debe dirigirse el esfuerzo arquitectónico. No se puede llegar a todo.

Por lo tanto, ecualizar los esfuerzos hacia las cualidades del software deseadas es imprescindible e iterar sobre esta ecualización debe formar parte de la revisión estratégica del software durante su ciclo de vida.

En este post veremos qué es necesario desde el punto de vista de la tecnología para la garantizar la agilidad, pero antes nos atrevemos a dar una definición clara y concisa del término:

Es decir, centrar el esfuerzo arquitectónico en la cualidad de la adaptabilidad para lograr que el software sea fácil de adaptar tanto durante los primeros sprints como en el sprint 400, con 25 módulos interoperando y miles de líneas de código.

Necesidad de adaptabilidad

Analicemos ahora la necesidad de cambio (necesidad de adaptabilidad) en un producto. Comienza siendo muy alta y, a medida que el producto se estabiliza en el mercado (se acerca a convertirse en una commodity), se reduce durante el tiempo.

Precisamente, ocurre lo contrario con la necesidad de mantenibilidad del producto: cuando se está en fases de ideación no hay nada que mantener, la necesidad de mantenibilidad es nula, mientras que la necesidad de prototipar, adaptar o crear es muy elevada.

En el momento en que se publica la primera entrega, ya es necesario disfrutar de unas operaciones de mantenimiento competitivas, necesidad que cada vez va siendo más acuciante.

La siguiente gráfica muestra la evolución teórica de ambas necesidades desde que el producto de software es una idea, hasta que se convierte en un producto estable y, finalmente, en una commodity.

Ambas tendencias están estrechamente ligadas con las expectativas del mercado. Al comienzo, una idea innovadora que se convierte en un nuevo producto llega al mercado a precio alto. El interés que despierta alza su percepción de valor.

En esos momentos, ser capaces de adaptar el producto a las necesidades reales una vez este ha sido probado en el mercado es imprescindible (Inspect & Adapt). Subsanar posibles errores es importante, pero, sobre todo, incorporar rápido las funcionalidades que está demandando el público: innovación constante para mantener el pulso, la atracción.

Todo se traduce en tener un software adaptable, cuyos cambios se puedan llevar a cabo eficazmente y eficientemente, con agilidad.

Con el tiempo, a medida que el mercado se satura, nacen competidores con sus propias implementaciones de la idea innovadora, los clientes ya llevan comprándolo un tiempo, casi todo el mundo dispone de un ejemplar o de acceso al servicio.

La capacidad de innovación en ese estadio se reduce y las mejoras son cada vez menos significativas aunque necesarias para seguir buscando la diferenciación en una competencia cada vez más abrasiva.

Mantenibilidad

La capacidad de cambiar de manera eficaz y eficiente es relevante, pero un producto con mucha oferta necesita bajar precios. Es momento de poner énfasis en reducir, aún más, los costes de mantenimiento. Es el comienzo del camino hacia la conversión del producto en una commodity, donde solo se compite por precio.

Por ello, se hace imprescindible que los costes de operación sean bajos. La adaptabilidad ha dejado de ser la cualidad más esperada en nuestro producto de software para ceder el protagonismo a la mantenibilidad.

Aquí viene la buena noticia: desde el punto de vista de la arquitectura de software, los patrones, diseños y buenas prácticas que ayudan a la adaptabilidad también favorecen a la mantenibilidad.

Poder adaptar un sistema con relativa facilidad es siempre gracias a que:

  1. Lo modificamos sin riesgo a romperlo.
  2. No rompemos otros sistemas que dependen del nuestro.
  3. Desplegamos los cambios de manera rápida y eficaz.
  4. Solo tiene el código que necesita y este tiene una buena estructura.
  5. Sabemos qué ocurre dentro de nuestro sistema en todo momento.
  6. Conocemos fácilmente cómo está desarrollado.

Un sistema con las anteriores características tiene más posibilidades de ser adaptable y, también, mantenible. De manera que dirigir nuestro esfuerzo arquitectónico a cuidar la adaptabilidad desde el comienzo ayuda a la mantenibilidad en el medio y largo plazo, lo que lo convierte en una estrategia interesante.

Veamos ahora qué significan las anteriores premisas desde un punto de vista arquitectónico.

Lo modificamos sin riesgo a romperlo

Una aplicación es, tal y como indicó ya a finales del siglo XX Frederick Brooks, un sistema esencialmente complejo. Como sistema complejo es necesario ser ortodoxo en su diseño y desarrollo.

Uno de los motivos de la complejidad del software es la dependencia que genera entre sus módulos. Ante tanta complejidad es imprescindible apoyarse en técnicas que reduzcan la incertidumbre de no saber si hemos afectado al software negativamente tras una modificación. Esto es, precisamente, lo que aporta tener una ambiciosa batería de pruebas automáticas.

Una batería de pruebas automáticas bien diseñada y con amplia cobertura permite al desarrollador comprobar, cuando ha aplicado el cambio sobre el software, si este cambio funciona según lo esperado.

Pero, además, permite conocer si el resto del sistema se ha visto afectado negativamente, aspecto que reduce notoriamente la incertidumbre y los riesgos de modificar un sistema.

Trabajar sin la incertidumbre de romper el software tras un cambio significa adaptarlo de manera más eficiente y más barata.

Si en el mundo hay incluso movimientos Tierraplanistas, es de esperar que las pruebas automáticas tengan sus detractores. Un argumento ampliamente empleado por ellos es la doble inversión necesaria: al final mantienes dos softwares, el producto y sus pruebas.

Visto así, podría parecer un argumento de peso, pero olvidan que la inversión necesaria en pruebas garantiza menos riesgo en los cambios y, esto, a su vez, más adaptabilidad, lo que supone mejor time to market y favorece la innovación.

Ambos aspectos hay que llevarlos al business case y en la mayoría de los casos “las pruebas se pagan solas”. Además, existe una técnica más avanzada en el mundo del testing, el Test Driven Development, técnica que logra incrementar la rentabilidad del testing porque mejora cuantiosamente la calidad del código, lo que a su vez reduce sus costes de mantenimiento y, por supuesto, su adaptabilidad.

No rompemos otros sistemas que dependen del nuestro

Modificar un sistema no solo pone en riesgo su propia estabilidad, también la de otros sistemas que puedan depender del mismo.

En el problema de la dependencia entre sistemas es importante entender que las interfaces con terceros generan parcelas del sistema cuya adaptabilidad es menor que la de otras parcelas no interconectadas externamente.

La adaptabilidad se reduce cuando el roadmap de un sistema afecta al de otro. Realmente, las interfaces que interconectan sistemas externos son solo la punta del iceberg de todo un área de nuestro software cuya adaptabilidad está supeditada a adaptabilidad de los sistemas con los que lo integran.

Dicho de otra manera, la cualidad de la interoperabilidad es inversamente proporcional a la cualidad de la adaptabilidad. Una aproximación ambiciosa para mantener gestionada, en la medida de lo posible, la dependencia entre sistemas de modo que se fomente la adaptabilidad es el patrón Consumer-driven Contracts.

Esta práctica permite que el servicio sea probado desde la óptica de su cliente, pues el sistema servidor incorpora en su batería de pruebas los test automáticos de sus clientes.

Implica la certeza de saber qué interfaces de las que tiene publicadas (datos, funcionalidad) son realmente usadas por terceros, cómo se están usando y si, dichos usos, siguen funcionando tras una modificación en el servicio.

Otra práctica imprescindible es el gobierno de las interfaces: estandarizar las arquitecturas empleadas para interoperar (datos por un lado y funcionalidades por el otro) y, así, evitar la proliferación incontrolada de punto de interconexión con otros sistemas, las famosas interfaces punto a punto.

El empleo de interfaces punto a punto es un anti-patrón que redunda en el encarecimiento del evolutivo de los sistemas que conectan.

Versionar las interfaces ayuda a la adaptabilidad del sistema, pero no se debe olvidar la importancia de publicar y cumplir de manera tajante la política de versionado de las mismas.

La práctica de versionar está muy extendida en el mundo de las APIs tipo REST, pero no es tan usual en la parcela de los datos (batch) o los mensajes. Cuando dos sistemas se relacionan entre sí porque uno emite un dato o mensaje ambos quedan acoplados.

Versionar los esquemas de los datos extraídos en modo batch, así como el esquema de los eventos emitidos, es igual de importante para la adaptabilidad como versionar las APIs de tipo REST.

Desplegamos los cambios de manera rápida y eficaz

Una vez escritos los tests correspondientes y desarrollado el propio cambio es hora de desplegar. El despliegue debe realizarse de manera rápida, pero también ajustada al cambio que se ha realizado; es decir, debe ser eficaz.

Gracias a la infraestructura como código, los gestores de configuración y las pipelines de despliegue se lleva a cabo de manera automática, cocktail que reduce enormemente el tiempo necesario y, lo que es más importante, evita errores humanos.

Además, el hecho de que el despliegue sea convertido en código que se puede versionar permite rollback, es decir, echar marcha atrás en caso de que algo haya salido mal. Son todo ventajas que nos ayudan a cambiar (o adaptar) con más seguridad, menos riesgo y más barato.

Por otro lado, es importante afinar los despliegues. No debería ser necesario desplegar el producto completo cuando el cambio ha sido solo en uno de sus módulos.

Así, debemos diseñar nuestro producto de manera modular lo que, entre otras cosas, favorece el hecho de reducir el despliegue al módulo que ha sido modificado. Los pipelines de despliegue automático deben partirse por módulos también.

Existen todavía modelos organizativos (normalmente en grandes compañías) en los que se exige que los despliegues a producción sean autorizados por una mesa redonda de “mentes pensantes” (en ITIL se llama Change Advisory Board - CAB -).

Esto podría ser considerado un antipatrón porque alarga el tiempo de despliegue y deslocaliza la toma de decisiones.

Para mitigarlo, es decir, mantener la autonomía de los equipos para desplegar en producción su propio producto y además permitir que el CAB (o equivalente) mantenga la capacidad de vetar un despliegue, se puede hacer lo siguiente: el racional empleo por el equipo CAB para aprobar o no un despliegue se convierte en una serie de reglas de decisión.

Estas reglas se incorporan al pipeline de despliegue de cada producto como si de tests se trataran. Esto mantiene el automatismo, mantiene la autonomía del equipo para desplegar y mantiene el control del propio CAB. Es una manera de reducir la burocracia propia de ITIL a partir de los automatismos que nos aporta Devops.

Solo tiene el código que necesita y este tiene una buena estructura

Desde el punto de vista del diseño de sistemas con foco en la adaptabilidad SOC - Separation of Concerns - es un ingrediente imprescindible.

A lo largo de la historia de la informática, las propuestas arquitectónicas siempre han buscado técnicas para separar el software en módulos:

Sea para lo que sea, el software modular necesita de una buena gestión del SOC. Esto significa mantener muchas conversaciones profundas a la hora decidir qué responsabilidad y funcionalidad debe tener cada módulo. De lo contrario, es fácil que una funcionalidad afecte a varios módulos, lo que complica tanto reutilización como la adaptabilidad de los mismos.

Paralelamente a lo anterior, el desarrollo de software siempre está muy centrado en la incorporación de nuevas funcionalidades. Es difícil encontrar entornos cuya cultura fomente, precisamente, lo contrario: eliminar funcionalidades que ya no se usan.

Lo normal es que las compañías tengan la tendencia a acumular código y aplicaciones, como si sufrieran del síndrome de Diógenes.

Cada línea de código es un lastre que dificulta la adaptabilidad y reduce la mantenibilidad total del sistema. Escribirla implica, inmediatamente, el compromiso de mantenerla en el tiempo con la condición de que sea usada, cuanto más mejor (maximizar su amortización).

Es más que sano fomentar la cultura del desmantelamiento de lo que ya no sirve. Establecer procesos gamificados que ayuden a mantener exclusivamente la base de código que realmente está entregando valor al negocio.

La modularidad es un cualidad del software que genera complejidades, pero también trae muchas ventajas. Las arquitecturas basadas en microservicios persiguen la adaptabilidad máxima del software, la independencia entre sus módulos y la escalabilidad; evitando no incurrir en mayores problemas de observabilidad y orquestación, entre otros.

Una tendencia que está cogiendo fuerza son los Micro Frontends, cuyo leitmotiv es llevar los principios de los microservicios a las interfaces gráficas (web, móvil, etc). Al final son propuestas que ponen en solfa la arquitectura de software en la búsqueda de alguna cualidad en este caso, de nuevo, la adaptabilidad, pero esta vez en la capa de front.

Sabemos qué ocurre dentro de nuestro sistema en todo momento

Telemetría y observabilidad son las nuevas palabras de moda (buzzwords) alrededor de la monitorización. Las arquitecturas distribuidas han traído nuevos retos en esta parcela.

Es complejo entender qué está pasando en un sistema formado por módulos autónomos pero dependientes, donde a veces el número es muy elevado. Entender qué ocurre dentro de nuestro sistema es imprescindible para que este sea fácil de adaptar y mantener.

Aunque no nos dejemos distraer por palabras y tendencias rimbombantes, empecemos por detalles básicos como la política de logado: tipos de logs, convenio para cada tipo de logs, convenio sobre cómo publicar los logs, convenio sobre los niveles de log y, sobre todo, reforzar la cultura de la verbosidad.

La verbosidad entendida como la costumbre de escribir código que habla de su comportamiento. Para ello, es necesario todo lo arriba indicado sobre los logs y, además, llegar a acuerdos sobre cómo el propio código debe exponer las métricas de su ejecución.

Estas métricas deben cubrir aspectos técnicos, como número de mensajes o estado. Pero también aspectos más propios de cada dominio funcional. La verbosidad ayuda a la adaptabilidad porque permite entender cómo está desarrollado un software y cómo se comporta antes y después de cada adaptación.

Existe otra vertiente de la observabilidad del sistema que está centrada en conocer cómo se está empleando dicho producto, cuáles son las funcionalidades más empleadas, cuáles las menos e, incluso, cuáles son las olvidadas por los usuarios.

Es interesante pues nos ayuda a conocer qué funcionalidades no se están usando y, por lo tanto, podemos desmantelar, lo que ayudará a la adaptabilidad y mantenibilidad.

Conocemos fácilmente cómo está desarrollado

Aquí es donde llega el apartado de la “maravillosa” documentación. En más de una ocasión me ha llegado el mantra de que los desarrolladores no deben documentar porque no son los mejores escritores y pierden el foco en el desarrollo.

Mi opinión es justo la contraria. Es verdad que un desarrollador puede pecar de estar muy sesgado por su posicionamiento y escribir textos técnicos en los que se da por hecho un grado de conocimiento muy profundo, lo que complica la lectura de la documentación a los neófitos. Esto es un problema real, pero con la práctica se entrena y evita.

Enseñar a un técnico a contextualizar la documentación y a emplear ciertas técnicas para abstraer el discurso y para ayudar a la compresión del documento es una inversión imprescindible. Inversión imprescindible porque el que mejor sabe y puede describir cómo funciona el software es su propio creador.

Además, con la documentación ocurre algo parecido que con el testing: el entregable es un subproducto en el que hay que invertir tiempo, pero que si se hace antes que el propio código lo mejora significativamente y ayuda a que el código esté diseñado para ser leído. Son conceptos tan parecidos que existe el Documentation Driven Development, de la misma manera que existe el TDD (arriba comentado).

Creo que no hace falta repasar, en términos generales, para qué es necesaria la documentación. Es obvio que para el asunto que nos ocupa, la adaptabilidad y, por ende, la agilidad, tener un software bien documentado facilita, sustancialmente, el acceso a comprender cómo está desarrollado y, por lo tanto, a cómo actuar para adaptarlo.

No puedo cerrar el apartado de la documentación sin aludir a otro mantra que nace de una mala interpretación del segundo valor del agilismo: software funcionando sobre documentación extensiva.

No son pocas las personas que, erróneamente, consideran que este valor desprecia la documentación y que, por consiguiente, esta no es necesaria ni deseada en entornos ágiles. Nada más lejos de la realidad.

El manifiesto indica que prefiere el software funcionando, pero eso no significa que la documentación esté fuera de su interés. Puede que sea un problema en la redacción del propio manifiesto. Lo que está claro es que el software necesita la documentación pues ayuda a la adaptabilidad, tal y como se explica anteriormente.

Conclusión

A parte del desarrollo de la funcionalidad esperada del software que estemos desarrollando, es imprescindible poner foco en las actividades arriba descritas para garantizar en el tiempo la agilidad de nuestro proyecto.

Aunque los stakeholders muchas veces tengan la mirada centrada exclusivamente en la funcionalidad de negocio que da sentido al software en el que invierten, es importante ayudarles a entender el impacto de ningunear la calidad del sistema. De no hacerlo, se acabará incurriendo en una deuda, la deuda técnica.

Referencias

Cuéntanos qué te parece.

Enviar.

Los comentarios serán moderados. Serán visibles si aportan un argumento constructivo. Si no estás de acuerdo con algún punto, por favor, muestra tus opiniones de manera educada.