Initial commit
This commit is contained in:
305
commands/refactor.md
Normal file
305
commands/refactor.md
Normal file
@@ -0,0 +1,305 @@
|
||||
## Refactor
|
||||
|
||||
Implementa refactorización de código segura y gradual, evalúa cuantitativamente la adherencia a los principios SOLID. Visualiza la deuda técnica y clarifica las prioridades de mejora.
|
||||
|
||||
### Uso
|
||||
|
||||
```bash
|
||||
# Identificación de código complejo y plan de refactorización
|
||||
find . -name "*.js" -exec wc -l {} + | sort -rn | head -10
|
||||
"Refactoriza estos archivos grandes para reducir la complejidad"
|
||||
|
||||
# Detección e integración de código duplicado
|
||||
grep -r "function processUser" . --include="*.js"
|
||||
"Unifica estas funciones duplicadas con Extract Method"
|
||||
|
||||
# Detección de violaciones de principios SOLID
|
||||
grep -r "class.*Service" . --include="*.js" | head -10
|
||||
"Evalúa si estas clases siguen el principio de responsabilidad única"
|
||||
```
|
||||
|
||||
### Ejemplos básicos
|
||||
|
||||
```bash
|
||||
# Detección de métodos largos
|
||||
grep -A 50 "function" src/*.js | grep -B 50 -A 50 "return" | wc -l
|
||||
"Divide métodos de más de 50 líneas con Extract Method"
|
||||
|
||||
# Complejidad de ramificaciones condicionales
|
||||
grep -r "if.*if.*if" . --include="*.js"
|
||||
"Mejora estas declaraciones condicionales anidadas con patrón Strategy"
|
||||
|
||||
# Detección de code smells
|
||||
grep -r "TODO\|FIXME\|HACK" . --exclude-dir=node_modules
|
||||
"Resuelve los comentarios que se han convertido en deuda técnica"
|
||||
```
|
||||
|
||||
### Técnicas de refactorización
|
||||
|
||||
#### Extract Method (Extracción de método)
|
||||
|
||||
```javascript
|
||||
// Antes: Método extenso
|
||||
function processOrder(order) {
|
||||
// 50 líneas de procesamiento complejo
|
||||
}
|
||||
|
||||
// Después: Separación de responsabilidades
|
||||
function processOrder(order) {
|
||||
validateOrder(order);
|
||||
calculateTotal(order);
|
||||
saveOrder(order);
|
||||
}
|
||||
```
|
||||
|
||||
#### Replace Conditional with Polymorphism
|
||||
|
||||
```javascript
|
||||
// Antes: sentencia switch
|
||||
function getPrice(user) {
|
||||
switch (user.type) {
|
||||
case "premium":
|
||||
return basePrice * 0.8;
|
||||
case "regular":
|
||||
return basePrice;
|
||||
}
|
||||
}
|
||||
|
||||
// Después: patrón Strategy
|
||||
class PremiumPricing {
|
||||
calculate(basePrice) {
|
||||
return basePrice * 0.8;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Puntuación de principios SOLID (0-100 puntos)
|
||||
|
||||
#### Criterios de evaluación y puntuación
|
||||
|
||||
```text
|
||||
S - Single Responsibility (20 puntos)
|
||||
├─ Número de responsabilidades de clase: 1 (20 pts) | 2 (15 pts) | 3 (10 pts) | 4+ (5 pts)
|
||||
├─ Número de métodos: <7 (+5 pts) | 7-15 (+3 pts) | >15 (0 pts)
|
||||
├─ Claridad de razón de cambio: Clara (+5 pts) | Ambigua (0 pts)
|
||||
└─ Ejemplo de puntuación: UserService(autenticación+procesamiento de datos) = 10 puntos
|
||||
|
||||
O - Open/Closed (20 puntos)
|
||||
├─ Puntos de extensión: Strategy/Template Method (20 pts) | Solo herencia (10 pts) | Ninguno (5 pts)
|
||||
├─ Cambios en código existente al agregar nuevas funciones: No necesario (+5 pts) | Mínimo (+3 pts) | Necesario (0 pts)
|
||||
├─ Uso de interfaces: Apropiado (+5 pts) | Parcial (+3 pts) | Ninguno (0 pts)
|
||||
└─ Ejemplo de puntuación: PaymentProcessor(Strategy) = 20 puntos
|
||||
|
||||
L - Liskov Substitution (20 puntos)
|
||||
├─ Adherencia al contrato de clases derivadas: Completa (20 pts) | Parcial (10 pts) | Violación (0 pts)
|
||||
├─ Fortalecimiento de precondiciones: Ninguno (+5 pts) | Existe (-5 pts)
|
||||
├─ Debilitamiento de postcondiciones: Ninguno (+5 pts) | Existe (-5 pts)
|
||||
└─ Ejemplo de puntuación: Square extends Rectangle = 0 puntos (violación)
|
||||
|
||||
I - Interface Segregation (20 puntos)
|
||||
├─ Tamaño de interfaz: 1-3 métodos (20 pts) | 4-7 (15 pts) | 8+ (5 pts)
|
||||
├─ Implementación de métodos no utilizados: Ninguno (+5 pts) | 1-2 (+2 pts) | 3+ (0 pts)
|
||||
├─ Claridad de rol: Rol único (+5 pts) | Múltiples roles (0 pts)
|
||||
└─ Ejemplo de puntuación: Separación Readable/Writable = 20 puntos
|
||||
|
||||
D - Dependency Inversion (20 puntos)
|
||||
├─ Dirección de dependencia: Solo abstracción (20 pts) | Mixta (10 pts) | Solo concreta (5 pts)
|
||||
├─ Uso de DI: Constructor Injection (+5 pts) | Setter (+3 pts) | Ninguno (0 pts)
|
||||
├─ Capacidad de prueba: Mockeable (+5 pts) | Difícil (0 pts)
|
||||
└─ Ejemplo de puntuación: Repository Pattern = 20 puntos
|
||||
|
||||
Puntuación total = S + O + L + I + D
|
||||
├─ 90-100 puntos: Excelente (Cumplimiento completo SOLID)
|
||||
├─ 70-89 puntos: Bueno (Margen de mejora leve)
|
||||
├─ 50-69 puntos: Aceptable (Refactorización recomendada)
|
||||
├─ 30-49 puntos: Pobre (Mejora a gran escala necesaria)
|
||||
└─ 0-29 puntos: Crítico (Revisión de diseño obligatoria)
|
||||
```
|
||||
|
||||
### Cuantificación de deuda técnica
|
||||
|
||||
#### Fórmula de cálculo de deuda
|
||||
|
||||
```text
|
||||
Deuda técnica (tiempo) = Puntuación de complejidad × Alcance de impacto × Dificultad de corrección
|
||||
|
||||
Puntuación de complejidad:
|
||||
├─ Complejidad ciclomática: 1-5(baja) | 6-10(media) | 11-20(alta) | 21+(peligrosa)
|
||||
├─ Complejidad cognitiva: Profundidad de anidación × Número de ramificaciones condicionales
|
||||
├─ Líneas de código: <50(1 pt) | 50-200(2 pts) | 200-500(3 pts) | 500+(5 pts)
|
||||
└─ Tasa de duplicación: 0-10%(1 pt) | 10-30%(2 pts) | 30-50%(3 pts) | 50%+(5 pts)
|
||||
|
||||
Alcance de impacto:
|
||||
├─ Número de módulos dependientes: Dependencia directa + Dependencia indirecta × 0.5
|
||||
├─ Frecuencia de uso: Número de llamadas API/día
|
||||
├─ Importancia comercial: Crítica(×3) | Alta(×2) | Media(×1) | Baja(×0.5)
|
||||
└─ Conocimiento del equipo: 1 persona que entiende(×3) | 2-3(×2) | 4+(×1)
|
||||
|
||||
Dificultad de corrección:
|
||||
├─ Cobertura de pruebas: 0%(×3) | <50%(×2) | 50-80%(×1.5) | >80%(×1)
|
||||
├─ Documentación: Ninguna(×2) | Insuficiente(×1.5) | Suficiente(×1)
|
||||
├─ Relaciones de dependencia: Acoplamiento fuerte(×3) | Moderado(×2) | Acoplamiento débil(×1)
|
||||
└─ Riesgo de cambio: Breaking Change(×3) | Consideración de compatibilidad(×2) | Seguro(×1)
|
||||
|
||||
Conversión de costos:
|
||||
├─ Costo de tiempo: Tiempo de deuda × Salario por hora del desarrollador
|
||||
├─ Costo de oportunidad: Días de retraso en desarrollo de nuevas funciones × Impacto diario en ventas
|
||||
├─ Costo de calidad: Probabilidad de aparición de bugs × Costo de corrección × Frecuencia de aparición
|
||||
└─ Costo total: Tiempo + Costo de oportunidad + Costo de calidad
|
||||
```
|
||||
|
||||
#### Matriz de prioridades
|
||||
|
||||
| Prioridad | Grado de impacto | Costo de corrección | Plazo de respuesta | Ejemplo concreto | Acción recomendada |
|
||||
| ------------------------------------- | ---------------- | ------------------- | --------------------- | --------------------------------------------------------------------- | ----------------------------------------------- |
|
||||
| **Critical (Respuesta inmediata)** | Alto | Bajo | Dentro de 1 semana | God Object, dependencia circular | Iniciar refactorización inmediatamente |
|
||||
| **Important (Respuesta planificada)** | Alto | Alto | Dentro de 1 mes | Separación de responsabilidades a gran escala, cambio de arquitectura | Incorporar en planificación de sprint |
|
||||
| **Watch (Objeto de monitoreo)** | Bajo | Alto | Dentro de 3 meses | Procesamiento interno de alta complejidad | Monitoreo de métricas, respuesta cuando empeore |
|
||||
| **Acceptable (Rango aceptable)** | Bajo | Bajo | No requiere respuesta | Code smells leves | Respuesta con refactorización normal |
|
||||
|
||||
### Procedimiento de refactorización
|
||||
|
||||
1. **Análisis y medición del estado actual**
|
||||
- Medición de complejidad (ciclomática ・cognitiva)
|
||||
- Cálculo de puntuación SOLID (0-100 puntos)
|
||||
- Cuantificación de deuda técnica (tiempo/costo)
|
||||
- Creación de matriz de prioridades
|
||||
|
||||
2. **Ejecución gradual**
|
||||
- Pasos pequeños (unidades de 15-30 minutos)
|
||||
- Ejecución de pruebas después de cada cambio
|
||||
- Commits frecuentes
|
||||
- Medición continua de puntuación SOLID
|
||||
|
||||
3. **Confirmación de calidad**
|
||||
- Mantenimiento de cobertura de pruebas
|
||||
- Medición de rendimiento
|
||||
- Confirmación de reducción de deuda técnica
|
||||
- Revisión de código
|
||||
|
||||
### Code smells comunes y puntuación de deuda
|
||||
|
||||
| Code Smell | Criterio de detección | Puntuación de deuda | Método de mejora |
|
||||
| ----------------------- | --------------------------------------- | ------------------- | ----------------------------- |
|
||||
| **God Object** | Responsabilidades >3, métodos >20 | Alta (15-20h) | Extract Class, aplicación SRP |
|
||||
| **Long Method** | Líneas >50, complejidad >10 | Media (5-10h) | Extract Method |
|
||||
| **Duplicate Code** | Tasa de duplicación >30% | Alta (10-15h) | Extract Method/Class |
|
||||
| **Large Class** | Líneas >300, métodos >15 | Alta (10-20h) | Extract Class |
|
||||
| **Long Parameter List** | Parámetros >4 | Baja (2-5h) | Parameter Object |
|
||||
| **Feature Envy** | Referencias a otras clases >5 | Media (5-10h) | Move Method |
|
||||
| **Data Clumps** | Repetición de mismo grupo de argumentos | Baja (3-5h) | Extract Class |
|
||||
| **Primitive Obsession** | Uso excesivo de tipos primitivos | Media (5-8h) | Replace with Object |
|
||||
| **Switch Statements** | case >5 | Media (5-10h) | Strategy Pattern |
|
||||
| **Shotgun Surgery** | Áreas afectadas al cambiar >3 | Alta (10-15h) | Move Method/Field |
|
||||
|
||||
### Ejemplo práctico: Evaluación de puntuación SOLID
|
||||
|
||||
```javascript
|
||||
// Objeto de evaluación: clase UserService
|
||||
class UserService {
|
||||
constructor(db, cache, logger, emailService) { // 4 dependencias
|
||||
this.db = db;
|
||||
this.cache = cache;
|
||||
this.logger = logger;
|
||||
this.emailService = emailService;
|
||||
}
|
||||
|
||||
// Responsabilidad 1: autenticación
|
||||
authenticate(username, password) { /* ... */ }
|
||||
refreshToken(token) { /* ... */ }
|
||||
|
||||
// Responsabilidad 2: gestión de usuarios
|
||||
createUser(data) { /* ... */ }
|
||||
updateUser(id, data) { /* ... */ }
|
||||
deleteUser(id) { /* ... */ }
|
||||
|
||||
// Responsabilidad 3: notificación
|
||||
sendWelcomeEmail(user) { /* ... */ }
|
||||
sendPasswordReset(email) { /* ... */ }
|
||||
}
|
||||
|
||||
// Resultado de evaluación de puntuación SOLID
|
||||
S: 10 puntos (3 responsabilidades: autenticación, CRUD, notificación)
|
||||
O: 5 puntos (sin puntos de extensión, implementación directa)
|
||||
L: 15 puntos (sin herencia, no aplicable)
|
||||
I: 10 puntos (interfaz no segregada)
|
||||
D: 10 puntos (dependencia de clases concretas)
|
||||
Total: 50 puntos (Aceptable - Refactorización recomendada)
|
||||
|
||||
// Deuda técnica
|
||||
Complejidad: 15 (7 métodos, 3 responsabilidades)
|
||||
Alcance de impacto: 8 (autenticación usada en todas las funciones)
|
||||
Dificultad de corrección: 2 (con pruebas, documentación insuficiente)
|
||||
Tiempo de deuda: 15 × 8 × 2 = 240 horas
|
||||
Prioridad: Critical (sistema de autenticación requiere respuesta inmediata)
|
||||
```
|
||||
|
||||
### Ejemplo de implementación después de mejora
|
||||
|
||||
```javascript
|
||||
// Después de aplicar principios SOLID (Puntuación: 90 puntos)
|
||||
|
||||
// S: Responsabilidad única (20 puntos)
|
||||
class AuthenticationService {
|
||||
authenticate(credentials) { /* ... */ }
|
||||
refreshToken(token) { /* ... */ }
|
||||
}
|
||||
|
||||
// O: Abierto/cerrado (20 puntos)
|
||||
class UserRepository {
|
||||
constructor(storage) { // Strategy Pattern
|
||||
this.storage = storage;
|
||||
}
|
||||
save(user) { return this.storage.save(user); }
|
||||
}
|
||||
|
||||
// I: Segregación de interfaz (20 puntos)
|
||||
interface Readable {
|
||||
find(id);
|
||||
findAll();
|
||||
}
|
||||
interface Writable {
|
||||
save(entity);
|
||||
delete(id);
|
||||
}
|
||||
|
||||
// D: Inversión de dependencia (20 puntos)
|
||||
class UserService {
|
||||
constructor(
|
||||
private auth: IAuthService,
|
||||
private repo: IUserRepository,
|
||||
private notifier: INotificationService
|
||||
) {}
|
||||
}
|
||||
|
||||
// Reducción de deuda: 240 horas → 20 horas (92% de reducción)
|
||||
```
|
||||
|
||||
### Soporte de automatización
|
||||
|
||||
```bash
|
||||
# Medición de puntuación SOLID
|
||||
npx solid-analyzer src/ --output report.json
|
||||
|
||||
# Análisis de complejidad
|
||||
npx complexity-report src/ --format json
|
||||
sonar-scanner -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info
|
||||
|
||||
# Visualización de deuda técnica
|
||||
npx code-debt-analyzer --config .debt.yml
|
||||
|
||||
# Formato de código
|
||||
npm run lint:fix
|
||||
prettier --write src/
|
||||
|
||||
# Ejecución de pruebas y cobertura
|
||||
npm test -- --coverage
|
||||
npm run test:mutation # pruebas de mutación
|
||||
```
|
||||
|
||||
### Precauciones
|
||||
|
||||
- **Prohibición de cambios funcionales**: No cambiar el comportamiento externo
|
||||
- **Test first**: Agregar pruebas antes de la refactorización
|
||||
- **Enfoque gradual**: No hacer cambios grandes de una vez
|
||||
- **Verificación continua**: Ejecución de pruebas en cada paso
|
||||
Reference in New Issue
Block a user