printf vs. debugger

Skal man bruge en debugger eller skal man sætte printfs ind i sin kode for at finde fejlen ?

Det er et forbavsende religøst spørgsmål og ofte aner man en generationskrig bag fronterne:

Den gamle garde har prøvet adb og tidlige versioner af gdb og er fandt ud af at livet er for kort til den slags.

De unge ulve er vokset op med grafiske IDE'er hvor debuggeren faktisk virker i et eller andet omfang og de kan ikke forestille sig hvordan man finder en fejl uden en debugger.

Det er tåbeligt ikke at bruge de værktøjer der findes, hvad enten det er debuggere eller syntax highlighting i psykedeliske farver.

Men hjernen er det eneste værktøj der gør nogen forskel i sidste ende og man skal tænke over koden for at kunne indsætte de rigtige printfs for at finde fejlen.

At tænke over koden er også den bedste måde at finde sikkerhedsfejl, bedre algoritmer, afrundingfejl osv.

Jeg synes jeg kan se en tendens til at folk der er debugger-fixerede løser problemer med små lapper rundt omkring, mens folk der bruger printf tager fat ved ondets rod.

Personligt indrømmer jeg gerne at jeg bruger debuggere, men kun til at få et backtrace. Alt det der med trace-points, value-traps og single-step, det rører jeg aldrig.

Er avancerede debuggere kun for folk der ikke kan kode og hvis de er, lærer disse folk så noget af at bruge dem ?

phk

Kommentarer (32)
sortSortér kommentarer
  • Ældste først
  • Nyeste først
  • Bedste først
#1 Peter Makholm Blogger

Jeg debugger også helst ved at skrive lidt debug-information ud på velvalgte steder i koden. Og som du selv skriver, så kræver det at man lige stopper op og vælger at skrive det rigtige ud.

Men når man har gjort det, så kan man lige så vel køre debuggeren, sætte en breakpoint og inspicerer den konkrete variabel fra debuggeren.

Om det ene eller andet er bedst afhænger så meget af situationen. Hvis det er en one-shot ting synes jeg at debuggeren er lige så velegnet som printf, men hvis man skal finde afvigelsen blandt 256 funktionskald, er printf måske bedst.

Men grundlæggende handler det som sagt at tænke lidt over problemet og formulere en arbejdshypotese før man gør noget.

  • 0
  • 0
#2 Erik Jacobsen

Jeg bruger begge - hvad der nu er nemmest, eller tilgængeligt.

Af hensyn til IDE-debuggeren forbereder jeg koden med linier som (VB.NET):

dim breakpoint2 as int32 = 2 'passende kommentar.

som ikke fjernes i produktionskode. Desuden er der andre regler, der gør debugging nemmere: fx "single exit point" fra funktioner.

  • 0
  • 0
#3 Rasmus Morten Helbig Hansen

I dag er den fremadstormende metodik vel skruet sådan sammen at man hverken bruger printf eller debugger.

Debugger support is like nail-biting support, or farting-in-public support. Its absence is a feature. You want to avoid supporting bad habits. If programmers have to break their bad habits, that's a good thing.

(http://gilesbowkett.blogspot.com/2007/10/debugger-support-considered-har...)

  • 0
  • 0
#4 NA NA

TDD er kun en fremadstormende metodik for dem som hverken har talent eller indsigt i softwareudvikling :).

Hvis man har skrevet sine test først vil ens kode i højere grad være fejlbehæftet da ens kode bliver funktionel i natur, typisk har en total mangel på meningsfyldte koncepter og som følge deraf er mere kompleks og svær at forstå. Dette sker fordi man fokusere for meget på input/output og fordi man vil have en tendens til at stoppe med at refaktorere når ens test er grønne. En langt mere fornuftig tilgang er at skrive noget kode, refaktorere indtil man begynder at have nogle gode koncepter på plads og så skrive ens tests når man er klar til at stabilisere ens kode.

Uanset hvordan man udvikler software vil der altid opstå fejl og man vil stå i den situation at en unit test fejler.

Hvis man kører TDD helt i ekstremerne så giver man fuldstændigt op overfor at forstå hvorfor ens kode ikke virker og undo'er ændringer indtil man når tilbage til noget der virker og så skriver man det om.

