Adoptarea TDD in php/javascript

ARGH!!! … Login cu github nu merge. Nu pot mentiona mai mult de 2 useri … WTH? E un forum pentru developeri si geeks sau pentru maimute? C’mon guys! Mi-am modificat postul sa nu fiti cu arond in fata … ca altfel nu mi-l accepta.


Bine v-am gasit. Iata ca cineva de aici era o conexiune de LinkedIn cu mine si am fost invitat sa particip la forum.

In primul rand ma simt onorat ca se doreste opinia mea chiar si in cercuri de oameni pe care nu-i cunosc. Multumesc pentur asta.

Intr-ucat intru cu o mica intarziere in poveste, voi incerca sa dau cu parerea la mai multe posturi de acici:

@AdrianBasalic
Clientul plateste produsul final. Daca tu il faci mai repede si cu mai putine bug-uri folosind TDD in timp ce stai intr-o mana cu capul in jos in 20cm apa rece ca gheata … clientului nu-i va pasa. Depinde si de tine, evident, sa iti dai seama cum sa vinzi un produs final si nu o activitate de programare.

@iamntz
Nu pot exista tutoriale atot-cuprinzatoare. Eu sunt atat scriitor cat si trainer pe tutsplus. Aproape tot timpul incerc sa foloses exemple cat mai apropiate de realitate, vezi doar ultima serie de refactoring de exemplu. https://tutsplus.com/authors/patkos-csaba
Acum nu stiu exact acel curs la care ai dat tu link, dar seria mea scrisa despre SOLID a avut foarte mare succes. De asemenea, primul meu curs video cu Agile Design Patterns este si acum unul foarte vizionat.

Cand e vorba de testare JavaScripts si cand crezi ca metodle de jQuery sunt naiv de testat, iti recomand sa te uiti la seria de filme de la James Shore http://www.letscodejavascript.com Iti garantez ca iti vei schimba total parerea despre testing in JS.

@msd
Documentatie si requirements complicate? Caz perfect, aproape ideal pentru TDD. Poate nu in stilul lui Uncle Bob, ci mai degraba in stilul lui Nat Price asa cum este descris in Growing Object Oriented Software Guided by Tests (Goos). Ati putea incerca sa transformati acele documentatii in teste. Imaginizea-ti cat de mult v-ar ajuta. In primul v-ar forta sa inelegeti ce vrea documentatia. Dupa acea v-ar forta sa va dati seama daca intr-adevar se poate implementa. Iar in final v-ar forta sa scrieti exact codul ce va trebuie ca sa se intample cerintele din documente.

@iamntz
Cat despre cursurile scrise sau video in limba romana, daca cineva e dispus sa ma plateasca cel putin cat iau pe ele de la NetTuts, cu cea mai mare placere.
Pentru cei care doresc insa sa isi ofere timpul voluntar in a traduce articole scrise in alte limbi, exista un proiect in acest sens pe NetTuts. Este pur voluntar, fara plata. Daca va intereseaza va pot pune in contact cu proiectul respectiv.

“TDD nu presupune să rulezi testele rapid și constant?” Asta este doar un side-effect. TDD presupune sa iti construiesti design-ul codului asa cum iti sugereaza testele. Sa te lasi ghidat de teste, sa decizi doar cand esti fortat de teste. Sa ai asa de mare incredere in testele tale incat sa le lasi pe ele sa decida ce cod e de scris.

@IonutBajescu
Felicitari, tu faci “test first development”. Este un lucru bun, dar nu este TDD. Vezi ce am speicifat mai sus.

4 Likes

@patkoscsaba: Nu știam că nu funcționează auth cu github. Îmi cer scuze, voi investiga mâine dimineață.
Nu puteai menționa mai mult de doi utilizatori pentru că așa era setat pentru utilizatorii noi (am remediat problema) .

Edit: maimuțicile noastre zic că auth cu github merge făra probleme :monkey_face:

Mulțumesc pentru restul lămuririlor :smile:

1 Like

Popup galben de cate ori dau reply??? … Nu sunt expert in UX si WebDesign, dar imi imaginez ca un forum de developeri trebuie sa fie simplu si intuititv, fara briz-briz-uri. Vezi familia stackexchange. Ah, da, nu mi jena sa va critic :wink: Va asigur ca de fiecare imi voi exprima si o sugestie pe langa critica.


Revenind la subiect.

Cand as folosi TDD? Aproape tot timpul.
Cand nu as folosi TDD? Pentru UI, dar strict pentru partea de prezentare. As testa de exemplu ca se populeaza corect un dropdown, dar nu as testa partea vizuala, de exemplu culoarea dropdownului. Nu as mai face TDD la chestii foarte mici, scriptulete ce ruleaza scurt iar output-ul este testabil prin apreciere vizuala. Poate as folosi mai putin TDD pentru proiecte “one-shot” care nu necesita mentenanta in viitor. Facut / predat / abandonat.

Cat de repede ar trebui sa ruleze testele? <5ms / test. Evindent pentru unit teste. Noi la Syneto avem in momentul de fata in PHPUnit urmatoarea situatie, citat direct din logurile ultimului build:

Time: 2.31 minutes, Memory: 137.75Mb
[14:43:48][Step 1/1]
[14:43:48][Step 1/1] OK (1335 tests, 6166 assertions)

Si asta in conditiile in care masina de build este un hardware destul de jalnic, un xeon mai vechi cu 8 GB RAM. Din acete 2.31 inca 50-60 secunde se pot taia, doar ca ne e lene sa rescriem niste teste neperformante.

In timpul developmentului, evident ca nu rulam toate testele. Eu personal rulez testele pentru clasa in cauza, sau fisierul de test daca e focalizat. Asta inseamna ca ele ruleaza. Cum per test class avem de obicei in jur de 7 (±2) metode te test, ele ruleaza in aprox 7*5ms + 0.5sec overhead (comunicare retea si afisare)… Oricum, intr-o secunda am raspuns.

Cat despre rularea automata cu un whatcher. Am folosit metoda, mi se pare cool, dar nu foarte util. Parca ma simt mai concentrat si mai in control cand apas eu F1 si ruleaza testele. Da, shortcut-ul meu pentru teste este F1. “Help”-ul cel mai de folos ce ai putea avea in timpul programarii :smile:

No, cam atat acum. Sa aveti o seara faina.

4 Likes

@patkoscsaba: dacă întâmpini probleme (sau ai sugestii), te rog să le postezi în categoria Meta, de preferat însoțite și de un screenshot (dacă e cazul). Nu știu despre ce popup galben e vorba, așa că m-ar ajuta ceva mai multe detalii (screenshot, browser). Idem și pentru problemele de auth. Mulțumesc!

Edit: overall nu e nici un briz-briz, este Discourse instalat by default cu mici tweaks (adăugat support pentru tag-uri și schimbat simbolul pentru :+1:)

De precizat insa ca uneori, daca softul necesita dependente, o mare parte din timpul alocat pentru teste e ocupat de composer si alte pregatiri pentru testarea propriu zisa.

@IonutBajescu Despre ce fel de test vorbim aici? Testele unit nu au nici o legatura cu dependintele din composer. Ele trebuie sa fie izolate suficient de bine sa nu se atinga librarii 3rd party.

Uneori, chiar daca suna prea frumos ca dependetele sa fie izolate, nu putem chiar sa “mock”-am totul.

Exemplu: https://github.com/laravel/framework/blob/master/.travis.yml

@patkoscsaba, bine ati venit!

Inteleg ce ziceti si daca stau sa ma gandesc putin, nu as putea sa va contrazic, insa lipsa de experienta in aceasta arie ma cam incurca. Experienta teoretica, din studii, exista, dar cand e sa pun in practica, deocamdata merge greu.

