Come posso evitare di causare errori nel software quando correggo bug non correlati? [duplicare]

48

Sono uno stagista di software e mi vengono assegnati bug da correggere oltre a funzioni da aggiungere al software. Quando aggiungo funzionalità, tutto funziona bene. Il mio problema è più con la risoluzione dei bug. Sto lavorando su un codebase estremamente ampio (con milioni di righe) con una documentazione scarsa (non ci sono commenti, tonnellate di numeri magici, accoppiamento stretto tra classi diverse, ecc.). L'unica documentazione fornita è un documento Word di 8 o più pagine. Ma mi sento ancora come se potessi fare un lavoro migliore con il bug fixing.

Darò un esempio di una situazione che ho riscontrato, che mi sento come se avessi potuto fare meglio in:

  • Mi è stato assegnato un bug per correggere i calcoli di estensioni per un tipo specifico di oggetto (grafica computerizzata)
  • Ho trovato il problema con il bug e il motivo per cui è stato causato. Poiché il programma popolava una struttura dati (array contiguo) con memoria che rappresentava un punto cartesiano 3D che apparentemente non avrebbe dovuto avere (pertanto questo punto verrebbe utilizzato nei calcoli di estensione).
  • Il bug è stato effettivamente causato da questo. TUTTAVIA, un altro pezzo di codice (in una classe diversa) ha usato l'aritmetica del puntatore per ottenere questo punto e usarlo per un'altra funzione, per fare in modo che il mouse si agganci vicino a questo punto quando è stata abilitata una determinata funzione nel software. Tuttavia, da quando ho rimosso il punto, ho risolto il bug che mi era stato assegnato ma ha causato un altro bug nel software.

Che cosa posso fare per evitare che accadano cose del genere? Come posso migliorare? C'è qualche processo che mi manca?

    
posta Jason 14.09.2017 - 05:23
fonte

7 risposte

71

Non puoi essere l'unico responsabile di questi tipi di difetti. Sei umano, ed è impossibile pensare a sistemi di grandi dimensioni nel loro insieme.

Per aiutare a prevenire "bug di regressione" - bug che vengono involontariamente creati durante la modifica del sistema, puoi fare quanto segue:

  • Sviluppa una suite completa di test di regressione automatizzati. Speriamo che il tuo sistema abbia una vasta gamma di test. Ogni volta che viene scoperto un bug nel tuo sistema, dovresti scrivere un test automatico che riproduca il bug. Quindi correggi il bug. Se il sistema regredisce, il tuo "test di regressione" si interromperà e notificherà lo sviluppatore.
  • Ispeziona il codice. Ogni volta che risolvi un bug, è una buona idea ispezionare gli usi della funzione che hai modificato per cercare di identificare eventuali modifiche irrisolte che hai introdotto
  • Scrivi altri test. Se durante l'ispezione del codice, identifichi un codice che non è coperto da test automatici, questa è una buona opportunità per aggiungerne alcuni.
  • Familiarizza con il sistema e lavora con il software da molto tempo. La pratica rende perfetti. Nessuno si aspetta che uno sviluppatore non introduca bug in un sistema nuovo di zecca o quando è uno stagista. L'abbiamo fatto tutti.
risposta data 14.09.2017 - 05:42
fonte
10

Non puoi eliminarlo completamente. Ecco alcuni passaggi per ridurre l'impatto e ridurre la probabilità:

  1. Aggiungi un test unitario e un test di regressione per la funzionalità o il bug che stai modificando o correggendo. Se non si dispone di alcuna infrastruttura di testing o configurazione del cablaggio per il proprio progetto, configurarlo in modo tale che sia la parte del processo. Ciò migliorerà le cose nel tempo.
  2. Migliora la progettazione del codice in modo che il codice sia più facilmente accoppiato. Ciò significa che seguire l'SRP significa anche sacrificare alcuni ASCIUTTI. In particolare, nei sistemi OOP il tuo codice e i tuoi dati dovrebbero essere nella stessa classe e i dati dovrebbero sempre essere privati. Se ciò non ha senso, c'è un disadattamento di impedenza tra il dominio del problema e il progetto. Non dovrebbe essere possibile per un cambiamento nella struttura dei dati in una classe influenzare il comportamento di un'altra classe.
  3. Parla con i tuoi colleghi della tua proposta di correzione. Questo potrebbe assumere la forma di revisioni del codice, ma a volte questo non accetterà le regressioni. Le revisioni del codice non servono di solito a catturare insetti. Come corollario, assicurati che il resto del team sia a conoscenza delle modifiche che stai apportando e dia loro il tempo di darti un feedback su quali altre parti del sistema potrebbero fare affidamento sul codice. Fai questo anche se sei la persona più anziana del team.

