Tot el que hem vist fins ara ha estat conceptual: què és un microservei, què es guanya i què es paga, com es compara amb el monòlit i quan convé fer el pas. A partir d'aquí, el curs es torna pràctic, i perquè el que és pràctic tingui sentit necessitem un cas realista que ens acompanyi de cap a cap. Aquest cas és TechCorp i la seva botiga online, techcorp-shop.
En aquesta lliçó presentem el fil conductor amb tot detall: qui és TechCorp i qui són les persones que prendran les decisions, com és el seu monòlit actual, quins problemes concrets pateix, quin és el flux de negoci central que farem servir una vegada i una altra ("un client fa una comanda"), un fragment real del codi actual que servirà de punt de partida, el mapa de serveis que construirem, l'stack tecnològic triat i un full de ruta que explica què avançarà cada mòdul sobre aquest cas. Encara no dissenyarem els límits dels serveis (això és feina del mòdul 2) ni implementarem res (mòdul 4): aquí només fixem l'escenari i les regles del joc.
Contingut
- Qui és TechCorp
- La botiga avui: un monòlit Node.js/Express amb una única PostgreSQL
- Les sis àrees funcionals
- Els problemes concrets que pateix TechCorp
- El flux central: "un client fa una comanda"
- Un fragment del monòlit actual:
crearComanda - El mapa objectiu de serveis
- L'stack tecnològic triat i per què
- Full de ruta del cas al llarg del curs
- Errors comuns i consells
- Exercicis
- Conclusió
- Qui és TechCorp
TechCorp és una empresa fictícia de comerç electrònic que ven productes d'electrònica de consum (auriculars, altaveus, accessoris, petits dispositius) a través de la seva botiga online techcorp-shop. Totes les dades que apareixeran al curs (clients, productes, imports, comandes) són inventades.
Dades de context que anirem fent servir:
| Aspecte | Situació |
|---|---|
| Antiguitat de la botiga | Uns set anys en producció |
| Volum habitual | De l'ordre de 3.000 comandes diàries en un dia normal |
| Pics | Black Friday i rebaixes de gener: navegació pel catàleg multiplicada per 20, comandes per 3-4 |
| Equip tècnic | Unes 25 persones: desenvolupament, QA i sistemes |
| Organització actual | Un "equip de back-end", un "equip de front-end" i un "equip de sistemes"; el back-end comença a organitzar-se informalment per àrees |
Dues persones apareixeran constantment:
- La Marta, CTO de TechCorp. És qui decideix l'estratègia tècnica, qui defensa (o no) les inversions davant la direcció i qui ha arribat a la conclusió, després d'aplicar els criteris de la lliçó anterior, que la botiga necessita evolucionar cap a microserveis de manera incremental. La Marta posarà les restriccions de negoci: no es pot aturar la botiga, no hi ha pressupost il·limitat, cada pas ha d'aportar valor.
- El Luis, líder de l'equip de Comandes. És el responsable de l'àrea més delicada de la botiga (on es creuen clients, catàleg, estoc, pagaments i notificacions) i serà el nostre protagonista tècnic: la major part del codi que escriurem al curs serà el de
servei-comandes, i moltes decisions les veurem des del seu punt de vista.
- La botiga avui: un monòlit Node.js/Express amb una única PostgreSQL
techcorp-shop és un únic projecte Node.js 20 amb Express, escrit en JavaScript, que s'executa com un sol procés (replicat en tres servidors idèntics darrere d'un balancejador) i que utilitza una única base de dades PostgreSQL amb totes les taules de totes les àrees.
Estructura simplificada del repositori actual:
techcorp-shop/ ├── servidor.js # arrenca Express i registra totes les rutes ├── rutes/ │ ├── clients.js │ ├── cataleg.js │ ├── inventari.js │ ├── comandes.js │ ├── pagaments.js │ └── notificacions.js ├── controladors/ │ ├── clientsControlador.js │ ├── catalegControlador.js │ ├── comandesControlador.js # aquí viu crearComanda │ └── ... ├── bd/ │ ├── connexio.js # un únic pool de PostgreSQL │ └── migracions/ # totes les taules juntes ├── serveis/ │ ├── correu.js # enviament d'emails │ └── passarellaPagament.js # crida al proveïdor de pagaments └── package.json
I l'esquema de la base de dades, molt resumit:
-- Totes a la mateixa base de dades "techcorp"
CREATE TABLE clients (id SERIAL PRIMARY KEY, email TEXT, nom TEXT, adreca TEXT);
CREATE TABLE productes (id SERIAL PRIMARY KEY, nom TEXT, preu NUMERIC(10,2), categoria TEXT, actiu BOOLEAN);
CREATE TABLE estoc (producte_id INT REFERENCES productes(id), quantitat INT, reservat INT);
CREATE TABLE comandes (id SERIAL PRIMARY KEY, client_id INT REFERENCES clients(id), estat TEXT, total NUMERIC(10,2), creat_en TIMESTAMP);
CREATE TABLE linies_comanda (comanda_id INT REFERENCES comandes(id), producte_id INT REFERENCES productes(id), quantitat INT, preu_unitari NUMERIC(10,2));
CREATE TABLE pagaments (id SERIAL PRIMARY KEY, comanda_id INT REFERENCES comandes(id), import NUMERIC(10,2), estat TEXT, referencia_passarella TEXT);
CREATE TABLE notificacions (id SERIAL PRIMARY KEY, client_id INT, tipus TEXT, enviada_en TIMESTAMP);Fixa't en les claus foranes creuades entre àrees (comandes.client_id → clients, linies_comanda.producte_id → productes, pagaments.comanda_id → comandes). Avui són una comoditat enorme; al mòdul 2 veurem que són també el principal obstacle per separar les dades.
- Les sis àrees funcionals
El monòlit agrupa sis àrees de negoci, que avui són carpetes i taules dins del mateix projecte i que demà seran serveis:
| Àrea | Què fa avui | Taules principals |
|---|---|---|
| Clients | Registre, inici de sessió, perfil, adreces d'enviament. | clients |
| Catàleg | Fitxes de producte, categories, preus, cerca. | productes |
| Inventari | Quantitats disponibles per producte, reserves en fer comanda, entrades de magatzem. | estoc |
| Comandes | Creació i cicle de vida de la comanda (pendent, confirmada, cancel·lada, enviada). | comandes, linies_comanda |
| Pagaments | Cobrament a través de la passarel·la externa, registre de pagaments i devolucions. | pagaments |
| Notificacions | Enviament de correus i SMS al client (confirmació, enviament, incidències). | notificacions |
Aquestes sis àrees es correspondran, una a una, amb els sis serveis del mapa objectiu. Que la correspondència sigui tan directa és una simplificació deliberada per al curs; a la vida real, trobar els límits correctes és una feina en si mateixa, que abordarem al mòdul 2.
- Els problemes concrets que pateix TechCorp
La Marta no vol microserveis per moda. Els vol perquè la botiga té problemes mesurables que encaixen amb els senyals de la lliçó 01-04:
-
Desplegaments setmanals amb por. Tota la botiga es desplega els dijous a la nit. La suite de proves triga 40 minuts; el desplegament, amb comprovacions manuals, dues hores. L'últim trimestre, quatre de dotze desplegaments es van revertir totalment o parcialment. Qualsevol correcció urgent espera el dijous següent o requereix un desplegament d'emergència de tota l'aplicació.
-
Caigudes en campanyes. L'últim Black Friday, el trànsit de navegació pel catàleg va saturar els tres servidors. Com que el catàleg comparteix procés i base de dades amb tota la resta, la creació de comandes i els cobraments també van caure: la botiga no va vendre durant 50 minuts el dia de més vendes de l'any. Per evitar-ho, sistemes va replicar tot el monòlit a deu servidors durant la campanya, pagant per capacitat de pagaments i clients que no calia.
-
Un equip trepitjant-se. Els desenvolupadors de les diferents àrees treballen sobre el mateix repositori i les mateixes taules. Quan l'equip de Notificacions va canviar una consulta sobre
comandesper a un correu nou, va trencar un informe de Comandes. Quan Comandes va afegir una columna alinies_comanda, la migració va fallar en producció per un bloqueig amb una consulta pesant de Catàleg. Els pull requests s'encallen per conflictes, i l'equip del Luis calcula que dedica un 20 % del temps a coordinar-se amb altres equips. -
Incidents que es propaguen. Un mes abans, una fallada del proveïdor de correu va fer que l'enviament d'emails comencés a acumular connexions obertes; la fuita de memòria va acabar tombant el procés sencer, cobraments inclosos.
-
Model de dades del catàleg forçat. Els productes tenen atributs molt variables (uns tenen talla, altres voltatge, altres compatibilitat) i a PostgreSQL s'ha acabat amb una taula
atributs_productegenèrica de clau-valor incòmoda de consultar i de mantenir.
Aquests cinc problemes són el "perquè" de tot el curs. Cada mòdul posterior en resoldrà algun.
- El flux central: "un client fa una comanda"
De tots els fluxos de la botiga, n'hi ha un que els travessa tots: un client fa una comanda. És el flux que més valor té per al negoci, el que més àrees implica i el que més problemes concentra. Per això serà l'exemple recurrent de tot el curs: el modelarem, el dividirem, l'implementarem, el desplegarem, el monitorarem i l'assegurarem.
Els passos, tal com passen avui al monòlit:
- El client, ja identificat, envia el seu cistell (
clientIdi una llista deproducteIdamb quantitats). - Es comprova que el client existeix i se'n recupera l'adreça.
- Es consulten els productes per obtenir-ne el nom i el preu actual.
- Es comprova l'estoc de cada producte i es reserva (s'incrementa
estoc.reservat). - Es calcula el total i es crea la comanda en estat
PENDENTamb les seves línies. - Es cobra cridant la passarel·la de pagament externa i es registra el pagament.
- Si el cobrament va bé, la comanda passa a
CONFIRMADA, l'estoc reservat es descompta definitivament i s'envia el correu de confirmació. - Si el cobrament falla, s'allibera la reserva d'estoc, la comanda passa a
CANCELLADAi s'envia un correu d'incidència.
Tot això passa dins d'una única petició HTTP i, gairebé tot, dins d'una única transacció de base de dades.
sequenceDiagram
autonumber
actor C as Client
participant M as Monòlit techcorp-shop
participant BD as PostgreSQL (única)
participant PP as Passarel·la de pagament (externa)
participant SMTP as Servidor de correu (extern)
C->>M: POST /comandes {clientId, linies}
M->>BD: BEGIN
M->>BD: SELECT client
M->>BD: SELECT productes (preu)
M->>BD: UPDATE estoc SET reservat = reservat + quantitat
M->>BD: INSERT comanda (PENDENT) + linies
M->>PP: cobrar(total)
alt cobrament correcte
PP-->>M: OK, referència
M->>BD: INSERT pagament; UPDATE comanda = CONFIRMADA; UPDATE estoc (descomptar)
M->>BD: COMMIT
M->>SMTP: enviar correu de confirmació
M-->>C: 201 Created {comandaId, estat: CONFIRMADA}
else cobrament rebutjat
PP-->>M: rebutjat
M->>BD: ROLLBACK (desfà reserva i comanda)
M->>SMTP: enviar correu d'incidència
M-->>C: 402 Payment Required
end
Quan la botiga estigui dividida en serveis, aquest mateix flux es convertirà en una coreografia d'esdeveniments: servei-comandes crearà la comanda i publicarà comanda.creada; servei-inventari reservarà estoc i publicarà estoc.reservat; servei-pagaments cobrarà i publicarà pagament.confirmat; servei-comandes confirmarà la comanda i publicarà comanda.confirmada (o comanda.cancellada si alguna cosa falla); i servei-notificacions enviarà el correu. Aquesta versió la dissenyarem al mòdul 2 i la construirem al 4; de moment, queda't amb la versió monolítica i amb els noms dels esdeveniments, que reapareixeran constantment:
| Esdeveniment | Qui el publica | Què significa |
|---|---|---|
comanda.creada |
servei-comandes | S'ha registrat una comanda en estat PENDENT. |
estoc.reservat |
servei-inventari | L'estoc de les línies de la comanda ha quedat reservat. |
pagament.confirmat |
servei-pagaments | La passarel·la ha acceptat el cobrament. |
comanda.confirmada |
servei-comandes | La comanda està completa: estoc i pagament correctes. |
comanda.cancellada |
servei-comandes | La comanda no s'ha pogut completar (sense estoc, pagament rebutjat...). |
- Un fragment del monòlit actual:
crearComanda
crearComandaAquest és, simplificat però fidel a l'esperit del codi real, el controlador Express que avui implementa el flux anterior. Llegeix-lo amb calma: és el punt de partida de tot el curs, i hi tornarem per descompondre'l (mòdul 2), extreure'n serveis (mòdul 4) i comparar-lo amb el resultat final (mòdul 8).
// controladors/comandesControlador.js (monòlit techcorp-shop, versió actual)
const bd = require('../bd/connexio'); // únic pool de PostgreSQL
const passarellaPagament = require('../serveis/passarellaPagament');
const correu = require('../serveis/correu');
async function crearComanda(req, res) {
const { clientId, linies } = req.body; // linies: [{ producteId, quantitat }]
const client = await bd.connectar(); // una connexió per a tota l'operació
try {
await client.query('BEGIN');
// 1. Dades del client (taula d'UNA ALTRA àrea: clients)
const { rows: [dadesClient] } = await client.query(
'SELECT id, email, nom FROM clients WHERE id = $1', [clientId]);
if (!dadesClient) throw new Error('CLIENT_NO_EXISTEIX');
// 2. Preus actuals (taula d'UNA ALTRA àrea: catàleg)
const ids = linies.map(l => l.producteId);
const { rows: productes } = await client.query(
'SELECT id, nom, preu FROM productes WHERE id = ANY($1) AND actiu = true', [ids]);
if (productes.length !== ids.length) throw new Error('PRODUCTE_NO_DISPONIBLE');
// 3. Comprovar i reservar estoc (taula d'UNA ALTRA àrea: inventari)
let total = 0;
for (const linia of linies) {
const producte = productes.find(p => p.id === linia.producteId);
const { rowCount } = await client.query(
`UPDATE estoc SET reservat = reservat + $1
WHERE producte_id = $2 AND quantitat - reservat >= $1`,
[linia.quantitat, linia.producteId]);
if (rowCount === 0) throw new Error('SENSE_ESTOC');
total += producte.preu * linia.quantitat;
}
// 4. Crear la comanda i les seves línies (taules pròpies de l'àrea de comandes)
const { rows: [comanda] } = await client.query(
`INSERT INTO comandes (client_id, estat, total, creat_en)
VALUES ($1, 'PENDENT', $2, NOW()) RETURNING id`, [clientId, total]);
for (const linia of linies) {
const producte = productes.find(p => p.id === linia.producteId);
await client.query(
`INSERT INTO linies_comanda (comanda_id, producte_id, quantitat, preu_unitari)
VALUES ($1, $2, $3, $4)`, [comanda.id, linia.producteId, linia.quantitat, producte.preu]);
}
// 5. Cobrar (crida síncrona a un proveïdor extern, enmig de la transacció)
const resultatCobrament = await passarellaPagament.cobrar({ import: total, clientId, comandaId: comanda.id });
if (!resultatCobrament.ok) throw new Error('PAGAMENT_REBUTJAT');
// 6. Registrar pagament i confirmar (taula d'UNA ALTRA àrea: pagaments)
await client.query(
`INSERT INTO pagaments (comanda_id, import, estat, referencia_passarella)
VALUES ($1, $2, 'CONFIRMAT', $3)`, [comanda.id, total, resultatCobrament.referencia]);
await client.query(`UPDATE comandes SET estat = 'CONFIRMADA' WHERE id = $1`, [comanda.id]);
for (const linia of linies) {
await client.query(
`UPDATE estoc SET quantitat = quantitat - $1, reservat = reservat - $1 WHERE producte_id = $2`,
[linia.quantitat, linia.producteId]);
}
await client.query('COMMIT');
// 7. Enviar email (àrea de notificacions), fora de la transacció però a la mateixa petició
await correu.enviar({
a: dadesClient.email,
assumpte: `Comanda ${comanda.id} confirmada`,
cos: `Hola ${dadesClient.nom}, la teva comanda per ${total} € està confirmada.`
});
return res.status(201).json({ comandaId: comanda.id, estat: 'CONFIRMADA', total });
} catch (error) {
await client.query('ROLLBACK');
const codis = { CLIENT_NO_EXISTEIX: 404, PRODUCTE_NO_DISPONIBLE: 400, SENSE_ESTOC: 409, PAGAMENT_REBUTJAT: 402 };
return res.status(codis[error.message] || 500).json({ error: error.message });
} finally {
client.alliberar();
}
}
module.exports = { crearComanda };Què cal observar en aquest codi, perquè cada punt serà un tema del curs:
- Una funció fa sis coses de cinc àrees diferents: valida client, consulta catàleg, reserva inventari, crea comanda, cobra i notifica. És fàcil de llegir, però qualsevol canvi en qualsevol àrea passa per aquí.
- Accés directe a taules d'altres àrees (
clients,productes,estoc,pagaments). És el que fa impossible que Notificacions canviï el seu esquema sense avisar Comandes, i viceversa. La lliçó 02-04 tractarà precisament de trencar això. - Una transacció ho protegeix tot: si el pagament falla, el
ROLLBACKdesfà la reserva d'estoc i la comanda. És la comoditat que perdrem en separar bases de dades i que la lliçó 02-05 substituirà amb una saga. - Una crida externa (la passarel·la de pagament) dins de la transacció: mentre la passarel·la respon (de vegades segons), les files d'
estocqueden bloquejades per a totes les altres comandes. En campanyes, això contribueix a la saturació. - L'enviament de correu és síncron: si el servidor de correu triga o falla, la resposta al client triga o falla, encara que la comanda estigui perfectament cobrada. Això és el que les notificacions asíncrones per esdeveniments resoldran al mòdul 3.
- Sense idempotència: si el client prem dues vegades "comprar", es creen dues comandes i es cobra dues vegades. Avui ho evita el front-end; en un sistema distribuït, no serà suficient.
- El mapa objectiu de serveis
Aquest és el sistema que anirem construint. Els noms, ports i bases de dades són fixos per a tot el curs; els reutilitzarem al codi, als fitxers de Docker Compose i als manifests de Kubernetes.
| Servei | Port | Responsabilitat | Base de dades |
|---|---|---|---|
servei-clients |
3004 | Registre, autenticació de clients (delegada a Keycloak), perfil i adreces. | PostgreSQL (clients) |
servei-cataleg |
3001 | Fitxes de producte, categories, preus, cerca. Alta lectura. | MongoDB (cataleg) |
servei-inventari |
3006 | Estoc disponible, reserves i alliberaments, entrades de magatzem. | PostgreSQL (inventari) |
servei-comandes |
3002 | Creació i cicle de vida de la comanda; coordina el flux mitjançant esdeveniments. | PostgreSQL (comandes) |
servei-pagaments |
3003 | Cobraments contra la passarel·la externa, registre de pagaments i devolucions. | PostgreSQL (pagaments) |
servei-notificacions |
3005 | Enviament de correus i SMS a partir d'esdeveniments d'altres serveis. | Sense base de dades pròpia rellevant (cua de RabbitMQ i registre mínim d'enviaments) |
| API Gateway | 8080 | Punt d'entrada únic: encaminament, autenticació JWT, límits d'ús. | — |
I la infraestructura de suport que envoltarà els serveis:
| Peça | Paper |
|---|---|
| RabbitMQ | Broker de missatges per als esdeveniments comanda.creada, estoc.reservat, pagament.confirmat, comanda.confirmada, comanda.cancellada. |
| Keycloak | Servidor d'identitat (OAuth2 / OpenID Connect) que emet els JWT que el gateway i els serveis validen. |
| Prometheus, Grafana, Loki | Mètriques, panells i logs centralitzats. |
| OpenTelemetry + Jaeger | Traces distribuïdes per seguir una comanda a través de tots els serveis. |
| Docker / Docker Compose | Empaquetat i entorn local de desenvolupament. |
| Kubernetes (+ Istio) | Orquestració en producció i malla de serveis. |
| GitHub Actions | Pipelines d'integració i desplegament continu. |
flowchart TB
Client[Navegador / App mòbil] --> GW[API Gateway :8080]
KC[Keycloak] -. JWT .-> GW
GW --> CLI[servei-clients :3004]
GW --> CAT[servei-cataleg :3001]
GW --> COM[servei-comandes :3002]
CLI --> BD1[(PG clients)]
CAT --> BD2[(MongoDB)]
COM --> BD3[(PG comandes)]
INV[servei-inventari :3006] --> BD4[(PG inventari)]
PAG[servei-pagaments :3003] --> BD5[(PG pagaments)]
NOT[servei-notificacions :3005]
COM <-. esdeveniments .-> MQ[(RabbitMQ)]
MQ <-. esdeveniments .-> INV
MQ <-. esdeveniments .-> PAG
MQ -. esdeveniments .-> NOT
PAG --> PP[Passarel·la de pagament externa]
NOT --> SMTP[Correu / SMS extern]
- L'stack tecnològic triat i per què
La Marta i els líders d'equip han fixat l'stack amb dos criteris: continuïtat amb el que l'equip ja coneix (per no aprendre un llenguatge nou alhora que una arquitectura nova) i estàndards de mercat per a la resta de peces.
| Decisió | Elecció | Per què |
|---|---|---|
| Llenguatge i framework dels serveis | Node.js 20 + Express (JavaScript) | És el que ja fa servir el monòlit; l'equip el domina. Els microserveis permetrien altres llenguatges, però TechCorp no té avui cap raó per fer-ho. Identificadors en català (crearComanda, ComandaRepositori, clientId) per coherència amb el codi existent. |
| Base de dades relacional | PostgreSQL (una per servei) | Ja es coneix i s'opera; encaixa amb comandes, pagaments, inventari i clients, on importen les transaccions locals. |
| Base de dades del catàleg | MongoDB | Resol el problema real dels atributs variables de producte. És l'únic cas d'heterogeneïtat justificada. |
| Missatgeria | RabbitMQ | Broker madur, senzill d'operar a l'escala de TechCorp, amb suport de confirmacions i cues d'errors. |
| Empaquetat i entorn local | Docker i Docker Compose | Estàndard de facto; permet aixecar tota la botiga en un portàtil. |
| Orquestració | Kubernetes | Estàndard de facto per operar contenidors en producció; l'equip de sistemes ja l'ha provat. |
| CI/CD | GitHub Actions | El codi ja és a GitHub; s'evita una altra eina. |
| Observabilitat | Prometheus, Grafana, Loki, OpenTelemetry, Jaeger | Conjunt de codi obert àmpliament usat que cobreix mètriques, panells, logs i traces. |
| Seguretat | JWT/OAuth2 amb Keycloak | Identitat centralitzada i estàndard; els serveis només validen tokens. |
| Malla de serveis | Istio | Xifratge entre serveis, polítiques i observabilitat de xarxa sense tocar el codi dels serveis. S'introdueix al final, quan la resta ja funciona. |
Una nota important per al teu aprenentatge: aquestes eleccions són raonables, no les úniques. A la lliçó 04-01 discutirem alternatives (Kafka enfront de RabbitMQ, altres llenguatges, altres orquestradors). Aquí simplement fixem el terreny perquè tots els exemples del curs siguin coherents.
- Full de ruta del cas al llarg del curs
Així avançarà la història de TechCorp mòdul a mòdul. Cada fila respon a la pregunta "què li passa a la botiga en aquest mòdul?".
| Mòdul | Què avança el cas de TechCorp | Problema de TechCorp que ataca |
|---|---|---|
| 1. Introducció (aquest) | Es fixa l'escenari, el flux central i el mapa objectiu. La Marta decideix migrar de manera incremental. | Entendre el perquè. |
| 2. Disseny | S'analitzen les sis àrees, se'n defineixen els límits (bounded contexts), es decideix quines dades són de qui i com se substitueix la gran transacció de crearComanda per una saga basada en esdeveniments. |
Equips que es trepitgen; transacció única. |
| 3. Comunicació | Es dissenyen les APIs REST de cada servei, els esdeveniments de RabbitMQ del flux de comanda, el gateway al 8080, com es troben els serveis i com es versionen els contractes. | Acoblament entre àrees; correu síncron. |
| 4. Implementació | Es construeixen de debò els serveis en Node.js/Express, començant per servei-comandes amb el Luis: configuració, consum d'APIs, publicació d'esdeveniments i proves (unitàries, d'integració, de contracte). |
Punt de partida real del codi. |
| 5. Desplegament | S'empaqueten els serveis en Docker, s'aixeca la botiga amb Docker Compose i després a Kubernetes, es munten pipelines a GitHub Actions i es desplega servei-cataleg en canary. S'afegeix Istio. |
Desplegaments setmanals amb por. |
| 6. Monitoratge | S'instrumenten mètriques, logs i traces del flux de comanda; es dissenyen reintents, circuit breakers i cues d'errors; s'escala el catàleg per al Black Friday; es defineixen SLOs i alertes. | Caigudes en campanyes; incidents que es propaguen. |
| 7. Seguretat | Es protegeix el gateway amb JWT de Keycloak, es xifra la comunicació entre serveis i s'endureixen contenidors i clúster. | Superfície d'atac d'un sistema distribuït. |
| 8. Casos d'estudi | Es recorre la migració completa de cap a cap (patró strangler), es veu la implementació i el desplegament complets del sistema, i se n'extreuen lliçons. | Consolidar-ho tot. |
flowchart LR
M1[M1<br/>Escenari] --> M2[M2<br/>Disseny de límits<br/>i dades] --> M3[M3<br/>APIs, esdeveniments<br/>i gateway] --> M4[M4<br/>Codi dels<br/>serveis]
M4 --> M5[M5<br/>Docker, K8s,<br/>CI/CD] --> M6[M6<br/>Observabilitat<br/>i resiliència] --> M7[M7<br/>Seguretat] --> M8[M8<br/>Migració completa<br/>i lliçons]
Un detall que convé tenir present des d'ara: el curs no fa cap "big bang". TechCorp no apagarà el monòlit un divendres per engegar sis serveis el dilluns. Els serveis s'extrauran un per un, començant pel catàleg (la raó d'escalat més clara i el risc més baix), després el flux de comandes, i el monòlit s'anirà aprimant fins a desaparèixer. Aquest procés incremental es detalla a la lliçó 08-01.
Errors Comuns i Consells
- Perdre de vista el perquè. Quan al mòdul 5 t'estiguis barallant amb un manifest de Kubernetes, recorda els cinc problemes de l'apartat 4: cada peça d'infraestructura hi és per resoldre'n un, no per si mateixa.
- Idealitzar el punt d'arribada. El mapa de serveis de l'apartat 7 és l'objectiu, però es construirà pas a pas, i algunes decisions es revisaran pel camí (és el normal en un projecte real).
- Menysprear el codi del monòlit.
crearComandaés un codi raonable per a un monòlit; no és "dolent", és inadequat per al problema que TechCorp té ara. Entendre'l bé és la clau per descompondre'l bé. - Canviar els noms. Mantén els noms de serveis, ports i esdeveniments exactament com apareixen a les taules d'aquesta lliçó; la resta del curs els dona per suposats.
- Consell: guarda una còpia mental (o real) del diagrama de seqüència de l'apartat 5. El compararàs amb la seva versió en esdeveniments al mòdul 2 i amb la traça distribuïda real al mòdul 6, i aquesta comparació és una de les millors maneres d'entendre què canvia amb els microserveis.
Exercicis
Exercici 1: Traçar el flux
Sense mirar el diagrama de seqüència, escriu en ordre els vuit passos del flux "un client fa una comanda" tal com passa avui al monòlit, i indica per a cada pas a quina àrea funcional pertany.
Exercici 2: Llegir crearComanda amb ulls d'arquitecte
Sobre el fragment de l'apartat 6, respon:
- Quines taules consulta o modifica que no pertanyen a l'àrea de comandes?
- Què passa si la passarel·la de pagament triga 15 segons a respondre? A qui afecta?
- Què passa si l'enviament del correu falla després del
COMMIT? Què veu el client i què queda a la base de dades?
Exercici 3: Relacionar problemes i mòduls
Per a cadascun dels cinc problemes de l'apartat 4, indica quin mòdul (o mòduls) del curs l'abordaran i amb quina peça del mapa objectiu o de l'stack es relaciona.
Solucions
Exercici 1
- El client envia el cistell → Comandes (punt d'entrada).
- Comprovar client i recuperar adreça → Clients.
- Consultar productes i preus → Catàleg.
- Comprovar i reservar estoc → Inventari.
- Calcular total i crear comanda
PENDENT→ Comandes. - Cobrar a la passarel·la i registrar el pagament → Pagaments.
- Confirmar comanda, descomptar estoc i enviar correu → Comandes, Inventari i Notificacions.
- Si el cobrament falla: alliberar reserva, cancel·lar i notificar incidència → Inventari, Comandes i Notificacions.
Exercici 2
clients(àrea de clients),productes(catàleg),estoc(inventari) ipagaments(pagaments). Noméscomandesilinies_comandasón pròpies.- La transacció continua oberta durant aquests 15 segons, amb les files d'
estocd'aquests productes bloquejades per l'UPDATE. Qualsevol altra comanda que inclogui algun d'aquests productes es queda esperant. En una campanya, moltes comandes esperant bloquejos esgoten les connexions i el sistema sencer es degrada. A més, el client veu la pàgina "carregant" durant 15 segons. - La comanda està confirmada, cobrada i amb l'estoc descomptat a la base de dades (el
COMMITja s'ha executat). Peròcorreu.enviarllança una excepció, elcatchexecuta unROLLBACK(que ja no desfà res, perquè la transacció ha acabat) i respon al client amb un 500. El client creu que la seva compra ha fallat, tot i que se li ha cobrat; probablement ho tornarà a intentar i se li cobrarà dues vegades. És un exemple perfecte de per què les notificacions han de ser asíncrones i desacoblades.
Exercici 3
| Problema | Mòduls | Peces relacionades |
|---|---|---|
| Desplegaments setmanals amb por | 5 (Docker, Kubernetes, CI/CD, estratègies de desplegament) i 4 (proves per servei) | GitHub Actions, contenidors, desplegament canary |
| Caigudes en campanyes | 6 (escalabilitat, resiliència) i 2/3 (catàleg com a servei a part) | servei-cataleg escalat independentment, Prometheus/Grafana |
| Un equip trepitjant-se | 2 (límits i una base de dades per servei) i 3 (contractes) | Bounded contexts, APIs versionades |
| Incidents que es propaguen | 3 (missatgeria asíncrona) i 6 (gestió d'errors, circuit breakers) | RabbitMQ, servei-notificacions aïllat |
| Model de dades del catàleg forçat | 2 (una base de dades per servei) i 4 (implementació) | MongoDB a servei-cataleg |
Conclusió
En aquesta lliçó hem presentat a fons el cas que vertebra el curs: TechCorp, una botiga online que avui és un monòlit Node.js/Express sobre una única PostgreSQL amb sis àrees funcionals, i que pateix problemes concrets i mesurables: desplegaments setmanals temuts, caigudes en campanyes per saturació del catàleg, equips que es trepitgen sobre el mateix codi i les mateixes taules, incidents que es propaguen d'àrees secundàries a les crítiques i un model de dades forçat al catàleg. Hem recorregut pas a pas el flux central "un client fa una comanda" i hem llegit el codi real de crearComanda, que concentra en una sola funció i una sola transacció la feina de cinc àrees: aquest fragment és el nostre punt de partida. Hem fixat el mapa objectiu (sis serveis amb els seus ports i bases de dades més un gateway), l'stack tecnològic i les seves raons, els cinc esdeveniments del flux de comanda i un full de ruta mòdul a mòdul.
Amb l'escenari definit, el mòdul 2 comença la feina de debò: dissenyar els microserveis. Partirem dels principis de disseny, aprendrem a descompondre el monòlit de TechCorp, en definirem els bounded contexts, decidirem com repartir les dades entre serveis i substituirem la gran transacció de crearComanda per una saga coordinada mitjançant esdeveniments. La Marta ha pres la decisió; a partir d'ara acompanyem el Luis i el seu equip en l'execució.
Curs de Microserveis
Mòdul 1: Introducció als Microserveis
- Conceptes Bàsics de Microserveis
- Avantatges i Desavantatges dels Microserveis
- Comparació amb l'Arquitectura Monolítica
- Quan Adoptar Microserveis: Criteris de Decisió
- El Cas Pràctic del Curs: la Botiga Online de TechCorp
Mòdul 2: Disseny de Microserveis
- Principis de Disseny de Microserveis
- Descomposició d'Aplicacions Monolítiques
- Definició de Bounded Contexts
- Gestió de Dades: una Base de Dades per Servei
- Consistència Distribuïda: Sagues, CQRS i Event Sourcing
Mòdul 3: Comunicació entre Microserveis
- APIs RESTful
- Missatgeria Asíncrona
- Protocols de Comunicació: gRPC, GraphQL
- API Gateway i Backend for Frontend
- Descobriment de Serveis i Balanceig de Càrrega
- Contractes i Versionat d'APIs
Mòdul 4: Implementació de Microserveis
- Elecció de Tecnologies i Eines
- Desenvolupament d'un Microservei Simple
- Gestió de Configuració
- Integració Pràctica: Consumir APIs i Publicar Esdeveniments
- Proves en Microserveis: Unitàries, d'Integració i de Contracte
Mòdul 5: Desplegament i Orquestració
- Contenidors i Docker
- Orquestració amb Kubernetes
- CI/CD per a Microserveis
- Estratègies de Desplegament: Rolling, Blue-Green i Canary
- Service Mesh: Istio i Linkerd
Mòdul 6: Monitoratge i Manteniment
- Monitoratge i Logging
- Traçabilitat Distribuïda amb OpenTelemetry
- Gestió d'Errors i Recuperació
- Escalabilitat i Rendiment
- SLOs, Alertes i Gestió d'Incidents
Mòdul 7: Seguretat en Microserveis
- Autenticació i Autorització
- Seguretat en la Comunicació
- Pràctiques de Seguretat
- Seguretat en Contenidors i Kubernetes
