fredag 18 december 2009

Jönköping Developer Dojo

Jag skrev sist om att ta ansvar för sin egen kompetens och jag avslutade med att beställa en bok för att läsa på kvällarna. De som känner mig vet att jag har läst jobbrelaterade böcker hemma länge så det är inget revolutionerande att jag lägger lite av min fritid för att hålla mig ajour. Nu har jag dock tagit nästa steg, eller försök till nästa steg i alla fall lite beroende på vad jag får för respons.

Mitt nästa steg i att ta ansvar för min egen kompetens är att försöka bygga ett nätverk av andra programmerare. Detta i syfte att förhoppningsvis få lära av dem och kanske eventuellt få dela med mig av mina erfarenheter. Men hur ska nu detta gå till?

Jag började med att se om jag kunde hitta något på google och sedan på linkedin men jag var helt utan framgång. Detta leder till att jag får försöka att starta något på egen hand. Så sagt och gjort. Jag har skapat upp en sida med hjälp av Google Sites och en grupp på linked in, och så skriver jag det här. Det jag försöker att komma till är jag nu finns det en användargrupp i Jönköping, eller i alla fall ett embryo av något som kan bli en användargrupp. Jag har valt att kalla den Jönköping Developer Dojo.

Jönköping Developer Dojo hoppas jag kan bli en mötesplats för programmare som bor eller jobbar i Jönköping. Än så länge är planerna för hur gruppen ska träffas och vad vi ska göra när vi träffas ganska flytande men det är inget som vi behöver spika på en gång.

Tycker du att det låter intressant, gå med i gruppen Jönköping Developer Dojo på linkedin eller skriv en kommentar om att du är intresserad av att vara med.

torsdag 10 december 2009

Ta ansvar för din kompetens!

Företaget du jobbar för vill inte betala för att du ska utbilda dig. De förstår inte att du förlorar kompetens jämfört med omvärlden varje dag som du inte förkovrar dig och lär dig något nytt. Din arbetsplats är dömd att dö en långsam död för att de inte hänger med i utvecklingen och du kommer att vara värdelös på arbetsmarknaden när företaget kursar. Känner du igen dig i resonemanget?


Ett företag som inte förstår att du som programmerare behöver kontinuerlig vidareutbildning är inte det bästa företag man kan tänka sig. Dina chanser att vara attraktiv på arbetsmarknaden hänger mycket ihop med de arbetsuppgifter du har haft. Det är inte många företag som anställer cobolprogrammerare längre och det dröjer inte länge innan den teknik du jobbar på är lika antik som cobol. Men företaget du jobbar på kanske inte planerar att göra sig av med sitt "cobolsystem" de närmaste åren och tycker att det vore bortkastade pengar att du ska lära dig något som är av lite modernare snitt. Ska du då skylla på företaget att du inte har fått någon utbildning? Du kan ju det du behöver kunna för att kunna utföra dina uppgifter och även om du tycker att det skulle vara bra med en kurs iLinq eller Wicket så tycker ju uppenbarligen inte dina chefer det.


Så nu har du några val. Du kan söka jobb och med lite tur får du tag dina drömmars arbetsgivare som ger dig det du behöver och lagom mycket utmaningar för att du ska utvecklas som både personligt och i din yrkesroll. Eller så resignerar du och ger upp väntar på bättre tider. Den tredje varianten är att du börjar ta tag i din utbildning själv, för egna pengar och på egen tid. Du slutar skylla på omgivningen och tar gör det du behöver för att upprätthålla och förbättra din kompetens. I stället för att vänta på att någon annan ska bestämma vad du ska kunna så väljer du dig det som du själv tror på.


Att betala för en utbildning är ganska dyrt så det kanske man inte kommer att betala själv. Men att lägga ett par hundra på en bok som man kan ha på nattduksbordet och läsa ett kapitel innan man somnar på kvällen, det är ingen större ansträngning. Om man bor i större städer finns det användargrupper som träffas lite då och då för diverse olika tekniker. Med andra ord behöver det inte bli dyrt. Det som blir den stora uppoffringen är att gå upp ett par timmar i veckan i arbetstid. Det tycker jag att det kan vara värt men det är ett val som är upp till var och en naturligtvis. Men gör det till ett val ochifrågasätt valet ett par gånger om året.


Nu med detta skrivet ska jag beställa en bok, utan att bry mig om jobbet kommer att betala den. Jag kommer att läsa den för att jag tror på att det boken tar upp är viktigt. Inte för att någon annan säger till mig att jag måste göra det. Det är mitt val. Nu kanske man ska ta och se om orten jag bor i är stor nog för att se om det finns fler som resonerar som jag och kanske träffas någon gång i månaden för att prata programmering.

tisdag 8 december 2009

Patterns of Enterprise Application Architecture

Martin Fowler är en i programeringskretar ganska känd person. Framför allt när det kommer till de mera agila grenarna systemutvecklingsprocessen. Boken jag har läst har dock ganska lite med XP, TDD eller parprogrammering att göra. Det är en bok där vi får ta del av Martins erfarenheter i form av olika patterns han har tagit till sig. Många hade jag hört talas om sedan tidigare och några är nya.

En bok av den här typen är inte helt lämpligt att försöka att sträckläsa utan man skummar igenom den för att kunna slå upp i vid senare tillfälle. För värdet som en bok av den här typen har är inte i första hand de idéer som samlats ihop utan att de som har läst boken får en gemensamt ordförråd. Precis som när man läst Design Patterns (GoF) och lärt sig vad en Facade eller en Abstract Factory är så får man i Martins bok fler ord för att beskriva mer eller mindre vanligt förekommande mönster man stöter på i livet som programmerare.

Boken är uppdelad i två större delar. Den första beskrivs de många val man har vid utvecklingen av en större applikation. Denna del är uppdelad i de olika delar applikationen består av. Web, sessioner, domänobjekt, databasaccess. De strategier som Martin ger är i denna del inte beskrivna på ett djuplodande sätt utan övergripande och hur de olika mönstrena hänger ihop.

Den andra delen är mer av referenstyp. Här får man läsa om varje pattern igenom för sig. Vilka fördelar och nackdelar de har och även vilka andra patterns som kan vara relevanta.

Jag tror att det här är en bok som man bör ha läst eller i var fall ha någon i närheten som läst. För även om det kommer nya framework så är det sällan de faktiskt har uppfunnit något riktigt nytt. Microsoft MVC är en Front Controller precis som Struts så inget nytt under himlen där. Lite mer hårdvara och erfarenhet har naturligvis drivit utvecklingen frammåt men det finns bara så många sätt att ta hand om ett http-anrop och göra något vettigt med det.

Boken har exempel i C# och Java vilket i princip borde göra att alla kan läsa den med god behållning även om man skulle ha drag av religon.

Nu en kort ordlista som kanske kan motivera någon att ta upp boken och börja läsa ett kapitel eller två:

  • Active Record
  • Application Controller
  • Accociation Table Mapping
  • Class Table Inheritance
  • Client Session State
  • Coarse-Grained Lock
  • Concrete Table Inheritance
  • Data Mapper
  • Data Transfer Object
  • Database Session State
  • Dependent Mapping
  • Domain Model
  • Embedded Value
  • Foreign Key Mapping
  • Front Controller
  • Gateway
  • Identify Field
  • Identify Map
  • Implicit Lock
  • Inheritance Mapper
  • Layer Supertype
  • Lazy Load
  • Mapper
  • Metadata Mapping
  • Model View Controller
  • Money
  • Optimistic Offline Lock
  • Page Controller
  • Pessimistic Offline Lock
  • Plugin
  • Query Object
  • Record Set
  • Registry
  • Remote Facade
  • Repository
  • Row Data Gateway
  • Separated Interface
  • Serialized LOB
  • Server Session State
  • Service Layer
  • Service Stub
  • Single Table Inheritance
  • Special Case
  • Table Data Gateway
  • Table Module
  • Template View
  • Transaction Script
  • Transform View
  • Two Step View
  • Unit Of Work
  • Value Object

söndag 6 december 2009

Test Driven Development

Jag har lekt lite med TDD (Test Driven Development) vilket har varit ganska intressant. Att skriva testdriven kod är först och främst en vanefråga, att vänja sig vid ett sätt att tänka. Det är en sorts förändring som jag tror kräver en hel del övning innan man börjar försöka att applicera tekniken på skarpa projekt där man faktiskt ska leverera kundnytta. Utan någon form av ledarskap och erfarenhet att luta sig mot finns det många fällor man kan hoppa in i och därmed göra livet betydligt svårare än det behöver vara.

Test driven utveckling följer en cykel med tre steg

1) Fundera ut ett test och implementera det i testkoden, testet ska falera.
2) Implementera produktionskod för att få testet att fungera
3) Refaktorera, både produktionskod och testkod.

När man skriver testet ska man försöka att göra det så litet som möjligt. Tanken är inte att testet ska täcka in allt som kan inträffa utan enbart ett scenario. Man ska alltså skriva så lite som möjligt för att åstadkomma ett falerande test. Det får till följd att en serie av tester kan ses som en specifikation av programmet du skriver. Varje nytt test bygger på de tidigare. Varje nytt test beskriver en liten bit ny funktionalitet. När man läser en testklass ska man intoduceras i problemet och test för test få de mer komplicerade användningsområdena presenterade.

