Home
5 risposte su… Clean Craftsmanship: diventare maestri dello sviluppo software

03 Dicembre 2021

5 risposte su… Clean Craftsmanship: diventare maestri dello sviluppo software

di

Siamo orgogliosi del lavoro di sviluppo che abbiamo svolto oggi? Non tanto del risultato, ma del modo in cui abbiamo programmato? Ci sono molte vie alla buona programmazione, ma una delle più solide e producenti è pensarci come artigiani del software.

Di che cosa parliamo

  1. Quali sono le tre leggi del Test-Driven Development
  2. Che cos’è la matrice di Eisenhower
  3. Qual è lo schema fondamentale per tutti i test
  4. Che cosa non rilasceremo mai
  5. Che cosa vuol dire giurare di fare del proprio meglio

Quali sono le tre leggi del Test-Driven Development

Prima dobbiamo occuparci di alcuni preliminari. L’essenza del Test-Driven Development (TDD) richiede disciplina nel fare quanto segue.

  1. Creare una suite di test che applichi il refactoring e sia affidabile nella misura in cui tale passaggio implichi la possibilità di distribuire il software. Cioè, se la suite di test passa con successo, il sistema può essere distribuito.
  2. Creare del codice di produzione sufficientemente disaccoppiato da essere testabile e rifattorizzabile.
  3. Creare un ciclo di feedback estremamente stretto,che permetta di scrivere programmi con un ritmo e una produttività stabili.
  4. Creare codice di test e di produzione sufficientemente disaccoppiati tra loro, in modo da consentire una comoda manutenzione di entrambi, senza l’impedimento di dover replicare le modifiche tra i due.

La disciplina del TDD è racchiusa in tre leggi del tutto arbitrarie. La prova che queste leggi sono arbitrarie è che l’essenza può essere raggiunta con mezzi molto diversi. In particolare con la disciplina test && commit || revert (TCR) di Kent Beck. Sebbene la disciplina TCR sia completamente diversa dal TDD, raggiunge esattamente gli stessi obiettivi essenziali.

Le tre leggi del TDD sono il fondamento di base della disciplina. Seguirle è molto difficile, soprattutto all’inizio: richiede abilità e conoscenze difficili da trovare. Se provi a seguire queste leggi senza tali abilità e conoscenze, quasi sicuramente ne ricaverai frustrazione e abbandonerai la disciplina.

La prima legge

Non scrivere codice di produzione fino a quando non avrai prima scritto un test che fallisca a causa dell’assenza di quel codice di produzione.

Se hai anni di esperienza nel campo della programmazione, questa legge può sembrarti stupida. Potresti chiederti quale test dovresti mai scrivere se non c’è ancora del codice da sottoporre a test. Questa domanda deriva dall’aspettativa comune che i test debbano essere scritti dopo il codice. Ma se ci pensi, ti renderai conto che se puoi scrivere il codice di produzione, puoi anche scrivere il codice che sottopone a test il codice di produzione. Può sembrare fuori luogo, ma non ti mancano le informazioni che ti servono per scrivere prima il test.

La seconda legge

Non scrivere più di un test di quanto sia sufficiente per fallire o per far fallire la compilazione. Risolvi l’errore scrivendo del codice di produzione.

Iscriviti alla nostra newsletter

Di nuovo, se hai una buona esperienza di programmazione, probabilmente ti renderai conto che la prima riga del test non verrà compilata, perché l’avrai scritta per interagire con del codice che non esiste ancora. E questo significa, ovviamente, che non sarai in grado di scrivere più di una riga di un test prima di dover passare alla scrittura del codice di produzione.

La terza legge

Non scrivere più codice di produzione di quello necessario per risolvere il test attualmente non passato. Una volta superato il test, scrivi altro codice di test.

Ora il ciclo è completo. Dovrebbe essere ovvio che queste tre leggi bloccano in un ciclo che dura solo pochi secondi. Funziona così.

  • Scrivi una riga di codice di test, ma non viene compilata (ovviamente).
  • Scrivi una riga di codice di produzione, che fa compilare il test.
  • Scrivi un’altra riga di codice di test, che non viene compilata.
  • Scrivi un’altra riga o due di codice di produzione, che fa compilare il test.
  • Scrivi un’altra riga o due di codice di test, che viene compilata ma fallisce un’asserzione.

E questa sarà la tua vita, d’ora in poi.

Torna all’inizio.

Che cos’è la matrice di Eisenhower

Il generale Dwight D. Eisenhower una volta disse:

Ho due tipi di problemi, quelli urgenti e quelli importanti. Quelli urgenti non sono importanti e quelli importanti non sono mai urgenti.

(in un discorso del 1954 alla Seconda assemblea del Consiglio Mondiale delle Chiese, l’ex presidente degli Stati Uniti Dwight D. Eisenhower, citava J. Roscoe Miller, presidente della Northwestern University).

C’è una profonda verità in questa affermazione: una profonda verità sull’ingegneria. Potremmo anche chiamarlo il motto dell’ingegnere:

Maggiore è l’urgenza, minore è la rilevanza.

La prossima figura presenta la matrice decisionale di Eisenhower:l’urgenza sull’asse verticale, l’importanza sull’asse orizzontale. Le quattro possibilità sono urgenti e importanti, urgenti e non importanti, importanti ma non urgenti, né importanti né urgenti.

Clean Craftsmanship - la matrice di Eisenhower

La matrice decisionale di Eisenhower. Dwight D. Eisenhower, presidente degli Stati Uniti, foto del febbraio 1959. Niday Picture Library/Alamy Stock Photo.

Ora disponiamoli in ordine di priorità. I due casi ovvi sono importanti e urgenti in alto e né importanti né urgenti in basso.

La domanda è: come si ordinano i due nel mezzo, urgente ma non importante e importante ma non urgente? Che cosa dovresti affrontare prima?

Chiaramente,le cose che sono importanti dovrebbero avere la priorità su quelle che non sono importanti. Direi, inoltre, che se qualcosa non è importante, forse non dovrebbe neppure essere fatto. Fare cose senza importanza è uno spreco.

Se eliminiamo tutte le cose non importanti, ne rimangono due. Facciamo prima le cose importanti e urgenti. Poi le cose importanti ma non urgenti.

Il punto è che l’urgenza ha a che fare con il tempo, l’importanza no. Le cose importanti sono a lungo termine, le cose urgenti sono a breve termine. La struttura è a lungo termine, pertanto, è importante. Il comportamento è a breve termine, pertanto, è solo urgente. Quindi, la struttura, che è importante, viene prima, e il comportamento è secondario. Il tuo capo potrebbe non essere d’accordo con questa priorità, ma questo perché non è compito del tuo capo preoccuparsi della struttura. Quello è il tuo compito. Il tuo capo si aspetta semplicemente che tu mantenga pulita la struttura mentre implementi i comportamenti urgenti.

Kent Beck ha detto: Prima fallo funzionare. Poi fallo bene. Ora sto dicendo che la struttura ha una priorità più elevata del comportamento. È un dilemma tra l’uovo e la gallina, vero?

Il motivo per cui prima lo facciamo funzionare è che la struttura deve supportare il comportamento; di conseguenza, prima implementiamo il comportamento, poi gli diamo la giusta struttura.

Ma la struttura è più importante del comportamento, gli diamo una priorità più elevata, ci occupiamo dei problemi strutturali prima di occuparci dei problemi comportamentali. Possiamo quadrare questo cerchio scomponendo il problema in minuscole unità. Iniziamo con le storie degli utenti. Fai funzionare una storia e poi dagli la sua giusta struttura. Non passare alla storia successiva finché quella struttura non sarà corretta. La struttura della storia attuale ha una priorità più elevata rispetto al comportamento della storia successiva.

Tranne per il fatto che le storie sono troppo grandi. Dobbiamo sminuzzarle. Non storie, quindi: test. I test hanno le dimensioni perfette.

Prima si scrive un test da superare, poi si corregge la struttura del codice per farle superare quel test e infine si passa al test successivo.

Questa discussione è il fondamento morale del ciclo Rosso → Verde → Refactoring del Test-Driven Development (TDD).

È quel ciclo che ci aiuta a prevenire danni al comportamento e danni alla struttura. È quel ciclo che ci permette di dare la priorità alla struttura rispetto al comportamento. Ed è per questo che consideriamo il TDD una tecnica di progettazione e non una tecnica di test.

Torna all’inizio.

Qual è lo schema fondamentale per tutti i test

Molti anni fa, Bill Wake ha identificato lo schema fondamentale per tutti i test. Lo chiamò 3A Pattern o AAA, che sta per Arrange/Act/Assert.

La prima cosa che devi fare quando scrivi un test è organizzare (Arrange) i dati da sottoporre a test. Questa operazione viene in genere eseguita in un metodo Setup o all’inizio della funzione di test. Lo scopo è porre il sistema nello stato necessario per eseguire il test.

La successiva cosa che fa il test è svolgere un’azione (Act). Il test richiama la funzione, esegue l’azione o richiama in altro modo la procedura che è l’obiettivo del test.

L’ultima cosa che il test fa è affermare (Assert). Questo di solito comporta l’esame dell’output per garantire che il sistema sia nel nuovo stato desiderato.

Come semplice esempio di questo schema, considera questo test di una ipotetica partita di bowling:

