Files
jaildoctors_dilemma/.claude/commands/refactor-class.md
2025-11-11 13:02:25 +01:00

8.5 KiB

description
description
Refactoriza una clase C++ aplicando buenas prácticas de estilo

Refactor Class Command

Refactoriza una clase C++ siguiendo estas reglas de estilo y buenas prácticas:

Reglas de Refactorización

1. Inicialización de Variables Miembro

  • Inicializar en la declaración todas las variables "simples" que no tengan dependencias complejas:
    • Tipos primitivos: int, float, bool, etc.
    • Enumeraciones: valores de enum class
    • Valores por defecto conocidos: 0, 0.0F, false, nullptr, etc.
  • NO inicializar en declaración si:
    • Dependen de otros miembros
    • Requieren llamadas a funciones complejas
    • Son punteros a recursos que necesitan construcción específica

2. Structs con Valores por Defecto

  • Todos los miembros de structs deben tener valores por defecto:
    • Tipos primitivos: int x{0}, float y{0.0F}, bool flag{false}
    • Strings: std::string name{}
    • Punteros: Type* ptr{nullptr}
  • Ventajas: Inicialización segura, evita valores indefinidos

3. Arrays C-style → std::array

  • Convertir todos los arrays C-style a std::array:
    • Type array[N]std::array<Type, N> array{}
    • Inicializar con {} para zero-initialization
  • Agregar #include <array> si no existe
  • Ventajas: type-safety, size(), métodos STL, sin decay a pointer

3. Reorganización de la Clase

Orden de Secciones

  1. public (primero)
  2. private (después)

Dentro de cada sección (private principalmente)

  1. Estructuras y enumeraciones (tipos anidados)
  2. Constantes (static constexpr)
  3. Métodos (funciones miembro)
  4. Variables miembro (al final)

4. Agrupación y Comentarios de Métodos

  • En sección public: Agrupar métodos relacionados funcionalmente
  • Comentarios en línea (a la derecha) para describir cada método/grupo
  • Formato: void method(); // Descripción concisa
  • Espaciado: Línea en blanco entre grupos funcionales

Ejemplo:

public:
    static void init(...);    // Inicialización singleton
    static void destroy();    // Destrucción singleton
    static auto get() -> T*;  // Acceso al singleton

    void render();            // Renderizado
    void update(float dt);    // Actualización lógica

    auto isActive() -> bool;  // Consulta estado

5. Comentarios de Variables

  • Posición: A la derecha de la variable/grupo
  • Formato: // Descripción concisa
  • Agrupar variables relacionadas con un comentario común

6. Constructores en Structs

  • Eliminar constructores por defecto redundantes en structs:
    • Si todos los miembros tienen inicialización en declaración
    • Y no hay múltiples constructores
    • Eliminar explicit Type() = default;
  • El compilador generará automáticamente un constructor por defecto

Ejemplo:

struct Data {
    int x{0};
    std::string name{};
    // NO NECESITA: explicit Data() = default;
};

7. Includes Necesarios

  • Agregar includes faltantes según lo que se use
  • Mantener orden alfabético si es posible

8. Header Guards

  • Usar #pragma once en todas las cabeceras (.hpp)
  • NO usar #ifndef/#define/#endif tradicionales
  • #pragma once debe ser la primera línea del archivo (antes de includes)
  • Ventajas: Más simple, menos propenso a errores, ampliamente soportado

Ejemplo de Aplicación

Antes:

class Example {
    private:
        struct Data {
            std::string name;
            int value;
        };

        int counter_;
        bool flag_;
        float values_[10];

    public:
        Example();
        void update();
};

// Constructor
Example::Example()
    : counter_(0),
      flag_(false) {
    for (int i = 0; i < 10; ++i) {
        values_[i] = 0.0F;
    }
}

Después:

#pragma once

#include <array>

class Example {
    public:
        Example() = default;  // Ya no necesita inicializar
        void update();

    private:
        // Tipos anidados
        struct Data {
            std::string name{};    // Nombre con valor por defecto
            int value{0};          // Valor inicializado
        };

        // Variables miembro
        int counter_{0};                        // Contador de frames
        bool flag_{false};                      // Estado activo
        std::array<float, 10> values_{};        // Buffer de valores
};

Tareas a Realizar

