Refaktorisering i ett XP-projekt

Relevanta dokument
Tentamen. 2D4135 vt 2005 Objektorienterad programmering, design och analys med Java Lördagen den 28 maj 2005 kl

Föreläsning 2. Länkad lista och iterator

Labb 1: Vad, hur, och varför?

Föreläsning 4 Innehåll. Abstrakta datatypen lista. Implementering av listor. Abstrakt datatypen lista. Abstrakt datatyp

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Föreläsning 2. Länkad lista och iterator

//Använd main som ett "handtag" för att hålla ihop programmet. //Själva programmet finns i övriga klasser.

XP-projekt: En fördjupning

TDDC30 Programmering i Java, Datastrukturer och Algoritmer Lektion 2. Länkade listor Stackar Köer MyList Iteratorer Lab 2 Exceptions Paket

TDDC30. Kursledning Kursledare: Jonas Lindgren. Labassistent: Jonas Lindgren Labassistent: Niklas Holma Labassistent: Erik Nilsson

D J U P S T U D I E I E D A S I M P L E C O D E A N D D E S I G N

725G61 - Laboration 7 Implementation av ett API. Johan Falkenjack

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 11 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Objektorienterad programmering i Java

Grundkurs i programmering, 6 hp (725G61) Dugga 2 tillfälle 2

Objektorienterad programmering E. Back to Basics. En annan version av printtable. Ett enkelt exempel. Föreläsning 10

Föreläsning 3: Abstrakta datastrukturer, kö, stack, lista

Refaktorisering i praktiken. Aron Kornhall D00, Lunds Tekniska Högskola

Kritik av Extrem Programmering

Föreläsning 23. Tobias Wrigstad. Refaktorering

Tentamen, EDAA10 Programmering i Java

DUGGA: Objektorienterade applikationer. Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad.

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Tentamen Programmering fortsättningskurs DIT950

Tentamen i TDP004 Objektorienterad Programmering Lösningsförslag

TENTAMEN PROGRAMMERINGSMETODIK MOMENT 2 - JAVA, 4P

Objektorienterad programmering D2

Föreläsning 8 - del 1: Objektorienterad programmering (forts.) - Exempel

TENTAMEN I PROGRAMMERING. På tentamen ges graderade betyg:. 3:a 24 poäng, 4:a 36 poäng och 5:a 48 poäng

Laboration 1 - Grunderna för OOP i Java

Föreläsning 10. ADT:er och datastrukturer

Förändringskontroll i XP-team. Love Johansson (d00lj), Joakim Persson (d00jp)

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

TDDC30 Programmering i Java, Datastrukturer och Algoritmer Lektion 2. Laboration 2 Datastrukturer En liten uppgift Frågor

Djupstudie Code smells / Refaktorisering. Martin Larsson dt08ml5 Stefan Johansson, dt08sj7

ITK:P1 Föreläsning 1. Programmering. Programmeringsspråket Java. Stark typning Explicit typning Strukturerat Hög säkerhet

Lösningsförslag till omtentamen för TDA540 Objektorienterad Programmering

4 13 / %.; 8 </" '': " / //&' " " ' * TelefonKostnad +,-%&. #!" $% " &' . > / ' 5 /' * 13/ &' static Math 1+" &'/ % 12 "" static "' * 1 /") %& &

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

Objektorienterad Programmering (TDDC77)

Objektorienterad programmering E. Algoritmer. Telefonboken, påminnelse (och litet tillägg), 1. Telefonboken, påminnelse (och litet tillägg), 2

Programmering med Java. Grunderna. Programspråket Java. Programmering med Java. Källkodsexempel. Java API-exempel In- och utmatning.

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING. Övningstentamen 1

Cult of Code Quality

TDDI82 - Projekt. Christoffer Holm. Institutionen för datavetenskap (IDA)

Nyttomaximering av spikes

Föreläsning 6: Introduktion av listor

UML: Exempel. Ett modelleringsspråk. UML: Ansvar. UML: tre huvudanvändningar. Exempel: En klass position storlek. UML Unified Modelling Language

Gruppdynamik och gruppsykologi i Extremet Programming

Algoritmer. Två gränssnitt

