Non accettare di sviluppare qualcosa che non capisci

Non accettare di sviluppare qualcosa che non capisci

Dall'inizio del 2018 ricopro la posizione di capo/capo/sviluppatore capo del team - chiamatelo come volete, ma il punto è che sono interamente responsabile di uno dei moduli e di tutti gli sviluppatori che lavorano su di essa. Questa posizione mi offre una nuova prospettiva sul processo di sviluppo, poiché sono coinvolto in più progetti e più attivamente nel processo decisionale. Recentemente, grazie a queste due circostanze, mi sono improvvisamente reso conto di quanto la misura della comprensione incida sul codice e sull'applicazione.

Il punto che voglio sottolineare è che la qualità del codice (e del prodotto finale) è strettamente correlata alla consapevolezza di ciò che stanno facendo le persone che stanno progettando e scrivendo il codice.

Potresti pensare in questo momento: “Grazie, Capitano. Certo, sarebbe bello capire cosa stai scrivendo in generale. Altrimenti, potresti anche assumere un gruppo di scimmie per premere tasti arbitrari e lasciare le cose come stanno." E hai assolutamente ragione. Di conseguenza, dò per scontato che tu ti renda conto che è necessario avere un'idea generale di ciò che stai facendo. Questo può essere chiamato il livello zero di comprensione e non lo analizzeremo in dettaglio. Esamineremo in dettaglio cosa devi capire esattamente e come influisce sulle decisioni che prendi ogni giorno. Se avessi saputo queste cose in anticipo, mi avrebbe risparmiato un sacco di tempo sprecato e codice discutibile.

Anche se non vedrai una singola riga di codice di seguito, credo comunque che tutto ciò che viene detto qui sia di grande importanza per scrivere codice espressivo di alta qualità.

Primo livello di comprensione: perché non funziona?

Gli sviluppatori di solito raggiungono questo livello molto presto nella loro carriera, a volte anche senza l'aiuto di altri, almeno nella mia esperienza. Immagina di aver ricevuto una segnalazione di bug: alcune funzioni nell'applicazione non funzionano, devono essere corrette. Come procederai?

Lo schema standard è simile al seguente:

  1. Trova il pezzo di codice che causa il problema (come farlo è un argomento separato, ne parlo nel mio libro sul codice legacy)
  2. Apporta modifiche a questo snippet
  3. Assicurati che il bug sia stato corretto e che non si siano verificati errori di regressione

Ora concentriamoci sul secondo punto: apportare modifiche al codice. Esistono due approcci a questo processo. Il primo è approfondire cosa sta succedendo esattamente nel codice corrente, identificare l'errore e correggerlo. Secondo: spostati a sensazione: aggiungi, ad esempio, +1 a un'istruzione condizionale o a un ciclo, verifica se la funzione funziona nello scenario desiderato, quindi prova qualcos'altro e così via all'infinito.