Cuando uses este comando en una clase específica:

  1. Leer el archivo .hpp y .cpp correspondiente
  2. Verificar que la cabecera use #pragma once (reemplazar #ifndef/#define/#endif si existen)
  3. Identificar structs y agregar valores por defecto a todos sus miembros
  4. Identificar variables que pueden inicializarse en declaración
  5. Identificar arrays C-style que convertir a std::array
  6. Reorganizar la estructura de la clase (public/private, agrupación)
  7. Actualizar el archivo .cpp eliminando inicializaciones redundantes
  8. Compilar para verificar sintaxis correcta
  9. Ejecutar clang-tidy (análisis, sin --fix) y revisar resultados
  10. Ejecutar cppcheck (nivel -w) y revisar resultados
  11. Aplicar fixes apropiados basados en análisis de linters
  12. Recompilar si se aplicaron fixes
  13. Reportar resumen al usuario: cambios + hallazgos de linters

Workflow de Linters (Pasos 9-12)

Paso 9: Ejecutar clang-tidy

tools/linter/run_clang-tidy.sh archivo.cpp archivo.hpp

Analizar resultados:

  • Identificar issues críticos (bugprone, cert)
  • Separar recomendaciones válidas de falsos positivos
  • Ignorar: magic-numbers en game constants, defaults.hpp errors
  • Si hay issues críticos, informar al usuario y pausar
  • Si solo hay recomendaciones, continuar

Paso 10: Ejecutar cppcheck

tools/linter/run_cppcheck.sh -w --path archivo.cpp

Leer archivo de resultados:

  • tools/linter/cppcheck-result-warning-style-performance.txt
  • Identificar errores críticos (error, nullPointer, uninitvar)
  • Separar warnings de style issues
  • Filtrar falsos positivos (passedByValue para tipos pequeños, unusedFunction en API pública)
  • Si hay errores críticos, informar al usuario y pausar

Paso 11: Aplicar Fixes

Si hay issues aplicables:

  1. Fixes automáticos de clang-tidy (solo si son seguros):

    • modernize-use-auto
    • readability-redundant-access-specifiers
    • Performance optimizations claras
    tools/linter/run_clang-tidy.sh --fix archivo.cpp archivo.hpp
    
  2. Fixes manuales necesarios:

    • Inicializar variables no inicializadas
    • Corregir null pointer issues
    • Resolver memory leaks
  3. Documentar cambios para el reporte final

Paso 12: Recompilar

Si se aplicaron fixes en paso 11:

cmake --build build

Verificar:

  • Compilación exitosa → Continuar a reporte
  • Errores → Informar al usuario, sugerir revisión manual

Formato de Reporte Final (Paso 13)

=== Refactor Completado: ClassName ===

📝 Cambios estructurales:
  ✅ #pragma once aplicado
  ✅ 3 structs actualizados con valores por defecto
  ✅ 12 variables movidas a inicialización en declaración
  ✅ 2 arrays C-style → std::array
  ✅ Clase reorganizada (public primero, variables al final)
  ✅ Constructor simplificado (elimina 12 inicializaciones redundantes)

🔍 Análisis de linters:

clang-tidy:
  ✅ Sin issues críticos
  🟡 3 recomendaciones aplicadas automáticamente:
     - Modernize: use auto (2 lugares)
     - Readability: redundant specifier (1 lugar)
  ⚪ 2 opcionales ignorados:
     - magic-numbers en game constants

cppcheck:
  ✅ Sin errores
  🟡 2 style issues encontrados:
     - Unused variable 'temp' en línea 45 → Eliminada
     - Redundant assignment en línea 102 → Corregida

📊 Resultado:
  ✅ Compilación exitosa
  ✅ Todos los linters pasan sin issues críticos
  ✅ Código refactorizado y verificado

💡 Próximos pasos:
  - Revisar cambios manualmente
  - Ejecutar tests si existen
  - Commitear con mensaje descriptivo

Notas Importantes

  • No cambiar lógica: Solo refactorización estructural
  • Mantener compatibilidad: std::array usa misma sintaxis [] para acceso
  • Formato consistente: Respetar estilo del proyecto (comentarios, espaciado)
  • Validar compilación: Siempre verificar que compile después de cambios
  • Linters integrados: Análisis automático post-refactor para garantizar calidad
  • Fixes inteligentes: Solo aplicar --fix de clang-tidy si los cambios son seguros
  • Contexto importa: Game code tiene patrones legítimos (magic numbers, etc.)
  • Falsos positivos: Identificar y documentar, no corregir ciegamente