@Test
public void gutterGame() throws Exception {
	rollMany(20, 0);
	assertEquals(0, g.score());
}

La parte Arrange di questo test è la creazione della funzione Game nella funzione Setup, e rollMany(20, 0) per impostare il punteggio di un gioco tutto nel canale.

La parte Act del test è la chiamata a g.score().

La parte Assert del test è assertEquals.

Nei due decenni e mezzo trascorsi da quando ho iniziato a praticare il Test-Driven Development, non ho mai trovato un test che non seguisse questo schema.

Torna all’inizio.

Che cosa non rilasceremo mai

In qualità di tuo nuovo Chief Technical Officer (CTO), mi aspetto che non rilasceremo mai m***a.

Sono sicuro che tu sappia che cosa intendo per m***a. In qualità di tuo CTO, mi aspetto che non rilasceremo m***a.

Clean Craftsmanship - non rilasceremo mai m***a

Questo non lo faremo mai; invece, faremo un buon lavoro.

Hai mai rilasciato m***a? La maggior parte di noi l’ha fatto. Io l’ho fatto, e non mi ha fatto sentire bene. Non mi è piaciuto. Agli utenti non è piaciuto. Ai manager non è piaciuto. Non è piaciuto a nessuno.

Allora perché lo facciamo? Perché rilasciamo m***a?

Perché per qualche motivo abbiamo deciso che non avevamo scelta. Forse c’era una scadenza che dovevamo assolutamente rispettare. Forse abbiamo fatto una stima che ci vergognavamo di ammettere. Forse è stato per pura noncuranza o disattenzione. Forse avevamo il management addosso. Forse era una questione di autostima.

Qualunque fosse il motivo, non era un buon motivo. È uno standard minimo assoluto che non rilasceremo mai m***a.

Che cos’è la m***a? Sono sicuro che tu già lo sappia, ma… parliamone lo stesso.

  • Ogni bug che rilasci è m***a.
  • Ogni funzione non sottoposta a test è m***a.
  • >Ogni funzione scritta male è m***a.
  • Ogni dipendenza dai dettagli è m***a.
  • Ogni accoppiamento non necessario è m***a.
  • La presenza di codice SQL nella GUI è m***a.
  • Lo schema del database nelle regole operative è m***a.

Potrei andare avanti. Ma lasciami tagliare corto. Ogni insuccesso in una delle discipline del Test-Driven Development (TDD) rischia di far rilasciare m***a.

Ciò non significa che ognuna di queste discipline debba essere rispettata sempre e a qualsiasi costo.

Siamo tecnici e i tecnici devono scendere a compromessi. Ma un compromesso tecnico non implica disattenzione o noncuranza. Se devi infrangere una disciplina, è meglio che tu lo faccia per una buona ragione.

Ancora più importante, dovresti avere un buon piano di mitigazione dei danni.

Per esempio,supponiamo che tu stia scrivendo del codice per fogli di stile CSS. Scrivere in anticipo dei test automatizzati per i CSS è quasi sempre poco pratico. Non puoi sapere come verrà visualizzato il codice CSS finché non lo vedrai effettivamente sullo schermo.

Quindi, come possiamo mitigare il fatto che il codice CSS infrange la disciplina TDD? Dovremo sottoporre a test il codice CSS manualmente, con i nostri occhi. Dovremo anche sottoporlo a test in tutti i browser che utilizzeranno i nostri clienti. Quindi, faremmo meglio a fornire una descrizione standard di ciò che vogliamo vedere sullo schermo e di quanta variabilità possiamo tollerare.

Ancora più importante, faremmo meglio a trovare una soluzione tecnica che renda il codice CSS facile da sottoporre a test manualmente, perché noi, non il reparto Quality Assurance, lo sottoporremo a test prima di rilasciarlo.

Lasciamelo dire in un altro modo: fai un buon lavoro!

Questo è ciò che tutti si aspettano. Tutti i nostri manager, tutti i nostri utenti, tutti coloro che toccano o vengono toccati dal nostro software, si aspettano che abbiamo fatto un buon lavoro e non dobbiamo deluderli.

Mi aspetto che non rilasceremo mai m***a.

Torna all’inizio.

Che cosa vuol dire giurare di fare del proprio meglio

Chiaramente, questa è una promessa perfettamente ragionevole per un programmatore. Ovviamente farai del tuo meglio e ovviamente non rilascerai consapevolmente codice che produce danni.

E, naturalmente, questa promessa non è una cosa che è solo bianca o nera. Ci sono momenti in cui la struttura deve piegarsi al programma. Per esempio, se per partecipare a una fiera devi mettere insieme una soluzione rapida e sporca, allora così sia.

