La leggibilità del codice

Codice illeggibile?

The rationale for the code being the primary source of documentation is that it is the only one that is sufficiently detailed and precise to act in that role [….].

This principle comes with a important consequence – that it’s important that programmers put in the effort to make sure that this code is clear and readable.

Martin Fowler – CodeAsDocumentation

Di solito gli sviluppatori non dedicano particolare attenzione alla scrittura della documentazione. Nel caso migliore è vista come un male necessario, nel caso peggiore invece è trattata come un task da fare il più tardi possibile (e tendenzialmente mai).

Recentemente, grazie alla diffusione di metodologie agili, la scrittura della documentazione sta diventando parte integrante del processo di sviluppo di un software. Infatti il processo di scrittura e di mantenimento della documentazione può essere semplificato inserendola all’interno del codice stesso. In questo modo il codice assume il ruolo di sorgente principale di documentazione di un progetto.

In questo articolo ti voglio parlare dell’importanza di mantenere una documentazione a scopo interno che sia ben fatta, con un codice che sia “parlante” e con il giusto numero di commenti. Per farlo cercherò di rispondere alle seguenti 3 domande:

  • Perché il codice deve essere leggibile?
  • Quando è che un codice è leggibile?
  • Come scrivo codice che sia leggibile?

Ma prima di rispondere a queste domande mi presento, sono Lorenzo Millucci e sono un ingegnere del software che ama lavorare con Symfony e a cui piace condividere in questo blog le cose che impara. Iscriviti al mio canale Telegram per non perderti nessuna notizia!

Perché il codice deve essere leggibile?

Affrontiamo subito l’elefante nella stanza: perché devo prendermi la bega di scrivere del codice che sia leggibile?

Lo sviluppo di software è un task che viene affrontato in team nella quasi totalità dei casi. Ormai quasi nessun progetto viene sviluppato da una singola persona. Questo vuol dire che il codice che oggi io scrivo da solo davanti al mio PC prima o poi dovrà essere letto e capito da altri sviluppatori in modo che possano modificarlo per correggere bug o per aggiungere nuova funzionalità.

Quando il codice non è facilmente leggibile, lo sviluppatore che dovrà modificare dopo di me quelle righe dovrà perdere una notevole quantità di tempo solo per capire cosa ho fatto e come l’ho fatto per quello che magari poteva essere un fix facile e veloce.

Nel caso peggiore il codice scritto potrebbe essere così astruso che uno sviluppatore, piuttosto che perdere tempo nel cercare di decifrarlo, potrebbe decidere di riscriverlo da capo. Ma il processo di riscrittura non è esente da rischi. Infatti non è raro che qualche edge-case particolare non venga coperto dal nuovo codice o che venga introdotto qualche bug che il codice originale non aveva. Tutto ciò rende quindi necessario iterare più e più volte il processo di scrittura aumentando notevolmente i tempi e i costi di sviluppo.

Un altro fenomeno che spesso si verifica quando il codice non è facilmente interpretabile dagli sviluppatori è quello chiamato “Shanghai programming”.
Hai presente il gioco Shanghai? Quello in cui c’è un mucchio di bastoncini e i giocatori si sfidano a chi ne sfila il numero maggiore senza muovere gli altri.
Bene, può accadere la stessa cosa nello sviluppo di un software. Uno sviluppatore, non riuscendo a capire cosa faccia il mio codice, potrebbe essere portato a cambiare solamente le parti strettamente necessarie ad implementare la funzionalità richiesta senza toccare il resto. Questo comportamento non può che portare ad un’ulteriore riduzione della leggibilità del codice.

Arrivati a questo punto non devi stupirti del fatto che il codice non leggibile sia uno dei più grandi contribuenti all’aumento incontrollato del debito tecnico.

Ora che hai capito il perché il codice deve essere facilmente leggibile da chiunque procediamo a chiarire quando è che un codice è leggibile (e di conseguenza quando non lo è).

Malore: La tipica reazione di uno sviluppatore di fronte ad un codice illeggibile
La tipica reazione di uno sviluppatore di fronte ad un codice illeggibile

