Regresia — este o eroare care apare după introducerea modificărilor în cod, deși aceeași funcționalitate funcționa corect înainte. Regresia înseamnă că modificarea nouă „a stricat“ ceea ce fusese deja scris și testat anterior. Este una dintre cele mai frecvente și periculoase probleme în dezvoltare: reparând o eroare, dezvoltatorul poate strica neobservat alte trei funcții. Conform Capers Jones Software Engineering 2023, densitatea medie a erorilor de regresie este de 1–3 la fiecare 100 de linii de cod modificate. Analizăm cauzele regresiilor, metodele de detectare și strategiile de prevenire.
Principalele puncte
Regresia — este situația când o funcționalitate care funcționa în versiunea anterioară încetează să mai funcționeze după introducerea modificărilor. Modificarea poate fi orice: remedierea unei erori, adăugarea unei noi funcționalități, refactorizarea, actualizarea unei biblioteci sau chiar modificarea configurației. Regresia este principalul inamic al stabilității: fiecare modificare riscă să strice ceva care fusese deja verificat și lansat.
Termenul provine din testare: testarea regresivă — este reexecutarea testelor existente după fiecare modificare. Dacă un test care trecea anterior eșuează — înseamnă că a avut loc o regresie. În sens larg, regresia nu este doar eșecul unui test, ci și orice deteriorare a comportamentului observată de utilizator sau QA. Conform Tricentis State of Testing 2023, regresiile reprezintă 35–45% din toate erorile găsite în producție.
Regresia se deosebește de o eroare obișnuită prin contextul temporal: eroarea ar fi putut exista dintotdeauna, iar regresia este întotdeauna rezultatul unei modificări. Aceasta este o diferență importantă, deoarece căutarea cauzei regresiei începe cu analiza modificărilor: ce s-a schimbat între „funcționa“ și „a încetat să funcționeze“. Git bisect — instrumentul standard pentru găsirea commit-ului care a cauzat regresia.
Regresia locală — modificarea în modulul A strică funcționalitatea în același modul A. Exemplu: dezvoltatorul rescrie funcția de sortare, iar aceasta nu mai procesează corect un array gol. Regresia locală este cea mai simplu de detectat și remediat, deoarece cauza și efectul sunt apropiate.
Regresia la distanță — modificarea în modulul A strică funcționalitatea în modulul B, care nu este legat direct prin cod, dar este legat prin date sau timp. Exemplu: modificarea schemei bazei de date în modulul „Utilizatori“ strică raportul în modulul „Analitică“, care utilizează același tabel. Regresiile la distanță sunt cele mai perfide: dezvoltatorul nu bănuiește că modificarea sa va afecta un alt modul.
Regresia efectelor secundare — modificarea unui efect secundar (logare, cache, trimitere de notificări) strică comportamentul așteptat. Exemplu: dezvoltatorul a adăugat cache pentru accelerare, dar din cauza cache-ului învechit, utilizatorii văd date expirate. Regresiile efectelor secundare sunt greu de prins cu teste automate, deoarece efectele secundare adesea nu sunt acoperite de teste.
Regresia de performanță — codul continuă să funcționeze corect din punct de vedere funcțional, dar mai lent decât înainte. Exemplu: noul algoritm de criptare produce aceleași rezultate, dar timpul de execuție a crescut de la 2 ms la 200 ms. Regresiile de performanță nu sunt detectate de testele unitare obișnuite — sunt necesare benchmark-uri și profilare.
| Tip de regresie | Exemplu | Metodă de detectare |
|---|---|---|
| Locală | Sortare stricată | Teste unitare |
| La distanță | Modificare schemă BD | Teste de integrare |
| Efecte secundare | Cache învechit | Teste E2E |
| De performanță | Încetinire răspuns | Benchmark-uri |
Prima cauză — cuplarea codului (coupling). Cu cât modulele depind mai mult unele de altele, cu atât este mai mare probabilitatea ca o modificare într-unul să provoace o regresie în altul. Antipattern-uri clasice: God Object (obiectul care face totul), Shotgun Surgery (modificarea unuia necesită ajustări în zeci de locuri), Circular Dependency. Reducerea cuplării — sarcina arhitecturii: principiile SOLID, Dependency Injection, arhitectura hexagonală.
A doua cauză — lipsa testelor pentru funcționalitatea modificată. Dacă codul nu este acoperit de teste, dezvoltatorul află despre regresie doar de la QA sau utilizatori. Conform Google Testing Blog, proiectele cu acoperire de teste >75% au de 5 ori mai puține regresii decât proiectele cu acoperire <25%. TDD (Test-Driven Development) garantează că testele sunt scrise înaintea codului, nu „când va fi timp“.
A treia cauză — factorul uman. Dezvoltatorul nu știe de existența funcționalității adiacente, nu înțelege toate dependențele sau pur și simplu se grăbește. Cauza — partajarea insuficientă a cunoștințelor despre baza de cod. Soluții: code review cu participarea dezvoltatorilor din alte module, pair programming, documentarea arhitecturii. Bus factor al proiectului este invers proporțional cu numărul deciziilor arhitecturale documentate.
Testarea regresivă — este procesul de reexecutare a testelor existente după fiecare modificare pentru a verifica dacă funcționalitatea veche nu a fost stricată. Este singura modalitate de a garanta că modificarea nouă nu a afectat funcționarea codului existent. Fără testarea regresivă, fiecare lansare este o loterie: dezvoltatorul speră că nu a stricat nimic, dar nu poate confirma acest lucru.
Testarea regresivă manuală — cea mai costisitoare și ineficientă abordare. Pe măsură ce proiectul crește, numărul scenariilor de testare regresivă crește liniar, iar timpul de executare manuală — exponențial. După 2–3 ani de dezvoltare, executarea manuală a regresiei poate dura 2–3 săptămâni, ceea ce face imposibile lansările frecvente. Singura soluție este automatizarea.
Testarea regresivă automatizată se împarte pe niveluri conform piramidei testării:
Conform Google Testing Blog, raportul optim: 70% teste unitare, 20% integrare, 10% E2E. Abaterea de la această proporție scade eficiența testării regresive: excesul de teste E2E încetinește pipeline-ul, lipsa testelor unitare lasă micro-eroile neobservate.
Prima strategie — Full Regression. Se rulează toate testele proiectului. Cea mai fiabilă, dar și cea mai lentă abordare. Aplicabilă pentru proiecte mici (până la 10 000 de teste, timp de rulare <30 minute). Pentru proiecte mari, regresia completă poate dura ore, ceea ce face pipeline-ul CI/CD nepractic.
A doua strategie — Selective Regression. Se rulează doar testele legate de codul modificat. Pentru determinarea legăturilor se folosește graful de dependență al codului. Instrumente: Bazel (Google), Nx (JavaScript), sbt (Scala). Selective regression economisește 60–80% din timpul de rulare, dar necesită construirea precisă a grafului de dependență — erorile duc la regresii omise.
A treia strategie — Prioritized Regression. Toate testele sunt clasificate pe priorități: critical path (cele mai importante scenarii de utilizator), high risk (cod cu istoric de erori), changed code (cod afectat de modificare). Mai întâi se rulează testele cele mai prioritare — dacă trec, dezvoltatorul primește feedback rapid. Rulare cu limită de timp: în 10 minute se verifică testele critice, restul — în fundal.
Primul și cel mai important pas — cultura scrierii testelor. Fiecare modificare ar trebui însoțită de un test care verifică că modificarea funcționează și de un test care verifică că nu s-a stricat nimic. TDD (Test-Driven Development) oferă cele mai bune rezultate: dezvoltatorul scrie mai întâi testul care eșuează, apoi codul care îl face să treacă. Aceasta garantează că testul există înaintea codului.
Al doilea pas — pipeline CI/CD cu rulare obligatorie a testelor. Pull request nu poate fi îmbinat până când toate testele nu trec. Nu se pot „sări“ testele din cauza urgenței — modificările urgente trec printr-un set accelerat, dar obligatoriu de teste. Conform Google DevOps Research, echipele cu CI/CD obligatoriu au de 3 ori mai puține regresii în producție.
Al treilea pas — monitorizare în producție. Nici cele mai bune teste nu garantează 100% protecție împotriva regresiilor. Instrumentele de observabilitate (Sentry, Datadog, New Relic) trebuie să urmărească metricile cheie după fiecare implementare: rata de erori, latența, debitul. Revenirea automată (rollback) la depășirea pragurilor — o pernă de siguranță dacă regresia ajunge totuși în producție.
Al patrulea pas — code review cu gândire regresivă. Recenzorul trebuie să pună întrebarea: „Ce alte module s-ar putea strica din cauza acestei modificări?“. Nu este suficient să verifici că codul este corect — trebuie să verifici că nu va afecta funcționalitatea adiacentă. Lista de verificare pentru code review trebuie să includă punctul „verificarea regresiilor în modulele adiacente“.
Întrebări frecvente
Regresia — este o eroare care nu exista înainte. O eroare obișnuită ar fi putut exista din momentul creării funcționalității. Regresia este întotdeauna legată de o modificare specifică — aceasta permite utilizarea git bisect pentru găsirea cauzei.
Folosește git bisect: indică commit-ul unde totul funcționa și commit-ul unde s-a stricat. Git va efectua o căutare binară în istoric și va găsi commit-ul care a cauzat regresia. Aceasta funcționează chiar și pentru proiecte mari cu mii de commit-uri.
Nu există un număr exact, dar există o regulă empirică: acoperirea fluxurilor cheie de utilizator trebuie să fie 100%, acoperirea tuturor funcțiilor — cel puțin 70%. Mai importantă este calitatea decât cantitatea: un test care verifică un edge case valorează mai mult decât zece teste pe happy path.
Da, și se numește infrastructure regression. Actualizarea sistemului de operare, a versiunii bazei de date, a certificatului SSL sau a configurației serverului web poate strica codul care funcționa. IaC (Infrastructure as Code) și testarea infrastructurii (Test Kitchen, Terratest) ajută la detectarea acestor regresii.
Începe cu un singur flux critic de utilizator. Scrie un test automat pentru cel mai important scenariu (autentificare, plasare comandă). Arată în demo cum testul prinde o regresie. Când echipa vede beneficiul — implementează testarea treptat, extinzând acoperirea.
Concluzii
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și