For et par dage siden modtog jeg to forskellige stylus'er, som var blevet bestilt fra dealextreme som et hurtigt impulskøb. Det er første gang, jeg bestiller fra dx.com, så jeg var lidt spændt på om jeg måtte bløde en masse, da pakken blev sendt fra Kina. Det var heldigvis ikke tilfældet, så jeg måtte alt i alt slippe i omegnen af 100kr. for 6 stylus'er.

Jeg valgte at satse på to forskellige modeller for at sprede risikoen lidt, og valgte to, der havde fået relative gode anmeldelser fra andre brugere på dx.com. De to modeller er:

Der er blevet leget lidt med de to modeller i gratis-versionen af GoodNotes, der er én af mange notattagningsprogrammer, der findes til ipad. Da jeg ikke længere er studerende er GoodNotes og stylus'er ikke blevet testet i "rigtige" scenarier, og jeg skal ikke kunne sige, om det er bedre at kaste 20-70kr. efter nogle af de andre apps på markedet. GoodNotes har dog de features jeg umiddelbart kunne forestille mig ville være relevante for mig, blandt andet:

  • Skrivefelt. Når man skriver med en stylus er det svært at skrive lille skrift, da stylus'er som regel har en stor rund og blød ende. Derfor svarer det lidt til at skrive med tavlekridt. Skrivefeltet sørger for, at din store håndskrift nedskaleres til "normal" tekststørrelse på dit "kladdepapir". Se Zoom window nederst på denne side for et eksempel.
  • Import af PDF. Smart hvis man skal kommentere og korrekturlæse på et dokument. Jeg er stadig bedst til at læse korrektur med et stykke papir i hånden og en rød kuglepen i hånden, og på denne måde kan jeg næsten få samme følelse som med papir.
  • Import af billeder. Jeg forestiller mig det kan være anvendeligt i nogle sammenhængen. Det fungerer i hvert fald upåklageligt.
  • Figurtegning. Når denne funktion er slået til vil app'en gøre en streg helt lige, en cirkel rund etc. Det gør det noget lettere at lave pæne figurer, men man skal nok lige vænne sig lidt til funktionaliteten.
  • Farver, stregtykkelse og overstregninger. Disse features må forventes at være minimumsfunktionalitet i sådan en app.

Jeg har ikke noget at udsætte på GoodNotes. Det fungerer rigtigt godt og den eneste begrænsning i den gratis version er et maksimum på 2 noter.

De to stylus'er ligner hinanden i udseende og materialer. De er begge sorte og lavet af plast. Aluminum Alloy er lidt kortere end en normal kuglepen mens den anden er samme størrelse som en normal kuglepen, og indeholder også en rigtig kuglepen (som jeg ikke har afprøvet).

Black Ink Ball Pen har en blød ende mens Aluminum Alloy er lidt mere hård i gummiet, hvorfor man skal presse lidt mere hårdt for at aktivere stulus'en mod glasset på ipad'en. Personligt foretrækker jeg Black Ink Ball Pen da man ikke behøver at presse så hårdt og samtidigt passer størrelsen mig lidt bedre, da den føles som en almindelig kuglepen i hånden.

Priserne taget i betragtning er det bare at bestille nogle stykker hjem - holdbarheden er formodentlig relativ lav og holder næppe til at man får sat sig på dem i sofaen. Til gengæld får man til billige penge en masse ekstra funktionalitet til sin tablet.

Som de fleste ved, så kom Netflix til landet for en måneds tid siden, og da de reklamerer med en gratis måned, er det jo bare at prøve det af Smile

Desværre synes det ikke at være så let at finde de nye emner, der løbende bliver lagt på Netflix, og selvom Microsofts OData eksempler reklamerede rigtigt meget for Netflix' API og OData stream, så er det åbenbart ikke noget, de ønsker at udbygge i takt med Netflix kommer til nye sprogområder. Desværre. Det gør det jo lidt mere bøvlet at lave sin egen "hvad er nyt på Netflix"..

Til gengæld fandt jeg forleden et RSS-feed, som kan anvendes i stedet: https://movies.netflix.com/NewWatchInstantlyRSS