F12 - Collections. ID1004 Objektorienterad programmering Fredrik Kilander

Praktikum i programmering

Tentamen, EDAA20/EDA501 Programmering

TENTAMEN PROGRAMMERING I JAVA, 5P SOMMARUNIVERSITETET

Coaching av programvaruteam EDA270, djupstudie: Praktisk SCM användning i XP-projekt

Lösningar för tenta 2 DAT043,

Laboration A Objektsamlingar

Programmering för språkteknologer II, HT2014. Rum

Föreläsning 4 Innehåll

Kungliga Tekniska Högskolan Ämneskod 2D4134 Nada Tentamensdag maj - 19 Tentamen i Objektorientering och Java Skrivtid 5 h

Påminnelse: en datatyp för bilder. Programmering. En datatyp för bilder. Spegelbild. hh.se/db2004

Malmö högskola 2012/2013 Teknik och samhälle

Proj-Iteration1. Arkitektur alt. 1

F2 XP Extrem Programmering översikt. EDAF45 Programvaruutveckling i grupp Projekt Boris Magnusson, Görel Hedin Datavetenskap, LTH

Tentamen. DD2385 Programutvecklingsteknik vt 2011 Tisdagen den 24 maj 2011 kl Hjälpmedel: penna, suddgummi, linjal

F2 XP Extrem Programmering översikt. EDAF45 Programvaruutveckling i grupp Projekt Boris Magnusson, Görel Hedin Datavetenskap, LTH

TDDI02. Programmeringsprojekt. Föreläsning 3 Jonas Lindgren, Institutionen för Datavetenskap, LiU

Grundläggande programmering med C# 7,5 högskolepoäng

Att använda pekare i. C-kod

Verktyget FindBugs. Djupstudie i kursen EDA 270 Coachning av programvaruteam. Christofer Bach dt05cb6 Daniel Nilsson dt05dn4. Lunds Tekniska Högskola

Testdriven utveckling. Teorin bakom testdriven utveckling. Bakgrund. Januari 2009, KTH. Alexander Tarnowski

JAVA Mer om klasser och objektorientering

Att skriva till och läsa från terminalfönstret

Interface. Interface. Tobias Wrigstad (baserat på bilder från Tom Smedsaas) 3 december 2010

Chapter 4: Writing Classes/ Att skriva egna klasser.

Dugga Datastrukturer (DAT036)

Upplägg. Introduktion. Examination. Mål. Konsekvenser. Java. Kursen heter konstruktion, ej design eller formgivning.

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING

UML. Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2016

F4. programmeringsteknik och Matlab

Arv. Objektorienterad och komponentbaserad programmering

Föreläsning 2 Objektorienterad programmering DD1332. Typomvandling

PROGRAMMERING-Java Omtentamina

JAVAUTVECKLING LEKTION 4

Mjukvarudesign. Designprocessen. Teknisk design. Konceptuell design

Tentamen OOP

Proj-Iteration 3. Grov plan för releaser

Laboration 3 HI1024, Programmering, grundkurs, 8.0 hp

F5 Selektion och iteration. ID1004 Objektorienterad programmering Fredrik Kilander

Tentamen i Objektorienterad modellering och design Helsingborg

Lösningsförslag till tentamen i OOP, HI1027 Fredag 21 oktober 2011

Tentamen i Grundläggande programmering STS, åk 1 lördag

DAT043 Objektorienterad Programmering

Scrum + XP samt konsekvensanalys

Laboration 1 Introduktion till Visual Basic 6.0

Det finns en referensbok (Java) hos vakten som du får gå fram och läsa men inte ta tillbaka till bänken.

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

Språkkonventioner och redigering av tal.

Tentamen för TDA540 Objektorienterad Programmering. Institutionen för Datavetenskap CTH HT-17, TDA540. Dag: , Tid:

Malmö högskola 2008/2009 CTS

Transkript:

Författare: Erik Norberg, Joakim Puusaari E-post: {d00en, d00jpu@efdlthse Datum: 2004-02-22 Refaktorisering i ett XP-projekt

Sammanfattning I denna djupstudie delar vi med oss av våra erfarenheter av refaktoriseringar, som vi har fått under vår tid som coacher i ett litet XP-projekt med c:a 10 utvecklare Införskaffandet av underlag till vår studie har gjorts kontinuerligt under projektens gång då vi har studerat hur refaktoriseringarna utförts Nästa års coacher kommer att hitta flera tips och förslag till riktlinjer i den här studien I grova drag kan resultatet av vår studie delas upp i två delar: Observationer Vilka bakomliggande orsaker till refaktoriseringar vi har upptäckt Baserat på observationerna ger vi förslag på hur man kan undvika stora refaktoriseringar Erfarenheter Våra erfarenheter summeras genom att vi tar upp ett par exempel av refaktoriseringar Exemplena används för att identifiera olika typer av refaktoriseringar utifrån Martin Fowlers definitioner - 1 -

Innehållsförteckning 1 Inledning 3 2 Bakgrund 3 3 Allmänna observationer 3 4 Refaktoriseringsexempel 4 41 Information om exempelkoden i appendix 4 42 Absorbering av klass 4 43 Namnändring av klass 5 44 Namnändring av metod 5 45 Förflyttning av metod 5 46 Förbättring av metod 5 47 Utbrytning av metod 5 5 Slutsatser 6 6 Referenser 7 61 Litteratur 7 62 Artiklar 7 63 Internet 7 7 Appendix 8 71 Exempel 1 8 72 Exempel 2 9 73 Exempel 3 10-2 -

1 Inledning I den här artikeln kommer vi att först gå igenom bakgrunden kring refaktoriseringar inom XPmetodiken och hur projekten vilka vi har använt som underlag till vår studie är uppbyggda Vi kommer därefter att berätta lite om vad vi har upptäckt under projektens gång Därefter visar vi några konkreta exempel på refaktoriseringar som gjordes under projekten Till slut så sammanfattar vi våra erfarenheter under slutsatser Vi har hämtat refaktoriseringsexempel från de team vi har coachat, analyserat dem och tagit fram goda råd för när refaktorisering skall ske Det är de stora fallen där refaktorisering motsvaras av en story eller en spike som vi har studerat och inte de små som skett innan varje story avslutats Den ena anledningen till detta är att de stora kräver mer resurser och därmed är intressantare att titta närmare på Den andra anledningen är att det är mycket svårare att samla in exempel av små refaktoriseringar eftersom de alltid sker i en utvecklares privata workspace som en del av hans uppgift 2 Bakgrund I enlighet med XP-metodiken är refaktorisering inte bara en god programmeringsvana utan också en förutsättning för att uppnå ett bra program Detta skall göras hela tiden och alla refaktoriseringar, stora som små, är viktiga Refaktorisering är en vana som andra metodiker skulle kunna ta till sig av för att förbättra deras utvecklingscykel En av de viktigaste anledningarna till att använda sig av refaktorisering är att man gör koden lättläslig, vilket gör att andra utvecklare vågar ändra på koden vid behov Andra anledningarna till att refaktorisera är att få bra namngivning, objektorienterad design och kod med hög prestanda I XP-projekt blir refaktorisering speciellt viktigt då man ser koden som dokumentation, dvs man har en snyggt strukturerad och lättförståelig kod istället för en massa dokument som beskriver krav, design mm 3 Allmänna observationer Vi har kommit fram till att följande saker kan visa på att man är i behov av refaktorisering: 1) Nya funktioner tillkommer istället för att gamla modifieras 2) Bristande kännedom om interaktionen mellan klasserna 3) Olika datastruktur används på samma sätt 4) Svårigheter att skapa förståelse för koden Det bör observeras att punkterna inte på något sätt är självständiga utan sammankopplade på många sätt Exempelvis kan punkterna ett och tre leda till punkt fyra och tvärtom Vilket gör det lätt att komma in i en negativ spiral av sjunkande kvalité på koden om ingenting görs Här följer en ingående beskrivning på hur punkterna har dykt upp i våra projekt Observera att detta bara är ett möjligt utfall av flera Alltså ska nedanstående upptäckter inte ses som allmänna tecken på problem utan de är vissa speciella yttringar av de ovanstående problemen - 3 -

