archivo

Archivo de la etiqueta: MSI

Llegado un punto resulta más costoso seguir mejorando un sistema de información que los beneficios que realmente produce esa mejora.

Si el producto está consolidado los cambios serán cada vez más complejos (rizar el rizo) y responderán generalmente más a caprichos que a necesidades reales. No se trata de oponerse a la evolución sino de entender cuándo produce beneficios y cuando no.

Cuanto más grande sea el producto más complejo será mantenerlo, probablemente mayor será su deuda técnica y más complicado será para el usuario (y eso es un problema).

Cuanto más cambios hagamos más posibilidad hay de que introduzcamos errores graves en la aplicación, los cuales pueden tener un efecto bola de nieve en el sistema porque si la aplicación ha tenido éxito y tiene un amplio grado de implantación se requerirá una rápida solución y todos sabemos qué pasa cuando se va demasiado deprisa: posiblemente no se corrigen todos los errores, se introducen otros y el código no tiene toda la calidad que debería.

Desde el punto de vista del usuario nunca vas a encontrar la perfección en un software, cuando creas que al usuario no se va a ocurrir nada nuevo le surgirá una nueva idea y cuando realmente se quede sin ideas aparecerá otro con un listado sin fin (cada persona tiene percepciones y necesidades distintas).

Tampoco la vas a encontrar desde el punto de vista del desarrollador, siempre tendremos la oportunidad de mejorar el código o la arquitectura, de automatizar nuevos tests, de abstraer funcionalidades, de modificar el comportamiento de una funcionalidad o de hacer nuevas propuestas.

Donald Norman realizó una reflexión que viene a refrendar lo que comento en el artículo: «Una vez que se ha alcanzado un producto satisfactorio, realizar más cambios puede ser contraproducente, especialmente si el producto tiene éxito. Tienes que saber cuándo parar».

El desarrollo de software es un continuo adelante y detrás no solo fruto del feedback o del cambios en las especificaciones sino también como parte del proceso de construcción. ¿Quién no tiene que corregir errores?, ¿quién no mejora una sección del código que no termina de convencerle?, ¿quién no tiene que realizar ajustes como consecuencia de evolución solicitada por el área usuaria?.

Este tema lo traté en artículo: «¿Qué es el mantenimiento?» y lo vuelvo a hacer ahora porque realmente el hecho de que en el desarrollo de software la frontera entre la construcción y el mantenimiento sea tan débil (por no decir inexistente) me parece muy interesante ya que refleja un aspecto inherente al desarrollo de software como es su naturaleza evolutiva, es decir, el sistema se desarrolla poco a poco y con el paso del tiempo va adquiriendo forma, en todo ese proceso hay evolución y no solo por los aspectos funcionales (o no funcionales) que se van añadiendo, modificando o eliminando sino porque en ese proceso el software también cambia y no necesariamente para cambiar una funcionalidad (refactorización, corrección de incidencias, etc…).

Esta naturaleza evolutiva junto a otra característica inherente al proceso de desarrollo como es la incertidumbre ponen de manifiesto que el software estará sometido a cambios a lo largo del proyecto (por muy diversas causas) y que será necesario habilitar los mecanismos necesarios para que la adaptación a los mismos se realice lo antes posible.

Me gusta el enfoque que Dave Thomas da sobre este tema (traducción libre): «Si nos fijamos en el tiempo que pasamos programando, escribimos un poco y luego volvemos atrás y hacemos un cambio. O volvemos atrás y corregimos una incidencia. O lo tiras todo o lo reemplazas por otra cosa».

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).

Tenemos los extremos de tener sistemas absolutamente cerrados y tener sistemas totalmente configurables. ¿Qué extremo es el más válido? Dependerá, como es lógico, del sistema de información que se desarrolla.

Si hablamos en términos generales, un sistema totalmente cerrado, sin posibilidad de configurar nada, requiere cambios en el código para realizar cualquier tipo de modificación. En mi opinión, este comportamiento no es deseable.