Og på den måde fandt jeg et par DreamWorks kortfilm, der lige skal ses inden testmåneden ophører Wink

The Room fra Fireproof Games er et fængslende og flot spil til iPad 2 eller senere. Spillet tager sin begyndelse med et mystisk skab med hemmelige låger, gåder og knapper. Mens man arbejder sig længere og længere ind i skabet, udfolder der sig samtidig en historie, hvor ikke alt er, som det ser ud.

Spilkoncepten er relativt enkelt; drej, tryk og slide på alle de dimser, man kan komme i nærheden af. De fleste små puzzles kan gennemføres i løbet af få minutter, men da der er læssevis af ting at interaktere med, så er der alligevel nogle timer i spillet. Hvis man går i stå undervejs vil det være muligt at få op til tre hints pr. udfordring, hvilket til tider kan være nødvendigt som casual gamer, hvis man lige skal være sikker på, at det nu er det rigtige hjørne, man har gang i. Det hele er pakket ind i flot 3D grafik og stemningsfuld lyd, og fås netop nu på Halloween tilbud til 13kr., hvilket er alle pengene værd.

Nedenfor følger et par screenshots fra et stykke inde i spillet.

 

CodeMaid er for alle os, der gør en dyd ud af at arrangere sin kode pæn og læsbar. Desværre ved vi jo også af erfaring, at man ikke skal være langt inde i et projekt før der bliver fokuseret mere at skidtet virker og kan leveres til tiden, end at koden kan læses næste gang man har næsen nede i linjerne i en given del af applikationen.

Jeg har længe brugt StyleCop til at forcere ensartet kodestil, men nogle gange er det noget trivielt at flyttet rundt på metoder, slette blanke linjer m.v. for at tilfredsstille StyleCop. Dette er heldigvis én af CodeMaids mange features, og yderligere kan metoder, felter etc. sorteres alfabetisk, så navigationen bliver endnu lettere.

Når man så er i gang med at rydde op i sin kode, så kan man også kaste et blik på den McCabe complexity score, som beregnes. Den siger noget om hvor kompleks en metode er og vil give en god indikation af hvor en refaktorering er nødvendig (eller hvor man skal starte sit code review).

Du finder CodeMaid som Visual Studio Extension her. Selvom den aktuelle version pt. er 0.4.2 så er den stabil og fungerer upåklageligt i VS2010.

Det er fredag, så her er et par party tricks til at vise frem over fredagsøllen :-) De viste tricks er tyvstjålet fra en kollegas præsentation på et internt gå-hjem-møde..

Testdata indenfor en given kategori kan hurtigt genereres således (til ære for ne0san vælger vi banker..)

 

Hold CTRL nede og træk i nedre højre hjørne, og vupti..

 

Skal man have lidt hjælp til oversættelsen kan dette også klares direkte fra regnearket;

 

Jeg er egentlig fint tilfreds med de farver Visual Studio 2008/2010 anvender til syntax farvning, men hvis man er til andre farver kan man jo starte med andres farveschemaer. ScottGu twittede et tip om studiostyles.info, hvor man kan dele schemaer.

Et par af schemaerne mindede mig om mine første programmeringssessioner i folkeskolens edb-lokale, fx det monokrome PDP-11

Eller de klassiske Commodore 64 farver;

Jeg har lidt overvejet en af schemaerne med sort baggrund - de ser jo rigtig kodeagtig cool ud, men bliver man ikke træt i øjnene af at se på en sort skærm?

Allerførst et ønske om en glædelig jul og et godt nytår :-)

 Dernæst et lille tip om at du kan erhverve dig en licens til Linqpad for kun 100kr ($19) frem til 31. december - den kan installeres på op til 3 maskiner samtidigt og er en varig licens til fremtidige versioner.

Hvis du ikke allerede kender Linqpad så er det et glimrende tidspunkt at teste det. Personligt bruger jeg den til mange af de situationer, hvor man liiige laver et lille testprojekt for at teste en stump kode - og ikke mindst til linq queries, entity framework forespørgsler, regex patterns etc.

Tilmeld dig her

 Ja, yderligere introduktion af Scott Guthrie behøves vel ikke, men har du sovet under en sten de sidste mange år, så start med at se dokumentaren om Visual Studio på channel 9. Dokumentaren kan i øvrigt også anbefales selvom du kender både ScottGu og Visual Studio :-)

 Ses vi?