I början av projektet såg vi mycket av punkt ett då de började skapa klasser och funktioner för sina stories Detta ledde bla till att man inte ändrade på coachernas iteration noll klasser utan istället skapades piratkopior av de gamla klasserna dvs nya klasser med samma ansvarsområden Orsakerna till detta är att man inte förstår de befintliga klasserna och hur de skall ändras för att uppnå sitt syfte Vid andra planeringsmötet var många eniga om behovet av en översikt då alla hade skapat klasser för sina stories Här kommer punkt två in i utvecklingen då det kan vara så att systemet innehåller många klasser med vagt definierade ansvarsområden tex piratkopior Då vi kommit en bit på utvecklingen började vi märka att en massa olika datastrukturer började användas i samma syfte, punkt tre Botemedlet här är att refaktorisera till en enda datastrukturera och att anamma sig meningen med KISS, Keep It Simple Stupid Ju längre fram i utvecklingen man kommer desto mer vikt bör läggas vid att förstå koden då det kommer allt mer avancerade stories Vid extrema problem med att förstå koden ska man i ett XP-projekt kunna skriva om koden från grunden Detta är möjligt eftersom vi har ett säkerhetsnät i form av enhetstesterna, vilka försäkrar oss om att all funktionalitet finns kvar Vi har kommit fram till att följande saker kan göras för att undvika behovet av stora refaktoriseringar: 1) Man kan ha korta designsessioner under laborationerna, vilket är extra lätt i början av projektet då det inte är så svårt att snabbt besluta sig för en design 2) Skapa ett klassdiagram som uppdateras under utvecklingens gång 3) Lär känna all kod genom att kontinuerligt ta sig tid till att gå igenom programmet 4) En namnkonvention som är överenskommen redan från början 4 Refaktoriseringsexempel I detta avsnitt tänker vi visa några speciellt intressanta refaktoriseringar som teamen gjort och koden till dem finns i appendix Vi kommer att gå igenom flera i projekten återkommande typer av refaktoriseringar Till varje refaktorisering som tas upp ges en motivation till varför det är bra att utföra dem 41 Information om exempelkoden i appendix I våra exempel har vi tagit bort alla funktioner som inte har berörts av refaktoriseringarna, vilket har gjorts för att läsaren lättare ska kunna koncentrera sig på det som har ändrats Av samma anledning har exception-hanteringen och alla importsatser tagits bort Notera speciellt att vi i exempel 2 inte har tagit med klassen FinishList, vilken ser exakt likadan ut som StartList men med annat syfte 42 Absorbering av klass Denna refaktorisering används för de gånger man flyttar en klass funktionalitet till en annan klass Exempelvis om man har en liten klass med oklart ansvarsområde kan det vara lämpligt att slå samman den med en annan liknande klass Detta visas med tre klasser i Exempel 2 i Appendix Se M Fowler definitionen Inline Class - 4 -

43 Namnändring av klass Denna refaktorisering används då man har ett otydligt namn på en klass och behöver döpa om klassen för att namnet bättre ska återge klassens ansvarsområde Vi visar ett exempel på detta i Exempel 2 där det finns en klass vid namn DatabaseHandler, vilken är i tydligt behov av ett bättre namn Nu var det inte bara namnändring som skedde utan lösningen i det här fallet var att flytta all funktionalitet och ta bort klassen 44 Namnändring av metod Denna refaktorisering används då man har ett otydligt namn på en metod som inte reflekterar metodens funktion Vi visar ett exempel på detta i Exempel 2 där det finns en metod addstart som byter namn till addtime då klassen byter namn Se M Fowler definitionen Rename Method 45 Förflyttning av metod Denna refaktorisering används när en metod i en klass passar bättre in i en annan klass Var en metod passar bäst in beror på de olika klassernas syften och ansvarsområden Se Exempel 2 för ett exempel Se M Fowler definitionen Move method 46 Förbättring av metod Denna refaktorisering används för att göra en metod bättre prestandamässigt och/eller lättare att förstå Se exempel 1 där en metod går från att läsa in en fil ett tecken i taget till att läsa in en rad i taget Se M Fowler definitionen Substitute algorithm 47 Utbrytning av metod Denna refaktorisering används för att dela upp en lång funktion i flera mindre funktioner Detta ökar läsbarheten, förståelsen och gör det lättare för senare ändringar av funktionaliteten Se exempel 3 i Appendix där en skriv funktion extraheras ur en ohyggligt stor funktion Se också M Fowler definitionen Extract method - 5 -

