de Luca Piccinelli

Test Driven Development este greu! Acesta este adevărul nespus despre el.

În aceste zile citiți o mulțime de articole despre toate avantajele de a face test Driven Development (TDD). Și probabil auziți multe discuții la conferințele tehnologice care vă spun să „Faceți testele!” Și cât de mișto este să le faceți.

Și știi ce? Din păcate, au dreptate (nu neapărat despre partea „cool”, ci despre partea utilă). Testele sunt o TREBUIE! Avantajele tipice pe care le enumerăm atunci când vine vorba de TDD sunt reale:

  • Scrii software mai bun
  • Aveți protecție împotriva spargerii lumii atunci când sunt introduse noi funcții
  • Software-ul dvs. este auto-documentat
  • Evitați supra-ingineria

Chiar dacă am fost întotdeauna de acord cu aceste avantaje, a fost o vreme când am crezut că nu am nevoie de TDD pentru a scrie un software bun și care poate fi întreținut. Desigur, acum știu că m-am înșelat, dar de ce am avut această idee în ciuda magiei strălucitoare a profesioniștilor? Motivul este doar unul: și permiteți-mi să o rog pe Rihanna să o spună pentru mine …

Costul!

Costă mult! Probabil cineva se gândește „dar costă și mai mult dacă nu faci testele”- și acest lucru este corect, de asemenea. Dar aceste două costuri vin în momente diferite:

  • faci TDD ➡ ai un cost acum.
  • Nu faceți TDD ➡ veți avea un cost in viitor.

Deci, cum ieșim din acest impas?

Cea mai eficientă modalitate de a face ceva este să o faci cât mai natural posibil. Natura oamenilor este de a fi leneși (aici dezvoltatorii de software sunt cei mai performanți) și lacomi, așa că trebuie să-ți găsești calea reducerea costurilor acum. Este ușor de spus, dar atât de greu de făcut!

Aici voi împărtăși experiența mea și ceea ce a funcționat pentru mine în transformarea raportului beneficiu / cost în favoarea mea.

Dar, înainte de a face asta, să analizăm câteva dificultăți tipice în aplicarea TDD.

Ești capabil să testezi suma a două numere?

În general, teoria nu este opțională; trebuie să o stăpânești pentru a stăpâni practica. Cu toate acestea, încercarea de a aplica imediat toate cunoștințele teoretice pe care le-ați dobândit anterior ar putea avea următorul efect:

Lecția teoretică tipică despre TDD începe cu așa ceva:

Și iată-te

Apoi vine acest lucru:

  • roșu ➡ verde cycle ciclu refactor
  • teste de unitate, acceptare, regresie, integrare
  • batjocoritoare, cioturi, falsuri
  • dacă ești norocos (sau poate ghinionist?), cineva îți va spune despre testarea contractului
  • iar dacă sunteți foarte norocoși (sau poate foarte ghinioniști?) veți atinge refacerea vechii baze de coduri

Lucrurile devin dificile, dar sunteți un dezvoltator cu experiență și toate aceste concepte nu sunt atât de greu de gestionat pentru dvs. Apoi se termină clasa; te duci acasă și, de-a lungul următoarelor zile, faci cu sârguință niște katas de cod pentru a remedia conceptele tocmai învățate. Până acum, bine.

Lupta este reală

Urmează un proiect real, cu termene reale și costuri reale de sincronizare – dar sunteți motivați să aplicați noul dvs. TDD strălucitor. Începi să te gândești la arhitectura software-ului tău și începi să scrii teste pentru prima clasă și pentru clasa în sine – hai să o numim Clasa 1.

Acum vă gândiți la primul utilizator al clasei 1, să-l numim UsageOfAClass, iar din nou o testezi și o scrii. Class1 este un colaborator al UsageOfAClass, deci o să-l batjocorești? Ok hai să ne batem joc. Dar ce se întâmplă cu interacțiunile reale ale clasei 1 și UsageOfAClass? Poate ar trebui să le testați și pe toate? S-o facem.

În acest moment, în interiorul tău, începi să auzi o voce mică care spune „Eu m-aș dezvolta mult mai repede dacă nu ar trebui să scriu aceste teste …”. Nu ascultați această voce rea și continuați direct la următorul test.

Clasa 2 va fi folosit de UsageOfAClass și persistă în interiorul unui Db. Deci, trebuie să testăm Class2, interacțiunea sa cu UsageOfAClass și persistența în Db? Dar așteptați … a menționat cineva cum să facă față testelor I / O în timpul clasei de teorie TDD?

Teoria din spatele TDD nu este atât de greu de înțeles, dar aplicarea ei în lumea reală poate fi cu adevărat complexă dacă nu o abordați în mod corect.

Doar fă-o

Ar trebui să ținem cont întotdeauna că teoria trebuie să fie îndoită de nevoile noastre și nu dimpotrivă.

Scopul principal este de a face treaba. Deci sfatul meu este, doar fă-o!

Începeți simplu și faceți-vă sarcina până la capăt. Apoi, când vă blocați într-o buclă teoretică a minții, cum ar fi:

  • este o unitate sau un test de integrare?
  • aici ar trebui să-l bat sau nu?
  • oh, porcărie, aici ar trebui să scriu un nou colaborator, deci o nouă suită de teste unitare infinite doar pentru a scrie „hei, banana” …