Måske er jeg ved at blive gammel, eller måske er jeg blot kommet til den indsigt, at bliver man længe nok på samme arbejdsplads, så er så godt som alle nye og spændende projekter også ensbetydende med endnu et projekt, der skal vedligeholdes over tid. Selv projekter, der blot skal skydes af en enkelt gang, har en tendens til med jævne mellemrum at dukke frem til en ny omgang. Hvad enten det skyldes det ene eller det andet, så er ord som standardisering, genkendelse, testbar begyndt at fylde mere og mere når nye projekter angribes - der er jo stor sandsynlighed for at jeg selv ender med aben, når min egen kode på sigt skal vedligeholdes :-)

 Jeg har noget tid anvendt StyleCop til at forcere en ensartethed ned over min kode. Ja, det kan være mega-irriterende at være tvunget til at skrive kommentarer og flytte rundt på metoder og properties for at tilfredsstille StyleCop, men i sidste ende bliver koden lettere at læse, når man gør det på samme måde på tværs af projekter. For at komme lidt videre i samme spor købte jeg Robert C. Martins Clean Code: A Handbook of Agile Software Craftsmanship

Mine forventninger til bogen var lidt de samme som da jeg i sin tid tog StyleCop i brug, nemlig at det kan godt være at man ved hvordan det skal gøres, men nogle gange kan det være en fordel at blive mindet om det endnu engang. De forventninger lever bogen til fulde op til, men meget mere synes jeg heller ikke der er at hente, hvis man programmeret i nogle år. Bogen anvender eksempler i Java, men kan sagtens læses med tanke på C# eller VB.Net.

En af de ting, jeg har taget til mig fra bogen finder man allerede i første kapitel. Martins kalder den "The Boy Scout Rule" og går i sin enkelhed ud på, at man skal efterlade sin kode pænere end da man fandt den. Med andre ord; hver gang man er i et hjørne af sin kode, man ikke har været i længe, så brug lige et øjeblik på at gøre koden lidt pænere. På den måde bliver hele projektets kode gradvis bedre med tiden.

Andre udsagn finder jeg knapt så logiske. Eksempelvis argumenterer han under navnekonventioner for, at et interface ikke skal prefixes med stort I. Det distraherer er argumentet, men her vil jeg nok fortsætte med at følge StyleCops regler, der netop påtvinger I som prefix. De fleste regler er dog gode at få genopfrisket, og meget praktisk er disse regler samlet i kapitel 17 - Smells and Heuristics. Langt de fleste, der har programmeret nogle år vil formodentlig kunne nøjes med de 30 sider som dette kapitel udgør, og disse 30 sider kan med fordel skimmes med jævne mellemrum. 

Det virker som om forfatteren har haft lidt svært ved at beslutte sig for hvem bogen skal skrives til. På den ene side genopfriskes helt basal viden som at navnet "modificationTimestamp" er bedre end "modymdhms" (selvom ymdhms afledt af formatet - yy/mm-dd hh:mm:ss). På den anden side forventes en grad af indsigt, når der pludselig introduceres en stump unit test kode ca. 20 sider før kapitlet om unit tests. Ca. 150 sider af bogens 400 sider er to marathon eksempler, hvor bogens regler og refaktoreringsmetoder hældes ned over to rigtige cases. Sider, der i bedste fald blot ender med at blive skimmet - selv hvis man uøvet ud i at vedligeholde kode.

Alt i alt en udmærket, men lidt kedelig bog, til at minde én om at gøre al kode lidt bedre, og ikke blot opfylde kravsspec på kort sigt. Hvis jeg var chef ville jeg tvinge mine medarbejdere til at læse den - jeg tror mange, ville have gavn af en opfrisker. Vi ender på 4 små ninjastjerner pga. value-for-money. Set til kr. 243,-

Det er endelig lykkedes mig at finde et lille projekt, som jeg kan køre strengt efter TDD metodikken, med andre ord testen skrives først. I den forbindelse er der noget mere fokus på access modifiers end når vægten er på integrationstests, men man må jo hænge i og gøre plads til injektere fake objekter efter bogen.

