Segui su:
Programmazione Web Italia

Scopri quali sono i 3 principali paradigmi della programmazione software

Scopri quali sono i 3 principali paradigmi della programmazione software

I principali paradigmi di programmazione si riducono a tre: programmazione strutturata, programmazione ad oggetti e programmazione funzionale. Lo scopo di questo articolo è quello di evidenziarne i caratteri salienti e i vantaggi che derivano dalla loro applicazione.

Programmazione strutturata

Lo scopo della programmazione strutturata è la destrutturazione di una applicazione software in moduli, ogni modulo può, a sua volta, essere suddiviso ricorsivamente in componenti più piccole, fino ad arrivare alla singola funzione atomica. Questo paradigma permette di affrontare un problema complesso (la nostra applicazione) attraverso un approccio divide-et-impera separando le sue funzionalità in unità più piccole e gestendole in maniera indipendente: è un approcciò più strategico nella gestione della complessità.

Ogni funzione può essere descritta tramite l'utilizzo delle tre strutture di controllo: sequenza, selezione e iterazione, ne deriva che tutti i programmi, a prescindere dalla loro complessità, possono essere descritti utilizzando solamente questi tre principi di base.

Un altro concetto importante circa il paradigma della programmazione strutturata e il suo approccio modulare riguarda il fatto che le funzioni atomiche risultanti dalla destrutturazione sono soggette a test formali volti a verificare la presenza eventuale di bug: il successo del test ci dimostra che un tale bug è presente nel sistema che stiamo progettando; al contrario il fallimento del test ci può dare una ragionevole sicurezza che certuni bug non siano presenti, nonostante non sia formalmente possibile dimostrarne l'assenza totale.

Programmazione orientata agli oggetti

La programmazione orientata agli oggetti (OOP) vuole organizzare la struttura della nostra applicazione attorno ad "oggetti" il più possibile attinenti al mondo reale; all'interno di questi oggetti, dati e comportamenti vengono simulati dagli attributi e dalle funzioni della classe utilizzata per rappresentare il nostro oggetto.

I tre principi su cui si fonda la OOP sono essenzialmente i seguenti.

  • Incapsulamento: i dati e i dettagli di implementazione dell'oggetto sono nascosti al suo interno e raggiungibili solo attraverso funzioni apposite.
  • Ereditarietà: attributi e funzionalità di un oggetto possono essere ereditate da altri oggetti (essenzialmente delle sotto-classi) creando così una gerarchia di classi/oggetto che condividono alcune caratteristiche comuni.
  • Polimorfismo: gli oggetti hanno comportamenti differenti a seconda del contesto in cui vengono eseguiti. Questo avviente attraverso l'overloading (la stessa funzione può accettare differenti parametri) o attraverso l'override (una funzione viene ridefinita nelle sottoclassi).

Non si tratta di concetti nuovi o particolarmente innovativi, ma i linguaggi che implementano il paradigma OOP (Java, C++, ...) rendono il loro utilizzo più sicuro e facile.

Dal punto di vista architetturale, sfruttare i principi della OOP permette di creare una architettura a plugin dove i vari moduli della nostra applicazione possono essere sviluppati, testati e connessi tra di loro secondo le regole dettate dalla loro interfaccia e non dalla loro implementazione interna. Si ottiene una indipendenza di deploy in quanto differenti componenti possono essere forniti in maniera separata ed indipendente, e una indipendenza di sviluppo in quanto i vari componenti possono essere sviluppati in modo indipendente da team differenti.

Programmazione funzionale

Il concetto di fondo di questo paradigma riguarda il fatto che le variabili utilizzate... non variano! Il risultato ottenuto è quello derivante dalla esecuzione di funzioni pure (funzioni indipendenzi da variabili globali, che producono lo stesso output a partire dallo stesso input e che non hanno effetti collaterali). I dati e i risultati prodotti dalla esecuzione sono per definizione immutabili e vengono mantenuti tutti in memoria: una soluzione perfetta se abbiamo a disposizione una quantità infinita di memoria. Nella realtà, ci sarà bisogno di qualche compromesso.

Da questi postulati si ricava il concetto di Origine degli Eventi (event sourcing), una strategia che si occupa di memorizzare tutte le computazioni ma non lo stato complessivo. Quando è necessario lo stato, questo viene ricavato eseguendo nuovamente le computazioni.

Il costo in termini di calcolo e memoria si compensano, dal punto di vista architetturale, con il fatto che la programmazione funzionale è particolarmente adatta per la scrittura di codice parallelo e concorrente perchè aggira i problemi dovuti alla mutabilità delle variabili (pensiamo ad una variabile il cui valore viene letto e scritto da più soggetti in maniera concorrente - ricordo che in questo paradigma le variabili sono delle costanti: il loro valore non muta- ) e permette di segregare l'applicazione in componenti mutabili ed immutabili. I componenti immutabili sfrutteranno tutti i vantaggi del paradigma funzionale lasciando la possibilità di utilizzare altre strategia per quanto riguarda le componenti mutabili.