code-quality-master

jokken79's avatarfrom jokken79

Maestro de calidad de código - refactoring, code smells, arquitectura limpia y mejores prácticas

⭐1stars🔀0forks📁View on GitHub🕐Updated Jan 11, 2026

When & Why to Use This Skill

The Code Quality Master skill is a comprehensive tool designed to audit, maintain, and enhance software codebases. It specializes in identifying 'code smells,' implementing automated refactoring patterns, and enforcing SOLID principles and Clean Architecture. By providing deep analysis of cyclomatic complexity and maintainability indices, it helps developers eliminate technical debt and ensure high-performance, readable, and scalable code.

Use Cases

  • Automated detection and refactoring of 'Code Smells' such as God Classes, Long Methods, and Feature Envy to improve code readability.
  • Applying SOLID principles and Clean Code guidelines to legacy codebases to transform them into maintainable and modular systems.
  • Calculating and monitoring software quality metrics, including Cyclomatic Complexity and the Maintainability Index, for data-driven optimization.
  • Restructuring complex conditional logic using polymorphism and extracting classes to adhere to the Single Responsibility Principle.
  • Providing architectural recommendations and modularization strategies for large-scale projects (e.g., splitting monolithic files into service-oriented structures).
namecode-quality-master
descriptionMaestro de calidad de código - refactoring, code smells, arquitectura limpia y mejores prácticas

Code Quality Master Skill

Skill especializado en mantener y mejorar la calidad del código a través de detección de code smells, refactoring automático, y aplicación de principios de arquitectura limpia.

Principios de Calidad

SOLID Principles

S - Single Responsibility: Una clase, una razón para cambiar
O - Open/Closed: Abierto para extensión, cerrado para modificación
L - Liskov Substitution: Subtipos sustituibles por tipos base
I - Interface Segregation: Interfaces específicas > interfaces grandes
D - Dependency Inversion: Depender de abstracciones, no de concretos

Clean Code Guidelines

# 1. Nombres significativos
# MALO
def calc(d, u):
    return (u / d) * 100

# BUENO
def calculate_usage_rate(granted_days: float, used_days: float) -> float:
    return (used_days / granted_days) * 100

# 2. Funciones pequeñas (< 20 líneas)
# 3. Un nivel de abstracción por función
# 4. Comentarios solo cuando el código no puede explicarse
# 5. Manejo de errores separado de lógica de negocio

Detección de Code Smells

Catálogo de Smells

1. Long Method (> 50 líneas)

# Detección
def detect_long_methods(file_content: str, threshold: int = 50) -> list:
    """Detecta métodos con más de N líneas."""
    issues = []
    for func in extract_functions(file_content):
        if func['line_count'] > threshold:
            issues.append({
                'type': 'LONG_METHOD',
                'name': func['name'],
                'lines': func['line_count'],
                'suggestion': 'Extract smaller methods with single responsibility'
            })
    return issues

# Refactoring: Extract Method
# ANTES
def process_employees(employees):
    # 100 líneas de código
    pass

# DESPUÉS
def process_employees(employees):
    validated = validate_employees(employees)
    enriched = enrich_with_metadata(validated)
    return save_to_database(enriched)

2. God Class (> 20 métodos o > 500 líneas)

# ANTES: App class con 50+ métodos
class App:
    def init_data(self): ...
    def fetch_employees(self): ...
    def render_table(self): ...
    def render_charts(self): ...
    def handle_click(self): ...
    # ... 45 métodos más

# DESPUÉS: Separar en clases especializadas
class DataService:
    def fetch_employees(self): ...
    def sync_data(self): ...

class UIManager:
    def render_table(self): ...
    def render_charts(self): ...

class EventHandler:
    def handle_click(self): ...

3. Feature Envy

# MALO: Método que usa más datos de otra clase
def calculate_employee_stats(employee):
    return {
        'usage_rate': (employee.used / employee.granted) * 100,
        'is_compliant': employee.used >= 5,
        'days_remaining': employee.granted - employee.used
    }

# BUENO: Mover lógica a la clase Employee
class Employee:
    def get_usage_rate(self) -> float:
        return (self.used / self.granted) * 100

    def is_compliant(self) -> bool:
        return self.used >= 5

    @property
    def days_remaining(self) -> float:
        return self.granted - self.used

4. Data Clumps

# MALO: Grupos de datos que siempre van juntos
def create_employee(name, employee_num, hire_date, department, factory):
    ...

def update_employee(employee_id, name, employee_num, hire_date, department, factory):
    ...

