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.