Hace unos años (no tantos) era relativamente raro que al desarrollar una aplicación se prestara mucha atención a aspectos como la tolerancia a fallos, la escalabilidad, etc. Es cierto que había aplicaciones que sí requerían de estas características, pero la gran mayoría de aplicaciones que se desarrollaban acababan instaladas dentro de las empresas, con un sólo servidor y, bueno, de aquella manera.
Hoy en día, con la llegada de la nube (el cloud computing que dirían los que te la quieren vender), parece que la tolerancia a fallos, la escalabilidad y demás son características fundamentales y críticas para cualquier aplicación, incluso para la web de la mercería de la esquina, y todo el mundo está muy familiarizado y concienciado con estos conceptos.
Ahora que todos tenemos claro que es fundamental que los sistemas de los demás tengan esa solidez y robustez, llega el momento de pensar un poco en nosotros, ¿cómo de tolerante a fallos y escalable es tu equipo de desarrollo?
El problema son los humanos
Al hablar de fallos de un equipo de desarrollo podemos pensar en mil tipos de contratiempos, pero en este caso me quiero centrar en el aspecto humano, porque por mucho que les pese a algunos, un equipo de desarrollo no está formado por recursos, sino por humanos, y los humanos son problemáticos de manejar. Además, me gustaría centrarme en factores internos al equipo, asumiendo un mundo de fantasía en el que el entorno ayuda al equipo de desarrollo en su trabajo.
¿Qué pasa si mañana desaparece uno de los miembros del equipo? ¿Y si es “el que sabe” (llámalo líder técnico, arquitecto o lo que más te guste)? ¿Y si desaparece más de uno? ¿Cuál es el factor autobús de tu equipo?
Esto es algo que puede pasar en cualquier momento. No se trata de que lo abduzcan, pero puede cambiar de trabajo, mudarse a otra ciudad, tocarle la lotería o simplemente hartarse. Esto acabará ocurriendo antes o después y debemos estar preparados para ello.
Un problema muy frecuente ante este tipo de situaciones es que, de repente, ya nadie sabe cómo mantener y modificar el código que manejaba esa persona. Eso hace que «su parte» del sistema se vaya degradando poco a poco porque nadie se atreve a meterle mano, los bugs se acumulan y llega un momento en que la situación estalla.
Redundancia y balanceo de carga
La forma más directa de evitar esto es evitar que nadie posea «su parte» del sistema. En terminología de eXtreme Programming, esto sería fomentar la propiedad colectiva del código y hacer que todo el mundo toque (o sea capaz de tocar) todo el código.
Si el proyecto es muy grande, es imposible que todo el mundo toque todo el código, pero debemos intentar que siempre haya más de una persona que pueda modificar cada parte. Si aplicamos técnicas como la programación por parejas o las revisiones de código tendremos mucho ganado, porque todo el código lo habrán visto al menos dos personas.
Hay que tener en cuenta que esto es aplicable a todo lo que comprende el sistema, no sólo el código en C# (o Java), sino también el HTML, el CSS, la base de datos, los scripts de instalación, el script de compilación, etc.
Tener un experto nivel 50 en CSS y que nadie más sepa centrar un div lo que hace es introducir un punto único de fallo en el sistema, es decir, en el equipo de desarrollo, y si la persona que desaparece del equipo es el experto en CSS, tendremos un problema bastante serio.
Una ventaja adicional de emplear este solapamiento de roles es que nos permite balancear la carga entre todos los miembros del equipo. Si cada miembro del equipo es experto en una cosa, podemos tener situaciones en que haya personas que están colapsadas de trabajo mientras otras no tienen nada que hacer porque no se está tocando su área de experiencia. Por el contrario, si todos los miembros del equipo son flexibles, siempre podrán echar una mano en las áreas de la aplicación que así lo requieran en cada momento.
Existe otro enfoque para este problema, que es el de commoditizar a los desarrolladores, asumiendo que no tienen valor intrínseco y que lo único que necesitas cuando se marche un desarrollador es contratar a otro y ya está. Aunque este enfoque tan típico en determinados círculos cárnicos pueda resultar rentable económicamente, técnicamente no suele funcionar muy bien.
Independientemente de lo bueno o malo que sea el desarrollador que estamos reemplazando, si lleva algún tiempo en el equipo habrá adquirido una serie de conocimientos sobre la aplicación y los habrá plasmado en su código, mientras que alguien que parta de cero deberá empezar por adquirir esos conocimientos.
Si además la persona que se está reemplazando no era muy bueno técnicamente o no comprendía bien lo que estaba implementando, seguramente su código y su diseño sean más complicados de entender para quien lo sustituye, entrando en una especie de círculo vicioso que acaba produciendo un código… como el que se suele ver en proyectos gestionados así.
Documentar o automatizar
En realidad, si profundizamos un poco en el problema podemos llegar a la conclusión de que el mayor inconveniente no es que falten una o más personas, sino que hemos perdido el conocimiento que tenían esas personas.
Ya hemos visto que lo ideal es evitar ese punto de único de fallo, pero si no podemos permitírnoslo, una alternativa es el uso de documentación para facilitar la transmisión de conocimiento cuando un miembro deja el equipo.
El problema que tiene la documentación es que es costosa de generar y aún más costosa de mantener. Antes era frecuente encontrarse con documentos de análisis y de diseño llenos de diagramas UML y detalladas descripciones de casos de uso, pero esos documentos tendían a quedarse desactualizados muy rápidamente y acaban por no ajustarse al código real de la aplicación (si es que lo habían hecho alguna vez). Eso hacía que en lugar de ayudarnos a comprender el sistema, nos confundieran aún más.
Una solución a esto es contar con documentación ejecutable, es decir, tests automatizados, que sirvan a la vez para documentar el sistema y para darnos cierta confianza a la hora de introducir partes del sistema con las que no estamos muy familiarizados.
Esto no sólo es aplicable al código como tal, sino también a los procesos que hay alrededor, como la generación de la documentación, de los instaladores, el paso a producción, etc. Si todos esos procesos están automatizados, aunque perdamos al «experto en despliegues» podremos poner una versión en producción ejecutando un simple script. Al final tendremos que comprender cómo funciona ese script para poder mantenerlo, pero al menos habremos ganado tiempo.
Conclusiones
Igual que una aplicación puede estar diseñada para que resista mejor los contratiempos, un equipo de desarrollo puede tomar medidas que le permitan sobrevivir a momentos complicados.
Aplicando conceptos similares a los que usados al diseñar una aplicación podemos analizar cuáles son los factores de riesgo, detectar los puntos únicos de fallo y tratar de buscar medidas que nos permitan limitarlos.
Documentar todo lo que hacemos puede resultar de ayuda para transmitir el conocimiento cuando un miembro deja el equipo, pero el coste de mantener esa documentación es tan algo que pocas veces merece la pena, por lo que tratar de automatizar en lugar de documentar es una buena salida.
Hasta ahora nos hemos centrado en la parte de supervivencia, pero hay otro factor que podemos asimilar entre aplicaciones y equipos de desarrollo: la escalabilidad y cómo podemos preparar un equipo para crecer, pero eso lo dejaremos para un próximo post.
Hola, como estas? Me presento mi nombre es Magdiel y quería compartir con vosotros una experiencia y reflexión personal surgido debido a lectura de este post. En uno de mis trabajos, lamentablemente en Venezuela, mi país, está presentado una difícil situación económica que ha obligado a mucho a tener varios empleos. Continuando, se nos contrató para desarrollar una aplicación con unos requerimientos especiales. El equipo de desarrollo decidimos, ósea Nosthertus y mi persona, utilizar una arquitectura rest-ful basada en Node.js, si bastante originales en estos tiempos por cierto.
Ya habíamos utilizado Express en otras oportunidades y queríamos observar si fuera de mainstream que este representa si realmente era el mejor framework para desarrollar nuestra aplicación. Se consideraron varios asuntos, como rendimiento, peso en Kb del framework, si disponía de middley way, entre otras cuestiones. A la final elegimos e framework diet.js aquí te dejo la página por si te interesa revisarlo http://dietjs.com/ si post con cuña incluida jejeje.
Bueno, eso que tu comentas de documentar lo considere en el transcurso del desarrollo del proyecto y decidimos implementar una documentación para nuestra API también se consideraron varias opciones pero a la final se eligió por raml, http://raml.org/ más publicidad pero prefiero contextualizar claramente. La decisión presento una dificultad, no existen herramientas de automatización para a partir de la documentación ayudar en el proceso de desarrollo del rest, en Express si existen dichas herramientas, eso nos pasa por hípster jejeje.
Bueno, tomamos la decisión de crear nuestro propio generado de rutas partir del documento raml pasándose en el framework diet.js, ha ya se entiende porque tanta publidad, verdad? Bueno te comparto e invito a que te eches una pasada por el generador, aun esta en alfa y tiene muy poca documentación, error responsabilidad únicamente mía pero pronto la documento. No obstante, aceptamos todo tipo de sugerencias que nos ayude a mejorarlo. https://github.com/Nosthertus/diet-raml-generator
Bueno todo esto, fue la introducción mi punto es que en el transcurso del desarrollo de la aplicación usando nuestro generador se han presentado no pocos casos que los cuales por errores de diseño, cambios de requerimientos, entre otros motivos se han ido actualizando el router directamente. Dejando la documentación inicial un tanto desfasada con respecto al estado actual de la aplicación, si bien es cierto yo he estado como guardián de la misma usando tus principios expuestos yo no debería un punto único de fallo.
Esto me lleva a pensar en un nuevo desarrollo que consuma el router y algunos trozos del middley para generar una documentación raml. Este paso inverso es sustancialmente más complejo que la implicación directa ya realizada, en especial porque no se tiene un parser sobre el cual basarnos para la realización del mismo. Pero quería saber que opinabas de esta idea que me surgió a raíz de tu interesante artículo.
Antes de despedirme quiero agradecerte por estos interesantes artículos que públicas, aunque uno lee muchísimas cosas en ingles siempre es agradable leer algo en su lenguaje original en especial esta parte blanda de la computación que no tiene una recompensa directa, como por ejemplo leerse la documentación de X lenguajes o framework.