Facade Pattern: semplificare l'accesso a sistemi complessi — articolo

> Facade Pattern: semplificare l'accesso a sistemi complessi

Pillar article sul Facade Pattern: come creare interfacce semplificate che nascondono la complessita di sottosistemi articolati.

Luigi Iadicola
~5 min lettura
#Architettura #Design Pattern #SOLID #Refactoring
Facade Pattern: semplificare l'accesso a sistemi complessi
Facade Pattern: semplificare l'accesso a sistemi complessi

Il problema: troppi oggetti per fare una cosa semplice

Per inviare un'email di conferma ordine servono sei passaggi: creare il template engine, caricare il template, renderizzare con i dati dell'ordine, creare il transport SMTP, configurare le credenziali, costruire il messaggio con mittente, destinatario, oggetto e corpo, e infine inviare. Sei oggetti, dodici metodi, venti righe di codice. Ogni controller che deve inviare un'email ripete lo stesso boilerplate, o copia-incolla da un controller precedente.

Il Facade Pattern propone di creare un'interfaccia semplificata che nasconde questa complessita. Invece di sei oggetti e dodici metodi, il controller chiama Mailer::send('order-confirmation', $order, $customer->email). Una riga. La Facade si occupa di orchestrare i sei oggetti sotto il cofano.

Cos'e il Facade Pattern: definizione formale

Il Gang of Four definisce il Facade come un pattern strutturale che "fornisce un'interfaccia unificata a un insieme di interfacce in un sottosistema. La Facade definisce un'interfaccia di livello superiore che rende il sottosistema piu facile da usare". Non nasconde il sottosistema — lo rende accessibile a chi non ha bisogno di conoscerne i dettagli.

La struttura e semplice: una classe Facade che conosce quali classi del sottosistema sono responsabili di ogni richiesta, e delega le chiamate del client alle classi appropriate. Il sottosistema non sa dell'esistenza della Facade — le sue classi sono autonome e possono essere usate direttamente quando serve un controllo fine.

Esempio teorico: un sottosistema di reportistica

Immagina un sistema di generazione report con diverse componenti:

  • DataExtractor: esegue query sul database e restituisce dati grezzi
  • DataTransformer: aggrega, filtra e formatta i dati per il report
  • ChartGenerator: genera grafici SVG dai dati trasformati
  • PdfRenderer: combina testo e grafici in un documento PDF
  • FileStorage: salva il PDF generato nel filesystem o nel cloud
  • NotificationService: notifica l'utente che il report e pronto

Senza Facade, il controller deve orchestrare tutti questi oggetti manualmente: estrarre i dati, trasformarli, generare i grafici, renderizzare il PDF, salvarlo e notificare l'utente. Sei dipendenze nel controller, sei passaggi da coordinare, sei punti dove qualcosa puo andare storto.

La Facade ReportFacade espone un metodo: generate(string $type, array $params, int $userId): string. Internamente orchestra tutti e sei i passaggi e restituisce il path del report generato. Il controller ha una sola dipendenza e una sola riga di codice.

La Facade non imprigiona

Un malinteso comune e che la Facade impedisca l'accesso diretto al sottosistema. Non e cosi: la Facade e un in piu, non un invece di. Se un caso d'uso specifico richiede il controllo fine sul ChartGenerator — ad esempio per generare un grafico senza il PDF — il codice puo usare direttamente ChartGenerator senza passare dalla Facade. La Facade semplifica il caso comune, non limita i casi speciali.

Esempio teorico: Facade per l'autenticazione

L'autenticazione coinvolge molti componenti: verifica credenziali, hashing password, gestione sessione, generazione token, verifica 2FA, logging dei tentativi. Una AuthFacade espone:

  • attempt(string $email, string $password): bool — verifica credenziali, logga il tentativo, avvia la sessione
  • verify2FA(string $code): bool — verifica il codice TOTP e completa l'autenticazione
  • logout(): void — invalida sessione e token
  • check(): bool — verifica se l'utente e autenticato

Ogni metodo della Facade coordina 3-4 componenti interni. Il middleware di autenticazione chiama AuthFacade::check() senza sapere che sotto il cofano vengono verificati sessione, token JWT e timestamp di scadenza.

Facade vs Service: la differenza

La distinzione tra Facade e Service e sottile ma importante:

  • Facade: semplifica l'accesso a un sottosistema esistente. Non aggiunge logica di business: orchestra componenti gia esistenti. Se rimuovi la Facade, le classi del sottosistema funzionano ancora.
  • Service: contiene logica di business propria. Puo usare componenti del sottosistema, ma aggiunge regole, validazioni e decisioni che non esistono altrove.

Se il metodo della tua "Facade" contiene 50 righe di logica di business con condizioni e calcoli, probabilmente e un Service, non una Facade. Se orchestra 6 chiamate a componenti diversi senza aggiungere logica, e una Facade pura.

Facade in Laravel e il malinteso

Le Facade di Laravel (Cache::get(), DB::table(), Auth::check()) non sono il Facade Pattern del Gang of Four. Sono static proxy: classi che risolvono un service dal container e delegano la chiamata statica a un'istanza. La confusione di nomenclatura e storica, ma e importante capire la differenza: il Facade Pattern originale crea un'interfaccia semplificata per un sottosistema complesso. Le "Facade" di Laravel sono un meccanismo di risoluzione dal container con sintassi statica.

Quando usare il Facade Pattern

  • Usa la Facade quando un sottosistema ha molte classi e il caso d'uso comune richiede di coordinarle sempre nello stesso modo
  • Usa la Facade quando vuoi ridurre le dipendenze del codice client: una Facade al posto di sei classi
  • Usa la Facade quando vuoi creare un punto di ingresso chiaro per un modulo o package
  • Non usare la Facade per nascondere un cattivo design: se il sottosistema e confuso, semplificarlo con una Facade non risolve il problema strutturale
  • Non usare la Facade se il sottosistema ha una sola classe: stai aggiungendo un layer di indirezione senza beneficio

Il Facade Pattern e il pattern della cortesia: rende un sistema complesso accessibile senza semplificarlo oltre misura. Non elimina la complessita — la nasconde dietro un'interfaccia pulita per chi non ha bisogno di vederla, e la lascia accessibile per chi ne ha bisogno.

altri articoli