archivo

Archivo de la etiqueta: deuda técnica

Es importante tener en cuenta segundas o terceras opiniones y reflexionar sobre la posible solución a un problema cuando la misma parece compleja a priori y por tanto requeriría un esfuerzo significativo para su realización.

Este ejercicio puede ahorrar días o incluso semanas de programación a lo que habría que añadir que probablemente la solución más simple tenga aparejada una menor deuda técnica.

Es posible que la solución simple implique alguna modificación sobre la dinámica de funcionamiento de la solución que especificó el usuario (es decir, que no sea un aspecto exclusivamente técnico), en estos casos es fundamental exponérsela y probablemente la acepte siempre y cuando la finalidad de la funcionalidad no varíe, hay que tener en cuenta que el usuario cuando realiza la especificación, por más que incluso la haga debatiéndola contigo, no tiene en consideración todas las opciones posibles sino la que en ese momento le viene a la cabeza o la que estuvo pensando la semana anterior.

Si te precipitas probablemente tardarás mucho más que si se analizan las posibles alternativas de solución. Al fin y al cabo será cuestión simplemente de esperar horas o días para madurar qué camino es el más óptimo.

Siempre agradecerás una solución simple, muchas desviaciones en los proyectos se producen precisamente por no dedicar suficiente atención a disminuir la complejidad técnica y funcional.

No importa que la idea no la hayas tenido tu, lo importante es el proyecto y éste es el resultado de la colaboración de todos los que participáis en el mismo. Tenemos el síndrome de la primera piedra, que consiste en que queremos ser nosotros los que coloquemos siempre el primer ladrillo pese a que el siguiente que se ponga sea el quinientos. Es importante dejar el ego a un lado para poder escuchar a tus compañeros.

Anuncios

Como desarrolladores somos reacios a la realización de cambios y no es que seamos así genéticamente sino por el hecho de que se nos ha formado y después hemos trabajado en proyectos en donde nuestra capacidad de ser flexibles estaba muy limitada por el cumplimiento de una agenda de costes y plazos (mucho más lo primero que lo segundo).

Cuando se enfoca un proyecto con presupuestos inmovilistas y sobre todo, carentes de toda aproximación a la realidad no se puede pretender que acojamos los cambios dando aplausos porque lo que el presupuesto no cubre (hasta cierto límite, claro está) lo tendremos que cubrir con nuestro trabajo.

No se trata de trabajar con presupuestos ilimitados, sino de desarrollar con intención (que es lo mismo que tratar de desarrollar de manera eficiente) y de determinar cuándo el valor del producto es suficiente y cuándo deja de ser rentable el crecimiento del valor con respecto a la inversión que se está realizando.

Con esta visión del desarrollo del software el cambio resulta bienvenido ya que se entiende que a través de él se consigue dotar al producto de un mayor valor (como consecuencia de que cada vez se ajustará más al contexto existente y a las expectativas de los usuarios).

Ahora bien, el cambio debe hacerse con intención (evitando en lo posible las circunstancias de prueba y error) y con un sistema en los que los cambios se puedan realizar con agilidad (deuda técnica acorde a las características del sistema que se desarrolla, arquitectura y modelo de datos escalable, etc…).

Cuando uno se acostumbra a este esquema de trabajo se acepta el cambio como una parte más del proceso de desarrollo de software y efectivamente se cumple la siguiente reflexión de Ken Auer y Roy Miller: “La única manera de deshacerte de tu miedo a los cambios en el código es hacerlos una y otra vez”.

Comenta Bertrand Meyer que: “El único gran enemigo de fiabilidad (y tal vez de la calidad del software en general) es la complejidad”, y tiene gran parte de razón.

La complejidad en sus dos vertientes: incluir funcionalidades no necesarias (o hacer más complejas funcionalidades que sí son necesarias) y descuidar la arquitectura y construcción del software haciendo el software mucho más complicado de evolucionar (mayor esfuerzo y mayor probabilidad de errores).

Tenemos que aprender a ser pragmáticos, a dejar de construir la casa por el tejado, a querer rizar el rizo sin ni siquiera tener el producto funcionando y todo ello sin olvidar que si no se construye software de calidad estamos poniendo resistencia y frenos a la capacidad de adaptación y evolución del sistema.

Una solución más compleja no tiene por qué ser mejor, una solución con más funcionalidades no tiene por qué ser mejor y una solución que esté a lo último en tecnología no tiene por qué ser mejor. Lo de menos es más, no es tampoco ciencia exacta, pero la verdad es que funciona más veces de lo que creemos.

Si desarrollas una solución demasiado compleja, al final pasa como con los mandos a distancia, muchos botones, muchas funciones, pero al final no utilizas ni el 10% de ellas.

Por otro lado, añadir complejidad de manera sistemática sin tener el producto en producción supone prácticamente comprar toda la taquilla para un más que probable fracaso y con poco margen de maniobra posterior, ya que tendremos un software mucho más voluminoso que mantener (y con una mayor deuda técnica ) y habrá menos recursos económicos para hacerlo.

La tentación, muchas veces motivada por las circunstancias, es obviar la mejora de la factura técnica del producto, para centrarnos en corregir errores y en incrementar las funcionalidades.

El usuario siente la calidad del software con lo que ve: cumplimiento de sus expectativas de funcionamiento y buen rendimiento y disponibilidad, por eso pondrá resistencia a invertir tiempo en reducir la deuda técnica.

No debemos olvidar que desarrollamos para el usuario y él es quien tiene la última palabra, lo cual no quita que le expongamos la ventaja que tiene la realización de este tipo de tareas, como una inversión que permita no solo incrementar la capacidad de trabajo que puede abordar el equipo, sino además, reducir la posibilidad de efectos colaterales que provoquen errores cuando y donde menos los esperamos.

De serie, un desarrollador debe tener en cuenta estas prácticas y tenerlo en cuenta a la hora de definir su velocidad. El tiempo que se puede dedicar a esto puede ser prácticamente ilimitado porque todo es susceptible de ser mejorado, por ese motivo, ese tiempo de más sobre las buenas prácticas de programación cotidiana es el que se tiene que discutir con el cliente.

Comenta Mary Poppendieck: “La refactorización continua no es opcional. Si se elige no refactorizar se elige no pagar la deuda técnica que con el tiempo demostrará que la posibilidad de fracaso aumenta”.

La clave es mantener la deuda técnica bajo control y esto requiere un esfuerzo desde la programación de base como de las tareas adicionales de refactorización, de acuerdo siempre con las necesidades de quién paga, el cual debe estar siempre informado de las consecuencias que tiene realizar desarrollos sobre un software de baja calidad.

Su enunciado es el siguiente: “Cuando un sistema evoluciona se incrementa su complejidad a menos que se trabaje para mantenerla o reducirla”.

La complejidad crece no solo a nivel de deuda técnica (algo que es razonable por el incremento del tamaño del sistema), sino también a nivel de administración, usabilidad y recursos software y hardware necesarios para su funcionamiento.

Si se tiene cuidado y se aplican buenas prácticas, este incremento de la complejidad puede hacerse más moderado e incluso puede reducirse si se aplican medidas específicamente destinadas a este fin (que se complican cuando a la vez se están incorporando nuevas funcionalidades al sistema).

Lo que viene a decirnos (de la mano de la Primera Ley) es que con el paso del tiempo va a ser necesario evolucionar las aplicaciones y que ese coste será progresivamente mayor conforme se realicen nuevas actividades de mantenimiento en el sistema.

Para Donald Norman: “Los objetos bien diseñados son fáciles de interpretar y de comprender ya que contienen pistas visibles de su funcionamiento”.

Un código fácil de leer y de entender en entornos altamente colaborativos como son los equipos de trabajo ágiles resulta esencial. También lo es para otros tipos de enfoques.

No es sencillo, se requiere tiempo, conocimientos y experiencia, también nos podemos apoyar con herramientas que nos ayuden a aplicar buenas prácticas y también se requiere ser sistemático y creer en los beneficios que aporta hacer el trabajo de esta manera, de lo contrario se te pondrá muy en cuesta arriba refactorizar, tanto tanto, que no lo harás.

Hacer esto bien requiere dedicarle el tiempo que necesita, cuando estamos en proyectos ligados a plazos y los recursos disponibles son muy limitados, se convierte en objetivo ejecutar todo el trabajo posible y se deja de lado la calidad del código ya que en esos momentos conceptos como la deuda técnica no se encuentran entre las prioridades del desarrollador. Es cierto que es contraproducente ya que una deuda técnica elevada hace más pesado el proceso de desarrollo pero cuando el fuego te está llegando a los pies solo piensas en correr.

Por ese motivo creo mucho más en el valor del software que en las agendas, un buen software requiere del tiempo y de las personas necesarias para hacerlo, sin equilibrio la calidad del software sufre (también la cuenta de resultados del proyecto).

Resulta complicado que no lleguen defectos a producción. Llegado a un punto, la inversión a realizar para tratar de que el número de defectos que lleguen a producción sea cero, crecerá exponencialmente, si bien, no se trata solo de echar dinero, sino de hacer las cosas bien, y mucho mejor si se hacen desde un principio y están integradas como una parte más del proceso de desarrollo.

Cuanto mayor sea la complejidad del sistema, cuanta más deuda técnica exista, más posibilidades hay de surjan defectos y de que estos resulten, en ocasiones, complicados de detectar, porque en muchos casos serán consecuencia de una combinación de actuaciones del usuario que no ha sido contempladas o testeadas previamente.

¿Cuántas veces se ha tenido un cuidado extremo en tratar de que no se cuelen defectos y después, cuando el producto ha entrado en producción, han empezado a aparecer errores?

Por ese motivo, considero importante que los responsables funcionales y determinados usuarios empiecen a testear el producto (independientemente de la estrategia de testing utilizada por el equipo de desarrollo) desde la misma etapa de construcción, desde el mismo sprint, conforme se van completando historias de usuario. De esta forma, no solo se consigue perfilar mejor determinados aspectos de las historias, sino que también se permiten detectar defectos que probablemente hubieran llegado a producción.

Sobre lo comentado en este artículo, me parece muy interesante la siguiente cita de Brian Kernighan: “Cada nuevo usuario en un nuevo sistema descubre una nueva clase de bug”.