archivo

Archivo de la etiqueta: mantenibilidad

¿Es el software que funciona el patrón a seguir? Para empezar deberíamos tener todos claro qué significa «software que funciona», algo que resulta tan complicado como ponernos de acuerdo en dar una definición al término calidad del software.

Un software que funciona no es un software que corra sobre un sistema operativo o a través de un navegador, sino que sirva para el propósito para el que se ha desarrollado y eso se consigue si se satisfacen las expectativas que tenían los usuarios sobre él. Y las expectativas van más allá de valores funcionales, ya que hay otros aspectos como: usabilidad, rendimiento, disponibilidad y seguridad (entre otros), que también resultan de gran importancia.

Pero un software que funciona debe ser sostenible, es decir, debe estar preparado para podamos adaptarlo al cambio si resulta preciso, esto implica que se deban tener en cuenta otros factores como su mantenibilidad, algo que está directamente ligado a su deuda técnica.

Es posible que algunos esteis pensando que estoy tratando de dar mi propia definición de la calidad del software utilizando como excusa el término «software que funciona». No lo niego, pero no es más que una visión personal en base a la visión actual que tengo del desarrollo de software, mañana puede que añada, quite o modifique matices y por supuesto, es probable, que varíe en función del proyecto.

Trabajamos para eso, para desarrollar software que funciona. Pero, ¿de qué se trata eso de que el software funcione?. Cada uno tenemos diferentes perspectivas de las cosas, esta no iba a ser una excepción, por lo que para cada uno el listón puede estar a diferente altura y no necesariamente (dependerá del momento del proyecto, del contexto, de las características del sistema de información, etc…) unos tienen que estar siempre equivocados y otros estar en lo cierto.

Siguiendo un enfoque iterativo incremental vamos a ir liberando diferentes versiones del producto hasta obtener una «versión final» (lo pongo entre comillas porque el software es generalmente objeto de una continua evolución por lo que se puede hablar de versiones finalistas de un proyecto más que versiones finales de un sistema de información).

Independientemente de que desde el primer momento intentemos liberar el mejor software posible (desarrollo con intención) es razonable pensar que en las primeras iteraciones de una aplicación el listón no esté tan alto, sobre todo en aquellos casos donde esas iteraciones no llegan a un entorno de producción o de llegar su uso está limitado a su evaluación y porque la incertidumbre y falta de acoplamiento (al proyecto y entre las personas) en los momentos iniciales hace que se falle más de la cuenta (desarrolladores y usuarios).

No se trata de relajarnos en las primeras iteraciones, no quiero decir eso, sino de entender que no todos los momentos del proyecto son iguales (ni todas las circunstancias). No hay minutos prescindibles en un proyecto porque lo perdido no se recupera y por ese motivo siempre soy partidario de ir con intención siempre sin olvidar y, eso es lo que quiero dejar patente, que como en toda carrera de larga distancia hay que saber regular (y que todas las carreras son diferentes).

Un software que funciona debe satisfacer las expectativas del usuario. Si no satisface sus expectativas tenemos un producto que hace cosas pero no tal y como las quiere el usuario. No se trata de términos absolutos sino que tenemos que tener en cuenta los umbrales, es decir, la liberación de una nueva versión puede que no deje totalmente satisfecho al usuario pero sí supere sus umbrales de satisfacción. Nuestro objetivo será que la «versión final» esté más cerca de la total satisfacción del usuario que de su umbral superior pero eso requerirá mucho trabajo, voluntad por parte de los usuarios para darnos su feedback y diferentes evoluciones del sistema.

Un software que funciona no debe quedarse solo con la parte visible del iceberg. La deuda técnica cuenta y mucho. El usuario no la ve, no la valorará y sin embargo condicionará la mantenibilidad del producto y la disponibilidad del sistema ante futuras evoluciones del mismo. Es posible que haya clientes que no la tengan en cuenta, en cualquier caso soy de la opinión de que los proveedores deben marcar unos estándares de calidad para los sistemas que desarrollan, como elemento diferencial respecto a los que no lo hacen.

Más allá de la deuda técnica se encuentra la mantenibilidad (un concepto más general). Un software que funciona debe ser lo más fácilmente de mantener posible (dentro del contexto en el que se ha realizado el proyecto) y eso va más allá de la deuda técnica pudiendo contemplar elementos documentales si así fuera preciso.