uită doar de teorie o vreme și fă un pas înainte. Fă-o așa cum vine!

După ce ați terminat sarcina, aruncați o privire înapoi la munca dvs. Privind in urma la locul de muncă finalizat, va fi mult mai ușor să analizăm ce ar fi fost lucrul corect de făcut.

TDD practic

Doar fă-o. Apropo, cred că aceasta este și abordarea corectă a TDD.

Ce a fost greșit în modul în care am construit Class1, Class2 și UsageOfAClass? Apropierea.

Aceasta este o abordare de jos în sus:

  • analizează problema
  • descoperi o arhitectură
  • începeți să-l construiți din componentele unității

Această abordare este cea mai bună prietenă supra-inginerie. De obicei, construiți sistemul pentru a preveni modificările pe care credeți că vor veni în viitor, fără să știți dacă vor veni efectiv. Apoi, când unele cerințe se schimbă, de obicei se întâmplă într-un mod care nu se potrivește structurii dvs., indiferent cât de bun este.

Pentru mine cheia reducerii drastice a costurilor imediate a scrie cu TDD a fost să adopte o abordare de sus în jos:

  1. aduce o poveste de utilizator
  2. scrieți un test foarte simplu al unui caz de utilizare
  3. fă-o să alerge
  4. reveniți la pasul 2 până când toate cazurile de utilizare sunt complete

În timp ce faceți acest proces, nu vă faceți griji prea mult cu privire la arhitectură, cod curat (bine, amintiți-vă cel puțin să utilizați nume de variabile decente) sau orice fel de complicație care nu este necesară în prezent. Fă doar ceea ce știi că ai nevoie acum, până la capăt.

Testele poveștii indică clar care sunt cerințele actuale și cunoscute.

Odată ce ați terminat, aruncați o privire la codul dvs. mare de noroi de spaghete, treceți peste rușine și priviți mai profund ceea ce ați făcut:

  • functioneaza! Și testele o dovedesc.
  • Tot sistemul este acolo, și exact ceea ce este de fapt necesar pentru a face treaba.

Acum aveți o imagine de ansamblu asupra tuturor părților sistemului dvs., astfel încât să puteți refactora cu cunoștințele domeniului pe care nu le-ați fi putut avea când ați început de la zero. Și testele se vor asigura că nimic nu se va sparge în timpul refactorizării.

Refactorizare

Cel mai bun mod de a începe să refactorizez este să identific domeniile de responsabilitate și să le separ în metode private. Acest pas ajută la identificarea responsabilităților și a intrărilor și a rezultatelor acestora.

După aceea, clasele de colaboratori sunt aproape acolo și trebuie doar să le mutați în fișiere diferite.

Pe măsură ce continuați, scrieți mai întâi teste pentru clasele care ies din proces și iterați până când sunteți mulțumit de rezultat. Și amintiți-vă, dacă vă blocați undeva, faceți-o! Dacă faci ceva rău, odată ce ai terminat, vei avea mai multe informații despre cum să treci peste greșeală data viitoare când o vei face față. Prioritatea este realizarea muncii, la cele mai bune abilități actuale.

În acest fel, dacă vă analizați erorile pentru a învăța de la ele, vă veți rafina și abilitățile.

Următoarea poveste a utilizatorului

Continuați să vă dezvoltați produsul urmând acești pași:

  • ia o poveste
  • faceți-l să funcționeze complet într-un ciclu „test – cod”.
  • refactor

În timp ce adăugați caracteristici, veți continua să vă schimbați software-ul și poate chiar structura acestuia. Dar pe măsură ce sistemul crește, costul schimbării va menține o creștere liniară datorită celor două caracteristici principale ale TDD:

  • descoperirea arhitecturii (care ajută la controlul complexității)
  • protecție împotriva schimbărilor de rupere

Sistemul nu va fi supra-conceput, deoarece arhitectura va apărea pe măsură ce poveștile vor fi finalizate. Nu vă gândiți la care ar putea fi cerințele viitoare; dacă ajungeți să aveți nevoie de el, atunci costul pentru implementare va fi mic.

Ce o poate face să meargă prost?

Mărimea poveștii. Ceea ce construiți până la capăt trebuie să aibă dimensiunea potrivită. Nu prea mare (altfel va dura prea mult timp pentru a primi feedback) sau prea mic (altfel nu veți avea o imagine de ansamblu).

Ce se întâmplă dacă povestea este prea mare? Împarte-l în bucăți care pot fi construite de la început până la sfârșit.

Ce urmeaza?

În articolul următor voi oferi un exemplu practic al conceptelor pe care le-am explicat aici. Vom implementa, pas cu pas, Joc de bowling kata începând de la un test de acceptare.

Nu este o problemă din lumea reală, dar are suficientă complexitate pentru a vedea cum TDD poate ajuta la gestionarea acesteia.

Vă rugăm să împărtășiți părerea și sugestiile dvs. despre acest articol. Ești de acord cu mine sau crezi că toate acestea sunt o grămadă de gunoaie? Spune-mi ce părere ai în comentarii; ar fi foarte frumos să începem o conversație pe TDD și să ne împărtășim experiențele.

Vreau să-i mulțumesc lui Matteo Baglini pentru că m-a ajutat să-mi găsesc drumul printr-o abordare practică a dezvoltării de software și TDD.

Mulțumesc că ai citit!

Imagine de copertă, prin amabilitatea lui testigma.