Info sul libro Design pattern in Typescript + codici in TypeScript

Come ragionare per creare il design ottimo a partire dai requisiti di progetti reali

  • Informazioni
  • A cosa servono i design pattern (estratto del libro)
  • Codici
  • Indice del libro

Informazioni

Come nasce il libro

Insegno il Corso di Ingegneria del Software all’Università degli Studi di Perugia e dopo diversi anni mi sono accorto che i testi classici sui design pattern sono spesso pensati come manuali.

Ho sempre pensato che per la comprendere velocemente e in maniera efficace un concetto l’approccio a manuale spesso non basta. Per questo ho voluto scrivere un libro che spiegasse il processo per raggiungere un design ottimale, arrivando ad ottenere un pattern come naturale evoluzione del design.

Autore

Ciao, sono Salvatore e trovi tutto su di me sul sito

https://linkedin.com/in/salvatoreromeo

Sviluppo software fin da quando avevo 12 anni. Oggi è il mio lavoro principale. Insegno Ingegneria del Software all’Università degli Studi di Perugia e creo mini corsi di 3 giorni per le aziende che si occupano di sviluppo software. Il più recente è il corso su Angular erogato insieme al Codemotion. Il corso completo è anche disponibile in formato libro su Amazon.

Se vuoi maggiori informazioni su di me contattami pure tramite linkedin o tramite form in basso.


A cosa servono i design pattern

Lo sviluppo del software è una disciplina molto recente. Alcuni accomunano lo sviluppatore ad un artigiano che modella una materia (che nel caso dello sviluppatore vuol dire scrivere del testo) per ottenere un risultato (il sistema software che svolge le sue funzioni).

In quasi tutte le arti per ottenere un ottimo risultato finale occorre che tutte le parti siano state pensate e costruite nel migliore dei modi; nel caso del software può invece succedere qualcosa di singolare: il risultato finale può essere eccellente, anche se le parti del sistema sono state implementate in maniera approssimativa e superficiale.

Se questo non è un problema al momento della prima consegna del sistema, lo diventa subito dopo. Sono rari i casi in cui un software viene scritto e consegnato in maniera definitiva: molto più comune è il caso in cui un software si evolve, vengono aggiunte delle funzionalità, si trasforma per migliorare le prestazioni o i risultati attesi.

E’ proprio quando il software si trasforma e si evolve che cominciano i problemi.

Da questo momento, se le basi del sistema non erano state pensate fin dal principio per essere estese, si inizieranno ad aggiungere pezzi su pezzi, “appiccicare” codici qui e là finché si arriverà all’inevitabile: un sistema ingestibile.

Gli sviluppatori che hanno il compito di evolverlo non sanno più dove intervenire per migliorare una parte del sistema senza coinvolgere il tutto e magari rischiare di compromettere funzionalità precedenti per aggiungerne di nuove.

I design pattern sono una prima risposta a tutte queste problematiche, perché permettono di applicare soluzioni ormai consolidate a problemi che si ripetono nello sviluppo software. E ciò è vero a vari livelli. In questo testo ci occuperemo del livello più basso: le classi base che costituiscono un sistema software.

Cerchiamo di capire meglio questo concetto.

Quando un programmatore inizia a programmare per la prima volta, gli esercizi o gli esempi che esegue mentre sta sviluppando hanno tutti una caratteristica: esiste un input e si deve produrre un output. Per ottenere l’output si scrive il codice opportuno. Quello che si ottiene è quasi sempre un’unica classe con centinaia di righe di codice. Nella migliore delle ipotesi viene aggiunto un metodo solo quando lo stesso gruppo di istruzioni deve essere usato in vari punti del codice.

Immaginiamo ora di progettare un sistema moderno con questo approccio. Le centinaia di righe di codice diventerebbero presto migliaia.

Lo sviluppatore alle prime armi potrebbe ancora non vedere il problema: in fondo ha scritto personalmente tutto il codice e sa esattamente dove intervenire per modificare parti del sistema.

Supponiamo però di essere in una situazione differente: stiamo lavorando con un gruppo di persone, in un team, e un nostro collega ha scritto un sistema completo, usando la stessa filosofia di progettazione: migliaia di righe di codice in un unico file.

Immaginiamo quindi di dover capire dove intervenire per estendere il sistema del nostro collega. Sarebbe altrettanto facile? Quando non si conoscono i nomi delle funzioni, le istruzioni usate per arrivare allo scopo, un if pensato in un modo quando il nostro modo di ragionare ci avrebbe portato ad implementarlo in un altro modo. Con tutte queste varianti, siamo sicuri di essere ancora in grado di estendere il sistema altrettanto agevolmente come nel caso del sistema sviluppato personalmente?

Torniamo per un attimo al sistema scritto da noi. Supponiamo ora di non intervenire sul sistema per due mesi. In questi due mesi abbiamo continuato a programmare e abbiamo sviluppato altri sistemi. Magari il nostro modo di sviluppare è anche migliorato. Se ora andiamo a riprendere il codice di due mesi prima, siamo sicuri di comprenderlo e ricordarlo come allora?

Vi assicuro che l’esperienza è purtroppo identica al caso di intervenire sul codice di un’altra persona, se non peggio.

E’ importante quindi scrivere codice pensando sempre che domani un’altra persona possa dover intervenire al posto nostro.

E’ importante scrivere codice ordinato, sintetico, pulito e manutenibile.

