Curso – Claude

Catálogo de olores de código

Una referencia completa de los olores de código basados en Martin Fowler Refactorización (2a edición). Los olores de código son síntomas de problemas más profundos, indican que algo podría estar mal con el diseño de tu código.

"Un olor a código es una indicación superficial que generalmente corresponde a un problema más profundo en el sistema." — Martin Fowler


Bloaters

Los olores de código representan algo que ha crecido demasiado grande para ser manejado con eficacia.

Método largo

Señales: - Método supera 30-50 líneas - Necesidad de desplazarse para ver todo el método - Múltiples niveles de anidación - Comentarios que explican lo que hacen las secciones

Por qué es malo: - Difícil de entender - Difícil de probar en aislamiento - Los cambios tienen consecuencias no deseadas - La lógica duplicada se esconde dentro

Refactorización: - Método de extracción - Reemplazar la temperatura con la pregunta - Introduzca el objeto del parámetro - Reemplazar el método con el objeto del método - Descomponer condicional

Ejemplo (Antes):

function processOrder(order) {
  // Validate order (20 lines)
  if (!order.items) throw new Error('No items');
  if (order.items.length === 0) throw new Error('Empty order');
  // ... more validation

  // Calculate totals (30 lines)
  let subtotal = 0;
  for (const item of order.items) {
    subtotal += item.price * item.quantity;
  }
  // ... tax, shipping, discounts

  // Send notifications (20 lines)
  // ... email logic
}

Ejemplo (después):

function processOrder(order) {
  validateOrder(order);
  const totals = calculateOrderTotals(order);
  sendOrderNotifications(order, totals);
  return { order, totals };
}

Clase grande

Señales: - Clase tiene muchas variables de instancia (>7-10) - Clase tiene muchos métodos (>15-20) - Nombre de clase es vago (Gestor, Manejador, Procesador) - Los métodos no utilizan todas las variables de instancia

Por qué es malo: - Viola el principio de la responsabilidad única - Difícil de probar - Cambios en las características no relacionadas - Difícil de reutilizar piezas

Refactorización: - Clase de extracción - Subclase de extracción - Interfaz de extracción

Detección:

Lines of code > 300
Number of methods > 15
Number of fields > 10

Obsesión primitiva

Señales: - Uso de primitivos para conceptos de dominio (cadena para correo electrónico, int por dinero) - Arranca de primitivos en lugar de objetos - Constantes de cuerdas para códigos de tipo - Números mágicos/cadenas

Por qué es malo: - No hay validación a nivel de tipo - Lógica dispersa en la base de código - Fácil de pasar valores incorrectos - Faltan conceptos de dominio

Refactorización: - Reemplazar Primitivo con Objeto - Reemplazar Código de Tipo con Clase - Reemplazar Código de Tipo con Subclases - Reemplazar Código de Tipo con Estado/Estrategia

Ejemplo (Antes):

const user = {
  email: 'john@example.com',     // Just a string
  phone: '1234567890',           // Just a string
  status: 'active',              // Magic string
  balance: 10050                 // Cents as integer
};

Ejemplo (después):

const user = {
  email: new Email('john@example.com'),
  phone: new PhoneNumber('1234567890'),
  status: UserStatus.ACTIVE,
  balance: Money.cents(10050)
};

Lista de parámetros largos

Señales: - Métodos con 4+ parámetros - Parámetros que siempre aparecen juntos - Banderas booleanas cambiando el comportamiento del método - Nulo/indefinido pasado con frecuencia

Por qué es malo: - Difícil de llamar correctamente - Confusión de orden de parámetros - Indica método haciendo demasiado - Difícil de añadir nuevos parámetros

Refactorización: - Introducir el objeto parámetro - Conservar el objeto completo - Reemplazar el parámetro con la llamada del método - Eliminar el argumento de la bandera

Ejemplo (Antes):

function createUser(firstName, lastName, email, phone,
                    street, city, state, zip,
                    isAdmin, isActive, createdBy) {
  // ...
}

Ejemplo (después):

function createUser(personalInfo, address, options) {
  // personalInfo: { firstName, lastName, email, phone }
  // address: { street, city, state, zip }
  // options: { isAdmin, isActive, createdBy }
}

Clumps de datos

Señales: - Los mismos 3 + campos aparecen juntos repetidamente - Parámetros que siempre viajan juntos - Clases con subconjuntos de campo que pertenecen juntos

Por qué es malo: - Lógica de manipulación duplicada - Abstracción faltante - Más difícil de extender - Indica clase oculta

Refactorización: - Clase de extracción - introducir el objeto del parámetro - preservar el objeto entero

Ejemplo

// Data clump: (x, y, z) coordinates
function movePoint(x, y, z, dx, dy, dz) { }
function scalePoint(x, y, z, factor) { }
function distanceBetween(x1, y1, z1, x2, y2, z2) { }

// Extract Point3D class
class Point3D {
  constructor(x, y, z) { }
  move(delta) { }
  scale(factor) { }
  distanceTo(other) { }
}

Abusadores de la orientación de objetos