Hvis man ikke har lyst til at udvikle software af ringe kvalitet i slowmotion så kan man få brug for at inspicere værdien af ens variable. Det kan man så gøre på en ekstremt ineffektiv måde ved at skrive printfs - ja eller også kan man bruge en debugger :).

  • 0
  • 0
#5 Bjarke Walling

Nu bruger jeg noget af min fritid på at skrive mit eget operativsystem; det der kaldes OSDev. Udover at det nogle gange er frustrerende, så er det også sjovt og spændende, når det virker, og i sidste ende lærerigt.

Jeg har indtil nu benyttet mig af printf-metoden. Det er vist den gængse metode, da den er nem at komme igang med. Dog er der i virtuelle maskiner som QEMU og Bochs mulighed for debugging. Det er jeg så småt begyndt at bruge, men jeg synes det er for besværligt. Det er et helt nyt sprog man skal lære. Jeg går ind for test-drevet udvikling. Det er det jeg gerne vil have. Jeg er gået igang med at udvikle et library, der giver mig mulighed for at teste min OS-kerne. Det fungerer ved at hooke ind i debuggeren i en virtuel maskine. På den måde kan jeg eksternt styre og teste min kerne. Jeg har også en idé med at den single-stepper igennem alle tests, hvorved jeg får viden om test coverage. Det kræver selvfølgelig jeg compilerer min kerne med debugging-symboler. Det er utrolig spændende - og nok ikke noget Linus Torvalds nogensinde ville benytte. Det skal også siges at man altid skal teste sin OS-kerne på rigtig hardware engang imellem, da virtuelle maskiner ikke har de samme småfejl og bugs.

Mvh. Bjarke

  • 0
  • 0
#6 Bjarke Walling

TDD er kun en fremadstormende metodik for dem som hverken har talent eller indsigt i softwareudvikling :).

Det er jeg ikke enig i. Det bliver selvfølgelig noget rod, hvis du ikke er god til at refactor. Men mestrer du det, giver det sikkerhed for ikke at ødelægge funktionalitet som før virkede.

Mvh. Bjarke

  • 0
  • 0
#7 Deleted User

Er avancerede debuggere kun for folk der ikke kan kode og hvis de er, lærer disse folk så noget af at bruge dem ?

Spørgsmålet er lidt for enkelt.

Folk der kan kode, bruger som regel begge dele afhængig af, hvad der nu lige er tilgængeligt og nemmest. Jeg selv bruger sjældent source-level debuggeren, da det oftest er en tidsrøver. Source-level-debuggeren kan være god til at få overblik over det dynamiske forløb i en programtekst, man ikke selv har skrevet, eller har skrevet for længe siden og glemt alt om. Det er højst personlig smag, hvad der lige passer den enkelte bedst. Jeg bruger også selv test til at hjælpe med programmeringen. En "printf" kan naturligvis være hvad som helst - fx en lysdiode, et bip, eller hvad fantasien nu sætter grænse for - der giver noget uddata i en eller anden nyttig form.

For folk, som ikke kan kode, og dybest set ikke ønsker at forbedre sig, så har jeg med egne øjne set, at de moderne IDE'er, herunder debuggeren, faktisk er med til at forværre både programdesign og deres evner. IDE'en hjælper her med at få spyttet endnu mere dårlig programtekst ud, ikke mindre, og debuggeren forstærker blot deres selvfølelse af at være produktive, og af at have lavet noget godt, selvom det modsatte er tilfældet. Jeg har også observeret fænomenet hos potentielt dygtige programmører, hvor det så tager dem længere tid at blive gode.

For folk som gerne vil blive bedre til at programmere, så hjælper næsten hvad som helst, som lige får sat gang i deres synapser. Det er igen personligt, hvad der fungerer bedst. Her har jeg dog observeret, at de fleste bruger source-level-debuggeren mindre og mindre hen over tid.

Så lidt kortere sagt, så må mine svar blive nej, og ja - sidstnævnte under betingelse af, at de rent faktisk ønsker at lære noget!

Mvh. Dennis Decker Jensen

  • 0
  • 0
#8 Michael Rasmussen

En ting der ikke er blevet nævnt, er anvendelsen af asserts mv. som del af en test strategi.

Anvender man glib findes der indbyggede avancerede asserts, der også kan returnere en værdi i tilfælde af en fejltilstand.