När man skriver produktionskod ska man inrikta dig på att få testet att gå igenom med minsta möjliga insats. Även om du kan lösa tusen problem genom att implementera ett helt framework i din produktionskod så behöver du sannolikt inte det för att få ett test att gå igenom. De första testerna löser man sannolikt genom att returera null, eller textkonstanter i produktionskoden. Syftet med att man vill lösa minsta möjliga del av problemet är att man ofta vill ta fram lösningar som är betydligt komplexare än vad man faktiskt har behov av. Genom att lösa ett test i taget med minsta möjliga förändring går man inte händelserna i förväg. Många problem har väldigt enkla lösningar om man kan undvika att börja med att bygga stora arvsheirakier och domänmodeller.

Det tredje och sista steget är att refaktorera koden man har skrivit. Någon skrev att man ska genomföra detta steg skoningslöst. Med testerna som stöd för refaktoreringen så får man snabbt reda på om man har förstört någon existerande funktionallitet och genomgripande förändringar i koden. Men man ska också refaktorera sina tester. Det är förmodligen viktigare att testerna är i bra skick än produktionskoden.

Jag har gjort tre små experiment med TDD så här långt. PrimfactorsKata, BowlingGameKata och så en PostfixMiniräknare. Det jag har lärt mig är att man bör ha ganska bra koll på problemet man löser. För skriver du dina tester fel är det inte riktigt lika lätt att ändra i dem som det är att ändra i produktionskoden. Tex missuppfattade jag reglerna för hur man beräknar poäng i BowlingGameKatan vilket inte var helt smidigt att rätta till. Däremot att byta ut den rekursiva kod jag använde i PrimefactorsKatan till en algoritmisk dito gjorde med lätthet, testerna talade om när något inte var som det skulle och testerna förändrades inte bara för att jag bytte lösning, api:et var det samma. Så om man har en god idé om hur api:et ska se för det problem man ska lösa är TDD utmärkt. Om man har mer svävande uppfattning om vilket api problemet döljer sig bakom får man nog ganska omfattande förändringar i både tester och i produktionskod, något som gör livet lite besvärligare.

En lösning för att ta fram vilket api man vill utgå från i testerna kan vara att göra en prototyp där man kan experimentera sig fram till hur problemets api ser ut. Man behöver inte implementera problemet i detalj men man kan testa ett par möjliga gränssnitt mot problemet. När man sedan har sin idé om hur man vill använda funktionen kan man börja implementera med hjälp av TDD.

Nu skulle säkert en renlärig TDD:are säga att det api man tagit fram utan TDD inte är optimalt eller att man har försökt att lösa problemen i fel ordning. För om du utgår från sådant du inte kan ändra, tex ett utseendet på en miniräknare så har du inte så stora möjligheter att ändra API:et. Sedan för varje steg du jobbar dig ner i lagren av kod så skulle api:et redan mer eller mindre vara förutbestämt. Jag kan köpa in på det resonemanget också men har inte hittills någon erfarenhet av att det faktiskt fungerar på det sättet utan skulle behöva få tag på ett lämpligt scenario att testa det på. De jag har gjort hittills har ju varit av ganska trivial natur för att begränsa tidsåtgången.

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.

fredag 27 mars 2009

Swedish developer conference 2009

Nu så här några dagar senare kommer det en liten rapport av mina äventyr från Swedish Developer Conference 2009. På det stora tyckte jag att besöket var väl värt tiden även om jag framför allt på Emliy Bache seminarie led ganska hårt av att jag läst boken Clean Code och reflekterat en hel del på ämnet här på bloggen. Här kommer ett litet referat av de seminarium som jag gick på.

Keynote: Kent Beck - Responsive design
Handlade i första hand om de vanor som skiljer de team som lyckas från de som misslyckas. Tex att vara action-inriktad, alltså att våga prova nya tekniker och att hantera en föränderlig verklighet genom att gå till handling och inte vänta på att något ska hända. Men man får inte bara gå till handling, lämpligtvis måste man också stanna upp när man nått någon form av resultat, framgång eller ej, och reflektera och fundera på hur man kan dra nytta av erfarenheten. Kanske lite förenklat så våga prova nya vägar. Värdera varje experiment förutsättningslöst och dra lärdomar.

Chris Hedgate: From good developer to great developer
Chris pratade bland annat om "The four steps of competence" och vilka konsekvenser det har för möjligheterna att kunna dela med sig kunskap och mottagarens förmåga att kunna ta till sig denna kunskap.

Några småsaker jag noterade var att Chris menade på att underhåll av kod börjar samtidigt som man skriver koden. För varje rad du skriver så tar du hänsyn till den tidigare och om inte den är välskriven och genomtänkt så blir nästa svårare att skriva.

Chris menade också att det är en god vana att för varje klass man är och skriver i försöker att göra den lite bättre i stället för att bara nå upp till den existerande kodens standard. Även om du inte hinner göra några större refaktoreringar så kanske det finns ett dåligt valt variabelnamn eller förtydliga ett flöde genom att bryta isär en metod i två.

Markus Widerberg - Refactoring .Net-code towards readability
Detta seminarie handlade till stora delar om hjärnans förmåga att ta till sig information. Tex nämndes att den mänskliga hjärnan klarar 7 (+-2) saker utan att först bygga en struktur. Därför är det viktigt att döpa saker på ett sådant sätt att läsaren kan koppla ihop texten med existerande strukturer. Med hjälp av dessa strukturer kan vi hålla många saker i huvudet. Utan dem trillar vi ner på 7 (+-2).

Markus konsterade att Visual Studio suger fett när det kommer till refactorering och att en plugin som tex Resharper är absolut nödvändigt. Han hade försökt att göra sin demo utan Resharper men fick ge upp. Kan tilläggas att de exempel som han visade inte var avancerade på något sätt.

Jag frågade Markus om han, som respresentant för det enda .Net fokuserade seminariet jag gick på under dagen, uppfattade om användande av m_ och I på interface är ungersk notation. Svaret på frågan var ja. Det skulle vara kul att få höra en officiell Microsoft representant resonera om detta då många verktyg i Visual studio generar kod som i mina ögon är ganska ungersk så att säga.

Ola Ellnestam - Software development team antipattern
Detta var inget bra seminarie. Inte för att Ola inte hade bra saker att berätta om utan för att framförandet var misslyckat.

Det viktigast som fastnade hos mig var ansvaret för kod och hur det ofta tenderar till att landa på en person. "Det var Kalle som implementerade det så fråga honom". Om Kalle är sjuk, på semester eller har slutat från jobbet så finns det ingen annan som vet hur det fungerar och Kalle kan ha skrivit saker på ett sätt som ingen annan förstår. Att rotera uppgifter och ansvar i ett projekt kan vara en lösning på problemet.

Todo:er var något som Ola också tog upp i kontextet att det är lätt att todo:er blir en form av inofficiell backlogg i projektet. Uppgifter som ingen igentligen vet att de borde göras och ingen heller kan ta ansvar för att de blir gjorda. Att regelbundet söka efter todo och att säga att todoer inte hör hemma i koden utan i backloggen kan vara ett par lösningar för att komma bort från det problemet.

Niclas Nilsson - Black Belt TDD/BDD
För några månader sedan så kom Stackflow #38 där det påstods att det är lätt att göra en liten förändring i en kodbas och genom den lilla förändringen tvinga fram förändringar i 10% av testerna. För de som kör TDD där i det närmaste halva kodbasen kan bestå av testkod är det en alarmerande siffra. Niclas beskred inte att det är möjligt att skriva kod på det sättet men menade att problemet med att många spruckna tester vid små förändringar kommer av dålig kod i första rummet. Han menade kort och gott på att om koden är välskriven i första rummet utan onödiga beroenden kommer inte heller testerna att ha det problemet. Niclas hade en teori om att mycket dålig kod beror på att den är skriven ur fel förutsättningar, att man har börjat fundera på detaljerna först. Problemet med att beskriva detaljerna först är att för varje abstraktionsnivå man flyttar sig uppåt (utåt?) så har man redan koden för de undre lagren redan skrivna och då använder man den i stället för att tänka efter hur det abstraktionslagret borde fungera.

Nicklas lösning är att man börjar på toppen (utsidan) med att gå över kundens krav och börjar skriva toplevel-funktionalliteten först. Eftersom detaljerna inte är skrivna ännu måste man skriva mock-implementationer. Något som i praktiken leder till Dependency Injection. De tester man skriver (före eller efter) produktionskoden kommer om man skriver utsidan först att testa mycket mindre delar av koden och risken för att de ska spricka i onödan minskar drastiskt.

Emily Bache - Clean code
Tyvärr så har jag läst boken. Utöver den hade inte Emily så hemskt mycket matnyttigt att erbjuda mig. Jag hade gärna sett lite kodexempel på när man dragit Uncle Bobs regler för långt, eller inte tillräkligt långt. Eller exempel på hur man kan bena ut existernade kod till något clean.