Quando è che un codice è leggibile?

Sfortunatamente non esiste una risposta universale a questa domanda. A seconda del linguaggio utilizzato, del team o della singola persona presa in considerazione la risposta a questa domanda varia.

Quello che sicuramente possiamo dire è che un codice è illeggibile se non è formattato in modo coerente.
Ti è mai capitato di aprire un libro e vedere una pagina fitta-fitta di testo senza alcuna suddivisione in paragrafi? Quando succede a me la prima reazione è quella di chiudere il libro e lasciare perdere la lettura. Questa è la stessa reazione di uno sviluppatore che vede un codice mal-formattato.

Quindi una prima costatazione da fare è che per aumentare la leggibilità del codice è necessario stabilire delle convenzioni da seguire per l’impaginazione/formattazione del codice. Ad esempio definire che tutti i metodi devono essere scritti in camelCase. Oppure che l’indentazione del codice deve essere fatta utilizzando gli spazi piuttosto che tabulazioni. Ecc…
Tipicamente per queste regole stilistiche ci vengono incontro vari tool automatici di analisi statica che, una volta definite le regole, evidenziano (e a volte correggono automaticamente) tutti gli errori che incontrano.

Ma è sufficiente definire delle regole stilistiche per scrivere del codice leggibile? Ovviamente la risposta è no.

Una volta che il codice è ben formattato bisogna iniziare a vedere che ciò che abbiamo scritto sia comprensibile anche agli altri membri del team di sviluppo.

La prima cosa da fare in questo caso è farsi una serie di domande:

  • Si riesce a seguire il flusso del codice?
  • Il nome di un metodo/variabile aiuta a capire a cosa serve?
  • E’ necessario aggiungere un commento ulteriore per chiarire cosa sto facendo?
  • ecc…

Una volta terminata questa fase di “auto-analisi” del codice posso finalmente affermare che il codice è chiaramente leggibile da me stesso.

Ma come dicevamo all’inizio orma si lavora sempre in team e quindi non è sufficiente che il codice che ho scritto sia leggibile da me ma deve essere leggibile da qualunque altro collega.

Ecco quindi la prova finale per garantire la leggibilità di un software: superare la code-review.

Solo nel caso in cui un altro sviluppatore sia effettivamente in grado di capire cosa fa il mio codice senza porre domande sul suo funzionamento e senza fraintenderne in alcun modo il flusso logico posso dire di aver prodotto un codice veramente leggibile.

Reazione di festeggiamento quando finalmente la code review passa
Finalmente il codice è leggibile

Come scrivo codice che sia leggibile?

Anche a questa domanda non esiste una risposta universalmente riconosciuta. Tuttavia alcuni principi da avere bene a mente durante lo sviluppo del software sono:

  • Single-responsibility principle (SRP): ogni elemento di un programma deve avere una e una sola responsabilità. In modo tale che per uno sviluppatore sia facile capire cosa andare a modificare in caso di necessità.
  • Don’t repeat yourself (DRY): ogni elemento di un programma deve essere scritto una e una sola volta all’interno della code-base. Deve esistere una sola fonte di verità in modo da garantire che la modifica di un blocco di codice non debba mai essere ripetuta in più volte in più punti dell’applicazione.
  • Naming significativo: i nomi degli attributi, delle funzioni e delle classi deve essere significativo ed essere pensato in modo tale da aiutare la comprensione del codice.
  • Commenti solo se necessari: con un buon naming si può fare a meno di molti blocchi di commenti. Tuttavia esistono porzioni di codice che richiedono ulteriori spiegazioni e che quindi devono essere necessariamente commentate. I buoni commenti spiegano il “perché” di una determinata scelta. Il “come” è spiegato dal codice.
  • Testing: sebbene i test automatici non migliorino direttamente la leggibilità di un blocco di codice, questi permettono di capire il contesto in cui il codice è utilizzato. Inoltre, anche con il codice più leggibile del mondo è facile incappare in errori. Solo con una suite di test automatici in grado di coprire tutto il software è possibile modificare un software senza il terrore di aver rotto qualcosa nel tentativo di aggiustare qualcos’altro.

