Ai fost vreodată în situația în care, după ce ai încercat să identifici un bug, cel mai bun rezultat a fost: „nu se reproduce”, „merge pe mașina mea”, „nu are sens” sau „vom verifica încă o dată dacă se întâmplă din nou”?
Fiecare dezvoltator a trebuit, la un moment dat, să descifreze de ce aplicația la care lucra nu se comporta așa cum se aștepta. Indiferent de natura aplicației, există câțiva pași pe care ar trebui să-i urmezi.
De unde să începi?
Asigură-te că înțelegi pe deplin problema. Dacă este un subiect nou pentru tine, acordă-ți timp să te familiarizezi cu prerechizitele și condițiile de bază care ar putea declanșa comportamentul respectiv. Dacă nu ești atent la ele, șansele tale de succes sunt deja mici. Nu te arunca direct în cod; cele mai comune bug-uri provin din greșeli de dezvoltare. Dacă nu poți găsi sursa, s-ar putea să fii tentat să renunți din cauza grabei sau a frustrării. Dacă s-ar deschide o investigație asupra cauzei principale a problemei, cel mai probabil ar fi o problemă mai profundă.
Colectează informații
Îmi amintesc o dată că am avut o problemă cu niște inserări în bloc care eșuau din cauza unei schimbări în schemă. A fost frustrant pentru că a necesitat multă muncă manuală pentru a corecta datele corupte. Am încercat să adăugăm logare suplimentară și să izolăm operațiunea într-o tranzacție cu prioritate ridicată. Totuși, nimic nu părea să funcționeze sau să ne ofere vreo idee despre ce se întâmpla, și, desigur, problema nu putea fi reprodusă local.
Planul nostru de mentenanță, care făcea backup la jurnalele de tranzacții ale bazei de date pentru a activa și dezactiva CDC-ul pe baza de date la fiecare oră, a blocat tabelul de logare al sistemului pentru a recrea utilizatorul său, ceea ce a dus la o schimbare de schemă. Am reușit să legăm evenimentele abia după ce am făcut o altă investigație asupra unor deadlock-uri. Totuși, am învățat cu siguranță o lecție importantă: încearcă să găsești cât mai multe informații despre circumstanțele incidentului, chiar dacă par nesemnificative. Informațiile potențiale includ pași pentru a reproduce problema, loguri, data și ora, valorile resurselor, intrările/flag-urile din baza de date, activitatea din interiorul sau exteriorul aplicației și, desigur, codul.
Păstrează întotdeauna atenția asupra oricărei activități care are loc în timpul incidentului, fie că este vorba de un utilizator sau de alte procese care rulează; intercalarea thread-urilor este frecventă și dificil de diagnosticat.
Clasifică informațiile tale.
Acum că ai o mulțime de informații despre tot ce s-a întâmplat, trebuie să filtrezi datele; unele elemente s-ar putea să nu facă parte din puzzle-ul tău, așa că nu încerca să formulezi o ipoteză încă. În timp ce evaluezi înregistrările, trebuie să-ți categorizezi informațiile în grupuri: circumstanțiale, documentare, demonstrative, nesigure și dovezi obiective.
Circumstanțiale: relația dintre evenimente care ar fi putut declanșa un comportament, cum ar fi pașii necesari pentru a reproduce o problemă.
Acest tip de informație nu ar trebui luat de-a gata, deoarece se bazează pe experiența individuală (un utilizator spune că a apăsat un buton și aplicația a căzut – chiar butonul a fost cauza?). Totuși, nu o ignora! (Un utilizator a apăsat un buton care a declanșat un proces ce a intrat în deadlock undeva, iar aplicația a căzut).
Documentare: informații înregistrate într-un fel: loguri, urme (traces), monitorizarea activității. Acestea oferă o mai bună perspectivă asupra fluxului evenimentului, pe baza căruia poți deduce alte acțiuni declanșate.
Demonstrativ: dovezi care ajută la susținerea contextului altor dovezi: grafice cu înregistrări CPU/memorie (poți suspecta, de exemplu, o excepție de tip out-of-memory).
Nesigură (Unreliable): informații care se pot schimba în timp, cum ar fi o intrare în baza de date actualizată între momentul evenimentului și cel al investigației. Una dintre capcanele în care poți cădea este să-ți bazezi teoria pe informații nesigure. Cel mai probabil, acest lucru te va abate de la drumul corect.
Obiectivă (Real): o dovadă incontestabilă care indică sursa problemei: o linie de cod, o configurare greșită.
Asamblează piesele
Informațiile tale sunt acum grupate pe baza fiabilității; trebuie să le parcurgi de sus în jos pentru a identifica scenariile posibile care s-ar potrivi și să le analizezi pe fiecare.
Imaginează-ți evenimentele ca elemente individuale și notează fiecare; astfel, vei înțelege mai bine dependențele dintre ele atunci când le vei combina.
Creează o cronologie a incidentelor care au dus la un anumit comportament. Plasează dovada care susține un eveniment sub acesta pentru a crea o imagine clară a ceea ce s-a întâmplat.
Dacă problema se manifestă în mod repetitiv, reconstruiește și celelalte apariții pentru a vedea dacă poți identifica un tipar între scenarii.
Încearcă să-l reproduci
După ce ai toate circumstanțele problemei, poți încerca să o reproduci. Asigură-te că recreezi mediul cât mai exact posibil. Dacă lucrezi cu un volum mare de date, nu fi leneș și investighează elementul specific care cauzează probleme; problema ar putea fi în grup, nu la nivel individual.
Parcurge codul linie cu linie, chiar dacă ai o idee despre ce se întâmplă. Uneori, setările implicite te pot păcăli.
Dacă încă nu ai o imagine clară, nu te teme să adaugi mai multă logare și să revizuiești investigația după ce obții informații suplimentare.
Este în regulă să ceri ajutor.
Dacă te-ai chinuit zile întregi să rezolvi problema fără succes, încearcă să ceri ajutor colegilor; uneori, o pereche de ochi proaspătă sau mai experimentată poate fi de mare ajutor.
Colaborarea este cheia rezolvării problemelor!
Anti-modele pentru investigații
Geronimo: încearcă să-ți ții pașii și faptele organizate; odată ce găsești o piesă a puzzle-ului despre care crezi că este cheia problemei, nu paria totul pe ea; păstrează-ți firul logic și investighează până la capăt. Altfel, s-ar putea să ajungi la o concluzie greșită.
Găina nebună: nu alerga în toate direcțiile încercând să aduni informații de peste tot, chiar dacă sunt irelevante, doar pentru că nu ai dovezi solide; concluziile tale s-ar putea să devieze complet de la adevăr.
Păun: folosește-ți logica, nu formula o teorie înainte să începi, bazându-te doar pe experiența ta sau pe zvonuri. Altfel, ai putea vedea doar dovezile care susțin opinia ta, ignorând alte piste clare.
Leneșul: chiar dacă durează mai mult, nu presupune nimic; verifică totul cu ochii tăi; altfel, s-ar putea să ratezi adevăratul vinovat.
Pasărea cântătoare: asumă-ți investigația, nu o da altcuiva doar pentru că nu ai reușit să o rezolvi; nu este menită să fie ușoară; dacă ar fi, ar fi fost deja rezolvată.
Negatorul: nu continua presupunând că o anumită funcționalitate funcționează corect; fiecare eveniment este un suspect potențial, chiar dacă provine de la un terț.
Dar el pur și simplu știa!
Ai întâlnit vreodată pe cineva care putea „simți fumul” și să-ți spună de unde vine? Odată cu experiența vine instinctul; finalizând mai multe astfel de investigații, înveți să filtrezi mai bine informațiile și să ajungi direct la sursă.
Da, parcurgerea tuturor pașilor descriși poate fi consumatoare de timp, dar pe măsură ce exersezi acest tipar de gândire, vei ajunge la un nivel de competență, iar acesta va deveni reflex. Cu suficientă practică, vei începe să faci asta mental. Până atunci, fii meticulos și neobosit.