Regressie — is een bug die verschijnt na het aanbrengen van wijzigingen in de code, terwijl dezelfde functionaliteit eerder correct werkte. Regressie betekent dat de nieuwe wijziging „heeft gebroken“ wat al eerder was geschreven en getest. Dit is een van de meest voorkomende en gevaarlijkste problemen in de ontwikkeling: bij het repareren van één bug kan een ontwikkelaar ongemerkt drie andere functies breken. Volgens Capers Jones Software Engineering 2023 is de gemiddelde dichtheid van regressiebugs 1–3 per elke 100 gewijzigde regels code. We bespreken de oorzaken van regressies, methoden om ze te detecteren en preventiestrategieën.
Belangrijkste punten
Regressie — is een situatie waarin functionaliteit die in de vorige versie werkte, stopt met werken na het aanbrengen van wijzigingen. De wijziging kan van alles zijn: een bugfix, het toevoegen van een nieuwe functie, refactoring, het bijwerken van een bibliotheek of zelfs een configuratiewijziging. Regressie is de grootste vijand van stabiliteit: elke wijziging riskeert iets te breken dat al was gecontroleerd en uitgebracht.
De term komt uit het testen: regressietesten — is het opnieuw uitvoeren van bestaande tests na elke wijziging. Als een eerder geslaagde test faalt — betekent dit dat er een regressie is opgetreden. In bredere zin is regressie niet alleen een testfout, maar ook elke verslechtering van het gedrag die door een gebruiker of QA wordt opgemerkt. Volgens Tricentis State of Testing 2023 vormen regressies 35–45% van alle bugs die in productie worden gevonden.
Regressie verschilt van een gewone bug door temporele context: een bug kan altijd al hebben bestaan, terwijl regressie altijd het resultaat is van een wijziging. Dit is een belangrijk verschil, omdat het zoeken naar de oorzaak van een regressie begint met het analyseren van wijzigingen: wat is er veranderd tussen „het werkte“ en „het werkte niet meer“. Git bisect — de standaard tool voor het vinden van de commit die de regressie heeft veroorzaakt.
Lokale regressie — een wijziging in module A breekt functionaliteit in dezelfde module A. Voorbeeld: een ontwikkelaar herschrijft een sorteerfunctie en deze stopt met het correct verwerken van een lege array. Lokale regressie is het eenvoudigst te detecteren en te repareren, omdat oorzaak en gevolg dicht bij elkaar liggen.
Remote regressie — een wijziging in module A breekt functionaliteit in module B, die niet direct door code is verbonden, maar wel door data of tijd. Voorbeeld: het wijzigen van een databaseschema in de module „Gebruikers“ breekt een rapport in de module „Analyse“ die dezelfde tabel gebruikt. Remote regressies zijn het meest verraderlijk: de ontwikkelaar vermoedt niet dat zijn wijziging een andere module zal beïnvloeden.
Bijwerkingenregressie — het wijzigen van een bijwerking (loggen, cachen, verzenden van meldingen) breekt het verwachte gedrag. Voorbeeld: een ontwikkelaar voegt caching toe om de prestaties te versnellen, maar door verouderde cache zien gebruikers verouderde gegevens. Bijwerkingenregressies zijn moeilijk te vangen met automatische tests, omdat bijwerkingen vaak niet door tests worden gedekt.
Prestatieregressie — code blijft functioneel correct werken, maar langzamer dan voorheen. Voorbeeld: een nieuw versleutelingsalgoritme geeft dezelfde resultaten, maar de uitvoeringstijd is gestegen van 2 ms naar 200 ms. Prestatieregressies worden niet gedetecteerd door gewone unittests — er zijn benchmarks en profilering nodig.
| Type regressie | Voorbeeld | Detectiemethode |
|---|---|---|
| Lokaal | Gebroken sortering | Unittests |
| Remote | DB-schemawijziging | Integratietests |
| Bijwerking | Verouderde cache | E2E-tests |
| Prestatie | Vertraagde respons | Benchmarks |
Eerste oorzaak — codekoppeling (coupling). Hoe sterker modules van elkaar afhankelijk zijn, hoe groter de kans dat een wijziging in de ene een regressie in de andere veroorzaakt. Klassieke antipatronen: God Object (object dat alles doet), Shotgun Surgery (wijziging van één vereist aanpassingen op tientallen plaatsen), Circular Dependency. Het verminderen van coupling — een taak van architectuur: SOLID-principes, Dependency Injection, hexagonale architectuur.
Tweede oorzaak — gebrek aan tests voor de gewijzigde functionaliteit. Als code niet door tests wordt gedekt, hoort de ontwikkelaar pas over een regressie van QA of gebruikers. Volgens Google Testing Blog hebben projecten met een testdekking >75% 5 keer minder regressies dan projecten met een dekking <25%. TDD (Test-Driven Development) garandeert dat tests worden geschreven vóór de code, niet „als er tijd is“.
Derde oorzaak — menselijke factor. De ontwikkelaar weet niet van het bestaan van aangrenzende functionaliteit, begrijpt niet alle afhankelijkheden of heeft gewoon haast. Oorzaak — onvoldoende kennisdeling over de codebase. Oplossingen: code review met ontwikkelaars uit andere modules, pair programming, architectuurdocumentatie. De Bus factor van een project is omgekeerd evenredig met het aantal gedocumenteerde architectuurbeslissingen.
Regressietesten — is het proces van het opnieuw uitvoeren van bestaande tests na elke wijziging om te controleren of oude functionaliteit niet is gebroken. Dit is de enige manier om te garanderen dat een nieuwe wijziging de werking van bestaande code niet heeft verstoord. Zonder regressietesten is elke release een loterij: de ontwikkelaar hoopt dat hij niets heeft gebroken, maar kan dit niet bevestigen.
Handmatig regressietesten — de duurste en meest inefficiënte aanpak. Naarmate een project groeit, neemt het aantal regressietestscenario's lineair toe en de tijd voor handmatige uitvoering exponentieel. Na 2–3 jaar ontwikkeling kan handmatige regressie 2–3 weken duren, wat frequente releases onmogelijk maakt. De enige uitweg is automatisering.
Geautomatiseerd regressietesten wordt onderverdeeld in niveaus volgens de testpiramide:
Volgens Google Testing Blog is de optimale verhouding: 70% unittests, 20% integratietests, 10% E2E. Afwijking van deze verhouding vermindert de effectiviteit van regressietesten: een overvloed aan E2E-tests vertraagt de pipeline, een tekort aan unittests laat microbugs onopgemerkt.
Eerste strategie — Full Regression. Alle tests van het project worden uitgevoerd. De meest betrouwbare, maar ook de langzaamste aanpak. Toepasbaar voor kleine projecten (tot 10.000 tests, uitvoeringstijd <30 minuten). Voor grote projecten kan volledige regressie uren duren, wat de CI/CD-pipeline onpraktisch maakt.
Tweede strategie — Selective Regression. Alleen tests die verband houden met de gewijzigde code worden uitgevoerd. Voor het bepalen van verbanden wordt de afhankelijkheidsgraaf van de code gebruikt. Tools: Bazel (Google), Nx (JavaScript), sbt (Scala). Selective regression bespaart 60–80% van de uitvoeringstijd, maar vereist een nauwkeurige opbouw van de afhankelijkheidsgraaf — fouten leiden tot gemiste regressies.
Derde strategie — Prioritized Regression. Alle tests worden gerangschikt op prioriteit: critical path (belangrijkste gebruikersscenario's), high risk (code met foutgeschiedenis), changed code (code die door de wijziging is getroffen). Eerst worden de meest prioritaire tests uitgevoerd — als ze slagen, krijgt de ontwikkelaar snelle feedback. Tijdsgebonden uitvoering: binnen 10 minuten worden kritieke tests gecontroleerd, de rest — op de achtergrond.
Eerste en belangrijkste stap — cultuur van testen schrijven. Elke wijziging moet vergezeld gaan van een test die controleert of de wijziging werkt en een test die controleert of er niets is gebroken. TDD (Test-Driven Development) geeft de beste resultaten: de ontwikkelaar schrijft eerst een falende test, dan de code die hem laat slagen. Dit garandeert dat de test vóór de code bestaat.
Tweede stap — CI/CD-pipeline met verplichte testuitvoering. Een pull request kan niet worden samengevoegd totdat alle tests zijn geslaagd. Tests kunnen niet worden „overgeslagen“ vanwege urgentie — urgente wijzigingen doorlopen een versnelde maar verplichte testsuite. Volgens Google DevOps Research hebben teams met verplichte CI/CD 3 keer minder regressies in productie.
Derde stap — monitoring in productie. Zelfs de beste tests garanderen geen 100% bescherming tegen regressies. Observability-tools (Sentry, Datadog, New Relic) moeten na elke implementatie de belangrijkste metrieken volgen: foutpercentage, latentie, doorvoer. Automatische terugdraaiing (rollback) bij overschrijding van drempels — een vangnet als een regressie toch in productie terechtkomt.
Vierde stap — code review met regressiedenken. De reviewer moet de vraag stellen: “Welke andere modules kunnen door deze wijziging worden gebroken?“. Het is niet voldoende om te controleren dat de code correct is — er moet worden gecontroleerd of deze geen aangrenzende functionaliteit verstoort. De checklist voor code review moet het punt “controle op regressies in aangrenzende modules“ bevatten.
Veelgestelde vragen
Regressie — is een bug die eerder niet bestond. Een gewone bug kan hebben bestaan sinds het maken van de functie. Regressie is altijd gekoppeld aan een specifieke wijziging — dit maakt het mogelijk om git bisect te gebruiken om de oorzaak te vinden.
Gebruik git bisect: geef de commit aan waar alles werkte en de commit waar het brak. Git voert een binaire zoekopdracht uit in de geschiedenis en vindt de commit die de regressie heeft veroorzaakt. Dit werkt zelfs voor grote projecten met duizenden commits.
Er is geen exact getal, maar er is een empirische regel: de dekking van kritieke gebruikersstromen moet 100% zijn, de dekking van alle functies — minimaal 70%. Kwaliteit is belangrijker dan kwantiteit: een test die een edge case controleert is meer waard dan tien tests op het happy path.
Ja, en dit wordt infrastructure regression genoemd. Het bijwerken van het besturingssysteem, de databaseversie, het SSL-certificaat of de webserverconfiguratie kan werkende code breken. IaC (Infrastructure as Code) en infrastructuurtesten (Test Kitchen, Terratest) helpen dergelijke regressies op te sporen.
Begin met één kritieke gebruikersstroom. Schrijf een automatische test voor het belangrijkste scenario (inloggen, bestelling plaatsen). Laat in een demo zien hoe de test een regressie vangt. Wanneer het team het voordeel ziet — implementeer testen stapsgewijs en breid de dekking uit.
Samenvatting
We ontwikkelen een mobiele applicatie turnkey
IT Sectr creëert sinds 2017 iOS- en Android-applicaties voor startups en bedrijven. We adviseren u en stellen de beste oplossing voor.
Lees ook