qpc8

Loading...

Por Qué la Mayoría del Software Personalizado Se Vuelve Inmantenible Después de 12 Meses

Los patrones que convierten software funcional en deuda técnica. Qué sale mal, por qué sucede, y cómo construir sistemas que permanezcan mantenibles.

Kevin Kulcsar··10 min read

El Precipicio de los Doce Meses

La mayoría del software personalizado funciona perfectamente en el lanzamiento. Las características coinciden con la especificación. El cliente está feliz. Todos siguen adelante.

Doce meses después, algo necesita cambiar. Una nueva característica. Una integración. Un arreglo para un workflow que ya no coincide con la realidad. Y de repente, lo que debería tomar días toma semanas. Lo que debería costar €500 cuesta €5,000. Cambios simples rompen funcionalidad no relacionada.

Esto no es mala suerte. Es predecible. Y casi siempre es causado por los mismos patrones.

Patrón 1: Sin Documentación (El Problema de "Está Todo En Mi Cabeza")

El desarrollador que construyó el sistema lo entendía perfectamente. Cada decisión tenía sentido en contexto. La arquitectura era elegante en su mente.

Luego se movieron a otro proyecto. O dejaron la empresa. O simplemente olvidaron los detalles después de trabajar en otras cosas.

Lo que se pierde:

  • Por qué se tomaron ciertas decisiones arquitectónicas
  • Qué depende de qué (el acoplamiento oculto)
  • Cómo configurar el entorno de desarrollo
  • Qué requiere realmente el proceso de despliegue
  • Qué partes son frágiles y por qué
El resultado: Cada cambio requiere arqueología. Los nuevos desarrolladores pasan horas entendiendo antes de poder modificar. Hacen cambios que parecen seguros pero rompen supuestos que no sabían que existían.

La solución: La documentación no es opcional. Como mínimo: un README que explique el setup, una visión general de la arquitectura, y comentarios inline para decisiones no obvias. Esto toma quizás 10% más de tiempo durante el desarrollo pero ahorra 500% durante el mantenimiento.

Patrón 2: Feature Creep Sin Refactorización

La versión 1 tenía tres características. La arquitectura soportaba tres características hermosamente.

Luego el cliente pidió una cuarta característica. No encajaba del todo en la arquitectura, pero el deadline era ajustado, así que se acopló. Luego una quinta. Luego una sexta. Cada adición añadiendo complejidad a una base que nunca fue diseñada para manejarla.

Lo que sucede:

  • Las funciones crecen de 20 líneas a 200 líneas
  • Los archivos se convierten en vertederos de código vagamente relacionado
  • La gestión de estado se dispersa y se vuelve impredecible
  • Los workarounds "temporales" se convierten en fixtures permanentes
  • Las nuevas características requieren modificar 15 archivos en lugar de 2
El resultado: El sistema se convierte en un campo minado. Los desarrolladores experimentados tienen miedo de tocarlo. Los nuevos desarrolladores no pueden entenderlo. Cada cambio es arriesgado.

La solución: Presupuesta para refactorización. Cuando una característica no encaja limpiamente, di no o asigna tiempo para reestructurar. El enfoque de "hack rápido ahora, arreglar después" nunca se arregla después.

Patrón 3: Dependencias Como Minas Terrestres

El software moderno depende de cientos de paquetes externos. Cada paquete tiene sus propias dependencias. Cada dependencia tiene su propio ciclo de actualización.

Lo que sale mal:

  • Las vulnerabilidades de seguridad requieren actualizaciones urgentes
  • Las actualizaciones rompen compatibilidad con otras dependencias
  • Los paquetes deprecados dejan de recibir parches de seguridad
  • Diferentes paquetes requieren versiones conflictivas de dependencias compartidas
  • Las actualizaciones de versión mayor requieren cambios de código en toda la aplicación
La línea de tiempo:

Mes 1: Todo funciona, las dependencias están actualizadas. Mes 6: Algunos paquetes están desactualizados, sin problemas urgentes. Mes 12: Varios paquetes tienen vulnerabilidades conocidas, las actualizaciones requieren cambios en cascada, algunos paquetes están deprecados. Mes 18: Actualizar cualquier cosa es un proyecto de varios días con resultados impredecibles.

La solución: Mantenimiento regular. Actualiza dependencias mensualmente, no anualmente. Fija versiones cuidadosamente. Evita dependencias innecesarias. Elige paquetes maduros y bien mantenidos sobre los nuevos y trendy.

Patrón 4: La Base de Datos Crece Colmillos

