Lezione 2 · Canale 2 · lunedì 28 settembre 2026

Ciclo di vita e qualità del software

Progettazione del Software

Riassunto

Il software ha un ciclo di vita che comprende studio di fattibilità, raccolta dei requisiti, analisi, progetto e realizzazione, verifica e manutenzione. Gran parte dei costi e del lavoro riguarda la manutenzione di sistemi esistenti, spesso legacy: per questo modularità, documentazione e manutenibilità sono essenziali. La verifica valuta correttezza, completezza ed efficienza. Il software deve inoltre soddisfare qualità esterne, percepibili dagli utenti, e interne, valutabili da specialisti. Alcune qualità possono entrare in conflitto. Le qualità non sono sempre misurabili direttamente e vengono valutate tramite indicatori. Gli approcci modulari e orientati agli oggetti aiutano a sostenere l'evoluzione dei sistemi nel tempo.

Concetti chiave

  • SDLC (Software Development Life Cycle) — ciclo di sviluppo del software, cioè il processo seguito per ideare, sviluppare, verificare e mantenere un sistema.
  • Utente finale — persona che utilizza effettivamente il sistema, per esempio un operatore dell'organizzazione committente o un suo cliente.
  • User experience (UX) — esperienza d'uso del sistema, legata, tra l'altro, alla semplicità e alla gradevolezza dell'interazione.
  • Manutenzione software — attività svolte dopo l'entrata in produzione per correggere errori, adeguare il sistema o ampliarne le funzionalità.
  • Legacy system — sistema esistente e spesso datato, che continua a svolgere funzioni importanti e richiede interventi per essere mantenuto o integrato con tecnologie più recenti.
  • Manutenzione correttiva — intervento che corregge un bug del sistema.
  • Manutenzione adeguativa — intervento che adatta il sistema a cambiamenti normativi, tecnologici o infrastrutturali senza modificarne le funzionalità previste.
  • Manutenzione evolutiva (MEV) — intervento che modifica o amplia le funzionalità del sistema in risposta a requisiti nuovi o cambiati.
  • Transazione — operazione sui dati che richiede una semantica corretta, per esempio il collegamento tra il pagamento di un biglietto e la registrazione della prenotazione.
  • Studio di fattibilità — fase che valuta costi e benefici dell'iniziativa e pianifica ad alto livello risorse e attività.
  • Requisito — descrizione di ciò che il sistema deve fare nel contesto reale; la raccolta può avvenire con interviste, focus group, studi longitudinali e osservazione degli utenti.
  • Analisi dei requisiti — attività volta a comprendere a fondo il problema descritto dai requisiti e le informazioni che il sistema dovrà trattare.
  • Schema concettuale — rappresentazione astratta dei concetti e degli oggetti informativi del sistema, senza entrare nei dettagli della loro implementazione.
  • UML (Unified Modeling Language) — linguaggio indicato come standard de facto per rappresentare schemi concettuali.
  • Verifica — attività che valuta se il sistema è corretto, completo rispetto ai requisiti ed efficiente.
  • Qualità esterne — proprietà percepibili dagli utenti senza conoscenze tecniche specifiche, come l'usabilità.
  • Qualità interne — proprietà valutabili soprattutto da specialisti che conoscono la struttura del programma, come modularità e mantenibilità.
  • Robustezza — capacità del sistema di reagire a usi o input non previsti senza perdere del tutto la funzionalità o produrre risultati gravemente errati.
  • Interoperabilità — capacità di scambiare e usare dati con altri sistemi, favorita dall'adozione di formati e standard condivisi.
  • Modularità — organizzazione del sistema in parti riconoscibili, con responsabilità coerenti, che possono essere comprese e modificate con interventi circoscritti.
  • Portabilità — capacità del software di funzionare su piattaforme diverse da quella per cui è stato progettato.
  • Indicatore di qualità — misura osservabile usata per valutare indirettamente una proprietà che non è misurabile in modo diretto.
  • Scala Likert — scala di risposta, per esempio da 1 a 5 o da 1 a 10, usata nei questionari per rilevare il grado di soddisfazione.

Sviluppo

Utente finale e SDLC

L'utente finale è chi usa effettivamente il sistema. Può essere un operatore dell'organizzazione che ha commissionato il software oppure un cliente che utilizza il servizio. Nel caso di un sistema bancario, sono utenti finali sia gli operatori allo sportello sia le persone che effettuano operazioni bancarie.

