måndag 16 november 2009

Refaktorering

Jag ska hålla i en kodkata på jobbet och tänkte försöka att samla mina tankar lite inför denna händelse skriftligt. Det brukar bli lite lättare att komma ihåg saker och ting när jag skrivet ner det. Ämnet är refaktorering och det blir inte mitt mest strukturerade inlägg och jag kommer säkert att fylla på det tills kodkatan är genomförd.

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.
  1. metoden kan delegera till andra metoder
  2. metoden kan skapa andra objekt
  3. metoden kan göra något.
En metod som delegerar sitt uppdrag kan sägas förklara uppgiften. Genom att inte blanda in kod som gör något "arbete" blir metoden en beskrivning av de steg som måste tas för att uppgiften ska kunna lösas.

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.

tisdag 28 juli 2009

Unlocking Android

Nu en bit in på semestern har jag läst igenom Unlocking Adroid från Manning. Jag tyckte den var bra och informativ även om det är långt till en Head First bok. Upplägget går ut på att visa de olika begreppen genom små exempelapplikationer. Upplägget med exempelapplikationer tror jag passade bra för att visa hur Android fungerar och hänger ihop då det är en del konfiguration som hänger ihop med koden. Alla exempel finns att ladda ner.

Kort och gott, för den som vill lära sig android och få en lite mer sammanhängande bild av vad man kan göra än vad man kan få genom att söka exempel på internet är detta en bra bok.

lördag 20 juni 2009

Head First Design Patterns

Ibland träffar man på saker där man inte kan tänka sig hur det skulle göra bättre. Den bok jag håller på att läsa är ett bra exempel på detta. Head First från O'Relly är en serie av böcker där de har utgått från lite forskning om hur hjärnan fungerar och sedan skrivit böckerna med den kunskapen i första rummet.

Design Patterns är inget som får safterna att flöda hos många. Men i denna bok är det faktiskt riktigt roligt. Inte bara det, en förståelse växer fram. Jag har läst ett par böcker i ämnet sedan tidigare men trots det lyckas jag lära mig något av den här boken.

Jag är inte på långa vägar färdig med boken utan måste bara säga. Om ni har ett val när ni ska köpa en bok. Kolla upp O'Relly's Head First och kolla om det finns en bok i ämnet ni är intresserade av. Jag har svårt att tro att ni kommer att ångra er.

fredag 19 juni 2009

Förändringsbar kod

Det var ett tag sedan jag skrev. Lusten har inte funnits... men nu är det dags att rapportera mina senaste erfarenheter. Jag har under en tid roat mig med ett litet hobbyprojekt som springer ur ett experimentet som ni kan läsa om här. Experimentet går kort och gott ut på att visa att det är lättare att förändra en applikations beteende om koden är bra. Min personliga tolkning av detta experiment landade i följande hobbyprojekt.
  1. Skriv en enkel applikation (tictactoe).
  2. Refaktorera koden så att du även kan spela luffarschack.
  3. Refaktorera koden så att du kan spela othello.
Hur gjorde jag då detta? Till att börja med så visste jag att jag skulle behöva hantera förändring så jag beslutade mig för att skriva tester och dessutom dra det ett steg längre och skriva testerna innan jag skriver implementationskoden. Detta för att testerna i möjligaste mån ska agera specifikation och dessutom tvinga mig till att skriva testbar kod i stället för att slacka och skriva tester där det är enkelt.

Nästa steg var att skriva första varianten av spelet. Här försökte jag så gott det nu gick att ignorera att jag visste att jag skulle få skriva om mycket av koden. Så en hel del av koden blev bunden mot siffran 3. Men eftersom hela poängen med övningen är att det ska finnas lite att skriva om för att stödja funktionallitet som jag "inte visste" skulle komma så var det i princip som det skulle vara.

Nästa steg blev nu att försöka att skriva om Tictactoe till luffarschack. Då jag hade ett enkelt GUI (i konsoll) så beslutade jag mig för att se till att det koden som utgjorde GUI inte skulle röras. Detta beslut tog jag av två anledningar. 1) Det är lätt att kolla om jag har några luckor i mina tester genom att provspela det som fungerade. 2) I verkligheten är det ofta så att man kan ha applikationer som är beroende av ens egen kod som inte kan förändras.

Nu håller jag på med steg tre (Othello) och börjar i viss mån uppleva lite deja vu så vi får se om jag slutför det hela. Jag har beställt en bok om Android så kanske jag försöker att göra spelen njutningsbara med ett riktigt GUI. Men det är nog några API:er som jag ska lära mig innan det händer.

Men har jag lärt mig något då? Jo, det första är att den här övningen är svår att göra själv. Tex det tredje steget i TDD är lätt att förhandla bort (skriv testet, implementera koden, refaktorera). De vägval man gör blir även lite färgade av att man skrivit koden för det förra steget och därför kan koden ganska bra. Det minskar viljan (i alla fall hos mig) att skriva om det som fungerar bara för att det ska bli bättre. Om någon annan skrivit koden så tror jag att jag hade haft det lättare att identifiera vad som är knöligt och vad som är bra.