El esquema inicial de base de datos tenía sentido para los requisitos iniciales. Las tablas mapeaban limpiamente a conceptos. Las consultas eran simples.

Luego los requisitos cambiaron. Se añadieron nuevos campos. Los campos viejos no podían eliminarse (algo podría depender de ellos). Las relaciones que parecían claras se volvieron ambiguas.

Síntomas comunes:

  • Tablas con 50+ columnas, la mayoría raramente usadas
  • Campos llamados nuevo_status y status_actual porque cambiar el original era muy arriesgado
  • Consultas que hacen join de 8 tablas para responder preguntas simples
  • Datos inconsistentes porque las reglas de validación cambiaron pero los datos viejos permanecen
  • Campos nullable misteriosos de los que nadie recuerda el propósito
El resultado: Las consultas de base de datos se convierten en cuellos de botella de rendimiento. Los problemas de integridad de datos se acumulan. Los reportes simples requieren agregaciones complejas.

La solución: Trata los cambios de base de datos tan cuidadosamente como los cambios de código. Escribe migraciones que realmente migren datos, no solo añadan columnas. Archiva o limpia datos obsoletos. Documenta el esquema.

Patrón 5: Tests Que No Testean

El sistema tiene tests. Los tests pasan. El sistema aún así se rompe.

Lo que realmente está pasando:

  • Los tests verifican que el código se ejecuta, no que produce resultados correctos
  • Los tests se escriben contra escenarios ideales, nunca casos límite
  • Los tests de integración mockean tanto que no testean integración
  • Los tests se rompen cuando el código cambia, así que los desarrolladores dejan de ejecutarlos
  • Las métricas de cobertura están manipuladas (100% cobertura con assertions sin sentido)
El resultado: Falsa confianza. Los cambios se despliegan porque los tests pasan. Los usuarios descubren los bugs. La confianza en la suite de tests se evapora.

La solución: Testea comportamiento, no implementación. Escribe tests que atraparían bugs reales que has visto. Mantén los tests como código de producción. Elimina tests que no atrapan problemas reales.

Patrón 6: Deriva de Entornos

Desarrollo funciona. Staging funciona. Producción se rompe.

Por qué esto sucede:

  • Desarrollo ejecuta una versión diferente de OS
  • Staging tiene menos memoria/CPU que producción
  • Las variables de entorno difieren de formas sutiles
  • Producción tiene patrones de datos que no existen en entornos de test
  • El caching se comporta diferente bajo carga real
El resultado: "Funciona en mi máquina" se convierte en un meme porque es constantemente verdad. Debuggear problemas de producción requiere reproducir entornos que nadie entiende completamente.

La solución: Containeriza. Usa las mismas imágenes Docker a través de entornos. Automatiza el setup de entornos. Testea con volúmenes de datos similares a producción.

Patrón 7: El Factor Bus Ausente

Una persona entiende el sistema profundamente. Todos los demás tienen conocimiento superficial.

El riesgo:

  • Esa persona se convierte en un cuello de botella para todas las decisiones
  • Cuando no están disponibles, el progreso se detiene
  • Cuando se van, el conocimiento institucional se va con ellos
  • Acumulan "decisiones no documentadas" que se convierten en minas
El resultado: El futuro del sistema depende de un único punto de fallo. Y esa persona eventualmente sigue adelante — todos lo hacen.

La solución: Pair programming. Code reviews que realmente transfieran conocimiento. Requisitos de documentación. Cross-training. Sin propiedad de persona única de sistemas críticos.

Lo Que "Mantenible" Realmente Significa

Software mantenible no es software perfecto. Es software donde:

1. Un nuevo desarrollador puede entenderlo en días, no semanas. La estructura es obvia. Las convenciones son consistentes. La documentación existe.

2. Los cambios están localizados. Modificar la característica X no rompe las características Y y Z. Los límites entre componentes son claros.

3. Las dependencias son manejables. Las actualizaciones no cascadean impredeciblemente. Hay un proceso claro para mantener las cosas al día.

4. Los tests atrapan problemas reales. Cuando los tests pasan, el equipo tiene confianza real. Cuando los tests fallan, el fallo apunta a un problema real.

5. Los entornos son reproducibles. Configurar desarrollo está scriptado. Staging coincide con producción. Los deploys son predecibles.

6. El conocimiento está distribuido. Múltiples personas pueden hacer cambios. La documentación captura decisiones.

Por Qué Esto Sigue Pasando

El patrón se repite por desalineación de incentivos:

