8.5 KiB
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.
- Tipos primitivos:
- 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}
- Tipos primitivos:
- 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
- public (primero)
- private (después)
Dentro de cada sección (private principalmente)
- Estructuras y enumeraciones (tipos anidados)
- Constantes (static constexpr)
- Métodos (funciones miembro)
- 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 onceen todas las cabeceras (.hpp) - NO usar
#ifndef/#define/#endiftradicionales #pragma oncedebe 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:
- Leer el archivo
.hppy.cppcorrespondiente - Verificar que la cabecera use
#pragma once(reemplazar#ifndef/#define/#endifsi existen) - Identificar structs y agregar valores por defecto a todos sus miembros
- Identificar variables que pueden inicializarse en declaración
- Identificar arrays C-style que convertir a std::array
- Reorganizar la estructura de la clase (public/private, agrupación)
- Actualizar el archivo
.cppeliminando inicializaciones redundantes - Compilar para verificar sintaxis correcta
- Ejecutar clang-tidy (análisis, sin --fix) y revisar resultados
- Ejecutar cppcheck (nivel -w) y revisar resultados
- Aplicar fixes apropiados basados en análisis de linters
- Recompilar si se aplicaron fixes
- 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:
-
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 -
Fixes manuales necesarios:
- Inicializar variables no inicializadas
- Corregir null pointer issues
- Resolver memory leaks
-
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