Ny IDE-layout

05 maj 2009

Bytte layout på mitt IDE på jobbet. Kom på att automatiska testfönstret platsar bättre nedanför IDEt istället för vid sidan, eftersom felmeddelandena ofta är långa textrader. Känns helmycket bättre redan!

Mitt IDE-upplägg på jobbet

Mitt IDE-upplägg på jobbet

Taggar: ,

Annonser

Död programkod

15 april 2009

Hittade en gammal anteckning från att jag skrivit mitt första större dataprogram i C. Det var ett textspelsäventyr kallat Slasher (Slasher 2 för att vara noggrann – första versionen skrev jag till miniräknaren TI-80, populär på gymnasiet!). Tror programmet var c:a 5000 rader långt, förmodligen mycket längre än det behövde vara (det var också mitt första C-program!), men det intressanta är anteckningen som kommer här:

När man bygger ett program kommer man till sist fram till en punkt då programmet är så stort att det blir oöverskådligt och att lägga till nya funktioner vore ödesdigert för dess ‘överlevnad’. Slasher är det projekt som kommit närmast detta tillstånd och har faktiskt vid ett flertal tillfällen gått igenom genomgående förändringar vilket varje gång kunde resulterat i att programmet ‘dött’.

/Olof, 18 år

Denna nyckelobservation och utmaning har tagit mig mer än tio år att bestiga. Jag fann lösningen i enhetstesterna!

De ”genomgående förändringarna” jag talar om kallas ”large scale refactorings” på fackspråk. Refaktorisering tycker jag låter humbug – jag föredrar det mera svenska ordet förenkling.

Taggar: , , ,


Endagskurs i TDD/C# någon..?

31 december 2008

images4Har via mailinglistor jag är med på fått reda på att det går en webbaserad endagskurs i TDD för C#-utvecklare. Det verkar vara grunderna och lite till: använda enhetstestverktyg, att skriva tester, refactoring, dependency injection.

Låter det intressant? Besök denna adress och skriv upp dig ..

Taggar: , , ,


Varför enhetstesta – anledning 3

26 december 2008

images7Inlägg i denna serie, ”Anledningar att enhetstesta”:

Anledning 1 – Dokumentationseffekten

Anledning 2 – Säkerhetsbälteseffekten

Anledning 3 – Designeffekten


Vi är framme vid anledning 3: renare kod Designeffekten.

Det kan vara svårt att föreställa sig hur stor skillnad det gör på arkitekturen hos ett mjukvarusystem att börja enhetstesta den, eller till och med skriva enhetstester ända ifrån början.

Den huvudsakliga anledningen till att det gör en sådan skillnad är följande:

Det är svårt att testa ”fulkod”.

Tänk på det en stund. Tänk på vad du anser att fulkod är.

Med fulkod menar jag globalt tillstånd (statiska variabler), beroendegalenskap t.ex. ”spindelklasser” (även kända som ”control freaks”) som känner och kontrollerar tjugo andra klasser (rotar kanske t.o.m. i deras interna data, gud förbjude..), kod i användargränssnittsklasser (logik i event handlers t.ex.), kod som är för nära knutet till databas- eller filsystemslagret av systemet, kod som gör logiska beräkningar nära eller i utritningslogik för grafik etc.

Du har säkert en känsla av vad som är ”fulkod” om du programmerat mer än på nybörjarnivå.

Att det är svårt att testa sådan kod kommer du att lära dig om du börjar enhetstesta ett befintligt system som är lite skräpigt. Jag kan avslöja att en anledning är att koden är så beroende av tredjeparts-API:er vilket gör att testkod måste interagera ganska intimt med biblioteket ifråga – något som tyvärr ofta är om inte omöjligt så åtminstone rejält besvärligt.

När du använder dig av Test-Driven Development (TDD) vänder du på steken: du skriver tester innan du skriver kod! Givetvis blir klasser som designas efter denna princip (tester först!) mycket lättare att testa. Då måste du skriva koden mer eller mindre fritt från inblandning av beroenden, eftersom beroenden är så svårtestade. Givetvis måste din kod fortfarande interagera med tredjeparts-APIer men du kommer att behöva skikta systemet och abstrahera bort detaljer som exakt vilket tredjeparts-API ditt program använder sig av.