f.eks: void foo(char* bar) {

g_return_val_if_fail(bar != NULL, NULL); .... }

  • 0
  • 0
#9 Mark Ruvald Pedersen

... det er også nemmere med embeddede systemer og mikrocontrollere.

Til CLI programmer, kan man med fordel implementere sit eget lille verbose system: 1) Lav din egen vradic printf wrapper, fx debugf. Lad første argument være en level enum, fx {quiet, normal, informative, everything}. Andet og 3. arg er naturligvis fmt og '...'.

2) Indsæt debugf's relevante steder med respektive levels.

3) Acceptér verbose-level flaget '-v [1-9]', og sæt en global variabel med værdien af level'en (her synes jeg globale vars er okay).

  • 0
  • 0
#10 Daniel Møller

Jeg anvender Visual Studio, men yderst sjældent debuggeren (tror faktisk kun jeg har brugt den til javascript debugging i IE)

printf føler jeg oftest er den hurtigste måde at finde ud af hvad der foregår på hvis man sidder og er lidt på bar bund.

Og arbejder man med multi-trådede applikationer så er IDE debuggerne somregel helt useless. Selv printf kan være et problem i den sammenhæng, så skal man til og over i noget statistisk debugging og det er ikke altid sjovt.

WinDbg kan også være løsningen, hvor man kan få listet callstacks for hver tråd eller laver et memory dump, som ofte også kan fortælle noget om hvad der er gået galt (f.eks. hvis der ligger mange instancer af en klasse, som der burde være færrer af). WinDbg kan også anbefales til produktionsdebugging, selvom det ofte er et overset værktøj.

  • 0
  • 0
#11 Henrik Schmidt

Jeg bruger kun printf el. lign. hvis jeg ikke har andre muligheder. Det lidt trælse ved printf statements er, at man skal fjerne dem igen, så jeg foretrækker at bruge et log framework i stedet. Debuggeren bliver da også brugt, selvom det er relativt sjældent, men jeg har ikke noget fast princip for, hvornår jeg bruger det ene eller det andet udover, at jeg forsøger at lade så meget information blive tilbage i koden som muligt.

Jeg er også efterhånden begyndt at bruge assertions i Java-regi, og unit-tests ser jeg også som brugbare, selvom jeg ikke er specielt religiøs omkring dem. Det handler for mig igen om, at assertions og tests kan tydeliggøre, hvordan koden er tænkt, og at man ikke smider denne information væk bagefter.

Jeg stiller mig meget tvivlende overfor, om man kan skelne gode programmører fra dårlige udelukkende ud fra, hvilke værktøjer de benytter sig af i denne sammenhæng.

  • 0
  • 0
#13 Henning Makholm

Kan du ikke bare prefixe outputtet med 'Tråd X: '?

Nytter ikke meget hvis man leder efter en race condition. Den tid det tager at konstruere sporingsudskriften i én tråd kan give en anden tråd tid til at blive færdig med at opdatere en delt datastruktur tidsnok til at fejlen ikke viser sig alligevel.

  • 1
  • 0
#14 Daniel Møller

Jo det kan du godt og til små applikationer der gør lidt brug af nogle worker-threads kan debugging også godt fungere på det plan.

Har du derimod en meget asynkron skrevet serverapplikation, så ender du ofte ud i "information overload". Det er specielt morsomt hvis man har en situation hvor et problem først opstår ved f.eks. 10.000+ forbundne klienter.

Iøvrigt er jeg enig med Henrik i at man ikke bør bruge printf direkte, men istedet bør have et debugging system der kan styre informationen lidt bedrer end printf - men jeg går ud fra det der menes er mere "printf debugging" som koncept :)

  • 0
  • 0
#15 Daniel Møller

Ja race conditions kan også give nogle sjove problemer med den teknik.

Hvis man ikke laver en låsning på data der dumpes til en fil f.eks. så risikerer man at få noget værre garbage data som det er alt for tidskrævende at få noget fornuftigt ud af - det sjove er så at løser man den ved at indføre en lås i forb. med skrivningen så løser man ofte race conditionen i forsøget på at udskrive debug information :)

Generelt er debugging af trådede applikationer en art i sig selv og ofte fandens tidskrævende.

  • 0
  • 0
#16 Morten Nissen

