Nu acceptați să dezvoltați ceea ce nu înțelegeți

Nu acceptați să dezvoltați ceea ce nu înțelegeți

Din începutul anului 2018, ocup funcția de lead/șef/dezvoltator principal în echipă — numiți-o cum doriți, dar esența este că sunt complet responsabil pentru unul dintre module și pentru toți dezvoltatorii care lucrează la el. Această poziție îmi oferă o nouă perspectivă asupra procesului de dezvoltare, deoarece sunt implicat în mai multe proiecte și particip mai activ la luarea deciziilor. Recent, datorită acestor două circumstanțe, am realizat brusc cât de mult măsura înțelegerii influențează codul și aplicația.

Gândul pe care vreau să-l exprim se reduce la faptul că calitatea codului (și a produsului final) este strâns legată de cât de conștienți sunt cei care proiectează și scriu codul de ceea ce fac.

Poate vă gândiți acum: „Mulțumesc, căpitan. Desigur, ar fi bine să înțelegem ce scriem. Altfel, la fel de bine am putea angaja un grup de maimuțe ca să lovească la întâmplare tastele și să ne liniștim.” Și aveți perfectă dreptate. Așadar, accept ca dat fiind că înțelegeți că a avea o viziune generală despre ceea ce faceți este esențial. Acesta poate fi numit nivelul zero de înțelegere, iar acesta nu îl vom analiza în detaliu. În detaliu ne vom ocupa de ceea ce trebuie să înțelegem și cum aceasta influențează deciziile pe care le luați în fiecare zi. Dacă aș fi știut aceste lucruri dinainte, m-ar fi salvat de o mulțime de timp pierdut și cod îndoielnic.

Deși nu veți vedea niciun rând de cod mai jos, consider totuși că tot ceea ce s-a spus aici are o mare importanță pentru scrierea unui cod de calitate, expresiv.

Primul nivel de înțelegere: De ce nu funcționează?

De obicei, la acest nivel dezvoltatorii ajung în cele mai timpurii etape ale carierei lor, uneori chiar fără nicio ajutor din partea celor din jur — cel puțin, după observațiile mele. Imaginează-ți că ai primit un raport de bug: o funcție din aplicație nu funcționează, trebuie să o repari. Ce vei face?

Schema standard arată astfel:

  1. Găsește fragmentul de cod care provoacă problema (cum se face acest lucru este un subiect separat, pe care îl discut în cartea mea despre codul învechit)
  2. Fă modificări în acest fragment
  3. Asigurați-vă că bug-ul a fost corectat și că nu au apărut erori de regresie

Acum să ne concentrăm asupra celui de-al doilea punct – modificarea codului. Există două abordări pentru acest proces. Prima: a înțelege exact ce se întâmplă în codul curent, a identifica bug-ul și a-l corecta. A doua: a merge pe întuneric – să adaugi, de exemplu, +1 într-un operator condițional sau într-un ciclu, să vezi dacă funcția a început să funcționeze în scenariul dorit, apoi să încerci și altceva, și tot așa la nesfârșit.

Corect este prima abordare. Așa cum explică în cartea sa Code Complete Steve McConnell (pe care, de altfel, o recomand cu căldură), de fiecare dată când facem o modificare în cod, trebui să fim capabili să prezicem cu încredere cum va afecta această modificare aplicația. Îmi amintesc o citat, dar dacă bug fix-ul nu funcționează așa cum te aștepți, ar trebui să te îngrijoreze foarte mult, trebuie să pui la îndoială întregul tău plan de acțiune.

Rezumând, pentru a realiza un bug fix de calitate, care să nu afecteze negativ calitatea codului, este necesar să înțelegi atât întreaga structură a codului, cât și sursa problemei specifice.

Al doilea nivel de înțelegere: De ce funcționează?

Acest nivel este înțeles mult mai puțin intuitiv decât precedentul. Eu, fiind un dezvoltator începător, l-am învățat de la șeful meu și ulterior am explicat esența acestui concept de nenumărate ori începătorilor.

De data aceasta, să ne imaginăm că ai primit două rapoarte de bug-uri: primul se referă la scenariul A, iar al doilea - la scenariul B. În ambele scenarii se întâmplă ceva în neregulă. Așadar, începi mai întâi cu primul bug. Conducându-te după principiile pe care le-am derivat pentru primul nivel de înțelegere, te aprofundezi în codul relevant problemei, descoperi de ce acesta determină aplicația să se comporte astfel în scenariul A și faci modificările raționale necesare, care oferă exact rezultatul pe care l-ai așteptat. Totul decurge excelent.

Apoi treci la scenariul B. Repeți scenariul în încercarea de a provoca eroarea, dar - surpriză! - acum totul funcționează așa cum trebuie. Pentru a-ți confirma intuiția, anulezi modificările făcute în timpul lucrului la eroarea A, iar bug-ul B revine din nou. Fixul tău a rezolvat ambele probleme. Ai avut noroc!

