Comprendere il pattern Backend for Frontend (BFF): una guida semplice

Comprendere il pattern Backend for Frontend (BFF): una guida semplice

In un’architettura a microservizi, i nostri sistemi sono suddivisi in decine di servizi piccoli e mirati, come un servizio utente, un servizio ordini e un servizio prodotto.

Ma quando si tratta di mostrare queste informazioni agli utenti, i diversi dispositivi hanno esigenze molto diverse. Un browser Web su un computer desktop ad alta velocità richiede una dashboard ricca piena di tabelle, barre laterali e grafici. Un’app mobile su una rete cellulare lenta richiede un layout semplice e leggero per risparmiare larghezza di banda e batteria. Un’app per smartwatch potrebbe richiedere solo una singola riga di testo.

Se tutti questi frontend interrogano esattamente la stessa API di backend, qualcuno deve scendere a compromessi. O l’app mobile è costretta a scaricare enormi quantità di dati inutili, oppure l’app web è costretta a effettuare dozzine di richieste di rete separate per recuperare tutto ciò di cui ha bisogno.

Questo è esattamente il problema risolto dal Pattern Backend for Frontend (BFF). In questa guida spiegheremo questo modello in parole semplici, esamineremo un’analogia nel mondo reale, lo confronteremo con un gateway API standard e analizzeremo un’implementazione pratica del codice.


L’analogia con il mondo reale: il menu del ristorante

Immagina un ristorante che serve tre tipi di commensali molto diversi:

  1. Un critico gastronomico che desidera un menu degustazione completo di 5 portate con elenchi dettagliati degli ingredienti.
  2. Un pendolare impegnato che desidera uno spuntino veloce e preconfezionato da consumare sul treno.
  3. Un bambino che desidera un pasto semplice con porzioni piccole e senza ingredienti piccanti.

Se il ristorante avesse solo un unico menu che elencasse tutte e tre le opzioni in dettaglio, sarebbe travolgente. Il pendolare perderebbe tempo leggendo ricette di 5 portate e i genitori del bambino farebbero fatica a trovare opzioni alimentari semplici.

Invece, il ristorante stampa tre menu personalizzati: un menu degustazione, un menu Express To-Go e un menu per bambini.

Ogni menu attinge dalla stessa cucina (i microservizi), ma formatta e dimensiona le scelte appositamente per quel cliente (il cliente).

In questo scenario:

  • La cucina rappresenta i tuoi microservizi (Utente, Catalogo, Pagamento).
  • I menu personalizzati sono i tuoi migliori amici (Web BFF, Mobile BFF, Watch BFF).
  • I commensali sono i tuoi frontend (browser desktop, app mobile, smartwatch).

Il problema: l’API “unica per tutti”.

Quando i microservizi sono diventati popolari, molti team hanno creato un unico gateway API condiviso per gestire tutti i client frontend:

Diagramma dell'architettura Backend for Frontend (BFF) che confronta i flussi Web e Mobile

Sebbene un singolo punto di ingresso sia ottimo, un’API condivisa introduce diversi colli di bottiglia in termini di ridimensionamento:

  • Payload Bloat per dispositivi mobili: l’app Web desktop richiede la cronologia degli ordini, l’indirizzo di fatturazione, l’immagine del profilo e i punti fedeltà dell’utente. L’app mobile deve solo mostrare “Ultimo ordine: spedito”. Con un’API condivisa, l’app mobile scarica l’intero payload del profilo, sprecando dati preziosi e rallentando i tempi di caricamento.
  • Colli di bottiglia API: un singolo team diventa il collo di bottiglia per il gateway condiviso. Se il team iOS desidera modificare un piccolo campo di layout, deve attendere che il team del gateway condiviso distribuisca una nuova versione, rallentando i cicli di sviluppo.
  • Diverse esigenze di sicurezza: un browser Web potrebbe richiedere sessioni basate su cookie per impedire Cross-Site Scripting (XSS), mentre un’app mobile preferisce intestazioni OAuth basate su token. Gestirli entrambi in un unico server crea codice complesso e disordinato.

La soluzione: il modello BFF

Invece di creare un gateway gigante per tutti i dispositivi, il modello BFF sostiene la creazione di un server backend dedicato per ciascuna applicazione frontend.

Avrai:

  • Web BFF: gestisce le richieste dal browser desktop. Aggrega profili completi, cataloghi di prodotti e informazioni dettagliate sul checkout.
  • BFF mobile: gestisce le richieste dalle app iOS e Android. Aggrega i dati, filtra i campi non necessari e comprime la risposta finale per garantire prestazioni rapide.

Gateway API e BFF: qual è la differenza?

È comune confondere questi due modelli perché entrambi si collocano tra il client e i microservizi. Ecco la distinzione:

Caratteristica Gateway API generale Backend per frontend (BFF)
Numero di gateway Tipicamente uno per l’intero sistema. Multipli (uno per ogni tipo di dispositivo client).
Responsabilità Routing di alto livello, limitazione della velocità e sicurezza globale. Aggregazione di dati e personalizzazione dei payload per un frontend specifico.
Proprietà Gestito da un team dedicato all’infrastruttura backend/piattaforma. Gestito dal team frontend che crea l’app corrispondente.
Personalizzazione Basso. Le modifiche riguardano tutti i client. Alto. Le modifiche interessano solo un’applicazione client.

