Il colore del capanno delle bici
Si sa che quando vogliamo costruire una casa ci affidiamo ad architetti e ingegneri, non agli arredatori di interni. Per lo stesso motivo quando vogliamo costruire un software ci rivolgiamo a ingegneri informatici e programmatori, non a manager e analisti di dubbia competenza. Purtroppo nella maggioranza dei casi succede proprio che chi dovrebbe e saprebbe progettare finisce a seguire i capricci di chi guadagna tre volte più di lui e di ingegneria del software e programmazione sa meno di mia nonna. Purtroppo chi guadagna tre volte più di lui però ha anche la mano sul rubinetto dei soldi e quindi o si fa come dice lui o si fa la fame, con buona pace della Qualità.
Quando si progetta un software di una certa dimensione ci sono dei passi da seguire e delle regole che tutti gli ingegneri e i programmatori conoscono e sanno applicare cum grano salis. Per esempio, a seconda della dimensione del progetto e dall’esperienza delle persone coinvolte, la parte di progettazione può essere più o meno approfondita, coprire alcune parti in grande dettaglio e tratteggiarne appena altre perché tanto sappiamo già come sono fatte–o perché le prendiamo già fatte da qualche parte. Un altro adagio spesso ripetuto come un mantra dai programmatori è che “il codice è abbastanza autoesplicativo”, ma poi tutti sanno che documentarne le parti critiche è fondamentale per riaprire il codice un mese dopo e sapercisi raccapezzare, ma documentare pedissequamente ogni riga di codice è spesso perfettamente inutile. Infine la parte più importante di tutte, specialmente durante la fase di progettazione, ma anche durante la realizzazione, è comunicare con i collaboratori. Chiaro, se poi c’è un solo individuo che sviluppa la cosa, questo fatto può spaziare da difficile a patologico, ma mettere le idee su carta–o su lavagna–aiuta tutti.
Diagrammi strutturali
Ad un certo punto nella storia dell’ingegneria del software le persone hanno inizato a rappresentare i concetti in disegnini sempre più standardizzati, anche se ognuno si faceva il proprio standard, ma a quel punto la cosa non era molto importante se tutti nel gruppo di lavoro riuscivano a capirsi. L’industria ha visto con favore queste pratiche e, come ogni industria che si rispetti, ha cercato di formalizzarle e standardizzarle. Senza fare la storia del mondo, la prima formulazione di UML era nata. Trattavasi di un linguaggio visuale per modellare sistemi informatici usando un’astrazione che cominciava ad andare di gran moda in quel periodo, la programmazione ad oggetti, e tutti erano abbastanza contenti della cosa.
Purtroppo l’industria, come ogni industria che si rispetti, non ha un solo capo onniscente e saggio, ma ha collegi di capi da mediamente a drammaticamente incompetenti. In virtù del fatto che più o meno tutti sanno tenere in mano una matita e disegnare un rettangolo, ognuno ha voluto dire la sua in proporzione alla propria incompetenza. Alle orecchie più sveglie questo avrà già fatto suonare l’allarme “design by committee“. Una massima famosa recita che “un cammello è un cavallo progettato da una commissione“, che signfica che raramente una commissione, dovendo per forza mediare le varie incompetenze che la compongono, produce risultati migliori che mediocri–senza nulla togliere ai cammelli che sono dei nobili e utili animali ma che con l’eleganza del cavallo c’entrano poco.
Ma torniamo a UML. Quello lì nella figura sopra è quello che si chiama “diagramma delle classi” e ci dice che la classe Gatto eredita dalla classe Animale, cioè un gatto è un animale. Big surprise. I diagrammi delle classi possono essere un po’ più complicati di così, ma se vengono usati con criterio, in genere catturano porzioni ragionevolmente piccole di software in modo da poterne discutere agevolmente davanti ad un caffè e poi tutti al lavoro. Di seguito il diagramma delle classi del software della mia tesi.
Per capirci: l’ho disegnato perché mi è stato chiesto come documentazione e solo a progetto terminato, mentre durante la progettazione avrò disegnato sì e no due o tre schemini a matita in qualche angolo di quaderno comprendenti non più di tre o quattro classi ciascuno, giusto per tenere sott’occhio le cose. Se poi vi prendeste la briga di andare a vedere il codice, notereste che non tutti i metodi e le proprietà sono documentati nel diagramma, ma solo quelli essenziali.
Il diavolo sta nei dettagli.
Spesso avere una visione d’insieme aiuta. Anzi, la progettazione dovrebbe sempre iniziare con una visione d’insieme in modo da inquadrare bene obiettivi e caratteristiche del software, determinare quali saranno i suoi utenti, quali saranno le procedure che questi eseguiranno, ed eventualmente quali il software eseguirà autonomamente, oltre a tante altre belle cose che qui non ci preme indagare. Il punto è che per questo esistono degli altri tipi di diagrammi, per esempio il diagramma dei casi d’uso, il diagramma dei componenti, e il diagramma delle attività.
Diagrammi di comportamento
Il diagramma dei casi d’uso serve ad individuare gli utenti del sistema e descrivere quello che essi si aspettano di poter fare col sistema. Questo ne fa un ottimo diagramma per cominciare a progettare più o meno qualsiasi cosa perché risponde alle domande “a chi serve?” e “a cosa serve?”. Non devo nemmeno dire che infatti è il diagramma meno usato in assoluto, al meglio abbozzato a inizio progetto, quasi mai incluso in documentazione, e anche quando c’è, o esibisce un’imbarazzante laconicità o include casi d’uso inutili, scartati, ridondanti, ed altre cose brutte.
Il diagramma dei componenti è una specie di estensione del diagramma dei casi d’uso, nel senso che descrive i componenti del sistema (tra cui anche gli attori che possono essere di ogni natura, tipo umani, informatici, felini, positronici…) e descrive quali attori interagiscono con quali componenti e attraverso quali interfacce. Risponde più o meno alle stesse domande del precedente aggiungendo solo “quali parti interagiscono tra loro?”. È un diagramma abbastanza goffo perché contemporaneamente non riesce a dare il colpo d’occhio sulla funzione del sistema come fa il diagramma dei casi d’uso e nemmeno dà una panoramica sufficientemente dettagliata sui componenti per capirne il funzionamento. In virtù della sua maggiore inutilità, questo diagramma trova una più larga diffusione, pur trascinandosi dietro esattamente le stesse lacune dei casi d’uso. Sia ben chiaro che le lacune non sono proprie del diagramma ma di chi lo disegna, che spesso è privo del grano salis o più semplicemente è costretto da qualcuno più in alto di lui ad agire contro natura, producendo documentazione al meglio inutile che verrà stampata in grossi libri con tutta la documentazione contribuendo al disboscamento e al riscaldamento globale [1].
Infine il diagramma delle attività dà una sterzata alla parabola discendente dell’utilità, incrementando tuttavia l’entropia inventando un nuovo linguaggio grafico. Essenzialmente si tratta di un pittoresco incidente stradale tra i vecchi diagrammi di flusso e le reti di Petri che però ha l’indubbio pregio di unificare le due semantiche producendo diagrammi abbastanza efficaci per descrivere il flusso delle operazioni in sistemi paralleli. Il difetto sta sempre nell’ansia da prestazione di chi lo disegna che produce o diagrammi tipo Inizio › Facciamo cose › Aspettiamo che l’altro faccia cose › Fine, o mostri di freccette e rettangolini, con scritte miniate al loro interno, che ben rappresentano il concetto di spaghetti code. Poi ci si chiede perché la gente riesce a incasinare tutto anche con gli Oggetti. Ma siccome non ci vogliamo far mancare niente, per aggiungere confusione all’illogicità (o viceversa) e dato che nell’informatica la ridondanza è spesso un bene [2], ecco apparire il diagramma della macchina a stati, che descrive i possibili stati in cui può trovarsi il sistema e le transizioni tra di essi, cioè il come e il perché il sistema passa da uno stato all’altro. Incredibilmente questi diagrammi, che altro non sono che una riformulazione dei diagrammi di flusso con le condizioni spostate nelle transizioni, non contengono mai l’unico insieme di stati veramente utili, il FUBAR [3].
Un sottoinsieme dei diagrammi di comportamento, i diagrammi di interazione, mirano a descrivere nel tempo l’interazione dei componenti del sistema descrivendo il passaggio di messaggi tra di essi e mettendoli in una sequenza temporale. Di questi diagrammi ne esistono quattro che potrebbero però descrivere tutti le stesse informazioni, però con simboli grafici diversi. Ehm. Ma allora perché non estendere i diagrammi dei componenti, per esempio?
Ma a che pro?
Ci sarebbero molti altri tipi di diagrammi da descrivere, ma ho l’impressione di aver dato l’idea: eravamo partiti dal dire che un gatto è un animale e siamo arrivati ad una pletora di diagrammi sempre più complicati, costellati di frecce che cambiano significato a seconda che abbiano la testa vuota o piena, aperta o chiusa, con la coda tratteggiata o unita, con oggetti che hanno significati e comportamenti diversi a seconda che i nomi siano scritti in grassetto o in corsivo, che abbiano un + o un – a fianco, e via così. Un casino.
Ad un certo punto, dopo tutta questa analisi e dopo tutti questi diagrammi, abbiamo solo un mucchio di carta in mano, e nessun software. Ammesso di non aver esaurito il budget per acquistare tutti quei fantastici tool per realizzare diagrammi UML [4], entrano in scena gli schiavi che devono implementare il progetto. Idealmente si troveranno in mano tutta la documentazione sotto forma di diagrammi UML e liste di requisiti, e tutto quello che dovranno fare sarà mettere al lavoro le loro dita e produrre tante righe di codice.
Immaginiamo per un momento uno scenario di pura fantasia, alta speculazione, una vetta di astrattismo che mai si è vista in pratica, ma immaginiamo ugualmente per un momento che un bel giorno arrivi il cliente e chieda di modificare un caso d’uso perché nel frattempo hanno scoperto che la procedura che modellava era più efficiente se fatta in un’altro modo. Supponiamo, per quanto assurdo possa sembrare, che questo caso d’uso venga descritto in maggior dettaglio da un diagramma delle attività che interseca altri due casi d’uso, pure in modo periferico ma che nondimeno ci costringa a modificarli a loro volta. Che problema c’è, direte: riapriamo i nostri fantastici tool pagati fiori di quattrini, facciamo le modifiche, e ricominciamo a lavorare. Queste tre minuscole modifiche di solito coinvolgono non meno di un centinaio di righe di codice, ad essere ottimisti. Ad essere pessimisti non faccio neanche il conto sennò mi metto a piangere.
Ma è chiaro che questa è una situazione che non può accadere: abbiamo modellato tutto dall’inizio, il modello è solido… ricordo un progetto in cui i requisiti non sono cambiati in corso d’opera. Credo fosse in terza superiore, si trattava di calcolare il massimo comune denominatore di due numeri interi.
Una variante ancora più spaventosa di questa storia è quella in cui gran parte del codice può essere generato automaticamente a partire dai diagrammi. Poi qualcuno mi spiegherà come si modella il cast dinamico di C++, ma è ovvio che qui l’errore lo sto facendo io: dovevo usare Java che non ha cast dinamici. Non ha ereditarietà multipla perché sennò si incorre nel problema delle dipendenze a diamante (che, per inciso, è un problema di cui i programmatori ridevano e che gli analisti ignoravano prima che apparisse UML a descriverlo). Insomma, in Java non c’è niente di veramente utile, e in effetti credo sia per questo che va così bene a braccetto con UML.
Ma allora perché?
UML ha uno scopo molto semplice e non troppo palese. Se siete mai entrati in una libreria con una sezione tecnica avrete sicuramente notato la quantità di libri dedicati a UML. Se avete mai frequentato un corso di ingegneria del software ci sarà sicuramente saltata all’occhio la dimensione della bibliografia dedicata a UML. Se avete mai lavorato in qualcuna di queste aziende che usa UML come “metodologia di sviluppo” avrete sicuramente partecipato a corsi di aggiornamento tenuti da “esperti” in UML che poi non sapevano rispondere un dito più in là del libro [5] e chi credete che abbia formato questi esperti? Altri esperti. E quando un’azienda vuole adottare questa cosa di cui tutti parlano, chi chiamano? Ancora esperti! Che avranno ciascuno scritto un libro su UML, o avranno un amico che l’ha fatto, e che improntano il corso su questo libro, e poi consigliano un altro libro come riferimento, ma questo libro è talmente tecnico che serve un corso per capirlo e insomma… lo scopo di UML è creare un mercato che si autoalimenta in un’industria satura e addormentata che però vuole crescere ancora, e ancora, e ancora… e l’abbiamo sotto gli occhi tutti i giorni quello che succede quando un’entità pensa di poter crescere all’infinito.
Io sono giunto ad una conclusione: UML è immorale.
PS. Tanto perché poi non si dica che copio e non cito, leggetevi “UML: The Positive Spin“.
PPS. Il titolo fa riferimento alla Legge di Parkinson sulla Banalità.
Cico dice:
Ti sei dimenticato di dire che i libri di uml costano uno strafottio atomico.
Andrea Franceschini dice:
Pensavo fosse implicito ma hai fatto bene a farlo notare :)
(ah, Cico: oggi ho visto una Qubo verde mela, in UK, e ho avuto il riflesso condizionato di guardarci dentro per vedere se c’eri tu)