diff --git a/_posts/2022-10-03-introduzione.md b/_posts/2022-10-03-introduzione.md
deleted file mode 100644
index 13d1ea5cfb087411369d6a8742012d8ea908f1ed..0000000000000000000000000000000000000000
--- a/_posts/2022-10-03-introduzione.md
+++ /dev/null
@@ -1,324 +0,0 @@
----
-layout: post
-title: "[01] Introduzione"
-date:   2022-10-03 14:30:00 +0200
-toc: true
----
-
-# Informazioni logistiche
-- Non ci sarà lo streaming però ci sono le videolezioni
-- Teoria
-    - Lun 14:30-17:00 Aula 403
-    - Mer 14:30-17:00 Aula 403
-- Laboratorio
-    - Gio 13:30-17:30 due turni equivalenti
-        - Turno A matricole pari
-        - Turno B matricole dispari
-    - Due persone per computer, a coppia
-- Non c'è libro di testo, ma consigliati: 
-    - Software Engineering (Carlo Ghezzi, Dino Mandridi)
-    - Design Patterns (Eric Freeman, Elisabeth Robison)
-    - Handbook of Software and Systems Engineering (Albert Endres, Dieter Rombath)
-
-## Esami
-- __Laboratorio__
-    - prova pratica di laboratorio di 4 ore
-    - OPPURE _per chi segue tutti i laboratori_ ci saranno due laboratori valutati A COPPIE
-- __Teoria__ 
-    - prova orale
-- Prima di fare l'orale bisogna fare il laboratorio
-- La prova di laboratorio vale all'infinito
-
-# Introduzione 
-
-## Storia 
-Con la diffusione dei primi computer in ambito accademico, negli anni '50 e '60 si è subito colta la necessità di superare metodi di produzione "artigianale" del software: sebbene il cliente e il programmatore coincidessero e i programmi fossero prettamente matematici, si iniziavano già a vedere i primi problemi. Negli anni '70, si inizia dunque a pensare a dei metodi, dei processi e a degli strumenti che potessero migliorare e ___"assicurare"___ la __qualità del software__, sviluppando un approccio di tipo ingegneristico costituito da una serie di fasi.
-
-## Approccio ingegneristico
-1. __Target__: ci si prefigge un obiettivo da raggiungere.
-2. __Metric__: si definisce una metrica per misurare la qualità del software, ovvero quanto esso si avvicina al target prefissato.
-3. __Method, Process, Tool__: si provano una serie di metodi, processi e strumenti per avvicinarsi all'obiettivo.
-4. __Measurements__: si misura tramite la metrica stabilita se le strategie implementate sono state utili e quanto ci hanno avvicinato (o allontanato) all'obiettivo. A seconda dei risultati ottenuti vi sono due possibili strade:
-    - risultati soddisfacenti (_aumento delle metrica_) - accettiamo come buoni metodi e processi utilizzati.
-    - risultati insoddisfacenti (_diminuzione della metrica_)- ci sono dei peggioramenti o dei forti effetti collaterali, di conseguenza bisogna modificare il lavoro qualcosa: si possono cambiare target o metrica se ci si rende conto di non aver ben definito l'obiettivo, ma più comunemente bisogna rivedere i processi e metodi usati.
-
-Ma __che cosa si intede per target__? Gli obiettivi da raggiungere possono essere di due tipi: la risoluzione dei __problemi nella progettazione del software__ e l'assicurazione di una qualche __qualità che il software dovrà avere__. È dunque necessario chiedersi le seguenti domande:
-- Quali problemi ci sono?
-- Quali qualità deve avere il software?
-
-### Problemi principali
-Vediamo allora a questo punto alcuni dei problemi che possono insorgere durante lo sviluppo di software, partendo dal presupposto che una delle più grandi fonti di problemi sono le __persone__.  L'obiettivo della disciplina è infatti principalmente quello di risolvere i __problemi di comunicazione__, che possono essere:
-- tra il __programmatore__ e il __cliente__: sono esperti di domini diversi ed è difficile comprendersi;
-- tra un __programmatore__ e altri __programmatori__.
-
-Un'altra fonte di problemi sono le __dimensioni__ del software, che possono raggiungere valori molto elevati in termini di milioni di righe di codice e migliaia di _"anni uomo"_ di lavoro. Lo sviluppo software non è più piccolo e domestico, e questo crea chiaramente problemi di manutenzione e gestione della codebase.
-
-Il software è infine __facilmente malleabile__, ovvero modificabile nel tempo: il moltiplicarsi di versioni, evoluzioni e variazioni di target può creare non poche difficoltà.
-
-# Qualità
-Per fare fronte ai problemi sopracitati si sviluppano allora una serie di processi per lo sviluppo software: essi non assicurano la bontà del programma finito, ma possono assicurare la presenza di _proprietà desiderabili_ del prodotto, dette __qualità__. Le qualità del prodotto, che costituiscono a conti fatti un "valore per le persone", si dividono innanzitutto in due tipi:
-- __qualità esterne__: qualità che vengono colte dal cliente;
-- __qualità interne__: qualità che vengono esclusivamente colte dallo sviluppatore.
-
-Le qualità interne influenzano molto le qualità esterne (per esempio se ho un codice ottimizzato ed efficiente, il mio software produrrà i risultati più velocemente). Prima di vedere quali siano le proprietà auspicabili in un software, però, facciamo un'importante distinzione a livello terminologico tra __requisiti e specifiche__:
-- I __requisiti__ sono quello che il cliente vuole che il software faccia. Spesso sono cambiati in corso d'opera oppure sono espressi in modo sbagliato, per cui è necessaria un'interazione continua. 
-- Le __specifiche__ sono ciò che è stato formalizzato dal programmatore a partire dai requisiti: si tratta di una definizione più rigorosa di che cosa dovrà fare il software. Si noti però che se i requisiti sono stati espressi in modo non corretto anche le specifiche risulteranno inesatte (vd. <a href="#g1">G1</a>).
-
-Fatta questa doverosa distinzione, vediamo quali sono le qualità che un software dovrebbe idealmente possedere.
-
-## Qualità del software
-
-Un software di qualità deve <b><i>funzionare</i></b>, <b><i>essere bello</i></b> e <b><i>"farmi diventare ricco"</i></b>.
-
-<table style="margin-bottom: 20px">
-<thead>
-    <tr>
-        <th>Un software deve...</th>
-        <th>Qualità</th>
-        <th>Descrizione</th>
-    </tr>
-</thead>
-<tbody>
-    <tr>
-        <th rowspan="3"><i>Funzionare</i></th>
-        <th>Correttezza</th>
-        <td>
-            Un software è corretto se soddisfa la specifica dei suoi <i>requisiti funzionali</i>. Si tratta di una proprietà <i>"matematica"</i> e relativamente dimostrabile in modo formale.
-        </td>
-    </tr>
-    <tr>
-        <th>Affidabilità</th>
-        <td>
-            Un software è affidabile quando ci si può fidare del suo funzionamento, ovvero ci si può aspettare che faccia ciò che gli è stato chiesto.
-            Se è molto difficile perseverare la correttezza, in quanto si tratta una proprietà assoluta, l'affidabilità è invece relativa: un software può essere affidabile (o <i>dependable</i>) nonostante contenga qualche errore.
-        </td>
-    </tr>
-    <tr>
-        <th>Robustezza</th>
-        <td>
-            Un software è robusto se si comporta in modo accettabile anche in circostanze non previste nella specifica dei requisiti, senza generare effetti troppo negativi.
-        </td>
-    </tr>
-    <tr>
-        <th rowspan="3"><i>Essere bello</i></th>
-        <th>Usabilità</th>
-        <td>
-            Un software è usabile (o <i>user-friendly</i>) se i suoi utenti lo ritengono facile da utilizzare.
-            Si possono fare degli esperimenti (le grandi aziende lo fanno) per testare e quantificare l’usabilità del software ponendolo di fronte a dei soggetti umani (vd. <a href="#nn23">NN23</a>).
-        </td>
-    </tr>
-    <tr>
-        <th>Prestazioni</th>
-        <td>
-            Ad ogni software è richiesto un certo livello di prestazioni. L'efficienza è una qualità interna e misura come il software utilizza le risorse del computer; la performance, d'altro canto, è invece una qualità esterna ed è basata sui requisiti dell'utente. Essa ha effetto sull'usabilità, e spesso viene considerata alla fine dello sviluppo software visto che vari avanzamenti tecnologici possono efficientare algoritmi e processi prima troppo costosi.
-        </td>
-    </tr>
-    <tr>
-        <th>Verificabilità</th>
-        <td>
-            Un software è verificabile se le sue proprietà sono verificabili facilmente: è importante essere in grado di poter dimostrare la correttezza e la performance di un programma, e in tal senso la <b>leggibilità</b> del codice è fondamentale. 
-            La verifica può essere fatta con metodi formali o informali, come il testing.
-            È considerata una qualità interna, ma alcune volte può diventare una qualità esterna: per esempio, in ambiti in cui la sicurezza è critica il cliente può chiedere la verificabilità di certe proprietà.
-        </td>
-    </tr>
-    <tr>
-        <th rowspan="2"><i>Farmi diventare ricco</i></th>
-        <th>Riusabilità</th>
-        <td>
-            Le componenti del software che costruiamo dovrebbero essere il più riutilizzabili possibile così da risparmiare tempo in futuro: ciò può essere fatto non legandole troppo allo specifico contesto applicativo del software che stiamo sviluppando.
-            Con la proprietà di riusabilità, utilizziamo un prodotto per costruire - anche con modifiche minori - un altro prodotto (vd. <a href="#mi15">MI15</a>).
-        </td>
-    </tr>
-    <tr>
-        <th>Manutenibilità</th>
-        <td>
-            Per <i>manutenzione software</i> si intendono tutte le modifiche apportate al software dopo il rilascio iniziale.
-            Questa proprietà può essere vista come due proprietà separate:
-            <ul style="margin-bottom: 0;">
-                <li><b>Riparabilità</b>: un software è riparabile se i suoi difetti possono essere corretti con una quantità di lavoro ragionevole.</li>
-                <li><b>Evolvibilità</b>: indica la capacità del software di poter evolvere aggiugendo funzionalità. È importante considerare questo aspetto fin dall'inizio: studi rilevano come l'evolvibilità decresce con il passare delle release (vd. <a href="#l27-28">L27-28</a>).</li>
-            </ul>
-        </td>
-    </tr>
-</tbody>
-</table>
-
-### Leggi rilevanti
-
-<a id="g1"></a>
-__Prima legge di R.Glass (G1)__. 
-> La mancanza di requisiti è la prima causa del fallimento di un progetto.
-
-<a id="nn23"></a>
-__Legge di Nielsen-Norman (NN23)__.
-> L'usabilità è misurabile.
-
-<a id="mi15"></a>
-__Legge di McIlroy (MI15)__. 
-> Riutilizzare il software permette di incrementare la produttività e la qualità.
-
-<a id="l27-28"></a>
-__Leggi di M. Lehman (L27-28)__. 
-> Un sistema che viene utilizzato cambierà. 
-
-> Un sistema che evolve incrementa la sua complessita a meno che non si lavori appositamente per ridurla.
-
-## Qualità del processo
-> Un progetto è di qualità se segue un buon processo.
-
-Sappiamo che il prodotto è influenzato dal processo che viene utilizzato per svilupparlo, di conseguenza possiamo parlare anche di  __qualità del processo__.
-
-Anche un processo deve funzionare, essere essere bello e farmi diventare ricco, ma dobbiamo interpretare queste parole in maniera differente.
-
-Quali caretteristiche ha un processo di qualità?
-
-<table style="margin-bottom: 20px">
-<thead>
-    <tr>
-        <th>Un processo deve...</th>
-        <th>Qualità</th>
-        <th>Descrizione</th>
-    </tr>
-</thead>
-<tbody>
-    <tr>
-        <th rowspan="1"><i>Funzionare</i></th>
-        <th>Robustezza</th>
-        <td markdown="span">
-            Un processo deve poter resistere agli imprevisti, come la mancanza improvvisa di personale o il cambiamento delle specifiche.
-            Esistono certificazioni (<i>CMM: Capability Maturity Model</i>) che valutano la robustezza di alcuni processi aziendali e che vengono per esempio considerate nei bandi pubblici.
-        </td>
-    </tr>
-    <tr>
-        <th rowspan="1"><i>Essere bello</i></th>
-        <th>Produttività</th>
-        <td markdown="span">
-            La produttività di un team è molto meno della somma della produttività individuale dei suoi componenti. È una metrica difficile da misurare: conteggi come il numero di linee codice scritte o la quantità di <i>tempo-uomo</i> richiesta per un lavoro si rivelano spesso un po' fallaci (per esempio, la gravidanza umana non è un'attività parallelizzabile, ma si potrebbe dire che servono 9 mesi-donna per creare un bambino).
-        </td>
-    </tr>
-    <tr>
-        <th rowspan="1"><i>Farmi diventare ricco</i></th>
-        <th>Tempismo</th>
-        <td markdown="span">
-            Un processo deve consegnare il prodotto nei tempi stabiliti, in modo da rispettare i tempi del mercato. È spesso conveniente la tecnica dello <b>sviluppo incrementale</b>, ovvero la consegna frequente di parti sempre più grandi del prodotto (es. compilatore ADA): essa permette infatti di conquistare il cliente ancor prima di avere il prodotto finito. 
-        </td>
-    </tr>
-</tbody>
-</table>
-
-# Il processo di produzione del software
-Il processo che seguiamo per costruire, consegnare, installare ed evolvere il prodotto software, dall'idea fino alla consegna e al ritiro finale del sistema, è chiamato __processo di produzione software__.
-
-Innanzitutto occorre riconoscere diverse problematiche.
-- I __requisiti__ imposti dal cliente possono cambiare spesso.
-- Produrre software __non è _solo_ scrivere codice__ (alla Programmazione I).
-- Bisogna risolvere i __problemi di comunicazione__ tra tutte le diverse figure in gioco (tra sviluppatori, tra progettista e sviluppatori, ecc).
-- Bisogna essere __rigorosi__, anche se può essere difficile. Ci sono lati positivi e negativi: la rigorisità può facilitare la comprensione di ciò che bisogna fare ma implica  al contempo molta fatica extra, e viceversa.
-    > __Ipotesi di Bauer-Zemanek (BZh3)__: Metodi formali riducono in maniera significativa gli errori di progettazione, oppure permettono di eliminarli e risolverli prima.
-    
-    Trovare gli errori prima della fase di sviluppo permette di facilitarne la risoluzione e di risparmiare sia tempo che soldi: tanto prima si individua un errore, tanto più facile sarà risolverlo.
-- Ci sono __tanti aspetti__ da considerare, che andranno affrontati uno alla volta. Per parlare di aspetti diversi ho bisogno di metodi comunicazione diversi, che interessano ruoli diversi in tempi diversi (_Aspect Oriented Programming_).
-
-Tenendo a mente tutto queste problematiche è necessario decidere come organizzare l'attività di sviluppo software in modo da mitgarle. Per modellare un ciclo di vita del software, occorre dunque in primo luogo __identificare le varie attività necessarie__ e quindi:
-- deciderne le precedenze temporali;
-- decidere chi le debba fare.
-
-In particolare, ci si pone due domande:
-- cosa devo fare adesso?
-- fino a quando e come?
-
-L'ingegneria del software prova a rispondere a queste domande per individuare quali siano le fasi necessarie per sviluppare un software e quale sia la loro migliore disposizione temporale. È dunque bene specificare da subito che lo sviluppo di un programma non è solo coding: tale presupposto genera conseguenze disastrose.
-
-Inizialmente, infatti, nell'ambito dello sviluppo software è stato adottato il modello ___code-and-fix___, che consisteva nei seguenti passi:
-1. scrivi il codice;
-2. sistemalo per eliminare errori, migliorare funzionalità o aggiungere nuove funzionalità.
-
-Ben presto però questo modello si è dimostrato pesantemente inefficace in gruppi di lavoro complessi, specialmente quando il cliente non era più lo sviluppatore stesso ma utenti con poca dimestichezza con i computer, generando codice estremamente poco leggibile e manutenibile.
-
-Per organizzare meglio l'attività di sviluppo e non ricadere negli errori del passato gli ingegneri del software hanno dunque individuato diverse __fasi__ del ciclo di vita di un software che, combinate, permettessero di produrre del software di qualità. Diamo dunque un'occhiata a quelle principali.
-
-## Le fasi del ciclo di vita del software
-
-### Studio di fattibilità
-Lo studio di fattibilità è l'attività svolta prima che il processo di sviluppo inizi, per decidere se dovrebbe iniziare _in toto_.
-L'__obiettivo__ è quello di produrre un __documento in linguaggio naturale__ presentante diversi scenari di sviluppo con soluzioni alternative, con una discussione sui trade-off in termini di benefici e costi attesi.
-
-Più specificatamente, il documento include:
-- uno studio di diversi scenari di realizzazione, scegliendo:
-    - le architetture e l'hardware necessario;
-    - se sviluppare in proprio oppure subappaltare ad altri.
-- stima dei costi, tempi di sviluppo, risorse necessarie e benfici delle varie soluzioni.
-
-È spesso difficile fare un'analisi approfondita, a causa del poco tempo disponibile o di costi troppo elevati: spesso viene commissionata esternamente.
-
-### Analisi e specifica dei requisiti
-L'analisi e specifica dei requisiti è l'attività più critica e fondamentale del processo di produzione del software.
-L'obiettivo è la stesura di un ___documento di specifica___ <!-- ... -->.
-
-
-In questa fase i progettisti devono:
-- comprendere il __dominio applicativo__ del prodotto, dialogando con il cliente e la controparte tecnica;
-- identificare gli __stakeholders__, ovvero tutte le figure interessate al progetto, e studiarne le richieste. Spesso non si tratta di figure omogenee (può essere il _top manager_ fino al segretario) e le loro necessità sono molto diverse;
-- capire quali sono le __funzionalità richieste__: la domanda più importante che deve porsi il programmatore è il _cosa_ non il _come_; al cliente non devono infatti interessare gli aspetti tecnici e le scelte architetturali interne. Le __specifiche__ vanno quindi viste dal punto di vista del cliente.
-- stabilire un __dizionario comune__ tra cliente e sviluppatore che può anche far parte della specifica per agevolare la comunicazione;
-- definire __altre qualità__ eventualmente richieste dal cliente: per esempio, _"la centrale non deve esplodere"_ non è un dettaglio implementativo, ma un requisito. Queste ulteriori qualità, che non sempre sono solo esterne, si dicono __requisiti non funzionali__.
-
-Lo scopo del _documento di specifica_ è duplice: da una parte, deve essere analizzato e approvato da __tutti gli stakeholders__ in modo da verificare il soddisfacimento delle aspettative del cliente, e dall'altra è usato dai programmatori per sviluppare una soluzione che le soddisfi, fungendo da punto di partenza per il design.
-È un documento contrattuale e deve essere scritto in modo formale per evitare contestazioni contrattuali e ambiguità.
-
-Deve essere presente anche un __piano di test__, ovvero una collezione di collaudi che certificano la correttezza del lavoro: se questi test hanno esito positivo il lavoro viene pagato, altrimenti il progetto non viene accettato. A differenza dei lavori di altri tipi di ingegneria, per esempio l'ingegneria civile, dove il collaudo è diretto, nell'ingegneria del software è molto difficile collaudare tutti i casi e gli stati possibili.
-
-Un altro output di questa fase può essere anche il __manuale utente__, ovvero la _"vista esterna"_ (ciò che il cliente vuole vedere, evitando i dettagli implementativi) del sistema da progettare.
-
-> __Legge di David__: Il valore dei modelli che rappresentano il software da diversi punti di vista dipendono dal punto di vista preso (assunto), ma non c'è nessuna vista che è la migliore per ogni scopo.
-
-### Progettazione (design)
-Il _design_ è l'attività attraverso la quale gli sviluppatori software strutturano l'applicazione a diversi livelli di dettaglio.
-Lo scopo di questa fase è quello di scrivere un __documento di specifica di progetto__ contenente la descrizione dell'architettura software (i diversi linguaggi e viste). 
-
-Durante questa fase occorre quindi:
-- scegliere un'__architettura software di riferimento__;
-- __scomporre__ in moduli o oggetti gli incarichi e i ruoli: si tratta del cosiddetto _object oriented design_, non necessariamente accompagnato da object oriented programming;
-- __identificare i patterns__, ovvero problemi comuni a cui è già stata trovata una soluzione generale giudicata come _"bella"_ dalla comunità degli sviluppatori (ne vedremo un paio più avanti nel corso). I pattern favoriscono alcune qualità, come il design.
-
-### Programmazione e test di unità
-In questa fase le _"scatole nere"_ - i moduli o oggetti definiti al punto precedente - vengono realizzate e per ognuna di esse vengono definiti dei __test unitari__ che ne mostrano la correttezza.
-Vi è infatti spesso la brutta abitudine di non fare il testing durante lo sviluppo di ciascun componente, ma solamente alla fine di tutto: questa usanza è molto pericolosa perché un problema scoperto solo alla fine è molto più oneroso da risolvere.
-
-I singoli moduli vengono testati indipendentemente, anche se alcune funzioni da cui dipendono non sono ancora sono state implementate: per risolvere tale dipendenza si utilizzano allora moduli fittizzi (___stub___) che emulino le funzionalità di quelli mancanti.
-Altri moduli, detti ___driver___, forniscono invece una situazione su cui applicare il modulo che sto testando.
-Nei linguaggi più utilizzati esistono framework che facilitano le suddette operazioni al programmatore.
-
-L'obiettivo di questa fase è avere un __insieme di moduli__ separati __sviluppati indipendentemente__ con un'interfaccia concordata e __singolarmente verificati__.
-
-### Integrazione e test di sistema
-In questa fase i moduli singolarmente implementati e testati vengono __integrati__ insieme a formare il software finito. In alcuni modelli di sviluppo (come nello sviluppo incrementale) questa fase viene accorpata alla precedente.
-
-Nei test, i moduli _stub_ e _driver_ vengono sostituiti con i componenti reali formando un sistema sempre più grande fino ad ottenere il risultato richiesto.
-È poi fondamentale testare che l'intero programma funzioni una volta assemblato (non basta che le singole parti funzionino!): test di questo tipo vengono detti __test di integrazione__. 
-
-L'integrazione può essere adottata seguendo un approccio _top down_ o _bottom up_. La fase finale è l'___alpha testing___, ovvero il testing del sistema in condizioni realistiche.
-
-### Consegna, installazione e manutenzione
-Dopo aver completato lo sviluppo, il software deve essere __consegnato__ ai clienti. Prima di consegnarlo a tutti, si seleziona un gruppo di utenti per raccogliere ulteriore feedback; questa fase è chiamata ___beta testing___.
-
-L'__installazione__ (deployment) definisce il _run-time_ fisico dell'architettura del sistema. Per esempio, un servizio di rete potrebbe necessitare di apparecchiatura server da installare e particolari configurazioni.
-
-Infine, la __manutenzione__ può essere definita come l'insieme delle attività finalizzate a modificare il sistema dopo essere stato consegnato al cliente. La manutenzione può essere di tipo:
-- __correttivo__: sistemare errori nel sistema;
-- __adattivo__: adattare il software ai nuovi requisiti (vd. _evolvibilità_);
-- __perfettivo__: migliorare certi aspetti interni al programma senza modificare gli aspetti esterni. Serve per migliorare la futura manutenzione riducendo il cosiddetto _debito tecnico_.
-
-Come già detto, è necessario sviluppare avendo in mente la futura manutenzione di ciò che si sta scrivendo: infatti, il __costo__ della manutenzione concorre al costo del software in una misura spesso superiore al 60%.
-
-L'_output_ di questa fase è un __prodotto migliore__.
-
-### Altre attività
-Alle attività sopracitate se ne aggiungono altre:
-- __Documentazione__: può essere vista come attività trasversale. Per esempio, un documento di specificazione contenente diagrammi UML e una descrizione narrativa che spiega le motivazione dietro certe decisioni può essere il risultato principale della fase di progettazione.
-È un'attività spesso da procastinare, perché le specifiche possono cambiare spesso. In alcuni gruppi esistono delle figure che si occupano di questa attività, anche se può essere pericoloso: non tutti possono capire ciò che un programmatore ha creato.
-- __Verifica e controllo qualità__ (Quality Assurance): nella maggior parte dei casi, la verifica è svolta attraverso review e ispezioni. L'obiettivo è anticipare il prima possibile la scoperta e la sistemazione degli errori in modo da evitare di consegnare sistemi difettosi. Andrebbe fatta costantemente e non tutta alla fine.
-- __Gestione del processo__: gestione incentivi (premi di produzione), responsabilità, formazione del personale, perfezionamento del processo con l'esperienza guadagnata, eccetera. 
-- __Gestione delle configurazioni__: gestione delle relazioni inter-progettuali, ovvero delle risorse di sviluppo non appartenenti ad un singolo progetto. Un esempio potrebbe essere una libreria condivisa tra più progetti, i quali vorrebbero modificare la libreria stessa.
-
-Tutte queste diverse attività saranno specificate successivamente entrando nel dettaglio.
diff --git a/_posts/2022-10-05-Ciclo-Vita-Software.md b/_posts/2022-10-05-Ciclo-Vita-Software.md
deleted file mode 100644
index 2d1042b2fec7307c93e3f22ef4c0f246b163e725..0000000000000000000000000000000000000000
--- a/_posts/2022-10-05-Ciclo-Vita-Software.md
+++ /dev/null
@@ -1,282 +0,0 @@
----
-layout: post
-title: "[02] Modelli di ciclo di vita del software"
-date:   2022-10-05 14:30:00 +0200
-toc: true
----
-
-In questa lezione vedremo i principali modelli di ciclo di vita del software, ovvero famiglie di processi di sviluppo che si distinguono per il modo in cui le fasi di produzione viste nella scorsa lezione vengono organizzate in un processo unitario. Ognuno di tali modelli avrà i propri pro e i propri contro, ed è bene da subito capire che non esiste il modello giusto per ogni situazione.
-
-# Modelli sequenziali
-
-Il modo più semplice e immediato di organizzare le fasi del ciclo di vita di un software è sicuramente quello __sequenziale__: i vari passaggi vengono posti in un ordine prestabilito e vengono attraversati uno alla volta uno dopo l'altro. Da questa idea nascono i cosiddetti _modelli sequenziali_, di cui il più famoso è certamente il _modello a cascata_.
-
-## Modello a cascata
-
-### Caratteristiche e punti di forza
-
-{% responsive_image path: assets/02_waterfall-model.png %}
-
-Nato negli anni '50 ma diventato famoso solo negli anni '70 grazie allo sviluppo di un grosso software per la difesa area chiamato SAGE (_Semi-Automated Ground Environment_), il modello a cascata organizza le fasi in una serie di step sequenziali: fatto uno si passa al successivo fino ad arrivare alla fine, come in una sorta di _catena di montaggio_. Viene infatti forzata una __progressione lineare__ da una fase alla successiva; non è previsto in questo modello tornare indietro a uno step precedente.
-
-Sebbene varino molto da processo a processo, la maggior parte dei processi che segue il modello a cascata include almeno le seguenti fasi organizzate in quest'ordine:
-
-1. Requisiti
-2. Progetto
-3. Codifica
-4. Testing
-5. Prodotto
-
-Ognuno di tali step produce un output, detto __semilavorato__, che è dato come input allo step successivo. In virtù dell'affidamento su tali semilavorati intermedi il modello a cascata si dice __document-based__: tra una fase e l'altra si crea infatti un documento che è il mezzo di trasmissione dell'informazione. Questo aspetto permette una __buona separazione dei compiti__ tra i vari dipendenti che lavorano al progetto: ognuno è infatti specializzato in una singola fase e una volta prodotto il documento utile ad avviare la fase successiva il suo coinvolgimento nel progetto non è più necessario ed esso può essere assegnato ad altri lavori.
-
-La linearità del modello rende inoltre possibile __pianificare i tempi__ accuratamente e monitorare semplicemente lo stato di avanzamento in ogni fase: è infatti sufficiente stimare la durata di ogni fase per ottenere una stima del tempo di completamento dell'intero progetto. Si tratta però di una stima a senso unico: una volta finita una fase non è possibile ridurre il tempo speso, e in caso di inconvenienti l'unica opzione è cercare di assorbire il ritardo.
-
-### Criticità
-
-Sebbene il modello a cascata abbia il grande pregio di aver posto l'attenzione sulla comunicazione tra gli elementi del progetto in un momento storico in cui il modello di sviluppo più diffuso era di tipo _code-and-fix_, esso soffre di numerose criticità.
-
-In primo luogo il modello __non prevede una fase di manutenzione__ del software prodotto: esso assume di non dover apportare modifiche al progetto dopo averlo consegnato, e impedisce dunque di _"tornare indietro"_ in alcun modo. Ovviamente questa assunzione è un'illusione smentita nella quasi totalità nei casi: qualunque software è destinato ad evolvere, e più un software viene usato più cambia. Una volta finito lo sviluppo ciò che si può fare è rilasciare al più piccole patch, che tuttavia non fanno altro che disallineare la documentazione prodotta precedentemente con il software reale.
-
-Il modello soffre inoltre di una generale __rigidità__, che mal si sposa con la flessibilità naturalmente richiesta dall'ambiente di sviluppo software. In particolare, l'impossibilità di tornare indietro implica un __congelamento dei sottoprodotti__: una volta prodotto un semilavorato esso è fisso e non può essere modificato; questo è particolarmente critico per le stime e specifiche fatte durante le prime fasi, che sono fisiologicamente le più incerte.
-
-Infine, il modello a cascata adotta un approccio volto alla __monoliticità__: tutta la pianificazione è orientata ad un singolo rilascio, e l'eventuale manutenzione può essere fatta solo sul codice. Inutile dire che si tratta di una visione fallace, in quanto come già detto più volte il software è destinato ad essere modificato e ad evolvere.
-
-### _Who's Afraid of The Big Bad Waterfall?_
-
-> LIBRO: __The Leprechauns of Software Engineeering__ di Laurent Bossavit.
-
-In realtà, il modello a cascata non è mai stato veramente elogiato, ma è sempre stato utilizzato come paragone negativo per proporre altri modelli o variazioni.
-Nel corso del tempo la sua presentazione è stata erroneamente attribuita al paper [_"Managing the development of large software systems: concepts and techniques"_](https://dl.acm.org/doi/10.5555/41765.41801) di W.W. Royce, di cui veniva citata solo la prima figura: Royce stava a dire il vero presentando quel modello per descrivere la sua esperienza nello sviluppo software, per poi proporre altri concetti più moderni (come lo sviluppo incrementale) che non sono però mai stati colti dalla comunità scientifica.
-
-Anche noi utilizziamo il modello a cascata solo come paragone negativo, e in generale nell'ambiente di sviluppo software esso non è più applicato alla lettera. Alcuni suoi aspetti si sono però mantenuti come linee guida generali (es. l'ordine delle fasi); è infatti bene chiarire subito che esistono due tipi di modelli:
-
-- __prescrittivi__: forniscono delle indicazioni precise da seguire per svolgere un processo;
-- __descrittivi__: colgono certi aspetti e caratteristiche di particolari processi esistenti, ma non obbligano a seguirli in modo rigoroso.
-
-Tutti i modelli visti per ora ricadono perlopiù nell'ambito descrittivo, mentre i modelli AGILE che vedremo più avanti tendono ad essere più di tipo prescrittivo.
-
-### Riassunto pro e contro
-
-<table style="margin-bottom: 20px">
-    <thead>
-        <tr>
-            <th style="text-align:center">Pro</th>
-            <th style="text-align:center">Contro</th>
-        </tr>
-    </thead>
-    <tbody>
-        <tr>
-            <td>
-                <ul style="margin-top: 15px">
-                    <li>Document-based</li>
-                    <li>Buona suddivisione dei compiti</li>
-                    <li>Semplice pianificazione dei tempi</li>
-                </ul>
-            </td>
-            <td>
-                <ul style="margin-top: 15px">
-                    <li>Rigidità</li>
-                    <li>Congelamento dei sottoprodotti</li>
-                    <li>Monoliticità</li>
-                </ul>
-            </td>
-        </tr>
-    </tbody>
-</table>
-
-## Modello a V (denti di pesce cane)
-
-{% responsive_image path: assets/02_v-model.png %}
-
-Dal modello a cascata nascono poi numerose varianti che cercano di risolverne i vari problemi: tra queste spicca per rilevanza il __modello a V__, che introduce fondamentalmente una __più estesa fase di testing__.
-
-Nonostante sia ancora un modello sequenziale come il modello a cascata, nel modello a V vengono infatti evidenziati nuovi legami tra le fasi di sviluppo, che corrispondono alle attività di __verifica__ e __convalida__: alla fine di ogni fase si _verifica_ che il semilavorato ottenuto rispetti la specifica espressa dalla fase precedente, e inoltre si richiede la _convalida_ del fatto che esso sia in linea con i veri vincoli e necessità del cliente. Come si vede, questo modello pone l'accento sul rapporto con il cliente, che viene continuamente coinvolto con la richiesta di feedback su ciascun sottoprodotto generato.
-
-Volendo formalizzare, le due nuove attività introdotte sono dunque:
-
-- __verifica__ (freccie grigie): controlla la correttezza rispetto alla descrizione formale delle specifiche;
-- __validazione__ (freccie bianche): controlla la compatabilità del sistema con le esigenze del cliente tramite feedback continuo.
-
-# Modelli iterativi
-
-Osservando il modello a cascata e le sue varianti ci si è ben presto resi conto che la stringente sequenzialità delle fasi costituiva un grosso limite non conciliabile con la flessibilità richiesta dallo sviluppo software e con la naturale mutevolezza dei requisiti imposti dal cliente. Si inizia dunque a pensare di permettere agli sviluppatori di _ripetere_ alcune fasi più di una volta, ciclando su di esse fino a ottenere un prodotto soddisfacente: nascono così i primi __modelli interativi__.
-
-## Modello a cascata con singola retroazione
-
-{% responsive_image path: 'assets/02_waterfall-retroazione.png' %}
-
-Uno dei primi modelli iterativi è in realtà una variante del modello a cascata, in cui si permette di fare un'unico salto indietro; a parire da una fase si può cioè __ritornare alla fase precedente__: così, per esempio, si può _iterare_ tra _Codifica_ e _Testing_ fino a consegnare il prodotto.
-
-Anche in questo modello non si può però tornare indietro dalla consegna per eseguire attività di manutenzione; inoltre, l'introduzione di un'iterazione rende molto __più difficile pianificare__ il lavoro e monitorarne l'avanzamento: si tratta questa di una caratteristica condivisa da molti modelli iterativi.
-
-## Modello a fontana
-
-{% responsive_image path: 'assets/02_fountain-model.png' %}
-
-Nel 1993 nasce, in contrapposizione al modello a cascata, il cosiddetto __modello a fontana__, che amplia il concetto di iterazione permettendo in qualunque momento di __tornare alla fase iniziale__: se ci si accorge della presenza di errori si torna indietro all'inizio (_software pool_) e si ricontrollano tutte le fasi precedenti. Ovviamente questo non implica buttare tutto il lavoro già fatto, quanto piuttosto risolvere l'errore con un approccio che parta innanzitutto dalla modifica dei requisiti (se possibile), delle specifiche e solo dopo del codice, evitando di rattoppare solo quest'ultimo alla bell'e meglio come nel modello _code-and-fix_.
-
-Il modello a fontana è inoltre il primo in cui sono previste delle azioni dopo la consegna; dopo l'ultima fase (_programma in uso_), infatti, si aprono ancora due strade: __manutenzione ed evoluzione__. La consegna del prodotto non è quindi più l'atto finale, ma solo un altro step del processo: ecco quindi che si aprono le porte ad una __visione incrementale__ dello sviluppo software, che approfondiremo nel prossimo paragrafo.
-
-Anche qui si perdono purtroppo le garanzie sui tempi di sviluppo: una volta ritornato all'inizio per sistemare un errore non è infatti affatto detto che riuscirò a ritornare alla fase da cui sono partito, ma potrei imbattermi in altri errori durante le fasi precedenti costringendomi a iterare su di esse più di una volta.
-
-# Modelli incrementali
-
-Un modello incrementale è un particolare modello iterativo in cui nelle iterazioni è inclusa anche la consegna: questo permette di sviluppare il software a poco a poco, rilasciandone di volta in volta parti e componenti che costruiscano _incrementalmente_ il programma finito.
-
-Si noti la differenza tra incrementale e iterativo; si può parlare infatti di:
-
-- __implementazione iterativa__: dopo aver raccolto le specifiche e aver progettato il sistema, _iterativamente_ sviluppo i componenti, li integro nel prodotto finale, quindi consegno.
-- __sviluppo incrementale__: l'iteratività interessa tutte le fasi, comprese quelle di specifiche e realizzazione.  
-
-Lo sviluppo incrementale riconosce la criticità della variabilità delle richieste e la integra nel processo. 
-La manutenzione non è quindi più una particolarità ma è vista come normale e perfettamente integrata nel modello: in tal senso, la richiesta di una nuova feature o la correzione di un errore generano gli stessi step di sviluppo.
-
-## Modello prototipale
-
-Un particolare modello incrementale è quello protitipale: in questo modello viene introdotto il concetto di __protitipi usa e getta__ (_throw away_), interi programmi che vengono costruiti e poi vengono buttati via.
-
-Lo scopo del prototipo __non è consegnare__ un prodotto finito, ma __ricevere feedback__ dal cliente per essere sicuri di aver compreso a pieno i suoi requisiti, oppure testare internamente un'idea o uno strumento. Per questo motivo tali prototipi vengono costruiti fregandosene di correttezza, pulizia del codice, leggibilità eccetera.
-I protitipi possono dunque essere:
-
-- __pubblici__: per capire meglio i requisiti del cliente (vd. <a href="#b3">L3</a>);
-- __privati__: per esplorare nuovi strumenti, linguaggi, scelte per problemi difficili; inoltre, molto spesso una volta programmata una soluzione si capisce anche meglio il problema (_"do it twice"_).
-
-La tentazione coi prototipi pubblici può essere quella di consegnarli come prodotto finito, ma c'è il __rischio__ enorme di dover mantenere poi in futuro software non mantenibile, illeggibile e con altissimo debito tecnico.
-
-<a id="b3"></a>
-__Legge di Bohem (L3)__
-> La propotipizzazione riduce gli errori di analisi dei requisiti e di design, specialmente per le interfacce utente.
-
-## I problemi dei modelli incrementali
-
-Come già detto nessun modello è perfetto, e anche i modelli incrementali soffrono di alcuni problemi.
-
-Viene innanzitutto __complicato il lavoro di planning__: bisogna pianificare tutte le iterazioni e lo stato di avanzamento è meno visibile; inoltre, la ripetizione di alcune fasi richiede di avere sempre sul posto gli esperti in grado di eseguirle.
-Ad ogni iterazione, poi, dobbiamo rimettere mano a ciò che è stato fatto, in un processo che potrebbe non convergere mai a una versione finale.
-
-Ma cosa è un'iterazione, e quanto dura? Tagliare verticalmente sulle funzionalità non è infatti facile, soprattutto considerando che quando si consegna il prodotto esso dev'essere funzionante con tutti i layer necessari ed essere al contempo pensato per poter crescere con successivi attaccamenti. Ci sono dunque diversi rischi:
-
-- voler aggiungere troppe funzionalità nella prima iterazione;
-- overhead dovuto a troppe iterazioni;
-- avere un eccessivo overlapping tra le iterazioni: non si ha tempo di recepire il feedback dell'utente (es. Microsoft Office 2020 e 2019 vengono sviluppati contemporaneamente).
-
-### Pinball Life-Cycle
-
-{% responsive_image path: 'assets/02_pinball-life-cycle.png' %}
-
-Il _"modello meme"_ del Pinball Life-Cycle, creato da Ambler come critica ai modelli incrementali, estremizza queste problematiche: l'ordine in cui faccio le attività è casuale, incoltrollabile. Qualunque passo è possibile dopo qualunque altro, e non si possono imporre vincoli temporal: il processo è __non misurabile__.
-
-Si tratta ovviamente di una visione eccessivamente pessimistica, ma spesso nelle aziende non specializzate l'iter di sviluppo assomiglia effettivamente a questo.
-
-## Modelli trasformazionali
-
-{% responsive_image path: 'assets/02_transformational-models.png' %}
-
-Diametralmente opposti all'incubo del Pinball Life-Cycle troviamo i __modelli trasformazionali__: tali modelli pretendono infatti di controllare tutti i passi e i procedimenti in __modo formale__.
-
-Partendo dai requisiti scritti in linguaggio informale, tali modelli procedono tramite una sequenza di __passi di trasformazione__ dimostrabili tutti formalmente fino ad arrivare alla versione finale.
-Essi si basano infatti sull'idea che se le specifiche sono corrette e i passi di trasformazione sono dimostrati allora ottengo un programma corretto, ovvero di sicuro aderente alle specifiche di cui sopra. Inoltre, la presenza di una storia delle trasformazioni applicate permette un rudimentale versioning, con la possibilità di tornare indietro a uno stato precedente del progetto semplicemente annullando le ultime trasformazioni fatte.
-
-{% responsive_image path: 'assets/02_formal-transformations.jpg' %}
-
-Ad ogni passo si ottiene quindi un __protitipo__ che differisce dal prodotto finale per efficienza e completezza, ma che è possibile trasformare in un altro più efficiente e corretto. Non si tratta tuttavia di un processo totalmente automatico, anzi: ad ogni passo di "ottimizzazione", ovvero applicazione di una trasformazione, è richiesto l'intervento di un decisore umano che scelga che cosa ottimizzare.
-
-Viene quindi introdotto il concetto di __prova formale di correttezza__ delle trasformazioni applicate; per via di questo approccio molto matematico questo tipo di modelli è nella realtà applicato quasi solo negli ambienti di ricerca e produzione hardware.
-
-## <i>Meta</i>modello a spirale
-
-{% responsive_image path: 'assets/02_spiral-model.png' %}
-
-Introduciamo ora un metamodello, ovvero un modello che ci permette di rappresentare e discutere di altri modelli (una sorta di framework).
-
-Nel metamodello a spirale l'attenzione è posto sui __rischi__, ovvero sulla possibilità che qualcosa vada male (decisamente probabile nell'ambiente di sviluppo software).
-Per questo motivo il modello è di tipo incrementale e pone l'accento sul fatto che non abbia senso fare lo studio di fattibilità una sola volta, ma ad ogni iterazione serva una decisione. Le fasi generali sono dunque:
-
-- Determinazione di obiettivi, alternative e vincoli
-- Valutazione alternative, identificazione rischi (decido se ha senso andare avanti)
-- Sviluppo e verifica
-- Pianificazione della prossima iterazione
-
-Nella figura il raggio della spirale indica i __costi__, che ad ogni iterazione aumentano fisiologicamente.
-
-### Variante _"win-win"_
-
-Esiste una variante al modello a spirale che fa notare come i rischi ad ogni fase non sono solo rischi tecnologici ma anche __contrattuali__ con il cliente. Ad ogni iterazione bisogna dunque trovare con esso un punto di equilibrio _win-win_ in entrambi le parti "vincono" (o hanno l'illusione di aver vinto), così da far convergere tutti su un obiettivo comune.
-
-## Modello COTS (Component Off The Shelf)
-
-{% responsive_image path: 'assets/02_cots.png' %}
-
-Vediamo infine un modello che si concentra molto sulla __riusabilità__: si parte dalla disponibilità interna o sul mercato di moduli preesistenti sui quali basare il sistema, e che è dunque necessario solo integrare tra di loro.
-
-Non si creda che si tratti di un approccio facile: questo modello di design necessita di far dialogare componenti che non necessariamente comunicano già nel modo voluto.
-
-Si tratta tuttavia di un modello di sviluppo diverso perché richiede attività diverse. In particolare:
-
-- _Analisi dei requisiti_
-- ___Analisi dei componenti___: prima di progettare considero la disponibilità di componenti che implementano una parte o tutte le funzionalità richieste;
-- ___Modifica dei requisiti___: stabilisco se il cliente è disposto ad accettare un cambiamento nei requisiti necessario per utilizzare un componente particolare;
-- ___Progetto del sistema col riuso di componenti___: occorre progettare il sistema per far interagire componenti che non necessariamente sono stati originariamente progettati per interagire;
-- _Sviluppo e integrazione_;
-- _Verifica del sistema_.
-
-# Metodologie Agili
-
-Finora i modelli visti erano di tipo prettamente descrittivo; vediamo ora dei modelli più prescrittivi, che dicano cioè che cosa fare effettivamente durante lo sviluppo.
-
-Le metodologie agili _"nascono dal basso"_, ovvero solitamente da chi sviluppa, per colmare un disagio prevalente nell'usare i metodi tradizionali. Per tale motivo, di tali metodologie esiste un...
-
-## [Manifesto](https://agilemanifesto.org/iso/it/manifesto.html)
-
-Nelle parole di Fowler e i suoi collaboratori, per migliorare il modo in cui sviluppiamo il software dobbiamo dare più importanza ad alcuni valori rispetto agli altri:
-
-- Gli __individui__ e la __collaborazione tra individui__ è più importante di processi e strumenti.
-- Il __software che funziona__ è più importante della documentazione ben fatta.
-- La __collaborazione con il cliente__ è più importante del contratto.
-- __Rispondere al cambiamento__ è più importante che seguire un piano.
-
-> LIBRO: __Agile!__ di Bertrand Meyer
-
-Come si vede, si tratta di un drastico cambio di rotta rispetto allo sviluppo tradizionale, che si evolve anche in un business model diverso: piuttosto che farsi pagare a programma finito, adesso gli sviluppatori vogliono farsi pagare a tempo di sviluppo, dando però la garanzia al cliente di lavorare durante tale periodo esclusivamente per lui e al massimo delle proprie capacità. Al rapporto confluttuale con il cliente, in cui ciascuno cerca di fregare l'altro, si sostituisce dunque una collaborazione più estesa in cui, come vedremo, anche il cliente diventa parte del team di sviluppo.
-
-Vediamo dunque adesso alcune delle più famose metodologie agili, mettendone in evidenza gli aspetti peculiari.
-
-## Lean Software
-
-Nato dal progetto di _Lean Manufactioring_ della Toyota, ha l'obiettivo di __ridurre gli sprechi__, ovvero quei prodotti e sottoprodotti che non vengono consegnati al cliente  (es. testing, prototipi...) e dunque non generano valore: essi possono essere ignorati.
-
-Un'altra idea interessante è quella di posticipare il più possibile le scelte vincolanti per aiutare a risparmiare risorse: più possibilità mi lascio aperte, più mi sarà facile adattarmi (a patto però che l'adattamento sia veloce).
-
-## Kanban
-
-{% responsive_image path: 'assets/02_kanban.jpg' %}
-
-L'obiettivo è qui invece di __minimizzare il lavoro in corso__ (work in progress), ovvero concentrarsi in ogni momento su una sola cosa in modo da evitare i continui _context switch_ che costituiscono una perdita di tempo.
-Le attività possono per esempio essere organizzate in una tabella con 5 colonne:
-
-- __backlog__: richieste dal cliente
-- __da fare__: attività da fare in questa iterazione
-- __in esecuzione__
-- __in testing__
-- __fatto__
-
-La tabella dà a colpo d'occhio informazioni sullo stato del progetto per tutti. Ogni __card__ (storia) è assegnata a uno sviluppatore (o coppia nel _pair programming_), in modo che nella colonna in esecuzione vi sia una sola card per sviluppatore (o coppia); qualora il lavoro di un altro blocchi il mio lavoro in qualche modo è poi mia responsabilità aiutarlo per rimuovere il blocco.
-
-## _Scrum_
-
-L'obiettivo è __fissare i requisiti__ durante le iterazioni (__brevi__, da 2 a 4 settimane), in modo da permettere agli sviluppatori di lavorare in pace senza doversi adattare continuamente a nuove richieste. Solo al termine di ogni iterazione, infatti, si permette al cliente di rimettere in discussione i requisiti.
-
-## Crystal
-
-Sebbene non sia molto apprezzata o usata, questa tecnica introduce l'interessante concetto di __comunicazione osmotica__. Nel modello a cascata la comunicazione è fatta tramite documenti rigidi, ed è settorializzata; in Crystal la conoscenza viene condivisa nel team tramite _"osmosi"_, in modo che tutti sappiano un po' di tutto.
-
-Questo rende il processo più robusto, perché l'assenza di una persona esperta in un campo non è più in grado di bloccare completamente i lavori. Il pair programming è in quest'ottica: tra i due componenti la conoscenza è condivisa; Crystal estende questo concetto all'intero team.
-
-Si capisce però facilmente che questa tecnica funziona solo con team piccoli (max 8-10 persone), sebbene altre metodologie agili (_SAFE_) tentino di scalarla anche a team più massicci.  
-
-## eXtreme Programming (XP)
-
-Si tratta di una tecnica a cui dedicheremo una trattazione più approfondita nella prossima lezione. Per il momento accontentiamoci di enunciarne i due motti:
-
-- __incrementa quindi semplifica__;
-- __sviluppo guidato dal test__ (_test-first_: prima testa poi sviluppa).
\ No newline at end of file