Análisis profundo de arquitectura de motor de juego en C++ con 29,785 símbolos (27,580 líneas), 989 funciones analizadas: complejidad, acoplamiento modular, código muerto y recomendaciones de refactorización.
MasbitsEngine es un motor de juego en C++ con renderer Vulkan que sirve como proyecto central del portfolio. Este análisis estático fue realizado con CodeGraph (AST analysis con Louvain community detection), Daem0n MCP y Engram para evaluar la salud arquitectural del código. 989 funciones analizadas de 29,785 símbolos totales, con corrección por falsos positivos de código condicional #if EDITOR / #if ENGINE.
| Lenguaje | Extensión | Líneas | Porcentaje |
|---|---|---|---|
| C++ | .cpp | 17,553 | 63.7% |
| C++ | .hpp | 9,823 | 35.6% |
| C++ | .h | 204 | 0.7% |
| Total C++ | — | 27,580 | 100% |
| # | Función | Archivo | Cicl. | Cogn. | MI | Líneas |
|---|---|---|---|---|---|---|
| 1 | EditorActions::executeEditorActions | src/Editor/Manager/editorActions.cpp:284 | 58 | 332 | 22.9 | 373 |
| 2 | CVulkanRenderImpl::handleMousePicking | src/RenderCore/Renderer/renderer.cpp:1315 | 54 | 88 | 32.4 | 222 |
| 3 | TilePreviewDialog::renderView | src/Editor/Data/TilePreviewDialog.cpp:1088 | 53 | 163 | 30.6 | 273 |
| 4 | TilesetGenerationDialog::renderView | src/Editor/Data/TilesetGenerationDialog.cpp:1002 | 53 | 163 | 30.6 | 287 |
| 5 | TilesetGenerationDialog::renderGridPreview | src/Editor/Data/TilesetGenerationDialog.cpp:1905 | 49 | 117 | 31.8 | 287 |
El análisis Louvain community detection reveló que módulos con alto número de comunidades están fragmentados — indicando architectural drift. Cada comunidad representa una agrupación natural de código que debería corresponder a una responsabilidad cohesiva.
| Módulo | Comunidades | Interpretación |
|---|---|---|
RenderCore/BaseRender | 19 | Muy fragmentado — múltiples responsabilidades mezcladas |
Game/Player/AnimStates | 18 | Alta fragmentación — estados de animación dispersos |
Game/Components | 16 | Fragmentado — componentes con responsabilidades cruzadas |
Editor/Data | 15 | Considerable — editor y gestión de datos acoplados |
RenderCore/Renderer | 14 | Significativo — renderer con múltiples sub-responsabilidades |
High community count indica que el código se agrupa naturalmente en muchas comunidades pequeñas en lugar de pocas comunidades grandes y cohesivas. Esto es un síntoma de architectural drift — el código ha evolucionado hacia múltiples responsabilidades dentro de lo que deberían ser módulos con fronteras claras.
Funciones que superan umbrales de complejidad y tienen alto riesgo de bugs. Corregidas las clasificaciones de dead-ffi que no consideraban código dentro de bloques #if condicionales.
| Función | Cognitiva | MI | Llaman | Estado Real |
|---|---|---|---|---|
EditorActions::executeEditorActions | 332 | 22.9 | Sí (appEngineTraits.cpp:63, 100) | #if EDITOR — CodeGraph marcó falso dead-ffi |
loadLevelFromFile | 187 | 13.6 | Sí (editormanager.cpp:113, gamemanager.cpp:50) | Falso dead-ffi — llamada desde ambos modos |
CVulkanRenderImpl::handleMousePicking | 88 | 32.4 | Interna | renderer.cpp — complejidad alta inherente al Vulkan |
CVulkanRenderImpl::buildCommandBuffers | 110 | 22.6 | Interna | 456 líneas, nesting 6 |
TilePreviewDialog::renderView | 163 | 30.6 | Interna | #if EDITOR — falso dead-ffi |
executeEditorActions373 líneas, nesting depth 12, MI 22.9 (crítico). Esta función fue clasificada como dead-ffi por CodeGraph, pero está llamada desde appEngineTraits.cpp:63 y :100 dentro de bloques #if EDITOR. Recomendación: extraer cada caso del switch en su propia función policy-driven, reducir nesting con early returns, y verificar callers dentro de bloques condicionales.
loadLevelFromFileMI 13.6 (crítico). Clasificada como dead-ffi pero llamada desde editormanager.cpp:113 y gamemanager.cpp:50 — existe en ambos modos de compilación. Recomendación: separar parsers por formato en funciones dedicadas, aplicar Strategy pattern para cada tipo de nivel.
Algoritmo de detección de comunidades en grafos que agrupa nodos densamente conectados. Usado para identificar módulos naturales del código y medir fragmentation. Un alto número de comunidades por módulo indica architectural drift.
Modela las rutas de ejecución dentro de cada función. Permite calcular cyclomatic complexity (# rutas independientes) y cognitive complexity (# decisiones anidadas que el cerebro humano debe rastrear).
Clasificación de funciones como dead-ffi (Foreign Function Interface) — funciones que no tienen callers en el grafo de llamadas. Indica código muerto o funciones de API no utilizadas actualmente.
rastreo de cómo fluyen los datos entre funciones a través de parámetros y valores de retorno. Permite calcular el blast radius de cambios y dependencies transitivas.
Análisis AST con Louvain community detection, CFG analysis, dead-ffi classification, data flow edges y impact analysis
AI memory system con persistent context, outcome tracking y semantic search para decisiones arquitecturales previas
Persistent memory capture for technical decisions, bug fixes y patterns established during the analysis
Knowledge base con historical context sobre evolutions del proyecto y trade-offs arquitecturales previos
| Herramienta | Propósito |
|---|---|
| CodeGraph | |
| Daem0n MCP | |
| Engram | |
| OpenLore |
Puntuación de cuan difícil es seguir mentalmente el código. Penaliza anidación (+1 por nivel) y saltos lógicos (+1 por if/else/for/while). A diferencia del cyclomatic, crece con la profundidad de anidación. Threshold de warning: 15.
Número de caminos de ejecución independientes en una función. Se calcula como E - N + 2P (edges - nodes + 2*connected components). Threshold de warning: 10. No penaliza anidación directamente.
Puntuación 0-100 que combina cyclomatic complexity, lines of code y cyclomatic per LOC. Valores >20 indican código difícil de mantener. 20-25 = crítico, 25-40 = alto riesgo, >40 = aceptable. Threshold de warning: 20.
CodeGraph lee archivos fuente directamente sin ejecutar el preprocesador C++ (#if, #ifdef, #endif). Esto causa falsos negativos en la detección de código muerto: funciones llamadas solo dentro de bloques condicionales se clasifican como dead-ffi o dead-leaf aunque existen en el códigobase.
| Paso | Lo que hace CodeGraph | Resultado |
|---|---|---|
| 1. Lectura de fuente | Lee appEngineTraits.cpp directamente | Sin evaluar #if EDITOR |
| 2. AST vacío | Funciones dentro del #if no tienen callers | 0 callers detectados |
| 3. Clasificación | Sin callers → dead-ffi | dead-ffi (falso positivo) |
| 4. Verificación | grep -r "func" --include="*.cpp" encuentra llamadas dentro de #if EDITOR | Código es vivo, no muerto |
| Función | Archivo | Clasificación CodeGraph | Realidad |
|---|---|---|---|
AppEngine::OnEvent | appEngineTraits.cpp:63 | dead-ffi | Callada dentro de #if EDITOR — código vivo |
AppEngine::Run | appEngineTraits.cpp:100 | dead-ffi | Callada dentro de #if EDITOR — código vivo |
dead-ffi, ejecutar grep -r "function_name" --include="*.cpp" --include="*.h" --include="*.hpp" --include="*.inl" antes de concluir que el código es no utilizado. Si grep encuentra llamadas dentro de bloques #if, el código es vivo en ese modo de compilación.
Las aproximaciones fallidas reciben 1.5x boost en búsquedas futuras de Daem0n para evitar repetir enfoques que ya demostraron no funcionar con código condicional.