5 Slutsatser Den tid vi nu har haft som coacher har visat oss att vissa team har haft svårt att skriva ett snyggt och fint program Definitionen av snyggt program är enligt vår mening att det är objektorienterat och med bra strukturerad kod där alla funktioner är små och lättlästa Svårigheterna för teamet att skriva ett sådant program beror inte på brist av motivation utan på att de inte kan principerna för refaktorisering och objektorientering Detta pekar på ett glapp i deras utbildning där de inte fått undervisning eller konkreta exempel på vad som menas med dåliga lukter i kod Vi vet att deltagarna i XP-projektet har fått en laboration i refaktorisering, som mestadels innebär att de prövar funktionerna i Eclipse för refaktorisering Det är svårt att se nyttan i att deltagarna bara får lära sig hur man refaktoriserar i stället för när och varför Vi föreslår därför att man låter deltagarna refaktorisera en mycket stor funktion, i storleken ca 80-100 rader, till mindre funktioner Detta skulle kunna få en del av deltagarna att inte leva efter devisen if it ain t broke then don t try to fix it Ett annat sätt att få deltagarna att förstå innebörden av refaktoriseringens fördelar är att låta de få uppleva de problem som uppstår då man har stora svårhanterliga funktioner Nämligen merge konflikter vid parallell utveckling och svårigheter att införa ytterligare funktionalitet Detta sätt tillsammans med rutinmässiga spikes på refaktorisering har dock inte fungerat fullt ut för våra team som ännu inte har försökt sig på att göra en uppdelning av deras stora komplicerade funktioner Ett sista sätt att få deltagarna att refaktorisera koden är att coachen/kunden går igenom koden noggrant och sedan delar ut stories/spike på detta Men detta är enligt vår mening inte coachens uppgift då de har tillräckligt mycket att hålla reda på pga ytterligare roller som manager/tracker/arkitekt Det är inte heller kundens uppgift då det inte är tänkt att han ska kunna programmera överhuvudtaget En annan idé som vi har är att man skulle kunna göra en ordentlig granskning av en annan grupps kod redan någon av de första veckorna Detta medför att de ser tidigt vilken kvalitet som de andra grupperna har och får uppleva svårigheterna med att sätta sig in i någon annans kod Vilket skulle kunna motivera dem att anstränga sig mer för att få en bra struktur på koden redan från början Detta kan passa rätt bra in i coachernas problem med att komma på spikes eftersom en del kan ägna sig åt att granska andras kod Under den första granskningen kan det vara bra om minst en av coacherna anordnar ett granskningsmöte och visar hur man kan gå till väga för att göra det noggrant Avslutningsvis anser vi att XP-kursen har lite väl höga mål för vad deltagarna ska hinna med och lära sig under kursens gång Tyvärr verkar det vara de grundläggande sakerna som har fått lida för det Ett barn måste få lära sig att gå innan man lär honom att cykla Att förvänta sig att de ska använda sig av automatiska refaktoriseringsfunktioner innan de egentligen har provat på att göra det manuellt har inte visats sig vara så lyckat - 6 -

6 Referenser 61 Litteratur R Jeffries, A Anderson, C Hendrickson, Extreme Programming Installed 62 Artiklar M Fowler, Refactoring K Beck, Embracing Change with Extreme Programming 63 Internet wwwrefactoringcom - 7 -

