Evitar la deuda técnica es un error

Deuda

Todos los que nos dedicamos a esto de desarrollar software manejamos con cierta soltura (y ligereza, por qué no decirlo) el concepto de deuda técnica. De hecho, conseguir explicar este concepto a roles más comerciales dentro de nuestras empresas es una de nuestras luchas más frecuentes.

Deuda es una palabra que suena bastante mal, y más después de la crisis de deuda que hemos padecido en muchos países desde el 2009, por lo que resulta natural que, al oir hablar de deuda, lo primero que sentimos es la necesidad de minimizarla y huir de ella como algo malo y trágico.

Sin embargo, el concepto de deuda no tiene por qué ser negativo, al contrario: endeudarse puede ser un medio perfectamente válido para alcanzar un objetivo concreto.

Igual que muchos de nosotros hemos recurrido al endeudamiento para poder comprarnos una casa que no hubiéramos podido adquirir de otra forma (si esto es una buena o mala decisión lo dejo al criterio de cada uno), asumir deuda técnica durante el desarrollo de un proyecto de software puede ser algo necesario y positivo. Pero para poder comprender esto, es importante primero tener claro a qué nos enfrentamos al hablar de deuda técnica.

Qué es la deuda técnica

El concepto de deuda técnica está muy ligado al tiempo. Decimos que adquirimos deuda técnica cuando resolvemos un problema de una forma subóptima para poder hacerlo en un tiempo menor.

Asimilar esto a la deuda financiera está motivado porque la deuda técnica, al igual que la financiera, implica el pago de unos intereses. Esa solución de compromiso que hemos tenido que alcanzar hoy va a afectar al futuro desarrollo del proyecto y nos ralentizará, por lo que hasta que la paguemos, estaremos pagando unos intereses en forma de tiempo.

Si nos centramos en aspectos puramente técnicos, solemos identificar la deuda con características del código: alta complejidad ciclomática, elevado grado de acoplamiento, poca legibilidad, etc. Aunque no soy muy amigo de ellas, existen métricas que nos permiten cuantificar la deuda técnica adquirida de una forma fácilmente automatizable y medible.

Esta vertiente de la deuda técnica es (relativamente) fácil de controlar, ya que al poder medirla, «tan sólo» necesitamos dedicar tiempo a mejorar nuestros indicadores para reducirla. Ese «tan sólo», así, entrecomillado, como os podéis imaginar viene de lo complicado que es explicar a algunos que vamos a dedicar tiempo a mejorar el código sin introducir mejoras funcionales visibles. Aquí la regla del boy scout es una buena guía para ir pagando esa deuda técnica de forma progresiva.

Existe otra parte de deuda técnica, para mi mucho más complicada de medir y de tratar, que tiene implicaciones puramente funcionales. Es posible que tengamos código perfectamente escrito, que cumple los principios SOLID (o lo que sea que esté de moda en ese momento), que se ajusta a buenas prácticas, está desacoplado, cohesionado, legible… pero que no se ajusta a los requisitos de negocio que tenemos, y que para poder ajustarlo a ellos nos obliga a realizar cambios profundos.

Estos cambios no son tanto a nivel de código (que también), sino a nivel conceptual. No se trata de refactorizar, se trata de reescribir aprovechando el nuevo conocimiento que tenemos del dominio de la aplicación que estamos desarrollando.

A veces estos cambios son motivados por una mala comprensión inicial del problema, y otras veces son necesarios porque los requisitos originales han evolucionado, pero la realidad es que el modelo que tan cuidadosamente hemos creado ya no se ajusta a lo que necesitamos.

Decía que esta parte es más complicada de tratar, entre otras cosas, porque es más complicada de medir y cuantificar. Además, aquí es fácil caer en la tentación de ir ñapeando el modelo actual para dar cabida a nuevos escenarios (de una forma perfectamente SOLID-compliant, eso sí), pero que hacen que cada vez sea más complicado modelar nuevos requerimientos porque en lugar de atajar el problema de raíz lo que hacen es añadir más complejidad accidental y dificultarnos los próximos cambios.

En ambos casos, uno de los mayores riesgos que tenemos que afrontar está muy ligado a la teoría de las ventanas rotas. Cada vez que vamos a tocar algo de la aplicación vemos tantos defectos y ñapas, que nos parece que por añadir una ñapa más no va a pasar nada, con lo que la entropía del sistema sigue aumentando y hace cada vez más complicado mejorar la calidad global.

Por qué es necesaria

Tras esta pequeña descripción de lo que es la deuda técnica, parece bastante claro que es algo que queremos evitar a toda costa, pero como decía en la introducción al post, esto no es siempre así.

Puesto que el concepto de deuda técnica se basa en un paralelismo con la deuda financiera, comencemos por analizar ésta.