1 Like

@IonutBajescu ajuta-ma sa inteleg te rog. Te referi la faptul ca nu poti mock-ui dependintele laravel-ului? Daca da, solutia este simpla. Framework-ul MVC ar trebui sa fie doar prezentare, eventual ca cateva este de integrare si end-to-end. Logica aplicatiei tale trebuie sa se afle in afara framework-ului si izolat de alte librarii.

De ce? Pentru ca atunci cand va trebui sa schimbi acea librarie sau framework, atunci nu vrei sa rescrii toata aplicatie. Mai mult, din experienta mea, business logic-ul trebuie sa-si expuna functionalitatea printr-un API independent de limbaj (ie. JSon). Daca ai asta, sa schimbi Laravel in Angular va fi o munca relativ usoara (nu neaparat rapida sau simpla).

Core-ul aplicatiei fiind izolat, cu mii de teste (evident numarul depinde de dimensiunea proiectului) care ruleaza rapid, iti ofera o siguranta ca orice schimbi in jur nu te va afecta.

1 Like

@msd Orice schimbare incepe cu primul pas. Propune-ti un tel. Fa-ti o promisiune ca pana la sfarsitul anului vei invata sa folosesti TDD in mod curent.

Dupa aceea fa primul pas in aceasta directie. Un pas mic, oricat de mic. Nu conteaza. De exemplu, luni cand mergi la lucru, programeaza folosind TDD timp de 1 (una) ora din cele 8 ore de lucru. Poti sa faci asta fara sa ai probleme? Cred ca poti. Tine-o asa timp de o saptamana.

Daca nu poti, mergi la lucru cu jumatate de ora mai devreme, cand nu e nimeni, si scrie cod timp de 1 ora cu TDD. Cod pentru proiectul vostru. Asa daca cineva zice ca lucrezi la jumatate de viteza, ii poti combate argumentul ca ai venit cu 30 minute mai devreme, deci din punctul de vedere al companiei nu s-a produs o intarziere.

Va fi greu? Desigur. La inceput, in prima saptamana, sau chiar in prima luna, e posibil sa nu reusesti sa scrii mai mult de 2-3 teste. Depinde de proiect si de cod. Dar o sa ai un castig enorm. In fiecare zi timp de 1 ora te vei concentra la asta. Subconstientul tau va procesa continuu dificultatile cu care te vei confrunta.

Dupa aceea, creste timpul alocat de la 1 ora la 2. Daca in continuare sunt probleme cu compania, vin-o cu 1 ora mai devreme, sau du-te acasa cu 1 ora mai tarziu. Gandeste-te ca doar tu esti responsabil pentru a invata o practica noua. Nu compania, nu colegii, nu sefii sau managerii, doar tu. Si asta se aplica pentru orice, nu doar pentru TDD.

Castigul? Enorm. Peste 6 luni vei fi singurul care stie TDD din echipa ta. Vei fi sigur pe tine, vei avea idei de impartasit cu colegii. Iar codul ce-l vei scrie cu siguranta va fi mai bun, il vei concepe mai rapid, testat, cu mai putine bug-uri.

Propune-ti sa devii cel care va conduce echipa catre succes, prin exemplu si dedicare.

4 Likes

Cand m-am uitat peste aplicatii foarte izolate fata de framework aratau foarte deplorabile. Se ajunsese la extrema in care efortul de a izola era mai mare fata de efortul de a nu folosi un framework.
Pur si simplu strica tot farmecul de a utiliza un framework, si in felul asta am renuntat in a mai crede ca a izola aplicatia fata de dependente este o solutie buna.

Din pacate nu mai am nici un link la indemana sa pot da exemplu, dar sunt sigur ca fiecare a vazut cel putin o astfel de aplicatie.

Referitor la ce spuneam eu era ca in 99% din cazuri dependentele sunt descarcate in timpul testelor, deci se adauga un minut la timpul in care se ruleaza testele.

