L'arquitectura monolítica és el punt de partida històric i conceptual de gairebé qualsevol sistema de programari. Consisteix a construir i desplegar una aplicació com una única unitat cohesionada: tot el codi (interfície d'usuari, lògica de negoci i accés a dades) viu en el mateix projecte, es compila conjuntament i s'executa en un sol procés. Malgrat la moda dels microserveis, comprendre el monòlit és imprescindible, perquè continua sent l'opció més sensata per a la majoria de projectes que comencen, i perquè molts dels "antipatrons" que pateixen els sistemes distribuïts neixen de no haver entès bé com organitzar un bon monòlit. En aquesta lliçó distingirem el monòlit clàssic del monòlit modular, veurem quan té sentit cadascun i desmuntarem diversos mites estesos.

Contingut

  1. Què és un monòlit i per què importa
  2. Monòlit clàssic (big ball of mud)
  3. Monòlit modular
  4. Comparativa: clàssic vs modular vs microserveis
  5. Quan té sentit un monòlit
  6. Mites sobre el monòlit
  7. Errors comuns i consells
  8. Exercicis
  9. Conclusió

  1. Què és un monòlit i per què importa

Un monòlit és una aplicació que s'empaqueta i es desplega com una sola unitat executable. En el món Java sol ser un únic .jar o .war; en altres entorns, un únic contenidor o procés.

Característiques definitòries:

  • Un sol artefacte de desplegament. Tota l'aplicació s'allibera alhora.
  • Un sol procés en execució. Les crides entre mòduls són crides a mètode en memòria, no peticions de xarxa.
  • Una base de codi compartida. Tots els equips treballen sobre el mateix repositori (habitualment).
  • Normalment, una sola base de dades. Encara que no és obligatori.
graph TD
    Usuario[Usuari / Navegador] --> Mono
    subgraph Mono[Procés únic - Monòlit]
        UI[Capa de Presentació]
        BL[Lògica de Negoci]
        DA[Accés a Dades]
        UI --> BL --> DA
    end
    DA --> DB[(Base de Dades)]

El diagrama mostra que, encara que internament existeixi una separació lògica en capes, tot s'executa dins del mateix procés i es desplega conjuntament. Aquesta és la diferència essencial amb un sistema distribuït.

  1. Monòlit clàssic (big ball of mud)

El monòlit clàssic és la forma més comuna i, sovint, la pitjor entesa. No és dolent per ser monòlit, sinó per com sol degenerar: quan no s'imposen fronteres internes clares, el codi acaba en allò que Brian Foote i Joseph Yoder van batejar com a "big ball of mud" (gran bola de fang).

Símptomes d'un monòlit degradat:

  • Qualsevol classe pot cridar qualsevol altra; no hi ha mòduls reals.
  • La lògica de negoci es barreja amb l'accés a dades i amb la presentació.
  • Un canvi petit obliga a tocar desenes de fitxers per tot el projecte.
  • El coneixement del sistema viu només al cap d'unes poques persones.
// Antipatró típic del monòlit clàssic: tot barrejat en un controlador
@RestController
public class PedidoController {

    @Autowired private DataSource dataSource; // accés a dades directe

    @PostMapping("/pedidos")
    public String crearPedido(@RequestBody Map<String,Object> body) throws Exception {
        // 1) Lògica de presentació (parseig) barrejada
        String cliente = (String) body.get("cliente");
        double total = (Double) body.get("total");

        // 2) Regles de negoci incrustades en el controlador
        if (total > 1000) total = total * 0.95; // descompte "màgic"

        // 3) SQL cru a la mateixa classe
        try (var con = dataSource.getConnection()) {
            var ps = con.prepareStatement(
                "INSERT INTO pedidos(cliente,total) VALUES(?,?)");
            ps.setString(1, cliente);
            ps.setDouble(2, total);
            ps.executeUpdate();
        }
        return "OK"; // sense gestió d'errors seriosa
    }
}

Analitzem per què aquest fragment és problemàtic:

  • Barreja de responsabilitats: el @RestController parseja la petició (presentació), aplica un descompte (negoci) i executa SQL (persistència). Tres responsabilitats diferents en un sol mètode.
  • Regla de negoci enterrada: el descompte del 5% està amagat en el controlador. Si un altre endpoint crea comandes, aquesta regla es duplicarà o s'oblidarà.
  • Acoblament a la infraestructura: el SQL cru i el DataSource fan que la lògica sigui impossible de provar sense una base de dades real.