Cosa possono fare i design pattern per noi? la cosa più significativa è che ci possono aiutare a scrivere codice che non dovrà mai più essere modificato quando ci sarà la necessità di:

  • aggiungere funzionalità;
  • migliorare le prestazioni delle funzionalità esistenti;
  • eliminare funzionalità precedenti perché obsolete.

In tutti questi casi, se non dobbiamo intervenire sul codice esistente, sarà bassissimo il rischio di creare sistemi ingestibili e fragili.

Progettare un buon design consisterà quindi nel trovare il giusto compromesso tra due obiettivi:

  • scrivere codice semplice e sintetico
  • scrivere codice manutenibile (cioè che possa evolversi con pochissime modifiche al codice esistente)

Quando il codice è troppo semplice e scritto esclusivamente per implementare una funzione, il rischio è di aver progettato un design poco manutenibile; quando creiamo un design troppo complicato forzando i pattern usati, sicuramente abbiamo compromesso la semplicità. Quando avremo trovato il giusto equilibrio tra i due punti sopra avremo sicuramente ottenuto un buon design.

I design pattern, in questo senso, sono soluzioni che rispettano appieno questo equilibrio: come vedremo, sono la massima espressione della manutenibilità per la progettazione delle classi e al contempo sono semplici, eleganti e minimali. In più possono essere applicati in molte situazioni. Da qui il nome pattern, cioè uno schema che si presta bene a risolvere un problema ricorrente.


Codici

Tutti i codici presenti nel testo sono anche pubblicati su GitHub all’indirizzo

https://github.com/devexp-io/codici-design-pattern-typescript/tree/master/src


Sommario

Indice        5

Autore        10

Introduzione        12

Prerequisiti        13

A cosa servono i design patterns        15

Dependency Injection: comprendere l’utilità delle interfacce e del polimorfismo        20

Interfacce e polimorfismo        21

Dependency Injection        26

Cosa imparerai con l’esperienza        36

Template Method: progettare un componente con un metodo personalizzabile        39

Oltre il design pattern        47

Cosa imparerai con l’esperienza        48

Codice per filtrare in base alla data        49

Strategy: diverse implementazioni dello stesso concetto astratto        52

Strategy        54

Nota per il linguaggio Typescript        58

Oltre il pattern        58

Cosa imparerai con l’esperienza        59

Observer: aggiungere comportamenti dinamici ad un sistema in esecuzione        64

Oltre il pattern        74

Cosa imparerai con l’esperienza        75

Nota sui diagrammi        75

Command: come trasformare un dato o ripristinare sue versioni precedenti        77

Nota        87

Un’implementazione generica di annullamento        87

Una variante del command per risparmiare memoria        89

Oltre il pattern        91

Cosa imparerai con l’esperienza        91

State: assegnare un comportamento ad un sistema in base al suo stato        93

Una variante dello state in cui le transizioni sono dinamiche        100

Oltre il pattern        102

Cosa imparerai con l’esperienza        102

Composite: come implementare strutture gerarchiche        105

Variante del composite che distingue le foglie dai nodi        111

Oltre il pattern        116

Cosa imparerai con l’esperienza        116

Factory Method: fornire implementazioni diverse della stessa interfaccia        118

Oltre il pattern        124

Cosa imparerai con l’esperienza        124

Singleton: usare sempre e solo una singola istanza di una classe        128

Oltre il pattern        132

Cosa imparerai con l’esperienza        132

Proxy: estendere un’operazione con istruzioni prima e dopo la sua esecuzione        134

Oltre il pattern        139

Cosa imparerai con l’esperienza        139

Adapter: come adattare un’interfaccia di un sistema esterno ad un’interfaccia del nostro sistema        140

Decorator: ampliare il comportamento di un oggetto con funzioni extra        142

MVC: come strutturare un progetto        149

Model        150

Controller        151

View        151

Esercitazione MVC        152

Oltre il pattern        154

Cosa imparerai con l’esperienza        155

Design di sistemi reali: progetto di un gestionale per un ristorante        157

Architettura del sistema: modello        158

Ristorante        159

Aree, stanze e tavoli        160

Operazioni sui tavoli        165

Occupazione di un tavolo        168

Conclusioni        173

Design di sistemi reali: progetto di un robot        175

Modellazione del robot        176

Modellazione delle azioni        177

Rendere le operazioni annullabili        181

Modellazione dello stato del robot        183

Conclusioni        187

Conclusioni e contatti        189

Appendice 1 – Node e NPM        192

Esigenza        192

Node e NPM        193

Installare Node e NPM        193

Problemi durante l’installazione        196

Esercitazione        197

Passo 1: Installiamo una libreria con NPM: moment        197

Passo 2: Creiamo un file index.html        198

Passo 3: Visualizziamo il risultato sul browser        199

Ricapitolando        201

Cosa imparerai con l’esperienza        201

Conclusioni        202

Appendice 2 – Typescript: installazione, sintassi ed esempi        204

Perché TypeScript        204

Typescript        205

Variabili e oggetti JSON        207

Visualizzare i risultati di una espressione usando console.log        208

Tipi        210

Array e for        211

Ordinamento semplice        212

Ordinamento di oggetti json, filtro e trasformazione        212

Funzioni autonome        213

Classi        214

Interfacce        216

Come gestire librerie esistenti        217

Esercitazione        219

Installiamo Typescript        219

Installiamo WebStorm (o VisualStudio Code)        220

Esercitazione array, classi, interfacce e funzioni        222

Ricapitolando        227

Cosa imparerai con l’esperienza        227