Am inteles.

Daca ai o aplicatie mica, care nu va creste, este OK sa mergi cu framework si atat.

Dar cred ca nici o aplicatie serioasa, mare, pe terment lung, nu se poate baza pe framework. Framework-urile, librariile, tool-urile, vin si pleaca. Sunt efemere. Intrebarea nu este niciodata ce faci daca trebuie sa schimb o dependinta externa. Intrebarea ce trebuie pusa este ce faci cand schimbi dependinta. Presupun ca vrei ca aplicatia ta, proiectul tau, sau chiar si firma ta, sa poata supravietui schimbarii.

In alte ordine de idei, vezi conceptul de Clean Architecture de Robert C. Martin. Este un lucru, ce odata implementat, pe proiecte mai mari, aduce avantaje deosebite.

Si pentru toata lumea, tineti minte, ca framework-urile web MVC, sunt frameworkuri de prezentare, si atat. Nu legati de ele aplicatii mari ca problemelele nu vor inceta sa apara.

Poate pentru că nu fac aplicații ci doar site-uri, pentru mine este destul de ciudat conceptul ăsta de separare a framework-ului. Am mai citit undeva de separarea asta de care spui tu, doar că nu sunt foarte sigur de o chestie.

După mintea mea, este nevoie de un „framework” intermediar, ce face legătura dintre framework-ul principal (e.g. Laravel) și aplicația ta, astfel încât dacă vei schimba framework-ul principal, va trebui să modifici/extinzi codul framework-ului intermediar. Greșesc?

Dar cred ca nici o aplicatie serioasa, mare, pe terment lung, nu se poate baza pe framework

suna a NIH

Framework-urile, librariile, tool-urile, vin si pleaca.

@patkoscsaba Rails are aproape 10 de ani / Spring are 11+ ani

Microservices incep sa prinda ceva tractiune (iarasi) insa in final nothing beats good design.

Legat de TDD, conceptul este simplu:

  • write test
  • make sure it fails
  • write logic to make it pass
  • all green, maybe break it to be sure it works
  • next feature

Problema principala este acel “driven” din TDD si anume daca nu esti atent testele iti vor dicta arhitectura iar ca noob you will fuck things up.

tl;dr: pet-project first / then apply proper TDD in production code also any amount of TDD won’t save you from bad design/arhitecture

4 Likes

@patkoscsaba, foarte de-acord cu atitudinea de care vorbiti. Problema e clar la mine, daca vreau sau nu sa fac ceva. Dar fiind intr-o perioada de cumpana privind viitorul meu in programare, nu ma pot determina pur si simplu sa adopt atitudinea asta. Momentan sunt intr-o stare gresita de “iau din zbor si voi vedea cum va fi”.

1 Like

Avand in vedere ca folosim un framework in varianta stabila cand incepem un proiect(asa facem, nu?) nu vad eventuale probleme.

Daca azi eu incep proiectul DevForum.ro pe Laravel 4, si maine se lanseaza Laravel 5, iar poimaine se renunta complet la Laravel proiectul meu nu o sa fie afectat.
Daca platforma functioneaza corect nici macar bug-urile din Laravel 4 nu ma vor afecta, pentru ca ele sunt specifice unor use case-uri de care eu nu m-am lovit. Iar daca exista o problema, pot arunca imediat un commit peste Laravel 4 sa mi-l repar.

Daca dupa 10 ani Laravel 4 mi se pare prea invechit cred ca e timpul ca si aplicatia mea sa treaca la o noua versiune de tipul x+1.0.0, adica e nevoie sa rescriu totul. Dar unde nu exista imbunatatiri voi refolosi bucati din cel vechi, dar nu-l voi recicla total.

Eu sunt de acord cu izolarea asta fata de framework, mi se pare o chestie ce ofera o siguranta foarte buna, dar oare merita sa platim costul acestei izolari?
As merge mai rapid pe varianta sa izolez doar unele parti, unde nu exista un cost, dar in nici un caz sa izolez toata aplicatia.

