I principi di sviluppo del software sono un insieme di regole specifiche e raccomandazioni che gli ingegneri dovrebbero seguire durante l’implementazione del programma se vogliono scrivere codice bello, chiaro e mantenibile. Non esiste una bacchetta magica che possa trasformare un’accozzaglia di variabili, classi e funzioni in codice perfetto, ma ci sono alcuni consigli e suggerimenti che possono aiutare un ingegnere a determinare se sta facendo la cosa giusta.
Diamo un’occhiata a queste raccomandazioni di base. Alcuni dei principi qui sotto sono specifici di Python, ma la maggior parte no.
Misura due volte e taglia una volta
Penso che questo sia il principio più importante di tutti. Se imparate un solo principio da questo post, dovrebbe essere questo. Noi, sviluppatori/architetti/manager lottiamo con la mancanza di attenzione, errori stupidi e refusi, problemi personali, cattivo umore e caffè freddo. Niente di tutto questo è rilevante – il problema deve essere risolto. Per me come ingegnere, questo principio significa scegliere la giusta soluzione al problema, scegliere il giusto approccio al problema, scegliere gli strumenti giusti per risolvere il problema, fiducia nella soluzione costruita. Scegliere qui significa metterci del pensiero, trovare le risorse necessarie, mettere insieme la squadra giusta, pensare al design, pensare all’approccio, impostare i compiti, controllare il risultato e assumersi la responsabilità di questo. Questo è “Ingegneria così com’è”. Penso che io stesso non sono pronto a descriverlo con parole corrette.
Don’t Repeat Yourself (DRY)
È un principio piuttosto semplice ma molto utile che dice che ripetere la stessa cosa in posti diversi è una cattiva idea. Prima di tutto, è legato alla necessità di ulteriore supporto e modifica del codice. Se qualche frammento di codice è duplicato in diversi posti all’interno di un programma, c’è un’alta probabilità di due situazioni catastrofiche:
- Quando si fanno anche piccole modifiche al codice sorgente, è necessario cambiare lo stesso codice in diversi posti. Richiederà tempo, sforzo e attenzione aggiuntivi (spesso non è facile).
- Il primo punto segue il secondo. Tu o un altro sviluppatore del tuo team potreste accidentalmente perdere uno dei cambiamenti (può accadere semplicemente unendo i rami in vcs) e affrontare i successivi bug nell’applicazione. Questi bug possono essere frustranti per te perché hai sentito che tale bug è già stato risolto.
A questo proposito, c’è una raccomandazione – se qualsiasi codice si trova nell’elenco più di due volte, dovrebbe essere messo in un modo separato. Questa è una raccomandazione generale. Infatti, dovreste pensare a creare un metodo separato anche se incontrate una ripetizione una seconda volta.
Rasoio di Occam
È un’idea molto comune, che è arrivata alla programmazione dalla filosofia. Il principio ha preso il nome dal monaco inglese William of Oakham. Questo principio dice: “Le entità non devono essere moltiplicate senza necessità”. In ingegneria, questo principio è interpretato come segue: non c’è bisogno di creare entità inutili senza necessità. Così, è sempre una buona idea pensare prima ai benefici dell’aggiunta di un altro metodo/classe/strumento/processo, ecc. Dopo tutto, se si aggiunge un altro metodo/classe/strumento/processo ecc. e non si ottiene nessun vantaggio se non una maggiore complessità, qual è il punto?
Keep It Simple Stupid (KISS)
Questo è un principio molto simile al precedente, ma ha un significato leggermente diverso. Questo principio dice che il codice deve essere il più semplice possibile senza strutture complesse, altrimenti complicherà il debug e la manutenzione del codice. Inoltre, sarà più difficile per un altro programmatore capire la logica del codice, che a sua volta richiederà anche tempo e sforzi aggiuntivi. Ecco perché dovreste sempre cercare di usare costrutti semplici che risolvano il problema il più possibile senza numerosi rami, nidificazione profonda e strutture di classe eccessivamente sovraccaricate. Facendo questo, renderete la vita più facile a voi stessi e ai vostri colleghi, perché la complessità genera bug. Ricordate cosa disse Peter Hintiens: “La semplicità è sempre meglio della funzionalità”.
You Aren’t Gonna Need It (YAGNI)
Un problema di cui soffrono molti programmatori. Il desiderio di implementare in una sola volta tutte le funzionalità necessarie (e a volte anche non necessarie) fin dall’inizio del progetto. Cioè, quando uno sviluppatore aggiunge tutti i metodi possibili alla classe fin dall’inizio e li implementa, e potrebbe anche non usarli mai in futuro. Quindi, secondo questa raccomandazione, prima di tutto, implementate solo ciò di cui avete bisogno, e più tardi, se necessario, estendete la funzionalità. In questo modo, risparmierete sforzi, tempo e nervi per il debugging del codice che non è realmente necessario.
Grande progettazione in anticipo
Prima di iniziare a sviluppare funzionalità, dovreste prima pensare all’architettura dell’applicazione e progettare l’intero sistema fino a dettagli sufficientemente piccoli, e solo dopo procedere all’implementazione secondo un piano predefinito. Il principio ha il diritto di esistere, ma ultimamente, ci sono state parecchie critiche nei suoi confronti. Si tratta prima di tutto dell’obsolescenza del piano durante la progettazione e l’elaborazione. A questo proposito, è necessario fare ancora i cambiamenti successivi. Ma ha anche innegabili vantaggi, in una corretta progettazione, è possibile ridurre notevolmente il costo di un ulteriore debugging e correzione degli errori. Inoltre, tali sistemi informativi, di regola, sono più laconici e architettonicamente corretti.
Evitare l’ottimizzazione prematura
“L’ottimizzazione prematura è la radice di tutti i mali (o almeno la maggior parte di essi) nella programmazione” – Donald Knuth
L’ottimizzazione è un processo molto corretto e necessario per accelerare il programma e per ridurre il consumo di risorse del sistema. Ma ogni cosa ha il suo tempo. Se l’ottimizzazione viene effettuata nelle prime fasi dello sviluppo, può fare più male che bene. Prima di tutto, è legato al fatto che lo sviluppo di un codice ottimizzato richiede più tempo e sforzi per lo sviluppo e il supporto. In questo caso, molto spesso si deve verificare all’inizio la correttezza dell’approccio di sviluppo scelto. Ecco perché all’inizio è più vantaggioso usare un approccio semplice ma non ottimale. E più tardi, quando si stima quanto questo approccio rallenta il lavoro di un’applicazione, passare a un algoritmo più veloce o che richiede meno risorse. Inoltre, finché si implementa inizialmente l’algoritmo più ottimale, i requisiti possono cambiare e il codice andrà nella spazzatura. Quindi non c’è bisogno di perdere tempo in ottimizzazioni premature.
Principio del minimo stupore
Questo principio significa che il tuo codice dovrebbe essere intuitivo e ovvio, e non sorprendere un altro sviluppatore quando rivede il codice. Per esempio, se il metodo si chiama “fare i biscotti” ma si ottengono patate come risultato, quel codice è cattivo (ovviamente). Inoltre, dovresti cercare di evitare gli effetti collaterali e documentarli se non puoi evitarli.
S.O.L.I.D.
“SOLID” è in realtà un gruppo di principi di progettazione orientati agli oggetti. Ogni lettera in “SOLID” rappresenta uno dei principi, che sono:
- La responsabilità singola afferma che ogni modulo o classe dovrebbe avere la responsabilità per una singola parte della funzionalità fornita dal software e che la responsabilità dovrebbe essere interamente incapsulata dalla classe;
- L’aperto-chiuso afferma che le entità software (classi, moduli, funzioni, ecc.) dovrebbero essere aperte per l’estensione, ma chiuse per la modifica;
- La sostituzione di Liskov afferma che la classe ereditata dovrebbe completare, non sostituire, il comportamento della classe base;
- La segregazione dell’interfaccia afferma che nessun client dovrebbe essere costretto a dipendere da metodi che non usa;
- L’inversione della dipendenza dice che il programmatore dovrebbe lavorare a livello di interfaccia e non a livello di implementazione.
Applicati insieme, questi principi aiutano uno sviluppatore a creare codice che è facile da mantenere ed estendere nel tempo.
Legge di Demetra
L’idea di base di questo principio è di dividere le aree di responsabilità tra le classi e incapsulare la logica all’interno di una classe, metodo o struttura. Da questo principio si possono distinguere diverse raccomandazioni:
- Le classi o entità dovrebbero essere indipendenti
- Si dovrebbe cercare di ridurre il numero di connessioni tra classi diverse (il cosiddetto accoppiamento).
- Le classi associate devono essere in un modulo/pacchetto/directory (noto anche come coesione.
Seguendo questi principi, l’applicazione diventa più flessibile, comprensibile e facile da mantenere.
Conclusione
Compagni sviluppatori, siamo ingegneri! Pensiamo a progettare e costruire sistemi robusti e ben implementati, piuttosto che crescere mostri organici. I principi elencati sono altamente correlati e collegati nella loro essenza. Certo, non li ho creati io, ma un piccolo promemoria non fa male, almeno la mia memoria non è sicuramente perfetta.
Libri consigliati
- Clean Code di Robert C. Martin
- Clean Architecture di Robert C. Martin