Committente e utente finale spesso non coincidono: una grande organizzazione può commissionare il sistema, mentre lo usano i suoi clienti e i suoi dipendenti. Ne deriva una possibile distanza tra gli obiettivi strategici di chi finanzia il software e le necessità quotidiane degli operatori. Il sistema può soddisfare gli obiettivi aziendali di alto livello ma risultare poco agevole per chi lo usa.

User experience e vincoli di budget

La progettazione che considera gli utenti mira a migliorare la UX: il sistema dovrebbe essere gradevole, semplice e immediato da usare. Migliorare l'interfaccia e l'ergonomia richiede effort e quindi risorse economiche. Il committente deve bilanciare il budget con le esigenze degli utenti: le caratteristiche desiderabili non sono sempre finanziabili.

Manutenzione e sistemi legacy

I manutentori gestiscono il sistema dopo che è entrato in produzione: correggono errori, introducono miglioramenti e adeguano il software a nuove condizioni.

Come stima generale, la fase iniziale di sviluppo può rappresentare al massimo circa il 10% del tempo e dei costi complessivi di un sistema, mentre la manutenzione ne rappresenta circa il 90%. Di conseguenza, molti professionisti lavoreranno su sistemi esistenti, non su sistemi costruiti da zero. Rendere moderno un sistema vecchio e mantenerlo funzionante può essere un'attività complessa e stimolante.

I sistemi software esistenti e datati vengono spesso chiamati legacy system. La loro longevità dipende anche dal fatto che svolgono funzioni importanti e che sostituirli comporta rischi.

Vincoli dei sistemi legacy: l'esempio dei codici aeroportuali

I codici degli aeroporti forniscono un esempio di come i vincoli storici dei sistemi legacy influenzino le decisioni ancora oggi. Perché per cercare un volo si usa il codice FCO invece di scrivere semplicemente Fiumicino? Una parte dei sistemi che gestiscono le prenotazioni aeree risale alla fine degli anni Sessanta e ai primi anni Settanta, quando si lavorava su mainframe con memoria limitata. Usando l'alfabeto inglese di 26 lettere, tre caratteri permettevano di rappresentare 263=1757626^3 = 17576 codici.

La prenotazione deve poter funzionare tra venditori e compagnie diverse: per questo il ruolo della IATA nel coordinare la condivisione delle destinazioni e degli standard è importante. Anche dopo la diffusione di Internet e delle prenotazioni online, il sistema sottostante non è stato necessariamente riscritto.

I sistemi longevi vengono corretti tramite patch man mano che emergono bug. Non si può dimostrare semplicemente che non contengano alcun errore, però la probabilità che restino errori non scoperti può diminuire nel tempo. Il software può diventare meno moderno nell'interfaccia, ma gli errori più frequenti possono essere stati individuati e corretti nel tempo.

Sistemi core, transazioni e wrapper

Le organizzazioni esitano a riscrivere un sistema che gestisce correttamente i dati e le transazioni, cioè le operazioni per cui la relazione tra le azioni deve essere garantita. L'esempio è l'acquisto di un biglietto aereo: al pagamento deve corrispondere una prenotazione registrata.

I portali moderni possono offrire un'interfaccia più gradevole e aggiungere funzionalità, pur appoggiandosi a sistemi core più vecchi, anche scritti in COBOL. Quando una persona seleziona l'aeroporto da un menu, l'interfaccia può trasformare la scelta in una chiamata comprensibile al sistema sottostante. Questo rapporto è paragonabile a un sistema legacy avvolto da strati (wrapper) che lo rendono accessibile da web, app o call center.

I manutentori contribuiscono a modernizzare l'accesso al core e a cambiarne le parti circostanti senza compromettere le operazioni fondamentali.

Manutenibilità e responsabilità

Poiché la manutenzione occupa una parte così ampia della vita del software, modularità e manutenibilità sono principi centrali della progettazione. Anche chi rilegge il proprio codice dopo qualche tempo si trova nella posizione di un manutentore, e lo stesso problema è maggiore per chi entra in azienda molti anni dopo. Nomi poco chiari e assenza di documentazione rendono difficile ricostruire la funzione di una parte del programma.

Il software va quindi prodotto pensando a una catena di lavoro in cui le persone cambiano, mentre il sistema resta in uso. Documentazione e chiarezza del codice aiutano chi dovrà continuare a lavorarci.

Tipi di manutenzione

La manutenzione correttiva interviene quando si verifica un bug, per esempio la schermata blu che può comparire su uno schermo in aeroporto.

La manutenzione adeguativa serve quando cambiano condizioni legali, tecnologiche o infrastrutturali, ma non le funzionalità del sistema. Per esempio, un programma realizzato per Java 1.8 potrebbe dover essere adeguato a una versione successiva, e un sistema progettato per il vecchio ordinamento universitario ha dovuto essere adeguato al passaggio alle lauree 3+2.

La manutenzione evolutiva (MEV) modifica o amplia le funzionalità: per esempio, aggiungere a un sistema web la possibilità di essere usato tramite app mobile. Molti domini applicativi sono già informatizzati, quindi è frequente lavorare sull'evoluzione di sistemi preesistenti.

Ruoli professionali e settori applicativi

Nel settore si può lavorare come manutentore, analista, progettista o programmatore; queste figure tendono a fondersi. Si può anche diventare esperti del dominio in cui si lavora, come banche, agricoltura o assicurazioni, imparando il settore nel tempo. Il software è presente in molti settori: intrattenimento (videogiochi, piattaforme di streaming), bancario, assicurativo, dei trasporti.

Un esempio di evoluzione nei videogiochi riguarda i personaggi controllati dal computer (non-player character, NPC). Se sono scripted, un algoritmo deterministico ne stabilisce il comportamento e il giocatore, dopo averne imparato lo schema, può anticiparli. Piccole reti neurali possono invece far apprendere agli NPC come gioca l'utente; il modello dovrebbe girare localmente sulla console, con risorse di calcolo limitate, anziché nel cloud.

Studio di fattibilità e raccolta dei requisiti

Il ciclo di vita comincia con lo studio di fattibilità e l'analisi dei requisiti. Lo studio valuta i costi e i benefici dell'idea del committente: sbagliare la stima può mettere a rischio l'azienda. Prima di scrivere codice si pianificano ad alto livello risorse, attività e tempi. Un nuovo prodotto può anche essere un'evoluzione, come l'app mobile di una banca che continua a usare un sistema legacy.

La valutazione considera inoltre vincoli relativi ad ambiente di programmazione, hardware e software. Per raccogliere requisiti si possono intervistare potenziali utenti ed esperti di dominio. Una versione alpha gratuita può permettere al vendor di osservare l'uso e ricevere segnalazioni su errori o funzionalità desiderate. Si possono inoltre impiegare focus group, interviste strutturate e studi longitudinali, che osservano come una persona svolge le proprie attività quotidiane.

Il risultato atteso è una specifica, anche in linguaggio naturale, che descriva cosa deve fare l'applicazione nel mondo reale.

Analisi dei requisiti e schema concettuale

Analizzare significa comprendere a fondo il problema rappresentato dai requisiti e individuare gli oggetti informativi di cui il sistema deve parlare. Per esempio, un sistema bancario deve rappresentare informazioni relative a banche e conti correnti.

Lo schema concettuale descrive i concetti senza specificare tutti i dettagli di rappresentazione. Per esempio, per una data di nascita ci si concentra sul concetto di data, senza decidere ancora se memorizzarla come giorno, mese e anno o in un altro formato. UML viene presentato come standard de facto per rappresentare questi schemi.

Progetto, realizzazione e documentazione

Dopo l'analisi si progetta come il sistema realizzerà le proprie funzioni. Ciò include la definizione delle classi e delle loro segnature, il modo di rappresentare digitalmente i concetti e la scelta delle strutture dati. Segue la scrittura del codice.

La documentazione è parte del prodotto: permette ad altri di capire come funziona il programma e di svolgere la manutenzione. Non è sufficiente consegnare codice che funziona se nessuno riesce a comprenderlo o a modificarlo.

Scelte di rappresentazione: il millennium bug

Una scelta di rappresentazione può produrre costi molti anni dopo. Nei sistemi degli anni Settanta, per risparmiare spazio, una data poteva essere memorizzata con sei cifre: due per il giorno, due per il mese e due per l'anno. Non era stato considerato cosa sarebbe accaduto quando l'anno fosse passato da 99 a 00.

Il valore 00 poteva essere interpretato come 1900 oppure come 2000. Per le banche, per esempio, un'interpretazione errata poteva incidere sui calcoli degli interessi. Negli anni Novanta furono necessari interventi di manutenzione adeguativa su larga scala per affrontare questo problema, tra i maggiori investimenti mondiali in manutenzione del software; il disastro temuto non si verificò su scala generale. Questo episodio mostra come le decisioni progettuali, anche apparentemente minori, possono avere conseguenze significative nel lungo termine. Anche la confusione fra unità di misura metriche e anglosassoni ha causato incidenti gravi: il Mars Climate Orbiter (1999, sonda senza equipaggio) andò perso perché dati di impulso in libbre-forza per secondo furono letti come newton per secondo.

