L'arquitectura en capes és, probablement, l'estil arquitectònic més estès del món. Gairebé qualsevol aplicació empresarial que hagis utilitzat —un banc, una botiga en línia, un gestor de pòlisses— està organitzada internament en capes: una per a la presentació, una altra per a les regles de negoci i una altra per parlar amb la base de dades. El seu èxit es deu al fet que és intuïtiva, fàcil d'ensenyar i proporciona una separació de responsabilitats clara. Tanmateix, aplicada sense criteri, amaga paranys com ara les capes que no aporten res (l'"antipatró embornal") o l'acoblament entre nivells. En aquesta lliçó entendrem les capes habituals, la diferència entre capes obertes i tancades, i els errors que convé evitar.

Contingut

  1. Què és l'arquitectura en capes
  2. Les capes habituals: presentació, negoci i persistència
  3. Capes tancades vs capes obertes
  4. Avantatges i inconvenients
  5. L'antipatró de la capa embornal
  6. Exemple pràctic end-to-end
  7. Errors comuns i consells
  8. Exercicis
  9. Conclusió

  1. Què és l'arquitectura en capes

L'arquitectura en capes (també anomenada N-Tier o layered architecture) organitza el programari en grups horitzontals de responsabilitat. Cada capa:

  • Té una responsabilitat ben definida.
  • Només es comunica amb la capa immediatament inferior (en la seva forma tancada).
  • Amaga els seus detalls interns a les capes superiors.
