Clean Architecture – Robert C. Martin

Clean Architecture è il libro che stavo aspettando da tempo. Uncle Bob (ovvero Robert C. Martin) conclude con questo volume la sua trilogia del Clean Code, portando le sue idee e i suoi consigli per un miglior codice a livello di design e di architettura del codice stesso. Il risultato è un volume dalla consistenza importante, con ottimi consigli, concetti volutamente ripetuti e ripresi, e qualche piccola chicca qua e là. Andiamo con ordine.

Uncle Bob ci porta ad iniziare il nostro viaggio per un’architettura ‘pulita’ dai mattoncini, con il solito approccio bottom-up. Si parte con concetti quali: “cos’è un architettura?”, “cosa deve e può fare un software architect?”, “quale differenza al giorno d’oggi c’è fra design e software architecture?”. In maniera chiara e concisa egli mette le basi per i concetti a venire, partendo dai paradigmi di programmazione, dove enfatizza: “essi ci pongono restrizioni su cosa possiamo fare, piuttosto che darci la possibilità di fare nuove cose con il nostro codice”.

Il focus si sposta poi sui principi SOLID, un insieme di cinque principi che vengono ripresi e trattati prima a livello di codice, poi di unità deployabile di codice (il componente) e infine a livello di connessione fra diversi componenti (il sistema software). I principi sono interessanti, cercherò di riassumerli in cinque punti schematici:

  • Single Responsability Principle: ogni componente software deve cambiare per un solo motivo. Ovvero, separare tutti i componenti e i layer che cambiano per diversi motivi, in diversi momenti.
  • Open-Closed Principle: I componenti ‘stabili’, ovvero di alto livello, non devono essere mai cambiati, ma devono poter essere estendibili, e per questo vanno definiti astratti.
  • Liskov Substitution Principle: per avere del software riusabile ed estendibile, i componenti devono essere definiti da interfacce tramite le quali è possibile intercambiarli.
  • Interface Segretation Principle: separare i componenti da dipendenze che effettivamente non usano.
  • Dipendency Inversion Principle: il flusso di dipendenze deve sempre andare dai componenti meno stabili (di dettaglio implementativo) a quelli stabili (business rules). La comunicazione deve avvenire non in maniera diretta ma tramite un componente di indirezione, astratto.

Questi principi vengono, come già detto, espansi anche al macro-livello di connessione fra componenti: interessante in questo caso lo studio per trovare dipendenze fra moduli e cicli di dipendenze, tramite metriche inventate da Martin stesso e ‘cablabili’ in script e programmi per controllare periodicamente, in maniera automatica, le dipendenze del nostro sistema software, di modo da prevenire i problemi prima di ulteriori implementazioni.

Architettura software, per Martin, significa utilizzare i principi DIP e SRP per supportare al meglio gli aspetti di un sistema software, ovvero: sviluppo, deploy, dev-ops e manutenzione. Il miglior software architect cercherà di portare più beneficio possibile, con trade-off a vari livelli dell’architettura, per migliorare questi aspetti, tenendo sempre presente il principio fondamentale: il software cambierà, i requisiti stessi cambieranno, e l’unico modo per avere un software utilizzabile e facilmente modificabile è ‘tenere tutte le opzioni aperte’, il più possibile a lungo.

Per Martin, avere un sistema che non si lega a framework troppo invasivi, che utilizza livelli di indirezione astratti, e che organizza il codice in maniera modulare e a componenti, permette il più possibile di ritardare le scelte implementative e di dettaglio soltanto a quando sarà strettamente necessario farle.

Si arriva quindi al capitolo portante, ‘Clean architecture’, che racchiude i principali concetti in questo schema:

Gli elementi di dettaglio sono il cerchio azzurro più esterno, e sono trattati nei capitoli finali, rispettivamente riguardano Frameworks, Database e Web. Tutti essi sono dettagli implementativi, esterni dalle logiche applicative (business rules), ovvero core, del sistema.