Durante el desarrollo:

  • La velocidad se recompensa
  • Las características funcionando son visibles
  • La documentación es invisible
  • La deuda técnica es invisible
  • El presupuesto está fijo
Durante el mantenimiento:
  • La velocidad depende de la calidad del código
  • Cada atajo se vuelve visible
  • La documentación faltante bloquea el progreso
  • La deuda técnica demanda pago
  • El presupuesto para "limpieza" es difícil de justificar
Los desarrolladores construyendo el sistema frecuentemente no son los desarrolladores manteniéndolo. El negocio pagando por características ahora no siente el dolor del mantenimiento después. Todos actúan racionalmente dentro de sus restricciones — y el sistema se degrada predeciblemente.

Cómo Construimos en QPC⁸

En QPC⁸, la mantenibilidad no es opcional. Cada sistema que enviamos sigue los mismos principios:

La documentación es parte de la entrega. No consideramos un proyecto completo hasta que el README explique el setup, la arquitectura esté documentada, y el despliegue esté scriptado.

Refactorizamos mientras construimos. Cuando los requisitos cambian a mitad de proyecto (siempre lo hacen), reestructuramos en lugar de acoplar. Esto cuesta más a corto plazo. Cuesta dramáticamente menos durante la vida del sistema.

Las dependencias son conservadoras. Elegimos paquetes maduros y bien mantenidos. Evitamos librerías trendy que podrían abandonarse el próximo año. Mantenemos los conteos de dependencias bajos.

Los tests atrapan bugs reales. Nuestros tests se enfocan en comportamiento que importa. No perseguimos métricas de cobertura — perseguimos confianza.

Sin conocimiento de persona única. Nuestros sistemas están documentados lo suficientemente bien para que cualquier ingeniero pueda mantenerlos. Esto no es negociable.

El resultado: sistemas que permanecen saludables con el tiempo. Clientes que pueden hacer cambios sin descubrir minas. Software que permanece como un activo, no un pasivo.

El Costo de Hacerlo Bien

Construir software mantenible cuesta más por adelantado. Quizás 20-30% más que la entrega más rápida posible.

Pero:

  • El mantenimiento del Año 2 es 50% más barato
  • Las modificaciones del Año 3 son 70% más baratas
  • El sistema puede evolucionar en lugar de requerir reemplazo
  • Los equipos internos pueden contribuir sin ayuda externa
  • Puedes cambiar de proveedores sin empezar de nuevo
Los negocios que construyen la V1 más barata posible frecuentemente pagan por ella tres veces: una vez por la construcción inicial, una vez por arreglos de emergencia, y una vez por el eventual reemplazo.

Los negocios que invierten en calidad por adelantado pagan una vez e iteran.

Preguntas Para Hacerle a Tus Desarrolladores

Si estás evaluando desarrollo de software (o manteniendo software existente), pregunta:

1. ¿Cómo configuro un entorno de desarrollo? Si la respuesta toma más de 10 minutos en explicar, hay un problema.

2. Muéstrame la documentación. Si no hay ninguna, dependes de conocimiento tribal.

3. ¿Cuándo actualizaste dependencias por última vez? Si la respuesta es "en el lanzamiento", tienes una bomba de tiempo.

4. ¿Qué pasa si te atropella un autobús? Si nadie más puede mantener el sistema, tienes un único punto de fallo.

5. ¿Cómo despliego un cambio? Si el proceso no está documentado y automatizado, cada deploy es arriesgado.

Las respuestas te dicen si tu software es un activo o un pasivo.

---

QPC⁸ construye sistemas de producción diseñados para mantenibilidad a largo plazo. Ve nuestros sistemas enviados o configura tu proyecto.

ingeniería de softwaredeuda técnicamantenibilidadcalidad de códigoarquitectura2025

Need this built?

We build production systems that implement these concepts. Get transparent pricing on your project.

Configure Your System →

Related Posts

Web Systems

Por Qué la Mayoría de Backends SaaS Fallan al Escalar

Errores arquitectónicos comunes que matan productos SaaS cuando crecen. Cómo construir backends que soporten 10x tráfico sin reescrituras.

Web Systems

Desarrollo web barato en la Costa del Sol — Lo que realmente obtienes por €290

¿Buscas desarrollo web barato en la Costa del Sol? Esto es exactamente lo que €290 te compra — una web Next.js real, no un desastre WordPress.

Web Systems

La web profesional más barata de Málaga — Por qué €290 gana a lo gratis

Los constructores de webs gratis prometen todo. Aquí te explicamos por qué una web profesional Next.js a €290 los supera a todos — y realmente ayuda a crecer tu negocio en Málaga.