Kritik mot TDD (och några svar)

På sista tiden har det dykt upp en del kritik mot Testdriven utveckling (TDD). Som stark förespråkare av TDD är jag naturligtvis intresserad av att se vad folk opponerar sig mot. Kanske har de en poäng och kanske bör jag vara mindre entonig i mitt TDD-mantra? Låt oss se efter.

Coplien på JAOO
Från JAOO och andra konferenser har Jim Coplien basunerat ut sitt budskap att TDD inte är bra (“the ugly step-child of XP”, som jag har för mig att han kallade det i en intervju som jag läste). Jag tycker personligen att hans attityd mot Robert C Martin var burdus och tämligen respektlös. Men låt oss förbise sådana saker och koncentrera oss på hans budskap, i den mån jag kan förstå dem.

Om jag tolkar honom rätt är hans första kritik den att TDD inte skapar bra arkitektur eftersom man fokuserar på att göra det enklast möjliga som kan fungera (YAGNI). Hans exempel är att reducera ett bankkonto till ett tal, en siffra, vilket aldrig kan fungera i en seriös bankapplikation.

Mitt svar: Jag tror att det finns en uppenbar risk att man missuppfattar YAGNI. Det innebär inte den enklaste jag kan tänka ut utan den enklaste, snyggaste lösningen av de som faktiskt skulle kunna fungera. För en större bankapplikation kommer inte en siffra att vara ett element i mängden av möjliga lösningarna. (För en applikation som hanterar privatekonomi kan det kanske vara det.) Jag tror att Coplien utnyttjar detta missförstånd för sina egna syften, eller så har han helt enkelt inte förstått.

Jag tror vidare att Coplien kraftigt undervärderar värdet av refaktorisering och hur vi kan bygga design och arkitektur bit för bit, mer och mer generellt, komplexare bara när det behövs, det vi kallar evolutionär design. Vissa saker kan inte TDD:as fram, helt korrekt, men paket, lager och delsystem är faktiskt inte någon av dessa saker (aspekter, loggning, trådhantering är det däremot).

Copliens andra kritik är mer svårförståelig. Han påstår att han har sett applikationers gränssnitt, deras GUI:n, förstöras på grund av TDD. Tyvärr har jag inte förstått exakt varför han tror att TDD har något med detta att göra.

Mitt svar: Jag kan tänka mig många skäl till att gränssnitt blir ointuitiva, men TDD skulle nog inte vara med på min lista. Om skälet skulle vara att utvecklarna har tvingats att arbeta med en funktionsbit i taget (s.k. sashimi) förstår jag att resultatet kan bli plottrigt… om man samtidigt inte har haft en vision, en informations- och navigationsstruktur och en bra UX-designer i sitt team. Jag har svårt att se detta annat än som ett misslyckande hos personerna med det övergripande blicken över det gränssnitt som ska skapas – inte hos TDD. Om Coplien menar att GUI:t blev dåligt därför att utvecklarna testdrev fram det så förstår jag nog ännu mindre. Om någon som läser detta kan se kopplingen så vill jag gärna veta.

Cédric Beust på QCon San Fransisco 2007
Jag har precis hört en intervju med Cédric Beust på InfoQ. Cédric jobbar på Google och är bl.a. en av personerna bakom testramverket TestNG. Cédric är, enligt egen utsago, “något skeptisk” mot TDD. En av sakerna han menar är att eftersom så mycket av arbetet med TDD är vad han kallar “mikrodesign” (metoder eller delar av metoder) så har TDD en tendens att göra dig “närsynt”. Jag förmodar här att Cédric här menar att man inte har en bra överblick av designen.

Mitt svar: Jag håller med Cédric att detta är en fara, men bara om du inte använder seriös refaktorisering och designskisser på tavla. I refaktorisering ingår just att “ta ett steg tillbaka och reflektera över din design”. Det är tyvärr en vanlig missuppfattning att dessa saker inte ingår i TDD. Som vanligt i XP stödjer arbetssätten varandra på ett subtilt sätt och om man enbart gör TFP, dvs Test-först-programmering, är garanterat risken att du får en svag design. Om du använder refaktorisering för utbyggbarhet och förvaltningsbarhet är risken för närsynthet liten, enligt min mening.

Cédrics andra kritik var att man om man arbetar med TDD “långa stunder” befinner sig i ett tillstånd där inte koden kompilerar och man därför inte kan använda alla finesser i våra fina IDE:er och det skulle vara ett steg tillbaka.

Mitt svar: Återigen en kritik som är svår att ens begripa. Om jag får gissa, läsandes mellan raderna, så arbetar Cédric med att skriva en komplett testmetod för en hel metod för att därefter skriva en metod som får testet att gå igenom. Detta skulle få effekten att vi är i rött, så att säga, en stor del av tiden. Detta är inte bra TDD, det är alldeles för stora steg. Genom att ta mycket mindre steg kan vi, och bör vi, minimera tiden i rött. Låt mig vara tydlig: Det ingår i TFP att vara i rött (inte kompilera eller test är trasigt), men helst ska enbart ett enda test vara trasigt och vi gör allt för att minimera tiden där (enligt tumregel: 1. Make it work 2. Make it right).