Men det som är intressant, och samtidigt svårt att förstå, är att testbar kod per automagi blir renare, snyggare och mer ”pattern-inriktad”/”objektorienterad”/”pick-your-fancy-word”-aktig kod! Pröva själv med ett hemmaprojekt. Så får du se!

Tidigare avsnitt i denna serie:

Anledning 1 – Dokumentationseffekten

Anledning 2 – Säkerhetsbälteseffekten

Taggar: , , , , ,


Varför enhetstesta – anledning 2

20 december 2008

images7Inlägg i denna serie, ”Anledningar att enhetstesta”:

Anledning 1 – Dokumentationseffekten

Anledning 2 – Säkerhetsbälteseffekten

Anledning 3 – Designeffekten


Förra veckan skrev jag ”Varför enhetstesta – anledning 1”. Då tog jag upp den dokumenterande effekt enhetstestning har.

Denna vecka tänkte jag diskutera det säkerhetsbältesliknande system man får när man har enhetstester på sina klasser.images2

Har du varit med om följande? En av supportkillarna kommer fram till dig och säger

Det finns en bugg i kommando X. Om man öppnar den här filen, och kör kommandot på det här och det här sättet, kraschar den här dialogen när man klickar på denna knapp”.

Du är fullt uppe i implementationen av en helt annan del av systemet, men eftersom det är en viktig kund och kunden såklart vill ha det här fixat på stört så är det läge att byta uppgift på momangen.

Buggletandet börjar. Du börjar med att reproducera felet, och mycket riktigt kraschar dialogen när du trycker på knappen i given situation. Du börjar skumma dialogkod och rotar dig ned genom klasser och algoritmer med hjälp av debuggern.

Felet ligger i metod M av klass K som kraschar eftersom den försöker anropa en metod på ett objekt som av någon anledning är Null – Null exception krasch boom bang.

Så du ska in och göra ingrepp i en metod du skrev för ett halvår sedan. Du är inte helt på det klara med hur metoden fungerar – inte heller på de klasser som anropar denna klass.

Vi ska nu göra en studie av vad som utspelar sig i en sådan här situation med och utan enhetstest.

Fall 1: Inga enhetstester

images3 Du är inne i ”gammal kod” (legacy code är kod utan enhetstester enligt Michael Feathers – bibel i min hylla – klicka på bilden!) och vill helst städa upp för att förstå vad som egentligen händer (varför objektet är Null i denna metod); metoden som kraschar är ganska lång (>20 rader kod) och några variabelnamn är förvirrande vilket inte underlättar förståelsen. Och av tidigare erfarenhet vet du hur farligt det är att börja ändra om kod som ”nästan fungerar”. Kommandot funkar ju trots allt i de flesta situationer! Det är ju i just den här konstiga situationen buggen uppstår.

Vad göra? Ja helst vill du röra vid så lite kod som möjligt här i ”djungeln”. Du debuggar länge länge för att förstå vem som anropar vem, vilka relationer objekten har till varandra osv. Till sist fattar du att objektet som ger null-exception inte sätts i en klass K3, givet ovanstående situation, och det felet propageras ned ända till K1 och där blir det Null exception. Du lägger på en ytterligare if-sats i K3 för bryta exekveringen av aktuell metod i den situation kunden har hittat, eftersom det är på tok för mycket förändringar av kodstrukturen (och alla de risker för trasering av andra delar av kommandot det innebär!) för att motivera en korrekt buggfix. Nu undviks åtminstone programkraschen.

Istället hittar du ett alternativt sätt att utföra det kunden vill ha gjort, meddelar support hur och ber honom förklara för kunden. Buggen är så att säga ”fixad” – eller egentligen är den inte det. Det är bara för jobbigt och riskabelt att göra aktuell förenkling/generalisering av koden för att lösa det egentliga problemet. Support förstår och accepterar detta – även om han tycker att det varit bättre om ”det bara funkat”.

Fall 2: Du har enhetstester

Denna gång tittar du på kod som har säkerhetsbälte runt omkring sig.