Conclusioni

Spero che questo articolo ti abbia aiutato a capire “perché”, “quando” e “come” scrivere un codice leggibile. Sicuramente ha aiutato me a mettere in ordine varie idee e nozioni che avevo acquisito ma che non avevo mai avuto modo di organizzare in modo strutturato.

Come hai potuto leggere nel corso dell’articolo alla base di un codice leggibile non c’è nessun concetto astratto o complesso da capire. Si tratta di nozioni che chiunque abbia provato a programmare con un qualunque linguaggio conosce ma che di solito si tende a dimenticare in quanto concetti considerati banali.

Un ulteriore punto che ci tengo a precisare è che la perfezione non esiste. Esisterà sempre un modo più ricercato o più elegante per rendere maggiormente leggibile una porzione di codice.
Il problema è che poiché la leggibilità non è un concetto universalmente definito dagli sviluppatori si possono creare delle situazioni di stallo in cui opinioni differenti rischiano di bloccare completamente lo sviluppo. Proprio per evitare di cercare la perfezione a tutti i costi è fondamentale tenere a mente che molte volte è sufficiente che il codice sia leggibile da chi effettivamente dovrà lavorare sul codice. Ed è per questo che le code-review sono lo strumento principale per garantire la leggibilità del codice.

Infine c’è da dire che il codice non è scritto nella pietra. La ricerca della miglior leggibilità del codice è un processo continuo. Ogni volta che puoi migliorare la leggibilità è bene non indugiare e farlo subito in modo da ridurre il debito tecnico. Grazie alla suite di test automatici (che non a caso ho inserito tra i requisiti per un buon codice leggibile) potrai rifattorizzare il codice avendo la certezza di non aver rotto nulla.


Se questo post ti è stato utile puoi farmelo sapere lasciando un commento qui sotto oppure scrivendomi direttamente a t.me/lorenzomillucci.
Inoltre ti invito ad iscriverti al mio canale Telegram e a seguirmi su Twitter per non perderti nemmeno un post del mio blog. A presto!

Fonte
Fonte

Responsible disclosure: esposizione della cartella .git su di un sito di comparazione prezzi

responsible disclosure

Era un normalissimo Lunedì mattina. Come sempre, prima di iniziare a lavorare, stavo facendo una navigata sul web. Ero appena entrato sul sito di una compagnia di comparazione prezzi quando una notifica del browser cattura la mia attenzione: Found an exposed .git.

L’estensione del browser che utilizzo per verificare automaticamente se un sito web ha la cartella /.git esposta ne aveva appena beccato uno.

Ops, ho appena trovato una cartella .git pubblicamente accessibile

Se non sei uno sviluppatore ti starai chiedendo: “è quindi”? Se invece conosci Git sai già quanto possa essere potenzialmente grave avere la cartella .git pubblicamente accessibile.

Infatti attraverso l’accesso a quella cartella sono riuscito ad estrapolare le chiavi di accesso al database!

A livello puramente teorico, in assenza di ulteriori meccanismi di protezione, ottenere credenziali del genere potrebbe garantire ad un malintenzionato l’accesso in lettura e scrittura ai dati di tutti gli utenti della piattaforma (username, hash di password, ecc…).

Ma prima di vedere nel dettaglio che strumenti ho usato per accorgermi della vulnerabilità e come è andata a finire la storia lasciami presentare. Io sono Lorenzo Millucci e sono un ingegnere del software che ama lavorare con Symfony e a cui piace condividere in questo blog le cose che impara. Iscriviti al mio canale Telegram per non perderti nessuna notizia!

Cos’è Git?

Andiamo con ordine. La prima cosa che ti serve sapere per capire quale sia stato il problema di sicurezza è capire cosa sia Git e perché avere accesso a quella cartella è un problema di sicurezza.

Git è un popolarissimo software utilizzato dagli sviluppatori per tracciare le modifiche del codice sorgente (versionamento) creato da Linus Torvalds (il creatore di Linux) nel 2003.

