CAPÍTULO 3 · Cada pieza encuentra su responsabilidad
Las reglas necesitan vivir más allá de HTTP
Separar consultas y comandos aclara la entrada al sistema. Ahora podemos reconocer que registrar una lectura no consiste únicamente en recibir JSON: hay reglas que deberían cumplirse tanto si la solicitud llega desde una API como si la inicia un proceso interno. Repetir esas reglas en cada puerta de entrada volvería a fragmentar el comportamiento.
Extraemos el caso de uso a un servicio con entradas y resultados comprensibles. La vista interpreta la petición, valida el contrato que le corresponde y delega. El servicio coordina la operación de negocio sin necesitar que fabriquemos un request para utilizarlo. Cuando una regla cambia, sabemos dónde buscarla.
Esta decisión reduce el peso de las vistas, pero no toda la repetición desaparece. Todavía hay muchas que buscan por ID, validan un serializer o construyen la misma respuesta. Esas operaciones comparten una mecánica HTTP, aunque pertenezcan a negocios diferentes. Ahí aparece la oportunidad de construir una biblioteca que acompañe al equipo en cada aplicación.
Leer esta parte dentro del relato completo →DEL RELATO A LA PRÁCTICA
Vamos a desarrollar esta decisión con su mapa, explicación, código y ejercicio.
MIRA · CONECTA · COMPRENDE
El coordinador del caso de uso
Las flechas resumen el recorrido conceptual. Los controles y dependencias se detallan debajo.
Selecciona una pieza para destacar su responsabilidad.
Leer la explicación del mapa
- Vista. Adapta la petición
- Validación. Comprueba entrada
- Servicio. Coordina reglas y persistencia
- Repositorio. Accede al estado
01 / EL PROBLEMA
¿Para qué sirve?
Una vista que valida, calcula, guarda y envía correos se vuelve difícil de probar. Un servicio permite expresar la operación sin mezclar todo con HTTP.
02 / COMPRENDER
El concepto, explicado
La vista traduce request y response. Un servicio coordina el negocio. Una función pura calcula. Un modelo conserva reglas e integridad de persistencia.
No necesitas una clase para cada línea. Extrae cuando hay reglas relevantes, varias dependencias o reutilización desde tareas y comandos de gestión.
03 / CONSTRUIR
Implementación paso a paso
- Define entradas del caso de uso.
- Usa valores validados, no request completo.
- Retorna un resultado claro.
- Deja que la vista traduzca errores a HTTP.
04 / APLICAR
Ejemplo en SensorHub
# catalogo/services.py
from django.db import transaction
from catalogo.models import Sensor
@transaction.atomic
def register_sensor(*, station, code):
normalized = code.strip().upper()
if not normalized:
raise ValueError("El código no puede estar vacío.")
return Sensor.objects.create(station=station, code=normalized)
# Después de validar en la vista:
# sensor = register_sensor(**serializer.validated_data)Cómo leer el ejemplo
- Los argumentos con nombre aclaran el contrato.
- atomic agrupa escrituras del caso de uso, pero no resuelve por sí solo todas las carreras.
- El servicio sigue dependiendo del ORM; se acepta ese acoplamiento en el monolito.
Error habitual
No valides reglas distintas en serializer y servicio con dos implementaciones inconsistentes. Decide dónde vive la regla y reutilízala.
05 / PRACTICAR
Tu turno
Reutiliza register_sensor desde un comando de gestión.
Ver solución orientativa
El comando resuelve la estación y llama al mismo servicio; no importa la vista ni construye un request falso.
06 / VERIFICAR
Cómo sabes que funciona
- La regla se prueba sin pasar por una URL.
- La vista mantiene una responsabilidad pequeña.
CONTINUAR LA EXPERIENCIA
El siguiente paso del recorrido:
repoGenerico: la biblioteca reutilizable del equipo →Continuar en modo relato