images4Det betyder att om du förändrar koden, t.ex. för att minska längden på en metod, döpa om variabler och metoder hit och dit, stuva om saker och ting så det går att förstå vad som händer, så kan du köra enhetstesterna för att se om du ”pajat” något. För då skulle något eller flera enhetstester ge ”larm”. Klicka på bilden för att se en lista på enhetstestningsverktyg i massa olika programmeringsspråk.

Känner du skillnaden? Nu kan du strukturera om koden så att det går att förstå vad som händer. Ta bort den där konstiga statiska (globala!) variabeln och instansiera klassen på riktigt från dess anropare, helt enkelt därför att det förenklar koden. Visst behöver du kanske ändra ett eller annat test på vägen (en oftast tämligen enkel process då testkod är och bör vara enkel att läsa!) men du har en distinkt annan känsla i arbetsflödet – du känner dig långt mer säker i dina förändringar. När du förändrar saker behöver du knappt analysera på något djupare plan vad förändringen har för effekter, eftersom enhetstesterna kommer säga till om du förstör något!

Men jag ska inte överdriva hur bra detta system fungerar. Allt beror faktiskt på hur bra enhetstesterna är skrivna – om de inte täcker upp hela klasser så är det vanskligt att ändra i någon metod som inte är har enhetstest. Och även metoder som är täckta av enhetstest kan ha udda kodvägar genom logiken som inte testas av något testfall.

Det är egentligen som med säkerhetsbälte och bilarmed säkerhetsbälte på är du inte garanterad att överleva vid en olycka. Men du har bra mycket bättre odds än utan bälte!

images5

Taggar: , , , ,


Kontinuerlig testkörning i Visual Studio

16 december 2008

Häromdagen skrev jag om kontinuerlig testkörning i Python.

Det experimentet fungerade så bra att jag nu utvecklat en liknande lösning i Visual Studio, där jag kodar i C#.

Samma princip, bara det att jag trycker F6 (build solution, som även sparar icke-sparade filer) istället för Ctrl+S som jag gjorde i Python.

Så här ser det ut: Visual Studio autotesting experiment

  • Till vänster Visual Studio.
  • Uppe till höger ett litet dosfönster som kontinuerligt kör NUnit på aktuellt projekt (hårdkodat, jag ändrar bara i python-scriptet som körs när jag byter aktuellt projet).
  • Nere till höger använder jag OpenOffice som ett klotterplank för refactoring/förenklingsidéer och TODO-lista.

När man stängt av bygget av alla projekt som inte är under utveckling just nu mha Configuration manager går bygget hyffsat snabbt, och eftersom enhetstesterna körs i bakgrunden får jag ett nästan lika snabbt utvecklingstempo som i Python. IntelliSense ger ju en positiv inverkan på hastigheten också, men det känns ändå inte lika kvickt som Pythonmiljön.

Taggar: , , ,


Kontinuerlig testkörning i Python

15 december 2008

Satt och lekte med ett ”autotestscript” i helgen. Det är mycket simpelt uppbyggt:

  1. Kör Test.py som innehåller enhetstest för projektet
  2. Vänta i fem sekunder
  3. Upprepa från 1

Jag har ”snott” idén från en kommentar angående utvecklingen av Google Chrome – tydligen kör Google ibland enhetstesterna kontinuerligt i bakgrunden. På så sätt får man ett ”larm” när man bryter mot något enhetstest!

Rent konkret kör jag scriptet, som jag kallar autotests.py, i ett terminalfönster. Invid detta fönster har jag igång två editorfönster jag skriver kod i, dels enhetstesterna, dels projektkoden. Jag har alltså tre filer i projektet som utvecklas:

  • Main.py – själva programkoden
  • Tests.py – enhetstester för Main.py
  • autotest.py – kontinuerlig körning av Tests.py

Känslan hittills är go! Det blir ett mjukt men ändå högt tempo på kodandet. Lägga till ett test, se det larma, lägga till kod för att få testet att gå igenom. Detta utan att behöva kompilera, vänta på bygget + enhetstestkörning. Bara trycka Ctrl+S när jag skrivit nått nytt.

autotest.py ser ut så här:

import os, time
while True:
  for i in range(0,50):
    print ""
  os.system("python Tests.py")
  time.sleep(5)
autotest

Autotest in action

Taggar: , , , ,


%d bloggare gillar detta: