PTENES
MÓDULO 1.5

🏗️ Arquitectura saludable

Salir de la bola de barro sin refactorizar todo. Identifica puntos de mejora, abórdalos incrementalmente, mantén vivas las decisiones.

8
Secciones
35
Minutos
Inter
Nivel
Práctica
Tipo
1

🪣 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
Responsabilidad
Cada módulo hace una cosa y tiene un buen nombre.
Dirección
Dependencias sin ciclos.
Vocabulario
Un concepto = un nombre.
Previsibilidad
¿Dónde vive una feature nueva? Tú lo sabes.
2

🔍 /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.

Informado
Lee CONTEXT.md y los ADRs.
Priorizado
Impacto × esfuerzo.
Accionable
Cada elemento tiene un punto de partida.
No destructivo
Sugiere profundizar, no reescribir.
3

🔭 /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.

1

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.

2

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.

3

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
Para el foco
Divide los detalles en partes pequeñas.
Reposiciona
La pregunta correcta, no una respuesta rápida.
Usa CONTEXT.md
El dominio como brújula.
Vuelves mejor
Zoom-in 2 ≠ zoom-in 1.
4

🌱 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".

Incremental
1 mejora por sprint.
Sin ramas largas
Merge continuo.
Conserva
Los edge cases ya están dominados.
Acumulativo
La arquitectura mejora visiblemente.
5

🧭 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.

Escala
Contrasta el código con el dominio.
Glosario
Resuelve disputas de nombres.
Límites
Dónde vive la feature.
Invariantes
Reglas intocables al refactorizar.
6

📜 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-architecture lee 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.

Memoria
Por qué X ≠ Y, registrado.
Antirregresión
El siguiente refactor no deshace los cambios.
Breve
1 página > 10.
Inmortal
Sustituye, no elimines.
7

📈 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.

S0

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.

S1

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.

S2

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.

S3

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.

S4

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
1 por sprint
Cadencia sostenible.
Docs vivas
CONTEXT.md + ADRs evolucionan.
Sin pausa
Las funcionalidades continúan.
Acumulativo
El nuevo diagnóstico muestra una mejora.
8

🎯 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. 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. 2.
    Ejecuta /improve-codebase-architecture en el proyecto real (no en sandbox).
  3. 3.
    Anota las 3 primeras sugerencias con: descripción, impacto, esfuerzo. No las 5: solo las 3 primeras.
  4. 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. 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
Ejecuta
En el proyecto real, no en un ejemplo.
3, no 5
Enfoque en la elección.
Defiende
3 frases: esta, ahora, riesgo.
ADR primero
Si no está escrito, no está listo.

✅ Resumen del Módulo

✓
Ball of mud se puede diagnosticar — señales específicas (god modules, ciclos, vocabulario inconsistente, duplicación).
✓
/improve-codebase-architecture enumera oportunidades — informadas por CONTEXT.md y ADRs, priorizadas según su impacto.
✓
/zoom-out rompe el túnel del detalle — devuelve la perspectiva arquitectónica antes de la próxima edición.
✓
Deepening > rewrite — una mejora acumulativa por sprint, sin ramas largas.
✓
CONTEXT.md es la vara de medir — un concepto de dominio merece un módulo, un nombre y atención arquitectónica.
✓
Los ADRs preservan decisiones — sin ellos, el próximo refactor lo deshace por desconocimiento.

Siguiente módulo:

1.6 — continuando el recorrido de skills.