Varför vill man refaktorera sin kod?
För att den alltid kan bli bättre.
Vad är bättre kod?
Kod som du själv och andra kan förstå snabbare. Små tricks som att använda beskrivande metodnamn eller låta klasser utföra en sak i taget kan göra underverk för hur snabbt du kan ta till dig hur koden fungerar. Att dölja det som läsaren inte är intresserad av och göra det enkelt att hitta den kod han/hon faktiskt vill se minskar mängden kod man behöver för att förstå lösningen. Att dela upp lösningarna i små samverkande moduler kan göra även komplicerade sysslor triviala.
Extract method
Ta en metod och dela upp den i flera mindre genom att markera ett antal rader kod och ge dessa en egen metod. Fördelen är att man kan ge de markerade raderna en betydelse i metodnamnet som inte självklart kan utläsas ur koden. Vad betyder det att ett objekt är null?
När man bryter ut metoder kan man ha tre idéer om vad koden ska göra. Om man seperarar dessa blir koden enklare att förstå och i en hel del fall även enklare att modifiera efteråt.
- metoden kan delegera till andra metoder
- metoden kan skapa andra objekt
- metoden kan göra något.
En metod som enbart skapar objekt gör det enkelt att förändra vilka objekt som skapas. Den begränsar på det sättet klassens beroende på de klasser som skapas och kan sannolikt användas av andra klasser för att skapa objekt. Alternativet är att skapa objekten där man ska använda dem och då begraver man beroendet på dessa objekt djupt och gör det svårt att ändra.
En metod som gör något gör det som blir kvar efter de två första metodtyperna. Om man använt delegerande metoder och skapande metoder blir den arbetande metoden oftast ganska kort och enkel att förstå. Den uppgift som utförs är förmodligen redan uppdelad i lämpliga delar av en delegerande metod och de objekt som metoden jobbar på är redan skapade vilket tar bort en hel del komplexitet.
Naturligtvis går det inte helt vattentäta skott mellan de tre metoderna. Tex kan en arbetande metod som innehåller ett antal if-else-satser delegera jobbet som ska utföras för varje utfall i respektive if-else. Men att tänka på en metod som skapande, delegerande eller arbetande tycker jag hjälper till med att strukturera koden så att den blir lättare att förstå.
Globalt tillstånd
Vi vet att globala variabler är dåliga men att statiska metoder och singletons är minst lika illa är det kanske färre som har koll på. Globala variabler avskaffade med objektorienterade programmeringsspråk. Statiska variabler och metoder blev dock kvar vilket nog måste ses som en eftergift åt alla procedurella programmerare i världen. Singletons är ett återskapande av globala variabler i form av objekt vilket ger samma problem som globala variabler.
Statisk kod är procedurell och procedurell kod är svår bygga vidare på utan att göra utbyggnaden procedurell. Det blir som cancer i din kod. Precis som med all annan procedurell kod är det lite knepigt att hantera objectorienterade begrepp med statisk kod.
Problemet med singletons är det samma som med globala variabler. En singleton är ett globalt objekt, inget mer inget mindre. Singletons är dessutom ett utmärkt sätt att dölja klassers beroenden. Eftersom klassen kan hämta objektet den behöver precis där den behöver det behöver vi aldrig visa att vår metod som ser ut att beräkna 1+1 anropar en webservice på Nasa för att utföra beräkningen. Dessutom är det svårt att skriva små snabba tester som man faktiskt kan köra ofta om det finns singletons i koden.
Gör en sak och gör den bra
En bra metod utför en uppgift. I en bra klass utför en metod beräkningar på det data som klassen håller internt, ett data som enbart räcker till för att lösa den uppgift som klassen ska hantera. Den största anledningen till att man vill ha det på det sättet är att vi inte vill behöva spendera tid på att fundera på vad klassen har för uppgift. Om en klass eller metod gör flera saker krävs det en större ansträngning för att förstå vad som händer. En ansträngning som kan användas till viktigare frågor. Klasser med en tydlig uppgift tenderar till att lösa den uppgiften bra vilket gör att den blir lätt att använda ifrån andra klasser.
Visa beroenden
Som jag skrev ovan är Singletons bra på att gömma sig i klasser och ställa till problem där man minst väntar sig. Anledningen till att det blir problem är när en metod som man förväntar sig ska göra en sak på ett sätt visar sig lösa den på ett helt annat sätt, tex genom att anropa en webservice i stället för göra operationen lokalt. I exemplet är det inte att man använder en webservice som är problemet, det kan mycket väl vara rätt lösning. Det som blir ett problem är när användaren av klassen inte enkelt kan se att operationerna har ett beroende på nämnda webservice. Därför bör man deklarera sina beroenden genom konstruktorn eller metodsignaturerna. Webservicen bör tex skickas in i konstruktorn så att beroendet blir tydligt. Ingen beräkning utan att en webservicehandler skickas in. En annan poäng med att skicka in de objekt behöver i konstruktorn i stället för att använda globala objekt är att det blir lätt att byta ut webservicehandlern mot en annan handler som implementerar det gränssnitt som webservicehandler definierar. Bra för test och när man kommer på att det det går snabbare att utföra beräkningen lokalt.
Inga kommentarer:
Skicka en kommentar