En el mundo real muchas veces es necesario pedir prestado dinero. Si eres un particular y tienes una vivienda en propiedad, es muy probable que hayas necesitado pedir una hipoteca para ello, contrayendo una deuda con un banco. También es frecuente comprar un coche a plazos. O algún electrodoméstico. O incluso financiar las compras realizadas con la tarjeta de crédito.

Si la deuda en el mundo real es mala y nos obliga a pagar intereses, ¿por qué hacemos este tipo de transacciones? Está claro: porque necesitamos disponer de un bien antes de reunir el dinero necesario para comprarlo.

Esto es aplicable también en el mundo empresarial, y no es raro que una empresa necesite abrir una línea de crédito para financiarse y poder obtener algún recurso (mano de obra, materia prima) con el que comerciar, obtener un beneficio, y así pagar la deuda y sus intereses.

En el caso del desarrollo de software, la deuda técnica puede cumplir exactamente la misma misión, pero en lugar de con respecto al dinero, con respecto al tiempo.

En lugar de dedicar 5 meses a desarrollar perfectamente una funcionalidad y comenzar a explotarla, podemos dedicar 1, hacer algo razonablemente válido, y explotarlo antes. Probablemente luego haya que reescribirlo y por el camino estemos pagando el precio del desarrollo de calidad subóptima que hemos hecho, pero los 4 meses que hemos ganado pueden merecer la pena.

Al hablar de cosas como Producto Mínimo Viable, el principio YAGNI, o hacer la cosa más simple que podría funcionar, muchas veces hay implícita una aceptación de una posible deuda técnica. En lugar de buscar una solución perfecta, aceptamos una solución inferior para ganar tiempo que nos permita validar una idea o desarrollar de forma especulativa cosas que no necesitamos.

Es probable que siguiendo esos principios acabemos desechando código, pero cuando llegue ese momento, deberíamos tener más información que compense el esfuerzo extra y los intereses (en forma de tiempo de desarrollo adicional) afrontados hasta entonces.

Qué debemos hacer con ella

Ahora que tenemos una imagen más completa de cómo se manifiesta la deuda técnica y las ventajas que puede tener endeudarse temporalmente, parece más razonable pensar que el objetivo no es evitar la deuda técnica, sino gestionarla adecuadamente.

Para ello es fundamental ser consciente de la deuda que estamos asumiendo y acumulando. Incrementar la deuda sin tener una idea, aunque sea cualitativa, de cuál es nuestro nivel de deuda, es muy peligroso porque nos podemos ver en la desagradable situación de no poder pagar los intereses y dedicar tanto tiempo a mantener el sistema funcionando que no podemos añadir nuevas funcionalidades.

Una vez que somos conscientes de las áreas en las que estamos acumulando deuda y las implicaciones que eso tiene para el desarrollo de la aplicación (exceso de bugs en ciertas partes, dificultar para añadir determinado tipo de funcionalidades, imposibilidad de escalar hasta los niveles deseados), podemos empezar a decidir qué parte de la deuda pagamos y cómo la pagamos.

Nunca hay que olvidar que el proceso de desarrollo es, en definitiva, una cuestión optimizar el valor que se obtiene del tiempo invertido. Por ello se hace necesario analizar si resultr más productivo invertir tiempo en crear funcionalidad y seguir pagando intereses de la deuda existente, o dedicar ese tiempo a pagar intereses.

Desgraciadamente, saber dónde es más rentable invertir el tiempo no es una tarea en absoluto sencilla, por lo que realizar esta gestión de la deuda tampoco lo es. Aun así, merece al pena hacer el ejercicio de intentarlo o, al menos, tenerlo en cuenta a la hora de tomar decisiones.

Si la parte comercial tiene una clara tendencia a ignorar el precio que se paga por la deuda técnica adquirida, la parte técnica suele tener la tendencia inversa y sobrevalorar el impacto de no hacer las cosas tan bien como nos gustaría. Tratemos de buscar el equilibrio y ser racionales.