Important: ser monòlit no obliga a escriure així. Aquest és el monòlit mal fet. Vegem com evitar-ho.

  1. Monòlit modular

El monòlit modular conserva tots els avantatges operatius del monòlit (un sol desplegament, sense xarxa entre mòduls) però imposa fronteres internes estrictes entre mòduls de negoci. Cada mòdul exposa una API pública i amaga els seus detalls interns; els altres mòduls només poden comunicar-se a través d'aquesta API.

graph TD
    subgraph Monolito Modular
        direction LR
        Pedidos[Mòdul Comandes\nAPI pública]
        Clientes[Mòdul Clients\nAPI pública]
        Facturas[Mòdul Factures\nAPI pública]
        Pedidos --> Clientes
        Facturas --> Pedidos
    end

Les claus d'un monòlit modular:

  • Encapsulació per mòdul: cada mòdul té el seu propi paquet arrel i amaga les seves classes internes.
  • Comunicació per contractes: els mòduls es parlen a través d'interfícies, no accedint a classes internes.
  • Cohesió per domini: s'agrupa per capacitat de negoci (Comandes, Clients, Facturació), no per capa tècnica.
// Mòdul Comandes: API pública (l'única cosa que veuen els altres mòduls)
package com.fiatc.pedidos.api;

public interface ServicioPedidos {
    Long crearPedido(NuevoPedido datos);
}

// Implementació interna (package-private, invisible fora del mòdul)
package com.fiatc.pedidos.internal;

import com.fiatc.pedidos.api.ServicioPedidos;

class ServicioPedidosImpl implements ServicioPedidos {

    private final RepositorioPedidos repositorio;
    private final PoliticaDescuentos descuentos; // regla aïllada i testejable

    ServicioPedidosImpl(RepositorioPedidos r, PoliticaDescuentos d) {
        this.repositorio = r;
        this.descuentos = d;
    }

    @Override
    public Long crearPedido(NuevoPedido datos) {
        double total = descuentos.aplicar(datos.total());
        return repositorio.guardar(datos.cliente(), total);
    }
}

Què ha millorat respecte a l'exemple anterior:

  • La classe ServicioPedidosImpl és class sense public (package-private): els altres mòduls no poden instanciar-la ni acoblar-s'hi; només coneixen la interfície ServicioPedidos.
  • La regla de descompte viu a PoliticaDescuentos, una classe única i reutilitzable que es pot provar de manera aïllada.
  • L'accés a dades està darrere de RepositorioPedidos, per la qual cosa la lògica de negoci no sap res de SQL.

Eines com Spring Modulith o el sistema de mòduls de Java (JPMS) ajuden a verificar automàticament que aquestes fronteres no es trenquin.

  1. Comparativa: clàssic vs modular vs microserveis

Criteri Monòlit clàssic Monòlit modular Microserveis
Fronteres internes Difuses o inexistents Estrictes (en codi) Físiques (xarxa)
Desplegament Únic Únic Múltiple i independent
Comunicació entre mòduls Crida en memòria Crida en memòria via API Xarxa (HTTP/missatgeria)
Cost operatiu Baix Baix Alt (orquestració, observabilitat)
Escalat Tot o res Tot o res Granular per servei
Complexitat inicial Baixa Mitjana Molt alta
Risc de "bola de fang" Alt Baix Es trasllada al sistema distribuït
Refactor de fronteres Costós (acoblament) Barat (és codi) Molt costós (contractes de xarxa)

La lliçó clau de la taula: el monòlit modular sol ser el "punt dolç" per a molts equips. Captura disciplina arquitectònica sense pagar el cost operatiu del que és distribuït, i deixa la porta oberta a extreure microserveis més endavant si un mòdul ho necessita.

  1. Quan té sentit un monòlit

Un monòlit (preferiblement modular) és una bona elecció quan:

  • L'equip és petit o mitjà (fins a unes poques desenes de persones).
  • El domini encara no està clar: les fronteres dels mòduls canviaran molt, i refactoritzar dins d'un monòlit és barat.
  • No hi ha necessitats d'escalat dispars: totes les parts del sistema reben una càrrega similar.
  • Es vol maximitzar la velocitat de lliurament inicial i minimitzar la complexitat operativa.
  • Les transaccions creuen diversos mòduls: dins d'un procés es resolen amb una transacció ACID local; en el que és distribuït requereixen patrons complexos (sagues).