Mens jeg er godt i gang med implementering af validering i et business objekt støder jeg så ind i en "hvorfor-nu-det" situation, som stadig ikke er helt klar for mig. Vi har følgende setup eksempliceret ved det klassiske books eksempel.

I klassen "BookBusinessObject" ønsker vi at teste om en given bog (CurrentBook) findes i en liste af bøger (ListOfBooks). Listen kan fx initialiseres via opslag i en database men for at lette presset lidt på databasen gemmes listen i en statisk liste (books). Den unge dansker skriver sin unit test og får en fin grøn lampe fra NUnit med følgende kode;

    1 using System.Collections.Generic;

    2 using NUnit.Framework;

    3 using Rhino.Mocks;

    4 

    5 public class Book

    6 {

    7     public string Author { get; set; }

    8     public string Title { get; set; }

    9 }

   10 

   11 public class BookBusinessObject

   12 {       

   13     private static List<Book> books;

   14 

   15     public Book CurrentBook { get; set; }

   16 

   17     public virtual List<Book> ListOfBooks()

   18     {

   19         if (books == null)

   20         {

   21             InitializeBooks();

   22         }

   23 

   24         return books;

   25     }

   26 

   27     private static void InitializeBooks()

   28     {

   29         List<Book> bookList = new List<Book>();

   30         bookList.Add(new Book { Title = "Microsoft .NET: The Programming Bible", Author = "O'Brien, Tim" });

   31         bookList.Add(new Book { Title = "XML Developer's Guide", Author = "Gambardella, Matthew" });

   32 

   33         books = bookList;

   34     }

   35 

   36     public bool IsBookInList()

   37     {

   38         foreach (Book b in ListOfBooks())

   39         {

   40             System.Console.WriteLine(b.Title);

   41         }

   42 

   43         return this.ListOfBooks().Contains(this.CurrentBook);

   44     }

   45 }

   46 

   47 [TestFixture]

   48 public class BookBusinessObjectTest

   49 {

   50     [Test]

   51     public void IsBookInList_BookInList_ReturnTrue()

   52     {

   53         // arrange

   54         List<Book> fakeBookList = new List<Book>();

   55         Book fakebook = new Book { Title = "TDD for dummies", Author = "John Doe" };

   56         fakeBookList.Add(fakebook);

   57 

   58         BookBusinessObject businessObjectMock = MockRepository.GenerateStub<BookBusinessObject>();

   59         businessObjectMock.Stub(x => x.ListOfBooks()).Return(fakeBookList);

   60 

   61         businessObjectMock.CurrentBook = fakebook;

   62 

   63         // act

   64         bool included = businessObjectMock.IsBookInList();

   65 

   66         // assert

   67         Assert.IsTrue(included);

   68     }

   69 }

Der hviles et par minutter på laurbærerne inden næste test skrives. Det er ikke nok at vide om en given bog findes i listen, der skal også tilføjes andre valideringsregler så der kan med fordel oprettes en IsValid() metode, der kalder alle business objektets valideringsregler og giver en samlet vurdering af om business objektet er valid.

I unit testen for IsValid() kan det være en fordel at vi i stedet for at lave en fakeBookList blot laver et fake metodekald til IsBookInList() der altid returnerer true. Dermed skal der ikke sættes en masse op for at test IsValid(), hvis vi antager at IsBookInList() blot er én af mange ting, der skal være opfyldt.

Så for at Rhino Mocks kan fake retursvaret fra IsBookInList() ændrer vi accessoren i IsBookInList() fra "public" til "public virtual", men hov!! Det giver problemer, for nu siger NUnit;

TestCase 'BookBusinessObjectTest.IsBookInList_BookInList_ReturnTrue' failed:
  Expected: True
  But was:  False

0 passed, 1 failed, 0 skipped, took 2,64 seconds (NUnit 2.4).

Og det store spørgsmål er; hvorfor nu det?!?

Hjælpelinjerne 38-41 angiver, at fakeBookList ikke bliver injekteret da ListOfBooks() er tom. Ændres accessoren i stedet til "internal virtual" så er testen igen OK. Hvor er det at filmen knækker? Og hvad er best practice?