Por otro lado, un sistema totalmente configurable requiere un nivel muy importante de su abstracción en su desarrollo y la definición de modelos de datos generalistas. Esto requiere un coste adicional y puede dar lugar a dificultades con la explotación de la información y el rendimiento. También, si son muchas las opciones de configuración el usuario puede perderse en ellas.

Configurable es que el comportamiento de determinadas funcionalidades, la realización de determinados cálculos o la aplicación de determinadas restricciones varíe en tiempo de ejecución (o en tiempo de arranque del servidor) pero va más allá de eso, ya que configurable también es la posibilidad de poder actualizar manualmente (sin entrar directamente en las tablas de la base de datos) los valores de las tablas maestras o de determinados parámetros. Esto que parece obvio no lo es tanto cuando ves incrustados en el código determinados dominios de datos o se le impide al usuario modificar valores de una tabla maestra.

Pese a que los generadores de código prácticamente te ahorran el tiempo de desarrollo (o buena parte de él) de la gestión CRUD existe mucha pereza en los desarrolladores a dedicarle tiempo a esto: «Total, siempre existe la posibilidad de hacerlo directamente a través de base de datos». ¿Qué pasa después? Pues que podemos tener un sistema con doscientas tablas y un montón de ficheros de configuración y a ver quién mantiene eso. Desde luego el usuario no, por lo que la responsabilidad recaerá en el departamento TIC, debiendo dedicar unos recursos a realizar estas tareas que con el paso del tiempo suponen un mayor coste del que hubieran tenido si las cosas se hubieran hecho bien desde un principio.

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.

Si no se le ha prestado mucha o ninguna atención a la deuda técnica de los sistemas que se han desarrollado para tu organización ya sea porque no se ha medido o porque midiéndola ni tan siquiera se ha analizado nos encontraremos con que la mayoría, por no decir todos, los sistemas que tienes en producción tendrán una deuda técnica superior a la que debería haber tenido incluso existiendo un contexto o contextos de desarrollo desfavorables.

Esta deuda técnica tiene un impacto directo en el mantenimiento y evolución de los sistemas: cuesta más hacerle los cambios y existe una mayor probabilidad de que los mismos provoquen efectos colaterales y nuevos errores.

Es como la gasolina, céntimo a céntimo y parece que no te duele, pero duele.

Los clientes ignoran la deuda técnica pese a que cada vez notan como los costes de mantenimiento son mayores y los pasos a producción son cada vez menos limpios. Se centran en aspectos funcionales y no entran a valorar las posibles causas que provocan ese problema.

Pero hay algo que considero casi más grave que lo anterior y es que los proveedores, en la mayoría de los casos, también la ignoran y asumen mantenimientos sin valorar y evaluar qué se van a encontrar detrás. Como en el presupuesto no se habrá tenido en cuenta la deuda técnica al final será insuficiente para el alcance previsto y provocará, además del consiguiente desgaste con el cliente, una pérdida en la calidad del producto (y a la vez un nuevo incremento no proporcional a los desarrollos realizados).

Que el software se deteriora conforme se va evolucionando es un hecho a partir del momento en que el sistema tiene implementadas el conjunto de funcionalidades que el usuario realmente necesita (el problema de esto es que casi siempre resulta complicado saber cuándo se llega a este punto y que incluso llegando a él habrá funcionalidades adicionales a las estrictamente necesarias que también se habrán implementado).

Este deterioro es aplicable a nivel funcional (se implementarán nuevas funcionalidades muchas de las cuales serán innecesarias, lo que hará más complejo el uso del sistema, introducirá nuevos errores y provocará probablemente efectos colaterales) y técnico (antipatrones ancla de barco y lava seca, incremento de la complejidad, etc…).

Hablo en términos generales, ya que incluso en estos casos es posible mejorar el sistema en ambos aspectos.

Ahora bien, me parece muy interesante poneros la siguiente reflexión de Dave Thomas, ya que la deuda técnica es una resistencia que tiene el software pero de cara a su evolución y en ese sentido es importante tenerla en cuenta, no obstante la deuda técnica no actúa si el software está en reposo (eso de que no actúa también es relativo ya que un sistema con una deuda técnica alta es serio candidato a dar muchos problemas) si vemos dicho concepto desde el punto de vista de la mantenibilidad: «La métrica del coste del cambio empieza a correr cuando tomas una decisión. Si no tomas una decisión, entonces no hay nada que cambiar y la curva contínúa plana».