Per tracciare tutti i cambiamenti all’interno di una codbase, Git mantiene tutti i (meta-)dati necessari all’interno di una cartella nascosta chiamata .git.

Normalmente Git è uno strumento utilizzato esclusivamente internamente ai team di sviluppo e i meta-dati che produce non sono accessibili pubblicamente. Può però capitare che a causa di una dimenticanza o di una cattiva configurazione del server questa cartella non venga opportunamente protetta e che sia quindi leggibile da chiunque.

Avendo accesso alla cartella .git è possibile estrapolare diverse informazioni sensibili sul sito web semplicemente guardando i file in essa contenuti:

  • .git/config: è il file di testo utilizzato da git per tracciare le informazioni generali sul repository (es. l’URL del server con il repository, l’username, le branch attive… )
  • .git/index: è il file contente l’indice di tutti i file presenti nel repository e di tutte le modifiche fatte. Il file è in formato binario ma esistono dei tool appositi in grado di leggerne il contenuto.
  • .git/objects: è la cartella che contiene tutte i file del progetto. Tutti i file sono salvati senza estensione e utilizzando l’hash SHA1 come file name. E’ da questa cartella che è possibile estrapolare dati sensibili del sito web.

Come mi accorgo di una cartella .git esposta pubblicamente?

Ora che hai capito cos’è Git ti chiederai come si fa a verificare se la cartella .git è pubblicamente accessibile su una web-app.

Il metodo più semplice (e più macchinoso) per verificare se una cartella .git è esposta pubblicamente è quello di provare a modificare l’URL della pagina aggiungendo di volta in volta il percorso alla cartella .git nel seguente modo:

  • https://example.com/.git/config
  • https://example.com/.git/HEAD
  • https://example.com/.git/logs/HEAD
  • https://example.com/.git/index

Siccome farlo manualmente è una scocciatura è possibile scaricare un estensione del browser (per Firefox e Chrome) chiamata DotGit che permette di effettuare la verifica automaticamente. Nel caso in cui i file sono pubblicamente accessibili l’estensione lo farà presente immediatamente con una notifica.

Che ci faccio con la cartella .git?

Ora arriva la parte divertente. Una volta che ho trovato una cartella Git esposta tutto quello che devo fare è utilizzare un software chiamato GitTools per scaricare ed estrarre automaticamente tutto il codice lasciato incustodito.

Per scaricare il contenuto della cartella .git basta dare il comando:

./Dumper/gitdumper.sh https://example.com/.git/ /output-directory/

Siccome spesso i repository vengono compressi può succedere che i dati scaricati non siano immediatamente leggibili. Proprio per questa evenienza i GitTools mettono a disposizione un altro strumento che permette di carpire quanta più informazione possibile dal repository scaricato.
Per usare questo strumento il comando da utilizzare è:

 ./Extractor/extractor.sh /output-directory/ /output-directory-extracted/

Una volta che il tool avrà finito di estrarre il contenuto della cartella sarà possibile esplorare il codice sorgente. A seconda dell’applicazione web è possibile cercare all’interno del codice chiavi di accesso, credenziali hordcodate, nuovi endpoint segreti, ecc…

Disclosure

Ma ritorniamo a Lunedì mattina. Avevo appena ricevuto la notifica da parte di DotGit. Ero abbastanza stupito che un sito così famoso avesse potuto commettere un errore tanto banale senza che nessuno se ne accorgesse.

Così ho provato a vedere cosa ci fosse all’interno del repository utilizzando i GitTools e mi sono accorto che tra i file c’era il file di configurazione .env contenete le chiavi di accesso ai vari database del sito.

Uno dei “pericolosi” file che contengono le chiavi di accesso ai database. Naturalmente ho oscurato i dati sensibili

Io non ho provato a connettermi ai vari database del sito visto che il mio interesse era puramente “accademico” e visto che molto probabilmente sono protetti da ulteriori meccanismi di protezione. Tutto quello che ho fatto è stato segnalare la vulnerabilità al supporto tecnico del sito che si è rivelato svelto a rispondermi e a risolvere il problema.