Daca insa vreau sa schimb framework-ul, si costul e mai mic decat a rescrie aplicatia. Voi creea propriul meu Laravel 4 plin de proxy-uri care trimit catre framework-ul pe care l-am ales.

1 Like

Nu cred ca e nevoie de un framework la framework. Daca partea de prezentare depinde de business logic, la o schimbare, in mod ideal, efectele trebuie sa se revada doar in prezentare. De exemplu daca partea ta de business logic borbeste JSON, orice framework ai folosi, in orice limbaj, il poti interfata cu business logic-ul, fara modificarea acestuia din urma.

Cat despre starea proiectului in 10 ani. Tocmai asta este problema. Ai un proiect. Ai investit 10 ani in dezvoltarea sa. Daca ai o echipa de 10 oameni care au facut asta, costurile de a ajunge unde esti sunt imense. Sa zicem 25mii euro pe luna, timp de 10 ani, aprox 3milioane de euro.

Acum, frameworkul pe care ai construit, pur si simplu devine abandonat. Si acest lucru, reiterez, sigur se va intampla. Ce faci? Vei avea nevoie de alti 10 ani si alti 3 milioane de euro sa rescrii aplicatia. Ea nu mai e de 10mii de linii, este de miloane.

Nici sa continui cu ce ai nu poti, decat daca e un framework opensource, iar tu decizi ca il intretii pe costurile tale. Poate mai angajezi 5 programatori pentru asta. Rezultatul? Mai amani inevitabilul inca vreo 5 ani.

In urma cu 5-6 ani, toata lumea jura ca Prototype pentru JS este sfant. Este atotputernic. Stabil. Sigur. Si nu va disparea niciodata. Then JQuery came…

Acum, daca ai o aplicatie strans legata de Prototype, trebuie sa il schimbi. Ce faci? Investesti luni de zile (in cazuri fericite) sa treci pe JQuery? Aceste luni au pret dublu: costul productiei si costul oportunitatii pierdute.

In opinia mea, in acest caz ai o singura cale rationala pe care sa mergi. Renunti la Prototype, treci pe JQuery, dar in asa fel incat toata comunicarea cu JQuery sa fie separata de un layer de adaptoare. Aplicatia ta va sti si lucra doar cu metode din adaptoare.

Cand JQuery va disparea, schimbarea va fi simpla. Va trebui sa iti modifici doar layer-ul de adaptoare. Schimbare localizata, redusa, rapida.

Iata o alta poveste. Cand am inceput lucrul la StorageOS, CakePHP era dumnezeul frameworkurilor. Au trecut 5-6 ani. Acum este codasul listei. Laravel si AngularJS duc trena. Ce ma fac? Vreau sa schimb. Trebuie sa schimb.

Norocul nostru este ca avem o separare destul de buna, dezvoltata in ultimii 2-3 ani, de framework. Da, va trebui sa lucram, dar probabil doar vreo 2 luni, nu ani. Ah, si vrem sa trecem, probabil pe Angular care este JS. Backend-ul nostru este in PHP. Interfatarea cu Cake este in PHP. Va trebui sa dezvoltam un layer de JSON. Dar acest lucru va fi relativ usor, pentru ca toata comunicarea cu business logic-ul se face prin Fatade bine definite, izolate de CakePHP.

Si daca va intrebati, este un proiect destul de mare.

3 Likes

Cred ca daca framework-ul care l-ai ales era bun atunci e la fel de bun si acum.
Nu trebuie sa rescrii nimic, daca maine Laravel adauga o noua functie nu am nevoie de ea.

