Clean Code and Quality Code - alfonsogastalverllamas/documentation GitHub Wiki

Cleaninfo



🧼 Clean Code

El concepto de Clean Code fue popularizado por Robert C. Martin (Uncle Bob) en su libro “Clean Code: A Handbook of Agile Software Craftsmanship”. Su objetivo es escribir código que sea fácil de leer, entender, modificar y mantener por cualquier desarrollador, no solo por su autor original.


✅ ¿Por qué es importante el Clean Code?

Razón Explicación
👁️ Legibilidad Código claro permite entender rápidamente qué hace una función o clase.
🔁 Mantenibilidad Facilita hacer cambios sin introducir errores.
🤝 Colaboración Cualquiera del equipo puede trabajar sobre el mismo código sin confusión.
🐛 Menos bugs El código claro es menos propenso a errores.
📈 Escalabilidad Proyectos bien estructurados son más fáciles de escalar en complejidad.
💸 Ahorro de costes Se reduce el tiempo de desarrollo, mantenimiento y depuración.

🧱 Pilares Fundamentales del Clean Code

Pilar Descripción Ejemplo
Nombres significativos Usa nombres que expresen intención. calculateTotal() es mejor que calc()
Funciones pequeñas Cada función debe hacer una sola cosa. sendEmail() no debería también validar datos
Evita comentarios innecesarios El código debe explicarse solo. Los comentarios solo si aportan valor. Mejorar el nombre en vez de comentar algo obvio
Evita duplicación Reutiliza lógica común en funciones o clases. isValidEmail() en vez de validar varias veces
Código expresivo El código debe contar una historia clara. if user.isAdmin() vs if u.flag == 1
Manejo de errores limpio Usa excepciones, evita if-else anidados complejos. try-except bien estructurado
Menos dependencias Clases/módulos poco acoplados. Separar lógica de negocio de UI
Formateo consistente Sigue convenciones de estilo. Indentación clara, uso de linters

🔑 Conceptos Clave