Timeline

  • Lunedì 22/06/2020 navigando prima di attaccare al lavoro mi accorgo della vulnerabilità;
  • Lunedì 22/06/2020 11:24 contatto il supporto del sito per segnalare la vulnerabilità;
  • Lunedì 22/06/2020 13:05 mi risponde il responsabile tecnico del sito;
  • Lunedì 22/06/2020 13:17 segnalo il problema al responsabile;
  • Lunedì 22/06/2020 15:21 il supporto mi segnala che il problema è stato risolto.

Conclusioni

Alla fine tutto bene quel che finisce bene. Sfortunatamente il problema di lasciare cartelle .git esposte è più comune di quanto si pensi. Tanto è vero che anche OWASP (il progetto che ha come scopo la sicurezza delle applicazioni web) lo inserisce tra i requisiti da verificare per garantire la protezione da accessi indesiderati ai siti web.

In ogni caso l’assistenza si è dimostrata rapida ed efficace nel risolvere il problema e mi piace pensare che ora il web sia diventato un po’ più sicuro anche per merito mio.

Nonostante il problema sia stato gestito e risolto in maniera impeccabile l’azienda in questione mi ha chiesto di non divulgare il suo nome e di conseguenza non è riportato da nessuna parte nell’articolo.


Se questo post ti è stato utile puoi farmelo sapere lasciando un commento qui sotto oppure scrivendomi direttamente a t.me/lorenzomillucci.
Inoltre ti invito ad iscriverti al mio canale Telegram e a seguirmi su Twitter per non perderti nemmeno un post del mio blog. A presto!

Cos’è il debito tecnico?

Debito tecnico

Fin da quando ho iniziato a lavorare ho sentito parlare di “debito tecnico”. Al lavoro recentemente abbiamo anche creato una board dedicata esclusivamente al tracciamento del debito tecnico.

Ma che cos’è il debito tecnico? Pur non avendo mai approfondito il concetto è facile capire a grandi linee di cosa si tratta: sono tutte quelle cose che uno lascia indietro oggi per poter rilasciare prima il software sapendo che prima o poi sarà necessario ritornarci sopra.

In realtà la metafora del debito tecnico è un po’ più articolata di così e oggi ho approfittato di un giorno di ferie per studiare meglio la questione analizzando le parole del leggendario Martin Fowler.

Prima di cominciare mi presento, sono Lorenzo Millucci e sono un ingegnere del software che ama lavorare con Symfony e a cui piace condividere in questo blog le cose che impara. Iscriviti al mio canale Telegram per non perderti nessuna notizia!

Definizione

Il debito tecnico è una metafora concepita da Ward Cunningham che assimila la complessità di un software ad un debito finanziario e lo sforzo necessario ad aggiungere una nuova funzionalità all’interesse pagato sul debito.

Ogni riga di codice scritta, ogni libreria installata nel progetto incrementa il livello di complessità generale al progetto andando ad incrementare il debito tecnico.

Esattamente come accade per i debiti finanziari, la scelta migliore è pagare gradualmente in “comode” rate mensili.

La forza di questa metafora consiste nel rendere evidente anche a chi non è un ingegnere del software come anche le attività di refactoring del codice, pur non portando nuove funzionalità al progetto, sono necessarie a “ripagare” la quota del debito.

Ogni volta che è necessario aggiungere una nuova funzionalità al progetto sarebbe buona norma investire del tempo per ristrutturare il codice esistente. Chiaramente in questo modo si otterrebbero dei cicli di sviluppo più lunghi. Tuttavia, qualora dovesse capitare di lavorare nuovamente sulla stessa porzione di codice il lavoro potrebbe procedere in modo molto più spedito avendo già pagato la quota di debito.

Se invece si decidesse di non pagare periodicamente le quote di debito tecnico si finirebbe per avere cicli di sviluppo molto rapidi all’inizio ma, mano a mano che il debito si accumula, i tempi di sviluppo si estenderebbero sempre di più fino ad arrivare al fatidico momento in cui la complessità del software è così alta che non è più possibile sviluppare nuove funzioni in tempi ragionevoli. Quando si arriva in questa situazione, quello che accade solitamente è che si getta la spugna ed è necessario riscrivere da capo il software.