Verifica del sistema

Dopo analisi, progetto e codifica, il sistema deve essere verificato. La verifica considera tre aspetti: correttezza, completezza rispetto ai requisiti ed efficienza, cioè capacità di svolgere il compito in tempi ragionevoli.

La responsabilità per il software resta di chi lo sviluppa, anche quando parte della codifica è affidata ad agenti software o chatbot. Per questo la verifica diventa importante: bisogna controllare che il sistema prodotto soddisfi davvero il compito e i requisiti.

Una ripartizione indicativa delle risorse nel ciclo di sviluppo è: studio di fattibilità circa il 10%; studio e analisi dei requisiti insieme circa il 25%; progetto e realizzazione circa un altro 25%; verifica almeno il 50%, e in alcuni casi fino al 60%. Nei sistemi mission-critical, come quelli che controllano impianti, treni, centrali nucleari o semafori, la verifica può durare a lungo e assorbire una quota molto alta del progetto.

Non si dimostra facilmente che un sistema sia privo di errori: lo si sottopone a test ripetuti per aumentare la confidenza che eventuali errori residui siano rari. Le versioni beta sono sistemi non ancora verificati completamente, distribuiti anche per raccogliere segnalazioni e ampliare i test con l'uso degli utenti: usarle significa contribuire alla verifica di un prodotto non ancora garantito come versione definitiva.

Ciclo di manutenzione evolutiva

Una manutenzione evolutiva può diventare un nuovo progetto: occorre raccogliere e analizzare i requisiti dell'intervento, progettarlo, realizzarlo e verificarlo. Per questo il ciclo è descritto come una spirale: dopo una versione il sistema può ripartire dall'analisi per rispondere a nuove esigenze, poi passare a progetto, realizzazione e verifica.

Qualità esterne e interne

Le qualità esterne sono percepibili anche da chi non conosce la struttura del programma. Tra di esse si trovano l'aspetto, l'usabilità e la fluidità dell'interazione.

Le qualità interne riguardano il sistema dal punto di vista di chi lo sviluppa e richiedono spesso di conoscerne la struttura. La distinzione non è sempre netta: per esempio, le prestazioni interne possono influire sull'esperienza percepita dagli utenti.

Correttezza, affidabilità e robustezza

La correttezza significa che il sistema produce risultati coerenti con il dominio. Una app che restituisce un risultato errato (per esempio 5 per il calcolo 2+22+2) non è corretta.

L'affidabilità riguarda la possibilità di usare il sistema per la maggior parte del tempo senza interruzioni o crash. Anche un programma usato per una prova pratica deve essere affidabile: se si blocca durante la correzione, non svolge il suo compito.

Un sistema è robusto se reagisce in modo adeguato anche quando riceve input ai limiti o fuori dalle condizioni previste. Per esempio, inserire il 29 febbraio in un anno non bisestile non dovrebbe far crollare il programma: il sistema può segnalare l'input non valido e mantenere un comportamento controllato.

Sicurezza e innocuità

La sicurezza informatica riguarda la protezione del sistema da violazioni e accessi non autorizzati. È una proprietà fondamentale dei sistemi reali.

L'innocuità (safety) è la proprietà per cui il sistema non deve causare danni fisici agli utenti. Un sistema, soprattutto quando interagisce con dispositivi fisici, non deve mettere in pericolo le persone.

Usabilità e interoperabilità

L'usabilità riguarda la facilità con cui le persone riescono a usare il sistema ed è collegata a un'esperienza semplice e gradevole.

L'interoperabilità riguarda la possibilità di usare dati e file anche con sistemi di altri vendor. Formati standard condivisi rendono più agevole aprire e scambiare documenti tra programmi diversi. La standardizzazione è importante in un contesto globale in cui le persone usano dispositivi e prodotti di fornitori diversi.

Proprietà interne: estendibilità, modularità e portabilità

Tra le proprietà interne, l'estendibilità indica che sia possibile aggiungere funzionalità nel tempo. La riusabilità permette di usare parti del software anche in altri programmi.

L'efficienza riguarda l'uso ottimizzato delle risorse, come memoria, CPU e spazio su disco. La strutturazione rende riconoscibili i moduli e i componenti dell'architettura. La modularità consiste nell'individuare parti con responsabilità coerenti e coese, così da poter intervenire su una componente senza dover modificare l'intero sistema.