Daca poimaine Zend 3 conduce razboiul framework-ului atunci aplicatia mea poate sa ramana linistita si stabila pe Laravel 4.
Eu nu trebuie sa intretin “framework”-ul, eu imi intretin aplicatia mea. Nu ai nevoie de 5 programatori pentru ca a scos piata un framework mai bun nici in cele mai negre cazuri.
Tu alterezi framework-ul doar cand exista bug-uri ale framework-ului, nu creezi noi feature-uri pentru framework.

Plus ca nu o sa fii singura firma care lupta cu bug-urile unui soft abandonat, nu duci lupta singur, o sa mai existe multi gata sa repare daca se lovesc de o problema.

1 Like

@IonutBajescu Da. Este si asta un punct de vedere.

Eu ce pot sa zic, ca costul decuplarii fata de costul schimbarii CakePHP pe Laravel / Angular si a Prototype pe JQuery, este mai mic in cazul nostru.

Din experienta noastra, costul introducerii decuplarii este mai mic decat costul schimbarii totale.

Desigur, acest aspect poate avea consecinte diferite pentru proiecte diferite.

Eu recomand tuturor sa faca asa cum e cel mai bine pentru proiectul si business-ul lor. Doar sa incerce mai multe variante, sa le faca un timp mai indelungat, si dupa aceea sa ia o decizie. Este important sa nu sari de la idee la concluzie. Este important, cu orice in general, sa il faci un timp suficient de mult incat sa poti evalua daca o technologie or arhitectura este buna sau nu pentru tine.

1 Like

Exista o diferenta substantiala intre urmatoarele concepte:

Unit Testing
Test After
Test First Programming
Test Driven Development

Unit Testing inseamna ca vreau sa testez o clasa / o metoda sau functie / un comportament in izolare. Vreau sa testez in izolare pentru ca altfel voi avea dependente care imi vor face testul sa fie greu de inteles si/sau testul va rula foarte mult timp.
Cum a zis si @patkoscsaba un test unitar trebuie sa ruleze in milisecunde.
Unit testing poate fi facut:

  • dupa ce e facut designul si scris codul
  • dupa ce e facut design-ul dar nu e scris codul
  • inainte ce e facut codul si designul.
    Prin design ma refer la totalitatea conexiunilor intre elementele din cod (variabile, functii, interfete, clase, module, etc)

Test After
Am facut designul, am scris codul si apoi scriu teste. Functioneaza foarte bine daca toate componentele sunt gandite cu un design decuplat, care sa imi permita sa fac mocking si stubbing. Daca nu, este un calvar sa incerc sa refac conexiunile dintre elemente in asa fel incat sa pot sa testez in izolare doar ce am nevoie.

Test First Programming
Am facut design-ul, sau il am in cap foarte clar. Scriu testul, dar tot timpul ma ghidez dupa un plan de design. Implementez testul si stiu foarte bine unde merg, pentru ca design-ul este stabilit. Respect Red/Green/Refactor, dar nu generez design in timpul refactoring, pentru ca il am deja

Test Driven Development
Ma concentrez pe problema, si nu pe solutie, ca in cazurile de mai sus. Vreau sa inteleg care este cea mai mica solutie posibila. Ma gandesc la 3-7 teste care au sens, de la cea mai simpla solutie, spre a adauga detalii importante. Nu ma gandesc la conexiunile intre elemente, ci le fac uitandu-ma la duplicarea din cod, ma concentrez pe nume foarte bune. Doresc sa am un cuplaj cat mai mic intre elemente si testele deja scrise nu ma lasa sa fac cuplari nenaturale. Prin refactoring generez conexiunile intre elemente (design) in permanenta.
Din acest motiv parerea mea este ca TDD este o unealta de design, nu o unealta de unit testing. Scopul principal pentru care faci TDD este sa ai un design emergent, prin refactoring. Testele sunt ajutatoare si sunt un produs auxiliar procesului de generare a design-ului. Mai multe despre TDD si design incremental am scris impreuna cu Alex Bolboaca http://www.todaysoftmag.com/article/en/15/Test_Driven_Development_and_incremental_design_575

3 Likes