Skip to main content

Código limpio y mantenible

⏱ Dedicación recomendada: 0 minutos
Esto considera el contenido visible y relevante, e ignora texto colapsado o marcado como opcional.


Escribir código limpio no es solo una cuestión de estilo, sino un aspecto crítico para el éxito de un proyecto. Un código desordenado genera errores, dificulta la colaboración y hace que cualquier cambio sea un riesgo.

📌 Ejemplo "real":

Un equipo de desarrollo estaba implementando un sistema de control de acceso. Una variable llamada auth fue utilizada en el código, pero distintos desarrolladorxs la interpretaron de manera diferente:

  • Algunxs pensaron que significaba "authentication" (autenticación, es decir, el proceso de verificar la identidad de un usuario).
  • Otrxs asumieron que significaba "authorization" (autorización, es decir, los permisos que tiene un usuario después de autenticarse).

Como resultado, en algunos módulos del sistema, auth verificaba credenciales de usuario, mientras que en otros se usaba para comprobar permisos. Esto llevó a problemas de seguridad en los que personas sin autorización pudieron acceder a recursos restringidos. El error pasó desapercibido durante semanas debido a la confusión semántica.

Solución

En lugar de auth, se debieron usar nombres más explícitos como userAuthentication y userAuthorization, eliminando la ambigüedad.

En esta lección, exploraremos cómo evitar estos problemas con principios clave de código limpio, nombres descriptivos, funciones pequeñas y buenas prácticas de formateo.

👀 Código fácil de leer y entender

Un código bien escrito no solo facilita su lectura, sino que también reduce errores, mejora la colaboración y permite la evolución del software sin generar deuda técnica. Algunas prácticas esenciales incluyen:

  • Nombres descriptivos: Es fundamental usar nombres que sean claros y expresivos tanto para las variables como para las funciones. Los nombres deben reflejar su propósito de forma que el código sea más fácil de leer y entender.

    fun cx(cxPb: Double): Gt {
    // ...
    }

    📌 Problemas:

    • cx no indica su propósito.
    • cxPb no deja claro su significado.
    • Gt como tipo de retorno es ambiguo.
  • Facilitar el trabajo en equipo: Un código limpio y estructurado mejora la colaboración. Nuevos miembros pueden integrarse rápidamente y hacer revisiones más efectivas.

  • Soporte a la evolución del software: Un código mantenible permite realizar cambios y agregar nuevas funcionalidades de manera eficiente, reduciendo la deuda técnica y minimizando riesgos.

🚀 Impacto de un Código Claro y Mantenible

Escribir código limpio no solo mejora la comprensión inmediata, sino que también reduce costos de mantenimiento y facilita su crecimiento.

📌 Beneficios en el desarrollo diario

  • 🏗 Facilidad de entendimiento → Permite a cualquier persona del equipo comprender y modificar el código sin esfuerzo.
  • 🚀 Menos errores → Reduce la posibilidad de errores críticos al hacer el código más legible.
  • 🔄 Evolución eficiente → Facilita la adición de nuevas funcionalidades sin romper el código existente.

📈 Beneficios a largo plazo

  • 🔧 Reutilización de componentes → Un código modular puede aplicarse en distintos proyectos sin modificaciones innecesarias.
  • 📊 Adaptabilidad a nuevos requisitos → Un diseño limpio permite extender la funcionalidad sin necesidad de grandes refactorizaciones.
  • 👥 Mayor eficiencia del equipo → El código claro reduce la fricción en el trabajo colaborativo, evitando errores y malentendidos.

🎯 Principios de código limpio

🏷️ Nombres descriptivos

Los nombres en el código deben describir su propósito sin necesidad de explicaciones adicionales. Un buen nombre actúa como documentación implícita y evita la dependencia de comentarios innecesarios. Si una función o variable requiere un comentario para aclarar su propósito, probablemente el nombre no sea lo suficientemente expresivo.

fun getThem(theList: List<IntArray>): List<IntArray> {
val list1 = mutableListOf<IntArray>()
for (x in theList) {
if (x[0] == 4) {
list1.add(x)
}
}
return list1
}

📌 ¿Por qué es problemático?

  • getThem: No queda claro qué obtiene.
  • theList: No describe su contenido.
  • list1: Un nombre genérico que no aporta información.
  • x[0] == 4: No explica qué representa el 4.

Este enfoque no solo mejora la legibilidad del código, sino que también facilita el mantenimiento y la colaboración en equipo. Nombres descriptivos permiten comprender rápidamente el propósito de una función o variable sin necesidad de buscar explicaciones adicionales.

⚠️ Evitar nombres confusos

Evita nombres que varían ligeramente, ya que pueden causar confusión:

  • Incorrecto: XYZControllerForEfficientHandlingOfStrings vs XYZControllerForEfficientStorageOfStrings

Evita usar nombres secuenciales como a1, a2, ..., aN, ya que no aportan información sobre el propósito o contenido de las variables.

fun copyChars(a1: CharArray, a2: CharArray) {
for (i in a1.indices) {
a2[i] = a1[i]
}
}

En este ejemplo, los nombres a1 y a2 no proporcionan contexto sobre qué representan estas variables, lo que complica la comprensión de la función.

🔊 Nombres pronunciables

Es fundamental que los nombres sean pronunciables. Como dice Robert C. Martin en Clean Code:

"Si no puedes pronunciarlo, no puedes hablar de ello sin sonar como un tonto. (…) Esto importa porque la programación es una actividad social."

val genymdhms: String = TODO() // "generation date, year, month, day, hour, minute, and second"

El nombre genymdhms es complicado de pronunciar y recordar, lo que obstaculiza la comunicación entre desarrolladores y la comprensión del código.

Usar nombres pronunciables facilita las discusiones sobre el código, lo que es clave para un trabajo en equipo eficiente y la claridad a largo plazo.

🛠️ Funciones

  • Las funciones deben ser pequeñas. Como señala Robert C. Martin en Clean Code:

    "La primera regla de las funciones es que deben ser pequeñas. La segunda regla es que deben ser aún más pequeñas que eso."

  • Las funciones deben tener un solo propósito claro y no dividirse en secciones.
  • El número ideal de argumentos de una función es 0, seguido por 1 y luego 2. Tres o más deben estar fuertemente justificados.
  • Las funciones deben hacer algo o responder una pregunta, pero no ambas.

🗨️ Comentarios

Robert C. Martin también nos recuerda que:

"El uso adecuado de los comentarios es compensar nuestra incapacidad para expresarnos claramente con el código."

  • Los comentarios son propensos a quedar obsoletos, por lo que deben mantenerse actualizados.
  • Deben usarse cuando el código por sí solo no sea suficiente para expresar la intención, pero no como sustituto de un código claro.

Comentarios: ¿Cuándo son útiles y cuándo redundantes?

Los comentarios deben usarse con moderación y solo cuando aporten un valor real que el código por sí mismo no puede expresar. Veamos algunos ejemplos:

// Esta variable almacena el nombre de usuario
val userName = "Elizabeth Sinskey"

En este caso, el nombre de la variable (userName) ya es suficientemente descriptivo. El comentario no aporta información adicional y puede convertirse en una distracción.

¿Qué acabamos de hacer?
  • Comentario redundante: El código es tan claro que no se necesita explicación adicional, de modo que el comentario simplemente repite lo que ya se ve.
  • Comentario útil: Proporciona información de contexto, histórico o técnico que no es obvio con solo leer el código.

Este criterio te ayudará a decidir cuándo un comentario en tu código aporta valor real en términos de comprensión o justifica decisiones de diseño, y cuándo es mejor confiar en un buen nombre de variable o función para transmitir la intención.

📐 Formato de código

  • Archivos pequeños: Son más fáciles de manejar y leer.
  • Orden lógico: El código se lee de arriba hacia abajo, por lo que debe estar organizado de manera que su flujo sea lógico.
  • Estándares de formato: Es importante definir y seguir estándares de formato en el proyecto para asegurar la consistencia.
  • Herramientas de análisis estático: Estas herramientas pueden ayudar a detectar problemas de formato y garantizar que el código cumpla con los estándares establecidos.

Mantener un formato de código coherente no solo mejora la legibilidad, sino que también facilita la colaboración y el mantenimiento a largo plazo.

