Technical Debt

Una condición actual y sus consecuencias futuras

Technical Debt describe una condición técnica de diseño o implementación que agrega costo, riesgo o fricción a cambios y mantenimiento futuros. La pregunta es qué trabajo adicional provoca conservarla, bajo qué cambios y durante qué horizonte. No se identifica solo por apariencia, edad o preferencia tecnológica.

Un sistema puede satisfacer hoy sus requisitos y aun exigir una costosa coordinación para cambiar mañana. Una solución también puede ser sencilla, adecuada y suficiente sin implementar generalidad futura. No construir capacidad especulativa no demuestra deuda: hace falta explicar una consecuencia técnica frente a necesidades plausibles.

evolution-and-modernization conecta esta mirada con legacy-systems. Un sistema heredado puede contener deuda, pero también uno nuevo; ni el contexto legacy ni el nombre de su arquitectura permiten estimar automáticamente esa carga.

Cunningham: aprender y consolidar

En The WyCash Portfolio Management System, Cunningham describe crecimiento incremental desde un prototipo y consolidación de la implementación a medida que se comprende el producto. La metáfora permite obtener valor temprano y reconocer el trabajo pendiente para sostener esa evolución. Ward Cunningham, 1992.

Su argumento no autoriza equiparar deuda con código deliberadamente malo ni con pereza. Una primera representación puede funcionar y después requerir revisión al aprender más. Tampoco prescribe reescribir todo el sistema: el reporte habla de consolidación dentro del desarrollo incremental de WyCash.

El SEI formula la deuda en términos de construcciones de diseño o implementación que facilitan el corto plazo pero pueden volver cambios futuros más costosos o imposibles. Su impacto depende de cómo se pretenda evolucionar el sistema. Managing the Consequences of Technical Debt, 2019. El Atlas usa esa relación temporal como criterio; los ejemplos de Commerce siguientes son propios.

Principal e interest: una metáfora con límites

Principal es el costo de cambiar o retirar la condición de deuda. Puede incluir modificar dependencias, migrar datos, probar compatibilidad y coordinar consumidores. No equivale solamente a horas de editar código.

Interest es el costo adicional de cargar con ella: repetir cambios, ampliar regresión, secuenciar releases o investigar efectos difíciles de atribuir. El reporte del cuarto workshop de Managing Technical Debt explica esta distinción y advierte que no es literalmente un préstamo financiero. Towards a Crisper Definition, 2013, sección 1.

No hay una tasa universal ni un principal perfectamente conocido. El interés puede aparecer solo cuando una capacidad cambia. Riesgo de regresión y esfuerzo observado son evidencias distintas; una posibilidad de incidente no debe presentarse como gasto ya ocurrido.

Condición ilustrativaCarga posible al conservarla
Regla de devolución duplicada.Modificar y verificar varias representaciones de la misma decisión.
Consumidores de un schema privado.Ampliar pruebas y coordinar releases por cambios internos.
Configuración de entrega duplicada.Repetir ajustes y revisar divergencias en cada entorno.
Recuperación acoplada a internals.Mayor esfuerzo cognitivo y diagnóstico durante mantenimiento.

Una incidencia puede revelar deuda, pero no todo incidente es interés: un proveedor externo puede fallar sin que exista una condición de diseño evitable. Hay que mostrar el mecanismo que agrega exposición, trabajo o dificultad de recuperación.

Deliberada y emergente

Un equipo puede aceptar una solución temporal para entregar antes y revisar la condición cuando se confirme demanda. También puede descubrir deuda al crecer el volumen, cambiar requisitos, perder validez una suposición o comprender mejor el dominio. Identificar deuda no exige reconstruir una decisión consciente de endeudamiento.

Fowler distingue deuda deliberada e inadvertida y separa esa dimensión de su juicio sobre prudencia. El aprendizaje puede revelar mejores diseños después de una entrega competente. Technical Debt Quadrant, 2009. Es una herramienta de discusión, no una clasificación moral de personas.

El origen no decide por sí solo prioridad ni respuesta. Una condición aceptada puede volverse urgente; otra recién descubierta puede tener poca consecuencia en el roadmap actual. Evaluar con conocimiento presente sin atribuir retrospectivamente información que el equipo anterior no tenía.

Defectos y trabajo pendiente

Un defecto viola un requisito o comportamiento acordado. Deuda describe una condición que encarece mantener o cambiar. Pueden coexistir: una dependencia cíclica puede dificultar arreglar un defecto, pero cerrar ese bug no necesariamente elimina la dependencia.

Una feature todavía no implementada pertenece al trabajo de producto. Un TODO puede registrar un recordatorio, una idea o un defecto; la etiqueta no demuestra deuda. Missing tests tampoco bastan como diagnóstico: precisar qué comportamiento resulta difícil de verificar y qué costo o riesgo agrega esa condición.

El SEI separa defectos, features pendientes y falta de proceso de la condición técnica de deuda, aun cuando puedan relacionarse como causas o consecuencias. The Future of Managing Technical Debt, 2016. Un backlog de bugs no es automáticamente un inventario de deuda.

Complejidad, trade-offs y obligación de cambiar

accidental-complexity pregunta qué dificultad proviene de la solución y su contexto. Technical Debt pregunta qué condición genera carga futura. Se superponen, sin identidad: un framework puede introducir representación adicional y seguir siendo adecuado y barato de mantener; reglas duplicadas pueden encarecer cada cambio requerido.

essential-complexity conserva distinciones exigidas por el problema. Importes, monedas, devoluciones parciales y autorizaciones tienen semántica que no desaparece al reemplazar código. Su dificultad no constituye deuda por sí misma. Una representación que obliga a mantener esas reglas en varios sitios sí merece examinarse.

