Una pratica molto comune, quando sviluppiamo o manteniamo codice in un qualsiasi linguaggio, è di cercare una soluzione veloce sul web per un problema specifico. Quello che si vorrebbe trovare è uno snippet (un pezzetto di codice) che faccia al caso nostro: molte volte la ricerca funziona, e risolviamo il problema in pochi istanti. Altre volte troviamo risposte che sembrano corrette, ma non riusciamo a beneficiare delle informazioni perché non comprendiamo la terminologia, o ci mancano le basi teoriche. Oggi cercheremo di spiegare i concetti essenziali dei design patterns più utilizzati, sperando di fornire il vocabolario minimo necessario per interpretare gli snippet più interessanti.
Trattandosi di un argomento molto vasto, che tocca tematiche cruciali dell'ingegneria del software, eviteremo una trattazione completa dei concetti esposti, cercando invece di chiarire la terminologia, per consentire al lettore di approfondire autonomamente le nozioni di suo interesse. Per lo stesso motivo considereremo solamente i design patterns che vengono comunemente applicati in PHP, pur essendo comuni a molti altri linguaggi (come Java e C++).
MVC (Model-View-Controller)
E' un pattern di programmazione applicabile a qualsiasi paradigma o linguaggio. Sia che lavoriamo con PHP, Java o JavaScript possiamo adottare il pattern MVC come struttura di base del software. Un pattern di questo tipo serve principalmente a modellare un software che richiede un'interfaccia utente o GUI (Graphic User Interface), la quale rappresenta dei dati o delle entità gestibili dall'utente.
Un esempio classico potrebbe essere un software gestionale: l'utente agisce sull'interfaccia (che in questo caso è detta View), le sue azioni sono controllate da alcune parti del software (dette Controller) e come risultato finale si modificano o leggono dei dati da un database. Il modello, o Model, in questo caso potrebbe essere il codice che si occupa di connettersi al database e implementare la business logic, ovvero descrivere gli scenari d'uso. Apparentemente si tratta della scoperta dell'acqua calda, ed in parte è vero: il pattern MVC è presente quasi ovunque, almeno in prima approssimazione. Le cose cambiamo quando andiamo a vedere l'architettura del software in dettaglio. Si parla di pattern MVC quando tutte le componenti software rispettano questo modello. Vediamo un esempio, considerando un'applicazione webmail via browser. Quando l'utente visualizza la posta in arrivo, avremo una view specifica che si occupa di visualizzare il mittente, l'oggetto della mail, ecc. Una view di questo tipo potrebbe chiamarsi inboxView, ed essere associata all'inboxController. Ogni volta che l'utente clicca sull'interfaccia, il controller si occupa di gestire l'evento e inoltrare l'azione, opportunamente parametrizzata, ad un pezzo di codice chiamato inboxModel, dove si trova la logica principale di trattamento delle informazioni.
Se l'utente decide di scrivere una mail avremo una nuova interfaccia grafica (la composeView), regolata dal composeController e gestita dal composeModel.
Questo dovrebbe chiarire perché il pattern MVC non è banale come sembra. Esemplificando, se la nostra applicazione prevede una dozzina di finestre o pannelli, probabilmente avremo una dozzina di terne MVC, ovvero: dodici viste (views), dodici gestori (controllers) e dodici modelli (models). In alcuni casi potrebbero bastare meno modelli, perché alcune viste o gestori potrebbero condividere lo stesso modello. In altri casi si potrebbe avere una vista per ogni interfaccia, associata al suo controller, ma un unico modello comune.
Lavorare col pattern MVC significa investire più tempo in fase di design e sviluppo, col vantaggio di semplificare i tempi di manutenzione e aggiornamento del software. Un'applicazione basata sul pattern MVC permette di aggiungere facilmente nuove funzionalità, fissare bug o addirittura cambiare tecnologia, perché separa a livello logico le diverse componenti software. Un esempio classico è la rivisitazione di un'interfaccia grafica: se l'applicazione è realizzata col pattern MVC, possiamo stravolgere l'interfaccia grafica, cambiare layout o addirittura tecnologia, semplicemente modificando o sostituendo la vista che ci interessa: tutto il resto continuerà a funzionare come prima.
Entità e Value Objects
Un'entità (Entity) è un pattern frequente della programmazione OOP (Object Oriented Programming), recentemente perfezionata e adattata anche da altri paradigmi, come ad esempio il DDD (Domain-driven design). Al di là di queste sigle, il concetto è veramente semplice: un'entità è un qualsiasi pezzo di codice (o classe se lavoriamo ad oggetti) che rappresenta un insieme di dati aventi un'identità propria. Consideriamo un array contenente i dati di un cliente, ad esempio
array("id" => "1", "name" => "Mario", "surname" => "Rossi")
questa può essere considerata, da un punto di vista astratto, un'entità. La caratteristica principale è la seguente: se abbiamo un altro array (o oggetto) dello stesso tipo, possiamo sempre dire se si tratta della stessa entità oppure di un'entità diversa. Ad esempio
array("id" => "2", "name" => "Mario", "surname" => "Rossi")
la persona qui sopra è un'entità diversa dalla precedente, perché ha un ID diverso. Le due persone sono omonime, potrebbe avere altri dati in comune, ma noi sappiamo che si tratta di persone distinte. E' importante precisare che la decisione di cosa è un'entità e cosa non è un'entità avviene in fase di analisi e progettazione. Nell'esempio qui sopra, siccome abbiamo deciso che persone omonime devono essere distinte a livello software, abbiamo aggiunto il campo ID nell'array per gestire tale possibilità. In termini più precisi: l'array qui sopra contiene il campo ID perché le persone sono entità, e non viceversa! Il fatto di essere un'entità deriva dall'analisi del mondo reale, quello che analizziamo con i requisiti o gli scenari d'uso, e solo dopo si riflette nel come scriviamo il codice.
Per i Value Objects (VO) valgono sostanzialmente gli stessi concetti di un'entità, con un differenza cruciale: i VO non hanno identità. Possiamo implementare il concetto sia come oggetto, classe o array, ad esempio
$indirizzo = array("Via" => "Roma", "numero" => "42", ...)
che potrebbe contenere tutti i campi del caso (città, CAP, provincia ecc.). Probabilmente abbiamo usato i value objects da sempre, senza saperlo. Esistono però alcune differenze tra un banale wrapper, array o bundle contenente una serie di dati, e un vero value object. Innanzitutto si parla di VO soprattutto nella programmazione ad oggetti, perché non è poi così utile definire il termine nell'ambito della normale programmazione strutturata. In secondo luogo, i value objects sono spesso immutabili, ovvero non è possibile modificare i dati contenuti come attributi. Questo spiega perché il concetto di VO è usato soprattutto nella programmazione Obiect Oriented: una classe VO di solito contiene solamente costruttori e metodi getters, ma non contiene i metodi setters. Ogni volta che modifichiamo un VO, viene creata una nuova istanza (ma il nome della variabile potrebbe restare invariato).
Senza un esempio completo i concetti qui sopra potrebbero sembrare astratti o troppo generici. Nelle prossime puntate vedremo come applicare i concetti per creare di alcuni snippet PHP specifici, e tutto dovrebbe essere più chiaro.