Posso pagare il debito tecnico in stelline?

Una delle principali differenze con i debiti finanziari invece è che, contrariamente ai debiti finanziari in cui l’interesse da pagare è sul totale, sui debiti tecnici il costo da pagare è dipendente dalla porzione di codice. In un software possono esistere parti di codice da incubo con un debito tecnico altissimo ma che non tocca nessuno e quindi un interesse bassissimo e parti di codice che invece sono modificate frequentemente e che quindi pur avendo dei piccoli debiti hanno degli interessi stellari.

TIPOLOGIE DI DEBITO

A seconda di come si affronta il debito tecnico è possibile individuare due classificazioni del debito. Una basata sul rischio (prudente/imprudente) e una basata sulla coscienziosità con cui si protrae il debito (volontario/involontario). Vediamo di seguito come si combinano le due classi:

  • DEBITO VOLONTARIO E PRUDENTE: nello sviluppo di un progetto è ammissibile accettare di fare del debito per concentrarsi sulle cose urgenti. L’importante è sapere che il debito fatto oggi tornerà a chiederci gli interessi domani.
  • DEBITO VOLONTARIO E IMPRUDENTE: questo forse è il caso peggiore. So di indebitarmi pur di consegnare il software ma faccio finta che stia andando tutto bene trascurando completamente le conseguenze di tale indebitamento.
  • DEBITO INVOLONTARIO E IMPRUDENTE: questo in genere accade agli sviluppatori alle prime armi che non conoscono il concetto di debito tecnico e non si rendono conto che cattive scelte fatte in fase di progetto li perseguiteranno in futuro.
  • DEBITO INVOLONTARIO E PRUDENTE: Molto spesso accade che nonostante si abbiano seguito perfettamente le migliori best-practices ci si rende conto che se si fosse utilizzato quel design pattern o quell’altra architettura il codice sarebbe stato sicuramente migliore (in termini di complessità).

Queste combinazioni possono essere riportate in un grafico fatto nel seguente modo:

Il quadrante del debito tecnico

Il fatto che ogni progetto finisca per avere del debito tecnico però non deve essere preso come scusa per trascurare la qualità del codice. Aggiungere codice di scarsa qualità ad un progetto già indebitato fino al collo o scordarsi di pagare le rate degli interessi non può che peggiorare la situazione arrivando a rendere impossibile lo sviluppo di nuove funzionalità.

D’altro canto, un debito ben ragionato con piccole quote di interesse pagate regolarmente può permettere di accelerare il rilascio di nuove funzionalità.

Conclusioni

Ogni volta che adottiamo una soluzione “quick and dirty” per risolvere un problema stiamo facendo debito. Ogni volta che trascuriamo di aggiornare le libreria del progetto stiamo facendo debito. Ogni volta che ci rendiamo conto che avremmo potuto semplificare il codice e non lo facciamo stiamo facendo debito.

Il debito tecnico quindi è un’ombra che che incombe su ogni sviluppatore. Può sembrare minacciosa ma il solo sapere che esiste può essere sufficiente per tenerla a bada. 

Il debito tecnico di per sé non è malvagio. Avere un debito è normale per qualunque azienda si occupi di software. La cosa fondamentale da fare però è fare in modo che non raggiunga mai soglie troppo elevate e che le quote di interesse non schizzino alle stelle paralizzando completamente il progetto. 

Come per i debiti finanziari la bravura sta nel ripagare il debito in piccole rate includendo sempre nella roadmap dei progetti del tempo da dedicare al refactoring del codice.


Se questo post ti è stato utile puoi farmelo sapere lasciando un commento qui sotto oppure scrivendomi direttamente a t.me/lorenzomillucci.
Inoltre ti invito ad iscriverti al mio canale Telegram e a seguirmi su Twitter per non perderti nemmeno un post del mio blog. A presto!

Fonte
Fonte