Un software que funciona debe tener también en cuenta aspectos no funcionales. Algunos de ellos están en la parte visible del iceberg (aunque tal vez en la parte de atrás, la que no se ve a simple vista o la que requiere más tiempo para ser descubierta) como por ejemplo el rendimiento o la disponibilidad y otros en la parte no visible como por ejemplo la seguridad.

Es necesario adaptarse al cambio cuando surge un nuevo contexto. Cambiar es casi siempre posible pero el tiempo y esfuerzo que se invierte en ello puede provocar que lleguemos demasiado tarde y/o que hayamos gastado gran parte o casi todo el esfuerzo disponible en ese cambio dejándonos sin posibilidades ante futuros cambios o ante la propia evolución del sistema.

No todos los cambios son iguales ya que hay contextos tan radicalmente diferentes al anterior que no hay proyecto que lo pueda sostener salvo que se redefinan las restricciones del mismo (principalmente el presupuesto).

Sin embargo cuando el cambio sea «más suave» sí que resulta necesario estar preparado para ello y no supone realmente una inversión adicional al proyecto sino que el esfuerzo destinado a ello empieza a amortizarse prácticamente desde el principio.

Sí, hablo de una arquitectura y un código que favorezcan la mantenibilidad del producto a través de una deuda técnica acorde a las características del proyecto y los recursos disponibles pero no solo se tratan de aspectos técnicos ya que un equipo (y no hablo solo del equipo de desarrollo, sino que lo extiendo también a los responsables funciones o al Product Owner y al conjunto de personas que intervienen de manera más o menos directa en la construcción del producto) que se entiende, que se comunica, en el que hay confianza y que es consciente de que puede haber cambios de contextos tomará decisiones más acertadas, de manera más rápida y pensando en el bien general.

También hablo de una adecuada gestión de riesgos. Hay cambios de contexto que suceden y es complicado tener una previsión de los mismos, sin embargo, hay otros cambios de contexto que son el resultado de la materialización de riesgos (en algunos casos pueden ser evitables y en otros caso no).

Es un caso particular del antipatrón «software inflado«, en el que se invierte más esfuerzo del necesario en hacer los productos más robustos, seguros y complejos de lo que realmente necesitan.

Pero, ¿es malo que un software sea más robusto o más seguro? En absoluto, siempre y cuando no olvidemos cuáles son sus prioridades, es decir, si hacerlo más robusto o seguro de lo que necesita implica que tengamos que invertir esfuerzo en estas actividades y restarlo de la adecuada evolución del producto, no solo no estamos haciendo un uso eficiente del presupuesto, ya que lo invertimos en actividades que proporcionan menos valor, sino que además podemos poner en riesgo la propia línea de desarrollo del sistema, si es que nos quedamos sin dinero y no hemos cubierto las necesidades funcionales más prioritarias.

A lo anterior, hay que sumarle el riesgo de que se produzca un incremento de la complejidad del producto, ya que querer hacer el sistema más robusto o más seguro, no implica que se acierte con la estrategia, técnica o programación utilizada, lo que implica que aunque se consiga ese objetivo es posible que el producto sea más complicado de evolucionar (mayor deuda técnica) o que incluso se haya invertido un esfuerzo y que el sistema se haya quedado más o menos como estaba.

Otro aspecto que no hay que perder de vista, es que llega a un momento en el que no es posible mejorar la robustez, seguridad o complejidad del sistema, ya que lo que se termina mejorando en un punto, se termina estropeando en otro (ver Ley de Tesler).

Textual. Esto me lo comentó un amigo cuando estuvimos conversando sobre la importancia de la deuda técnica en la mantenibilidad del software.

¿Cuál era el contexto de esa frase? Pues el típico proyecto Death March Project: presupuesto muy por debajo de las necesidades del proyecto, plazos irreales y un equipo de proyecto con desarrolladores de muy escasa experiencia para intentar que la diferencia entre costes y presupuesto no fuera abismal (aunque todos sabemos que lo que te puedes ahorrar en precio/hora lo vas a perder por el tiempo de más que requieren para desarrollar y por la existencia de un mayor número de errores tanto en la programación como en las tareas de análisis).

El proyecto, por tanto, estaba condenado desde que empezó y en esas condiciones casi todo eran problemas:

– Desgaste con el cliente para intentar negociar continuamente el alcance, eliminar las peticiones que van más allá de ese alcance e intentar que los cambios en los requisitos sean los menores posibles.

– Desgaste con tus jefes que no paran de apretar por las desviaciones de los costes (precisamente esos mismos jefes que habían mal vendido el proyecto) y transmitiendo continuamente las quejas de los clientes por los retrasos, por los errores de las entregas y por discutir continuamente el alcance.

