Supón que sigues todas las guías de estilo, eres "clean", cuidadoso, fiel seguidor de TDD, conoces tu plataforma, ... pero, aun así, por una extraña razón, con el tiempo tu sistema se tambalea, o debes perder mucho tiempo en refactorizar, o el número de tests hace que tus despliegues demoren horas, o cada vez te resulta más confuso ver la mejor forma de introducir mejoras, ... ¿qué ha fallado?
No estoy hablando de cuando se hacen las cosas mal (en que es más o menos obvio que tarde o temprano se pierda el control), estoy hablando de cuando las cosas se hacen bien o, al menos, se han seguido los cánones marcados por la industria. No es infrecuente perder el control de un proyecto y ocurre en una gran variedad de ámbitos, equipos grandes o pequeños, en grandes y pequeñas empresas, con recursos y sin recursos.
¿Qué es la fragilidad del software?
La fragilidad del software representa una propiedad global de un sistema (de software), pero no de lo bien o mal que funciona, sino de la capacidad del mismo para adaptarse a algún cambio. Así, un sistema puede ser muy robusto, tolerante a fallos, rápido, ... y, aun así, ser tremendamente frágil. Si cuando de un sistema que funciona bien (razonablemente, bien o muy bien) se dice "mejor no tocarlo", es porque ese sistema es frágil.
La fragilidad del software da idea de la capacidad de un sistema de software para adaptarse a algún cambio
Si definir la fragilidad del software resulta bastante sencillo (tolerancia al cambio), determinar y/o identificar sus causas resulta tremendamente complicado ya que existen innumerables razones por las que un sistema se vuelve frágil, pero además, dichas razones están con frecuencia interrelacionadas (enrevesadas mas bien) de modo que, por ejemplo, alguien podría pensar que un sistema es más frágil cuanto más tiempo transcurre sin mantenimiento (por ejemplo, porque la plataforma de desarrollo evoluciona y debe guardarse, recuperarse o reinstalarse una versión acorde a dicho sistema), pero no es menos cierto el recíproco, que un sistema es más frágil cuanto más modificaciones sufre (por ejemplo, si no mantenemos la probabilidad de detectar y corregir por encima de la de introducir errores, los errores, sólo pueden aumentar con el tiempo).
Por el ejemplo primero queda claro que no es suficiente con "no tocar nada" para que no aumente la fragilidad de nuestro software (¡aumentará aunque no modifiquemos nada!) y por el segundo que la fragilidad aumentará o disminuirá de acuerdo a un complicadísimo juego de malabares entre una aparente infinidad de factores interrelacionados (enrevesados).
no es suficiente con "no tocar nada" para que no aumente la fragilidad de nuestro software
¿En qué me afecta la fragilidad del software?
En primer lugar decir que, el que no te sientas afectado (no percibas síntomas de fragilidad en tus softwares) ya es un síntoma de que (quizás) estés ignorando la fragilidad del software, en el sentido de que puedas estar derrochando recursos (muy probablemente), no obstante, es sin duda el mejor punto del que partir (siempre que ese derroche sea asumible).
Sin embargo en general (con excepciones por supuesto) y en todo tipo de países y empresas (ojo, en mi subjetiva experiencia), los sistemas frágiles están a la orden del día, y existe una clara intención (que sea consciente o inconsciente lo desconozco) de mantener un equilibrio entre los costes y la fragilidad del sistema de tal forma que el patrón habitual suele ser rentabilizar el sistema al máximo y por tanto, asumiendo muchos inconvenientes que no son populares (a.k.a son vergonzantes) en el mundillo. Decidir si es un acierto o una equivocación a mí me parece que es mucho más difícil de lo que parece, porque aunque seguro que todos tenemos en mente proyectos que han sido un desastre, lo cierto es que esas empresas funcionan y ganan mucho dinero con esos sistemas tan frágiles. Si les afecta, no lo parece mucho.
esas empresas funcionan y ganan mucho dinero con esos sistemas tan frágiles
Por otro lado, también hemos comentado que aunque un sistema no se modifique (no sólo el codebase, me refiero a todo el sistema, incluyendo hardware, personal, etc...), la fragilidad aumenta, aunque en dicho caso, no se sufre (manifiesta) dicha fragilidad. Un ejemplo podrían ser los videojuegos, la gran mayoría de los juegos poseen una fragilidad "latente" bastante elevada (no tan grande como cabría esperar porque suelen ser "cajas negras", compárese dicha fragilidad con aquellos que requieren un servidor para funcionar...) pero el mecanismo de la emulación, permite congelar ese estado y la fragilidad de todos los juegos emulados pasa a ser la que tenga el emulador.
Por tanto, que la fragilidad exista en mayor o menor medida no parece ser tan relevante como que tenga un efecto real sobre nuestros objetivos. ¿No estaría bien poder determinar o regular en qué medida me va a afectar la fragilidad de mi sistema?.
¿Qué hace frágil un sistema?
Que yo sepa, nadie lo sabe, es decir, está claro que proviene de infinidad de factores interrelacionados y trivialmente podríamos enumerar una gran cantidad de ellos, también podemos enumerar cuestiones que nos parecen obvias (muchas de las cuales son ampliamente discutidas, tan obvias no serán...), pero no hay un modelo matemático (sí algunas métricas) que describa la evolución de la fragilidad de un sistema y por tanto que nos permita hacer predicciones, como se hace con el tiempo meteorológico, y actuar anticipadamente y/o de forma inteligente (preventiva).
De todos modos, podemos enumerar algunos muy muy generales que engloban otros muchos particulares:
- fallos de software: básicamente "corner cases" cruzados entre múltiples piezas de software que a posteriori son difíciles de identificar o, aunque son identificados, son difíciles de aplicar una solución global (por las interacciones producidas).
- fallos en la arquitectura: básicamente incoherencias en el/los modelo/s utilizados a lo largo del tiempo, normalmente introducidos por desconocimiento (ej. pensar que el cliente conoce las interrelaciones de su negocio) o bien de forma consciente por imposibilidad de definir un modelo mejor, ésto tiene (al menos) dos causas no excluyentes, la falta de recursos y/o la impredictibilidad (que no es exactamente desconocimiento).
- fallos en el proceso: aquí estarían todas las técnicas englobadas por el término "buenas prácticas": clean code, documentación, patrones, testing, ...
- fallos de hardware: el software requiere un hardware para funcionar (un emulador al final corre en un hardware) y no siempre es fácil emular todo el contexto que requiere el software (por ejemplo, ya hemos comparado la fragilidad de los juegos "caja negra" y aquellos que requieren un servidor para funcionar).
- fallos de personal: no sólo de aquellas implicadas directamente en el sistema, aun cuando la "caja negra" que describe nuestro software no sufra ningún tipo de modificación, la fragilidad puede provenir del uso que terceras personas hacen de él (en el boom de las .com [en España ya en este milenio] se percibió claramente, pues las páginas web "viejas" asumían un internauta "friki" pero cada vez más internautas "normales" accedían a la red requiriendo un replanteamiento de las mismas, todo ello derivó en libros como "No me hagas pensar" de Steve Krug).
Fragilidad del software y la entropía
Si estás al tanto de la segunda ley de la termodinámica, te habrás fijado que la evolución de un sistema software y la evolución de su fragilidad tiene mucho que ver con la entropía de un sistema. Lehman indica que cuando se modifica un software, su complejidad siempre crece, pero yo (osado de mi) no estoy de acuerdo pues nuestro sistema software no está cerrado y de la misma forma que nuestra entropía decrece con nuestro ciclo vital (comer y ...; véase El camino a la realidad de Roger Penrose) podemos reducir la entropía de nuestro software a costa de aumentar (por ejemplo) la nuestra propia.
Una demostración (por fuerza informal) es que partiendo de un código vacío, podemos recorrer el ínfinito grafo de ediciones que podemos hacer sobre el mismo (por ejemplo, "v", "vo", "voi", "void" "voidm", "voidma", "voidm", "void", "void ", "void m", "void ma", "void mai", "void main", ...) y por tanto es obvio que podemos movernos a voluntad por todo el grafo, donde cada uno de los nodos corresponde a un estado de nuestro codebase (unos compilarán y otros no, unos tendrán más fragilidad y otros menos, etc...). Digamos básicamente que podemos reducir (¡o aumentar!) la complejidad (fragilidad y entropía) de nuestro software tirándola por el retrete...
Este resultado era obvio, cuanto más recursos dediquemos, más probable será (¡que no seguro!) que la fragilidad de nuestro sistema se reduzca (moviéndonos por el grafo de estados de nuestro código), la cuestión es ¿cuales son los recursos mínimos necesarios y cómo usarlos para que la fragilidad de mis sistemas estén dentro de cierto margen?.
¿Cuáles son los recursos mínimos necesarios y cómo usarlos para que la fragilidad de mis sistemas estén dentro de cierto margen?
¿Cómo minimizar la fragilidad de mi sistema?
Yo no lo se. La respuesta fácil es enumerar términos como clean, TDD, KISS, patrones, microservicios, ... pero son sólo técnicas, manifiestos, guías, ... basados en la experiencia y que pueden o no encajar con nuestro contexto particular. Obviamente usar buenas prácticas parece adecuado, pero no hay que olvidar que una buena práctica mal usada se convierte rápidamente en una pésima práctica y, además, ya hemos visto que dichas prácticas son sólo una parte, no hace mucho Google se preguntaba porqué algunos equipos de trabajo funcionan y otros no (otro factor que tiene visos de afectar a la fragilidad del producto).
Una buena práctica mal usada se convierte rápidamente en una pésima práctica
Parece entonces que hay "algo" por encima de esas prácticas que debería poder hacerse de las cuales yo veo dos sobre otras (que habrá, que yo desconozco y que puede sean más relevantes): la experiencia y sentido común de quien aplica las soluciones, pues es dicha experiencia la que sabe seleccionar las técnicas (ej. herramientas, normativa, arquitectura, ...) más adecuadas para el caso (y ésto es algo que no puede transmitirse fácilmente de unas personas a otras; los términos enumerados anteriormente apuntan a ello) y algo que sí creo firmemente que ayudaría sustancialmente a contener la fragilidad de nuestros sistemas son los estándares (porque definen autopistas sobre las que no hay margen de elección y pueden aprenderse muy fácilmente) que a nadie parece importarles demasiado o quizás nadie consigue definir buenos estándares para nuestros problemas pero, si lo piensas, son los estándares fijados hace décadas las partes de nuestros sistema que siempre funcionan y de las que ni siquiera nos fijamos (por asumidas) cuando ponemos los dedos en nuestros teclados.