Softuy
Volver al blog
Publicado el: 25 de octubre de 20267 min de lecturaDesarrollo de SoftwareMantenibilidad

Que funcione no alcanza: la diferencia entre código útil y código mantenible

El cambio parecía correcto. La tarea pedía aplicar una regla nueva: si un cliente pertenecía a cierto segmento, el sistema debía mostrar una condición comercial diferente. El desarrollador encontró el lugar donde se calculaba el resultado, agregó una condición, probó el caso esperado y la funcionalidad quedó funcionando. El ticket podía cerrarse.

Durante unos días, nadie tuvo motivos para cuestionar esa solución. El usuario veía lo que necesitaba ver, la pantalla respondía correctamente y el flujo principal no se rompía. Desde afuera, el código era útil: resolvía el problema inmediato.

El problema apareció después, cuando otra regla comercial llegó al mismo lugar. Luego apareció una excepción para otro mercado. Más tarde, una condición temporal que solo debía aplicarse durante una campaña. Al cabo de unos meses, el cálculo que al principio parecía simple se había convertido en una mezcla de condiciones difíciles de leer, dependientes del orden en que fueron agregadas y peligrosas de modificar. Nadie estaba completamente seguro de qué pasaría si se tocaba una línea.

Ese es el punto donde se entiende la diferencia entre código útil y código mantenible.

El código útil resuelve el presente. Hace que una tarea avance, que una pantalla funcione, que un endpoint responda o que un error deje de ocurrir. Y eso importa. El software no se escribe para ser contemplado: se escribe para resolver necesidades reales. Un código que no funciona no se vuelve profesional solo porque esté bien organizado.

Pero que funcione no alcanza.

El código mantenible también resuelve el presente, pero lo hace sin hipotecar el futuro del proyecto. Deja una solución que otra persona puede leer, entender, probar y modificar sin sentir que está desactivando una bomba. No se trata de belleza abstracta ni de aplicar patrones por decoración. Se trata de reducir el costo de la próxima decisión.

Una parte importante del oficio de programar está en reconocer que casi ningún cambio vive aislado. La línea que hoy agregamos para cerrar un ticket puede convertirse mañana en el lugar donde otro desarrollador necesita agregar una variación, corregir un bug, explicar un comportamiento o investigar una incidencia de producción. Cuando escribimos código, no solo estamos hablando con la máquina. También estamos dejando una explicación para el equipo y para nuestro propio yo del futuro.

El código útil suele responder a la pregunta “¿cómo hago que esto funcione?”. El código mantenible agrega otra pregunta: “¿cómo hago que esto siga siendo entendible cuando el sistema cambie?”. Esa segunda pregunta modifica muchas decisiones pequeñas. Cambia el nombre de una variable. Cambia el lugar donde vive una regla. Cambia si una condición queda escondida dentro de un controlador o si se expresa en un servicio con un nombre claro. Cambia si una validación se copia en tres lugares o si se centraliza donde realmente pertenece.

La diferencia no siempre se ve en el primer día. De hecho, muchas malas decisiones parecen eficientes al principio. Es más rápido agregar un if donde ya estamos parados que revisar si esa regla pertenece a otro nivel del sistema. Es más rápido copiar una validación existente que entender por qué existe. Es más rápido agrandar un método que detenerse a separar responsabilidades. El problema es que cada atajo deja una pequeña deuda de comprensión. Y esa deuda se cobra cuando el sistema necesita cambiar.

La mantenibilidad no significa convertir cada tarea en una arquitectura compleja. Ese es el malentendido más común. Hay equipos que, intentando escribir “código limpio”, terminan creando capas innecesarias, abstracciones prematuras y nombres elegantes para problemas simples. Eso tampoco ayuda. Un sistema puede ser difícil de mantener tanto por desorden como por exceso de diseño.

El código mantenible no es el código con más patrones. Es el código que deja clara la intención.

Si una regla comercial cambia el precio de una operación, el lector debería poder descubrir esa intención sin recorrer diez archivos ni interpretar nombres genéricos. Si una acción depende del estado de una entidad, ese estado debería tener un significado visible dentro del modelo y no vivir como una cadena dispersa en varias condiciones. Si una validación protege una restricción importante, el código debería mostrar esa restricción de forma explícita, no esconderla como un detalle accidental.