Por tanto, la degradación no debería considerarse función del tiempo sino de la evolución. Sin embargo se asocia generalmente con el tiempo y tiene una cierta lógica ya que la evolución es consecuencia de actuaciones que se realizan en el sistema conforme avanza el tiempo.

Para Brian Kernighan el control de la complejidad es la esencia de la programación.

Complejidad supone más esfuerzo en la construcción y en el mantenimiento, más probabilidad de que existan errores y sistemas de información más complicados de utilizar para el usuario.

La complejidad es resistencia al progreso en el desarrollo y resistencia cuando se trata de adaptarnos al cambio.

La complejidad es agotadora para los desarrolladores y una carga que lleva el producto durante todo su ciclo de vida.

Es necesario hacer un esfuerzo en todas las etapas del proyecto, desde su concepción hasta su entrega con el objetivo de encontrar la solución más simple que satisfaga las expectativas del usuario (y que permita un mantenimiento lo más simple posible ajustado a las características del sistema).

Buscar lo más simple implicará entender bien los procesos de fondo que informatiza el sistema, pensar en el usuario, pensar en el software es susceptible de ser modificado en todo su ciclo de vida, pensar en que hay que ser prácticos (tanto desarrolladores como usuarios) y no llenar el producto de funcionalidades que no se utilizan o que van a tener un uso residual.

De igual manera que resulta complicado realmente distinguir el desarrollo y el mantenimiento de software (en general y sobre todo en enfoques iterativos e incrementales), resulta complicado establecer una barrera entre lo que son requisitos y modificaciones, una vez que se ha definido un alcance inicial del sistema o se ha realizado una iteración.

Se podría considerar requisito si supone algo nuevo, aunque no deja de ser una modificación de una idea de base.

¿Tiene importancia establecer (o no) una diferencia entre uno y otro? Es cuestión de enfoque.

Yo sigo utilizando la palabra requisitos, ya que son tantos años usándola que me resulta complicado no hacerlo, sin embargo mi visión general de los mismos no es clásica o al menos no lo es, como decía antes, desde que se determina un alcance inicial del sistema, en mi opinión su tratamiento debería ser como modificaciones y las mismas no requieren de la formalidad de una ingeniería de requisitos: ¿hay que realizar una modificación? Hagamos lo necesario para llevarla a cabo.

Una cosa es que opine así y otra diferente que siempre pueda trabajar así, el contexto condiciona, las reglas de desarrollo de la organización también.

Hay muchos desarrolladores que aplican TDD en sus desarrollos o, al menos, desarrollan pruebas unitarias para el software que están implementando.

Sobre ambos aspectos TDD (las pruebas unitarias se construyen antes) o las pruebas unitarias en general hay defensores y detractores y como suele suceder en tantos aspectos, no hay una verdad absoluta, sino que la aplicación o no de estas estrategias dependen del contexto en que se realiza el desarrollo, del tipo de sistema y del equipo de programadores.

Pese a que hablo de contexto incluso en situaciones favorables existen reticencias por muchos desarrolladores que lo consideran una pérdida de tiempo o una carga que llevar encima desde que se implementan, sin embargo quienes lo utilizan y lo consideran como una actividad más dentro de la programación lo suelen aplicar prácticamente en cualquier contexto.

No voy a defender a unos o a otros, cada cual tiene su criterio. Desde mi punto de vista la posibilidad de realizar testing unitario y su automatización supuso en su día una revolución en el desarrollo de software y en el mantenimiento de sistemas porque todo lo que sea establecer controles que permitan construir sistemas más robustos y entregar productos con menos errores debería ser bienvenido

Martin Fowler como buen defensor de estas prácticas realizó la siguiente reflexión sobre los frameworks de pruebas unitarias: «Nunca en el campo de desarrollo de software tantos le debieron tanto a tan pocas líneas de código».