Claude Code Plugins

Community-maintained marketplace

Feedback

code-quality-master

@jokken79/YuKyuDATA-app1.0v
1
0

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

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name code-quality-master
description Maestro 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."