Din când în când, particip la discuții cu diverși oameni despre ce este de fapt TDD de fapt. Deoarece am dobândit în timp o anumită cunoaștere a acetui subiect, care se datorează nu numai utilizării, dar și datorită faptului că îl explic altora, am hotărât să scriu acest articol care detaliază punctul meu de vedere în legătură cu ce este TDD. Sper că îl veți găsi util.
Prezentul articol îl continuă pe cel din numărul trecut al revistei Today Software Magazine pe această temă.
Noi scriem cod pentru a rezolva o problemă și folosim teste pentru a defini comportamentul așteptat al soluției. Când testele sunt trecute, o altă bucățică a problemei este soluționată. Noi tocmai am creat intenționat o bucată de cod care rezolvă o problemă. Acesta este design.
Dar oare este un design bun? Aceasta este o discuție interesantă. Pentru a răspunde la întrebare, ar trebui să ne uităm la calitățile designului, pe care TDD ne obligă să le dezvoltăm. Iată două dintre ele:
Testabilitate - evident, deoarece codul este testat.
Este asta suficient pentru a numi ceea ce rezultă din TDD un "design bun"? Cel mai probabil, răspunsul este nu. Logic este să spui:
Calitatea designului depinde de abilitățile designerului.
Dar…
Este acum momentul să introducem încă un aspect al designului software. Scrierea codului nu este suficientă; este important să structurezi codul într-un anumit mod. Cea mai puțină structurare pe care o putem face este să scriem întregul cod într-o singură metodă enormă. Computerului nu îi va păsa, dar acest lucru va afecta calitățile designului.
Atunci când face TDD, un programator trebuie să ia multe decizii cu privire la structurarea codului. Aceste decizii se pot referi la utilizarea claselor ( metodelor, variabilelor, membrilor, etc. ), la modul denumirii lucrurilor, la tipologia datelor, la maniera de colaborare a claselor. Toate acestea sunt decizii legate de design, care contribuie la calitățile sale. Denumirea unei variabile prin litera "a" o va face mai puțin lizibilă decât dacă o numim "sumăDeBani" ("amountOfMoney"). Adăugarea a 10 straturi va face codul mai dificil de înțeles decât utilizarea a numai două starturi. O clasă cu 10 colaboratori este mai dificil de înțeles decât o clasă cu trei colaboratori.
Când luăm aceste hotărâri? Întotdeauna! Mai precis:
La început. De exemplu, utilizarea unui cadru web MVC înseamnă deja să respecți anumite constrângeri legate de structura codului.
Când scrii testul: numele clasei supuse testului.
Când scrii codul: numele metodelor private, membrii de probă sau variabile locale.
Îmbunătățirea calităților designului este un proces continuu. Nu se limitează la pasul de reutilizare sau la ciclul TDD. Iar acest lucru este în regulă, deoarece, de fapt…
Incremental înseamnă că noi concepem software bucată cu bucată. Se concepe software înainte de a începe ciclurile, în timp ce scriem testul și puțin când îl reutilizăm. Acțiunea de a concepe este intenționată: noi încercăm să îmbunătățim calitățile de design care sunt relevante în contextul nostru (în mod tipic, modificabilitatea). Incremental mai înseamnă, de asemenea, că soluția crește pas cu pas, prin tăierea problemei în felii mai mici. De exemplu, pentru a rezolva o problemă care are drept input o listă de multe numere, noi pornim de la o listă goală, apoi o listă cu un număr și așa mai departe.
Acest proces este foarte asemănător cu un altul: soluționarea problemelor în general. Tocmai s-a închis cercul. Dacă design înseamnă să rezolvi probleme, iar rezolvarea problemelor se face cel mai bine în mod incremental, atunci cum putem numi mai bine TDD decât o metodă de a concepe software într-o manieră incrementală?
Cititorii mai familiarizați își vor aminti probabil că TDD a fost adesea discutat în contextul "designului emergent". Eu cred că există o problemă legată de denumirea "emergent": mulți dezvoltatori pe care i-am întâlnit au tendința să considere că "design emergent" înseamnă un design care apare din senin datorită procesului. Bineînțeles, această accepție poate crea confuzii. Eu pledez pentru utilizarea termenului "incremental" pentru o mai bună descriere a procesului.
Iar aceasta nu e tot…
Acest articol s-a concentrat pe utilizarea cea mai comună a TDD. Lucrurile sunt puțin mai complicate, deoarece există un număr surprinzător de moduri de a utiliza testele și TDD. Iată câteva exemple avansate, nici într-un caz o listă completă:
Eu am utilizat TDD, în trecut, pentru a explora alternative de design: rezolv aceeași problemă cu constrângeri diferite și compar designurile rezultate. Aceasta este o metodă de design mai complexă, deoarece explorarea alternativelor face parte din procesul general de design.
TDD poate fi utilizat pentru a învăța lucruri noi. Eu am folosit TDD cu succes pentru a preda în trecut limbajele de programare unor oameni fără pregătire în domeniu.
TDD poate fi utilizat pentru a explora spațiul problemă. De exemplu, dacă luăm Game of Life (Jocul vieții) al lui Conway, eu mă întreb: dar dacă universul s-ar schimba? Cum ar fi dacă s-ar schimba timpul? Dar dacă regulile s-ar schimba? etc. Adesea fac același exercițiu și cu aplicațiile de afaceri pe care le dezvolt. Uneori utilizez TDD pentru a explora potențialele modificări ale caracteristicilor.
Într-o altă categorie, TDD As If You Meant It (ca și cum ai fi vrut asta) este un exercițiu bazat pe TDD dar cu constrângeri suplimentare care întârzie toate deciziile legate de structurarea codului, pentru cât mai mult timp posibil. Este probabil cea mai incrementală abordare posibilă, dar poate de asemenea să ducă la un cod care nu face prea multe chiar și după 1-2 ore. Eu îl consider un exercițiu intrigant, dar nu îl utilizez niciodată în producție.
Întrebările și comentariile voastre sunt binevenite; vă rog nu ezitați să îți scrieți pe alex.bolboaca@mozaicworks.com.