Estrategias de Organización: Paquete por Capa
La organización de código más simple agrupa por capa técnica (web/servicio/repositorio) — fácil de comenzar pero oculta la intención del negocio y permite atajos peligrosos entre capas.
Por qué importa
Package by Layer es la estructura de inicio más común: controllers/, services/, repositories/. Todo tutorial de framework lo usa. Es universalmente entendido y tarda minutos en configurarse. Para un prototipo de tres funcionalidades, está perfectamente bien.
El problema aparece a escala. Un sistema con 50 funcionalidades tiene 150 archivos en 3 directorios. Abrir el proyecto en un IDE no te dice nada sobre qué hace el sistema — ves nombres de capas, no nombres de dominio. Agregar "Pedidos" requiere tocar tres directorios separados. Un desarrollador que agrega una funcionalidad debe mantener mentalmente la conexión entre tres archivos dispersos.
La aplicación de acceso está ausente. Porque todo en services/ es típicamente público, un controlador puede importar un repositorio directamente y saltarse la capa de servicio por completo. Ningún compilador lo detiene. El resultado es una deriva lenta hacia una "gran bola de barro" — una estructura que parece en capas pero se comporta como espagueti.
Package by Layer no está mal. Es el punto de partida correcto para tutoriales y proyectos pequeños, y el punto final incorrecto para cualquier cosa que crezca. Reconocer cuándo migrar es una habilidad arquitectónica clave.
✗El problema
50 features × 3 layers = 150 files in 3 giant directories. No domain visibility. Adding a feature requires touching 3 separate packages with zero cohesion.
Bad
project/
├── controllers/
│ ├── order_controller.py # what does this system DO? Can't tell.
│ ├── user_controller.py
│ ├── payment_controller.py
│ └── ... (47 more files)
├── services/
│ ├── order_service.py
│ ├── user_service.py
│ ├── payment_service.py
│ └── ... (47 more files)
└── repositories/
├── order_repo.py
├── user_repo.py
├── payment_repo.py
└── ... (47 more files)
# Adding "Shipping" feature:
# 1. controllers/shipping_controller.py
# 2. services/shipping_service.py
# 3. repositories/shipping_repo.py
# → Touch 3 packages. Zero cohesion. Domain invisible.
src/
├── controllers/
│ ├── OrderController.ts // what does this system DO? Can't tell.
│ ├── UserController.ts
│ ├── PaymentController.ts
│ └── ... (47 more files)
├── services/
│ ├── OrderService.ts
│ ├── UserService.ts
│ ├── PaymentService.ts
│ └── ... (47 more files)
└── repositories/
├── OrderRepository.ts
├── UserRepository.ts
├── PaymentRepository.ts
└── ... (47 more files)
// Adding "Shipping" feature:
// 1. controllers/ShippingController.ts
// 2. services/ShippingService.ts
// 3. repositories/ShippingRepository.ts
// → Touch 3 packages. Zero cohesion. Domain invisible.
✓La solución
Same code, same classes — organized by feature instead of by layer. Domain is visible at the top level. Each feature is cohesive. Adding "Shipping" means one new directory.
✓ Good — Package by Feature
project/
├── orders/
│ ├── order_controller.py # all Order code in one place
│ ├── order_service.py
│ └── order_repo.py
├── users/
│ ├── user_controller.py
│ ├── user_service.py
│ └── user_repo.py
├── payments/
│ ├── payment_controller.py
│ ├── payment_service.py
│ └── payment_repo.py
└── inventory/
├── inventory_controller.py
├── inventory_service.py
└── inventory_repo.py
# Adding "Shipping" feature:
# 1. Create shipping/ directory
# 2. Add three cohesive files inside it
# → One package. Cohesion high. Domain visible. What does this do? Obvious.
src/
├── orders/
│ ├── OrderController.ts // all Order code in one place
│ ├── OrderService.ts
│ └── OrderRepository.ts
├── users/
│ ├── UserController.ts
│ ├── UserService.ts
│ └── UserRepository.ts
├── payments/
│ ├── PaymentController.ts
│ ├── PaymentService.ts
│ └── PaymentRepository.ts
└── inventory/
├── InventoryController.ts
├── InventoryService.ts
└── InventoryRepository.ts
// Adding "Shipping" feature:
// 1. Create src/shipping/ directory
// 2. Add three cohesive files inside it
// → One package. Cohesion high. Domain visible. What does this do? Obvious.
💡Conclusión clave
Package by Layer es el punto de partida correcto para tutoriales, pero el punto final incorrecto para sistemas reales. Cambia a Package by Feature cuando ya no puedas encontrar las cosas — cuando agregar una funcionalidad requiere buscar en tres directorios, la estructura está trabajando en tu contra, no a tu favor.
🔧 Algunos ejercicios pueden tener errores. Si algo parece incorrecto, usa el botón Feedback (abajo a la derecha) para reportarlo — nos ayuda a corregirlo rápido.
Pista: Paquete por Capa es el punto de partida correcto para tutoriales, pero el punto de llegada incorrecto para sistemas reales. Cambia cuando ya no puedas encontrar las cosas.
✗ Tu versión