Con il capitolo ‘Screaming Architecture’ Martin ci insegna che gli Use Cases dovrebbero essere visibili dalla struttura del progetto, per permettere ai nuovi sviluppatori del team di capire subito quali modifiche fare e soprattutto dove farle. Nel capitolo ‘The Dependency Rule’ vengono ripetuti i soliti concetti relativi alle dipendenze, estendendoli con uno sguardo “dall’alto” in accordo con lo schema sopra: esso rappresenta un’architettura a ‘Port and Adapters’, molto simile al modello ‘hexagonal’, dove i cerchi esterni dipendono sempre da quelli interni, e mai il viceversa. Inoltre ogni cerchio deve dipendere soltanto dal cerchio interno più vicino.

Interessante il punto di vista di Martin rispetto all’architettura a Micro-Servizi (microservices): Martin non è propenso con l’utilizzarla di default come architettura di partenza, ma preferisce partire con una separazione dei componenti meno forte, mantenendo comunque il sistema aperto a questa ulteriore (ed ‘estrema’) scelta. A dire il vero, visto che i micro-servizi possono a loro volta essere dei piccoli software monolite – se non separati a loro volta in componenti, Martin non crede che essa sia da considerarsi propriamente un’architettura.

L’ultimo capitolo è una piccola gemma scritta da Simon Brown; egli ripercorre brevemente i concetti del libro parlando di come si possono separare i componenti di un sistema. Si può avere un ‘package by layer’, ovvero una separazione per layer, oppure un ‘package by feature’ con una separazione per use case (rispetto all’altra, più ‘screaming’, ovvero parlante). Viene poi l’architettura di Martin ‘Port and Adapters’ e infine la proposta di Brown, ovvero ‘by component’, separando le view dai package degli use cases, i quali contengono informazioni di core e di persistenza, mantenendo comunque (come propone Martin) internamente una separazione a componenti.

Si conclude il capitolo con un ottimo consiglio: il poco utilizzo generale di modificatori d’accesso (public, private, protected in Java ad esempio) rende quasi inutile la separazione semantica trattata finora, poiché uno sviluppatore indisciplinato, pigro o semplicemente novizio, può ad ogni modo ‘saltare’ da un modulo all’altro ignorando i vincoli di dipendenze. Ciò ci porta a riflettere sull’importanza dei dettagli implementativi delle architettura, che se ignorati rendono vani tutti gli studi per il design del sistema in questione.

Il libro si conclude inoltre con un capitolo autobiografico di Martin sulla storia delle architetture software, alle quali Martin ha personalmente messo mano.

Un libro massiccio, completo, che non tratta le differenze fra le varie architetture software (o meglio, non direttamente) ma espone – e secondo me ciò risulta molto più utile – i principi che stanno dietro le architetture. Porta a ragionare e a questionarsi sul perché ogni scelta viene fatta o perché non è stata fatta, magari in un progetto a cui abbiamo messo mano. Porta ad essere critici e a capire che nel design di un sistema software, la prudenza non è mai troppa e a volta bisogna rischiare, mantenendosi sempre attenti e analizzando come il team e il software reagiscono alle scelte architetturali, cambiandole in corso d’opera quando necessario.

Un libro che forma e che fa pensare in grande. Consigliatissimo. Non è un libro con cui partire da zero: consiglio di accingervi alla lettura dopo che avrete lavorato a diversi progetti, con diverse architetture, ognuna con i suoi problemi. Vi renderete conto che Martin tratta problemi reali, e potrete pensare “Ecco, magari se lo avessi letto prima, lo avrei impostato così”. E ciò non sarà tanto fonte di rimorso quanto di soddisfazione, per la consapevolezza che avrete imparato, e tanto.

Precedente Collaborative Web Development - Adam Scott Successivo Nove Volte Sette - Isaac Asimov