– Desgaste con tu equipo al imponer un nivel de exigencia superior al que pueden dar por su experiencia y conocimientos y por hacerles ver que es necesario hacer esfuerzos más allá de la jornada laboral.

Y todo eso para desarrollar un producto que se prevé de baja calidad y que no cubrirá todas las necesidades del usuario y que estarán todavía más lejos de sus expectativas.

En medio de ese huracán tiene sentido la pregunta que da nombre al artículo.

La calidad es una inversión económica que permite a los proyectos partir de una base a partir de la cual desarrollar un software que satisfaga las expectativas del usuario y tenga una mantenibilidad adecuada a la naturaleza del sistema de información.

Si no inviertes en el proyecto, la calidad se verá mermada al tratar de hacerlo por un importe inferior o muy inferior a lo que necesita.

No todo es dinero, el proveedor también debe invertir en el proyecto poniendo el mejor equipo posible a realizarlo acorde al presupuesto disponible. Si se decide maximizar los beneficios poniendo un equipo de menor valor el equilibrio se empieza a romper y en algún momento las cuentas no empezarán a salir, sobre todo para el cliente que verá que la calidad de los trabajos estará muy por debajo de sus expectativas (y no tardará mucho en darse cuenta), pero también para el proveedor por el coste adicional que tiene no hacer las cosas bien a la primera (a la segunda, a la tercera…) y porque además se tarda más en realizar los desarrollos.

Soy de la opinión de que el equipo de proyecto debe partir de base con la actitud y aptitud necesaria para que el desarrollo de software con la menor deuda técnica posible esté integrado en su forma de concebir sus tareas, lo cual permitirá que incluso en las peores condiciones se consiga dentro de esas restricciones hacerlo lo mejor posible (las restricciones ponen el techo y si es muy bajo así serán los resultados que se podrán conseguir, pero hay que intentar estar lo más cerca posible de ese techo).

Me parece muy interesante la siguiente reflexión de Dave Thomas: «Queremos que la gente vea el software como algo más orgánico, como algo más maleable y algo con el que tengas que estar preparado para interactuar con él y mejorarlo todo el tiempo».

Esta reflexión está relacionada con una cita de Andy Hunt y Dave Thomas de su libro «The Pragmatic Programmer»: «En lugar de a la construcción el software se parece más a la jardinería» y en la justificación de dicha afirmación por parte del propio Dave Thomas (traducción libre): «En los jardines existe la suposición de que va a tener un mantenimiento constante. Todo el mundo dice que quiere un jardín que no requiera mucho mantenimiento pero al final es un jardín es algo con lo que siempre estás interactuando bien sea para mejorarlo o mantenerlo».

Yo también veo el desarrollo de software así. La realidad demuestra que los procesos que se informatizan están en continua evolución, cambian normativas, se quiere buscar una mejora continua, se quiere ser competitivo. Por otro lado el software por sus características es un elemento que puede ser mantenido y mejorado sin necesidad de interrumpir el funcionamiento normal del sistema, incluso cuando se realizan modificaciones radicales sobre el mismo (salvo en aquellos casos donde el cambio en el proceso sea tan abrupto que haga el sistema inútil de la noche a la mañana, cosa que si bien puede pasar, no es lo más frecuente).

El software va a requerir mantenimiento (o mejor dicho, evolución), por ese motivo hay que pensar en tiempo de desarrollo la estrategia más adecuada para reducir la necesidad y los costes de mantenimiento. Desarrollar dejando eso en segundo plano después cuesta mucho dinero y problemas.

Hay un aspecto importante a tener en cuenta, un software que no tiene prevista una evolución ya sea porque el proceso o procesos que informatiza ya están consolidados en la herramienta o porque no merece la pena ya que la tecnología está obsoleta (y resulta más adecuado, por tanto, hacer un nuevo desarrollo) no debería ser tenido en cuenta a la hora de plantear un programa progresivo de reducción de la deuda técnica en una aplicación.

Que no se tenga prevista una evolución no quiere decir que no vaya a surgir nunca esa necesidad, ya que basta con que lo pienses como para que mañana mismo te vengan con una petición de cambio. Ahora bien, se trata de sacar el mayor provecho posible a los medios que tengamos y para ello es necesario priorizar dónde realizar este tipo de actuaciones.