# BUENO: Agrupar en objetos
@dataclass
class EmployeeInfo:
    name: str
    employee_num: str
    hire_date: date
    department: str
    factory: str

def create_employee(info: EmployeeInfo):
    ...

5. Primitive Obsession

# MALO: Usar primitivos para conceptos de dominio
def process_leave_request(employee_num: str, days: float, leave_type: str):
    if leave_type not in ['full', 'half_am', 'half_pm', 'hourly']:
        raise ValueError("Invalid leave type")

# BUENO: Usar tipos específicos
from enum import Enum

class LeaveType(Enum):
    FULL = 'full'
    HALF_AM = 'half_am'
    HALF_PM = 'half_pm'
    HOURLY = 'hourly'

@dataclass
class LeaveRequest:
    employee_num: str
    days: float
    leave_type: LeaveType

Matriz de Severidad

Smell Severidad Impacto en Mantenibilidad
Long Method 🟠 MEDIUM -20% readability
God Class 🔴 HIGH -40% maintainability
Feature Envy 🟡 LOW -10% cohesion
Data Clumps 🟠 MEDIUM -15% clarity
Primitive Obsession 🟡 LOW -10% type safety
Duplicate Code 🔴 HIGH -50% DRY
Dead Code 🟠 MEDIUM -25% clarity
Magic Numbers 🟡 LOW -15% clarity

Refactoring Patterns

1. Extract Class

# ANTES
class Employee:
    def __init__(self):
        self.name = ""
        self.birth_date = ""
        self.address = ""
        self.city = ""
        self.postal_code = ""
        self.hire_date = ""
        self.granted_days = 0
        self.used_days = 0

    def get_full_address(self):
        return f"{self.address}, {self.city} {self.postal_code}"

    def get_balance(self):
        return self.granted_days - self.used_days

# DESPUÉS
@dataclass
class Address:
    street: str
    city: str
    postal_code: str

    def __str__(self):
        return f"{self.street}, {self.city} {self.postal_code}"

@dataclass
class VacationBalance:
    granted: float
    used: float

    @property
    def remaining(self) -> float:
        return self.granted - self.used

@dataclass
class Employee:
    name: str
    birth_date: date
    hire_date: date
    address: Address
    vacation: VacationBalance

2. Replace Conditional with Polymorphism

# ANTES
def calculate_days(employee_type: str, seniority: float) -> int:
    if employee_type == 'fulltime':
        return get_fulltime_days(seniority)
    elif employee_type == 'parttime':
        return get_parttime_days(seniority)
    elif employee_type == 'contract':
        return get_contract_days(seniority)

# DESPUÉS
from abc import ABC, abstractmethod

class EmployeeType(ABC):
    @abstractmethod
    def calculate_days(self, seniority: float) -> int:
        pass

class FullTimeEmployee(EmployeeType):
    def calculate_days(self, seniority: float) -> int:
        return get_fulltime_days(seniority)

class PartTimeEmployee(EmployeeType):
    def calculate_days(self, seniority: float) -> int:
        return get_parttime_days(seniority)

3. Introduce Parameter Object

# ANTES
def search_employees(
    name: str = None,
    department: str = None,
    factory: str = None,
    year: int = None,
    min_balance: float = None,
    max_balance: float = None,
    is_compliant: bool = None,
    sort_by: str = None,
    sort_order: str = None,
    page: int = 1,
    page_size: int = 50
):
    pass

# DESPUÉS
@dataclass
class EmployeeSearchCriteria:
    name: str = None
    department: str = None
    factory: str = None
    year: int = None
    min_balance: float = None
    max_balance: float = None
    is_compliant: bool = None

@dataclass
class PaginationOptions:
    page: int = 1
    page_size: int = 50
    sort_by: str = None
    sort_order: str = 'asc'

def search_employees(
    criteria: EmployeeSearchCriteria,
    pagination: PaginationOptions = None
):
    pass

Métricas de Calidad

Complejidad Ciclomática

def calculate_cyclomatic_complexity(func_ast) -> int:
    """
    CC = 1 + número de puntos de decisión

    Puntos de decisión:
    - if, elif, else
    - for, while
    - try, except
    - and, or
    - case (match)
    """
    complexity = 1
    for node in ast.walk(func_ast):
        if isinstance(node, (ast.If, ast.For, ast.While, ast.ExceptHandler)):
            complexity += 1
        elif isinstance(node, ast.BoolOp):
            complexity += len(node.values) - 1
    return complexity