La promessa non ti impedisce nemmeno di inviare ai clienti del codice con una struttura tutt’altro che perfetta. Se la struttura è buona ma non del tutto corretta e i clienti si aspettano di riceverla domani, allora così sia.

D’altra parte, la promessa significa che dovrai affrontare tali difetti di comportamento e struttura prima di aggiungere altri comportamenti. Non accumulerai nuovi comportamenti su una struttura che sai essere difettosa. Non permetterai che questi difetti si accumulino.

E se il tuo capo ti dicesse di farlo comunque? Ecco come dovrebbe andare quella conversazione.

Capo: Voglio che questa nuova funzionalità venga aggiunta entro stasera.

Programmatore: Mi dispiace, ma non posso farlo. Devo ripulire la struttura prima di poter aggiungere quella nuova funzionalità.

Lo farai domani. Completa la funzionalità entro stasera.

Questo è quello che ho fatto per l’ultima funzionalità, e il risultato è che ora ho un pasticcio ancora più grande da ripulire. Davvero devo ripulire il codice prima di iniziare a fare qualcosa di nuovo.

Forse non ci siamo capiti. Questo non è un club ma un’azienda. O facciamo business o non facciamo business. E se non riusciamo a completare le funzionalità, non facciamo business. Ora completa la funzionalità.

Ho capito, davvero, e sono d’accordo. Dobbiamo essere in grado di fornire funzionalità. Ma se non risolvo i problemi strutturali che si sono accumulati negli ultimi giorni, otterremo un rallentamento e ancora meno produttività.

Lo sai, un tempo mi piacevi. Dicevo che Danny è un bel tipo, ma forse mi sbagliavo. Quello che mi dici non va bene per niente. Forse non dovresti lavorare per me. Forse dovrei licenziarti.

Beh, è un tuo diritto. Ma sono abbastanza sicuro che tu voglia avere funzionalità fatte rapidamente ma anche fatte bene, e ti sto dicendo che se non sistemo il codice stasera, inizieremo davvero a rallentare. E forniremo sempre meno funzionalità. Voglio lavorare velocemente, proprio come fai tu. Mi hai assunto perché so farlo. Devi lasciarmi fare il mio lavoro. Deve lasciarmi fare quello che so che è meglio.

Credi davvero che tutto rallenterà se non ripulirai il codice stasera?

So che sarà così. L’ho già visto, e lo sai anche tu.

E devi proprio farlo stasera?

Non va bene lasciare che il pasticcio peggiori.

Riuscirai a darmi la funzionalità domani?

Sì, e sarà molto più facile da realizzare, una volta che la struttura del codice sarà ripulita.

Va bene, vada per domani. Ma non più tardi. Ora fila!

Ok. Mi ci metto subito.

[dopo che il programmatore se n’è andato] Mi piace quel ragazzo. Ha fegato. Ha buon senso. Non si è tirato indietro nemmeno quando ho minacciato di licenziarlo. Andrà lontano, fidatevi… ma non fategli sapere che ho detto così.

Torna all’inizio.

Questo articolo richiama contenuti da Clean Craftsmanship.

Immagine di apertura di Quino Al su Unsplash.

L'autore

  • Robert C. Martin
    Robert C. Martin, conosciuto anche come “Uncle Bob”, scrive codice dal 1970 ed è un consulente informatico di livello internazionale. Ha fondato le società Uncle Bob Consulting LLC, Object Mentor Inc e - insieme al figlio Micah Martin - The Clean Coders LLC. È stato caporedattore della rivista The C++ Report e presidente dell'Agile Alliance. Firmatario del Manifesto per lo Sviluppo Agile di Software, è autore di Clean Code, bestseller che vanta oltre 160.000 copie vendute nella sola edizione inglese.

Iscriviti alla newsletter

Novità, promozioni e approfondimenti per imparare sempre qualcosa di nuovo

Gli argomenti che mi interessano:
Iscrivendomi dichiaro di aver preso visione dell’Informativa fornita ai sensi dell'art. 13 e 14 del Regolamento Europeo EU 679/2016.

Libri che potrebbero interessarti

Tutti i libri

Sviluppare applicazioni con Angular - Nuova edizione aggiornata

Guida alla programmazione web e mobile

27,55

29,00€ -5%

di Vincenzo Giacchina

Sviluppare applicazioni con Django

Guida alla programmazione web aggiornata alla versione 5

35,00

49,99€ -30%

28,50

30,00€ -5%

19,99

di Marco Beri

Fare la domanda giusta

L'arte di lavorare con ChatGPT e le AI

23,50

33,99€ -31%

19,00

20,00€ -5%

13,99

di Sergio Sentinelli, Alessandro Placa


Articoli che potrebbero interessarti

Tutti gli articoli