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

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

Föreläsning 8 - del 2: Objektorienterad programmering - avancerat

Tentamen. DD2385 Programutvecklingsteknik vt 2013 Onsdagen den 22 maj 2013 kl Hjälpmedel: penna, suddgummi, linjal

Lösningar till Fiktiv Tentamen på kursen. 2D4135 Objektorienterad programmering, design och analys med Java vt2004. Teoridel

DI-institutionen Sid 1 av 6 Hans-Edy Mårtensson Sten Sundin

Tentamen i EDAF25. 1 juni Skrivtid: Skriv inte med färgpenna enda tillåtna färg är svart/blyerts.

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 14

2I1049 Föreläsning 5. Objektorientering. Objektorientering. Klasserna ordnas i en hierarki som motsvarar deras inbördes ordning

Tentamen i Objektorienterad modellering och design

Bankkonto - övning. Övning 2 Skriv en metod, geträntan, som returnerar räntan.

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

Mjukvarudesign. Designprocessen. Teknisk design. Konceptuell design

Idag. Exempel, version 2. Exempel, version 3. Ett lite större exempel

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Tentamen. 2D4135 vt 2004 Objektorienterad programmering, design och analys med Java Torsdagen den 3 juni 2004 kl

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

Laboration 2: Designmönster

F8 - Arv. ID1004 Objektorienterad programmering Fredrik Kilander

TUTORIAL: KLASSER & OBJEKT

Tentamen i Objektorienterad modellering och design Helsingborg

TDDC30. Objektorienterad programmering i Java, datastrukturer och algoritmer. Föreläsning 4 Erik Nilsson, Institutionen för Datavetenskap, LiU

Laboration 2: Designmönster

Arv. Fundamental objekt-orienterad teknik. arv i Java modifieraren protected Lägga till och modifiera metoder med hjälp av arv Klass hierarkier

Parsing med Recursive Descent, Avbildningsklasser. Syntaxdiagram. Syntaxdiagram och kodning expression. Betrakta följande uttryck

Arv: Fordonsexempel. Arv. Arv: fordonsexempel (forts) Arv: Ett exempel. En klassdefinition class A extends B {... }

Tentamen i Objektorienterad modellering och diskreta strukturer

F4. programmeringsteknik och Matlab

Chapter 4: Writing Classes/ Att skriva egna klasser.

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

Tentamen i Objektorienterad modellering och design Helsingborg

TENTAMEN PROGRAMMERINGSMETODIK MOMENT 2 - JAVA, 4P

Att prova på en enkel Applet och att lära sig olika sätt att hämta data från tangentbordet. Du får även prova på att skapa din första riktiga klass.

DAT043 Objektorienterad Programmering

Objektorienterad Programkonstruktion. Föreläsning 6 23 nov 2015

Tentamen i Grundläggande programmering STS, åk 1 fredag

Föreläsning 4. Klass. Klassdeklaration. Klasser Och Objekt

Abstrakta Klasser 2. Kodning är bara en liten del i programvaruutvecklingen 6% 1% 6% Abstrakta Klasser - deklaration. Programutveckling sker i faser

Vad handlar kursen om? Algoritmer och datastrukturer. Vad handlar kursen om? Vad handlar kursen om?

Fördjupad Java. Undantagshantering. Fel

Föreläsning 13 Innehåll