Un’implementazione pratica (Node.js/Express)

Per capire come funziona nella pratica, scriviamo un semplice esempio Node.js.

Immagina di avere due microservizi in esecuzione internamente:

  • Servizio utente (restituisce informazioni di base sul profilo utente)
  • Servizio ordini (restituisce un elenco di ordini con tutti i dettagli)

Vogliamo creare un BFF Web e un BFF mobile per servire il nostro sito desktop e l’app mobile in modo diverso.

1. Il mock dei microservizi condivisi

Innanzitutto, ecco i dati fittizi per i nostri due microservizi sottostanti:

// Internal User Service Response
const userProfile = {
    id: 42,
    username: "dev_coder",
    email: "coder@ghaznix.com",
    avatarUrl: "https://ghaznix.com/avatars/42.png",
    preferences: { theme: "light", newsletter: true }
};

// Internal Order Service Response
const orderHistory = [
    { id: "ORD-99", date: "2026-06-25", items: ["Laptop", "Mouse"], status: "Shipped", tax: 15.00, total: 1215.00 },
    { id: "ORD-88", date: "2026-05-12", items: ["Keyboard"], status: "Delivered", tax: 5.00, total: 105.00 }
];

2. Il Web BFF (restituisce il carico utile dettagliato completo)

Il Web BFF aggrega tutti i campi perché lo schermo del desktop ha molto spazio per mostrarli:

const express = require('express');
const webBff = express();

webBff.get('/dashboard', (req, res) => {
    // Web needs everything: profile + full order details + settings
    const responsePayload = {
        user: {
            username: userProfile.username,
            email: userProfile.email,
            avatar: userProfile.avatarUrl,
            theme: userProfile.preferences.theme
        },
        orders: orderHistory // Send all order details, taxes, and items
    };
    
    res.json(responsePayload);
});

webBff.listen(3001, () => console.log('Web BFF running on port 3001'));

3. Il migliore amico mobile (rendimenti ridotti al minimo, carico utile aggregato)

Il BFF mobile filtra i campi non necessari (come email, impostazioni e tasse) e aggrega gli elementi dell’ordine per risparmiare larghezza di banda:

const express = require('express');
const mobileBff = express();

mobileBff.get('/dashboard', (req, res) => {
    // Mobile only wants: username, avatar, and summary of the latest order
    const latestOrder = orderHistory[0];
    
    const responsePayload = {
        user: {
            username: userProfile.username,
            avatar: userProfile.avatarUrl
        },
        latestOrderStatus: {
            orderId: latestOrder.id,
            status: latestOrder.status,
            date: latestOrder.date,
            itemCount: latestOrder.items.length // Send count instead of array list
        }
    };
    
    res.json(responsePayload);
});

mobileBff.listen(3002, () => console.log('Mobile BFF running on port 3002'));

Confronto delle dimensioni del carico utile

  • Dimensione risposta Web BFF: contiene configurazione nidificata, preferenze, elenco completo degli ordini, tasse, articoli, ecc. (Circa 400 byte).
  • Dimensione risposta BFF mobile: contiene solo 6 coppie chiave-valore che rappresentano gli elementi essenziali. (Circa 120 byte—riduzione del 70% delle dimensioni della rete!).

Pro e contro del modello BFF

Sebbene altamente efficace, il modello BFF presenta dei compromessi:

Vantaggio (Pro) Svantaggio (Con)
Prestazioni client ottimizzate: i client caricano solo i dati esatti di cui hanno bisogno, riducendo il consumo della batteria e l’utilizzo della memoria. Duplicazione del codice: potresti finire per scrivere una logica di recupero dei dati simile in più codebase BFF.
Cicli di rilascio più rapidi: il team del frontend mobile può aggiornare il proprio server BFF senza bisogno di coordinarsi con gli sviluppatori web. Numero di server aumentato: invece di gestire un gateway API, ora devi distribuire e gestire diversi servizi BFF.
Codice frontend semplificato: il client non ha bisogno di gestire complesse logiche di ordinamento, filtraggio o unione; mostra semplicemente il JSON che riceve. Gestione della sicurezza: le certificazioni SSL/TLS, le regole sui limiti di velocità e i firewall devono essere gestiti su più gateway.

Conclusione

Il modello Backend for Frontend (BFF) è un’architettura potente per sistemi che servono più tipi di client, come dispositivi Web, mobili e IoT. Creando gateway su misura per ogni frontend specifico, disaccoppia lo sviluppo del client, riduci al minimo le dimensioni del carico utile e offri un’esperienza utente più rapida e reattiva.

Se il tuo sistema ha una sola applicazione web, è sufficiente un gateway API condiviso. Ma nel momento in cui inizi a creare app mobili o esperienze per dispositivi specializzati insieme alla tua applicazione web, implementare un BFF è il modo migliore per mantenere le tue architetture frontend e backend pulite, ottimizzate e indipendenti.


Scopri ulteriori approfondimenti sullo sviluppo software e sull’ingegneria backend sul blog di Ghaznix →