graph TD
    P[Capa de Presentació\nControladors, vistes, DTOs]
    N[Capa de Negoci\nServeis, regles, casos d'ús]
    PE[Capa de Persistència\nRepositoris, DAOs]
    BD[(Base de Dades)]
    P --> N --> PE --> BD

Convé aclarir una confusió habitual de vocabulari:

  • Layer (capa lògica): una divisió del codi per responsabilitat. Diverses capes poden viure en el mateix procés.
  • Tier (nivell físic): una divisió del desplegament (màquines/processos diferents). El navegador, el servidor d'aplicacions i el servidor de BD són tres tiers.

Un monòlit pot tenir 3 layers i desplegar-se en 1 sol tier. Són eixos independents.

  1. Les capes habituals: presentació, negoci i persistència

Capa Responsabilitat Què SÍ que conté Què NO ha de contenir
Presentació Interactuar amb l'exterior Controladors REST, mapatge de DTOs, validació de format Regles de negoci, SQL
Negoci Regles i casos d'ús Serveis, validacions de negoci, orquestració de transaccions HTML, SQL cru, detalls HTTP
Persistència Accés a dades Repositoris, DAOs, mapatge objecte-relacional Regles de negoci, lògica de presentació

La idea central: cada concepte viu en una sola capa. Si una regla de negoci apareix en un controlador o en una consulta SQL, s'ha trencat la separació.

// Capa de Presentació: només tradueix HTTP <-> model
@RestController
@RequestMapping("/polizas")
class PolizaController {

    private final ServicioPolizas servicio; // depèn de la capa de negoci

    PolizaController(ServicioPolizas servicio) { this.servicio = servicio; }

    @PostMapping
    PolizaResponse crear(@RequestBody @Valid PolizaRequest req) {
        // 1) Tradueix el DTO d'entrada a una ordre de negoci
        var id = servicio.contratar(req.toComando());
        // 2) Tradueix el resultat a un DTO de sortida
        return new PolizaResponse(id);
    }
}

Explicació:

  • El controlador no pren decisions de negoci: valida el format de la petició (@Valid), tradueix a una ordre i delega en ServicioPolizas.
  • Retorna un DTO de resposta propi de la capa de presentació, sense filtrar entitats internes.

  1. Capes tancades vs capes obertes

Aquesta és una de les decisions més importants —i pitjor enteses— de l'estil en capes.

  • Capa tancada: una petició que la travessa no pot saltar-se-la. Per arribar de Presentació a Persistència, ha de passar per Negoci.
  • Capa oberta: una petició pot saltar-se-la i accedir directament a la capa inferior.
graph TD
    subgraph Cerrada[Tancada]
        A1[Presentació] --> A2[Negoci] --> A3[Persistència]
    end
    subgraph Abierta[Amb capa oberta]
        B1[Presentació] --> B2[Negoci]
        B2 --> B3[Serveis compartits\nCAPA OBERTA]
        B3 --> B4[Persistència]
        B2 -.salta.-> B4
    end
Aspecte Capes tancades Capes obertes
Aïllament entre capes Màxim Menor
Cost d'un canvi Localitzat Pot propagar-se
Risc de salts descontrolats Baix Alt si se n'abusa
Ús típic Per defecte, recomanat Capes de serveis compartits/utilitats

Recomanació: mantén les capes tancades per defecte. Només obre una capa quan hi hagi una raó forta (per exemple, una capa transversal d'utilitats) i documenta-ho. Les capes tancades donen aïllament de canvis: si modifiques la persistència, només la capa de negoci pot veure's afectada.

  1. Avantatges i inconvenients

Avantatges Inconvenients
Separació de responsabilitats clara i fàcil d'ensenyar Pot degenerar en moltes capes que no aporten valor
Substituïbilitat: canviar la BD afecta només la persistència Risc de capa embornal (vegeu l'apartat 5)
Proves per capa amb dependències simulades L'acoblament vertical continua existint
Encaixa de manera natural en qualsevol framework MVC Les regles tendeixen a "filtrar-se" a presentació o persistència
Baix cost d'entrada per als equips El domini queda subordinat a la infraestructura (la BD sol "manar")

Un matís important respecte a estils posteriors (hexagonal, clean): en l'arquitectura en capes el domini depèn cap avall de la persistència. Això significa que la base de dades tendeix a condicionar el model de negoci. Ho veurem resolt en lliçons posteriors amb la inversió de dependències.

  1. L'antipatró de la capa embornal

L'antipatró de la capa embornal (architecture sinkhole anti-pattern) es produeix quan moltes peticions travessen les capes sense que aquestes facin res útil: simplement deleguen a la capa inferior. La capa es converteix en un "embornal" que afegeix codi i latència sense aportar valor.

// SÍMPTOMA: la capa de negoci no fa res, només reenvia
class ServicioClienteSumidero {
    private final RepositorioCliente repo;
    ServicioClienteSumidero(RepositorioCliente repo) { this.repo = repo; }

    // Pass-through pur: sense regles, sense validació, sense orquestració
    Cliente buscar(Long id) {
        return repo.buscar(id); // per què existeix aquesta capa, doncs?
    }
}

Per què és un problema i quan NO ho és?

  • És un problema si la majoria de les operacions del sistema són mers pass-through: estàs pagant el cost de la capa sense obtenir-ne el benefici.
  • NO és un problema si només algunes operacions són simples mentre que altres sí que contenen regles. La regla heurística habitual és la 80/20: si el 80% de les peticions passen de llarg, replanteja les capes; si només el 20%, és acceptable mantenir la uniformitat.

Possibles solucions:

  • Obrir capes concretes perquè certes peticions simples saltin directament (amb criteri).
  • Per a consultes de només lectura, utilitzar un patró CQRS lleuger que llegeixi directament del model de lectura.

  1. Exemple pràctic end-to-end

Vegem les tres capes col·laborant per contractar una pòlissa, amb la regla de negoci al seu lloc.

// --- Capa de Negoci ---
class ServicioPolizas {
    private final RepositorioPolizas repo;
    private final TarificadorRiesgo tarificador;

    ServicioPolizas(RepositorioPolizas repo, TarificadorRiesgo t) {
        this.repo = repo; this.tarificador = t;
    }

    Long contratar(ComandoContratar cmd) {
        // Regla de negoci real: rebutjar riscos no assegurables
        if (!tarificador.esAsegurable(cmd.riesgo())) {
            throw new RiesgoNoAsegurableException(cmd.riesgo());
        }
        var prima = tarificador.calcularPrima(cmd.riesgo());
        var poliza = new Poliza(cmd.cliente(), cmd.riesgo(), prima);
        return repo.guardar(poliza); // delega persistència
    }
}

// --- Capa de Persistència ---
interface RepositorioPolizas {
    Long guardar(Poliza poliza);
}

Explicació detallada:

  • ServicioPolizas (negoci) conté una decisió real: comprova si el risc és assegurable i calcula la prima. No és un embornal.
  • RepositorioPolizas (persistència) es defineix com a interfície: la capa de negoci depèn d'un contracte, no d'una implementació JPA o JDBC concreta. Això facilita les proves amb un repositori fals.
  • El flux complet és: PolizaController (presentació) → ServicioPolizas (negoci) → RepositorioPolizas (persistència) → BD. Capes tancades, sense salts.
-- La taula que dóna suport a la persistència (detall de la capa inferior)
CREATE TABLE polizas (
    id        BIGINT PRIMARY KEY AUTO_INCREMENT,
    cliente   VARCHAR(120) NOT NULL,
    riesgo    VARCHAR(60)  NOT NULL,
    prima     DECIMAL(10,2) NOT NULL
);

Observa que el SQL només apareix a la capa de persistència. Ni el controlador ni el servei saben que al darrere hi ha una taula relacional.

  1. Errors Comuns i Consells

  • Filtrar regles de negoci a la presentació. Si un if decideix alguna cosa del domini dins d'un controlador, mou-lo al servei.
  • Retornar entitats de persistència a l'exterior. Exposa DTOs; no filtris el teu model intern per l'API.
  • Crear capes buides "per simetria". No afegeixis una capa de servei si no fa res; això és exactament la capa embornal.
  • Obrir totes les capes "per flexibilitat". Tanca per defecte; obre només amb justificació.
  • Confondre capa (layer) amb nivell (tier). Decidir quants layers tens és independent de en quantes màquines desplegues.
  • Consell: numera les teves capes mentalment i, davant de cada classe, pregunta't "en quina capa viu aquesta responsabilitat?". Si no ho tens clar, probablement la classe fa massa coses.

  1. Exercicis

Exercici 1. Classifica cada element en la seva capa (Presentació, Negoci o Persistència): (a) @RestController que rep JSON. (b) Càlcul del recàrrec per impagament. (c) Mapatge d'una entitat a la seva taula amb JPA. (d) Validació @NotNull del format d'un camp d'entrada.

Exercici 2. El teu cap proposa obrir totes les capes "per anar més ràpid". Dóna dos arguments en contra i explica en quin cas concret sí que obriries una capa.

Exercici 3. Detecta si aquest servei és un antipatró embornal i proposa una millora:

class ServicioPedidos {
    private final RepositorioPedidos repo;
    Pedido obtener(Long id) { return repo.buscar(id); }
    List<Pedido> listar()    { return repo.listarTodos(); }
}

Solucions

Solució 1. (a) Presentació. (b) Negoci. (c) Persistència. (d) Presentació (validació de format; les validacions de negoci anirien a la capa de negoci).

Solució 2. Arguments en contra: (1) es perd l'aïllament de canvis, ja que la presentació podria acoblar-se directament a la persistència; (2) es fomenta saltar-se les regles de negoci, dispersant-les. Cas en què sí que obriria: una capa transversal d'utilitats/serveis compartits (logging, traducció de missatges) que no tanca regles de domini.

Solució 3. És un antipatró embornal: tots dos mètodes són pass-through purs sense regles. Millora possible: per a aquestes lectures simples, aplicar CQRS lleuger i deixar que la presentació consulti un model de lectura directament, reservant la capa de negoci per a operacions que sí que continguin regles (crear/modificar comandes amb validacions).

  1. Conclusió

L'arquitectura en capes és l'estil d'organització interna per excel·lència: separa presentació, negoci i persistència, i aporta una separació de responsabilitats clara i fàcil d'adoptar. Hem vist la diferència entre capes tancades i obertes, els seus avantatges i inconvenients, i el perillós antipatró de la capa embornal. La seva gran limitació —que el domini depèn cap avall de la infraestructura— serà precisament el que resoldran estils posteriors. Abans d'arribar-hi, en la propera lliçó estudiarem com es reparteixen aquestes capes entre màquines diferents amb l'Arquitectura Client-Servidor, on l'eix passa del que és lògic (layers) al que és físic (tiers).

Curs d'Arquitectura d'Aplicacions

Mòdul 1: Fonaments de l'Arquitectura d'Aplicacions

Mòdul 2: Principis i Tàctiques de Disseny

Mòdul 3: Estils i Patrons Arquitectònics

Mòdul 4: Arquitectures Distribuïdes i Microserveis

Mòdul 5: Arquitectures Dirigides per Esdeveniments i Missatgeria

Mòdul 6: Disseny Dirigit pel Domini (DDD)

Mòdul 7: Dades i Persistència

Mòdul 8: Arquitectura al Núvol i Desplegament

Mòdul 9: Qualitat, Seguretat i Observabilitat

Mòdul 10: Evolució, Governança i Casos Pràctics

© Copyright 2026. Tots els drets reservats