I går skrev David Heinemeier Hansson (DHH) et indlæg med titlen TDD is dead. Long live testing.
DHH skriver blandt andet at TDD leder til en nærmest fanatisk fokus på unittests – og her er jeg faktisk enig med ham i at det er usundt. Den pragmatiske tilgang er bedre uagtet af om der så er tale om unittest, integrationstests eller systemtests – det er den test du skrev for at nå målet der er relevant.
Men jeg uenig i, at der ikke er en gevinst i test-først principper.
TDD står som bekendt for test-driven-development så det handler altså om udvikling, ikke vedligehold. Derfor mener jeg at diskussion om hvorvidt TDD er vejen frem eller ej primært må handle om udviklerproduktivitet i udviklingsøjeblikket.
Når vi skriver en ny blok kode går vi ikke bare videre til den næste – vi bruger en stor del af udvikingstiden på at få den til at virke. Hvis vi kigger på ren nyudvikling tror jeg ikke at det er urealistisk at vi bruger 80% af tiden på at få det kode til at virke som vi har brugt 20% af tiden på at skrive.
Det er her tidlig feedback er vigtig. Det tager tid hvis man sidder med en applikation med en eller anden form for grafisk grænseflade og først skal starte applikationen op, måske trykke på et par knapper før nævnte blok bliver afviklet. Desuden ender man tit med at sidde og teste andre ting end nævnte blok pga. fejl ved applikationens andre grænseflader, eksterne services eller blot den interne tilstand der er forskellige fra sidst – og så mister man fokus.
Nu tager det også noget tid at skrive en fungerende test – sikkert meget mere end at trykke på et par knapper, men ofte er det forretningslogik der er i en test ikke meget forskellig fra det endelige logik der skal skrives. Prøv at tage en tilfældig forholdsvist isoleret funktion fra din eksisterende kode, læs den et par gange, forstå hvad den gør og skriv den forfra. Blev koden pænere?
I de fleste tilfælde bliver kode bedre når vi har erfaring med at løse det konkrete problem fra tidligere. Og det er den primære styrke ved at skrive tests først; vi får lov til at øve os lidt før den endelige kode skal skrives. Har du allerede løst problemet før, er der et mentalt overskud når du skriver den endelige kode, der kan bruges til at fange yderligere fejl, navngive bedre m.v.
At tests så, som DHH påstår, skulle føre til dårligere produktionskode er nyt for mig – af de kodebaser jeg er stødt på gennem tiden er det den utestede der har været sværest at forstå. Kæmpe klasser og lange funktioner er potentielle symptomer. DHH skriver om overdreven brug af abstraktioner og designpatterns som en mulig konsekvens af test først, men jeg ser det mere som et tegn på udviklingsnørderier og en slags Cargo Cultisme der er opstået siden GOF-bogen kom frem. Det misbrug hænger ikke sammen med test først.
TDD har stadig en plads i den professionelle udviklers værktøjskasse men bevar endelig den pragmatiske tilgang.
Om de tests vi måtte have skrevet giver værdi at gemme til fremtiden er en anden diskussion som jeg vil adressere en anden gang.
Hvis man ser Davids keynote fra railsconf 2014 (som i øvrigt er rigtig god) så virker hans pointe ikke så voldsom, da han er bedre til der til at komme med eksempler på hvad han mener.
Davids pointe er efter min forståelse også mest den del med, at folk føler de skal have dårlig samvittighed hvis de ikke laver TDD all the time.
Men god post du har skrevet, og det er rigtig vigtigt at få folk til at få et rigtigt forhold til TDD. 🙂
Jeg er lige ved at tro at det er skadeligt at lave TDD all the time 🙂
Der er helt klart stor forskel på hvor det gavner og hvor det ikke gør – og så er vi jo også forskellige, jeg kan godt lidt at vise folk hvad man kan få ud af det og så håbe at de selv ser lyset. Jeg håber så ikke at det giver dårlig samvittighed bagefter når de skrotter teknikken – det skal man huske at have med, at de selv må vælge til og fra.
Tak for feedback 🙂
Hvis man ser Davids keynote fra railsconf 2014 (som i øvrigt er rigtig god) så virker hans pointe ikke så voldsom, da han er bedre til der til at komme med eksempler på hvad han mener.
Davids pointe er efter min forståelse også mest den del med, at folk føler de skal have dårlig samvittighed hvis de ikke laver TDD all the time.
Men god post du har skrevet, og det er rigtig vigtigt at få folk til at få et rigtigt forhold til TDD. 🙂
Jeg er lige ved at tro at det er skadeligt at lave TDD all the time 🙂
Der er helt klart stor forskel på hvor det gavner og hvor det ikke gør – og så er vi jo også forskellige, jeg kan godt lidt at vise folk hvad man kan få ud af det og så håbe at de selv ser lyset. Jeg håber så ikke at det giver dårlig samvittighed bagefter når de skrotter teknikken – det skal man huske at have med, at de selv må vælge til og fra.
Tak for feedback 🙂
Nu skal jeg ikke tale for David, men efter min mening er en af udfordringerne med TDD at linien mellem hvornår der er tale om Test Driven Development og hvornår der er tale om Test Driven Design er mudret.
At bruge TDD til at drive API design, etc. er rigtig fint. At bruge TDD til at give svar på arkitekturelle og stor skal design udfordringer (så som at identificere bounded contexts) er jeg mere skeptisk overfor. Meget af den dogmatiske TDD praksis jeg har været “udsat” for resulterede tit i en overdreven fokus på UNIT tests hvilket efter min erfaring ikke er sundt og ret wasteful; fordi man nemt kommer til at sidde med skyggeklapper på tester uden at tænke på de større sammenhænge. Jeg har set MEGET af den slags kode (og ikke mindst unit test kode inkl. mocks, stub, etc) skulle skrives om, blot fordi man ikke tog sig 1 time eller 1 dag (alt efter scope og projekt) til at tænke sig lidt om. Det er ok at skrive kode om fordi man bliver klogere, men det er ikke ok at skrive om fordi man dogmatisk ikke vil tænke længere end denne eller næste test. I min verden er det lige så slemt som Big UpFront Design.
Er TDD derfor dårligt? Det synes jeg ikke, så længe det ikke bliver for dogmatisk. Efter min erfaring fungerer kryds funktionelle test (eller behaviour tests) med lavere indhold af unit tests rigtigt fint, da balancen falder bedre ud til fordel for test på resultatet og ikke på hvordan (hvilket også skaber mere stabile tests).
Tak for feedback.
Kan kun erklære mig helt enig – det er noget helt fundamentalt om hvordan man starter på en ny slice i sit system hvor man ikke undgår at tænke sig om. Jeg har da til tider også prøvet at sidde og skrive kode med tests der I perspektiv ikke passede særligt godt ind.
Når man skriver ny kode handler det jo om integration – så der hjælper unittests naturligvis ikke, det er næsten en selvfølge. Men der er meget at hente ved at teste integrationer og opførsel, som du også er inde på.
Nu skal jeg ikke tale for David, men efter min mening er en af udfordringerne med TDD at linien mellem hvornår der er tale om Test Driven Development og hvornår der er tale om Test Driven Design er mudret.
At bruge TDD til at drive API design, etc. er rigtig fint. At bruge TDD til at give svar på arkitekturelle og stor skal design udfordringer (så som at identificere bounded contexts) er jeg mere skeptisk overfor. Meget af den dogmatiske TDD praksis jeg har været “udsat” for resulterede tit i en overdreven fokus på UNIT tests hvilket efter min erfaring ikke er sundt og ret wasteful; fordi man nemt kommer til at sidde med skyggeklapper på tester uden at tænke på de større sammenhænge. Jeg har set MEGET af den slags kode (og ikke mindst unit test kode inkl. mocks, stub, etc) skulle skrives om, blot fordi man ikke tog sig 1 time eller 1 dag (alt efter scope og projekt) til at tænke sig lidt om. Det er ok at skrive kode om fordi man bliver klogere, men det er ikke ok at skrive om fordi man dogmatisk ikke vil tænke længere end denne eller næste test. I min verden er det lige så slemt som Big UpFront Design.
Er TDD derfor dårligt? Det synes jeg ikke, så længe det ikke bliver for dogmatisk. Efter min erfaring fungerer kryds funktionelle test (eller behaviour tests) med lavere indhold af unit tests rigtigt fint, da balancen falder bedre ud til fordel for test på resultatet og ikke på hvordan (hvilket også skaber mere stabile tests).
Tak for feedback.
Kan kun erklære mig helt enig – det er noget helt fundamentalt om hvordan man starter på en ny slice i sit system hvor man ikke undgår at tænke sig om. Jeg har da til tider også prøvet at sidde og skrive kode med tests der I perspektiv ikke passede særligt godt ind.
Når man skriver ny kode handler det jo om integration – så der hjælper unittests naturligvis ikke, det er næsten en selvfølge. Men der er meget at hente ved at teste integrationer og opførsel, som du også er inde på.
Uncle Bob og Gary Bernhardt blandt andre er også kommet med nogle gode indspark i ‘debatten’ synes jeg:
http://blog.8thlight.com/uncle-bob/2014/04/25/MonogamousTDD.html
https://www.destroyallsoftware.com/blog/2014/tdd-straw-men-and-rhetoric
Uncle Bob og Gary Bernhardt blandt andre er også kommet med nogle gode indspark i ‘debatten’ synes jeg:
http://blog.8thlight.com/uncle-bob/2014/04/25/MonogamousTDD.html
https://www.destroyallsoftware.com/blog/2014/tdd-straw-men-and-rhetoric