Refactoring.Guru define la refactorización como un proceso sistemático para mejorar el código sin agregar funcionalidad nueva. Esa idea es importante porque separa dos momentos que a menudo mezclamos: hacer que algo funcione y mejorar la forma en que queda construido. Refactorizar no es “tocar por gusto”. Es reconocer que la estructura del código también es parte del producto, porque determina cuánto costará corregirlo, extenderlo o entenderlo más adelante.

La mantenibilidad se nota especialmente cuando entra alguien nuevo al proyecto. En un sistema mantenible, esa persona todavía necesita aprender el dominio, pero el código la ayuda. Los nombres orientan. Las responsabilidades están razonablemente ubicadas. Las pruebas muestran comportamientos relevantes. Las funciones tienen un tamaño que permite comprenderlas. Los errores se pueden rastrear. Las reglas importantes no están duplicadas de forma contradictoria.

En un sistema que solo fue escrito para funcionar, el nuevo desarrollador aprende por miedo. Antes de cambiar algo, pregunta quién tocó eso por última vez. Busca en mensajes antiguos. Copia patrones sin entenderlos. Evita limpiar porque no sabe qué puede romper. Cada cambio pequeño requiere una investigación desproporcionada. El equipo sigue entregando, pero cada entrega cuesta un poco más.

También por eso la mantenibilidad no es un lujo reservado para proyectos grandes. En proyectos pequeños, una mala estructura puede parecer tolerable porque todavía hay pocas piezas. Pero justamente ahí es cuando muchas decisiones se vuelven fundacionales. El primer lugar donde se pone una regla suele convertirse en el ejemplo que otros repiten. La primera forma de manejar errores se transforma en costumbre. El primer método gigante habilita el segundo. La primera duplicación parece inocente hasta que hay cinco versiones de la misma lógica.

Cuidar la mantenibilidad no significa escribir perfecto desde el inicio. Nadie lo hace. El código se entiende mejor a medida que el problema se entiende mejor. Muchas veces la primera versión sirve para descubrir qué forma debería tener la solución. Lo importante es no confundir esa primera versión con el final del trabajo. Si al terminar una tarea sabemos más que al empezar, el código debería reflejar algo de ese aprendizaje.

Ese ajuste puede ser pequeño. Renombrar una función para que explique una decisión. Extraer una regla que quedó enterrada. Separar una validación que estaba mezclada con presentación. Agregar una prueba que capture el comportamiento que realmente importa. Eliminar una duplicación antes de que se convierta en contrato informal. No se trata de detener todo para alcanzar una pureza imposible, sino de dejar el sistema un poco más claro que antes.

Un buen criterio práctico es mirar el código como si alguien tuviera que modificarlo bajo presión dentro de seis meses. Esa persona puede ser otro desarrollador o podemos ser nosotros mismos, sin recordar el contexto original. La pregunta no es si esa persona admirará nuestra solución. La pregunta es si podrá entenderla lo suficiente como para cambiarla sin romper algo importante.

El código útil cierra tareas. El código mantenible cuida la capacidad del equipo para seguir cerrándolas mañana.

Esa diferencia marca un salto profesional. Resolver el presente es necesario, pero no debería hacerse destruyendo la claridad que permitirá resolver el próximo problema. En un proyecto real, el software no se termina cuando pasa la prueba del caso feliz. Empieza a demostrar su calidad cuando alguien necesita modificarlo y todavía puede entender qué decisión sostiene cada parte.

Que funcione es el primer nivel.

Que pueda seguir cambiando sin volverse una amenaza es donde empieza el verdadero trabajo de ingeniería.

Que el código funcione es el punto de partida. Que siga siendo comprensible cuando el sistema cambie es lo que protege el futuro del proyecto.

Compartir artículo

Resumen Ejecutivo

El artículo desarrolla la diferencia entre resolver una tarea y dejar una solución que el equipo pueda entender, modificar y sostener con el tiempo.

Puntos Clave

  • El código útil resuelve el presente.
  • El código mantenible reduce el costo de los cambios futuros.
  • La mantenibilidad no significa sobrearquitectura.
  • Refactorizar permite mejorar la estructura sin agregar funcionalidad.

Enfoque recomendado

"Artículo narrativo sobre el salto profesional entre hacer que una tarea funcione y dejar una solución que pueda cambiar sin volverse una amenaza para el equipo."