Il primo approccio è corretto. Come spiega Steve McConnell nel suo libro Code Complete (che tra l'altro consiglio vivamente), ogni volta che modifichiamo qualcosa nel codice, dovremmo essere in grado di prevedere con sicurezza come ciò influenzerà l'applicazione. Sto citando a memoria, ma se la correzione di un bug non funziona come ti aspettavi, dovresti essere molto allarmato e mettere in discussione l'intero piano d'azione.

Riassumendo quanto detto, per eseguire una buona correzione del bug che non degradi la qualità del codice, è necessario comprendere sia l'intera struttura del codice che l'origine del problema specifico.

Secondo livello di comprensione: perché funziona?

Questo livello è compreso in modo molto meno intuitivo del precedente. Io, quando ero ancora uno sviluppatore alle prime armi, l'ho imparato grazie al mio capo e successivamente ho spiegato ripetutamente l'essenza della questione ai nuovi arrivati.

Questa volta immaginiamo di aver ricevuto due segnalazioni di bug contemporaneamente: la prima riguarda lo scenario A, la seconda riguarda lo scenario B. In entrambi gli scenari accade qualcosa di sbagliato. Di conseguenza, affronta prima il primo bug. Utilizzando i principi che abbiamo sviluppato per la comprensione del Livello XNUMX, si scava in profondità nel codice rilevante per il problema, si capisce perché fa sì che l'applicazione si comporti come nello Scenario A e si apportano modifiche ragionevoli che producono il risultato desiderato. . Tutto sta andando alla grande.

Quindi passi allo scenario B. Ripeti lo scenario nel tentativo di provocare un errore, ma... sorpresa! - ora tutto funziona come dovrebbe. Per confermare la tua ipotesi, annulli le modifiche apportate mentre lavoravi sul bug A e il bug B ritorna. La tua correzione del bug ha risolto entrambi i problemi. Fortunato!

Non ci avevi affatto contato. Hai trovato un modo per correggere l'errore nello scenario A e non hai idea del motivo per cui ha funzionato per lo scenario B. In questa fase, è molto forte la tentazione di pensare che entrambe le attività siano state completate con successo. Questo è abbastanza logico: il punto era eliminare gli errori, no? Ma il lavoro non è ancora finito: devi ancora capire perché le tue azioni hanno corretto l'errore nello scenario B. Perché? Perché potrebbe funzionare secondo principi sbagliati e quindi dovrai cercare un'altra via d'uscita. Ecco un paio di esempi di tali casi:

  • Poiché la soluzione non è stata adattata all'errore B, tenendo conto di tutti i fattori, è possibile che tu abbia inconsapevolmente interrotto la funzione C.
  • È possibile che ci sia anche un terzo bug in agguato da qualche parte, correlato alla stessa funzione, e la correzione del bug dipende da questo per il corretto funzionamento del sistema nello scenario B. Tutto sembra a posto ora, ma un giorno questo terzo bug verrà notato e risolto. Quindi nello scenario B l'errore si ripresenterà, ed è positivo se solo lì.

Tutto ciò aggiunge caos al codice e un giorno ti cadrà in testa, molto probabilmente nel momento più inopportuno. Dovrai raccogliere la tua forza di volontà per sforzarti di dedicare del tempo a capire perché tutto sembra funzionare, ma ne vale la pena.

Terzo livello di comprensione: perché funziona?

La mia recente intuizione si riferisce proprio a questo livello, ed è probabilmente quello che mi avrebbe dato il maggior beneficio se fossi arrivato prima a questa idea.

Per renderlo più chiaro facciamo un esempio: il tuo modulo deve essere reso compatibile con la funzione X. Non hai particolare familiarità con la funzione X, ma ti è stato detto che per essere compatibile con essa devi utilizzare il framework F. Altro i moduli che si integrano con X funzionano esattamente con lui.

Il tuo codice non è stato in contatto con il framework F dal primo giorno di vita, quindi implementarlo non sarà così semplice. Ciò avrà gravi conseguenze per alcune parti del modulo. Tuttavia, ti butti nello sviluppo: passi settimane a scrivere codice, testare, lanciare versioni pilota, ottenere feedback, correggere errori di regressione, scoprire complicazioni impreviste, non rispettare le scadenze originariamente concordate, scrivere altro codice, testare, ricevere comunicazioni di feedback, correggere gli errori di regressione: tutto questo per implementare il framework F.

E ad un certo punto all'improvviso ti rendi conto - o forse senti qualcuno - che forse il framework F non ti darà affatto compatibilità con la funzionalità X. Forse tutto quel tempo e quegli sforzi sono stati investiti in modo completamente sbagliato.

Qualcosa di simile è successo una volta mentre lavoravo a un progetto di cui ero responsabile. Perché è successo questo? Perché avevo poca comprensione di quale fosse la funzione X e di come fosse correlata al framework F. Cosa avrei dovuto fare? Chiedi alla persona che assegna l'attività di sviluppo di spiegare chiaramente come la linea di condotta prevista porta al risultato desiderato, piuttosto che limitarsi a ripetere ciò che è stato fatto per altri moduli o credergli sulla parola che questo è ciò che la funzionalità X deve fare.

L'esperienza di questo progetto mi ha insegnato a rifiutarmi di iniziare il processo di sviluppo finché non avremo una chiara comprensione del motivo per cui ci viene chiesto di fare determinate cose. Rifiutare apertamente. Quando ricevi un incarico, il primo impulso è quello di assumerlo subito per non perdere tempo. Ma la politica di “congelare il progetto finché non entriamo in tutti i dettagli” può ridurre le perdite di tempo di ordini di grandezza.

Anche se cercano di farti pressione, di costringerti a iniziare a lavorare, anche se non ne capisci il motivo, resisti. Per prima cosa, scopri perché ti è stato assegnato un compito del genere e decidi se questa è la strada giusta verso l'obiettivo. Ho dovuto imparare tutto questo nel modo più duro: spero che il mio esempio renderà la vita più facile a coloro che leggono questo.

Quarto livello di comprensione: ???

C'è sempre altro da imparare nella programmazione e credo di aver solo scalfito la superficie dell'argomento della comprensione. Quali altri livelli di comprensione hai scoperto negli anni di lavoro con il codice? Quali decisioni hai preso che hanno avuto un impatto positivo sulla qualità del codice e dell'applicazione? Quali decisioni si sono rivelate sbagliate e ti hanno insegnato una lezione preziosa? Condividi la tua esperienza nei commenti.

Fonte: habr.com

Aggiungi un commento