La modularità software è analoga a quella dell'hardware: se un prodotto è diviso in moduli, una parte guasta può essere sostituita. Comprensibilità e documentazione facilitano la manutenzione: commenti e spiegazioni degli algoritmi aiutano a capire il codice. La verificabilità indica che il sistema può essere sottoposto a verifica; la mantenibilità deriva anche da queste proprietà.

La portabilità è la capacità di funzionare su piattaforme diverse. Python, linguaggio interpretato, può essere usato su sistemi differenti, in contrasto con programmi C che richiedono la compilazione per la piattaforma di destinazione.

Orientamento agli oggetti

L'orientamento agli oggetti viene presentato come un approccio che favorisce le qualità interne del software, incluse modularità e riuso. Dagli anni Dieci è diventato comune usare approcci orientati agli oggetti anche in linguaggi diversi.

Migliorare le qualità interne può lasciare più tempo e budget per curare anche quelle esterne. La progettazione cerca quindi metodi che rendano il sistema più facile da sviluppare e mantenere e che abbiano ricadute positive sull'esperienza d'uso.

Misurazione della qualità

La qualità non è sempre misurabile direttamente. Si definiscono proprietà e indicatori numerici che consentono di valutarla in modo più oggettivo. Per esempio, l'usabilità può essere valutata con questionari di soddisfazione e scale Likert; un contratto può stabilire una soglia di risposte positive per determinare il pagamento di un bonus.

Altri indicatori possono riguardare il tempo di risposta, ricavato dai log. L'usabilità complessiva può dipendere da più misure, come soddisfazione e rapidità di transizione tra pagine. Le qualità sono quindi concetti multidimensionali: ciascun indicatore ne misura indirettamente un aspetto e nessun indicatore fornisce da solo una misura completa.

Conflitti tra qualità

Alcune qualità possono entrare in conflitto. Per esempio, introdurre l'autenticazione a due fattori può aumentare la sicurezza ma rendere più scomodo l'accesso. Anche portabilità ed efficienza possono comportare compromessi: la portabilità di un linguaggio interpretato può andare a scapito dell'efficienza rispetto al codice compilato per una piattaforma specifica.

Sfide dello sviluppo e conclusione

Le informazioni da gestire, la dimensione dei progetti e l'eterogeneità degli utenti sono in crescita; anche la durata dei sistemi e i costi di produzione aumentano, mentre si richiedono prodotti di qualità sempre maggiore.

Gli approcci modulari, in particolare le tecnologie orientate agli oggetti, rappresentano una risposta a queste sfide.

Formule e dimostrazioni

Non sono svolte dimostrazioni formali; valgono le seguenti relazioni quantitative.

  • Codici aeroportuali con tre caratteri — 263=1757626^3 = 17576 dove 26 è il numero di lettere dell'alfabeto considerato e 3 il numero di caratteri usati per ciascun codice.

  • Quota indicativa di sviluppo e manutenzione — Dsviluppo≤0,10Dtotale,Dmanutenzione≈0,90DtotaleD_{\text{sviluppo}} \leq 0{,}10D_{\text{totale}}, \qquad D_{\text{manutenzione}} \approx 0{,}90D_{\text{totale}} dove DD indica tempo o costo complessivo del sistema. Queste proporzioni sono valori tipici e approssimativi.

  • Ripartizione indicativa delle fasi iniziali — F≈10%,F+A≈25%,P≈25%,V≥50%F \approx 10\%, \qquad F+A \approx 25\%, \qquad P \approx 25\%, \qquad V \geq 50\% dove FF è lo studio di fattibilità, AA l'analisi dei requisiti, PP il progetto e la realizzazione, e VV la verifica. La prima percentuale è riferita al solo studio di fattibilità; il 25% successivo è cumulativo per studio e analisi.

  • Rappresentazione a sei cifre della data — GGMMYY=2+2+2=6 cifre\text{GGMMYY} = 2+2+2 = 6\text{ cifre} dove GG rappresenta il giorno, MM il mese e YY le ultime due cifre dell'anno.

  • Scale Likert citate — x∈{1,2,3,4,5}oppurex∈{1,2,…,10}x \in \{1, 2, 3, 4, 5\} \qquad \text{oppure} \qquad x \in \{1, 2, \ldots, 10\} dove xx è la risposta numerica di un utente al questionario.