Hvis man har skrevet sine test først vil ens kode i højere grad være fejlbehæftet da ens kode bliver funktionel i natur, typisk har en total mangel på meningsfyldte koncepter og som følge deraf er mere kompleks og svær at forstå. Dette sker fordi man fokusere for meget på input/output og fordi man vil have en tendens til at stoppe med at refaktorere når ens test er grønne. En langt mere fornuftig tilgang er at skrive noget kode, refaktorere indtil man begynder at have nogle gode koncepter på plads og så skrive ens tests når man er klar til at stabilisere ens kode.

Hmmm, på en og eller anden måde er jeg enig, er det en tanke du selv har fået?

  • 0
  • 0
#17 NA NA

Jeps - nogle tanker jeg har gjort mig efter at have været på projekter med folk som er meget begejstret TDD.

Det har taget mig mange år at udvikle en vis "stilart" som jeg har opnået rigtig gode resultater med og som jeg har erfaring for passer godt til min personlighed og temperament. En "stilart" som iøvrigt variere meget i forhold hvilket projekt jeg er på.

Generelt er jeg meget skeptisk hver gang der kommer en ny religion som mener at have fundet den eviggyldige sandhed om hvordan MAN skal udvikle software. Den bedste måde at udvikle software på afhænger rigtig meget af ens personlighed og det projekt man arbejder på.

  • 0
  • 0
#18 Peter Favrholdt

Helt sjovt bliver det når koden styrer et eller andet (f.eks. en robot). Breakpoints duer ikke (så får man slag af robotten, når servoen stopper) og printf stjæler cpu og io så den tidslige afvikling påvirkes (og robotten bevæger sig pludseligt i ryk)...

Min erfaring siger at det eneste rigtige er en form for shared memory og separat debug-mekanisme til at aflæse programmets tilstand uden at påvirke det (for meget).

Derudover er det rart at kunne "tvangsstyre" variable udefra - for at se om bestemte værdier giver den adfærd som man ønsker.

Begge dele kan laves så det ikke påvirker programafviklingen ret meget. Jeg har engang lavet noget perl-snask som fletter disse "funktioner" ind i et almindeligt C-program - på bedste aspektorienterede vis selvfølgelig ;-) Dvs. man kunne skrive programmet og disse aspekter hver for sig.

Til almindelige programmer bruger jeg en blanding af printf og gdb. I øvrigt bør nævnes ddd "Data Display Debugger" der kan vise komplette datastrukturer. Jeg tror ddd kunne have sparet et par søvnløse nætter ifm. en obligatorisk programmeringsopgave på uni hvor vi implementerede datastrukturen "splay-tree".

  • 0
  • 0
#19 Tommy Vestermark

Ved arbejde med embeddede systemer er printf sjældent særlig brugbar. Har man først én gang i sit liv prøvet at kalde printf fra en interrupt rutine lærer man på den hårde måde, hvor meget overhead printf egentlig medfører :-)

Ved tidskritiske multitasking systemer er det en stor hjælp med et godt log system, hvor det meste overhead flyttes ud i en lav-prioritets task. Man lærer også at sætte pris på features som automatisk tidsstempling, task naming, multiple log-levels og logfil med begrænset størrelse.

En god in-circuit emulator eller debugger er nu heller ikke at foragte - især hvis compile-rerun cyklen er meget tidskrævende eller omkostningsfuld. Nogle gange kan det tage dage at genskabe en fejl, og så rebooter man ikke bare sådan lige.

En event tracer, der kan vise task-switching, interrupts, brug af OS kald mm. er også et forbavsende nyttigt værktøj. Hvis man kender sit system godt, kan man nogle gange nemt se et problem ved bare at kigge på Gannt diagrammet. I multitasking systemer med input fra den virkelige verden er mange problemer af dynamisk karakter.

Andre gange skal man være glad for bare at have en lysdiode at blinke med - og så må vi heller ikke glemme det uundværlige oscilloscop :-)

Generelt handler det vel om at bruge det værktøj, der bedst løser opgaven, og en dygtig udvikler mestrer flere værktøjer. Religion er jo bare et andet ord for, at man ikke er åben over for at blive klogere...

  • 0
  • 0
#20 Henrik Jensen

Jeg bruger helst debuggeren hvor jeg kan komme til det og det giver mening (dvs. det er afhængigt af programmeringssprog + applikationstype), da jeg mener det har nogle fordele:

1) Nemmere overblik over større objekter i et objekthieraki og med mange properties, lister m.v.

2) Du kan udskifte variabel/parameter-værdier on-the-fly og så lige gå et par kode statements tilbage og køre videre i stedet for at skulle starte ny testkørsel med andre variabel/parameter-værdier.

3) Du kan rette din fejl (eller forsøge på) on-the-fly og så igen lige gå et par kode statements tilbage og så køre videre derfra og se om fejlen er rettet unden at skulle bruge tid på at kompilere igen, foretage ny testkørsel m.v.

Så selv om det er noget nymodens pjat så synes jeg at det er hurtigt at debugge på den måde når man vel og mærke bare husker at bruge værktøjerne ordentligt. Det første stykke tid efter at Microsoft indførte 'Edit And Continue' i Visual Studio, tog jeg ofte mig selv I at sidde og stoppe debuggeren, rette min kode og så starte debugging igen, i stedet for blot at rette min kode mens debuggeren stadig kører og så ligge hoppe et par kode statements tilbage før min rettelse og forsætte herfra.

Om man lærer mere ved at bruge printf end debuggeren? Det ved jeg ikke, selve rettelsen af din fejl er jo stadig den samme uanset med hvilken metode du finder frem til den og efter min mening er det vel primært selve fejlen og rettelsen heraf man lærer af.

  • 0
  • 0
#21 Ole Østergaard

Dette sker fordi man fokusere for meget på input/output og fordi man vil have en tendens til at stoppe med at refaktorere når ens test er grønne.

Så kører du jo ikke efter "red/green/refactor". Hvis du gjorde det, ville du huske at refaktorere selv når testene er grønne - deraf navnet.

Glemmer du at refaktorere, kan jeg godt forstå at du ikke har gode erfaringer med TDD...

  • 0
  • 0
#22 Rasmus Morten Helbig Hansen

Sune Thrane:

test først vil ens kode i højere grad være fejlbehæftet

Der findes nogle undersøgelser af emnet.

Maximilien, Williams - Assessing Test-Driven Development at IBM:

the relatively inexperienced team realized about 50% reduction in FVT defect density when compared with an experienced team who used an ad-hoc testing approach for a similar product. They achieved these results with minimal impact to developer productivity.

George, Williams - A Structured Experiment of Test-Driven Development:

TDD practice yields code with superior external code quality.

Janzen, Saiedian - "Test-Driven Development: Concepts, Taxonomy, and Future Direction" samler flere af disse undersøgelser i letlæselig tabelform.

Det er rigtigt at test-først strategien typisk har en indvirkning på design. Jeg kender kun til undersøgelsen af Janzen, Saiedian - On the Influence of Test-Driven Development on Software Design. Denne giver dog ikke et entydigt resultat.

Sune Thrane:

udvikle software af ringe kvalitet i slowmotion

Der er vist en tommelfingerregel, som siger, at en udvikler skal være villig førend en ændring i arbejdsmetode kan have en positiv effekt.

  • 0
  • 0
#23 NA NA

Hej Ole - interessant kommentar

De tidligere kommentare jeg har skrevet gik mere på observationer af andre som bruger TDD - da jeg som nævnt har min egen stil. Der er i mine øjne to helt forskellige slags refaktorering:

  1. Det som Eric Evans kalder "Refactoring Toward Deeper Insight" eller "Breakthrough Refactoring" altså store ændringer af koden som gør at man gradvist når frem til en god domæne model med nogle gode koncepter og et overordnet design der giver mening. Altså noget der finder sted på tværs af klasser og metoder

  2. "Finpudsningsrefaktorering" som folk der bruger TDD går meget op i - går mere ud på at sikre kodekvalitet af enkelte metoder - eksempelvis med defensive coding, guards, asserts etc.

Nummer 1 er i mine øjne langt vigtigere end nummer 2. Det er bare min erfaring at folk der går meget op i TDD har en tendens til at fokusere for meget på det enkelte træ og for lidt på skoven når vi snakker kode kvalitet.

TDD folk ryder op efter at de har "snydt" til at få testen til at blive grøn og så kigger de på den enkelte metode og siger til sig selv det ser sørme flot ud og går videre.