Nu v-ați așteptat deloc la asta. Ați găsit o modalitate de a corecta eroarea din scenariul A și nu aveți idee de ce a funcționat și pentru scenariul B. În această etapă, tentația de a concluziona că ambele sarcini au fost îndeplinite cu succes este foarte mare. Este logic: până la urmă, scopul a fost să eliminați erorile, nu-i așa? Dar munca nu este încă terminată: trebuie să înțelegeți de ce acțiunile dumneavoastră au corectat eroarea din scenariul B. De ce? Pentru că există posibilitatea ca acesta să funcționeze pe principii greșite, iar atunci va trebui să căutați o altă soluție. Iată câteva exemple de astfel de cazuri:

  • deoarece soluția nu a fost adaptată specific pentru eroarea B, luând în considerare toți factorii, este posibil să fi stricat fără să vă dați seama funcția C.
  • nu este exclus ca undeva să se ascundă și o a treia eroare, legată de aceeași funcție, iar corectarea dumneavoastră leagă funcționarea corectă a sistemului în scenariul B de aceasta. Acum totul pare bine, dar într-o zi frumoasă, această a treia eroare va fi observată și corectată. Atunci, în scenariul B va apărea din nou o eroare, și bine că doar acolo.

Toate acestea aduc haos în cod și, într-o bună zi, se vor răzbuna asupra dumneavoastră — cel mai probabil în momentul cel mai nepotrivit. Va trebui să adunați voință pentru a vă obliga să petreceți timp înțelegând de ce totul pare că funcționează, dar merită.

Al treilea nivel de înțelegere: De ce funcționează?

Recenta mea revelație este legată exact de acest nivel și, probabil, acesta mi-ar fi oferit cele mai mari avantaje dacă aș fi ajuns la această idee mai devreme.

Pentru a fi mai clar, să analizăm un exemplu: modulul dumneavoastră trebuie să fie compatibil cu funcția X. Nu sunteți foarte familiarizat cu funcția X, dar vi s-a spus că pentru compatibilitate, trebuie să folosiți framework-ul F. Alte module care se integrează cu X funcționează exact cu acesta.

Codul tău nu a avut nicio interacțiune cu framework-ul F de la începutul său, așa că implementarea acestuia nu va fi chiar simplă. Aceasta va avea consecințe serioase asupra unor componente ale modulului. Cu toate acestea, te dedici complet dezvoltării: săptămâni întregi scrii cod, testezi, lansezi versiuni pilot, primești feedback, corectezi erori de regresie, descoperi complicații neprevăzute, nu te încadrezi în termenele inițiale, scrii și mai mult cod, testezi, primești feedback, corectezi erori de regresie - toate acestea pentru a implementa framework-ul F.

Și într-un moment dat, îți dai seama - sau, poate, auzi de la cineva - că, poate, framework-ul F nu îți va oferi compatibilitate cu funcția X. Poate toate aceste timp și efort au fost direcționate în direcția greșită.

Ceva similar s-a întâmplat odată în timpul lucrului la un proiect pentru care eram responsabil. De ce s-a întâmplat așa? Pentru că nu înțelegeam bine esența funcției X și cum se leagă de framework-ul F. Ce ar fi trebuit să fac? Să cer unei persoane care definește sarcinile de dezvoltare să explice clar cum planul de acțiune preconizat duce la rezultatul dorit, în loc să repet ceea ce s-a făcut pentru alte module sau să cred pe cuvânt că așa trebuie pentru funcționarea funcției X.

Experiența acestui proiect m-a învățat să refuz să încep procesul de dezvoltare până când nu avem o înțelegere clară despre ce ne cer să facem. Să refuz direct. Atunci când primești o sarcină, primul impuls este să te apuci imediat de ea pentru a nu pierde vremea. Dar politica de 'înghețare a proiectului, până ne clarificăm toate detaliile' poate reduce timpul pierdut semnificativ.

Chiar și atunci când cineva încearcă să te preseze, să te oblige să începi să lucrezi fără să înțelegi motivele, rezistă. Începe prin a înțelege ce scop are sarcina respectivă și decidă dacă este calea corectă spre scop. A trebuit să învăț toate acestea din experiență amară - sper că exemplul meu va ușura viața celor care citesc aceste rânduri.

Nivelul patru de înțelegere: ???

În programare, există întotdeauna ceva de învățat, iar eu cred că doar am atins suprafața subiectului înțelegerii. Ce alte niveluri de înțelegere ați descoperit de-a lungul anilor de lucru cu codul? Ce decizii ați luat care au avut un impact pozitiv asupra calității codului și aplicației? Ce decizii s-au dovedit a fi greșite și v-au oferit o lecție valoroasă? Împărtășiți-vă experiența în comentarii.

Sursa: habr.com

Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS 🔥 Cumpără un hosting fiabil pentru site-uri cu protecție DDoS, servere VPS VDS | ProHoster