7 Appendix 71 Exempel 1 Före refaktorisering public String[] loadfile(){ String txt = ""; BufferedReader br = new BufferedReader(new FileReader(filename)); int onechar = brread(); while(onechar!= -1) { txt+=stringvalueof((char)onechar); onechar = brread(); Funktionen läser in en fil med ett tecken åt gången i den första while-loopen StringTokenizer st = new StringTokenizer(txt, "\n\r;"); String s; LinkedList td = new LinkedList(); while((s = stnexttoken())!=null) { s = strim(); tdadd(s); Iterator itr = tditerator(); String del; String[] textdelar = new String[tdsize()]; int i=0; while((del = (String)itrnext())!=null) { textdelar[i] = del; i++; return textdelar; Efter refaktorisering public String[] loadfile(){ Vector v = new Vector(); String[] strarray = null; String oneline = ""; BufferedReader br = new BufferedReader(new FileReader(fileName)); oneline = brreadline(); while(oneline!= null) { vadd(onelinetrim()); oneline = brreadline(); Här är while-loopen ändrad så att den läser in en rad åt gången strarray = new String[vsize()]; for (int i = 0; i < vsize(); i++) { strarray[i] = (String) vget(i); return strarray; - 8 -

72 Exempel 2 Före refaktorisering class DatabaseHandler { private FileHandler fh, fh2; private StartList sl; private FinishList fl; public DatabaseHandler(String start, String finish) { fh = new FileHandler(new String(start)); fh2 = new FileHandler(new String(finish)); sl = new StartList(); fl = new FinishList(); public StartList printstart() { String[] allstart = fhloadfile(); for(int n = 0; n <= allstartlength-1; n++) { sladdstart(new DriverTime(CharactergetNumericValue((char) allstart[n]charat(0)),allstart[++n])); return sl; public FinishList printfinish() { printfinishkod public class StartList { private LinkedList starttimes; public StartList() { starttimes = new LinkedList(); public void addstart(drivertime d){ starttimesadd(d); Efter refaktorisering public class TimeList { private LinkedList times; private FileHandler fh; public TimeList(){ times = new LinkedList(); public TimeList(String filename) { times = new LinkedList(); fh = new FileHandler(new String(filename)); String[] allstart = fhloadfile(); for(int n = 0; n <= allstartlength-1; n++) { int startnbr = CharactergetNumericValue(allStart[n]charAt(0)); String time = allstart[n]substring(2, allstart[n]length())trim(); addtime(new DriverTime(startNbr, time)); Det enda som klassen DatabaseHandler gör är att den har två funktioner för att fylla listor med tider Listklasserna å andra sidan har ingen egentlig funktionalitet utan den innehåller bara datastrukturen Vidare så är StartList och FinishList identiska förutom en del namn Därför är FinishList utelämnad här Alla de tre ovannämnda klasserna är här ihopslagna till en TimeList som fyller den interna listan då den skapas Den nya listan används till både start- och måltider public void addtime(drivertime d){ timesadd(d); - 9 -

73 Exempel 3 Före refaktorisering public static void merge(timelist start, TimeList finish, DriverList driver, String filename){ String tobewritten; FileHandler resultat = new FileHandler(filename); tobewritten = "StartNr; Namn; TotalTid; StartTider; Måltider\r\n"; Iterator itr = mapdriverkeyset()iterator(); while(itrhasnext()) { Integer startnr = (Integer)itrnext(); tobewritten += startnrtostring() + "; " + mapdriverget(startnr) + "; " + calctotaltime((string)mapstartget(startnr), (String)mapFinishget(startnr)) + "; " + mapstartget(startnr) + "; " + mapfinishget(startnr) + "\r\n"; resultatsavefile(tobewritten); Efter refaktorisering private static LinkedList completelist = new LinkedList(); public static void merge(timelist start, TimeList finish, DriverList driver, String filename){ savetofile(filename); private static void savetofile(string filename){ FileHandler filehandler = new FileHandler(filename); String tobewritten = "StartNr; Namn; TotalTid; StartTider; Måltider\r\n"; ListIterator listitr = completelistlistiterator(0); while(listitrhasnext()){ CompleteDriver compdrv = (CompleteDriver) listitrnext(); Funktionen merge slår samman starttider, måltider och förare till en resultat lista Denna del av funktionen är borttagen Allt sparas sedan till fil med hjälp av while-lopen Funktionen att spara till fil har nu extraherats till en egen metod De nya metoderna är en aning lättare att läsa än den ursprungliga tobewritten += compdrvgetstartnr() +"; "+ compdrvgetname() +"; "+ compdrvgettotaltime() +"; "+ compdrvgetstarttime() +"; "+ compdrvgetfinishtime() +"\r\n"; filehandlersavefile(tobewritten); - 10 -