Todo diseño tiene compromisos. Elegir una base compartida, un protocolo o un deployment común no establece deuda automáticamente. Hay que relacionar la condición con architectural-drivers, constraints y cambios relevantes. Un límite aceptado para un alcance estable puede seguir siendo una decisión razonable.

Cuando la deuda es arquitectónica

La deuda puede atravesar código de buena calidad. dependency-structure puede revelar ciclos entre módulos; data-ownership, escrituras sobre representaciones ajenas; deployment, releases que deben secuenciarse por contratos incompatibles. modularity ayuda a observar decisiones que se propagan fuera de su responsabilidad.

Un contrato obsoleto puede exigir adaptaciones repetidas. Un mecanismo de configuración puede multiplicar entregas manuales; un cuello de botella puede hacer costosa una ampliación necesaria de scaling. La condición técnica subyacente importa más que el número de archivos con warnings.

«Todos los releases requieren tres equipos» describe un síntoma. Investigar si nace de un schema compartido, una política organizacional o un compromiso de consistencia. El remedio cambia según causa; distribuir componentes sin entenderla puede conservar la deuda y agregar costos de red.

Commerce: dos escrituras y una regla que cambia

En la plataforma ilustrativa, Orders escribe directamente tablas de Payments. Agregar estados de autorización obliga a modificar Orders, probar ambas capacidades y coordinar entrega. El pedido sigue funcionando: la deuda se manifiesta en carga adicional de cambio y riesgo de alterar invariantes ajenas.

Los años de operación, la integración SOAP de un partner y la historia de transacciones describen otro contexto. Ninguno demuestra esa deuda específica. La condición identificable es conocimiento privado compartido; el interés aparece al cambiar Payments. legacy-systems examina el valor y las restricciones del conjunto.

Una alternativa podría dar a Payments autoridad sobre las modificaciones y ofrecer un contrato. El principal incluye localizar escritores, preservar transacciones y compatibilidad, adaptar consumidores y verificar recuperación. Dibujar una API no paga la deuda; puede quedar un período de convivencia con mayor carga.

Otra plataforma recién creada con microservices puede duplicar autorización en varios servicios. Agregar una regla exige cambios repetidos aunque los runtimes sean actuales. En modular-monolith, proteger responsabilidades también requiere mecanismos efectivos: compartir proceso no obliga a compartir representaciones privadas.

Priorizar por consecuencias

refactor-vs-rewrite compara alternativas de transformación para un alcance: una carga elevada no justifica automáticamente reemplazarlo. migration-strategy mantiene visible el costo de coexistencia y retirada si se cambia la solución. El código nuevo puede introducir deuda propia, y continuar con el actual también consume oportunidad; comparar consecuencias durante un horizonte común.

Comparar frecuencia de cambio, roadmap, criticidad, incidentes, exposición de seguridad, obligaciones vigentes y costo de remediación. Un área poco atractiva y rara vez modificada puede ser menos urgente que una dependencia limpia que bloquea cada entrega importante.

cost-efficiency incluye ingeniería, operación y oportunidad de entrega. Aceptar deuda puede tener sentido si el valor temprano compensa la carga esperada y su eventual tratamiento, bajo incertidumbre explícita. Esa comparación no justifica ignorar compromisos obligatorios ni supone que toda condición tendrá retorno al corregirse.

Reunir evidencia localizada: cambios repetidos, consumidores afectados, tiempo de regresión, releases coordinados y fallos relacionados. Comparar trabajos suficientemente parecidos; atribuir toda demora a deuda omite complejidad del requisito, aprendizaje y dependencias externas.

No producir una puntuación universal mezclando LOC, bugs y dinero. Una estimación de remediación puede ser útil si declara alcance, supuestos y margen. Revisarla ante nueva evidencia, en vez de convertir una cifra inicial en verdad contable.

Tratar, contener o aceptar

strangler-fig, parallel-change y branch-by-abstraction pueden introducir caminos y compatibilidad temporales para reducir riesgo de cambio. Esa carga puede ser deliberada; necesita ownership, observación y condición de retiro. Conservarla por una obligación vigente es distinto de olvidarla después de instalar el reemplazo: el costo debe permanecer visible en ambos casos.

evolutionary-architecture pregunta qué carga limita una trayectoria probable y cómo obtener feedback al cambiarla. architecture-erosion puede crear deuda al debilitar intención vigente, pero un adapter temporal aceptado puede ser deuda sin erosión. fitness-functions detecta algunas condiciones; pasar sus evaluaciones no implica deuda cero.

Las respuestas incluyen refactorizar, automatizar, encapsular, migrar o retirar la capacidad. Encapsular puede limitar exposición sin eliminar el núcleo; automatizar puede reducir repetición sin corregir un contrato. Especificar qué carga disminuye y cuál permanece.

No toda deuda debe pagarse. Si una capacidad va a retirarse, una intervención grande puede consumir valor sin uso posterior. Confirmar que la retirada es viable y contempla datos, consumidores y soporte; una fecha deseada no elimina obligaciones actuales.

Registrar contexto, condición, razón, cambios afectados, consecuencias, riesgo, alternativa y trigger de revisión ayuda a decidir. No exige un schema nuevo ni un proceso separado. Un cambio repetido, un incidente o una variación del roadmap pueden activar esa revisión.

El resultado buscado es capacidad de evolución y mantenimiento con costos comprendidos. modifiability, evolvability y testability permiten comprobar mejoras concretas. Ni cero warnings ni una reescritura completa demuestran por sí solos que la carga relevante haya disminuido.