2 b) Bodega bodegan = new Bodega(); double moms = 0.235; String namn = "Vargtass"; System.out.println(namn + " " + moms + bodegan.ändra(moms, namn); S

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

DD2385 Programutvecklingsteknik Några bilder till föreläsning 1 24/ Kursöversikt Javarepetition/Javaintroduktion

FÖRSLAG TILL LÖSNINGAR FÖR TENTAMEN I INTERNETPROGRAMMERING MED JAVA, 5p för SY , kl

LÖSNINGSFÖRSLAG Programmeringsteknik För Ing. - Java, 5p

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

Inkapsling (encapsulation)

Lösningar till tentamen i EDAF25

TDDE10 m.fl. Objektorienterad programmering i Java Föreläsning 6 Erik Nilsson, Institutionen för Datavetenskap, LiU

Tentamen för TTIT71 Programmering kl Institutionen för datavetenskap Linköpings universitet. Uppgift 1. (2 p)

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

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

Kort om klasser och objekt En introduktion till GUI-programmering i Java

UML. Klassdiagr. Abstraktion. Relationer. Överskugg. Överlagr. Aktivitetsdiagram Typomv. Typomv. Klassdiagr. Abstraktion. Relationer.

Objektorientering. Objekt och metoder. Objektorientering. Viktiga begrepp. Klass. Objekt. Deklarativ programmering

1 Comparator & Comparable

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

PROGRAMMERINGSTEKNIK TIN212

HT1 2013, FÖRELÄSNING 14 (INFÖR TENTAN)

732G Linköpings universitet 732G11. Johan Jernlås. Översikt. Repetition. Felsökning. Datatyper. Referenstyper. Metoder / funktioner

Lite om felhantering och Exceptions Mer om variabler och parametrar Fält (eng array) och klassen ArrayList.

Tentamen. DD2385 Programutvecklingsteknik vt 2014 Måndagen den 2 juni 2014 kl Hjälpmedel: penna, suddgummi, linjal

Undantagshantering. Fördjupad Java. Undantag. Fel. Grupper av Undantag. Fånga Undantag

Lösningsförslag till tentamen i EDAF25 Objektorienterad modellering och design Helsingborg

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

Integritetsprincipen. Objektorienterad modellering och diskreta strukturer / design

Tentamen Programmering fortsättningskurs DIT950

F6 Objektorienterad design. ID1004 Objektorienterad programmering Fredrik Kilander

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

Lösningar för tenta 2 DAT043,

Programstruktur och terminologi. Programmet producerar följande utskrift i terminalfönstret: Ett Javaprogram består av en eller flera klasser

Föreläsning 8. Arv. Arv (forts) Arv och abstrakta klasser

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

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING

Tentamen. Lösningsförslag

OBJEKTORIENTERAD PROGRAMVARUUTVECKLING. Övningstentamen 2

Design av en klass BankAccount som representerar ett bankkonto

Refaktorisering i ett XP-projekt

Outline. Objektorienterad Programmering (TDDC77) En frukt har ett namn. Man kan lägga en frukt i en korg... Hashing. Undantag. Ahmed Rezine.

Objekt och referenser

Objektorienterad Programmering (TDDC77)

Undantagshantering. Fördjupad Java. Fel. Undantag. Fånga Undantag. Grupper av Undantag

Föreläsning 9: Arv och UML

Objektorienterad Programkonstruktion. Föreläsning 4 8 nov 2016

Tentamen i Objektorienterad modellering och diskreta strukturer

Dagens program. Programmeringsteknik och Matlab. Viktiga datum. Ett första exempel. Programmall, vad behöver vi i ett javaprogram?

Översikt MERA JAVA OCH ECLIPSE. Uttryck och tilldelning. Uttryck och tilldelning. Uttryck och tilldelning. Uttryck och tilldelning

Att öva på och förstå ett program med flera samverkande klasser.

Föreläsning 17 UTBLICK: FORTSÄTTNINGSKURSER I DATAVETENSKAP + ANDROID

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

Objekt, klasser. Tillstånd Signatur Kommunikation Typ. Fält, parametrar och lokala variabler. Konstruktorer Metoder DAVA15

Praktikum i programmering

Editering, Kompilering och Exekvering av Javaprogram

Läs detta! Uppgifterna är inte avsiktligt ordnade efter svårighetsgrad. Skriv ditt idnummer på varje blad (så att vi inte slarvar bort dem).

Institutionen för datavetenskap HT /2008. Testning med JUnit

Förra föreläsningen. Dagens agenda. Command Objektorienterad modellering och diskreta strukturer (EDAF10/EDA061)

Repetition av viktiga begrepp inom objektorienterad programmering

Kort repetition. Programmeringsteknik för Bio1 och I1. Vad ska vi lära oss idag? Ett exempel

Här beskrivs Eclipse, den programutvecklingsmiljö som utnyttjas i programmeringskurserna. Mera information finns på:

Föreläsningsmaterial (Arv) Skrivet av Andreas Lund

Transkript:

Refaktorisering i praktiken Aron Kornhall D00, Lunds Tekniska Högskola d00ak@efd.lth.se 24 Februari 2004

Abstract Den här artikeln behandlar refaktorisering ur ett praktiskt perspektiv och riktar sig till programmerare som inte har någon större vana av refaktorisering sedan innan. Några vanliga och tämligen enkla refaktoriseringar beskrivs och exemplifieras tillsammans med någon enstaka mer komplicerad. Vidare ges några mönster för refaktorisering, speciellt för refaktorisering till designmönster. Slutligen testas och recenseras ett antal refaktoriseringsverktyg för Java. Innehåll Innehåll... 2 1. Inledning... 3 2. Allmänt om refaktorisering... 3 3. Att refaktorisera till Designmönster... 3 4. Mönster för refaktorisering:... 4 4.1 Mönster: Högre kodkvalitet med refaktorisering... 4 4.2 Mönster: Mönsterlösning... 4 4.3 Mönster: Mönstermedborgaren... 5 4.4 Mönster: Säker refaktorisering... 5 5. Några vanliga refaktoriseringar... 6 5.1 Rename symbol [Fowler04]... 6 5.2 Remove double negative [Fowler04]... 7 5.3 Extract method [Fowler04]... 7 5.4 Subclassing to Decorator... 8 6. Refaktoriseringsverktyg... 12 6.1 Eclipse... 12 6.2 RefactorIT... 12 6.3 JRefactory... 13 7. Sammanfattning... 14 8. Tack till... 14 9. Referenser... 14 2

1. Inledning En definition på refaktorisering är [TDDN01]: Förändring av kod med bibehållen funktionalitet. Definitionen lämnar alltså en hel del frågor obesvarade: Varför man refaktoriserar man? När bör man refaktorisera? Blir resultatet av en refaktorisering bättre än dess föregångare? Hur bär man sig åt? etc. Det är min tanke att den här artikeln skall belysa de praktiska aspekterna på refaktorisering snarare än de teoretiska. Jag kommer att ta upp och ge exempel på några vanliga typer av refaktorisering som jag tycker är intressanta. Dessa skall inte ses som något försök till en lista över de bästa refaktoriseringarna utan snarare som ett antal smakprov på hur några olika typer av refaktorisering kan se ut. 2. Allmänt om refaktorisering En väl utförd refaktorisering kan lösa mängder av olika typer av problem, medan en dåligt utförd sådan kan ställa till med minst lika många. Refaktorisering är alltså inte något som per automatik ger ett bra resultat. Syftet med en refaktorisering kan som tidigare antytts variera, men vanligast är nog att man vill göra designen bättre och underlätta läsbarheten av koden. Andra motiv kan vara att förbättra konfigurerbarheten eller optimera koden för att snabba upp exekveringen. Oavsett vad man vill åstadkomma finns det dock alltid en risk för att man introducerar nya buggar i koden när man refaktoriserar, hur försiktig man än är. Det bästa sättet att komma tillrätta med detta problem är att se till att ha många och välskrivna testfall som kontrollerar att koden verkligen fungerar som den ska, även efter refaktoriseringen. 3. Att refaktorisera till Designmönster Designmönster är en företeelse som alla programmerare förr eller senare kommer i kontakt med vare sig de vill eller inte. Det stora flertalet av oss är dessutom eniga om att det är ett enkelt och förhållandevis smärtfritt sätt att återanvända fiffiga designlösningar och därmed undvika att uppfinna hjulet på nytt varje gång man behöver lösa ett programmeringsproblem. Att uppfinna hjul är inte heller det vi vill lägga vår energi på när vi refaktoriserar, så visst vore det trevligt om man kunde använda sig av designmönster även när man refaktoriserar. Denna typ av refaktorisering är visserligen inte helt lätt att lyckas med och tar ofta förhållandevis lång tid att ta sig igenom, men å andra sidan får man i gengäld en väl beprövad lösning som nästan garanterat ger en vacker design som lön för allt slit. 3

4. Mönster för refaktorisering: 4.1 Mönster: Högre kodkvalitet med refaktorisering Problem: Koden är svårläst, duplicerad kod förekommer och designen är oklar. Kontext: Du programmerar. Krafter: Det kan ta emot att ändra i kod som fungerar. Man kanske inte vågar göra ändringar eftersom man är rädd att ha sönder någonting. Det upplevs ofta som roligare att skriva ny kod än att skriva om gammal. Lösning: Gör refaktorisering till en naturlig del i programmerandet. Efter varje färdigskriven metod försöker du få överblick över vad koden gör och tänk till: Vad skulle jag kunna göra för att förbättra läsbarheten och strukturen? 4.2 Mönster: Mönsterlösning Problem: Koden är svårläst, duplicerad kod förekommer och designen är oklar. Kontext: Du programmerar men tycker att koden blir allt mer svårförståelig och designen oklar. Du inser att du måste förändra designen radikalt för att kunna komma vidare. Krafter: Det kan ta emot att ändra i kod som fungerar. Man kanske inte vågar göra ändringar eftersom man är rädd att ha sönder någonting. Alla programmerare har inte den kunskap om designmönster som krävs. Att ändra designen radikalt tar ofta emot eftersom det kräver förhållandevis mycket arbete. Det kan vara svårt att inse vilket designmönster man bör använda. Det upplevs ofta som roligare att skriva ny kod än att skriva om gammal. Lösning: Se till att vara någorlunda väl inläst på åtminstone ett par vanligt förekommande designmönster. När du refaktoriserar försöker du hela tiden identifiera delar av koden som skulle kunna skrivas om som ett designmönster. När dessa delar är identifierade gör du en utvärdering av vilka fördelar respektive nackdelar det skulle innebära att skriva om koden. Tycker du att fördelarna uppväger nackdelarna är det bara att fatta tangentbordet och skriva om hela rasket så att designen överensstämmer med det aktuella mönstret. 4

Relaterade mönster: Mönstermedborgaren beskriver hur man bör bete sig när man refaktoriserar till designmönster. 4.3 Mönster: Mönstermedborgaren Problem: När man väl kommit in i designmönstersvängen tenderar man att använda sig av dem in absurdum och all kod man skriver blir tryfferad med allehanda upptänkliga och oupptänkliga mönster. Kontext: Du programmerar och har fallit för tjusningen i designmönstrens underbara värld. Krafter: Att använda många mönster imponerar på andra programmerare. Mönster innebär en viss trygghet. Man tror lätt att bara man använder sig av en massa mönster kommer resultatet att bli bra. Ofta är det bättre med en enkel lösning som är lätt att förstå än en avancerad designmönsterlösning. Lösning: Behärska dig. Det kan vara svårt ibland men är inte alls omöjligt. Det handlar helt enkelt om att väga fördelarna med en lösning mot nackdelarna. Att använda sig av mönster ger inte automagiskt ett bra resultat. En mönstermedborgare är alltså en programmerare som använder designmönster om och endast om det är motiverat. 4.4 Mönster: Säker refaktorisering Problem: Koden behöver refaktoriseras, men risken för att nya buggar uppkommer är ett problem. Kontext: Du refaktoriserar. Krafter: För att kunna bygga på systemet krävs refaktorisering. Risken för att introducera nya buggar finns alltid vid refaktorisering. Välskrivna testfall fångar upp större delen av de buggar som kan tänkas introduceras vid refaktorisering. Lösning: Innan varje refaktorisering kontrollerar man om det finns tillräckligt med tester av den kod som skall refaktoriseras. Gör det inte det skriver man nya, genomtänkta sådana enligt konstens alla regler. När alla gamla och nya tester går igenom refaktoriserar man och kör sedan alla testfall igen. Går dessa igenom har man sannolikt inte introducerat några nya buggar. 5

5. Några vanliga refaktoriseringar 5.1 Rename symbol [Fowler04] Rename symbol är nog den allra enklaste och vanligast förekommande refaktoriseringen. Som namnet antyder innebär denna refaktorisering att man byter namn på symboler dvs. variabler, metoder, klasser eller paket. Ett refaktoriseringsverktyg är till stor hjälp vid denna refaktorisering eftersom ett namnbyte ofta innebär att flera referenser måste uppdateras. Motivering Det hör till god sed att ge sina variabler, metoder mm bra namn som beskriver vilken funktion de har i koden, men ibland kan det vara svårt att komma på bra namn och då kan det bli lite si och så med namngivandet. Efter någon dag, när man sovit på saken, brukar det dock vara lättare att gå tillbaka till koden och byta ut de gamla och dåliga namnen mot nya och bra. Exempel Innan refaktorisering: public class Account { private double money; public Account() { money = 0.0; public double getmoney() { return money; public void setmoney(double b) { this.money = b; När denna klass som beskriver ett bankkonto skrevs döpte författaren variabeln som innehåller aktuellt saldo till money vilket dessvärre inte är helt lyckat eftersom det bara betyder pengar i största allmänhet. Detsamma gäller för metoderna set- och getmoney som dessutom är publika och visar på så sätt även utåt upp det dåliga variabelnamnet. Efter Refaktorisering: public class Account { private double balance; public Account() { balance = 0.0; public double getbalance() { return balance; public void setbalance(double balance) { this.balance = balance; Här har variabeln money bytt namn till balance (som ju betyder just saldo). Get- och setmetoderna har ändrats på motsvarande sätt så att vi även publikt talar om att det är saldot vi kan förändra istället för det något oklara pengar. 6

5.2 Remove double negative [Fowler04] Dubbla negationer är inte bra. Det fick vi lära oss redan på grundskolans svensklektioner, och detsamma gäller i programmeringssammanhang. Motivering Eftersom människans förmåga att parsra ett logiskt uttryck korrekt är ganska begränsad bör vi göra det så enkelt som möjligt för oss och då är det en bra idé börja med att ta bort alla dubbla negationer. Tänk t ex på meningen: Du skall inte låta bli att inte använda dubbla negationer. Visst blir det besvärligt? Exempel Innan refaktorisering:... if(!fueltank.isnotempty()) { // gör något public boolean isnotempty() { return fuel > 0; Efter Refaktorisering:... if(fueltank.isempty()) { // gör något public boolean isempty() { return!isnotempty(); public boolean isnotempty() { return fuel > 0; Här har vi lagt till en ny metod isempty() som gör negationen åt oss Enkelt och praktiskt om vi fortfarande behöver isnotempty() någon annanstans i koden. 5.3 Extract method [Fowler04] Att bryta ut ett stycke kod till en egen metod är en mycket vanlig typ av refaktorisering. Den har ett syskon vid namn Extract class som jag inte tar upp här, men det bör inte vara så svårt att föreställa sig vad den gör efter att ha läst om Extract method. Motivering Att en metod börjar bli för lång är nog en av de vanligaste dåliga lukterna inom programvaruutveckling. Lyckligtvis är denna lukt ganska lätt att bli av med med hjälp av Extract method. 7

Exempel Innan refaktorisering: public void LongMethod() { //många, långa, digra rader kod String name = ""; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Hej!"); System.out.print("Vad heter du: "); try { name = br.readline(); catch (IOException e) { System.err.println(e); System.out.println("Hej " + name); //ännu fler, långa, digra rader kod Efter Refaktorisering: public void NotThatLongMethod() { //många, långa, digra rader kod System.out.println("Hej " + askforname()); //ännu fler, långa, digra rader kod private String askforname() { String name = ""; BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); System.out.println("Hej!"); System.out.print("Vad heter du: "); try { name = br.readline(); catch (IOException e) { System.err.println(e); return name; Som synes blev det plötsligt betydligt lättare att se att vi frågar användaren om hans/hennes namn mitt i den långa metoden. 5.4 Subclassing to Decorator Att refakorisera till designmönster kan vara mycket effektivt, men är förhållandevis svårt eftersom det kräver en djupare förståelse för koden och måste göras i flera steg. Jag har valt att som exempel på en sådan refaktorisering visa hur man kan ersätta en hierarki av subklasser med designmönstret decorator. Decorator är ett mönster som är bra att använda om man enkelt vill kunna skapa objekt med olika egenskaper. Jag går inte igenom Decorator i detalj här men det bör inte vara så svårt att förstå principen genom att studera nedanstående kod. För den intresserade finns mer information om Decorator och designmönster i största allmänhet i en sökmotor nära dig. 8

Motivering Med hjälp av Decorator kan man skapa objekt med olika egenskaper genom att skriva en klass för varje egenskap och sedan på ett fiffigt sätt kombinera dessa klasser när objektet skapas. I en lösning där varje kombination av egenskaper representeras av en subklass växer antalet klasser exponentiellt när antalet egenskaper ökar. Innan refaktorisering: public class Person { protected String name; public Person(String name) { this.name = name; System.out.println("Namn: " + name); public class Female extends Person { public Female(String name) { super(name); System.out.println("Namn: " + name); System.out.println("Sex: female"); public class Male extends Person { public Male(String name) { super(name); System.out.println("Namn: " + name); System.out.println("Sex: male"); public class Man extends Male { public Man(String name) { super(name); System.out.println("Namn: " + name); System.out.println("Sex: male"); System.out.println("Age: Adult"); public class Woman extends Female { public Woman(String name) { super(name); 9

System.out.println("Namn: " + name); System.out.println("Sex: female"); System.out.println("Age: Adult"); public class Girl extends Female { public Girl(String name) { super(name); System.out.println("Namn: " + name); System.out.println("Sex: female"); System.out.println("Age: Not very old"); public class Boy extends Male { public Boy(String name) { super(name); System.out.println("Namn: " + name); System.out.println("Sex: male"); System.out.println("Age: Not very old"); Här vill vi kunna representera personer med alla kombinationer av egenskaperna kön och ålder. För enkelhets skull finns det bara två åldrar barn och vuxen och så har vi inte tagit hänsyn till att hermafroditer inte kan representeras i vår modell. Det behövs alltså sex subklasser till Person för att representera alla kombinationer av dessa två egenskaper. Detta kanske inte låter så farligt, men om vi antar att vi hade 10 egenskaper som alla kunde anta två värden så skulle denna artikel utskriven på papper väga ca två kg Efter Refaktorisering: public abstract class Person { public Person() { public abstract void printinformation(); public class NameHolder extends Person { protected String name; public NameHolder(String name) { this.name = name; System.out.println("Namn: " + name); 10

public abstract class AbstractDecorator extends Person { protected Person component; public AbstractDecorator(Person component) { super(); this.component = component; public abstract void printinformation(); public class SexDecorator extends AbstractDecorator { private boolean ismale; public SexDecorator(Person component, boolean ismale) { super(component); this.ismale = ismale; component.printinformation(); System.out.println("Sex: " + getsex()); private String getsex() { // (c: if(ismale) { return "male"; else { return "female"; public class AgeDecorator extends AbstractDecorator { private boolean ischild; public AgeDecorator(Person component, boolean ischild) { super(component); this.ischild = ischild; component.printinformation(); System.out.println("Age: " + getage()); private String getage() { if(ischild) { return "Not very old"; else { return "Adult"; Med den här lösningen behöver vi bara skriva en ny subklass till Decorator för varje egenskap vi lägger till. Om man sen vill skapa t.ex. en pojke som heter Erik skriver man såhär: Person p = new AgeDecorator(new SexDecorator( new NameHolder("Erik"),true),true); 11

6. Refaktoriseringsverktyg Refaktorisering blir inte riktigt njutbar utan verktygshjälp. Även om man kan göra mycket med bara sök/ersätt funktionaliteten som finns i nästan alla texteditorer så blir det aldrig lika smidigt som med ett specialskrivet verktyg. På senare år har det kommit ut en hel rad mer eller mindre bra sådana verktyg och jag kommer här att presentera tre sådana för Java. Jag har testat dessa verktyg genom att i ett större programmeringsprojekt med många välskrivna tester göra ett antal refaktoriseringar och sen kontrollera om testerna fortfarande går igenom. Denna metod är måhända inte så vetenskaplig, men ger ändå en viss uppfattning om hur bra verktyget är på att refaktorisera. Jag kommer hädanefter att kalla detta test för domedagstestet. 6.1 Eclipse Eclipse är egentligen en hel utvecklingsmiljö med stöd för bl.a. CVS och en mängd plugins för UML-ritning mm. Det är dock refaktoriseringsfunktionaliteten som jag kommer att recensera här. Så här kan det se ut när man gör Extract Method i Eclipse: figur 1 Refaktorisering i Eclipse Användargränssnittet är mycket intuitivt. Man bara markerar det man vill refaktorisera och högerklickar så får man upp en meny där man kan välja mellan en mängd olika refaktoriseringar. Eclipse klarar sig igenom domedagstestet även om vi får en del onödiga import-satser, men å andra sidan gör Eclipse oss uppmärksamma på problemet med hjälp av en liten gul markering i kanten på aktuella klasser, så det är en smal sak att rätta det felet. 6.2 RefactorIT RefactorIT är ett fristående program, men har stöd för att integreras med bl.a. JBuilder och Forte vilket är nödvändigt eftersom det inte innehåller någon egen editor. Upplägget är ganska likt det i Eclipse, men inte riktigt lika intuitivt. Extract method på samma kod som i figur 1 ser ut så här: 12

figur2 Refaktorisering i RefactorIT Även RefactorIT klarar domedagstestet och även här genereras en del onödig kod vid flyttning av klasser. Vi får ingen direkt information om detta som på samma sätt som i Eclipse, men det finns inbyggda analyseringsverktyg som hittar den typen av överflödig kod om vi använder dem. 6.3 JRefactory Både Eclipse och RefactorIT har en traditionell syn på hur refaktorisering görs där det är källkoden man ändrar och därmed ändras också designen. JRefactory har en ganska annorlunda approach på hela refaktoriseringskonceptet. Här är det designen som står i centrum och visas i form av UML-diagram, medan källkoden hålls i skymundan och faktiskt inte visas alls. Man skulle kunna säga att man refaktoriserar grafiskt. Så här kan det t.ex. se ut: figur 3 Refaktorisering i JRefactory 13

JRefactory känns lite instabilt redan från början och det är (förhållandevis) svårt att förstå hur man skall importera källkoden i programmet. Dessutom misslyckas programmet i domedagstestet så att fyra testfall inte längre går igenom. Trots detta vill jag inte såga JRefactory totalt eftersom det sina brister till trots är en intressant och nyskapande lösning som kanske i senare versioner kan bli riktigt bra, även om det i nuläget har en del irriterande buggar. 7. Sammanfattning Jag har i denna artikel efter bästa förmåga försökt belysa de praktiska aspekterna på refaktorisering. Mycket av det som finns skrivet har en mer teoretisk inriktning och vänder sig till den erfarne programmeraren som redan har så stor erfarenhet att hon direkt inser en refaktoriserings användningsområde när hon läser en beskrivning av den. Jag har istället försökt att beskriva förhållandevis enkla refaktoriseringar med förhållandevis enkla exempel och mönster samt testat ett par förhållandevis enkla refaktoriseringsverktyg och det är min förhoppning att du som läsare nu tycker att refaktorisering är förhållandevis enkelt. 8. Tack till Magnus Starseth, Miguel Ewezon, Fredrik Redgård och Staffan Åberg som alla kommit med värdefulla kommentarer på mitt arbete. 9. Referenser [Cooper98] Cooper, James W, The Design Patterns Java Companion Addison-Wesley, 1998 [TDDN01] Tichelaar, Sander; Ducasse, Stéphane; Demeyer, Serge; Niertrasz, Oscar, A Metamodel for Language-Independent Refactoring 2001 [Fowler04] Fowler, Martin, www.refactoring.com 2004 [Kerievsky02] Kerievsky, Joshua, Refactoring to Patterns 2002 14