Et andet grundlæggende problem er at man derefter står tilbage med en gigant masse af tests som gør det (endnu) mere besværligt at lave store refaktoreringer og motivationen til at lave disse falder.

Når man fokuserer så meget på input/output så er der en tendens til at man ender op med en ikke eksisterende model, et dårlig design, manglende koncepter og en masse klasser som ikke ER noget men som bare GØR noget.

  • 0
  • 0
#24 David Rasmussen

Jeg har prøvet begge dele, intensivt. Jeg har arbejdet i miljøer hvor man ikke havde anden mulighed end at skrive til stderr/en fysisk fil/en eller anden form for log/RS232, og jeg har (siden de tidlige 90ere) brugt de debuggere jeg har haft til rådighed.

Det er sundt at kunne begge dele. Men hvis jeg skal vælge mellem dem, så er en god debugger klart at foretrække. Den kan det samme som dine printf()-linjer, og mere til.

Især når jeg har skulle fejlfinde i dybt paralleliserede, rekursive algoritmer, har det været uundværligt (selv om man også her engang imellem lige prøver med en simpel printf()).

  • 0
  • 0
#25 NA NA

Hej Rasmus

the relatively inexperienced team realized about 50% reduction in FVT defect density when compared with an experienced team who used an ad-hoc testing approach for a similar product. They achieved these results with minimal impact to developer productivity.

Nu er det jo sådan at folk som ikke har så meget erfaring har en tendens til slet ikke at skrive tests. Det er jo ikke en fair sammenligning - jeg argumentere for at skrive sine tests midt i forløbet - ikke for at man overhoved ikke skal skrive tests! Det afhænger iøvrigt meget af situationen og jeg kan sagtens finde på at skrive testen først hvis jeg står med noget som er meget veldefineret.

Der er da også nogle postive ting og sige om folk der går ind for TDD - typisk for de skrevet væsentlig flere tests end folk som ikke går ind for TDD og typisk er kvaliteten af de enkelte metoder højere. Det interessante er at de positive resultater fra TDD faktisk er tilnærmelsevis målbare eksempelvis ved code coverage og komplexitetsmålinger af metoder - dvs man kan sikre sig at disse kvalitetskrav er opfyldt og dermed give udviklerne frihed til at opnå målene med egne midler.

Der er vist en tommelfingerregel, som siger, at en udvikler skal være villig førend en ændring i arbejdsmetode kan have en positiv effekt.

Som nævnt tidligere er mine kommentarer baseret på observation af andre som er vilde med TDD. Iøvrigt en meget typisk kommentar som jeg har mødt flere gange fra folk som er vilde med TDD (eller scrumm for den sags skyld) - når folk der følger deres "religion" opnår dårlige resultater så må det være fordi de ikke har fulgt "religionen" fuldt ud og iøvrigt fordi de er på tværs eller besværlige.

Næste gang skal vi bare have alle udviklerne til at være 100 % fanatiske tilhængere så vil alt gå godt. Det er baseret på en tankegang der siger at alle detaljer i religionen skal følges 100 % før "magien" opstår. Nu er det bare sådan at siden jeg aldrig har set magien opstå og iøvrigt ikke tror på magi så kan jeg ikke tilslutte mig religionen.

  • 0
  • 0
#26 Ole Østergaard

Hej Sune - også tak for et interessant modsvar!

Jeg mener ikke at unit-tests modvirker større refaktoreringer i koden - tværtimod gør de at man tør tage fat og gennemføre ændringerne. Selvfølgelig, hvis du har et system hvor de enkelte moduler ikke er afkoblede, så har du nok også et problem med at mange tests har afhængigheder til store dele af systemet, og så vil testene være svære at refaktorere - præcis ligesom din kode vil være svær at refaktorere. (Og så har du ikke unit-tests, selvom de måske køres i JUnit, NUnit eller et andet test-framework.)

Tilsvarende laver jeg også selv meget mindre defensiv kodning når jeg kører TDD, da jeg kun skriver defensivt hvis jeg kan lave en test der viser at jeg har brug for det. Resultatet er derfor meget renere, lettere forståelig kode - kode som man har meget mere mod på at refaktorere når man finder behov for det.

Men vi kan nok blive ved med at diskutere til dommedag, da vi nok dybest set har to lidt forskellige opfattelser af hvad TDD er. Den måde jeg praktiserer TDD på, har ikke vist sig at sætte sig på tværs af større refaktoreringer - i hvert fald ikke hvad jeg selv har observeret. (Om mine kollegaer så har bandet ad mig bag min ryg, ved jeg jo ikke...)

