🪣 Síntomas de una bola de lodo
"Big ball of mud" es el término arquitectónico para código donde nada tiene lugar: responsabilidades mezcladas, dependencias circulares, módulos que crecen por acreción. Lo reconoces por el olor: cada cambio simple se propaga en cascada a tres archivos no relacionados.
✓ Código saludable
- ✓Cada módulo tiene una responsabilidad clara y fácil de nombrar
- ✓Las dependencias fluyen en una dirección (nivel alto → nivel bajo)
- ✓Vocabulario coherente entre código, pruebas y documentación
- ✓La duplicación es una excepción justificada
- ✓Prevés dónde vivirá una nueva feature
- ✓Cambiar una implementación no se filtra a 10 lugares
✗ Ball of mud
- ✗"Helper" / "utils" / "core" gigantes y sin enfoque
- ✗A importa B, que importa A (ciclos)
- ✗El mismo concepto tiene 3 nombres (user / customer / account)
- ✗Copiar y pegar con pequeñas modificaciones en varios lugares
- ✗Toda feature nueva requiere un "recorrido" para saber dónde ponerla
- ✗Cambiar una regla requiere buscar en 8 archivos
Señales típicas (code smells arquitectónicos)
- • God modules: un archivo de 2.000 líneas que "todos importan"
- • Shotgun surgery: un cambio simple toca 15 archivos
- • Envidia de funcionalidades: métodos que modifican más los datos de otra clase que los propios
- • Magic strings / numbers dispersos, sin una constante central
- • Condicionales por tipo: if/elif gigante que comprueba "type === 'X'"
- • Wrappers que solo reenvían: capas que no deciden nada
🔍 /improve-codebase-architecture
El comando /improve-codebase-architecture no pide "refactorizar todo".
Hace lo más útil: lista oportunidades de profundización — puntos donde
el código puede quedar significativamente más saludable, ordenados por impacto. El análisis se basa en el
CONTEXT.md y por los ADR del proyecto, así que las sugerencias respetan
lo que ya se decidió.
⚙️ Qué hace el comando
- •Lee CONTEXT.md para entender el dominio y el vocabulario del proyecto
- •Lee los ADRs para saber qué decisiones arquitectónicas están vigentes
- •Recorre la estructura del código buscando señales que contradigan el dominio
- •Devuelve una lista priorizada de oportunidades, no un plan de reescritura
- •Cada elemento tiene: descripción, impacto estimado, esfuerzo y punto de partida
Ejemplo de salida
terminal$ /improve-codebase-architecture # 5 deepening opportunities identified (sorted by impact) [1] HIGH src/billing/ — "materialization cascade" lives in 4 modules Impact: unifica lógica fragmentada, fecha conceito do CONTEXT.md Effort: 2-3 dias | Risk: medium Start: src/billing/cascade.py (extract; ADR-009 references this) [2] HIGH src/utils/helpers.py — 1,847 lines, 23 unrelated functions Impact: quebra god module; melhora descoberta Effort: 1-2 dias | Risk: low (mostly mechanical) Start: agrupar por consumer; mover; testar [3] MED "customer" vs "user" vs "account" usados intercambiavelmente Impact: alinha código ao glossário do CONTEXT.md (Sec. 2.3) Effort: 1 dia | Risk: low Start: renomear customer.* (canonical) e atualizar callsites [4] MED ciclo: api/orders → services/inventory → api/orders Impact: remove ciclo; clarifica direção de dependência Effort: meio dia | Risk: low Start: extract InventoryPort interface [5] LOW tests/ duplica fixtures de billing em 6 arquivos Impact: reduz manutenção de testes Effort: 2h | Risk: very low Start: conftest.py compartilhado por subdir
💡 Consejo
Ejecuta este comando antes de planificar el próximo ciclo. Te da una lista honesta de deuda arquitectónica para elegir 1 elemento por sprint, no para abordarlo todo de una vez.
🔭 /zoom-out — perspectiva general
Hay un patrón de falla común: el agente entra en un archivo, empieza a optimizar una función y, después de
20 minutos, está reescribiendo lógica aislada, sin darse cuenta de que esa función
ni siquiera debería existir en este módulo. /zoom-out sirve para
esto: obligar al agente a detenerse y pedir contexto de nivel superior antes de continuar.
Zoom-in inicial (detalle)
El agente entra en el archivo X y empieza a editar
Un enfoque estrecho es necesario para hacer el cambio inmediato, pero se convierte en una trampa cuando la función, el archivo, o incluso todo el módulo están en el lugar equivocado. El agente «se hunde» sin preguntar si el problema es mayor.
Zoom-out (panorama)
/zoom-out — pide contexto arquitectónico
El comando sube un nivel: ¿cuál es la responsabilidad de este módulo? ¿Qué dice CONTEXT.md? ¿Dónde está esta lógica debería ¿pertenecer? La pregunta correcta cambia de «¿cómo mejorar esta función?» a «¿esta función pertenece aquí?». A menudo, la mejor edición es mover o eliminar, no optimizar.
Zoom-in con contexto (detalle con mapa)
Vuelves al código, pero con una visión general
Ahora la edición local se guía por la arquitectura. Sabes qué NO hacer (crear nuevo acoplamiento, duplicar la lógica de otro módulo) y qué SÍ hacer (extraer, mover, alinear los nombres con el glosario). El detalle importa, pero está al servicio de la estructura.
💡 Usa /zoom-out cuando…
- • Estás editando el mismo archivo desde hace >15 minutos sin un progreso claro
- • El cambio simple se está convirtiendo en 4 archivos diferentes
- • El agente está "corrigiendo" algo que, en realidad, es síntoma de otro problema
- • Antes de aceptar una sugerencia grande que afecta varios módulos
🌱 Oportunidades para profundizar, no reescrituras
Deepening es un término tomado de Eric Evans (DDD): profundizar en el modelado donde el dominio es más importante, sin descartar lo que ya funciona. Es lo opuesto al impulso de "vamos a reescribir desde cero", que cuesta caro, rara vez cumple lo prometido y descarta todo el aprendizaje incorporado en el código actual.
✗ Reescritura destructiva
- ✗"Vamos a desecharlo y rehacerlo con la nueva arquitectura"
- ✗Rama paralela de 3-6 meses sin entregar
- ✗Pierde casos límite que el código actual ya contempla
- ✗Merge big bang → regresiones silenciosas masivas
- ✗El equipo se queda atascado en lo nuevo y se retrasa el soporte de lo anterior
- ✗Las lecciones aprendidas (CONTEXT.md, ADRs) se vuelven basura
✓ Profundización incremental
- ✓"Vamos a mejorar 1 oportunidad por sprint, sin dejar de entregar"
- ✓Cada PR es pequeño, fácil de revisar y de integrar
- ✓Mantiene los casos límite mientras refina la forma
- ✓Las regresiones aparecen pronto, en cambios pequeños
- ✓El equipo sigue entregando funcionalidades en paralelo
- ✓CONTEXT.md y ADRs evolucionan juntos y se convierten en una referencia viva
📖 Término: deepening
Deepening = profundizar en el modelado del dominio de forma incremental. En vez de reescribir, identificas conceptos que están "torcidos" en el código (ocultos en utils, dispersos, con nombres inadecuados) y los elevas a ciudadanos de primera clase, una extracción a la vez.
Origen: Domain-Driven Design (Eric Evans, 2003) — "deepening the model".
🧭 CONTEXT.md como guía
O CONTEXT.md no es solo onboarding: es
la pauta arquitectónica del proyecto. El lenguaje del dominio que
describe es lo que orienta dónde refactorizar: los módulos que implementan conceptos centrales merecen más atención
arquitectónica que la infraestructura genérica.
🎯 Principio: concepto de dominio = atención arquitectónica
Ejemplo: si CONTEXT.md describe "cascada de materialización" como un concepto clave del sistema de billing —
la cadena por la que los cambios de precio se propagan a los contratos activos—, entonces el módulo que implementa
esa cascada no puede estar oculto en utils/helpers.py
dividido en 4 funciones independientes.
Lo más obvio para profundizar aquí es extraer billing/cascade.py con la cascade como entidad con nombre,
alineada con el vocabulario de CONTEXT.md. El comando /improve-codebase-architecture ves esta
desalineación porque él lee el CONTEXT.md.
Preguntas que responde CONTEXT.md
- • ¿Cuáles son los conceptos centrales? → merecen módulos propios y nombres consistentes
- • ¿Cuál es el glosario canónico? → «customer» vs. «user» se resuelve aquí, no en la revisión del PR
- • ¿Cuáles son los límites? → dónde pertenece una feature es función del bounded context
- • ¿Qué invariantes existen? → reglas que NO se pueden violar al refactorizar
💡 Consejo
Si el CONTEXT.md es vago o está desactualizado, esta es la primera oportunidad de profundización. Sin él, cualquier mejora arquitectónica será local y perderá coherencia.
📜 ADRs como memoria arquitectónica
ADR = Registro de decisiones de arquitectura. Un documento breve por cada decisión arquitectónica relevante. Sin ADRs, la siguiente refactorización deshace silenciosamente una decisión consciente, porque nadie la recuerda por qué X se separó de Y.
ADR-009 — ejemplo
docs/adr/0009-separate-cascade.md# ADR-009: Separar materialization cascade de pricing ## Status Accepted — 2025-08-14 ## Contexto A "materialization cascade" propaga mudanças de preço para contratos ativos. Originalmente vivia dentro de pricing/calculator.py porque parecia "cálculo de preço". Na prática, são duas responsabilidades: - pricing/ → calcula o preço de UM item, sem estado - cascade/ → reage a mudanças, atualiza N contratos, com estado Misturadas, qualquer mudança em pricing arriscava efeito colateral em milhares de contratos ativos. ## Decisão Extrair cascade para billing/cascade.py como entidade nomeada e independente. pricing/ vira pure function. cascade/ orquestra. ## Consequências + pricing testável sem mock de DB + cascade tem ownership claro de invariantes (idempotência, ordem) + vocabulário do CONTEXT.md (Sec. 4) finalmente reflete o código - duas pastas onde antes havia uma (custo de descoberta) - imports adicionais entre os módulos (acoplamento explícito) ## Alternativas consideradas - Manter junto: rejeitado, acopla cálculo a propagação - Event bus: prematuro, sem necessidade de async hoje - Inline em cada caller: rejeitado, duplicação garantida
🧠 Por qué importan los ADR en el deepening
- • Sin ADR, dentro de 6 meses alguien volverá a "consolidar" la cascada en pricing porque parece redundante
- • El ADR demuestra que la separación ya fue pensada y tiene un motivo
- •
/improve-codebase-architecturelee los ADR antes de sugerir — no propondrá algo ya rechazado - • Los ADRs descontinuados también sirven: registran aprendizajes ("intentamos X, no funcionó porque Y")
💡 Consejo: ADR corto > ADR perfecto
Un ADR de 1 página le gana a uno de 10 páginas que nadie escribe. Estado, Contexto, Decisión, Consecuencias: cuatro encabezados, párrafos cortos. Numéralos secuencialmente (0001, 0002…) y no los elimines: márcalos como
Superseded by ADR-XXX cuando se sustituya.
📈 Ejemplo de mejora progresiva
Cómo un equipo sale de una bola de lodo sin detener el producto. Narrativa de 3 sprints, basada en un patrón real: una oportunidad por sprint, CONTEXT.md y ADRs actualizados en cada ciclo.
Sprint 0 — Diagnóstico
Ejecutamos /improve-codebase-architecture por primera vez
La salida enumera 5 oportunidades. El equipo las debate en 30 min, elige abordar 3 en las próximas 3 sprints, en orden de impacto. Las otras 2 quedan explícitamente en el backlog: no se olvidan ni son urgentes.
Sprint 1 — Extraer cascade
Oportunidad #1: cascada de materialización dispersa
El equipo extrae billing/cascade.py como módulo con nombre. PR pequeño, ~400 líneas movidas, sin
cambiar el comportamiento. Escribe ADR-009 para documentar la decisión. Actualiza CONTEXT.md (Sec. 4) con el
vocabulario canónico. Las nuevas features siguen desarrollándose en paralelo, sin una rama aparte.
Sprint 2 — Dividir god module
Oportunidad #2: utils/helpers.py con 1.847 líneas
La mayoría es mecánica: agrupa las funciones por consumer y muévelas a módulos cercanos. 3 funciones «huérfanas» plantean preguntas: ¿qué son? La respuesta está en CONTEXT.md (una es cascade, debería haber ido en la S1; las otras dos exponen un concepto nuevo que se convierte en ADR-010). Bug evitado.
Sprint 3 — Alinear el vocabulario
Oportunidad #3: customer / user / account intercambiables
Renombrado guiado por el glosario de CONTEXT.md. Es mecánico, pero afecta muchos archivos: aquí una feature flag no ayuda, así que haz PRs pequeños por subdir, con la aprobación del codeowner del subdir. Al final, el código habla el mismo idioma que la documentación y los equipos de producto.
Sprint 4 — Repetir el diagnóstico
Vuelve a ejecutar /improve-codebase-architecture
Lista nueva: las 3 oportunidades originales desaparecieron (se resolvieron). Las 2 que quedaron en el backlog continúan. Pero surgieron 2 nuevas porque el dominio evolucionó en los 3 sprints. La arquitectura mejoró visiblemente, sin big bang, sin dejar de entregar.
📊 Resultado en 4 sprints
- •3 oportunidades de alto impacto resueltas, 2 ADR nuevos
- •CONTEXT.md actualizado 3 veces, se convirtió en una referencia viva
- •Cero pausas en las features del producto
- •Bug evitado (cascade huérfana en helpers), encontrado por casualidad
- •El equipo confía en el proceso: la siguiente ronda ya está planificada
🎯 Ejercicio práctico
No aprendes deepening leyendo. Aprendes ejecutando el comando en tu proyecto y defendiendo la elección de la primera oportunidad que abordar.
🛠️ Pasos
-
1.
Confirma las bases: ¿tu proyecto tiene CONTEXT.md? ¿Tiene al menos 1-2 ADRs? Si no, empieza por ahí (ese es el pre-deepening).
-
2.
Ejecuta /improve-codebase-architecture en el proyecto real (no en sandbox).
-
3.
Anota las 3 primeras sugerencias con: descripción, impacto, esfuerzo. No las 5: solo las 3 primeras.
-
4.
¿Cuál abordas primero? Puede ser la #1, pero quizá no. Defiende tu elección en 3 frases: por qué esta, por qué ahora y cuál es el riesgo de dejarla para después.
-
5.
Bonus: redacta el ADR antes de tocar el código. Si no puedes escribir 1 página para justificarlo, quizás la propuesta aún no esté madura.
💡 Criterio de selección
Buena primera opción: alto impacto, esfuerzo bajo-medio, riesgo bajo, toca un concepto del CONTEXT.md. Mala primera elección: alto impacto, pero también alto riesgo; guárdala para cuando el equipo ya confíe en el proceso.
⚠️ No hagas
- ✗Atacar las 5 oportunidades de una vez: volverás al rewrite
- ✗Omitir el ADR: dentro de 6 meses nadie recordará el motivo
- ✗Refactorizar sin una prueba preexistente que cubra el camino: escríbela primero
✅ Resumen del Módulo
Siguiente módulo:
1.6 — continuando el recorrido de skills.