Errores frecuentes de formato de código y sus correcciones

Mantener un formato coherente a lo largo del proyecto es clave para facilitar la lectura y el mantenimiento del código. A continuación, se muestran algunos de los errores más comunes y cómo corregirlos.

fun myFunc(  name:String,age:Int):Boolean 
{ if(name.isEmpty()) {return false}
else{
return age>=18} }

Problemas notables:

  • Indentación inconsistente (espacios al azar).
  • Espacios y saltos de línea mal ubicados.
  • Llaves mal colocadas (la abertura de la función en otra línea).
  • Falta de espacios alrededor de operadores (: y >=).
  • Corte de línea que dificulta la lectura (else y su bloque en la misma línea).
¿Qué acabamos de hacer?

Consejos adicionales:

  1. Usar una herramienta de formateo automático: IDEs como IntelliJ IDEA, Android Studio o Visual Studio Code pueden aplicar las reglas de estilo definidas para tu equipo.
  2. Definir un estándar: Acordar una guía de estilo y formateo en tu proyecto (como Kotlin Coding Conventions) ayuda a mantener coherencia.
  3. Mantener líneas cortas: Evita líneas muy largas; se suelen recomendar 100-120 caracteres máximos para mejorar la lectura.
  4. Agrupar secciones lógicamente: Deja líneas en blanco antes y después de bloques de código que representen una funcionalidad o sección distinta.

La consistencia en el formato de código no solo facilita la lectura inmediata, sino que también agiliza el trabajo en equipo y la detección de conflictos en sistemas de control de versiones.

🧠 Ejercicio: Refactoriza tu propio código con ojos limpios

Ejercicio

Revisa un archivo de código que hayas escrito en el pasado y pregúntate:

  • ¿Los nombres son claros?
  • ¿Puedo reducir el número de argumentos de alguna función?
  • ¿Hay comentarios innecesarios o faltantes?
  • ¿El formato es consistente?

Intenta aplicar al menos dos mejoras de esta lección a ese archivo.

🎯 Conclusiones

El código limpio es una inversión en el futuro de tu proyecto. Aunque puede parecer que escribir código más expresivo o mejor formateado toma más tiempo, en realidad reduce errores, mejora la colaboración y facilita el mantenimiento. No se trata de escribir para la máquina, sino para las personas que lo leerán después—incluyéndote a ti misma.

Cada nombre claro, cada función pequeña y cada decisión de formato es una pieza que contribuye a un sistema más robusto, comprensible y profesional.

🔑 Puntos clave

  • Usa nombres descriptivos, pronunciables y coherentes para funciones, variables y clases.
  • Mantén las funciones pequeñas y enfocadas en una sola tarea.
  • Los comentarios deben agregar valor: explica lo que el código no puede expresar por sí solo.
  • El formato del código debe ser consistente, siguiendo convenciones claras del equipo o comunidad.
  • La legibilidad es una herramienta de calidad, no un lujo.

🧰 ¿Qué nos llevamos?

Escribir código limpio no es una meta aislada, sino una práctica diaria que fortalece tu capacidad para crear soluciones confiables, reutilizables y sostenibles. A medida que mejores tu estilo y claridad, también mejorarás tu pensamiento como diseñadorx de software. Recuerda: el código que escribes hoy será leído muchas veces mañana. Hacerlo claro y mantenible es un acto de respeto hacia quienes lo usen—incluyéndote a ti mismx.

📖 Referencias

🔥 Recomendadas

  • 📚 Martin, R. C. (Ed.). (2009). Comments. En Clean code: A handbook of agile software craftsmanship (pp. 53–74). Prentice Hall.
  • 📚 Martin, R. C. (Ed.). (2009). Formatting. En Clean code: A handbook of agile software craftsmanship (pp. 75–92). Prentice Hall.
  • 📚 Martin, R. C. (Ed.). (2009). Functions. En Clean code: A handbook of agile software craftsmanship (pp. 27–52). Prentice Hall.
  • 📚 Martin, R. C. (Ed.). (2009). Meaningful names. En Clean code: A handbook of agile software craftsmanship (pp. 33–50). Prentice Hall.