Adoptarea TDD in php/javascript

@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

Salutare tuturor. E primul meu post pe acest forum si ma bucur mult ca l-am gasit.
TDD-ul e acel ceva care ma nedumireste destul de tare si incerc sa-l inteleg. Mi-am facut cont pe laracast, unde sunt materiale destul de bune pe tema asta referitor la testarea de cod php. Din pacate, inca ma simt un pic depasit de concept, dar cred ca e important sa reusesti sa lucrezi cu teste scrise pentru codul tau, deoarece se reduce semnificativ efortul de testare al aplicatiei.
La munca folosesc Codeigniter. Nu ma simt in stare sa implementez testare automata in acest framework. Am de gand sa incerc sa o fac in proiecte personale pe care le incep dupa ce apare laravel5.
Ma bucur sa vad un expert in domeniu printre cei ce posteaza pe acest forum. Trebuie neaparat sa urmaresc trainingurile alea de pe tut-plus.
Mi se pare foarte interesant conceptul de izolare a codului de framework. Sunt curios cum s-ar putea face asta, mai ales in Javascript. In prima faza, nu mi se pare foarte fezabil si mi se pare un efort destul de mare. Aveti un link la un exemplu de cod construit pe acest principiu? Sau articol mai detaliat?

1 Like

De acord cu ce ai scris, însă BDD e mai mult un acronim inutil dacă faci corect TDD.

Pentru că în TDD, trebuie să testezi fix behaviour, deci faci deja BDD când faci TDD.

BDD a fost inventat deoarece erau mulți novici care scriau overspecified tests cu metodologia TDD.

O carte de referință este “xUnit Test Patterns: Refactoring Test Code”.

1 Like

Doar pentru a clarifica un pic lucrurile. BDD si TDD sunt doua lucruri diferite si complementare. Oarecum TDD face parte din BDD. Vezi filmeltul de mai jos pentru o explicatie de 5 minute chiare de la Corey Haines insusi.

Cat despre cartea lui Gerard Meszaros “xUnit Test Patterns: Refactoring Test Code”, acesta este cartea de referinta in unit testing. Cand a fost scrisa nici nu cred ca exista conceptul de BDD (doar speculez asta, nu am date concrete).

Daca vreti pot sa il intreb pe Gerard despre cum vede el diferenta dintre BDD si TDD si ce crede ca este diferenta cea mai semnificativa dintre ele.

4 Likes