Spero che questo aiuti.

    
risposta data 14.09.2017 - 05:55
fonte
8

Ci sono molti buoni suggerimenti in altre risposte. Vorrei aggiungerli: la tua organizzazione probabilmente ha un problema a livello di gestione.

  • La gestione può dare la priorità a un nuovo lavoro di funzionalità rispetto all'indebitamento. Il bug che hai citato è la prova che le passate cattive pratiche rendono oggi più costoso lo sviluppo di software privo di bug. Raccogli punti di dati come questi per informare la direzione che c'è un problema in corso causato da indebitamento senza indirizzo e che sarebbe saggio pianificare un "traguardo di qualità" in cui non sono state aggiunte nuove funzionalità, ma il debito esistente è diminuito.

  • La gestione è probabilmente ignorante della portata del problema. Gli strumenti di analisi statica che individuano i bug reali sono costosi, ma sono molto più economici di quelli falliti sul mercato perché avete spedito software che perde i dati dell'utente. Un buon analizzatore statico ti dirà che hai decine di migliaia di bug non indirizzati, dove sono e come risolverli. Ciò ti consente di ottenere un controllo sulla dimensione del problema e sulla velocità con cui lo stai attenuando.

risposta data 14.09.2017 - 13:45
fonte
5

In the matter of reforming things, as distinct from deforming them, there is one plain and simple principle; a principle which will probably be called a paradox. There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, “I don’t see the use of this; let us clear it away." To which the more intelligent type of reformer will do well to answer: "If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it."

- G.K. Chesterson

Oltre a tutte le altre idee raccolte qui, un'altra cosa preziosa da fare è scoprire come e perché è stato introdotto un bug. Supponendo che il tuo team utilizzi Git o un sistema di controllo del codice simile, strumenti come git blame o il pulsante Blame di GitHub possono essere d'aiuto. Una volta identificata la riga o le righe di codice errate che hanno causato il bug, utilizza i tuoi strumenti di controllo del codice sorgente per scoprire quando è stato aggiunto, da chi e come parte di un cambiamento più ampio.

Ogni volta che correggo un bug, provo a scrivere sul bug tracker dell'organizzazione un narrativo di come penso che il bug sia esistito. A volte si tratta di una storia stupida e un po 'imbarazzante come "Sembra che Bob abbia commentato la riga 96 a scopo di test, lo abbia commesso accidentalmente nel commit 5ab314c, e si è fuso perché stavamo correndo per far funzionare Frobnicator e non stavamo rivedendo roba propriamente questa settimana. " Ancora, imparando che è buono , al punto che stai risolvendo il bug, perché ti rassicura che probabilmente non c'è una buona ragione per il codice sii il modo in cui è e ti consente di risolverlo con maggiore sicurezza. Ma a volte si approfondisce il git blame e si scopre che la linea di codice "ovviamente rotta" che si stava per modificare è stata introdotta in un commit che si propone di correggere qualche altro bug che non si pensato, e all'improvviso ti rendi conto che la tua "correzione" sta andando a fare qualche danno e che devi fare qualcosa di più intelligente.

Naturalmente, come notano molte altre risposte qui, sarebbe bello se lo sviluppatore precedente si fosse lasciato alle spalle un test che avrebbe fallito se avessi reintrodotto in modo ingenuo un vecchio bug - una sorta di avvertimento automatico che la barriera che stai per abbattere ha uno scopo che non puoi vedere. Ma non puoi controllare quanti test hanno scritto i precedenti sviluppatori del tuo codebase, perché quello è il passato; approfondire la storia del codice è una delle poche tecniche disponibili per te al momento di correggere un bug esistente per ridurre il rischio di rompere le cose.

    
risposta data 14.09.2017 - 15:26
fonte
1