Kører man TDD uden også at tænke på andre aspekter af systemet (altså at klasserne hedder og gør noget fornuftigt, at man har fornuftige moduler, at man opfylder kundens ønsker osv. osv.), går det selvfølgelig galt. Men jeg har heller aldrig hørt nogen sige "brug TDD, og glem alt andet".

  • 0
  • 0
#27 Rasmus Morten Helbig Hansen

Det var vist dig som skrev noget om manglende evne og indsigt og ringe kvalitet og lav produktivitet. Jeg viser dig blot at nogle studier indikerer at der kan være kvalitetsforbedringer at hente ved at benytte en test-først strategi.

Ligesom et fjols nok altid vil være et fjols, så bliver en dårlig programmør nok ikke en god programmør ved et trylleslag. Og test-først er ikke engang magi.

  • 0
  • 0
#28 NA NA

Det var vist dig som skrev noget om manglende evne og indsigt og ringe kvalitet og lav produktivitet.

Der var en smiley :) Det var nu også mest ment som en provokation da jeg synes det er et interessant emne :)

Jeg viser dig blot at nogle studier indikerer at der kan være kvalitetsforbedringer at hente ved at benytte en test-først strategi.

Ja for folk uden så meget erfaring :). Det jeg skrev var:

TDD er kun en fremadstormende metodik for dem som hverken har talent eller indsigt i softwareudvikling.

Så du har faktisk delvist bevist min pointe :) Det er i hvert fald de færreste som ikke har meget erfaring som har opnået den helt store indsigt endnu.

Iøvrigt anerkendte jeg i et af mine tidligere indlæg at der kan være positive effekter af TDD min pointe er bare at disse effekter kan man godt opnå uden TDD og uden at få de mange negative effekter som jeg har nævnt i flere af mine indlæg.

Ligesom et fjols nok altid vil være et fjols, så bliver en dårlig programmør nok ikke en god programmør ved et trylleslag. Og test-først er ikke engang magi.

Ja og en dårlig programmør bliver heller meget bedre hvis han fokusere meget på ting som ikke er så vigtige - i stedet for at fokusere på det der er vigtigt

  • 0
  • 0
#29 Ole Østergaard

Ja og en dårlig programmør bliver heller meget bedre hvis han fokusere meget på ting som ikke er så vigtige - i stedet for at fokusere på det der er vigtigt

En af pointerne i TDD er netop at når man har fået det ind under huden, bekymrer man sig mindre om "de små ting", altså fx om man kommer til at ødelægge en eller anden subtil funktionalitet når man refaktorerer. Man kører hele tiden sine tests, og hvis de konstant er grønne, så har man en vis grund til at tro at systemet stadig fungerer. Bliver de røde, er det kun 2 minutter siden du har kørt dem sidst, og så kan du lynhurtigt "bakke tilbage" og lave de par linjer om du lige har lavet.

Og tests er jo dybest set ikke andet end specifikationer af hvad dit system skal kunne. Det skal du finde ud af alligevel efterhånden som systemet udvikler sig - og hvorfor sidde og "kode i blinde" uden at vide hvad det egentlig er for krav man prøver at opfylde, i stedet for at lade testene guide dig? Så har du også testene som et godt biprodukt - en komplet beskrivelse af hvad dit system kan, hverken mere eller mindre.

Men selvfølgelig, laver man kode som ingen andre kan læse (og derfor ikke tør rette i), laver man intetsigende klasser, laver man slet ikke den funktionalitet som kunden ønsker, så kan det hele selvfølgelig være ligegyldigt, men så er det måske programmøren eller den proces virksomheden følger, der skal rettes op på. (Eller man kan læse "Clean Code" af Robert Martin - super bog!!)

  • 0
  • 0
#30 Stig Johansen

Jeg tror det er her en del af forklaringen ligger.

Selv har jeg rodet med EDB siden '80, og i forhold til kodekvalitet og debuggere er der to ting jeg kommer til at tænke på.

Med hensyn til debuggere er det meget nemt, for der var ikke rigtig nogle debuggere til eks. store COBOL-batch programmer.