Det leder mig till slutsatsen att om kod ska skivas om så bör man inte låta samma programmerare som skrev applikationen en gång i tiden delta i refaktoreringen, i alla fall inte ensam. Det blir lite av en paradox att kunskap om hur en applikation är byggd kan bidra till applikationens förfall. Jag antar det ligger någon form av psykologi att att förneka att en investering är dålig och behöver revideras, att vilja tro på att allt är bra.

måndag 4 maj 2009

Två böcker lästa (nästan)

Jag har läst två böcker nu på sistone. .Net Domain-Driven Design with C# och ASP.NET 3.5 Application Architecture and Design. Ingen av böckerna gav mig speciellt mycket men av olika skäl.

Vi börjar med .Net Domain-Driven Design with C#.
För det första förstår jag inte varför någon köper böcker från Wrox. Jag har läst ett par böcker från det förlaget tidigare och maken till tråkigt upplägg finns inte. Bara det är en anledning att inte läsa denna bok. Gamla böcker som Design Patterns framstår som under av läsbarhet och upplyftande grafik. Men det ska jag inte lasta Tim McCarty för. Nu till boken.

Boken är en beskrivning av ett projekt som Tim varit med i där han fick möjlighet att avända Domain Driven Design som beskrevs i boken med samma namn. Det hade kunnat varit väldigt intressant. Dock faller Tom i fällan med att visa långa kodexempel. Tar vi kapitel tre som exempel så har 44 sidor kod på sig. Kanske inte låter så farligt men kapitlet är på 52 sidor och majoriteten av sidorna har mycket kod på sig. Inte små enkla exempel för att påvisa poänger utan bara långa rapningar av hur klasserna ser ut.

I mina ögon är boken ett typiskt exempel på när en författare får betalt för varje sida som han lyckas pressa in i boken. Att skriva en bok på 50 sidor och ha en zip-fil för nerladdning hade varit bättre.

Nästa bok är ASP.NET 3.5 boken.
För att jämföra förlagens strategi så har Packt ett betydligt roligare upplägg i sina böcker. Allt från val av typsnitt till bilder känns roligare.

Denna bok hade jag ganska stora förhoppningar på. Jag har bytt arbetsgivare från ett företag där vi skrev i Java till ett där vi använder .Net. Så en bok som beskriver hur allt hänger ihop utifrån ett design och arkitekturperspektiv lät väldigt lovande. Problemet är att boken i bästa fall kan beskrivas som en nybörjarbok i arktektur och design. Men jag upplevde boken som pedagogisk och välskriven i övrigt. Men den var inte skriven för mig.

Slutsatsen är att jag har läst större delen av två dåliga böcker. Men kanske jag har lärt mig något? Vem vet?

fredag 17 april 2009

Min föreläsning

I torsdags höll jag en föreläsning för mina kollegor på jobbet om Clean code, eller nåja, min uppfattning av det viktigast runt vad som gör kod enkel att underhålla.

Först pratade jag lite teori. Kanske inte så mycket kontrekta råd men ändå lyfta ett antal begrepp så att de finns på kartan.
  • Law of demeter
  • Open closed principle
  • Liskows substition principle
  • Single responsiblity principle
  • Don't ask, tell
  • Duplicering
Inga av begreppen är revolutionerande men att bygga ett gemensamt språk om koden vi skriver känns angeläget så att alla kan referera till samma utttryck och alla andra förstår vad uttrycket betyder. Några av uttrycken är motsägande, tex Law of Demeter och Single Responsibiltiy principle där LoD lätt resulterar i GOD-objects medans SRP lätt skapar långa kedjor av objekt som man måste navigera.

Den andra delen av föreläsningen tog upp något mer konkreta tips på hur man kan få bättre och renare kod.

  • Beskrivande namn
  • Förklarande variabler
  • Tvingande anropsordning (beroende på ordning)
  • Abstract factory
  • Template method
  • Dependency injection
  • Tester
  • Refaktorering
Jag kände att tiden inte riktigt räckte till för att kunna förklara tex Abstract Factory tillräkligt väl men förhoppningvis kommer de som lyssnar ihåg uttrycket och slår upp det.

Till sist pratade jag lite om "the boyscout rule" om att alltid försöka att lämna saker i bättre skick än man fann dem. Vi pratade även lite om de små klockor man bör försöka att träna upp till att ringa i bakhuvudet när man tex ser en metod som är mer än 10 rader lång. Inte för att man nödvändigtvis ska bryta ut en mindre metod utan för att man ska se om det faktiskt finns en metod där.

tisdag 14 april 2009

Team anti-patterns

Läste lite på Ola Ellnestams blog och såg att han skrivit ner de patterns som han hade med på sin föreläsning på SDC2009 som jag skrivit om tidigare. Ni hittar dokumentet här. Läs och fundera på om ni har något att ta till er.

De "team antipatterns" som jag känner mest för är "The code napper" och "The hidden backlog", men det kanske beror på att det är de två som jag har upplevt senast.

Det är bra läsning för de som ibland kanske intresserar sig för de något mjukare delarna av programmering.