"another piece of code (in a different class) used pointer arithmetic to get this point and use it for another feature, to make the mouse snap near this point when a certain feature in the software was enabled."

Sì, ti è stata consegnata una base di codice ad alta manutenzione. Sembra che in questo caso piuttosto che un normale accoppiamento tra oggetti con interfacce evidenti ci sia stata una "magia" in corso, che ovviamente ha smesso di funzionare non appena è stata cambiata.

Non c'è trucco magico per questo. Molte tecniche di sviluppo software si concentrano sulla gestione della complessità al fine di rendere possibile individuare quale sarà l'impatto di un cambiamento - ma non sono stati seguiti qui . Questa è colpa dei precedenti sviluppatori e degli anziani che supervisionavano il progetto.

    
risposta data 14.09.2017 - 13:21
fonte
1

Lavoro anche su una fragile applicazione legacy. Il mio obiettivo numero uno per ogni cambiamento è "non rompere nulla che in precedenza funzionava". (L'obiettivo numero due è che l'utente deve essere in grado di terminare il proprio lavoro, anche se diventa un po 'goffo o si deve invocare qualche soluzione alternativa, non possono rimanere assolutamente bloccati in qualsiasi punto.)

  1. C'è un libro, che funziona in modo efficace con Legacy Code di Michael Feathers. È abbastanza utile, ma ti avvertirò che è al 100% circa l'aggiunta di test automatici. È tecnicamente sempre possibile (e spiega come farlo per un sacco di situazioni difficili) ma non è sempre praticabile dal punto di vista del business. Il libro è anche utile perché ha delle piccole barre laterali divertenti su come le cose cattive possono arrivare.
  2. Tentissima ispezione manuale di tutto ciò che tocca il punto di svolta. Se hai cambiato due funzioni, foo e bar, esegui una ricerca full text sull'intera base di codice (hai TUTTO estratto, giusto?) Per le parole foo e bar. (Nota, vorrai diventare un utente esperto di alcuni strumenti di ricerca come grep.) È importante non cercare di semplificare questa ricerca ... non cercare solo nei file Java, perché la tua funzione può essere chiamata usando la riflessione da qualcosa avviato in qualche front-end JavaScript ... solo un esempio. Mantieni il back-tracking fino a quando non hai completamente testato tutto ciò che chiama la tua modifica.
  3. Invertire la tua tecnica di ricerca e cercare di trovare punti nella tua applicazione facendo la stessa cosa senza chiamare il tuo punto di svolta. Cerca il codice copiato e incollato o la stessa cosa-fatto-due-modi e assicurati di aver cambiato tutti i punti che dovevano essere cambiati. (Quindi ripetere il passaggio precedente.)

Sembra un po 'orribile, ma queste applicazioni legacy difficili da mantenere sono in genere ancora in circolazione e vengono aggiornate perché stanno facendo qualcosa di importante e qualcuno ha davvero bisogno che funzioni. Cerca di trarre qualche soddisfazione da questo.

    
risposta data 15.09.2017 - 00:30
fonte
0

Potresti rifattorizzare il codice per nascondere l'accesso diretto a quel membro specifico e aggiungere un accessorio. In questo modo si interromperà qualsiasi codice che si basi sull'accesso diretto al membro, in modo che tu conosca ogni posizione che lo utilizza.

Come bonus, trasferisci il membro e riempi la sua posizione precedente con garbage - questo interromperà il codice che lo accede tramite l'aritmetica del puntatore.

Come sviluppatore, vuoi che il tuo codice si interrompa presto, interrompi spesso. "Funziona al 99,99% o il tempo" è molto peggio per il bug fixing di "non funziona affatto".    (ovviamente, per il codice di produzione, non vuoi "interrompere presto, interrompere spesso")

    
risposta data 14.09.2017 - 09:44
fonte

Leggi altre domande sui tag