Niclas Nilsson - The unintuitive part of agile
Detta var för mig dagens bästa seminarie. Niclas tog upp några av de delar som vid en snabb titt kan verka slösa på tid faktiskt fungerar i praktiken.

  1. Täta iterationer borde innebära att man lägger ner massor med energi på att få något fungerade väldigt ofta, tid som man skullel kunnat skriva kod. Men poängen med de täta iterationerna är att man ger produktägaren en möjlighet att se vad som händer med applikationen och kunna prioritera utifrån de affärsvärden som ska betala arbetet i slutändan.
  2. Täta releaser borde innebära att man spenderar tid på att lägga ut applikationen i produktion och dessutom utsätta verksamheten för en risk för problem i samband med uppdateringen. Niklas menar att risken är imaginär, om man uppdaterar ofta vill man automatisera processen och buggar kommer att gå ur deploymentprocessen då den körs så ofta. Om man bara gör uppdatering var 6:e månad så är risken större då man är mindre benägen att automatisera processen.
  3. Parprogrammering borde innebära att man får hälften så mycket gjort då det bara en är person som faktiskt skriver kod. Dock är det så att man uppnår ökad effektivitet i from av ett antal sociala kontrakt. Man kollar inte mail med någon brevid, det är svårare att störa om någon ser ut som att de sitter i ett möte. Dessa sociala bitar menade Niclas att de skulle ge en produktivitetshöjning mer än väl motsvarande den extra kostnaden. Att man dessutom slipper ett antal buggar och feltänk gör det attraktivt att parprogrammera.
Niclas pratade om tester där han på ett ganska svart-vitt sätt menade på att testdriven utveckling fungerar. Dock bör man vara uppmärksam när man inför TDD, det finns fällor som man kan gå in i. Betalar sig inte TDD i form av minskade problem med buggar, ja då ska man stanna upp och fundera på vad man gör för fel.

Jag frågade hur man ska tänka om man vill införa TDD i en organisation. Niclas hänvisade till BDD som ett sätt att lära sig tänka utifrån tankebanor som gör TDD naturligt.

Ola Ellnestam, Daniel Brolund: Start paying your technical dept
De visade på ett sätt att lösa komplicerade refactoreringar utifrån ett mål i form av att nå ett affärsvärde. Metoden gick ut på att rita upp en graf över vad som ska göras och sedan rekursivt rita upp de beroenden som beroendena har tills man kommer till en punkt där man kan börja lösa upp beroenden. Fördelden med den modell de visade är att den går att avbryta mitt i arbetet. De förändringar man gör får aldrig kräva att man samtidigt ska lösa något annat beroende i grafen så för varje steg man tar på vägen tillbaka mot affärsvärdet ger bättre och mer flexibil kod. Skulle affärsvärdet förändras så har man förhoppningivis löst upp beroendena på ett sådant sätt att det nya affärsvärdet är bekänt av de förändringar man gjort på vägen.

På det stora tyckte jag att dagen var bra. Det som kanske var lite trist var att de som föreläste om process och metod alla körde java. Hade varit kul med någon .Nettare som kanske kunnat berätta något om Clean Code i .Net tex.

söndag 22 mars 2009

Ungersk notation

Ungersk notation (hungarian notation) är något som jag uppfattat att de flesta reflexmässigt säger att det är något dåligt. Men jag tror att det är färre som faktiskt vet varför det är något dåligt och som är villiga att ta konsekvenserna av att undvika att använda Ungersk notation.

Vad är då ungersk notation? Ursprungligen kommer det från programmeringsspråk som var otypade. Det enda sättet att se att en variabel innehåller en text var helt enkelt att kalla variabeln textName och för nummer numberSalary. Så kort och gott, ungersk notation är en deltext i en variables namn som ger namnet en betydelse som stäcker sig utanför applikationens logik. Det var ett nödvändigt ont förr men idag med moderna verktyg onödigt.

Det är att ge variabeln en betydelse som inte beskriver applikationens funktion som är det som anses vara dåligt. Men varför är det dåligt? I första hand gör det en applikation svår att underhålla genom att man stoppar in implementationsdetaljer på ställen i koden där de inte hör hemma. En variabels betydelse ska inte förändras bara för att man förändrar dess typ.

Finns det undantag från regeln? Självklart, få regler som inte har undantag. GUI programmerare brukar ofta uppskatta att de kan gruppera alla textfält genom att prefixa dem med txt. Dock bör man isolera dessa variabler i ett så tunt lager som möjligt och bearbeta dem på ställen där man har möjlighet ge saker riktiga namn.

Några exempel på vad jag anser vara ungersk notation:
  • IInterface - Här talar vi effektivt om att det är ett interface genom prefixet I. Någon som använder koden ska inte känna till implementationsdetaljer. Om det är en implementation av ett interface, en abstract klass eller en konkret klass är ointressant och störande information. Bättre då att att ge saker bra namn och om man inte kommer på något bra namn använda sig av ett suffix som tex impl, sub.
  • m_, s_ eller bara _ är bra hjälp men med en bra IDE som kan färgkoda variablerna helt onödig. Skriver man små överskådliga klasser och metoder är det lätt att se vad som är vad. Att prefixa variablerna på det sättet är att försöka sätta plåster på dålig kod.
Vad är inte ungersk kod? Det finns ett scenario som man kanske kan säga gränsar mot ungersk notation utan att vara det. Det är vid användning av kända designpatterns. Tex vid användandet av en Factory är det lämpligt att sätta Factory som suffix, tex EmployeeFactory. Nyansen ligger i att det inte är en specifik klass som man sätter i namnet utan ett beteende. Riktigt lurigt blir det när man har en EmployeeList där List är något man hittar i ett antal språk som en klass men som också bara kan markera det att objektet i fråga beter sig som en lista utan att ha något med implementationen att göra.

tisdag 17 mars 2009

Templatemethod

Fortsätter med strategier för att ta bort duplicerad kod. Förra var ett exempel på en abstract factory. Nu blir det en template method. Ett enkelt scenario där det är lätt att man börjar upprepa kod är när man ska använda en extern resurs, tex en fil. Man måste öppna filen för läsning och kanske läsa in den till minnet, man ska bearbeta filen och till sist ska man stänga filen. Avsett vad man ska göra med innehållet i filen så måste man utföra det första och sista steget. Följande metod är ett exempel:

public void handleContent(File file){
InputStream stream = getInputStreamFromFile(file)
processStreamData(stream);
closeStreamAndFile(stream, file);
}

Något förenklat säkert, men att skriva en variant på processStreamData utan att behöva använda upprepa anropen till getInputStreamFromFile(File file) och closeStreamAndFile(InputStream stream, File file) har sina sidor. Exemplet ovan ser inte så illa ut men det är nog inte varje metod som implementerar ett motsvarande mönster som har brutit ner det till tre rader.

Så hur komma ifrån duplicering om man vill skriva en varant på handleContent?

Vi vet att två av metoderna kommer att upprepas, öppna och stänga. Vi vet dessutom att vi vill stoppa in något mellan. Följande klass är första steget.

public abstract class TemplateMethodExample{

// Method för att öppna strömmen/filen
private InputStream getInputStreamFromFile(File file){ .... }

// Metod för att städa efter sig
private void closeStreamAndFile(InputStream stream, File file){ ....}

// Den metod som vi kommer att anropa och som öppnar
// processar och stänger
public handleContent(InputStream stream){
InputStream stream = getInputStreamFromFile(file)
processStreamData(stream);
closeStreamAndFile(stream, file);
}

// Den metod vi ska overrida med specifik funktionallitet
// i en konkret klass
protected abstract processStreamData(InputStream stream);
}

Tricket här är att vi gör en abstrakt klass med en abstrakt metod som där vi kan implementera den specifika funktionallitet vi önskar. När vi sedan vill använda vår specifika implementation så anropar vi handleContent(File file) som är klassens enda publika funktion och den i sin tur använder den implementation av processStreamData(InputStream stream) som har den specifika funktionallitet vi önskar.

Som extra vinst har vi dessutom effektivt hindrat att någon glömmer stänga filen efter sig.

måndag 16 mars 2009

Don't ask, tell

En liten utveckling på G5 som är beskriven tidigare. Mycket duplicering kan lösas genom att koda på en annan abstraktionsnivå. Genom att byta abstraktionsnivå kan dupliceringen förvinna. Låter lite småflummigt så jag skriver ner ett exempel:

public String getName(Example e){
String name;
if(e.type.equals("private customer"){
name = e.firstName + " " + e.lastName;
}else if(e.type.equals("supplier"){
name = e.companyName;
}else if(e.type.equals("creditor"){
name = e.creditName + "@" + e.companyName;
}
return name;
}

Koden ovanför är något krystad men beskriver ett objekt där "type" kan ha minst tre värden. Värdet på "type" bestämmer hur man ska bygga upp objektets name. Antag nu att den här koden är copy'n pastad på några ställen och du kommer på att name inte ska vara creditName + "@" + companyName utan i stället bara companyName. Då är risken ganska stor att man bara ändrar på första stället och lämnar en otrevlig bugg efter sig. Men hur ska man då hantera situationen? Vi ska byta plats för var man bygger namnet. I stället för att ha en Example-klass ska vi ha tre stycken subklasser till Example som var och en vet hur den skapar sitt eget namn.

public String getName(Example e){
return e.getName();
}

Vänta nu, hur gick det där till?

  1. Gör den existerande publika konstruktorn protected så att bara subklasser kan använda den. Det genererar ett gäng kompilieringsfel men det gör inget.
  2. Skapa en klass som heter ExampleFactory.
  3. Lägg till en metod createExample i ExampleFactory som tar samma argument som den nu protected konstruktorn i Examle. Implementera metoden enligt följande 4.
  4. public Example createExample(String type, .... ){
    Example example = null;
    if(e.type.equals("private customer"){
    example = new PrivateCustomer(....);
    }else if(e.type.equals("supplier"){
    example = new Supplier(....);
    }else if(e.type.equals("creditor"){
    example = new Creditor(....);
    }
    return example;
    }
  5. PrivateCustomer, Supplier och Creditor ärver samtliga från Example och samtliga implemeterar sin version av getName()
Nu har vi dolt den fula if-satsen i en factory. Det är det enda stället vi behöver den. Genom att skapa objekt på en bättre abstraktionsnivå har vi fått bort dupliceringen.

.... noteringen är för att jag är för lat för att skriva exemplet komplett.

fredag 27 februari 2009

10 artiklar som alla borde ha läst (minst två gånger)

Läste på http://blog.objectmentor.com/ ett inlägg av Michael Feathers. Han skriver tydligen på en ny bok och hade konstaterat att han hade tappat fokus på vilken publik han skriver för. Vad kan de som lässer boken. Kort och gott så kom han på sig med att förklara förklaringarna vilket inte var så bra. Så han plockade fram en lista på tio artiklar som i sin tur skulle förklara de begrepp han tänkte använda sig av. Några av dem är ganska gamla så det är ingen revolutionerande kunskap på något sätt. Ibland kan det vara bra att titta på annat än det som är hypat idag. Jag tänkte försöka mig på att läsa dessa tio artiklar och dessutom försöka att skriva ihop en kort sammanfattning här (om jag förstår tillräkligt mycket av dem).

De tio artiklarna är:
  • On the criteria to be used in decomposing systems into modules – David Parnas
  • A Note On Distributed Computing – Jim Waldo, Geoff Wyant, Ann Wollrath, Sam Kendall
  • The Next 700 Programming Languages – P. J. Landin
  • Can Programming Be Liberated from the von Neumann Style? – John Backus
  • Reflections on Trusting Trust – Ken Thompson
  • Lisp: Good News, Bad News, How to Win Big – Richard Gabriel
  • An experimental evaluation of the assumption of independence in multiversion programming – John Knight and Nancy Leveson
  • Arguments and Results – James Noble
  • A Laboratory For Teaching Object-Oriented Thinking – Kent Beck, Ward Cunningham
  • Programming as an Experience: the inspiration for Self – David Ungar, Randall B. Smith
  • söndag 22 februari 2009

    Legacy code

    Enligt wikipedia betyder "Legacy code" följande: source code that relates to a no-longer supported or manufactured operating system or other computer technology. Läser man Michel Feathers artikel "Working effectivly with legacy code" får man följande till livs: The main thing that distinguishes legacy code from non-legacy code is tests, or rather a lack of tests. Michel Feathers hävdar att man inte behöver vänta på att support för koden ska försvinna, man kan skriva legacy code, alltså koden du ser på skärmen kan uppfylla definitionen innan du ens tryckt på sparaknappen eller kompilerat den första gången.

    Gammal kod är ofta svår att arbeta med. Ingen som längre jobbar med koden kommer ihåg varför man gjorde på ena eller andra sättet och ännu värre, det är inte någon som vet vad som är rätt eller fel längre, särskilt med hänsyn taget till eventuella förändrade krav från omvärden på vad koden ska göra. Detta är dock brister man kan se efter någon vecka i projekt som har fått börja från början. "Det är N som har skrivit koden, han vet hur den fungerar" är något
    det man kan höra ganska snart in i ett projekt. Något som kan vara ett första tecken på att man nyproducerar Legacy code.

    Varför är då tester boten mot Legacy code? Tester skapar ett förtroende för att man kommer att få reda på om man förstör existerande funktionallitet och med det försvinner det största problemet med Legacy code, rädlan för att man förstör något som idag fungerar. Så Michel Feathers har säkert funderat på varför man ska vänta på att koden blir gammal och osupportad innan man kallar den för legacy code när det största problemet med legacy code kommer redan vid nyproduktion, rädslan för att ändra det som fungerar.

    Men om man nu sitter med ett projekt där det inte finns några tester och ingen längre kan säga hur de tänkte när de skapade koden. Tanken på att sätta sig och börja dokumentera existernade funktionallitet kanske är så upplyftande men på något sätt måste det göras. Hur ska man annars veta om den förändringen man gör inte påverkar annan funktionallitet på ett oavsiktligt sätt.

    Vi dokumenterar den existerande funktionalliteten genom att skriva tester, att sitta och klicka i applikationen är en syssla som människor är dåligt rustad för . Dessa tester är dock något annorlunda. De är inte till för att verifera att den existerande koden gör rätt utan har som enda syfte att upptäcka om den existerande funktionalliteten förändras. Om en metod för ett givet input returnerar true, så har testet som uppgift att tala om när samma input ger false. Hurvida det är rätt att returnera true för det givna inputet är inte viktigt. Det som är viktigt är att det är som koden levererar idag.

    Att skriva tester för en hel applikation är inte riktigt genomförbart dock. Vi måste försöka att titta på var det är vi ska göra vår förändring och sedan försöka att ringa en "trång punkt" genom vilken funktionalliteten styrs idag och testa utifrån denna trånga punkt. Syftet är inte att ge oss en komplett bild utan något som genom en rimlig arbetsinsats kan ge oss en relativt god chans att bli informerade om att vi har förändratat vi borde hållt tassarna borta från.

    Men nu när vi skrivit de tester som verkar rimliga har vi en uppgift till innan vi faktiskt kan påbörja den uppgift som är vårt faktiskta uppdrag. Vi bör refaktorera den existerande koden. Detta genom att bryta ut se till att variabler och metodnamn är vettigt döpta, bryta ut metoder och sist se om vi kan struktuerar klasserna på ett bättre sätt, tex genom att byta ut if/else mot polymorphism. För varje steg kör vi våra tester så att vi inte oavsiktligt har ändrat något.

    Nu är vi äntligen framme. Vi har betalat en del av den skuld som tidigare utvecklare belastat applikationen med och kan utifrån de tester vi skrivit steg för steg skriva om testerna till att testa den funktionallitet vi önskar att applikationen ska ha och till sist anpassa applikationen så att testerna börjar lysa grönt.

    Lät det krångligt? Att förändra kod till nya krav är inte alltid enkelt. Men man kan göra det på ett sätt som ger dålig nattsömn och kräver magsårs medicin eller så försäkrar man sig genom att installera larm som kan upptäcka felaktigheter.



    torsdag 19 februari 2009

    Design Principles and Design Patterns fortsättning

    Tyckte att det blev lite långrandigt så jag bestämde mig för att dela upp min sammanställning av Bob Martins - "Design principles and Design Patterns".

    Nu blir det hur man kan hantera beroenden moduler i en applikation.
    Packet Cohesion Priniciples
    Tre sätt att resonera runt hur man ska förpacka sina moduler
    • The Release Reuse Equivalency Priciple (REP) - REP kopplar ihop releasehantering med återanvändning. De klasser som behövs för att kunna skapa en release av en modul ska grupperas tillsammans och därmed återanvändas tillsammans. Det gör det smidigt tex för en kund att veta att det har hänt tillräkligt med koden för att det ska vara idé att uppdatera även om han/hon bara är intresserad av en liten delmängd av de funktioner som kommer med releasen.
    • The Common Closure Principle (CCP) - Klasser som ändras tillsammans bör förpackas tillsammans. Om man befinner sig i utvecklingsfasen så vill man inte hantera många olika moduler och hålla koll på vilka andra moduler som man är beroende och hur vida de modulerna ändrats på ett sätt som kräver ändring i den egna modulen. Därför minimerar man antalet moduler som behöver uppdateras för en releasecykel.
    • The Common Reuse Principle (CRP) - Klasser som inte används tillsammans ska inte förpackas tillsammans. Varför ska man behöva uppdradera ett operativsystem bara för att få tillgång till en funktion? Förpacka därför bara det som används tillsammans för att inte tvinga på användaren en större förändring än nödvändigt.
    De tre principerna ovan utesluter varandra. REP och CRP gör livet lite lättare för de som vill återanvända kod. CCP tenderar till att ge stora moduler medans CRP ger små. Som tur är vilken princip man väljer att förpacka modulerna inte skrivna i sten. Medans man utvecklar kanske man väljer att använda CCP och sedan när modulerna kanske man går mot något som är lättare för användarna av modulerna att använda som REP eller CRP.

    The Packet Coupling Principles
    De tre kommande principerna styr hur relationerna mellan olika modulerna ska fungera.
    • The Acyclic Dependencies Principle (ADP) - Ganska enkel och självklar. Modulerna ska inte ha cykliska relationer, tex Modul A -> Modul B -> Modul C -> Modul A. Tänk dig att ha dataproviders som är beroende på GUI. Ha någon som håller koll på att cykliska relationer inte smyger sig in i applikationen.
    • The Stable Dependencies Principle (SDP) - SDP säger att man ska försöka att rikta sina beroenden mot det som är stabilt. Vad är då stabilt? Det som är svårt att förändra av olika skäl kan sägas vara stabilt. Den viktigaste faktorn för att en modul är stabil är att den har många andra moduler som är beroende på den. Ska man ändra i modulen så får man ändra på många andra ställen. Herr Martin ställer upp en enkel formel för att beräkna om en modul är stabil eller ej.
      Ca = Inkommande beroenden (klasser utanför modulen som är beroende på modulen i fråga)
      Ce = Utgående beroenden (klasser som är beroende på andra klasser utanför modulen)
      I = Instabilitet - Beräknas I = Ce / (Ca + Ce)
      Så med formeln ovan kan vi säga att SDP betyder: Din modul ska ha högre beroenden än de den har sina beroenden på. Men ska alla moduler vara stabila? Självklart inte, vi vill ju att våra program ska kunna följa med ovärldens krav utan stora arbetsinsatser.
    • The Stable Abstractions Principle (SAP) - SAP är svaret på problemet som uppstår med SDP där det blir svårare och svårare att utföra förändringar desto fler beroenden modulen har. SAP säger att stabila moduler ska vara abstrakta, alltså inte ha någon implementation. Det ger oss frihet att förändra byta ut implementation utan att påverka modulen som alla andra beror på. Alltså ska de mest stabila modulerna vara abstrakta. Herr Matrin råkar ha en liten formel på att mäta detta också:
      Nc = Antalet klasser i modulen
      Na = Antalet abstrakta klasser/interface
      A = Abstrakthet(?) A = Na/Nc

      Om man jämnför A med den tidigare I så bör de följa varandra. En modul med högt I bör också ha ett högt N och en modul med lågt I bör ha lågt N.

      Det finns en ideallinje som I och A följer och man kan räkna på hur långt ifrån denna ideallinje en modul ligger med hjälp av följande formel:
      D = (A + I - 1) / sqrt(2) (ger ett värde mellan 0 - 0.7 ungefär) där värden närmare noll är bättre.

      Naturligtvis är detta bara beräkningar och inget man ska se som absoluta fakta. Men har man gjort värdena kan man välja att tro på dem eller säga att man har gjort val som gör dem missvisande. Men då har man ett värde att resonera runt vilket förmodligen är något bättre än att bara gissa.
    Resten av dokumentet handlar om designpatters som jag tror alla är representerande i GOF bok som heter Design Patterns.

    måndag 16 februari 2009

    Design Principles and Design Patterns

    Hittade ett kul dokument som Bob Matrin skriv i början av 2000-talet. Känner igen mycket av innehållet från Clean Code fast i kortare form. Tar upp några av sakerna där ifrån.

    Ruttnade kod
    Jag har inte varit med i något projekt där man inte har försökt att utgå från de bästa av principer och sett fram emot hur bra allt ska bli. Hur alla problem man har haft i tidigare projekt ska lösas och man ska göra allt rätt en gång för alla. Men när projektet har pågått ett tag så har de rosafluffiga drömmarna gått i kras och projektet är samma gamla ruttna soppa som de alltid blir. Man tycker att man borde ha lärt sig. En liten tröst i sammanhanget kan vara att de flesta utvecklingsprojekt tycks gå samma väga. Goda intentioner som malts sönder och samman. Bob tar upp fyra symtom på ruttnande design:
    • Stelhet inträffar när varje förändring tycks sluta i att man har skrivit om halva applikationen. En förändring kräver en förändring någon annanstans som i sin tur behöver ytterligare en uppsättning med förändringar. När man ser att även små förändringar får veckor att försvinna vill man inte gärna ändra ens när det behövs.
    • Skörhet inträffar när man utfört förändringar och man står inför en applikation som inte längre fungerar som den ska. Tillsynes helt orelaterade moduler slutar fungera pga ändringen. Vem vågar ändra när man vet att buggrapporterna kommer att hagla så fort man tagit applikationen i drift. Varje patch man gör tycks bara leda till fler problem än de fixade.
    • Orörlighet inträffar när man inte kan återanvända existerande kod trots att specifikationen borde passa som hand i handske. Det beror ofta på att modulen man ska använda har en stor ryggsäck i form av beroenden åt alla håll och kanter vars vikt överträffar vinsten i att återanvända den existerande funktionalliteten.
    • Tröghet kommer i två varianter, från design/arktektur och från utvecklingsmiljön. När trögheten kommer av design har man gjort vägval som kräver stora insatser om man ska göra "rätt". Då blir det ofta lätt att skriva ett hack eller två. Tröghet från utvecklingsmiljön kan vara långa kompileringstider. Då kan det tex vara frestande att checka in kod utan att ha kompilerat först. Dumt men frestande.
    Vad är orsakerna till dessa symtom då? Enligt Bob Martin är förändrade krav den stora källan till att symptomen ovan uppstår. För att det ska bli riktigt bra så kanske man har utvecklare som ska lösa en uppgift under tidspress utan att känna till hur den befintliga arkitekturen är tänkt att fungera. Bit för bit löses de ursprungliga goda intentionerna upp till en ohanterlig massa likt en sönderkokt potatis. Men vi utvecklare kan ju inte gärna skylla på förändrade krav. Vi vet att krav förändras.

    Lösningen för att hantera förändrade krav är att hantera de beroenden som finns i koden. Nedan kommer några av de principer som föreslås i dokumentet.

    Open closed principle (OCP)
    Alla "moduler" ska vara öppna för att byggas ut men stängda för att modifieras. Låter lite motsägelsefullt men är en av de viktigaste principerna för objektorienterad systemutveckling. Man ska kunna förändra vad modulen gör utan att behöva förändra modulens kod. Nedan kommer några tekniker för att hantera OCP.
    • Dynamic polymorphism - Går kort och gott ut på att man ska definiera ett gränssnitt, tex ett interface som man sedan kan lägga till implementationer som löser de specifika uppgifter som olika omständigheter.
    • Static polymorphism - Genom användning av templates eller generics kan man bygga ut funktionalliteten utan att behöva röra den existerande koden (exemplet i pappret känns lite gammalt och jag ser dem mer eller mindre som likadana).
    Genom att följa OCP kan vi skapa moduler som är lätta att bygga vidare på utan att man behöver ändra den existerande koden. Det är ett ideal som ibland kan vara svårt att nå men även om man bara delvis når målet är det något som gör din applikation betydligt enklare att underhålla. Det är alltid bättre om ändringar inte nästlar sig sin i existerande kod som fungerar.

    The Liskov Substitution Principle (LSP)

    Varje subklass ska kunna ersättas av sin basklass. Låter trivialt och med dagens moderna programmeringsspråk något som vi som vi får nästan gratis. Vi kan tex ta vilket objekt från en subklass och lägga det i en array typad för basklassen. Inget konstigt med det. Det finns dock några saker som vi fortfarande bör ha i bakhuvudet.
    • Cirkel/Oval dilemmat - Jag översätter detta till det något mer lätthanterliga Rektangel/Kvadrat. I skolan fick jag lära mig att en kvadrat är ett specialfall av en rektangel vars höjd och bredd råkar vara lika långa. Men så enkelt är det inte i programmeringens underbara värld. Om vi väljer att låta kvadrat vara en subklass till rektangel tvingar vi på en metod som en kvadrat inte har användning för. Höjd och bredd på en kvadrat är oviktigt, en längd på en sida räcker. Så för att kunna ha kvadraten som en subklass till rektangeln måste vi fuska till kvadraten så att om vi sätter höjden så kopierar vi det till bredden så att de alltid har samma värde. Men alternativet är inte mycket roligare. Om vi använder kvadraten som basklass kan vi inte manipulera rektangeln utan att behöva kolla vilken typ av objekt vi har och sedan kasta den till lämplig subtyp som vi sedan kan manipulera. Att ha rektangeln som basklass är lämpligare än kvadraten i detta fall. Nu tror vi att vi har tänkt på allt men betänk följande testmetod:

      public testSquare(){
      Rectangle rectangle = new Square();
      rectangle.setHeight(5);
      rectangle.setWidth(3);

      AssertEquals(rectangle.getHeight(), 5);
      AssertEquals(rectangle.getWidth(), 3);
      }

      Hur ska testet gå igenom om vi dolt baken kulisserna kopierar bredden till höjden på kvadraten för att lösa vår arvsheariki?
    Berättelsen ovan illustrerar att Rektangel enligt RSP är en dålig basklass för en Kvadrat, i alla fall om man vill sätta höjd och bredd. Om man sent i utvecklingscykeln hittar ett dyligt misstag kan det vara väldigt svårt att rätta till och man får börja skriva diverse mer eller mindre fula undantag från regeln vilket inte direkt gör koden lättare att förstå för den som ska läsa den vid en senare tidpunkt.

    The Dependency Inversion Principle (DIP)
    Många tekniker använder DIP (COM, CORBA, EJB för att nämna några). Om OCP är målet som ska uppnås kan man säga att DIP är den primära metoden att nå målet. DIP säger att man ska använda interface eller abstrakta klasser i sina gränsnitt i stället för att anropa de mer rörliga konkrekta klasserna direkt. Om man använder de konkreta klasserna är det svårt att ändra den underliggande funktionalliteten utan att behöva ge sig in och ändra i redan fungerande kod. Om det skulle uppstå en situation tex av licensskäl som innebär att du måste byta ut en existerande modul så ska du inte behöva ändra i din existerande kod utan bara plugga in den nya modulen mot det existerande gränssnittet. Genom att använda tex en Abstract Factory kan du dessutom i runtime bestämma vilket implementation av interfacet som ska användas.

    Det stora motivet för DIP är att skydda sig mot förändringar och jag tycker nog att man bör skriva så många klasser som möjligt mot interface, men inte alla. Där man kan lita på att det inte kommer att uppstå förändringar är det naturligtvis inte nödvändigt att förvänta sig förändring. Problemet är att det inte är så mycket man kan lita på här i världen. För en .Net-utvecklare kanske det verkar onödigt att dölja hanteringen av sökvägar bakom ett interface för att de alltid har börjat med C: men nu med Mono kanske det inte är så självklart längre.

    The Interface Segregation Principle (ISP)
    Tänk att du har en webtjänst med tio metoder. Denna webtjänst används av tre andra applikationer (klienter). Om du nu måste ändra i någon metod för att stödja ett nytt behov hos en av klienterna så måste du ändra på de andra två klienterna också för att de alla ser samma gränssnitt mot tjänsten. Ingen rolig tanke tycker i alla fall jag. En bättre metod hade varit att dölja din webtjänst bakom tre stycken gränssnitt som kan förändras oberoende av varandra. Om en ändring sker i webtjänsten så kommer den bara att synas för de som får tjänsten publicerad genom sitt klientgränssnitt.

    söndag 15 februari 2009

    T1-T9

    Kanske borde dela upp denna men det är de sista reglerna. De berör testning och ger råd om hur man ska förhålla sig till dem. Jag får skriva detta ganska närma vad som står i boken då min personliga erfarenhet med att jobba med tester inte är så hög jag skulle önska. Tyvärr är tester något som projektledare tror att det är okej att strunta i tron om att vi programmerare skulle leverera mera fungerande kod som kan tas i produktion.

    T1: Otillräkliga tester
    Det är en fråga som det är väldigt enkelt att ge ett enkelt svar på. Om det existerar vägar genom koden som inte har utforskats med hjälp av tester vet du inte att din kod fungerar som den ska. Framför allt vet inte andra utvecklare att de måste ta upp en webapplikation, skriva i sökfältet, dubbelklicka på listan och sedan ändra i postnumret och sedan spara för att han/hon ska se att just den funktionen fortfarande fungerar efter de sista ändringarna. Så även om du vet hur du ser att funktionen fungerar så är testerna även en specifikation hur funktionen ska fungera.

    T2: Använd test-täcknings verktyg
    Tog upp lite av detta på T1 men vi människor är inte gjorda för vissa typer av uppgifter. Använd därför ett verktyg för att påvisa vad som är testat och viktigare, vad som inte är testat.

    T3: Strunta inte i triviala tester
    De är enkla att skriva och värdet i form av dokumentation av hur de ska fungera är ovärderligt.

    T4: Ett ignorerat test är en fråga om tveksamheter
    Om du inte har skrivit ett test runt en funktion visar du att du inte har förstått hur funktionen ska fungera och lämnar dessutom de andra utvecklarna med ett stort frågetecken om hur funktionen ska uppföra sig.

    T5: Testa gränsfall
    Vi har gått igenom gränsfall tidigare. Att testa att gränsfallen fungerar är extra viktigt. Att metoden fungerar i de flesta fall är inte tillräkligt.

    T6: Testa mer runt buggar
    Det finns ett ordspråk som säger att en olycka sällan är ensam. Det samma gäller för utvecklare. En trött utvecklare som har missförstått något har förmodligen inte bara gjort ett fel. Skriv inte bara ett test för att verifiera buggens existens. Undersök testtäckningen på näraliggande kod och se till att den är testad. Det är ett betydligt effektivare sätt att upptäcka fel än att invänta nästa bugg och åter igen sätta sig in i vad det är koden antas leverera.

    T7: Se mönster för varför tester falerar
    Om du har ett stort antal tester kan man ofta se mer mönster som man inte har förstått att man måste testa för. Tex kanske man har en begränsning på hur lång en textsträng får vara som man inte var medveten om när man skrev testerna initialt.

    T8: Testtäckning påvisar mönster
    Varför man testat viss kod men inte annan kod kan visa på intressanta mönster hur utvecklarna tänker. Att viss kod kanske anses vara så stabil att man inte behöver testa på den kan vara en källa till att andra tester falerar. För man vet ju trots allt inte att koden fungerar.

    T9: Tester ska vara snabba
    Detta är nog den viktigaste reglen för testerna. Om inte testerna är snabba är det ingen som vill köra dem. Det är också den enskilt viktigaste anledningen till varför man inte ska använda xUnit (jUnut, nUnit etc) till att skriva integationstester som springer igenom hela applikationen. Desto mindre varje enskilt test testar desto snabbare är det och desto mindre är risken att någon utvecklare tröttnar på att vänta på dem och slutar att köra testerna.

    lördag 14 februari 2009

    N1 - N7

    Nu när vi är klara med de generella reglerna så tittar vi på de som rör namnsättning.

    N1: Använd beskrivande namn
    Vi har alla sett kod som ser ut ungefär så här:

    public void doCalculation(){
    i = j + k;
    }

    Det är kod där man kan fråga sig vad för beräkning doCalculation gör, letar upp den sista siffran i PI? Variablerna i, j och k säger inte heller så mycket om varför de ska finnas. Bättre då hade varit att skriva metoden så här (om nu metoden skulle beräkna löner)

    public void calculateTotalSalary(){
    totalSalary = baseSalary + overTime;
    }

    Här behöver ingen fundera på vad vare sig variablerna eller metoden har för syfte.

    N2: Välj rätt namn på rätt abstraktionsnivå
    Denna är lite lurig. När ska man kalla ett telefonnummer för telefonnummer och när är det en kopplingssträng eller riktnummer? Att fundera på hur abstrakt namnsättningen ska vara är oerhört viktigt då det begränsar fantasin på läsaren om vad en funktion kan ha för användningsområde. Kopplingssträng skulle kunna utnyttja vilken tjänst som helst (Skype, telefon eller två burkar med snöremellan. Telefonnummer har begränsat användningsområdet till bara telefonnummer. Ibland är det rätt att använda väldigt specifika namn på saker och ting och ibland är det bra att vara öppen för att det kan komma andra implementationer än den man ska skriva just nu. Att välja rätt är inte enkelt men oerhört viktigt. Fundera ett varv extra på varje namn om det är tillräkligt generellt eller inte.

    N3: Använd standardiserad vokabulär
    Att använda ord för företeelser som alla känner igen är viktigt i alla språk. Kebab med deg kanske går att få till pizza med lite fantasi men det hade varit lättare att förstå om jag sagt pizza direkt. Om det heter webcontroll eller taglib är i sig självt oviktigt. Vad de som ska läsa din kod känner till det som är däremot viktigt. Om man pratar om en AbstractFactory se då till att det är definitionen från GOF du hänvisar till för det är sannolikt den som de flesta känner till. Om du gör ett projekt för styrning av mjölkmaskiner se då till att du använder ord från den domänen i stället för att hitta på egna uttryck. I stora projekt kan man kanske tillåta sig att ha en uppsättning med egna uttryck för ett antal företeelser som är specifika för projeket men i övrigt använd uttryck som alla kan googla definitionen på.

    N4: Otvetydiga namn
    När man döper saker och ting ska man vara nogrann med att metoden inte kan tolkas till att den gör något annat än den gör. Metodnamn som uttrycker sig i svepande ordalag, tex rename säger inte så mycket om vad det är som ska döpas om eller hur objektet ska döpas om. Så var tydlig.

    N5: Använd långa namn på stora "scope"
    Att använda en "i" som ett variabelnamn kan vara ok för väldigt korta metoder där betydelsen av "i" kan framgå tydligt ändå. Men i större sammanhang behöver man längre mer beskrivande namn som klarar av att beskriva den komplexitet som kommer med större sammanhang.

    N6: Koda inte koden
    Detta är min favorit sedan jag började programmera i .Net-miljö där standarden (i alla fall på min arbetsplats) är att skriva variabler med m_ och s_ och prefixa interface med I. För mig är detta Ungersk kodning som är precis lika illa som btnMyTextStr. Om man nödvändigtvis måste koda sina variabler gör det som ett suffix och så långt bort från de publika gränssnitten som möjligt, tex på ett interface Company där den implementerande metoden skulle kunna kodas som CompanyImpl. Fast det bästa är om man kan ge riktiga namn utan att behöva lägga på koder. Unvik den Ungerska sjukan med all kraft.

    N7: Namn ska beskriva sidoeffekter
    Har ni stött på en metod som ser ut något i still med detta:

    public void setName(String name);

    Men i stället för att bara sätta ett namn så sparas objektet också i databasen. Om du måste göra metoder som gör två saker, se då till att det framgår av namnet. SetNameAndSave skulle ha varit ett bättre namn som inte ger utvecklarna några överraskningar.

    G31-G36

    Nu avslutar vi de generella reglerna (där av G). Det har varit tungt att ta sig igenom dem. Det som återstår efter detta inlägg är namnsättning och tester (kanske javareglerna också men de känns lite för specifika för min smak).

    G31: Dolt beroende av tid/ordning
    Ofta är metodanrop beroende av den ordning de anropas. Att döpa metoderna till first, second och third är kanske inte riktigt idealiskt för att hjälpa läsaren att förstå vilken ordning som anropen måste göras. Dessutom är det inget som faktiskt hindrar en programmerare från att anropa second före first. Bättre att first returnerar ett objekt av någon typ som second kan använda och att second i sin tur returnerar ett objekt som thrid tar som argument. Dessutom behöver man inte hänvisa till någon konvention (G27) utan tvingar användaren att följa anropsordningen, eller något som i alla fall tvingar den anropande klassen att se till att ha sina saker i ordning.

    G32: Var inte godtycklig
    Ha en anledning till varför du strukturerar din kod på ett speciellt sätt och se sedan till att koden på ett tydligt sätt reflekterar den strukturen. Om du i kod lyckas komunicera varför dina val är som de är kommer andra utvecklare följa ditt exempel. Om din strukturen är otydlig och svävande kommer känna att de kan göra på andra och för dem bättre sätt.

    G33: Kapsla in gränsfall
    Gränsfall är svåra att hålla koll på. Se därför till att de enbart hanteras på ett ställe och inte sprider sig som en pest genom koden. Ett enkelt exempel är en koll där första objektet i en lista inte ska kolla om det finns något tidigare objekt i listan. Siffran noll som värde på att det är den första ska vara dold bakom en variabel tex döpt till firstObject (G25). Metoden som faktiskt vet att det är skillnad på första och andra objektet i listan bör också bara finnas på ett ställe. Övrig kod ska inte behöva veta att det är skillnad i hanteringen, det är en implementationsdetalj.

    G34: Funktioner går enbart en abstraktionsnivå ner
    Denna har en del med G6 att göra och jag återanvänder bilexemplet. Bilen står still i en korsning och ska svänga vänster. Metoden för att hantera denna situaion ska öka farten och styra åt vänster och sedan när tillräklig riktningsförändring skett sluta svänga. Det är alltså tre anrop till tre andra metoder som tar hand om detaljerna med att bestämma bränsleblandning, mängd bränsle som ska sprutas in i cylindrarna och annat som faktiskt behövs för att bilen ska fungera. En enkel regel för att se när man går ner en abstraktionsnivå i koden är att man använder val eller snurror. Det som händer inne i valet eller snurran är oftast på en annan abstraktionsnivå och hör där med hemma i en egen metod och håller där med den första metoden kvar på "sin" abstraktionsnivå. Detta tillsammans med G30 gör det betydligt svårare att skriva komplicerad kod.

    G35: Håll konfigurerbart data på hög abstraktionsnivå
    Konfiguration är viktigt, att gömma den typen av information långt ner är inte helt lyckat. Den ska vara enkel att hitta och enkel att förändra. Att gömma konfigurerbart data där det faktiskt används innebär att läsaren får leta länge efter hur man ändrar tex en ipadress till en webservice.

    G36: Undvik beroenden på beroende
    I normalfallet vill vi att vår kod ska känna till så lite som möjligt om annan kod. Betänk följande metod i en klass:

    public void aMethod(){
    a.getB().getC.doSomething()
    }

    Den här klassen har en medlemsvariabel som heter a. Vår klass känner till att a har en metod som heter getB och det är helt normalt. Men att klassen känner till att det som returneras från getB() också har en metod som heter getC() och att man på den kan anropa doSomething() är ganska illa. Varför det är dåligt. Om man nu skulle vilja förändra getA() så att den i stället för att returnera ett objekt som har en metod som heter getB() returnerar ett objekt som inte har den metoden så måste du även ändra på alla ställen där man gjort en anropskedja som ovan. Hur löser man problemet då? I första steget använder vi G19 (förklarande variabler) så att det går att se vad getA() och getB() och getC() returnerar för något. Nästa steg är att undvika duplicering och bryta ut anropskedjan så att den bara existerar på ett ställe. Det tredje steget är lite svårare men det går ut på är att steg för steg korta ner kedjan genom att i stället för att anropa getA() anropa doSomething() i som i sin tur anropar den del av kedjan som är kvar och sedan upprepar man tills kedjan inte längre existerar. Ser att texten blir knölig att läsa så jag skriver ett kodexempel:

    // i vår klass
    public void aMethod()
    a.doSomething();
    }

    // i klassen som som objektet a kommer ifrån
    public void doSomething(){
    b.getC().doSomething();
    }

    Här har jag tagit bort ett steg ur anropskedjan i första exemplet. Det kan dock bli många metoder i en del klasser om de ska ta hand om anrop den här vägen så det kan kan ibland vara idé att implementera speciella klasser som får vara en punkt i applikationen som kanske har lite mer kunskap om ett antal klasser än de borde ha.

    fredag 13 februari 2009

    G26 - G30

    Inte många kvar på G efter den här...

    G26: Var exakt
    Den här handlar om att inte slarva och göra halvhjärtade val. Om du tex fyller en ArrayList med ett antal värden och sedan sak returnera denna så bör du fundera på om returntypen faktisk ska vara ArrayList. Kanske det är bättre att returnera bastypen List. Det kanske inte är så att du vill att en anropande klass ska kunna modifiera listan så en enumeration kanske är bättre. Om du returnera en List måste du implementera din metod för att faktiskt kunna hantera att listan ändras. Om du returnera ArrayList så måste du ha en anledning till att visa den implementationsdetaljen. Så fundera på hur du vill att din metod ska användas och tänk igenom de konsekvenser dina val får.

    G27: Struktur över konvention
    Dokument med konventioner kan vara bra ibland. Men att hindra de andra utvecklarna (och sig själv) från att missbruka koden är bättre. Får man inte anropa databaslagret från GUI-lagret se då till att det inte går genom att göra klasserna onåbara från GUI-lagret. Om dina dataproviders måste ha en transaktion kontrollera då det i koden så att de som försöker att använda dem får stora fula felmeddelanden om transaktionen inte är på plats. Struktur vinner över konvention alla gånger av alla (nästan).

    G28: Dölj boolska uttryck
    Betänk följande metod:

    public void MyMethod(){
    if( a == running & b <>
    // do something
    }
    }

    och jämnför med följande:

    public void MyMethod(){
    if(isTemperatureSafe()){
    // do something
    }
    }

    Boolska uttryck blir snabbt oläsbara och även om de är enkla och där med läsbara så är syftet av variable > 0 självklart alla gånger. Vad betyder det att värdet är större än noll? Kanske hade varit bättre med att ha en metod som faktiskt talar om vad vi testar.

    G29: Undvik negativa booska uttryck
    Vi människor har lite svårare att ta till oss negativa uttryck. Inte sant är svårare att förstå än falskt. Att använda de små språkkonstrukten som utropstecken (!) för att markera att uttrycket är falskt gör inte saken lättare. Försök att hitta uttryck som inte behöver använda negationer och dölj uttroptecken bakom metoder som låter dig skriva i klartext.

    G30: Funktioner bör göra en sak
    Denna är viktig. En metod ska göra en av två saker. Ta ett beslut eller utföra EN uppgift, till exempel populera ett objekt med värden från ett argument. Metoder som tar flera beslut är svårare att förstå. Metoder som tar ett beslut på om om argumentet är användbart, sedan populerar ett objekt och sedan tar ett annat beslut på om objektet är bra mycket svårare att förstå. Kanske så att man kan argumentera för att utvecklare är smartare än genomsnittsbefolkningen men det är förmodligen bättre ekonomi i att låta programmerare syssla med komplexa problem än komplex kod.

    G21 - G25

    Mer mer mer mer ... aldrig tar de slut..

    G21: Förstå algoritmen
    Ofta kan man se klasser och metoder där det ser ut som om något spejat skärmen med if-satser och boolska variabler. Detta kan vara ett tecken på att personen som skrivit koden har skrivit något som kanske fungerar men igentligen inte har någon större koll på vad koden faktiskt ska göra. Naturligtvis är det ofta så att man inte har riktigt koll på hur man ska lösa sin uppgift och mer eller mindre testar sig fram mot ett resultat och det är inget fel med det. Men innan du anser dig vara färdig refaktorera koden till något som faktiskt går att förstå och som faktiskt visar att du har förstått vad du gjort.

    G22: Gör logiska beroenden fysiska
    Denna står i lite i motsatsförhållande till G13. Den är inte helt enkel att förklara och jag stjäl exemplet i boken då jag inte lyckas komma upp med ett eget. Exemplet beskriver en utskriftfunktion som där den anropande klassen bestämmer hur många rader som ska skrivas ut på en papper genom att själv bestämma när sidbrytningarna ska ske i stället för att tala om för utskriftsklassen att den borde lägga in en sidbrytning enligt ett visst intervall. Detta innebär att utskriftklassen har ett logiskt beroende på den anropande klassen. Det hade varit bättre att skriva in detta i utskriftklassen... Ja.. inte helt enkel...

    G23: Föredra arv före if/else eller switch
    Jag om denna första gången i Pragmatic programmer under namnet "Don't ask, tell" och säger att man inte ska ta beslut efter vilket tillstånd en klass befinner sig i genom att fråga klassen vilket värdet variablen "type" har. I stället ska man när man skapar objektet ta beslut om vilken subtyp klassen ska vara och sedan be klassen "göra sin sak". Ser ni långa haranger med if/else som jämnför en variabel i klassen med ett antal värden är det sannolikt ett tillfälle där en polymorfisk lösning skulle vara bättre. If/else-satserna är dessutom lätta att klippa och klistra och blir där med svåra att underhålla.

    G24: Följ konventioner enligt standard
    Kodkonvention är inte något man skriver på varje företag. Sun har en kodkonvention för java och jag antar att Microsoft har en för C#. Följ dessa. Om ni tar in en konsult så ska de känna igen sig och om du byter arbetsplats ska du inte behöva lusläsa ett dokument för att vara säker på att man gör rätt. Om det finns frågetecken ska den existerande koden i projektet vara grund. Detta förutsätter naturligtvis att alla i projektet är rimligt vuxna och förstår att det igentligen inte spelar någon roll var man sätter krusidullparanteserna så länge alla sätter dem på samma ställe.

    G25: Ersätt magiska nummer med konstanter
    Visst har vi alla funderat på varför en variabel är satt till 1 eller kanske 0 eller -1 eller i värsta fall till 217? Siffran som bara står där mitt i koden utan någon förklaring som något magiskt som alla bara borde förstå. Ersätt dessa magiska konstanter i koden med riktiga konstanter som har fått bra tydliga namn. Detta gäller naturligtvis inte bara för siffror utan även för text.

    onsdag 11 februari 2009

    G16 - G20

    Inte så mycket att säga om... G fortsätter

    G16: Kodat uppsåt
    Kod ska i möjligaste mån beskriva vad det är den gör. Att då skriva saker som m_variabel, eller strNameBtn är inte speciellt mycket till hjälp idag. En gång i tiden var man tvungen att använda förkortningar av olika slag för att man hade ett begränsat antal tecken att använda vid namngivning men idag existerar inte den anledningen. Förr hade man inte en IDE som Netbeans eller Eclipse som kan visa med färger om en variabel är lokal för metoden eller ej (vilket iofs borde vara uppenbart om man inte gjort långa oläsbara metoder). Låt din kod beskriva vad koden försöker att göra. Undvik att använda koden till att gå runt tekniska brister i din utvecklingsmiljö.

    G17: Felaktigt placerat ansvar
    Den här punkten blir kanske lite flummig men det är nog den som är svårast att skriva något konkret om. Vad är det som gör att man placerar en variabel i den ena klassen eller den andra eller kanske till och med skapar en speciell klass för att hålla variabeln? I första hand handlar det om att placera sig in i läsarens position. Att försöka förstå var någon annan skulle förvänta sig att hitta variabeln i fråga. Det man bör försöka att unvika är att bli "smart" och hitta på smarta sätt. Som sagt.. en något flummig punkt men nog så viktig. Läs boken så förstår ni nog förhoppningvis denna bättre än vad jag har gjort. :-)

    G18: Olämpligt användning av static
    Man skulle kunna tro att alla metoder som inte använder någon av klassens lokala variabler skulle vara lämpliga att göra static. Då skulle andra klasser kunna utnyttja den existerande funktionalliteten och man skulle kunna öka återmvinningen av kod. Dessvärre är det inte riktigt så enkelt. Underhåll försvåras av att man inte kan ärva från klassen i fråga för att lägga till funktionallitet. Tester blir svåra att skriva om den statiska metoden i sin tur anropar andra statiska metoder. Faktum är att det ska finnas mycket tydliga skäl till när en metod ska vara statisk.

    G19: Använd förklarande variabler
    Om du ska skriva en metod utför ett flertal operationer är följande kod inte speciellt enkel att förstå.

    public int calculateActualSalary(){
    return getSalary() + addOverTime() - getTaxes()
    }

    Hur mycket påverkade addOverTime()? Vad är det för objekt som har en metod som heter withDrawTaxes()? Det bättre sättet att implementa metoden hade varit genom att visa vad som händer med hjälp av förklande variabler.

    public int caculateActulSalary{
    int salary = getSalary();
    int salaryWithOverTime = salary + addOverTime();
    int salarayWithOverTimeAndTaxesRemoved = withOverTime - getTaxes();
    remove salarayWithOverTimeAndTaxesRemoved;
    }

    Det blir några rader extra med kod men så mycket lättare att förstå vad det är som faktiskt händer. Ni kan säkert komma upp med bättre exempel där det skulle ha underlättat om man kunnat läsa ett tydligt bra namn på en variabel halvvägs in i beräkningen.

    G20: Funktionsnamn ska säga vad de gör
    Betänk följande:

    Date date = Date.today.add(5);

    Vad gör add-metoden ovan? Den lägger till något men vad? 5 sekunder eller 5 år? Låt inte den som ska läsa din kod behöva fundera på vad dina metoder faktiskt gör utan skriv det tydligt i metodnamnet. I exemplet ovan hade det varit bättre att ha kallat metoden för addDays eller addYears eller vad nu metoden ovan faktiskt gör.

    lördag 7 februari 2009

    G11 - G15

    Nästan halvvägs på G.....

    G11: Inkonsekvens
    Att inte överraska de som ska läsa din kod är inte oviktigt någonstans. Därför ska man följa de konventioner som finns (och gudarna ska veta att det är tråkigt att göra ibland). Så trots att denna blogg (eller ännu bättre Bob Martins bok) kan ge idéer om vad som är bra och vad som är mindre bra. Börja inte bara att följa regerna här för det kommer att förvirra de som inte förstår varför man gör på ena eller andra sättet. Det gäller inte bara det jag skrivit här utan rent generellt. Använder ni factories för att skapa alla domänobjekt sluta inte använda dem för att du har ett smarare sätt att göra det på. Det är tyvärr inte alltid så att det är rätt att använda de bästa lösningarna.

    G12: Skräp
    C5, G9 m fl handlar om skräp. Skräp som är i vägen och hindrar dig från att göra ditt jobb. Skräp som du måste lägga tid på helt i onödan. Så jag upprepar vad jag skrivit tidigare. Bort med skiten. Versionhanteringsystemet ska vara tillräkligt bra för att enkelt låta dig titta tillbaka i tiden om skräpet faktiskt skulle visa sig vara något användbart. Men det är versionshanteringsystemet uppgift och inget som ska ligga som kommentarer, död kod eller vilken annan anledning ni kan komma på för att låta skräpet ligga i koden.

    G13: Artificiella kopplingar
    Kod som inte har faktiska beroenden på varandra ska inte vara sammankopplade. Det kan finnas många anledningar till att att man kopplar ihop två klasser fast de egentligen inte har har med varandra att göra. En url till en databas kan vara smidigt att återanvända där den ligger. Problemet är att man ger en klass kunskap om en annan klass en inte har något med att göra, förutom den där lilla konstanten. Det skulle vara bättre att upprätta en separat klass med konstanter som båda klasserna klasserna kan använda. Då har man inte skapat en artificiell koppling mellan de två klasserna som inte har med varandra att göra.

    G14: Funktionsavundsjuka
    Feature envy låter mycket bättre men ska man skriva på svenska så... Metoder i en klass ska i första hand manipulera variabler i den egna klassen. När en metod manipulerar variabler (tex med hjälp av getters och setters) i en annan klass man kan säga att den första klassen önskar att den hade de där bra variablerna som den andra klassen har. Denna regel handlar i första hand om ansvarsfördelning. Varför har en klass just de variabler som den har varför ligger de inte i en annan klass. Det finns naturligvis tillfällen där det är lämpligt att bryta mot denna regel men du bör fundera ett var extra när du ser en klass som verkar avundsjuk på en annan.

    G15: Val genom argument
    Man kan tycka att det är smidigt med en metod som löser flera uppgifter. Dock metoder inte göra mer än en sak och i stället göra det bra och på ett förståligt sätt. Booleska argument är ofta en tydlig signal på att metoden utför flera uppgifter och borde rent generellt brytas isär till två metoder. Det blir lättare att förstå vad det är som händer när man slipper fundera på vad olika inputargument ska ställa till med. Om man behöver en metod för att välja mellan två olika beräkningar så låter man en metod göra valet och andra metoder får stå för själva beräkningen.

    G6 - G10

    Om man nu trodde att det skulle vara nära slutet nu så har man fel... G6 till G10

    G6: Kod i fel abstraktions nivå
    Vi människor är duktiga på att blanda abstraktionsnivåer. Ta tex när vi kör bil så kan de flesta klara av uppgiften att styra bilen med gaspedal, broms och ratt. Dessutom gör vi en uppgift som inte har direkt med att framföra bilen. Vi reglerar varvtalet på motorn med hjälp av växelspaken. Tänk efter nu. Många bilar har automatlåda så varför har vi en växellåda. Att behöva lyssna efter vilket varv motorn har måste rimligtvis vara en distraktion från de uppgifter som rimligtvis måste vara viktigare, som att hålla bilen på vägen. Samma regel gäller när vi skriver klasser och API:er. Vi ska inte förvirra användarna genom att ge dem möjligheter att utföra perifiera uppgifter. Med metoder så ska vi bryta ut privata metoder tex för att hantera loopar och kompilicerade if.

    G7: Klasser beroende av sina arvingar
    Denna regel får inte följas för bokstavstroget. Det finns undantag som vid användandet av Template-method där man faktiskt vill att subklassen ska anropas från basklassen. Men har man inte en riktigt bra motivation som i Template-method-fallet så är det dålig karma att bas-klasserna har beroenden i sina subklasser. Beroendet mellan bas och subklass bör vara enkelriktat.

    G8: För mycket information
    Det är lätt att låta en klass göra allt för att den redan finns och det inte är något extra arbete med att fundera vad man faktiskt vill att klassen ska utföra och ännu viktigare än vad den inte ska utföra. Den generella regel är att desto mindre en klass visar i sitt publika api desto bättre. Desto färre metoder en klass har desto bättre. Desto färre variabler en klass har desto bättre. Kan man hålla klasserna små tenderar de till ha färre beroenden och där med vara lättare att förändra. Splitta klasser som är stora och svåra att hantera till något som är lätt att hantera.

    G9: Död kod
    Precis som med C5. Det som inte används ska inte finnas i den aktiva kodbasen. Punkt slut. If-satser som inte kan inträffa. Metoder som inte anropas. Allt ska bort. Det är distraktionen och programmering är tillräkligt svårt utan att bli distraherad av skräp.

    G10: Vertikalt avstånd
    Denna handlar om hur man ska placera kod i förhållande till annan kod. Grundregeln är enkel. Allt ska vara så nära som möjligt från där det används. Jag upprepar det som står i boken mer eller mindre rakt upp och ner:
    • Lokala variabler ska deklareras raden ovan första användning
    • Privata metoder ska deklareras direkt efter första användning. Målet är att när man läser en metod ska man ha relaterad kod så nära som möjligt. Detta är inte helt enkelt när den privata metoden används av flera andra metoder men man får göra sitt bästa. :-)