In un precedente articolo si è parlato di programmazione Cargo Cult, ovvero uno stile di programmazione secondo cui gli sviluppatori includono pezzi di codice nel loro programma senza conoscere né comprendere il ragionamento per cui quel codice deve essere incluso.
Programmare per coincidenza è un concetto introdotto e ben spiegato in un manuale, un classico che prima o poi deve essere letto e approfondito da ogni programmatore: Pragmatic Programmer. Se stiamo programmando per coincidenza, significa in poche parole che non sappiamo cosa stiamo facendo. Il nostro codice si basa sulla fortuna e su un successo accidentale. Bisognerebbe sempre evitare la programmazione per coincidenza e preferire una programmazione “cosciente” e deliberata.
Supponiamo di iniziare scrivere un programma. Il codice, ai primi test, sembra funzionare bene e risolvere tutti gli scopi che ci siamo prefissati. Allora continuiamo a sviluppare il programma e notiamo che il programma continua a funzionare. Un bel giorno, dopo varie settimane di lavoro, il programma smette di funzionare improvvisamente. E nonostante impieghiamo molto tempo e fatica, non siamo in grado di risolvere il problema. Perchè? Il motivo è semplice, il funzionamento (o meglio, come noi ci saremmo aspettati che funzionasse) si è basato principalmente a un colpo di fortuna. Il successo dei nostri test effettuati in itinere sono stati solo delle coincidenze.
Ecco quindi alcuni consigli pratici per evitare il più possibile la programmazione per coincidenza:
- Non facciamo affidamento su errori o comportamenti non documentati. Ad esempio, potremmo finire per usare una funzione di libreria instabile e far funzionare il nostro codice. Ma poiché la libreria è instabile, la funzione potrebbe essere modificata nella prossima versione.
- Non assumiamo ipotesi. I presupposti che non sono supportati da fatti consolidati generano problemi e conflitti.
- Ricordiamo sempre il quadro generale. Dobbiamo essere consapevoli di ciò che stiamo facendo e non bisogna limitarci a programmare con gli occhi bendati.
- Testiamo l’applicazione con molta frequenza. Scriviamo unit test per ogni nuova funzionalità aggiunta. In questo modo saremo in grado di confrontare il comportamento previsto e quello effettivo.
- Non perdiamo mai l’occasione di fare refactoring al codice. Non dobbiamo temere di apportare modifiche quando il codice diventa obsoleto e non sia più appropriato. Tutto il codice può essere sempre sostituito.
Copia incolla si o no?
E’ una pratica ormai molto diffusa quella di copiare e incollare codice di terzi nelle proprie applicazioni. Dopotutto, come diceva un mio professore universitario, se un algoritmo o una funzione esiste già, perchè dobbiamo sforzarci per riscrivere tutto da zero? Per chi è relativamente nuovo nel mondo della programmazione, probabilmente non ha l’esperienza per capire il vantaggio o la pericolosità del copia-incolla. Forse con un po’ di esperienza in più si capiranno meglio alcuni dei problemi inerenti al codice di terze parti e come porvi rimedio.
I pro del copia-incolla
- Ci permette di trovare una soluzione alla maggior parte dei problemi online da qualche parte molto rapidamente
- Siti come StackOverflow hanno un sistema di classificazione in modo da poter essere certi che il codice che stiamo per copiare sia di migliore qualità
- Il codice scritto mesi o anni prima sappiamo che funziona, quindi non dobbiamo testarlo di nuovo
I contro del copia-incolla
- Il codice copiato da fonti esterne potrebbe avere malfunzionamenti, non abbiamo garanzie del suo funzionamento
- Probabilmente non vedremo mai miglioramenti al codice che abbiamo trovato se non controlliamo periodicamente e attivamente
- Il codice di altre persone non si adatta necessariamente ai nostri standard o modi di lavorare (sintassi, logica, pattern…)
- Il codice trovato online è in genere un caso esemplificativo che va poi “calato” sul caso specifico. Non include garanzie di sicurezza di alcun tipo
- Il codice online potrebbe contenere errori che non sono immediatamente evidenti (anche odiosi errori di sintassi che fanno perdere tempo)
Quando copiamo qualcosa scritta da qualcun altro, dovremmo almeno avere una conoscenza di base di ciò che abbiamo appena copiato. Capita spesso e volentieri, ad esempio, di essere vittime del copia-incolla a causa di codici all’apparenza giusti ma che contenevano impercettibili errori (ad esempio le virgolette errate per racchiudere una stringa). I compilatori solitamente evidenziano abbastanza rapidamente l’errore di sintassi, ma questo mostra che non controllare il codice proveniente da altrove, può far funzionare il software nella migliore delle ipotesi, ma fare qualcosa di molto diverso nella peggiore.
Un altro rischio dell’uso di codice di terzi è il relativo mantenimento del codice sparso incollato qua e la. Ogni volta che è necessario effettuare un aggiornamento a una parte del codice, si finisce per farlo in più punti; questo è un lavoro e uno sforzo extra e in realtà non dovrebbe essere così.
Hic Sunt Leones
Immaginiamo uno scenario in cui il codice copiato è più di una singola riga ed è in realtà un’intera funzione o blocco. Potrebbe anche succedere (se si da per buono il codice – si pensi ad esempio ad un listato di migliaia di righe) che quel codice contenga un cavallo di Troia. E’ anche vero che se il codice fosse disponibile su Github, la porzione malware verrebbe scovata rapidamente dalla community, ma bisogna tener presente che non tutti i progetti hanno un seguito o una folta community, quindi il malware potrebbe essere scovato in ritardo (e dopo che noi lo abbiamo utilizzato)
Qual è la soluzione?
In un mondo ideale, tutti comprenderebbero ogni riga di codice che stanno usando e tutto sarebbe perfettamente scritto per massimizzare il riutilizzo di tutto il codice condiviso. Purtroppo non viviamo in un mondo simile. Gli sviluppatori imparano il loro mestiere strada facendo e spesso si ritrovano a rimandare il factoring a causa delle scadenze strette da rispettare.
Quindi cosa possiamo davvero fare se questa è la realtà che stiamo affrontando?
La semplice risposta è fare del nostro meglio e ricordare che non siamo perfetti, cercare di mirare alla perfezione per tutto il tempo, anche se non è affatto facile. Diamo un’occhiata al codice di terze parti per vedere se c’è qualcosa di strano. Poniamoci delle domande: quella libreria dovrebbe davvero chiamare eval() in quel modo? Quelle virgolette singole e doppie sono corrette oppure è stato un errore dell’editor originale? Se stiamo copiando e incollando del codice in un nostro progetto, facciamo un passo indietro e chiediamoci: ci vorrebbe davvero tanto più tempo per ricodificarlo da capo?