Objetivos de Aprendizaje
Al finalizar esta clase, seras capaz de:
- Entender los principios de Clean Architecture
- Organizar codigo en capas independientes
- Aplicar la regla de dependencias
- Estructurar un proyecto con Clean Architecture
- Separar dominio de infraestructura
Que es Clean Architecture? (15 min)
Clean Architecture (Arquitectura Limpia) es un patron propuesto por Robert C. Martin que organiza el software en capas concentricas.
Principios clave:
- Independencia de frameworks
- Testeable sin UI, base de datos, servidor
- Independencia de UI
- Independencia de base de datos
- Independencia de agentes externos
Capas de Clean Architecture (20 min)
┌─────────────────────────────────────────┐
│ FRAMEWORKS │
│ (FastAPI, SQLAlchemy, DB) │
│ ┌─────────────────────────────────┐ │
│ │ INTERFACE ADAPTERS │ │
│ │ (Controllers, Gateways) │ │
│ │ ┌───────────────────────────┐ │ │
│ │ │ USE CASES / SERVICES │ │ │
│ │ │ (Business Rules) │ │ │
│ │ │ ┌───────────────────┐ │ │ │
│ │ │ │ ENTITIES │ │ │ │
│ │ │ │ (Enterprise │ │ │ │
│ │ │ │ Business Rules) │ │ │ │
│ │ │ └───────────────────┘ │ │ │
│ │ └───────────────────────────┘ │ │
│ └─────────────────────────────────┘ │
└─────────────────────────────────────────┘
Capas explicadas
| Capa | Responsabilidad | Ejemplo |
|---|---|---|
| Entities | Reglas de negocio centrales | Usuario, Tarea, Proyecto |
| Use Cases | Logica de aplicacion | UsuarioService, TareaService |
| Interface Adapters | Convierten datos | Controllers, Repositories, DTOs |
| Frameworks | Herramientas externas | FastAPI, SQLAlchemy, PostgreSQL |
Regla de Dependencias (15 min)
Las dependencias solo pueden apuntar hacia adentro:
Regla: El codigo interno NO debe conocer el codigo externo.
# ❌ INCORRECTO: Entity depende de infraestructura
from sqlalchemy import Column, String # MAL!
class Usuario:
username = Column(String(50)) # Entity acoplada a SQLAlchemy
# ✅ CORRECTO: Entity es agnostica
class Usuario:
def __init__(self, username: str, email: str):
self.username = username
self.email = email
def es_valido(self) -> tuple[bool, str]:
if len(self.username) < 3:
return False, "Username muy corto"
if "@" not in self.email:
return False, "Email invalido"
return True, "OK"
Estructura del Proyecto (20 min)
taskflow/
├── domain/ # ENTITIES (Centro)
│ ├── entities.py # Clases de dominio puras
│ ├── value_objects.py # Objetos de valor
│ └── exceptions.py # Excepciones de dominio
│
├── application/ # USE CASES
│ ├── services/ # Logica de aplicacion
│ │ ├── usuario_service.py
│ │ ├── proyecto_service.py
│ │ └── tarea_service.py
│ └── interfaces/ # Contratos (ABC)
│ └── repositories.py
│
├── infrastructure/ # INTERFACE ADAPTERS
│ ├── repositories/ # Implementacion repositorios
│ │ ├── base.py
│ │ └── usuario_repo.py
│ ├── database.py # Configuracion DB
│ └── adapters/ # Adaptadores externos
│
├── api/ # FRAMEWORKS
│ ├── routes/ # Endpoints FastAPI
│ ├── dependencies.py # Inyeccion de dependencias
│ └── schemas/ # Pydantic DTOs
│
└── tests/ # Tests
├── unit/ # Tests de dominio
├── integration/ # Tests de integracion
└── conftest.py
Ejemplo: Flujo completo
# 1. DOMAIN - Entity pura
class Usuario:
def __init__(self, username: str, email: str):
self.username = username
self.email = email
self.activo = True
# 2. APPLICATION - Service
class UsuarioService:
def __init__(self, repo: UsuarioRepository):
self.repo = repo
def crear_usuario(self, username: str, email: str) -> Usuario:
if self.repo.existe_username(username):
raise ValueError("Username ya existe")
usuario = Usuario(username, email)
return self.repo.crear(usuario)
# 3. INFRASTRUCTURE - Repository
class UsuarioRepositorySQLAlchemy(UsuarioRepository):
def crear(self, usuario: Usuario) -> Usuario:
modelo = UsuarioModel(
username=usuario.username,
email=usuario.email
)
self.db.add(modelo)
self.db.commit()
return usuario
# 4. API - Route
@router.post("/usuarios")
def crear(
data: UsuarioCreate,
service: UsuarioService = Depends(get_usuario_service)
):
return service.crear_usuario(data.username, data.email)
Ejercicio: Refactorizar TaskFlow (15 min)
Reorganiza el proyecto TaskFlow siguiendo Clean Architecture:
- Mover modelos de dominio a
domain/entities.py - Crear servicios en
application/services/ - Mover repositorios a
infrastructure/repositories/ - Crear interfaces en
application/interfaces/
E6 Proyecto Final: La arquitectura debe ser Clean Architecture completa.
Resumen
- Clean Architecture: Organiza codigo en capas concentricas
- Dependencias hacia adentro: El nucleo no conoce lo externo
- Entities: Reglas de negocio centrales
- Use Cases: Logica de aplicacion
- Interface Adapters: Conversion de datos
- Frameworks: Herramientas externas