Huele a uso incompleto o incorrecto de los principios OOP.

Cambiar las declaraciones

Señales: - Conmutador largo/case o si/o otras cadenas - El mismo interruptor en varios lugares - Encender códigos de tipo - Agregar nuevos casos requiere cambios en todas partes

Por qué es malo: - Viola Principio Abierto/Cerrado - Cambia la onda a todas las ubicaciones del interruptor - Difícil de extender - A menudo indica el polimorfismo faltante

Refactorización: - Reemplazar condicional con polimorfismo - Reemplazar código de tipo con subclases - Reemplazar código de tipo con Estado/Estrategia

Ejemplo (Antes):

function calculatePay(employee) {
  switch (employee.type) {
    case 'hourly':
      return employee.hours * employee.rate;
    case 'salaried':
      return employee.salary / 12;
    case 'commissioned':
      return employee.sales * employee.commission;
  }
}

Ejemplo (después):

class HourlyEmployee {
  calculatePay() {
    return this.hours * this.rate;
  }
}

class SalariedEmployee {
  calculatePay() {
    return this.salary / 12;
  }
}

Campo temporal

Señales: - Variables de instancia sólo utilizadas en algunos métodos - Campos configurados condicionalmente - Inicialización compleja para ciertos casos

Por qué es malo: - Confusar—el campo existe, pero podría ser nulo - Difícil de entender el estado del objeto - Indica ocultamiento de lógica condicional

Refactorización: - Clase de extracción - Introducir objetos nulos - Reemplazar campo temporal con local


Petición rechazada

Señales: - Subclase no utiliza métodos/datos heredados - Subclase anula para no hacer nada - Herencia utilizada para la reutilización de código, no la relación IS-A

Por qué es malo: - Abstracción errónea - Viola el principio de sustitución de Liskov - Jerarquía engañosa

Refactorización: - Empujar hacia abajo método / campo - Reemplazar subclase con delegado - Reemplazar herencia con delegación


Clases alternativas con diferentes interfaces

Señales: - Dos clases que hacen cosas similares - Diferentes nombres de métodos para el mismo concepto - Se podría utilizar indistintamente

Por qué es malo: - Implementaciones duplicadas - No hay interfaz común - Difícil de cambiar entre

Refactorización: - Método de cambio de nombre - Método de movimiento - Extraer Superclass - Interfaz de extracción


Preventores del cambio

Los olores que dificultan los cambios—cambiar una cosa requiere cambiar muchas otras.

Cambio divergente

Señales: - Una clase cambiada por múltiples razones diferentes - Los cambios en diferentes áreas desencadenan las mismas ediciones de clase - La clase es una "clase de Dios"

Por qué es malo: - Viola la responsabilidad única - Alta frecuencia de cambio - Fusionar conflictos

Refactorización: - Clase de Extracto - Superclase de Extracto - Subclase de Extracto

Ejemplo A User cambios de clase para: - Cambios de autenticación - Cambios de perfil - Cambios de facturación - Cambios de notificación

→ Extracto: AuthService, ProfileService, BillingService, NotificationService


Cirugía de escopeta

Señales: - Un cambio requiere ediciones en muchas clases - Pequeñas características necesitan tocar más de 10 archivos - Los cambios están dispersos, difícil de encontrar todo

Por qué es malo: Los cambios son propensos a errores.

Refactorización: - Método de movimiento - Campo de movimiento - Clase en línea

Detección: Busque: añadir un campo requiere cambios en los archivos >5.


Jerarquías de herencia paralelas

Señales: - Crear subclase en una jerarquía requiere subclase en otra - Prefijos de clase coinciden (por ejemplo, DatabaseOrder, DatabaseProduct)

Por qué es malo: - Doble mantenimiento - Acoplamiento entre jerarquías - Fácil de olvidar un lado

Refactorización: - Método de movimiento - Campo de movimiento - Eliminar una jerarquía


Dispensables

Algo innecesario que debería ser eliminado.

Observaciones (exceso)

Señales: - Comentarios explicando qué código hace - Código comentado - TODO/FIXME que se queda para siempre - Disculpas en los comentarios

Por qué es malo: - Los comentarios mienten (salir de la sincronización) - El código debe ser auto-documentación - Código muerto causa confusión

Refactorización: - Método de extracto (nombre explica qué) - Renombrar (claridad sin comentarios) - Eliminar código comentado - Introducir Aserción

Comentarios buenos contra malos:

// BAD: Explaining what
// Loop through users and check if active
for (const user of users) {
  if (user.status === 'active') { }
}

// GOOD: Explaining why
// Active users only - inactive are handled by cleanup job
const activeUsers = users.filter(u => u.isActive);

Código duplicado

Señales: - El mismo código en varios lugares - Código similar con pequeñas variaciones - Copia-pega patrones

Por qué es malo: - Corrección de errores necesarios en varios lugares - Riesgo de inconsistencia - Base de código hinchada

Refactorización: - Método de extracción - Clase de extracción - Método de extracción (en jerarquías) - Método de plantilla de formulario

Regla de detección: Cualquier código duplicado 3+ veces debe ser extraído.