Regla pràctica molt citada (Martin Fowler, MonolithFirst): comença amb un monòlit i extreu serveis només quan el dolor ho justifiqui.

  1. Mites sobre el monòlit

Mite Realitat
"Monòlit = codi espagueti" El desordre ve de la manca de fronteres, no del desplegament únic. Un monòlit modular pot estar més ben organitzat que un mar de microserveis.
"Els monòlits no escalen" Escalen horitzontalment desplegant diverses instàncies darrere d'un balancejador. El que no escala és l'escalat granular per component.
"Cal començar amb microserveis per no migrar després" Començar distribuït amb un domini immadur sol produir fronteres errònies molt cares de moure.
"Un monòlit implica una sola tecnologia/llenguatge" Cert en el procés, però rarament és un problema real davant dels avantatges.
"Desplegar un monòlit sempre és lent" Amb CI/CD moderns, compilar i desplegar un monòlit ben estructurat és perfectament àgil.

  1. Errors Comuns i Consells

  • No imposar fronteres des del primer dia. Encara que sigui un monòlit, organitza per domini i amaga els detalls interns. És l'única cosa que evita la bola de fang.
  • Organitzar per capa tècnica en lloc de per domini. Paquets controllers, services, repositories globals fomenten l'acoblament. Prefereix pedidos, clientes, facturas i, dins, les capes.
  • Confondre "modular" amb "molts fitxers". Modular significa encapsulació real (visibilitat package-private, APIs explícites), no només dividir en paquets.
  • Saltar a microserveis per moda. Si el teu monòlit fa mal, primer pregunta't si el problema és de modularitat, no de desplegament.
  • Consell: utilitza eines com Spring Modulith o ArchUnit per verificar automàticament que ningú no creua les fronteres dels mòduls.

  1. Exercicis

Exercici 1. Tens un monòlit amb paquets globals controllers, services i repositories. Proposa una reorganització per domini per a una aplicació d'assegurances amb les capacitats: Pòlisses, Sinistres i Clients. Descriu l'estructura de paquets.

Exercici 2. Donat el PedidoController de l'apartat 2, identifica les tres responsabilitats barrejades i proposa a quina classe/col·laborador hauria d'anar cadascuna.

Exercici 3. Raona si els següents escenaris justifiquen microserveis o un monòlit modular: (a) Startup de 4 desenvolupadors amb domini incert. (b) Un component concret rep 100 vegades més càrrega que la resta i ha d'escalar per separat.

Solucions

Solució 1. Estructura orientada a domini:

com.fiatc.seguros
 ├── polizas
 │    ├── api          (interfícies públiques: ServicioPolizas)
 │    └── internal     (impl, repositori, entitats - package-private)
 ├── siniestros
 │    ├── api
 │    └── internal
 └── clientes
      ├── api
      └── internal

Cada domini conté les seves pròpies capes; els dominis es comuniquen només a través dels paquets api.

Solució 2.

  • Parseig de la petició HTTP → responsabilitat de presentació; ha de quedar-se en el controlador, però delegant immediatament.
  • Descompte del 5% → regla de negoci; ha d'anar a una classe com PoliticaDescuentos dins del mòdul Comandes.
  • INSERT a la BD → persistència; ha d'anar a un RepositorioPedidos.

El controlador s'hauria de limitar a rebre el DTO i cridar ServicioPedidos.crearPedido(...).

Solució 3. (a) Monòlit modular. Domini incert i equip petit: les fronteres canviaran i el refactor ha de ser barat. (b) Candidat a extreure un microservei per a aquest component concret, si l'escalat granular justifica el cost operatiu. Tot i així, convé haver-lo aïllat primer com a mòdul dins del monòlit.

  1. Conclusió

El monòlit no és el dolent de l'arquitectura moderna; el dolent és la manca de fronteres internes. Un monòlit modular ofereix simplicitat operativa, transaccions locals i refactor barat, i és la millor opció de partida per a la immensa majoria de projectes. Hem vist la diferència amb el monòlit clàssic, quan triar-lo i els mites que convé desmuntar. En la següent lliçó aprofundirem en com estructurar internament qualsevol aplicació —monolítica o no— mitjançant l'Arquitectura en Capes (N-Tier), on estudiarem les capes de presentació, negoci i persistència, i antipatrons clàssics com el de la "capa embornal".

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