D J U P S T U D I E I E D A 2 7 0 S I M P L E C O D E A N D D E S I G N S. Marcus Jacobsson D03, Lunds Tekniska Högskola d03mj@efd.lth.se S. Magnus Weinberg D03, Lunds Tekniska Högskola d03mw@efd.lth.se Version 2.0 2006-02-20
Denna djupstudie tar upp vikten av simple code and design i ett XP projekt. Här tas det bland annat upp hur bad code identifieras och en kort sammanfattning av några av de viktigaste mönsterna i XP. Rapporten tar även upp en granskning av kod och design från en av utvecklingsgrupperna som läste kursen Programmering i grupp VT 2006 vid Lunds Tekniska Högskola. 2
Innehållsförteckning: 1 INTRODUKTION... 4 1.1 INLEDNING... 4 1.2 BAKGRUND... 4 2. TEORI OM SIMPLE CODE AND DESIGN... 4 2.1 SIMPLE CODE AND DESIGN... 4 2.2 DESIGN MÖNSTER... 5 2.2.1 Observer... 6 2.2.2 Singleton... 6 2.2.3 Command... 6 2.2.4 Abstract server... 7 2.3 AGILE DEVELOPMENT MOT BIG UPFRONT DESIGN... 7 2.4 METAFORER... 8 2.5 BAD CODE SMELLS... 8 2.5.1 Vanliga tecken på dålig kod... 8 2.5.2 Lösning i agila projekt... 10 2.6 KONSEKVENSERNA AV DÅLIG DESIGN... 10 2.7 VIKTEN AV REFAKTORISERING OCH TEST DRIVEN DEVELOPMENT... 10 3 GRANSKNING AV SIMPLE CODE AND DESIGN I XP TEAM... 11 3.1 GRANSKNING AV THE BLACK TEAM... 11 3.1.1 Mönster i koden... 11 3.1.2 Onödig komplexitet... 11 3.1.3 Agile design eller big upfront design?... 11 3.1.4 Bad code... 11 3.1.5 Utvecklingstopp... 12 3.1.6 Påverkan av refaktorisering... 12 3.1.7 Efter refaktorisering... 13 4 SAMMANFATTNING... 13 4.1 ETT EXTRA TACK TILL... 13 5 REFERENSER... 14 3
1 Introduktion 1.1 Inledning Detta är en djupstudie i kursen "Coaching av programvaruteam" på LTH. Djupstudien handlar om hur "Simple Code and Design" kan användas. Rapporten tar även upp vikten av att söka efter Bad Code i projekt. Djupstudien redovisar även resultatet av en analys av kod skriven av the black team och påpekar tecken på dålig kod. the black team är ett alias för en av utvecklingsgrupperna i kursen "Programmering i Grupp. Rapporten är inriktad på hur dålig kod ska upptäckas och lite om riskerna för vad som händer om man ignorerar det faktum att det finns dålig kod. Förhoppningen är att läsaren ska få en bättre inblick om vikten av bra kod i agila projekt. 1.2 Bakgrund I all programmering finns det vissa ramar man borde hålla sig innanför för att undvika onödigt arbete, fel och komplexitet. För att försöka minimera problem som onödigt komplex kod och felaktig design försöker programmeraren att använda sig av tekniker ur "Simple Code and Design" när han ska utveckla programmet och letar ständigt efter felaktigheter med hjälp av sin kunskap om "Bad Code Smells". Dessa finns i varierande utsträckning i alla projekt men med hjälp av kunskap och erfarenhet så kan de undvikas ganska effektivt. Med automatiska testsviter och tekniker som "Test First" så kan dagens utvecklare relativt enkelt refaktorisera felaktigheter och fortfarande vara säkra på att koden de skrivit fortfarande håller åtminstone lika hög kvalité som föregående versioner av koden. Huruvida ett stycke kod sedan kan anses vara enkel eller lättförståelig kan variera beroende på programmerarens kunskap och erfarenhet av tidigare sedda lösningar på problemet. I många fall kan det verka som att koden måste vara komplex för att uppnå rätt funktionalitet men detta stämmer oftast inte. 2. Teori om simple code and design 2.1 Simple code and design Med simple code and design menas en design som är enkel att förstå och samtidigt löser det problem som utvecklaren ska implementera. Detta utan att införa bad code samt någon onödig komplexitet. Den ska inte förväxlas med kod som är så enkel att den blir dum och då är omöjlig att arbeta vidare på. Designmönster är ett utmärkt sätt att genomföra simple design, man bör dock vara medveten om att det ger onödig komplexitet om man använder designmönster in absurdum. Vad som är simple design kan även variera beroende programmerarnas kompetens, en design som är enkel för en expert kan verka svårförståelig och komplex för en nybörjare. 4
Ett bra sätt att tänka när man ska skapa en design är att se till att man använder sig av tre grundläggande tankesätt ur XP: Consider the Simplest Thing That Could Possibly Work Se till att använda den enklaste lösning som uppfyller de kraven som är ställda. Var dock uppmärksam på att det inte alltid är den mest basala lösningen som är den bästa, tänk: simple, not stupid. Den enklaste lösningen är inte nödvändigtvis den lösning som är lättast att ändra. En lösning som är väldigt dynamisk innehåller ofta onödigt komplexitet. Enkel design betyder inte heller att det ska vara så få rader kod som måste ändras för att ny funktionalitet ska kunna implementeras. Ex. Det är bättre att använda en textfil för att lagra data än en databas om textfilen räcker för att täcka kraven på lösningen. You Aren t Going to Need It. Lägg inte ner kraft på att förutse framtida behov utan se istället till att nuvarande behov är tillgodosedda. Spenderar man tid på att förutspå framtiden så riskerar man att implementera funktionalitet som kunden inte vill ha. Once and Only Once. Istället för att lägga till duplicerad funktionalitet så är det bättre att generalisera funktionen. Första gången går det bra att göra något mindre generellt. Andra gången funktionaliteten behövs så får man refaktorisera och anpassa koden så att den kan uppfylla båda kraven. Duplicerad kod kostar mer att underhålla och uppdatera ( double maintenance ). Dubbel funktionalitet gör även projektet svårare att överskåda. 2.2 Design mönster För att underlätta för team med många utvecklare så använder man sig oftast av design mönster. Detta är mönsterlösningar som många utvecklare känner till. För många av de vanligaste problemen finns det bra mönster som underlättar implementering av funktionalitet. Detta sparar även utvecklarna mycket tid då de inte behöver uppfinna hjulet flera gånger. Eftersom XP kräver att utvecklarna är insatta i alla delar av koden så är det lättare om standard mönster används då utvecklarna inte behöver sätta sig in i en komplex lösning. Även om mönster kan lösa många problem så ska man inte använda mönster i onödan. Kan man uppnå tillräckligt bra resultat för att implementera en story utan att använda ett komplext mönster så är detta att föredra. Nedan beskrivs några mönster som kan anses passa väl in i ett agilt projekt, detta eftersom alla mönsterna följer SRP. Observer har valts då den är lämplig vid beroendekedjor som är viktiga att förstå t. ex. när man vill använda tabeller i AWT/Swing. Singleton är bra då man bygger en enkel databas och är ett bra exempel på hur en statisk referens till en klass kan användas. Command är ett exempel på hur klasser med ett gemensamt användningssätt kan fungera. Abstract server valdes pga. sin liket till Template och eftersom den beskriver arv på ett tydligt sätt, vilket är viktigt i all OO programmering. För mer information se Agile Software development av Robert C. Marting. 5
2.2.1 Observer Observer är ett av de mönster som kan vara svårt att förstå i början. Men när man väl lärt sig det så är det lätt att få det att passa in i ett projekt. Exempel på ställen där det kan tänkas fungera är ett excel liknande program där man använder mönstret för att hantera celler som uppdateras. Ett annat exempel kan vara att använda observer-mönstret för att utveckla ett gui med test first. Problemet med observer-mönstret är att det är svårare att förstå programmet och det blir svårare att söka. Detta strider mot Simple design. Därför bör man vara aktsam när man väljer att implementera observer-mönstret i XP. Men det är inte ovanligt att trots att det kan vara en komplex lösning så kan det vara den lättaste lösningen för att implementera ny funktionalitet. Fördelen med observer-mönstret är att det är lätt att lägga till en ny observerare utan att göra några ändringar i de objekt som blir observerade. Detta är väldigt viktigt i agila projekt då det ger en svag koppling mellan olika klasser. 2.2.2 Singleton I objektorientering finns det en riklig mängd av samband och förhållandesätt. Utav dessa förhållanden är ett av de mest grundläggande förhållandet mellan klasser och objekt där det brukar finnas ett en till flera förhållande mellan en klass och många objekt. Men sen har man ju situationer där man inte kan eller vill tillåta mer än ett objekt per klass. Ett av mönsterna som kan användas för att lösa ett sådant problem är singletonmönstret. En singleton skapar som mest ett objekt och håller sedan en statisk referens till sig själv som inte ska kunna förstöras. En singleton saknar alltid en konstruktor och ger ifrån sig en referens till sig själv genom en statisk metod ofta kallad instance. Exempel på bra tillfällen att använda singleton är Factory klasser eller då man vill ha en central hanterare. Detta mönstret kan användas för att hantera en global databas. Där det inte behövs mer än en instans som ska kunna nås i alla delar av programmet. Detta underlättar för utvecklare då de inte behöver skicka med en referens till klassen i projektet. Dock strider detta mot lösa kopplingar mellan klasserna, vilket är något man bör sträva efter i XP. 2.2.3 Command Ett av de mest lättförståeliga och användbara mönstren är just commandmönstret. Detta mönster använder sig av några av de mest grundläggande idéerna i objektorienterad programmering till grundstomme. Mönstret ger en förvånansvärt bra överskådlighet även i lite mer avancerade vidareutvecklingar. Detta mönster använder sig av ärvning eller interface för att uppnå en gemensam grund. Denna grund utnyttjas sedan för att skapa ett gemensamt sätt att använda en metod hos klasserna. Genom att bara ha en operation do (eller motsvarande) så skapas väldigt lösa kopplingar mellan klasserna. Detta är väldigt viktigt i agila metoder för att undvika att tester fallerar samt svåra merge konflikter. Command mönstret underlättar användning av klassen genom att påtvinga SRP. 6
2.2.4 Abstract server Möjligheten att enkelt kunna bygga ut, ersätta samt att lägga till klasser är några av de mest centrala delarna i objektorienterad programmering. Utan dessa möjligheter kommer ett projekt ha betydligt svårare att bli slagkraftigt i dagens mjukvaruindustri. Detta gör att användaren lätt kan lägga till ny funktionalitet genom att implementera ett interface. Eftersom klasserna som ska använda funktionaliteten bara känner till ett interface så behövs det inte göra någon ändring i de användande klasserna. Detta är en viktig del i XP då det läggs till ny funktionalitet utan så mycket tanke på design. Detta bidrar till lösa kopplingar mellan klasser vilket också är viktigt i XP. Ett praktiskt exempel på interface är i Sun s java awt där de flesta klickbara komponenter kan lägga till en eller flera lyssnare utan att specifikt deklarera deras klasser. 2.3 Agile development mot big upfront design I agila utvecklingsmetoder förespråkas en enkel liten design i början av ett projekt för att uppnå maximal flexibilitet. Denna grunddesign ska sedan utvecklas med tiden och till sist vara komplett. Detta fungerar mycket väl om både projektet och teamet är litet men för ett enterpiseprojekt med väldigt många utvecklare och en striktare krav-profil kommer detta ofta vara mindre slagkraftigt. Big upfront design innebär istället att hela projektets design fastslås innan någon funktionalitet implementeras. Problematiken som kommer med big upfront design är för det första att designen blir svårare att ändra för att implementera nya features samt att dålig design kan ge onödig komplexitet och duplicerad kod. Däremot kommer big upfront design ge en klarare bild över designen och ge en renare kod vid första implementeringen. Men allt eftersom projektet utvecklas och nya krav tillkommer så kan även big upfront design få bad code och behöva refaktoriseras. Men denna metodik tar inte upp refaktorisering vilket ofta leder till sämre kod och ökade kostnader för implementering. Detta till skillnad från agila metoder som tar upp refaktorisering och bad code som en naturlig del av utvecklingen. Här växer designen fram som ett fågelbo där man tar en bit, implementerare och upprepar detta tills det att designen uppenbarar sig. Detta genererar ofta mer bad code under implementeringen, men eftersom utvecklarna refaktoriserar efteråt så implementeras detta aldrig i den slutgiltiga produkten. Detta är förvisso idealet och efterföljs inte alltid. Fördelen med agila metoder är att det är lättare att svänga när kunden ändrar sina krav. Viktigt att komma ihåg i båda fallen är att en design dels måste vara tillräckligt övergripande för att täcka ett projekts användning och dels kan behöva ändras eller göras om då förändringar sker. I modern spelutveckling (speciellt online spel) så utvecklas spelen under hela spelet livslängd. Här passar de agila metoderna mycket bra. Det är nästan omöjligt att använda big upfront design eftersom kraven ändras regelbundet. I enterpriseprojekt passar exempelvis big upfront design bättre. Här har ofta kunden bättre definierade krav och det sitter fler utvecklare som ska koordineras. Big upfront design kan också lämpa sig bättre om både hårdvara och mjukvara ska utvecklas. 7
2.4 Metaforer Metaforer är ett kraftfullt verktyg i XP för att underlätta kommunikationen mellan utvecklare och kunder. Men det är även ett hjälpmedel för att göra koden lättare att förstå 1. Det handlar om att använda metaforer när utvecklare döper klasser och variabler. Det vanligaste är att man använder sig av naive metaphors, typexempel är att en klass som hantera en tävling i Enduro kallas för Race eller en klass som håller information om en förare kallas för driver. Utöver detta så väljer många utvecklare att använda mer tekniska metaforer för att beskriva arkitekturen, som resultat delen i enduro kallas ofta för server medan delen för att registrera tider kallas för klient. Genom att använda metaforer i namngivningen så blir det lättare att förstå kopplingen mellan koden och verkligenheten. Problemet är att metaforer inte alltid hjälpa teamet. En metafor som är självklar för någon kan vara helt obegriplig för en annan. Ett annat problem är att man ibland använder sig av metaforer som inte beskriver problemet tillräckligt bra. Detta kan leda till att utvecklarna väljer fel väg när de ska implementera ny funktionalitet vilket kan leda till en onödigt komplex eller i värsta fall en icke fungerande lösning. 2.5 Bad code smells Det bästa sättet att förstöra ett projekt är att ha för mycket dålig kod. Ett mantra som utvecklare bör använda sig av är bad code smells. Trots att dålig kod kan ställa till mycket problem så finns det i stort sett alltid i ett projekt. Det vanligaste sättet att dölja komplex kod är att använda kommentarer för att förklara vad den gör. Kommentarer är parfym till koden för att dölja stanken. Många gånger så beror dålig kod i XP på att utvecklare inte har en bra överblick över projekt eller inte vågar ändra kod de inte varit med och skrivit. Det krävs mycket mod för att ändra någon annans dåliga kod. Men det krävs även mycket kunskap för att upptäcka dålig kod. Det bästa sättet att undvika dålig kod i XP är att refaktorisera både före och efter att en story implementeras. Det är också viktigt att utvecklarna läser igenom koden efter varje iteration. Genom att läsa igenom koden så får utvecklarna en bättre överblick över programmet och kan då göra de ändringar som krävs. För att underlätta utveckling är det även bra att ha tillgång till ett UMLdiagram. För mer information om bad code så kan ni läsa A Taxonomy for Bad Code Smells" 2 och Bad smells in code 3. 2.5.1 Vanliga tecken på dålig kod Några av de vanligaste problemen är stora klasser, duplicerad kod och stora metoder. Large Classes: Kommer av att en design inte ändras då det behövts trots att nya features implementerats. Detta leder till att klasser växer sig enorma och svåröverskådliga. Shotgun surgery: Detta innebär att man måste göra små ändringar i många metoder som ligger i många klasser för att implementera ny funktionalitet. 1 http://xp123.com/xplor/xp0004/index.shtml 2 http://www.soberit.hut.fi/mmantyla/badcodesmellstaxonomy.htm 3 http://www.cs.uu.nl/docs/vakken/mso/badsmells.html 8
Large methods: Det är vanligt att det skapas långa metoder i XP. Ny funktionalitet ska hanteras men istället för att bryta ut den i en dynamisk metod så lägger man in kod i de metoder som redan existerar. Duplicated code: Innebär ett misslyckande med avseende på Once and Only Once. Man har antingen haft för bråttom eller inte insett att i stort sett samma sak redan görs på andra ställen i koden. Detta är ett vanligt fel hos oerfarna utvecklare. Lazy Classes: Detta är en klass som inte innehåller någon väsentlig egen funktionalitet utan istället bara delegerar ansvar till andra klasser. Divergent change: Enligt Single Responsibility Principle (SRP) ska varje klass ha ett Väldefinierat ansvarsområde. Men med tiden kan ibland klasser få bredare och bredare ansvar. När detta skett borde klassen delas upp i flera olika andra klasser då ansvarsområdet annars inte kan anses vara väldefinierat. Genom att dela upp funktionalitet i flera klasser minskas även risken för svåra merge konflikter. Message chains: Om man har en klass som begär ett object från en annan klass som i sin tur måste begära objektet från en tredje osv. Detta kallas message chains och är ett tecken på man kan ha ett fel i sin design. Comments: Kommentarer fungerar som deodorant för koden (undantaget javadoc). Om det behövs kommentarer i koden för att göra den begriplig så har man ofta onödig komplexitet eller en dålig kod standard. Istället för att skriva beskrivande kommentarer ska man ändra koden så att den blir läslig. Long parameter lists: Om en metod tar för många parametrar så blir den svårare att använda. En metod behöver inte få all information för att lösa uppgiften, bara tillräckligt för att hitta informationen. Temporary fields: Ibland lägger utvecklare variabler som enbart används lokalt i en metod som attribut. Detta kan uppstå om utvecklare inte refaktoriserar ordentligt efter att de gjort ändringar. Ex. Ett attribut kan ha används i två metoder och så har den ena metoden plockats bort. Dead code: Kod som inte används av projektet ska plockas bort. Detta är ett vanligt problem om man använder agila utvecklingsmetoder där utvecklarna inte refaktoriserar ordentligt eller inte har tillräcklig bra kunskap om arkitekturen och koden. Static coupled classes: Om klassernas relationer är väldigt statiska så leder detta ofta till svåra merge konflikter och problem som är svåra att lösa. Kopplingar mellan klasser ska därför vara väldigt lösa och dynamiska. Lösa kopplingar mellan klasser har varit ett av de starkaste tecken på väldesignad kod i över 30 år 4. 4 http://xprogramming.com/xpmag/whatisxp.htm#design 9
2.5.2 Lösning i agila projekt För att minska mängden bad code i projektet så måste utvecklarna refaktorisera ofta. Det krävs att det refaktoriseras både före en story implementeras och efter den checkas in. Detta är svårt för utvecklare som är nya till XP. Utvecklarna måste ha mod att våga ändra både i metoder och också klasser men även arkitekturen. Men för att kunna göra refaktoriseringar så krävs det att utvecklarna har bra insikt i vad koden gör och hur programmet fungerar. Det krävs även en heltäckande test svit för att undvika dålig kod. 2.6 Konsekvenserna av dålig design I XP görs ingen inledande design av arkitekturen. Filosofin är en story i taget och teamet ska implementera den på det lättast tänkbara sättet. Detta medför att designen blir hackig och behövs refaktoriseras. Målet i XP är att utvecklarna ska refaktorisera för en story påbörjas och efter den checkas in. Detta är något som många utvecklare har svårt för, speciellt under tidspress. Brist på refaktorisering och bristande kunskap om projektet leder till att designen blir sämre och mängden dålig kod ökar. Detta leder till att det blir svårare att implementera ny funktionalitet och det leder i sin tur till att det tar längre tid att bli klar med en ny story. Detta medför i sin tur till att kostnaderna för att implementera ny funktionalitet ökar. Om utvecklarna trots detta inte gör något åt problemet så riskerar hela projektet att fallera då det inte längre går att implementera någon ny funktionalitet och det blir för svårt att göra en refaktorisering för att åtgärda problemen. 2.7 Vikten av refaktorisering och Test Driven Development I de flesta projekt finns det åtminstone några ställen med "Bad Code Smells" men där ingen förändring har skett pga. antingen tidsbrist eller brist på förståelse. Det ända sättet att få bort dessa "Bad Smells" är att refaktorisera men många gånger finns det en motvilja mot att göra detta pga. risken att man förlorar funktionalitet. Denna motvilja beror på misslyckad TDD då testerna (om det nu finns några) inte tillräckligt täcker det ställe där det behövs refaktoriseras. TDD har många andra fördelar men den största är att försäkra sig om att koden man skrivit verkligen utför det man förväntar sig av den och inget annat. I TDD använder man test first eftersom man oftast inte vet exakt vad koden kommer eller inte göra förrän man testat att använda den. TDD tvingar även en utvecklare att tänka innan han börjar koda vilket kan undvika många problem som annars kan orsaka onödig komplexitet som sedan behöver refaktoriseras bort. If you want to refactor, the essential precondition is having solid tests. -- M. Fowler 10
3 Granskning av simple code and design i XP team 3.1 Granskning av The black team 5 En utförlig analys av teamets kod gjordes och resultatet av denna analys finns beskriven nedan(3.1.1-3.1.4). Efter denna refaktorisering gjordes ytterligare en analys i vilken effekterna av refaktoriseringen beskrivs(3.1.5 3.1.7). 3.1.1 Mönster i koden Utvecklarna har valt att bara implementera ett av de mönster vi har tagit upp i rapporten. Detta kan dels bero på bristande kunskaper om mönster och hur de ska implementeras. Det kan även bero på att de känner sig stressade och ovana med utvecklingsmetodiken. Det mönster de valt att implementera är ett av de viktigaste men även det enklaste mönstet, nämligen Template method. De har skapat en abstrakt klass som de kallar Race och sedan låter de alla typer av race utöka denna klass. Exempelvis MarathonRace, LapRace och StageRace. Detta har gjort att det är väldigt lätt att implementera en ny racetyp i programmet. Utvecklarna använde sig även av Singleton mönstret när de skulle implementera sin databas. De har skapat en klass Database som bygger på en statisk metod instance som returnerar databasen vilket följer Singleton mönstret. 3.1.2 Onödig komplexitet Något direkt tecken på onödig komplexitet har vi inte funnit i koden. Deras design är lätt att överblicka men p.g.a. att de saknar mönster, tester och har mycket dålig kod så är det svårt att implementera ny funktionalitet. 3.1.3 Agile design eller big upfront design? Gruppen har en väldigt agil design. De har inte haft någon direkt design av projektet vilket kanske borde ha gjorts när de refaktoriserade datastrukturen första gången. Även XP kräver en viss design för att underlätta vidareutvecklingen. 3.1.4 Bad code Detta är gruppens stora problem. Det är väldigt mycket tecken på dålig kod. Detta är troligen också den stora anledningen till alla problem med deras tester. I detta avsnitt kommer det att ges exempel på dålig kod i teamets projekt. Large Classes Database Denna klass är större än nödvändigt och bryter även mot SRP. RegisterGUI Denna klass är enorm, den är 16kbyte stor vilket är mycket större än rekommenderat. Large methods ResultCreator metoden readfromfilestodb är väldigt stor. RegisterGUI BuildTable är stor och ostrukturerad. Long parameter list ResultCreator readfromfilestodb och processinputfiles har långa parameter listor. 5 http://eda270.gangsterhood.net 11
Lazy Classes Racer Är en String i fårakläder Duplicated code Database Metod för sortering enligt vem som vinner I ett varvlopp. Denna funktionalitet ska ligga i LapRace klassen. Temporary fields Enduro EnduroVersion är public och används bara på ett ställe i koden. Comments ResultCreator readfromfilestodb har mycket kommentarer och har mycket onödig komplexitet. FileComparer isequal har 5 kommentarer och är onödigt komplex. Dead code Sorter Saknar fullständigt funktionalitet. Database Metod har inparameter som aldrig används. Racer Innehåller metoder som inte används. Exempelvis getheader(). Record - Attributet placement används inte. RegisterGUI Innehåller både oanvända imports och oanvända attribut. Övriga brister Record Returnerar av en typ som är deklarerad som private på två ställen. RegisterGUI Innehåller för många privata klasser. MyTableModel och Clock borde inte ligga där de gör när så många klasser implementerats i koden. FileComparer metoden isequal är onödigt komplex. ReadFile Data hämtas från klassen för att användas omodifierad i klassens metoder. WriteFile Data hämtas från klassen för att användas omodifierad i klassens metoder. WriteFile Stora delar av klassen är utkommenterade när de borde vara borttagna. För exempelkod se referenslista under Example code from The black team. 3.1.5 Utvecklingstopp I mitten av projektet så hade the black team så mycket tecken på dålig kod och fel i testerna att det inte längre gick att implementera nya stories. Detta löstes genom att införa ett utvecklingsstopp. Detta gav utvecklarna god tid att åtgärda de fel som hade uppstått dels pga. av ovana inför den nya metodiken och dels pga. av bristande kunskap om TDD och refactor mercilessly. Under en hel dag implementerades ingen ny funktionalitet. Efter denna iteration så blev ny funktionalitet billigare att implementera då en bättre design uppnåtts. 3.1.6 Påverkan av refaktorisering Det var nödvändigt att göra en stor refaktorisering efter 2 iterationer. Detta eftersom deras ursprungliga design inte längre var hållbar för utveckling. Detta beror troligen på omställningen till den nya utvecklingsmetodiken men även på brister med TDD. Refaktorisering var inriktad på att skriva om datastrukturen och de delar av programmet som var beroende av denna samt att rätta felaktig kod. Efter refaktoriseringen fick de en design som gjorde det lättare att implementera nya race typer. Men den skapade problem med flera tider till förare. Så alla stories som har med sortering att göra blev mycket svårare att genomföra. Detta berodde delvis på att de som refaktoriserade inte tittade på de stories som var utdelade men även till viss del att de misstolkade stories. 12
3.1.7 Efter refaktorisering Vårt projekt hade många fel och tecken på dålig kod. Efter att en refaktorisering gjorts blev koden mer lättöverskådlig vilket gjorde att teamet fick bättre inblick i projektets olika delar. Täckningen av testfall blev bättre och kodkvalitén blev mer tillförlitlig. Teamet fick lättare för att upptäcka och avlägsna dålig kod. Vi upptäckte att många stories kostade mycket mindre efter att refaktoriseringen gjorts. Detta var vad vi förväntat oss och även anledningen till att refaktoriseringen skulle ske. 4 Sammanfattning Simple code and design är lika viktig som TDD i ett XP projekt. Som utvecklare och som coach är det mycket viktigt att ha bra kännedom om hur man upptäcker Bad code och hur denna ska åtgärdas. För att bibehålla Simple code and design är det viktigt att utvecklarna har bra tester som gör det möjligt för dem att refaktorisera. Det är hjälper att göra stora refaktoriseringar med jämna mellanrum och det krävs att utvecklarna är noga med att refaktorisera både före de påbörjat en story och efter de är klara med den. Som coach är det viktigt att leda utvecklarna till att undvika och refaktorisera bort dålig kod. Det kan också vara viktigt att coacherna sätter de mest erfarna utvecklarna på att förbereda för stora designändringar i projektet. Dålig kod och dålig design leder till att kostnaden för implementering av ny funktionalitet ökar. Detta kan användas som motivering för att avbryta utvecklingen och åtgärda de fel som finns. 4.1 Ett extra tack till Vi skulle vilja tacka The black team som läste kursen EDA260 vt-2006 för ett bra underlag till vår djupstudie och för ett gott arbete under refaktoriseringen och utvecklingsstoppet vilket gjorde skillnaden på kvalité mer tydlig. 13
5 Referenser Agile software development Robert C. Martin ISBN: 0-13-597444-5 A Taxonomy for "Bad Code Smells" Mika Mäntylä http://www.soberit.hut.fi/mmantyla/badcodesmellstaxonomy.htm BAD SMELLS IN CODE http://www.cs.uu.nl/docs/vakken/mso/badsmells.html The System Metaphor William C. Wake http://xp123.com/xplor/xp0004/index.shtml What is Extreme Programming? Ron Jeffries http://xprogramming.com/xpmag/whatisxp.htm#design Example code from The black team http://eda270.gangsterhood.net 14