¿Qué es el Patrón Service?
En el desarrollo de software, el Patrón Service actúa como una capa intermedia que orquesta la lógica de negocio. Su objetivo principal es separar qué hace la aplicación de cómo se accede a los datos o cómo se presentan al usuario.
Imagina que tu aplicación es un restaurante:
- El Cliente (Frontend/API): Hace el pedido.
- El Mesero (Controlador): Toma el pedido y lo lleva a la cocina.
- El Chef (Servicio): Sabe exactamente cómo preparar el plato (la lógica).
- La Despensa (Repositorio/DB): Donde están los ingredientes.
¿Qué problemas resuelve?
- Controladores “Gordos”: Evita que tus rutas o controladores tengan cientos de líneas de código.
- Duplicación de Código: Si necesitas registrar un usuario desde la web y también desde un comando de terminal, la lógica reside en un solo lugar: el Servicio.
- Facilidad de Testing: Puedes probar la lógica de negocio de forma aislada sin necesidad de levantar una base de datos o un servidor HTTP.
- Mantenibilidad: Si cambias la regla de negocio (por ejemplo, cómo se calcula un descuento), solo tocas el archivo del Servicio.
Ejemplo Práctico en Python
Supongamos que estamos construyendo un sistema de e-commerce y necesitamos procesar un pedido. Sin el patrón service, pondrías todo en la ruta de tu framework (Flask/FastAPI). Con el patrón, lo separamos así:
1. El Servicio (services.py)
Aquí es donde vive “la verdad” de tu negocio.
class OrderService:
def __init__(self, db_repository, email_client):
self.db = db_repository
self.email = email_client
def create_order(self, user_id, items):
# 1. Calcular total
total = sum(item['price'] * item['quantity'] for item in items)
# 2. Aplicar lógica de negocio (ej. descuento por volumen)
if total > 500:
total *= 0.9 # 10% de descuento
# 3. Guardar en base de datos
order = self.db.save(user_id=user_id, total=total, items=items)
# 4. Notificar al usuario
self.email.send(user_id, f"Tu pedido #{order.id} ha sido procesado.")
return order
2. El Controlador o Punto de Entrada (main.py)
El controlador solo se encarga de recibir la petición y llamar al servicio.
@app.post("/orders")
def handle_create_order(request_data):
# El controlador no sabe calcular descuentos, solo delega
service = OrderService(db_repository=SQLRepository(), email_client=SendGridClient())
order = service.create_order(
user_id=request_data['user_id'],
items=request_data['items']
)
return {"status": "success", "order_id": order.id}
Conclusión
Implementar una capa de servicio puede parecer “trabajo extra” al principio, pero es la mejor inversión para cualquier proyecto que planee crecer. Mantiene tu código limpio, testeable y, sobre todo, organizado bajo el principio de Responsabilidad Única.