Lo normal es que si tienes previsto un plan de evolución de un producto y el mismo presenta una deuda técnica inadecuada se intente dedicar parte del esfuerzo a mejorar la misma de manera que vaya mejorando la mantenibilidad del sistema. Lo mismo no hay posibilidad de hacer un cambio en profundidad del sistema ya sea porque el esfuerzo que se puede invertir esté bastante limitado y/o porque existen fuertes restricciones temporales pero siembre cualquier mejora que se pueda aplicar se agradecerá después.

La deuda técnica condiciona el coste que tienen las tareas de evolución o mantenimiento de un software. Desde ese punto de vista todo software que sea susceptible de ser evolucionado debe tratar de mantener una deuda técnica acorde a las características del proyecto que se desarrolla y de su contexto (si los recursos para un proyecto son insuficientes la deuda técnica se verá impactada).

Ahora bien, si se trata de un desarrollo de usar y tirar, por regla general aquellas utilidades de pequeño tamaño que se hacen de manera específica para cumplir un objetivo concreto. Por ejemplo, hacer una migración o una explotación de datos no requieren un control de la deuda técnica si bien, siempre es recomendable intentar hacerlo de la mejor manera posible y si tenemos buenas prácticas de programacion, ¿por qué no aplicarlas?. ¿Qué no tendría sentido? Dedicar más tiempo del necesario para realizar ese desarrollo y por supuesto dedicar tiempo a refactorizar la solución.

¿En qué consiste anticiparse?, ¿es tener preparado todo lo necesario para cuando se produzca el cambio?. No hay respuesta general a eso pero sí diferentes reflexiones:

– No puedes prever todos los cambios que pueden producirse por lo que no puedes tener preparado todo lo necesario para todas las situaciones. Ten en cuenta que esos preparativos: planes de contingencia y de trabajo, ahorro de recursos, adaptación de la aplicación para lo que pueda venir, etc… son como tener carga en una mochila, a más peso más esfuerzo se necesita para continuar con el desarrollo hasta que se llega a un punto donde será necesario quitar carga de la misma para poder seguir.

– Hay cambios que sí son muy previsibles o muy probables y en esos casos sí que es posible o incluso recomendable que los trabajos que estemos realizando y los diferentes preparativos estén orientados a eso (si hay nubes negras y además los informes meteorológicos indican una alta probabilidad de lluvia no resulta razonable que salgas de casa sin paraguas y/o el chubasquero).

– Una gestión del riesgo eficaz deberá gestionar no solo los posibles problemas del proyecto, además deberá tener en cuenta las diferentes circunstancias conocidas que pueden provocar un cambio de contexto teniendo en cuenta que una cosa es inventariarlas y asignarle un perfil de riesgo y otra implementar las contramedidas algo que se deberá hacer en aquellos casos donde exista una alta probabilidad de ocurrencia (ya sea para adaptarnos cuando suceda o para evitarlo) y en donde exista un riesgo crítico para el proyecto (en este caso la definición y puesta en práctica de contramedidas deberá valorarse en función de diferentes factores: coste de las mismas, impacto real y probabilidad de que se produzca, etc…

– Hay prácticas que facilitan la adaptación al cambio (y que pueden ser suficientes en muchos casos) y que se amortizan desde el mismo momento en que se ponen en marcha: desarrollar software con una deuda técnica adecuada a las características del proyecto e intentar conseguir una cohesión entre los equipos de trabajo y dentro del equipo de desarrollo en los que además se fomente el hecho de que los proyectos no son necesariamente lineales ya que las condiciones iniciales pueden ser distinta de las finales.

Las expectativas del usuario y la calidad del software están muy por encima de las especificaciones funcionales, por eso que el producto final termine satisfaciendo el catálogo de requisitos funcionales (por mucho que se hayan refinado) no asegura ni el éxito del producto ni su calidad final.

Si solo pensamos en requisitos funcionales estamos limitando nuestra visión sobre lo que debe ser el producto final. Cada uno puede tener una definición de lo que considera calidad del software, en la mía no es condición suficiente la verificación de los requisitos funcionales (y probablemente muchos de vosotros estéis de acuerdo conmigo). Son importantes, no digo lo contrario, pero no es lo único.

Por un lado tenemos las expectativas que, si bien podría englobar los aspectos funcionales, contiene ingredientes adicionales como son la experiencia de usuario y la productividad en el uso de la herramienta (muy ligado a la anterior).

Y por otros los requisitos no funcionales (algunos de ellos serán detectados de manera temprana por los usuarios y podrían afectar a las expectativas del usuario sobre el producto), como por ejemplo, la mantenibilidad (deuda técnica), la disponibilidad, el rendimiento, los recursos que requiere y consume, etc…