Men kodekvalitet. Det er sikkert uhørt i dag, men selv et ikke ret stort program(modul) tog mere end 20 minutter at kompilere. Man satte typisk kompileringen igang umiddelbart før frokostpausen.

Hvis man udviklede på baggrund af 'coding by reading compiler errors' ville man aldrig blive færdig.

Et andet eksempel var nogle jendomsmælgersystemer på de tidlige PC'ere. Her brugte vi Turbo Pascal, der havde den egenskab at stoppe ved første compiler fejl. Her tog en kompilering også ca. 25 minutter. Jeg havde selv lavet et modul, der lå 'sidst'. Den stoppede efter ca. 25 minutter med 'missing ;'. S*tans, jeg havde ikke tid til den slags (fast pris) - ind på den pågældende linie og tilføje ;. 25 minutter efter : 'Error: missing ;' Hvad havde manden gjort ? Yes - copy/pasted.

Nå - men det jeg vil frem til er at undertegndede, og sikkert mange andre, har fået den slags 'ind med modermælken', så kontinuert kvalitetssikring af kodearbejdet er en naturlig del af processen.

De 'yngre' generationer har ikke, og vil formentlig ikke, opleve disse problemstillinger da HW er blevet en del hurtigere.

WRITE/WRITELN ctr. debugger ? Jeg har altid været vant til at bruge strategisk placerede udskrifter, så det bruger jeg primært.

Men som nævnt ovenfor gør jeg meget ud af den initielle kode, så det er sjældent der er brug for det helt store debug.

Om det er mere effektivt eller ej vil jeg ikke udtale mig om.

Det er et spørgsmål om tidsforbrug på udvikling ctr. tidsforbrug på fejlfinding.

Jeg vil gætte på afvejningen er individuel fra person til person.

  • 0
  • 0
#31 NA NA

Hej Ole

Her har du fat i noget meget centralt:

Man kører hele tiden sine tests, og hvis de konstant er grønne, så har man en vis grund til at tro at systemet stadig fungerer. Bliver de røde, er det kun 2 minutter siden du har kørt dem sidst, og så kan du lynhurtigt "bakke tilbage" og lave de par linjer om du lige har lavet.

Jeg mener ikke at det er en god ting at fokusere på om systemet fungerer i starten - i starten skal man i stedet fokusere på at få afklaret et overordenet design og sikre sig at kravne til system holder i praksis.

Det er en antagelse fra min side at det system du arbejder på er så komplekst at du ikke umiddelbart kan overskue hvordan det skal designes inden du har fået fingrene ned i det. Hvis det er så simpelt at et overordnet design giver sig selv så er det trivielt at udvikle det og egentlig ligegyldigt hvordan du gør det. Det er derfor vigtig at der er frihed til at lave meget store ændringer af systemet mens denne afklaring af et overordnet design og eventuelle store kravsændringer finder sted.

Problemet er at hvis du benytter dig af TDD så bliver du angstfyldt - du tør ikke lave de store ændringer som er vigtige i starten fordi de ikke nemt kan undoes, kan "ødelægge" for meget og refaktorings funktionerne i din favorit ide ikke understøtter store "breakthrough" refakoreringer.

En anden ting er at når du debugger igennem dit system så ser du din kode med andre øjne end når du sidder koder - du får øje på skoven! Det er ret ofte her at du får øje på eventuelle overordnede problemer.

Nå anyway tak for en interessant debat jeg tror ikke vi bliver enige :)

  • 0
  • 0
#32 Rasmus Morten Helbig Hansen

for folk uden så meget erfaring

Nåh, var det det du mente. "Hverken talent eller indsigt" fik mig til at tro noget andet. ;-) Nåh men jeg mener egentlig ikke at nævnte studier indikerer at erfarne programmører ikke kan få en kvalitetsgevinst ved at benytte en test-først strategi. Snarere tværtom.

Der var iøvrigt en spændende og relevant debat om TDD ifbm JAOO 2007, hvor Jim Coplien udtalte noget i stil med at TDD vil degenerere din arkitektur. Jeg fandt sørme debatten mellem Coplien og Uncle Bob her: http://www.infoq.com/interviews/coplien-martin-tdd - konklusionen er vist at TDD brugt forkert kan virke modsat intentionen.

  • 0
  • 0
Log ind eller Opret konto for at kommentere