# Thresholds
COMPLEXITY_THRESHOLDS = {
    'GOOD': (1, 10),
    'MODERATE': (11, 20),
    'HIGH': (21, 50),
    'VERY_HIGH': (51, float('inf'))
}

Maintainability Index

def calculate_maintainability_index(
    halstead_volume: float,
    cyclomatic_complexity: int,
    loc: int
) -> float:
    """
    MI = 171 - 5.2 * ln(V) - 0.23 * G - 16.2 * ln(LOC)

    Where:
    - V = Halstead Volume
    - G = Cyclomatic Complexity
    - LOC = Lines of Code

    Score interpretation:
    - 85+: Highly maintainable
    - 65-84: Moderately maintainable
    - <65: Difficult to maintain
    """
    import math
    mi = 171 - 5.2 * math.log(halstead_volume) \
             - 0.23 * cyclomatic_complexity \
             - 16.2 * math.log(loc)
    return max(0, min(100, mi))

Code Coverage Quality

COVERAGE_QUALITY_RULES = {
    'line_coverage': {
        'min': 70,
        'good': 80,
        'excellent': 90
    },
    'branch_coverage': {
        'min': 60,
        'good': 75,
        'excellent': 85
    },
    'function_coverage': {
        'min': 80,
        'good': 90,
        'excellent': 95
    }
}

Análisis Automático

Output de Análisis

{
    "file": "main.py",
    "metrics": {
        "loc": 5058,
        "functions": 145,
        "classes": 8,
        "avg_complexity": 4.2,
        "max_complexity": 32,
        "maintainability_index": 72
    },
    "code_smells": [
        {
            "type": "LONG_METHOD",
            "location": "main.py:234-350",
            "name": "sync_all_data",
            "lines": 116,
            "suggestion": "Extract into smaller methods: parse_excel, validate_data, save_to_db"
        },
        {
            "type": "DUPLICATE_CODE",
            "locations": ["main.py:400-420", "main.py:500-520"],
            "similarity": 0.92,
            "suggestion": "Extract common logic to shared function"
        }
    ],
    "refactoring_opportunities": [
        {
            "pattern": "EXTRACT_METHOD",
            "function": "get_employees_by_type",
            "benefit": "Reduce complexity from 15 to 5",
            "risk": "LOW"
        }
    ],
    "quality_score": "B",
    "recommendations": [
        "Split main.py into multiple modules (routes/, services/)",
        "Add type hints to 45 functions missing them",
        "Remove 12 unused imports"
    ]
}

Integración con YuKyuDATA

Refactorings Prioritarios

1. Modularizar main.py

# Estructura propuesta
app/
├── main.py              # Solo setup de FastAPI
├── routes/
│   ├── employees.py     # Endpoints de empleados
│   ├── leave_requests.py # Endpoints de solicitudes
│   ├── compliance.py    # Endpoints de compliance
│   └── analytics.py     # Endpoints de analytics
├── services/
│   ├── employee_service.py
│   ├── leave_service.py
│   └── compliance_service.py
├── models/
│   ├── employee.py
│   ├── leave_request.py
│   └── compliance.py
└── utils/
    ├── validators.py
    └── formatters.py

2. Aplicar Domain Objects

# Antes: Diccionarios por todos lados
employee = {
    'employee_num': '001',
    'name': 'Tanaka',
    'granted': 10,
    'used': 5,
    'year': 2025
}

# Después: Domain models
from pydantic import BaseModel

class Employee(BaseModel):
    employee_num: str
    name: str
    granted: float
    used: float
    year: int

    @property
    def balance(self) -> float:
        return self.granted - self.used

    @property
    def usage_rate(self) -> float:
        if self.granted == 0:
            return 0
        return (self.used / self.granted) * 100

    def is_compliant_with_5day_rule(self) -> bool:
        return self.granted < 10 or self.used >= 5

Comandos de Análisis

# Python
# Complexity analysis
pip install radon
radon cc main.py -a -s  # Cyclomatic complexity
radon mi main.py -s     # Maintainability index
radon hal main.py       # Halstead metrics

# Linting
pip install pylint flake8 mypy
pylint main.py --output-format=json
flake8 main.py --format=json
mypy main.py --json

# JavaScript
# ESLint with complexity
npx eslint static/js/app.js --format=json

# Code duplication
pip install pylint
pylint --disable=all --enable=duplicate-code *.py

# Dead code
pip install vulture
vulture . --min-confidence 80

Principio Guía: "El código limpio es código que otros desarrolladores pueden leer, entender y modificar con confianza."