8 comentarios en “Evitar la deuda técnica es un error

  1. Muy de acuerdo. Añadiría que la deuda técnica es inevitable. No somos adivinos y no sabemos como cambiará la tecnología y, sobretodo, el negocio, con lo que lo que hoy parece una buena idea, mañana puede ser algo que nos lastre.

    Y como dices en el artículo, a veces la deuda técnica es lo más óptimo. Puede ser que gane mucho más (dinero, clientes, aprendizaje) sacando un producto ahora que no de aquí cuatro meses.

    Siempre que todo esto se haga con cabeza, analizando pros y contras, riesgos, etc.

    Salut!

  2. josejuan dijo:

    La deuda técnica no tiene nada que ver con ser adivinos o no, ni siquiera con que nuestro modelo actual no cubra nuevas necesidades (¡aún previsibles!). De hecho, lo que para unos no es deuda técnica (sólo es que ignoran una forma mejor de hacerlo) para otros sí lo es (saben una forma mejor pero no la han aplicado a sabiendas; endeudándose). Tampoco tiene que ver con la fragilidad del software porque, ¿acaso alguien sabe calcular la geodésica de la evolución del software? (que minimice la entropía de forma práctica https://www.genbetadev.com/trabajar-como-desarrollador/fragilidad-del-software-en-que-estoy-fallando ).

    Y nada tiene nada que ver con nada porque todos esos conceptos no explican (casi) nada por si mismos. Pero sí están íntimamente relacionados y seguirán estándolo en tanto en cuanto alguien establezca un modelo que realmente explique qué es desarrollar software (razón por la cual las métricas que comentas no funcionan, ni tampoco el principio del boy scout, ni ser SOLID y chorradas similares [cuando son entendidas como «ideas reveladoras» y/o aplicadas sin pensar]).

    ¿Evitar la deuda técnica es un error? ¿ignorar las métricas (ej. complejidad ciclomática) es un error? ¿no seguir los principios SOLID es un error? ¿no dormir lo suficiente antes de definir una estrategia es un error? ¿no reevaluar (cuantas veces 1?, 2?, … veces) una estrategia antes de implantarla es un error? ¿no refactorizar un código que genera X problema con frecuencia F antes de 1?, 2?, … meses es un error? …

    Yo no tengo ni idea y hasta donde llega mi entendimiento nadie tiene ni idea. Sí, divagar podemos divagar mucho, e incluso estas divagaciones tendrán sentido y serán divertidas e interesantes pero en la práctica, no valen más que LA VALORACIÓN SUBJETIVA Y PUNTUAL del señor o señores de turno que toque evaluarlas y con menor o mayor fortuna solventarán los problemas que surjan mañana.

    ¿Teóricamente merece la pena (xej) desacoplar A de B? seguro, ¿y aquí y ahora? nadie lo sabe, todo lo más, que *si puedes tener* métricas, análisis, sugerencias, pruebas, maquetas, … mejor, pero finalmente, cada cual evaluará de acuerdo a su experiencia y buen hacer.

    Hasta donde sé, es lo único que funciona.

    En cuanto a todos éstos términos y cuestiones (deuda, fragilidad, solid, …) yo cada vez más los veo como una manifestación de la misma sopa primordial de la que emergen.

    Sí, eso es, hablemos de «la sopa primordial del software» para si no entender, al menos hacernos una idea de dónde emergen tantos términos independientes pero a la vez tan interconectados.

  3. Además del tiempo muchas veces se genera deuda técnica porque queremos tener algo que mostrar para tener feedback lo más rápido posible (fail fast) e ir aprendiendo del negocio y que el cliente también aprenda si lo que tiene en mente es lo que realmente necesita él, el negocio, el usuario, etc.

  4. Creo que todos los que leemos este post tenemos claro que es la deuda técnica. Como su propio nombre indica, hablamos de factores eminentemente técnicos, y que pueden venir dados por diferentes contextos. A mi parecer cuando hablamos de deuda técnica es necesario afrontarla desde la perspectiva del técnico, ni más ni menos.

    Cuando aparecen nuevos requisitos o nuevos refinamientos de las tareas ya desarrolladas, y esto implica cambios profundos, no tengo claro que aquello entre en la categoría de deuda. Simplemente es parte del ciclo de desarrollo y refactorización de las soluciones de software. No podemos meter como deuda técnica un nuevo requisito que ha traído un concepto nuevo a mi aplicación y esto implica un cambio en el modelo de dominio o en el flujo de ejecución de acciones. ¿Cómo iba a saber yo en su momento que este requisito iba a llegar? hasta donde debería de divagar en posteriores desarrollos para evitar este tipo de «deuda»? es evidente que esto no es viable.

    Ahora, por otra parte, sí que estamos de acuerdo en que trabajando en un equipo donde si damos por hecho que el conocimiento del negocio es bastante homogéneo y el nivel técnico de los desarrolladores también lo es, sí que más o menos podemos saber que partes (conceptos, fragmentos de código) podemos catalogar como deuda.

    En definitiva, para mi es deuda técnica todo aquello que pueda solucionar y me vaya a reportar beneficios como desarrollador (y siempre como desarrollador) a corto-medio plazo.

  5. Efectivamente son muy necesarias para poder seguir mejorando el producto en un tiempo razonable.
    Intentar crear algo perfecto desde 0 es como querer inventar el tele-transporte sin pasar por la rueda.
    Un saludo!

Comentarios cerrados.