Clase perezosa

Señales: - La clase no hace lo suficiente para justificar la existencia. - Envoltorio sin valor añadido.

Por qué es malo: - Mantenimiento de los gastos generales - Incidencia innecesaria - Complejidad sin beneficio

Refactorización: - Clase en línea - Jerarquía de colapso


Código muerto

Señales: - Código inalcanzable - Variables/métodos/clases no utilizadas - Código comentado - Código tras condiciones imposibles

Por qué es malo: - Confusión - Carga de mantenimiento - Reduce la comprensión

Refactorización: - Eliminar código muerto - Eliminar seguro

Detección:

# Look for unused exports
# Look for unreferenced functions
# IDE "unused" warnings

Generalidad especulativa

Señales: - Clases abstractas con una subclase - Parámetros no utilizados "para uso futuro" - Métodos que sólo delegan - "Marco" para un caso de uso

Por qué es malo: - Complejidad sin beneficio - YAGNI (No vas a necesitarlo) - Más difícil de entender

Refactorización: - Jerarquía de colapso - Clase en línea - Eliminar parámetro - Cambiar el nombre del método


Acopladores

Los olores que representan el acoplamiento excesivo entre las clases.

Envidia de la característica

Señales: - Método utiliza más datos de otra clase que los suyos propios - Muchas llamadas de getter a otro objeto - Los datos y el comportamiento están separados

Por qué es malo: - Ubicación incorrecta para el comportamiento - Mal encapsulado - Difícil de mantener

Refactorización: - Método de movimiento - Campo de movimiento - Método de extracción (entonces muévase)

Ejemplo (Antes):

class Order {
  getDiscountedPrice(customer) {
    // Uses customer data heavily
    if (customer.loyaltyYears > 5) {
      return this.price * customer.discountRate;
    }
    return this.price;
  }
}

Ejemplo (después):

class Customer {
  getDiscountedPriceFor(price) {
    if (this.loyaltyYears > 5) {
      return price * this.discountRate;
    }
    return price;
  }
}

Intimidad inadecuada

Señales: - Las clases acceden a las partes privadas del otro - Referencias bidireccionales - Las subclases saben demasiado sobre los padres

Por qué es malo: - Alto acoplamiento - Cambios en cascada - Difícil de modificar uno sin otro

Refactorización: - Método Mover - Campo Mover - Cambiar Bidireccional a Unidireccional - Clase de extracción - Ocultar Delegado


Cadenas de mensajes

Señales: - Cadenas largas de llamadas de métodos: a.getB().getC().getD().getValue() - El cliente depende de la estructura de navegación - Código "Arruinamiento de trenes"

Por qué es malo: - Frágil - cualquier cambio rompe cadena - Viola la Ley de Demeter - Acoplamiento a la estructura

Refactorización: - Esconder Delegado - Método de extracción - Método de movimiento

Ejemplo

// Bad: Message chain
const managerName = employee.getDepartment().getManager().getName();

// Better: Hide delegation
const managerName = employee.getManagerName();

Hombre de medio

Señales: - Clase de que sólo los delegados a otro - La mitad de los métodos son delegaciones - No hay valor añadido

Por qué es malo: - Indirectión innecesaria - Mantenimiento de los gastos generales - Arquitectura confusa

Refactorización: - Quitar el hombre medio - Método en línea


Guía de la gravedad del olor

Severidad Descripción Medidas adoptadas
Crítico Bloquea el desarrollo, causa errores Arreglar inmediatamente
Alta Carga de mantenimiento significativa Fijar en el sprint actual
Medio Notable pero manejable Plan para un futuro próximo
Baja Incomodidad leve Arreglar oportunistamente

Lista de comprobación de detección rápida

Utilice esta lista de verificación al escanear el código:

  • [ ] ¿Algún método > 30 líneas?
  • [ ] ¿Alguna clase > 300 líneas?
  • [ ] ¿Algún método con > 4 parámetros?
  • ¿Algún bloque de código duplicado?
  • [ ] ¿Algún interruptor/case en códigos de tipo?
  • ¿Algún código no utilizado?
  • [ ] ¿Algún método usando los datos de otra clase pesadamente?
  • [ ] ¿Alguna cadena larga de llamadas de método?
  • ¿Algún comentario explicando "qué" no "por qué"?
  • ¿Algún primitivo que deba ser objeto?

Lectura adicional

  • Fowler, M. (2018). Refactorización: mejorar el diseño del código existente (2a edición)
  • Kerievsky, J. (2004). Refactorización a patrones
  • Plumas, M. (2004). Trabajar eficazmente con el código de legado

Última actualización: 4 de agosto de 2026 Versión de Claude Code: 2.1.220 Fuentes: - https://code.claude.com/docs/en/skills Modelos compatibles: Claude Fable 5, Claude Opus 5, Claude Sonnet 5, Claude Sonnet 4.6, Claude Opus 4.8, Claude Haiku 4.5

Versión en español de Cris Severin. Basado en Claude How To de luongnv89, bajo licencia MIT. Proyecto original