Concepto Descripción
SRP (Single Responsibility Principle) Cada módulo o clase debe tener una única responsabilidad.
DRY (Don't Repeat Yourself) No dupliques lógica. Extrae a funciones reutilizables.
KISS (Keep It Simple, Stupid) No compliques el código innecesariamente.
YAGNI (You Aren’t Gonna Need It) No implementes cosas que aún no necesitas.
Refactorización continua Mejora progresivamente el código sin cambiar su comportamiento.

📌 Ejemplos específicos de Clean Code vs Dirty Code


1️⃣ Nombres de variables y funciones

❌ Dirty Code

def d(a, b):
    return a - b

✅ Clean Code

def calculate_discount(price: float, discount: float) -> float:
    return price - discount

2️⃣ Funciones largas vs funciones pequeñas

❌ Dirty Code

def process_order(order):
    # validate
    if not order.items:
        raise Exception("No items")
    if order.total <= 0:
        raise Exception("Total must be positive")
    # calculate taxes
    tax = order.total * 0.2
    # save to db
    save_to_database(order, tax)
    # send confirmation
    send_confirmation_email(order)

✅ Clean Code

def process_order(order):
    validate_order(order)
    tax = calculate_tax(order.total)
    save_to_database(order, tax)
    send_confirmation_email(order)

def validate_order(order):
    if not order.items:
        raise Exception("No items in order")
    if order.total <= 0:
        raise Exception("Total must be positive")

def calculate_tax(amount: float) -> float:
    return amount * 0.2

3️⃣ Estructura de control limpia vs anidada

❌ Dirty Code

def get_status(age):
    if age > 0:
        if age < 18:
            return "Minor"
        else:
            return "Adult"
    else:
        return "Invalid"

✅ Clean Code

def get_status(age: int) -> str:
    if age <= 0:
        return "Invalid"
    if age < 18:
        return "Minor"
    return "Adult"

4️⃣ Comentarios innecesarios vs código expresivo

❌ Dirty Code

# function to add two numbers
def f(x, y):
    return x + y

✅ Clean Code

def add_numbers(first: int, second: int) -> int:
    return first + second

5️⃣ Repetición de lógica vs reutilización

❌ Dirty Code

def is_valid_email(email):
    return "@" in email and "." in email

def register_user(email):
    if "@" in email and "." in email:
        print("Email válido")

✅ Clean Code

def is_valid_email(email: str) -> bool:
    return "@" in email and "." in email

def register_user(email: str):
    if is_valid_email(email):
        print("Email válido")

---

6️⃣ Manejo de errores limpio vs código frágil

❌ Dirty Code

def divide(a, b):
    return a / b  # ¡peligroso si b es 0!

✅ Clean Code

def divide(a: float, b: float) -> float:
    if b == 0:
        raise ValueError("No se puede dividir por cero")
    return a / b

7️⃣ Clases cohesionadas vs mal estructuradas

❌ Dirty Code

class User:
    def __init__(self, name):
        self.name = name

    def send_email(self, message):
        # lógica para enviar email
        pass

    def save_to_database(self):
        # lógica para guardar en DB
        pass

✅ Clean Code

class User:
    def __init__(self, name):
        self.name = name

class UserRepository:
    def save(self, user: User):
        # lógica para guardar en DB
        pass

class EmailService:
    def send_email(self, user: User, message: str):
        # lógica para enviar email
        pass

8️⃣ Constantes mágicas vs valores explícitos

❌ Dirty Code

def calculate_area(radius):
    return 3.14159 * radius * radius

✅ Clean Code

PI = 3.14159

def calculate_area(radius: float) -> float:
    return PI * radius * radius

9️⃣ Estilo y formato consistente

❌ Dirty Code

def sum ( a , b ) :
 return a+b

✅ Clean Code

def sum(a: int, b: int) -> int:
    return a + b

🔟 Validaciones defensivas

❌ Dirty Code

def process(user):
    print(user.name.upper())

✅ Clean Code

def process(user):
    if not user or not user.name:
        raise ValueError("Usuario inválido")
    print(user.name.upper())

🧼 Guía Práctica de Clean Code


✅ Buenas Prácticas de Clean Code

Práctica Descripción
Escribe funciones pequeñas Idealmente no más de 15-20 líneas, con una sola responsabilidad.
Usa nombres descriptivos Nombres que expliquen el "qué" y el "por qué", no solo el "cómo".
Aplica el principio SRP Cada clase/módulo debe tener una única razón para cambiar.
Evita comentarios innecesarios El mejor comentario es un buen nombre.
Refactoriza frecuentemente Pequeños ajustes continuos mantienen el código sano.
Haz que el código hable por sí solo Que se entienda sin tener que adivinar.
Mantén funciones puras cuando sea posible Sin efectos colaterales ni dependencias ocultas.
Sigue un estilo consistente Usa linters o formateadores automáticos.
Evita la duplicación (DRY) Extrae lógica repetida a funciones reutilizables.
Diseña para ser probado (testable) Código desacoplado y predecible facilita las pruebas.

📋 Checklist rápida de Clean Code

  • ¿Los nombres de variables y funciones son autoexplicativos?
  • ¿Las funciones tienen una única responsabilidad?
  • ¿El código evita duplicación?
  • ¿El flujo de control es claro y directo (sin anidaciones profundas)?
  • ¿El código está bien formateado (espaciado, indentación)?
  • ¿Se están usando constantes en lugar de valores mágicos?
  • ¿Hay validaciones y manejo de errores adecuados?
  • ¿Hay separación de capas/responsabilidades (UI, lógica, datos)?
  • ¿Hay pruebas para los casos importantes?
  • ¿Puedes entender el propósito del archivo en 1 minuto?

🛠️ Refactorización segura

Refactorizar es mejorar el diseño interno del código sin cambiar su comportamiento externo. Para hacerlo de forma segura:

1. ✅ Usa pruebas como red de seguridad

  • Asegúrate de tener tests antes de comenzar.
  • Refactoriza en pequeños pasos.
  • Ejecuta tests constantemente.

2. 📌 Refactorizaciones comunes

Cambio Motivo
Extraer función Cuando hay bloques repetidos o lógicos dentro de una función
Renombrar variable/función Para mejorar comprensión del código
Reubicar responsabilidad Mover lógica a otra clase o módulo donde pertenezca mejor
Dividir función grande Si hace múltiples cosas, divídela por responsabilidades
Encapsular condicionales Extrae if/else complejos en funciones con nombres descriptivos

3. 🧪 Tips de seguridad

  • Cambia solo una cosa a la vez.
  • Usa control de versiones (git) para retroceder si algo falla.
  • Si no entiendes algo, no lo toques aún: primero escribe tests que lo cubran.

🏷️ Naming Conventions (Convenciones de nombres)

Elemento Convención Ejemplo
Variables snake_case user_name, total_price
Funciones snake_case get_user_data(), send_email()
Clases PascalCase UserService, EmailClient
Constantes UPPER_CASE MAX_RETRIES, PI
Módulos/archivos snake_case.py user_service.py, config.py
Tests test_<function>() test_calculate_discount()
Booleanos Verbos + condición is_valid, has_items, should_update

✨ Tip extra:

Usa nombres que expliquen la intención, no la implementación.

# ❌ Malo
def handle(user):
    ...

# ✅ Bueno
def send_welcome_email(user: User):
    ...

🛠️ Quality Code: Código de Calidad

Quality Code va más allá de que el código se vea limpio: asegura que funcione correctamente, sea seguro, mantenible, escalable y probado. Es un conjunto de prácticas que garantizan que el software no solo sea entendible, sino también confiable y robusto.


✅ ¿Por qué es importante escribir código de calidad?

Beneficio Explicación
🔒 Mayor seguridad Previene vulnerabilidades desde el código mismo.
🧪 Mejor testabilidad Código bien diseñado se puede probar fácilmente y con precisión.
🔄 Facilidad de mantenimiento Facilita aplicar cambios, correcciones o mejoras.
🚀 Mejor rendimiento Mejores prácticas conducen a ejecución más eficiente.
🤝 Colaboración efectiva Cualquier miembro del equipo puede entenderlo y trabajar sobre él.
💼 Calidad profesional Refleja buenas prácticas de ingeniería, no solo funcionalidad.

🧱 Componentes Clave del Quality Code

Componente Descripción
Legibilidad Claridad en estructuras, nombres, comentarios útiles.
Modularidad Código dividido en partes reutilizables y separadas.
Reusabilidad Evita duplicación, promueve componentes compartidos.
Testabilidad Fácil de escribir pruebas unitarias, de integración y end-to-end.
Seguridad Validación de entradas, manejo de errores, protección contra inyecciones.
Rendimiento Código optimizado sin sacrificar claridad.
Escalabilidad Preparado para crecer en usuarios, datos o lógica sin reescrituras.
Documentación mínima útil Explica solo lo que no puede inferirse del código directamente.

🔍 Ejemplo de Quality Code

❌ Código funcional pero no de calidad:

def login(u, p):
    if u == "admin" and p == "1234":
        return True
    return False

✅ Código de calidad:

def is_valid_credentials(username: str, password: str) -> bool:
    # Nunca se deben hardcodear credenciales
    if not username or not password:
        raise ValueError("Credenciales incompletas")
    return authenticate_user(username, password)

def authenticate_user(username: str, password: str) -> bool:
    # Validación real contra una base de datos segura
    return user_repo.check_password(username, password)

📌 Ejemplos específicos de Quality Code


🔐 Ejemplo 1: Seguridad

❌ Inseguro: susceptible a inyección SQL

def get_user(email):
    query = f"SELECT * FROM users WHERE email = '{email}'"
    db.execute(query)

✅ Seguro: evita inyecciones

def get_user(email: str):
    query = "SELECT * FROM users WHERE email = %s"
    db.execute(query, (email,))

🧪 Ejemplo 2: Testabilidad

❌ Difícil de testear (función con lógica y efectos colaterales)

def register_user(email):
    if "@" not in email:
        raise ValueError("Invalid email")
    db.save(email)
    send_email(email, "Welcome!")

✅ Fácil de testear (separación de responsabilidades)

def is_valid_email(email: str) -> bool:
    return "@" in email

def register_user(email: str, repo, mailer):
    if not is_valid_email(email):
        raise ValueError("Invalid email")
    repo.save(email)
    mailer.send(email, "Welcome!")

🧱 Ejemplo 3: Modularidad

❌ Acoplamiento fuerte

class Order:
    def complete_order(self, user, payment):
        print("Validating payment")
        print("Saving to database")
        print("Sending confirmation")

✅ Código modular

class OrderService:
    def __init__(self, payment_service, order_repo, notification_service):
        self.payment_service = payment_service
        self.order_repo = order_repo
        self.notification_service = notification_service

    def complete_order(self, order, user):
        self.payment_service.validate(order)
        self.order_repo.save(order)
        self.notification_service.send(user, "Order confirmed")

📈 Ejemplo 4: Escalabilidad

❌ No escalable (mal manejo de datos)

def get_all_users():
    return db.query("SELECT * FROM users")

✅ Fácil de testear (separación de responsabilidades)

def get_users(page: int, page_size: int = 50):
    offset = (page - 1) * page_size
    return db.query("SELECT * FROM users LIMIT %s OFFSET %s", (page_size, offset))

🚀 Ejemplo 5: Rendimiento

❌ Ineficiente

def get_usernames():
    users = db.query("SELECT * FROM users")
    return [user['name'] for user in users]

✅ Fácil de testear (separación de responsabilidades)

def get_usernames():
    return db.query("SELECT name FROM users")

🧼 Guía Práctica de Quality Code


✅ Buenas Prácticas de Quality Code

Escribir código de calidad no solo se trata de que funcione, sino de que sea seguro, mantenible, escalable y confiable. A continuación, algunas de las mejores prácticas para garantizarlo:


🔐 Seguridad

  • Valida todas las entradas del usuario.
  • Usa consultas parametrizadas (evita SQL injection).
  • Maneja errores con excepciones controladas, no con mensajes genéricos.
  • Evita exponer información sensible (contraseñas, tokens, errores internos).

🧪 Testabilidad

  • Escribe funciones puras (sin efectos secundarios) cuando sea posible.
  • Usa inyección de dependencias para facilitar el uso de mocks.
  • Divide lógica compleja en partes pequeñas y testeables.
  • Escribe pruebas automatizadas: unitarias, de integración y E2E.

🧱 Modularidad

  • Aplica el principio SRP (Single Responsibility Principle).
  • Divide el sistema en componentes con interfaces bien definidas.
  • Reutiliza módulos donde tenga sentido (no repitas código).
  • Evita acoplamiento fuerte entre clases o servicios.

📈 Escalabilidad

  • Usa paginación y límites al trabajar con grandes volúmenes de datos.
  • Diseña para que nuevos casos de uso puedan añadirse sin romper lo existente.
  • Piensa en términos de servicios reutilizables y desacoplados.
  • No optimices prematuramente, pero deja espacio para crecer.

🚀 Rendimiento

  • Consulta solo los datos necesarios (no SELECT * innecesarios).
  • Minimiza el uso de recursos (memoria, CPU, red).
  • Usa estructuras de datos adecuadas para cada caso.
  • Mide y perfila antes de optimizar.

🧼 Legibilidad y Mantenimiento

  • Usa nombres descriptivos para funciones, variables y clases.
  • Refactoriza regularmente para mejorar claridad y simplicidad.
  • Sigue convenciones de código del equipo/proyecto.
  • Mantén el código y los comentarios sincronizados.

📋 Checklist de Quality Code

  • ¿El código es fácil de leer y entender?
  • ¿Las funciones y clases tienen una única responsabilidad?
  • ¿Se evita la duplicación innecesaria (DRY)?
  • ¿Se validan entradas y se manejan errores de forma segura?
  • ¿El código es fácilmente testeable (unit, integration, E2E)?
  • ¿Tiene un diseño modular y reutilizable?
  • ¿Cumple estándares de seguridad (inyecciones, validaciones, errores)?
  • ¿Tiene buen rendimiento para el caso de uso esperado?
  • ¿Está preparado para escalar en lógica o datos?
  • ¿Está documentado lo justo y necesario (no más, no menos)?
  • ¿Es consistente con el estilo y convenciones del equipo?

⚠️ **GitHub.com Fallback** ⚠️