Vidare, Cédric kan inte ha sett Robert C Martin genomföra en TDD-session för då skulle han inse och lära sig hur mycket nytta man kan ha av en IDE för att göra TDD (t.ex. Quick Fix-funktionen).

Allmänt mummel
Till sist en kritik som jag inte kan tillskriva till någon enskild person men som vi ofta hör när vi är ute och pratar om TDD. Det är farhågan att man med TDD måste göra om alltihop, eventuellt flera gånger. Alltså, att TDD leder till mycket omarbetning.

Mitt svar: Ja, detta är delvis sant (men inte i så stor omfattning som vissa tycks tro). Vi kommer att få omarbeta vår “enkla” lösning då och då därför att behoven visade att den inte var tillräckligt avancerad (komplex). Poängen är här att behoven först måste manifestera sig innan vi inför en mer avancerad lösning. Detta är En God Sak, eftersom en mer avancerad lösning är mer komplicerad att använda, svårare att förstå och underhålla. Vi vill hålla detta till ett minimum i våra system.

Så, hade det då inte varit bättre att designa den avancerade lösningen från början? Jo, om du har en perfekt fungerande kristallkula och kan förutspå framtiden. Men det finns ganska få trollkarlar bland oss. Vad TDD menar är att många gånger kommer inte den där “uppenbara” funktionen att göras och den generella lösningen sitter bara där och kostar pengar och att detta uppväger kostnaderna för någon eventuell omarbetning.

Min uppfattning att TDD är en teknik som tar tid att lära sig, men som är oerhört kraftfull. Den personifierar Toyotas tanke att vi bör bygga in kvalitet från början istället för att ägna en massa tid på att testa in den i efterhand. Vad är din åsikt?

4 thoughts on “Kritik mot TDD (och några svar)

  1. Coplien har en oförsonlig attityd då han har en avvikande mening, vilket leder till att han blir destruktiv i sitt argumenterande. Satt på en Michael Feathers dragning där han var med, och han ifrågasatte hela dragningens berättigande på ett ganska burdust sätt.

    Cedric har jag slutat bry mig om. Hans ovilja att förstå agile är historisk;

    http://marcus.ahnve.net/2003/01/29/pair-programming/
    http://marcus.ahnve.net/2006/06/09/cedric-still-dont-get-agile/

  2. I nästan alla fall – de fyra som du citerar ovan inkluderat – där TDD pekas ut som roten till det onda är TDD egentligen bara en markör för ett allvarligare problem: desajnen är redan dålig. Och faktum är att just lackmusegenskapen är en av de fina sakerna med TDD. Det är som att ha en Hesekiel i teamet, en väktare som varnar för hotande olyckor – både på makro- och mikronivå.

    Det här yttrar sig inte bara genom att test får negativt resultat. Det kan lika ofta visa sig genom att test är långa och svårbegripliga (Beust #2) eller att de är meningslösa (Beust #1). Utan TDD skulle desajnen ha varit precis lika dålig (Coplien), men dåligheten hade upptäckts senare och kostat mer att bota (“Allmänt mummel”).

    Motmedel? En adaptiv desajn genom refaktorering.

    http://brainmoda.wordpress.com/

  3. Jag gillar dina enkla svar på kritiken mot TDD. Det är intressant att så erfarna personer inte lyckas fånga känslan, för det är ju det handlar om. Men en känsla av helheten, inklusive refactoring, omstrukturering mm. som du mycket riktigt påpekar.

    Däremot håller jag inte med om att det skulle vara bättre att göra hela designen från början man visste allt om framtiden.

    Jag är kanske dummare än de flesta programmerare för jag har svårt att hålla reda på och komma ihåg “hela” designen. Jag använder TDD (inklusive refactoring) till att slippa tänka på en massa detaljer och interaktioner mellan olika delar av en mer komplex (eller komplett) lösning.

    För mig är det faktum att jag kan skriva några rader kod och veta att det var rätt eller fel, en välsignelse. Jag behöver aldrig ha mer i huvudet än så. Så även om jag visste allt om framtidens behov, så skulle jag testdriva fram den design som jag trodde att jag skulle få. Och jag är övertygad om att jag på vägen skulle inse att det fanns bättre lösningar.

    Ta t.ex Bowling-katan, efter 40 genomkörningar hittar jag fortfarande en del saker som jag skulle kunna göra annorlunda. Och det trots att vi vet precis kraven från början.

    En idé om en design är bra att ha från början, för det kan hjälpa att få en riktning i omstruktureringarna. Men baby-steps och emergent design är inte bara ett motmedel mot oförstådda krav, det hjälper också lata och obegåvade utvecklare som jag…

  4. Thomas,

    Tack för mycket bra kommentarer! Du har naturligtvis rätt. Mitt exempel var otydligt. Det jag tänkte mig var att man hade en kristallkula som även gav oss den perfekta designen – inte bara framtida behov. Men utan den behöver vi TDD, precis som du säger.

Comments are closed.