Llegamos al final del curso, y nada consolida mejor lo aprendido que diseñar un sistema completo desde cero aplicando, de forma justificada, las decisiones que hemos ido estudiando. En esta lección actuaremos como el equipo de arquitectura de una empresa ficticia, MercadoFiatc, que necesita construir una plataforma de comercio electrónico. Partiremos de los requisitos de negocio, los traduciremos en atributos de calidad, elegiremos un estilo arquitectónico con su justificación, modelaremos los datos, definiremos despliegue y observabilidad, y registraremos las decisiones clave como ADR. No buscamos "la" respuesta correcta —en arquitectura casi nunca existe—, sino mostrar un razonamiento coherente: cada decisión se deriva de un requisito y asume conscientemente sus compromisos. Este caso cierra el curso integrando los módulos sobre estilos, datos, comunicación, despliegue, gobernanza y evolución.
Contenido
- Requisitos de MercadoFiatc
- De requisitos a atributos de calidad
- Elección del estilo arquitectónico
- Diagrama C4 del sistema
- Diseño de datos
- Comunicación entre componentes
- Despliegue
- Observabilidad
- Decisiones registradas (ADR) y evolución
- Errores Comunes y Consejos
- Ejercicios
- Conclusión del curso
- Requisitos de MercadoFiatc
El negocio nos plantea estos requisitos funcionales y restricciones:
- Catálogo de productos navegable y con búsqueda, decenas de miles de referencias.
- Carrito de la compra y proceso de pago (checkout) con pasarela externa.
- Gestión de pedidos y su estado (confirmado, preparando, enviado, entregado).
- Recomendaciones de productos.
- Picos de tráfico muy fuertes en campañas (Black Friday): la navegación del catálogo puede multiplicarse por 50, mientras pagos crece mucho menos.
- Equipo de unas 25 personas, organizado en 4 squads.
- Presupuesto operativo limitado: no se quiere pagar la complejidad de lo distribuido donde no aporte.
- De requisitos a atributos de calidad
El primer paso de cualquier arquitectura seria es traducir requisitos de negocio en atributos de calidad medibles, porque son ellos —y no las funcionalidades— los que más condicionan el diseño.
| Requisito de negocio | Atributo de calidad | Objetivo medible |
|---|---|---|
| Picos de campaña en catálogo | Escalabilidad (granular) | Catálogo escala x50 sin tocar pagos |
| El pago no puede caerse | Disponibilidad | 99,95% en checkout |
| Navegación fluida | Rendimiento | p95 de catálogo < 200 ms |
| Equipo de 4 squads autónomos | Mantenibilidad / autonomía | Squads despliegan sin coordinarse |
| Presupuesto limitado | Coste operativo | Minimizar piezas distribuidas |
| Datos de pedidos fiables | Consistencia | Pedido y pago consistentes (transaccional donde toca) |
Observa la tensión clave: necesitamos escalado granular (catálogo crece mucho más que pagos) y autonomía de squads, lo que empuja hacia microservicios; pero el coste operativo limitado y la consistencia del pedido empujan hacia el monolito. La arquitectura nacerá de equilibrar esas fuerzas.
- Elección del estilo arquitectónico
No saltamos directamente a "microservicios para todo". Evaluamos opciones:
| Estilo | A favor para MercadoFiatc | En contra |
|---|---|---|
| Monolito modular | Bajo coste, consistencia fácil, refactor barato | No permite escalar catálogo aparte ni autonomía total de squads |
| Microservicios completos | Escalado granular y autonomía máxima | Coste operativo alto, consistencia compleja, sobreingeniería al inicio |
| Mixto: monolito modular + pocos servicios extraídos | Captura escalado donde importa, sin pagar todo el coste | Requiere disciplina de fronteras |
Elegimos el enfoque mixto y evolutivo, totalmente alineado con lo aprendido: empezamos con un monolito modular bien delimitado por dominios (Catálogo, Carrito, Pedidos, Pagos, Recomendaciones) y extraemos como microservicio solo lo que tenga necesidades de escalado o disponibilidad dispares. En concreto:
- Catálogo se extrae pronto: es el que sufre el x50 en campaña y conviene escalarlo solo.
- Recomendaciones se extrae: es opcional, puede fallar sin romper la compra y evoluciona rápido.
- Carrito, Pedidos y Pagos permanecen juntos en el monolito modular al principio, porque comparten transacciones y consistencia fuerte; extraerlos pronto traería sagas y dolor sin beneficio claro.
Esta decisión aplica directamente la regla MonolithFirst y el patrón Strangler Fig: el monolito modular es el punto de partida, y la extracción es incremental y guiada por dolor real.
- Diagrama C4 del sistema
Usamos el modelo C4 (Contexto, Contenedores, Componentes, Código) para comunicar el diseño a distintas audiencias. Mostramos el nivel de Contenedores, el más útil para arquitectura.
graph TD
Cliente[Cliente web/móvil] --> GW[API Gateway / Strangler Facade]
GW --> Cat[Servicio Catálogo\nextraído, escala x50]
GW --> Rec[Servicio Recomendaciones\nextraído, opcional]
GW --> Mono[Monolito Modular\nCarrito + Pedidos + Pagos]
Mono --> Pasarela[Pasarela de pago externa]
Cat --> DBCat[(BD Catálogo)]
Rec --> DBRec[(BD Recomendaciones)]
Mono --> DBMono[(BD principal:\nCarrito, Pedidos, Pagos)]
Mono -->|evento PedidoConfirmado| Broker[(Broker de mensajería)]
Broker --> RecLeamos el diagrama, que sintetiza casi todas las decisiones:
- El API Gateway actúa también de Strangler Facade: enruta cada petición al servicio extraído o al monolito. Es el punto desde el que seguiremos estrangulando si hace falta.
- Catálogo y Recomendaciones son contenedores independientes con su propia base de datos: pueden escalarse y desplegarse por separado.
- El monolito modular agrupa Carrito, Pedidos y Pagos sobre una única base de datos, permitiendo transacciones ACID locales en el checkout.
- La comunicación con Recomendaciones es asíncrona por eventos (
PedidoConfirmadovía broker): así el pedido no depende de que Recomendaciones esté disponible.
- Diseño de datos
Aplicamos el principio una base de datos por servicio donde hay servicios separados, y consistencia fuerte donde la transacción lo exige:
| Componente | Almacén | Justificación |
|---|---|---|
| Catálogo | Motor con búsqueda (p. ej. PostgreSQL + índice de texto, o Elasticsearch para búsqueda avanzada) | Lecturas masivas y búsqueda; tolera réplicas de lectura |
| Recomendaciones | Almacén propio (puede ser NoSQL) | Datos derivados, esquema flexible, no transaccional |
| Carrito + Pedidos + Pagos | PostgreSQL (relacional, ACID) | El checkout cruza las tres entidades y exige transacción fuerte |
La decisión más delicada es la consistencia entre pedido y pago. Como viven en el mismo monolito sobre la misma BD relacional, confirmar el pedido y registrar el pago ocurre en una transacción ACID local: o se hace todo o nada. Esto evita las sagas distribuidas, que solo introduciríamos si más adelante extrajéramos Pagos. La relación con Recomendaciones, en cambio, es consistencia eventual: tras confirmar el pedido se publica un evento y Recomendaciones se actualiza con un pequeño retardo, lo cual es perfectamente aceptable para datos sugeridos.
- Comunicación entre componentes
Combinamos estilos de comunicación según la naturaleza de cada interacción:
- Síncrona (REST/HTTP) a través del gateway para las peticiones del cliente: navegar catálogo, ver carrito, hacer checkout. El usuario espera respuesta inmediata.
- Asíncrona por eventos para integraciones internas que toleran retardo:
PedidoConfirmadodispara la actualización de Recomendaciones y, en el futuro, de Facturación. - Anti-Corruption Layer en el servicio de Catálogo si hubiera que integrarse con un PIM (Product Information Management) heredado con un modelo de datos antiguo.
# Contrato del evento de dominio publicado al confirmar un pedido
evento: PedidoConfirmado
version: 1
payload:
idPedido: "uuid"
idCliente: "uuid"
lineas:
- idProducto: "uuid"
cantidad: 2
total: 149.90
moneda: "EUR"
fecha: "2026-06-30T10:15:00Z"Este contrato de evento es la frontera pública entre el monolito y los consumidores (Recomendaciones hoy, Facturación mañana). Definirlo de forma explícita y versionada (version: 1) es esencial: los consumidores dependen de su forma, así que un cambio incompatible exigiría una version: 2. El evento lleva solo lo necesario y no incluye datos personales sensibles más allá de identificadores, lo que además ayuda a respetar la minimización de datos.
- Despliegue
El despliegue refleja la arquitectura mixta y el presupuesto contenido:
- Contenedores (Docker) orquestados con Kubernetes, pero con pocas piezas: monolito, catálogo, recomendaciones, gateway y broker. No multiplicamos servicios sin necesidad.
- Escalado horizontal independiente: Catálogo se configura con autoescalado agresivo (muchas réplicas en campaña); el monolito y los demás, con un escalado más moderado.
- Despliegue independiente por squad: cada contenedor tiene su propio pipeline, de modo que el squad de Catálogo despliega sin coordinarse con el de Pedidos. Esto satisface el atributo de autonomía.
- Estrategia de despliegue progresivo (canary o blue-green) para reducir el riesgo en cada release, con posibilidad de revertir.
# Esbozo de autoescalado del servicio de Catálogo (HPA de Kubernetes)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
name: catalogo-hpa
spec:
scaleTargetRef:
kind: Deployment
name: catalogo
minReplicas: 3
maxReplicas: 60 # holgura para el pico x50 de campaña
metrics:
- type: Resource
resource:
name: cpu
target:
type: Utilization
averageUtilization: 65Este manifiesto materializa el requisito de escalabilidad granular: el catálogo puede pasar de 3 a 60 réplicas automáticamente cuando la CPU supera el 65% de uso, absorbiendo el pico de campaña, mientras el resto del sistema mantiene su capacidad habitual. Es exactamente el beneficio que justificaba extraer Catálogo como servicio aparte.
- Observabilidad
Un sistema con piezas distribuidas y eventos asíncronos es opaco sin observabilidad. Implementamos los tres pilares:
- Logs estructurados (JSON) centralizados, con un
traceIdcomún en todas las piezas. - Métricas (Prometheus/Grafana): latencia p95 por servicio, tasa de errores, profundidad de las colas del broker, réplicas activas.
- Trazas distribuidas (OpenTelemetry): seguir una petición de checkout a través del gateway, el monolito y el broker, viendo dónde se va el tiempo.
La observabilidad no es un lujo: es la condición previa para evolucionar con seguridad. Sin métricas de latencia del catálogo, no sabríamos si el autoescalado funciona; sin trazas, depurar el flujo de eventos de Recomendaciones sería adivinar. Además, las métricas alimentan fitness functions continuas: una alerta si el p95 de checkout supera 300 ms es una función de aptitud que vigila la salud arquitectónica en producción.
- Decisiones registradas (ADR) y evolución
Cerramos el diseño documentando las decisiones clave como ADR, tal y como vimos en la lección de gobernanza:
- ADR-001: Empezar con monolito modular y extraer servicios solo por dolor (escalado/disponibilidad). Consecuencia: bajo coste inicial; aceptamos refactorizar fronteras más tarde.
- ADR-002: Extraer Catálogo como servicio independiente. Consecuencia: escalado granular; coste de una BD y un pipeline propios.
- ADR-003: Comunicación asíncrona por eventos hacia Recomendaciones. Consecuencia: desacople y disponibilidad; consistencia eventual e idempotencia obligatoria.
- ADR-004: Mantener Carrito, Pedidos y Pagos juntos con transacción ACID local. Consecuencia: consistencia fuerte sin sagas; reevaluar si Pagos necesita escalar aparte.
Y protegemos la arquitectura con fitness functions: tests de ArchUnit que prohíben ciclos entre los módulos del monolito y que impiden que el dominio dependa de la infraestructura, más una fitness continua de latencia en producción. Así, la arquitectura está documentada (ADR) y vigilada (fitness functions): puede evolucionar sin degradarse. Cuando un módulo del monolito empiece a doler, el Strangler Facade ya está en su sitio para extraerlo de forma incremental.
- Errores Comunes y Consejos
- Empezar por la solución y no por los atributos de calidad. Diseñar "con microservicios" antes de saber qué hay que escalar es ponerse la respuesta antes que la pregunta.
- Extraer servicios por moda. Cada servicio extraído cuesta operación, observabilidad y consistencia. Extrae solo donde el atributo de calidad lo justifique (Catálogo sí, Pagos todavía no).
- Olvidar la consistencia al separar. En el momento en que partes una transacción entre servicios, entras en sagas y consistencia eventual. Tenlo claro antes de cortar.
- Diseñar sin observabilidad. Un sistema mixto sin trazas ni métricas es imposible de evolucionar con seguridad.
- No documentar las decisiones. Sin ADR, dentro de un año nadie recordará por qué Pagos está en el monolito y alguien lo "arreglará" creando un lío.
- Consejo: revisa que cada decisión del diseño se pueda trazar hasta un requisito o atributo de calidad concreto. Si no puedes, probablemente sobra.
- Ejercicios
Ejercicio 1. El negocio añade un requisito: "el envío de emails transaccionales (confirmación de pedido) no debe ralentizar el checkout y debe poder reintentarse si el proveedor de email falla". ¿Cómo lo integrarías en la arquitectura propuesta?
Ejercicio 2. Tras seis meses, las métricas muestran que Pagos sufre picos propios y el equipo quiere desplegarlo aparte. Describe, con lo aprendido, cómo lo extraerías del monolito y qué problema nuevo de consistencia aparece.
Ejercicio 3. Justifica por qué Catálogo usa un almacén orientado a búsqueda y lecturas, mientras que Pedidos usa un relacional ACID. Relaciona cada elección con un atributo de calidad.
Soluciones
Solución 1. Mediante comunicación asíncrona por eventos: el checkout publica PedidoConfirmado (ya existe) y un consumidor de notificaciones envía el email de forma diferida. Así el checkout no espera al email; si el proveedor falla, el consumidor reintenta desde la cola. Conviene idempotencia para no enviar el correo dos veces si el evento se reentrega.
Solución 2. Aplicando Branch by Abstraction dentro del monolito (interfaz ServicioPagos), luego construyendo el microservicio de Pagos con su propia BD y conmutando con feature flags vía el gateway (Strangler). El problema nuevo: la confirmación de pedido y el registro de pago dejan de compartir transacción ACID; aparece la necesidad de una saga con compensación (p. ej. cancelar el pedido si el pago falla) y consistencia eventual entre ambos.
Solución 3. Catálogo prioriza rendimiento y escalabilidad de lectura (búsqueda rápida sobre decenas de miles de referencias bajo picos x50), de ahí un almacén optimizado para búsqueda y réplicas. Pedidos prioriza consistencia: el checkout cruza carrito, pedido y pago en una operación que debe ser todo-o-nada, lo que exige transacciones ACID de un relacional.
- Conclusión del curso
Con este estudio de caso cerramos el curso de Arquitectura de Aplicaciones. Hemos visto cómo un buen diseño no nace de elegir la tecnología de moda, sino de un razonamiento disciplinado: traducir requisitos de negocio en atributos de calidad medibles, elegir el estilo que mejor los equilibra —en MercadoFiatc, un monolito modular que evoluciona extrayendo solo lo que lo justifica—, modelar los datos según las necesidades de consistencia, combinar comunicación síncrona y asíncrona, desplegar con escalado granular donde importa, y sostenerlo todo con observabilidad. Y, sobre todo, hemos cerrado el círculo del módulo final: documentar las decisiones con ADR, protegerlas con fitness functions y dejar preparado el Strangler Facade para seguir evolucionando de forma incremental y guiada.
A lo largo del curso has recorrido el camino completo: qué es la arquitectura, los estilos monolíticos y distribuidos, las capas y la arquitectura hexagonal, la gestión de datos y la comunicación, el despliegue, y finalmente la evolución y la gobernanza. La lección de fondo es siempre la misma: en arquitectura no hay soluciones perfectas, solo compromisos bien razonados. Tu trabajo como arquitecto no es eliminar los compromisos, sino elegirlos conscientemente, justificarlos y dejar el sistema preparado para cambiar cuando los compromisos de hoy dejen de servir. Enhorabuena por completar el curso.
Curso de Arquitectura de Aplicaciones
Módulo 1: Fundamentos de la Arquitectura de Aplicaciones
- ¿Qué es la Arquitectura de Aplicaciones?
- El Rol del Arquitecto de Software
- Atributos de Calidad y Requisitos No Funcionales
- Decisiones Arquitectónicas y Compromisos (Trade-offs)
- Documentación de Arquitectura: Vistas y el Modelo C4
Módulo 2: Principios y Tácticas de Diseño
- Acoplamiento, Cohesión y Separación de Responsabilidades
- Principios SOLID Aplicados a la Arquitectura
- DRY, KISS, YAGNI y Otros Principios de Diseño
- Tácticas Arquitectónicas para los Atributos de Calidad
- Gestión de la Deuda Técnica
Módulo 3: Estilos y Patrones Arquitectónicos
- Arquitectura Monolítica
- Arquitectura en Capas (N-Tier)
- Arquitectura Cliente-Servidor
- Arquitectura Hexagonal (Puertos y Adaptadores)
- Arquitectura Limpia y Cebolla (Clean & Onion)
Módulo 4: Arquitecturas Distribuidas y Microservicios
- Introducción a los Sistemas Distribuidos
- Arquitectura de Microservicios
- Descomposición de Servicios y Bounded Contexts
- API Gateway, Service Discovery y Comunicación entre Servicios
- Patrones de Resiliencia: Circuit Breaker, Retry y Bulkhead
- El Teorema CAP y la Consistencia de Datos
Módulo 5: Arquitecturas Dirigidas por Eventos y Mensajería
- Fundamentos de la Arquitectura Orientada a Eventos
- Mensajería Asíncrona: Colas y Brokers
- Patrones de Eventos: Event Sourcing y CQRS
- Gestión de Transacciones Distribuidas: Patrón Saga
- Streaming de Datos en Tiempo Real
Módulo 6: Diseño Dirigido por el Dominio (DDD)
- Conceptos Fundamentales del DDD
- Diseño Estratégico: Bounded Contexts y Lenguaje Ubicuo
- Diseño Táctico: Entidades, Agregados y Repositorios
- Mapeo de Contextos (Context Mapping)
Módulo 7: Datos y Persistencia
- Estrategias de Persistencia: SQL vs NoSQL
- Patrones de Acceso a Datos: Repository, Unit of Work y DAO
- Base de Datos por Servicio y Gestión de Datos Distribuidos
- Caché y Estrategias de Invalidación
Módulo 8: Arquitectura en la Nube y Despliegue
- Fundamentos del Cloud Computing (IaaS, PaaS, SaaS)
- Contenedores y Orquestación con Docker y Kubernetes
- Arquitectura Serverless
- Patrones de Diseño Cloud-Native
- Infraestructura como Código (IaC)
Módulo 9: Calidad, Seguridad y Observabilidad
- Escalabilidad: Horizontal vs Vertical y Balanceo de Carga
- Alta Disponibilidad y Tolerancia a Fallos
- Seguridad por Diseño y Autenticación/Autorización
- Observabilidad: Logging, Métricas y Trazabilidad
- Rendimiento y Pruebas de Carga
