Å bli en .net ninja krever kontinuerlig utvikling – en evig jakt etter å bli bedre. Her skriver jeg om hvordan jeg gjør det, og håper det kan inspirere, og gi deg tips om hva du kan gjøre for å bli en super utvikler.

Sammenligne kjøretider mellom F# og C#

Thursday, April 11th, 2013
4 kommentarer

Dette er en oppfølger til blogposten Litt F#-kode for å måle kjøretid, hvor jeg blant annet målte tiden på ulike løsninger på Euler1-problemet. Det kom som en stor overraskelse at den rekursive varianten var såpass mye raskere enn å bruke løkker og muterbare variabler.

Spørsmålet jeg da stod igjen med var hvor rask den rekursive F#-varianten var i forhold til en løsning i C# – det har jeg nå undersøkt, og det er disse resultatene jeg skal presentere her. Og mot slutten kommer det en overraskelse!

Et testprogram

Jeg valgte å lage et testprogram i C#. Programmet inneholder tre ulike varianter av Euler1: En som bruker en for-løkke, en som bruker Linq, og en crazy variant som bruker GOTO. I Main-metoden kjører jeg disse tre samt de fire orginale variantene fra F#-bloggposten.

public class Program
{
    public static void CSharpTest1()
    {
        long result = 0;
        for (int i = 0; i < 1000000; i++)
            if (i % 3 == 0 || i % 5 == 0)
                result += i;
        Console.WriteLine("\nResult by for loop (C#): "
            + result);
    }
    public static void CSharpTest2()
    {
        Console.WriteLine("\nResult by Enumerable (C#): "
            + Enumerable.Range(1, 1000000)
                .Where(n => n % 3 == 0 || n % 5 == 0)
                .Select(Convert.ToInt64)
                .Sum());
    }

    public static void CSharpTest3()
    {
        int i = 0;
        long result = 0;
    Loop:
        if (++i > 1000000)
            goto End;
        if (i % 3 == 0 || i % 5 == 0)
            result += i;
        goto Loop;
    End:
        Console.WriteLine("\nResult by goto (C#): "
            + result);
    }

    static void Main(string[] args)
    {
        Benchmark.Measure("C# for loop ",
                          Program.CSharpTest1);
        Benchmark.Measure("C# sequence ",
                          Program.CSharpTest2);
        Benchmark.Measure("C# goto     ",
                          Program.CSharpTest3);
        Benchmark.Measure("F# mutable  ",
                          MyFSharpProject.Program.test1);
        Benchmark.Measure("F# sequence ",
                          MyFSharpProject.Program.test2);
        Benchmark.Measure("F# ref cell ",
                          MyFSharpProject.Program.test3);
        Benchmark.Measure("F# recursion",
                          MyFSharpProject.Program.test4);

        Console.ReadLine();
    }
}

Resultatet

Og nå er du vel spent? Kjøringen av dette testprogrammet gav følgende output, presentert som en graf:

Measurements

Resultatet er nedslående. Det er forsåvidt greit nok – og ikke uventet – at en rekursiv løsning er treigere enn en for-løkke i C#, selv om F# har tail call optimization. Men hvorfor er sekvens-løsningen i F# så veldig mye mere tidkrevende enn sekvens-løsningen i C#?

For sikkerhets skyld forsøkte jeg også å kjøre alle variantene fra en F# executable (man vet jo aldri), men det gav akkurat det samme resultatet.

Og det var da det slo meg: Jeg kompilerer testene mine i DEBUG modus! Kan det hende kjøretiden vil ble bedre i RELEASE? Jeg er ikke vandt til at det har så mye å si i C#, men kanskje det er anderledes i F#?

RELEASE-modus

Så jeg endret prosjektene til å kompilere i RELEASE-modus, og forsøkte C#-testprogrammet på nytt. Ingen merkbar endring!

Ok – hva om jeg tester fra F# igjen da? Og da ble resultatet anderledes!

Measurements2

I RELEASE-modus på F# runtime ble plutselig den rekursive algoritmen nøyaktig like rask som for-løkken i C#. Kompilatoren har altså sansynligvis vært i stand til å transformere rekursjonen til mer eller mindre den samme IL-koden som for-løkken. De andre variantene ble også betydelig raskere, selv om de fortsatt er et stykke fra den optimale løsningen.

Så det er på tide med en Note To Self: Mål alltid performance i RELEASE. Kompileringsmodus har mye å si for optimalisering av F#-kode.

Hackerkultur på NNUG Bergen

Wednesday, January 16th, 2013
Ingen kommentarer

NNUG Bergen starter 2013 med å invitere tre utviklere du kanskje har sett før – Bjørn Einar Bjartnes (skrev om “strømmer” i julekalenderen 2012), Einar W. Høst (skrev om IL-programmering i samme kalenderen) og Jonas Winje. Du så dem kanskje på Norwegian Developers Conference i fjor også?

nnugJan2013

Onsdag 30. januar flyr de over fjellet for å levere et show som vil inneholde litt av hvert. Slik beskriver de hva vi kan vente oss:

Noen ganger kan avstanden mellom drøm og virkelighet som programmerer virke stor. Det er lett å tenke noe i retning av at “bare jeg hadde jobbet i GitHub eller Facebook, eller hengt med Guy Steele i gode, gamle dager… Hadde jeg bare hatt tid og anledning, og de rette folkene rundt meg – da skulle jeg fått ut mitt virkelige potensiale!”

Hvordan bygger man egentlig hackerkultur? Vi vet ikke hvordan andre gjør det, men vi tenkte å snakke om hvordan vi har bygget en liten gjeng, med noe vi selv vil kalle hackerkultur. Vi er ikke studenter med masse fritid, vi må, som alle andre voksne, tjene til livets opphold ved å lage applikasjoner som leverer forretningsverdi. Likevel, det var ikke forretningsverdien, tilbudsskrivingen og faktureringen som egentlig lokket oss til maskinen vi er så dypt fascinert av, og ikke skal vi la forretningsfolk i dress ta den opprinnelige fascinasjonen fra oss!

Om du tenker at dette høres ut som en masse prat og ikke noe innhold: ikke bli bekymret. Dette er ikke en motivasjonstale, vi har kun tenkt å ha dette som en rød tråd i en serie av tekniske presentasjoner. Vi vil komme innom lambda-calculus, IL-hacking, node.js og droner. Det vil bli kode. Neppe kode som bør prodsettes i et miljø nær deg, men kanskje er det noe å lære likevel.

Møtet er som vanlig gratis å delta på for alle medlemmer, og siden medlemskapet også er gratis er jo det ganske greit. Og Pizza og noe å drikke får du også. Så virker dette interessant bør du melde deg på!

Brodwall finner opp hjulet [Luke 20, 2012]

Thursday, December 20th, 2012
10 kommentarer

Johannes Brodwall (@jhannes) har lenge vært et kjent fjes i det smidige utviklermiljøet i Norge. Han er ildsjelen bak Oslo XP Meetup, har vært med å arrangere flere av smidig-konferansene, og holder kurs om smidig utvikling, TDD og arkitektur. Johannes uttaler seg stadig vekk i Computerworld, og har sin egen blogg han kaller Thinking Inside a Bigger Box. Du finner også endel innlegg fra ham på Sterk Blanding.

I dagens bloggpost snakker Johannes om no så rart som viktigheten av å finne opp hjulet på nytt, med et konkret eksempel i C#.

Johannes portrettbilde

Hvem er du?
Flakkende programmerer som var overbevist om at han aldri kunne lære å programmere før han startet på universitetet.

Hva er jobben din?
Chief scientist og code coach i Exilesoft i Norge, Sverige og Sri Lanka.

Hva kan du?
Få nysgjerrige programmerere til å lære nye teknikker for å programmere og for å forstå hva de skal programmere.

Hva liker du best med yrket ditt?
At jeg kan lære meg litt om mange forskjellige problemstillinger som gjennomsyrer samfunnet og at jeg må forene den kompromissløse og kalde verdenen til maskinen med den ubesluttsomme, nyanserte verdenen til mennesker.


Når jeg lærte matte i barneskolen grep jeg etter kalkulatoren. Men min far sa til meg: “Du får ikke bruke kalkulator før du kan klare deg uten”. Jeg syntes naturligvis dette var både urettferdig og upraktisk, men etter en stund fant jeg ut hvilken fordel det har å forstå grunnferdighetene før man griper etter et verktøy.

For mange utviklere dreier det neste kompetansevalget seg om hvilket fancy rammeverk skal man skal lære seg. Eller hvilket programmeringsspråk som ville løse alle våre problemer (med et glimt i øye til fjorårets julekalender her i programmeringsbloggen). Før vi griper etter verktøyene kan det være nyttig å lære seg hvordan de egentlig fungerer. Mitt motto er “jeg vil ikke bruke et rammeverk jeg ikke kunne laget selv”. Det ville naturligvis vært problematisk å lage et like komplett rammeverk som mange av de som er tilgjengelig, men jeg burde i det minste klare å løse alle problemene under normale omstendigheter selv.

Fordelen med å ha gjort det samme som et rammeverk gjør er at da skjønner jeg hvordan denne koden må være implementert. Jeg får en større intuitiv forståelse for hvordan jeg skal bruke rammeverket, jeg skjønner raskerer hva som er problemet når ting ikke fungere og ikke minst: Jeg skjønner når rammeverket gir meg mer problemer enn hjelp.

Et eksempel jeg har likt å bruke mye er å lage en webapplikasjon i Java uten webrammeverk. Jeg bruker gjerne et enkelt eksempel med en adressebok der man kan registrere kontakter og søke etter disse kontaktene. Til ære for C#-utviklere som leser denne bloggen har jeg løst den samme oppgaven i C#: Hvordan ville du laget en webapplikasjon som verken brukte MVC, ASP.NET eller en gang IIS?

Personlig er jeg veldig avhengig av TDD for å tenke. (Jeg har gjort et unntak fra den overnevnte kalkulatorregelen for tester og bruker SimpleBrowser.WebDriver, FluentAssertions og NUnit). For å starte, har jeg skrevet en test som demonstrerer hva webapplikasjonen skal gjøre:

[Test]
public void ShouldFindSavedPerson()
{
    // Start a web server INSIDE THE TEST :-D
    var server = new My.Application.WebServer();
    server.Start();

    var browser = new SimpleBrowser.WebDriver.SimpleBrowserDriver();
    browser.Url = server.BaseUrl;

    // Navigate to the "add contact" page
    browser.FindElement(By.LinkText("Add contact")).Click();

    // Add a new contact
    browser.FindElement(By.Name("fullName")).SendKeys("Darth Vader");
    browser.FindElement(By.Name("address")).SendKeys("Death Star");
    browser.FindElement(By.Name("saveContact")).Submit();

    // Navigate to the "find contact" page
    browser.FindElement(By.LinkText("Find contact")).Click();

    // Execute some queries:
    browser.FindElement(By.Name("nameQuery")).SendKeys("vader");
    browser.FindElement(By.Name("nameQuery")).Submit();
    browser.FindElement(By.CssSelector("#contacts li")).Text
           .Should().Be("Darth Vader (Death Star)");
    browser.FindElement(By.Name("nameQuery")).SendKeys("anakin");
    browser.FindElement(By.Name("nameQuery")).Submit();
    browser.FindElements(By.CssSelector("#contacts li"))
           .Should().BeEmpty();
}

Når jeg kjører denne testen første gang, vil den feile allerede på linjen browser.Url = server.BaseUrl, fordi det er ikke noen faktisk server.

For å implementere WebServer har jeg brukt en liten artig klasse som kommer med .NET: System.Net.HttpListener. Her er den essensielle koden:

class WebServer
{
    public void Start()
    {
        var listener = new System.Net.HttpListener();
        listener.Prefixes.Add(BaseUrl);
        listener.Start();
        new Thread(HttpThread).Start(listener);
    }

    private void HttpThread(object listenerObj)
    {
        HttpListener listener = (HttpListener)listenerObj;
        while (true)
        {
            var context = listener.GetContext();
            using (context.Response)
            {
            }
        }
    }
}

Jeg kjører testen igjen og kommer et skritt videre. Denne gangen får jeg beskjed om at testen ikke finner linken til “Add contact”. Ikke så rart, vi produserer ikke noe HTML! En liten endring i koden over:

var context = listener.GetContext();
using (context.Response)
{
    new AddressBookController().Service(context);
}

Og så må vi bare implementere AddressBookController.Service:

class AddressBookController
{
    internal void Service(HttpListenerContext context)
    {
        var html = "<html>" +
            "<p><a href='/contact/create'>Add contact</a></p>" +
            "<p><a href='/contact/'>Find contact</a></p>" +
            "</html>";
        var buffer = Encoding.UTF8.GetBytes(html);
        context.Response.OutputStream.Write(buffer, 0, buffer.Length);
    }
}

Testen kommer et skritt videre. Vi ser at vi får opp hovedsiden med valgene “Add Contact” og “Find contact”. Når vi klikker på “Add contact” finner vi naturligvis ikke feltet “fullName” fordi vi ikke har laget skjemaet enda. Metoden “HandleGetRequest” sjekker URL’en for å bestemme hvilken side som skal vises:

internal void Service(HttpListenerContext context)
{
    var html = HandleGetRequest(context.Request);
    var buffer = Encoding.UTF8.GetBytes(html);
    context.Response.OutputStream.Write(buffer, 0, buffer.Length);
}

private string HandleGetRequest(HttpListenerRequest request)
{
    if (request.Url.LocalPath == "/contact/create")
    {
        return "<html>" +
            "<form method='post' action='/contact/create'>" +
            "<p><input type='text' name='fullName'/></p>" +
            "<p><input type='text' name='address'/></p>" +
            "<p><input type='submit' name='saveContact' value='Save'/></p>" +
            "</form>" +
            "</html>";
    }
    else
    {
        // som før
    }
}

Vi er nesten ferdig med å registrere kontakter. Nå finner vi ikke linken “Find contact” etter at vi har postet formen. Metoden “Service” må håndtere POST requester med redirect:

internal void Service(HttpListenerContext context)
{
    if (context.Request.HttpMethod == "GET")
    {
        var html = HandleGetRequest(context.Request);
        var buffer = Encoding.UTF8.GetBytes(html);
        context.Response.OutputStream.Write(buffer, 0, buffer.Length);
    }
    else
    {
        context.Response.Redirect(context.Request.Url.GetLeftPart(UriPartial.Authority));
    }
}

Nå mangler skjema for å søke etter personer. Her hjelper copy-paste pattern oss:

private string HandleGetRequest(HttpListenerRequest request)
{
    if (request.Url.LocalPath == "/contact/create") ...
    else if (request.Url.LocalPath == "/contact/")
    {
        return "<html>" +
            "<form method='get' action='/contact/'>" +
            "<p><input type='text' name='nameQuery'/></p>" +
            "<p><input type='submit' value='Find'/></p>" +
            "</form>" +
            "</html>";
    }
    else ...
}

Feilen nå er åpenbar: Vi har ikke med svaret med kontakter:

    class Contact
    {
        public string FullName { get; set; }
        public string Address { get; set; }
    }

    private static List<Contact> contacts = new List<Contact>();

    private string HandleGetRequest(HttpListenerRequest request)
    {
        else if (request.Url.LocalPath == "/contact/")
        {
            var contactsHtml = string.Join("",
                contacts.Select(c => "<li>" + c.FullName + " (" + c.Address + ")</li>")))
            return string.Format("<html>" + ...
                "<ul id='contacts'>{0}</ul>" +
                "</html>", contactsHtml);

        }

Så gjenstår det bare å ta vare på kontaktene når vi gjør en POST fra “Add contact” skjemaet:

internal void Service(HttpListenerContext context)
{
    if (context.Request.HttpMethod == "GET") ...
    else
    {
        // Read the parameters from the POST body (Request.InputStream)
        var request = context.Request;
        var encoding = context.Request.ContentEncoding;
        var reader = new StreamReader(context.Request.InputStream, encoding);
        var parameters = HttpUtility.ParseQueryString(reader.ReadToEnd(), encoding);

        context.Response.Redirect(HandlePostRequest(request, parameters));
    }
}

private string HandlePostRequest(HttpListenerRequest request, NameValueCollection parameters)
{
    contacts.Add(new Contact() { FullName = parameters["fullName"], Address = parameters["address"] });
    return request.Url.GetLeftPart(UriPartial.Authority);
}

En siste test feiler: Vi filterer ikke kontaktene basert på søket.

private string HandleGetRequest(HttpListenerRequest request)
{
    if (request.Url.LocalPath == "/contact/create") ...
    else if (request.Url.LocalPath == "/contact/")
    {
        var query = request.QueryString["nameQuery"];
        var contactsHtml = string.Join("",
            contacts
                .Where(c => query == null || c.FullName.ToLower().Contains(query.ToLower()))
                .Select(c => "<li>" + c.FullName + " (" + c.Address + ")</li>"));
        return string.Format("<html>" +
                ...
                "<ul id='contacts'>{0}</ul>" +
                "</html>", contactsHtml);
    }
    else ...
}

Nå gjenstår det bare å lagre personene til en ordentlig database og å rette den åpenbare sikkerhetssårbarheten ved vising av kontaktene. AddressBookWebServer bør også få en Main metode, slik at du faktisk kan kjøre koden. Men det overlater jeg til deg, kjære leser.

Og nå kommer vi til moralen

I denne artikkelen har du lært hvordan HTTP egentlig fungerer og hvordan rammeverk som ASP.NET MVC fungerer bak kulissene. Det er mange detaljer vi er glade for å slippe å håndtere, slik som konvertering mellom tegnsett og lesing av innholdet i en POST request. Og det er mange ting som slett ikke er så vanskelig, som for eksempel å gjøre ordentlig “redirect-on-post”. Jeg har på mer enn ett prosjekt innsett at etter at jeg hadde gjort et par dagers investering for å forstå den underleggende teknologien klarte jeg å levere prosjektet bedre uten de åpenbare, populære rammeverkene som alle anbefaler at man skal bruke.

Har jeg funnet opp hjulet på nytt her? Det er mulig å argumentere for det, men jeg ønsker å strekke “finne opp hjulet på nytt” metaforen så langt som den lar seg strekke:

Min erfaring er at det er mange “biler” i dag som har skjeive hjul der akslingen ikke er i midten. Det kan være at hjulet er dårlig eller det kan være at hjulet bare er montert feil. Så merker vi kanskje at bilen humper fordi vi har to hjul som begge har akslingen montert feil. Og så bruker vi masse innsats på å få justert disse to hjulene slik at de humper i takt.

Dersom vi har erfaring med i det minste å lage et “hjul” eller to, kan det hende vi klarer å identifisere de egentlige problemene med de “hjulene” som vi blir gitt, slik at vi kan finne ut hvilke “hjul” som er bra og hvilke som er dårlige, og ikke minst: Hvordan å bruke dem riktig.

Finn opp på nytt de hjulene du ikke forstår, ikke bruk et rammeverk du ikke kunne laget selv og ikke bruk en kalkulator før du forstår matematikken.

God (h)jul!

Einar bedriver svartekunst [Luke 3, 2012]

Monday, December 3rd, 2012
4 kommentarer

Einar W. Høst (@einarwh) er en hyggelig utvikler jeg møtte første gang på ROOTS-konferansen i Bergen. Han var også en av tre helsprø Computas-utviklere som blant annet holdt på å skade en stakkars publikummer på en av NDC 2012′s mest underholdende forelesninger. Jeg visste jeg ville få et solid og spennende bidrag da jeg spurte Einar om han ville bidra til julekalenderen i år.

einarwh-600x600

Hvem er du?
Eventyrlysten akademiker som utforsker den praktiske utviklerverdenen.

Hva er jobben din?
Overingeniør og leder for Software Engineering-fagnettverket i Computas.

Hva kan du?
Programmering som håndverk og vitenskap.

Hva liker du best med yrket ditt?
Oscilleringen mellom å føle seg som en idiot og et geni.

Her følger Einars post om IL-manipulering…


IL Tempo Gigante

Lurer du på hvor lang tid de ulike enhetstestene dine bruker på å kjøre? Ikke? Vel, la oss i så fall late som om du gjør det. Vi kan til og med tenke oss at du bruker et enhetstestrammeverk til å kjøre integrasjonstestene dine, og da begynner det jo faktisk å bli litt interessant å vite hvor lang tid ting tar. La gå at integrasjonstester ikke er ytelsestester, men vi kan jo bruke dem som det likevel.

Så hvis vi antar at det er interessant å få vite hvor lang tid testene bruker på å kjøre, hvordan kan vi gjøre det på en enkel og ikke-invaderende måte? I denne bloggposten skal vi gjøre det fullstendig ortogonalt og i det skjulte – vi skal faktisk ikke røre koden i det hele tatt. Det vil si, det skal vi så klart – men ikke kildekoden. I stedet skal vi bruke bytekodemanipulasjon for å trylle litt. Bytekodemanipulasjon vil si at vi gjør ting på IL-nivå, etter at testene er kompilert.

Alle .NET-programmerere vet at C# og VB.NET kompileres til IL, som videre kompileres til maskinkode ved behov, såkalt JIT-kompilering. Sånn sett er IL er det egentlige .NET-språket! Likevel er det få som noensinne kikker på IL-koden, og enda færre som finner på å endre på den. Men det er synd, for det er både enkelt og nyttig (for eksempel når man ønsker å gjøre akkurat det samme ørten forskjellige steder i koden uten å skitne til kildekoden med masse repetisjon). Og nå som C# går en usikker fremtid i møte, er det en glimrende anledning til å lære seg litt IL. Jeg vet ikke med deg, men jeg skriver heller IL for hånd enn å gå over til VB.NET!

IL er ikke vanskelig, men det er naturligvis annerledes enn C#. Det første man må venne seg til er at det er et stack-basert språk. En stack er det vi på godt norsk kaller en stabel. Det er to ting man kan gjøre med en stabel: legge en ny ting på toppen, eller ta av den øverste tingen som allerede er der. (Man kan forsåvidt også i mange tilfeller studere den øverste tingen uten å fjerne den.) Yrkesskadd som jeg er, har jeg det med å tenke “stack” hver gang jeg kommer inn i kantinen og får se stablene med tallerkner. Jeg tenker sågar “throw new StackEmptyException()” dersom en av stablene er tomme, men det er ikke min skyld – det skjer helt av seg selv!

Uansett, IL definerer et sett med bytekodeinstruksjoner som gjør ting med stacken. Generelt sett vil en bytekodeinstruksjon “poppe” y elementer fra stacken, gjøre noe med dem, og “pushe” y elementer tilbake på stacken. Et eksempel er add-instruksjonen som “popper” to verdier fra stacken, legger dem sammen, og “pusher” resultatet tilbake på stacken. Sånn sett fungerer stack-baserte språk ved at man gjør ting i postfix rekkefølge, det vil si at operasjonen kommer etter verdiene det skal opereres på. Det er verdt å merke seg at IL ikke er det eneste stack-baserte språket i verden. Det finnes, hva skal vi si… sluttbrukerorienterte språk som f.eks. Forth og Factor som fungerer på tilsvarende måte.

Når man skal starte et bytekodemanipuleringsprosjekt er det viktig å ha to kodeeksempler i C# tilgjengelig. For det første må man naturligvis ha et utgangspunkt: et enkelt, minimalistisk eksempel på opprinnelige, urørte koden. For det andre må man ha et målbilde: koden slik den ville sett ut dersom vi gjort endringene vi ønsker for hånd – altså uten bytekodemanipulering, bare ved å endre på C#-koden.

I vårt tilfelle er utgangspunktet en meget enkel enhetstest. Her bruker jeg MSTest, men det er naturligvis enkelt å gjøre tilsvarende ting for NUnit eller andre rammeverk. Som du ser har vi en veldig enkel test-klasse med to enhetstester. Det eneste de gjør er å sove.

[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        Thread.Sleep(4300);
    }

    [TestMethod]
    public void TestMethod2()
    {
        Thread.Sleep(2400);
    }
}

Hvordan skal så målbildet vårt se ut? Vel, vi trenger jo å ta tiden. Til det trenger vi en stoppeklokke. Vi må starte stoppeklokken før enhetstesten kjører, og stoppe den etter at testen har kjørt. Vi kunne brukt stoppeklokke direkte i test-metoden, men jeg tror vi heller bruker test-rammeverkets støtte for setup- og teardown-metoder. I MSTest heter det henholdsvis TestInitialize- og TestCleanup-metoder. Vi må altså legge til to metoder og annotere dem med hvert sitt custom attribute. Siden begge disse metodene må ha tilgang til samme stoppeklokke, trenger vi også et felt for selve klokken. Når testen er ferdig må vi på en eller annen måte rapportere hvor lang tid testen brukte på å kjøre. For enkelhets skyld kommer vi bare til å skrive til Trace.

Og så en litt subtil ting: vi må vite navnet på testen vi kjører! Det blir vi nesten nødt til å fange opp mens selve test-metoden kjører og lagre i et felt, slik at vi får det med når vi rapporterer. Men hvordan gjør man egentlig det? Vi er faktisk nødt til å ta i bruk en liten knivsodd reflection. Slik kan det se ut:

[TestClass]
public class UnitTest1
{
    private Stopwatch _stopwatch;
    private string _method;

    [TestInitialize]
    public void StartSecretUnitTestPerformanceTimer()
    {
        _stopwatch = new Stopwatch();
        _stopwatch.Start();
    }

    [TestCleanup]
    public void StopSecretUnitTestPerformanceTimer()
    {
        _stopwatch.Stop();
        var msg = string.Format("{0}.{1}: {2} ms.",
            GetType().FullName, _method, _stopwatch.ElapsedMilliseconds);
        Trace.WriteLine(msg);
    }

    [TestMethod]
    public void TestMethod1()
    {
        _method = new StackFrame().GetMethod().Name;
        Thread.Sleep(4300);
    }

    [TestMethod]
    public void TestMethod2()
    {
        _method = new StackFrame().GetMethod().Name;
        Thread.Sleep(2400);
    }
}

Så: hvordan går vi nå fram for å transformere det første kodeeksemplet til det andre? (Merk at vi egentlig ikke skal gjøre en C#-til-C#-transformasjon, men en IL-til-IL-transformasjon. Dvs. vi skal ta IL-koden vi får når vi kompilerer det første eksemplet og transformere den til å bli lik IL-koden vi får når vi kompilerer det andre eksemplet. Ingen tukling på C#-nivå.)

For å få til alt dette trenger vi verktøy. Det første verktøyet heter ILSpy, og brukes til å dekompilere .NET-assemblies. Tidligere brukte jeg Lutz Roeders .NET Reflector, men det begynte jo plutselig å koste penger. ILSpy er gratis og fungerer helt fint. Det kan dekompilere både til “disassembled” IL (IL i tekstformat) og til C#. I første omgang er vi mest interessert i tekstlig IL. Ved å studere IL’en som blir generert når de to kodeeksemplene blir kompilert kan vi finne ulikhetene som vi må kompensere for når vi gjør bytekodemanipulasjonen. Senere kan vi dekompilere vår bytekodemanipulerte assembly til C# for å verifisere at vi virkelig har laget kode som er helt lik originalen.

.method public hidebysig
	instance void StartSecretUnitTestPerformanceTimer () cil managed
{
	.custom instance void [Microsoft.VisualStudio.QualityTools.UnitTestFramework]Microsoft.VisualStudio.TestTools.UnitTesting.TestInitializeAttribute::.ctor() = (
		01 00 00 00
	)
	// Method begins at RVA 0x20a0
	// Code size 23 (0x17)
	.maxstack 2

	IL_0000: ldarg.0
	IL_0001: newobj instance void [System]System.Diagnostics.Stopwatch::.ctor()
	IL_0006: stfld class [System]System.Diagnostics.Stopwatch Insoluble.Test.UnitTest1::_secretStopwatchField
	IL_000b: ldarg.0
	IL_000c: ldfld class [System]System.Diagnostics.Stopwatch Insoluble.Test.UnitTest1::_secretStopwatchField
	IL_0011: callvirt instance void [System]System.Diagnostics.Stopwatch::Start()
	IL_0016: ret
} // end of method UnitTest1::StartSecretUnitTestPerformanceTimer

Kodeeksemplet viser den ene av metodene vi må lage: TestInitialize-metoden. Jeg har kalt den StartSecretUnitTestPerformanceTimer, bare for at det skal være usannsynlig at testen allerede har en annen metode med det samme navnet.

Hvis dette er første gang du ser IL: ikke få panikk! Dette er egentlig ganske enkle saker. Det burde være mulig å kjenne igjen metodesignaturen fra det andre kodeeksemplet. (Ikke bry deg om hidebysig, det er en teknisk detalj som ikke har noen betydning for oss.) Den tingen som begynner med .custom er TestInitialize-attributtet. Dybden på stacken er angitt av .maxstack; heller ikke det er spesielt skummelt. Det betyr bare at vi ber .NET om å la oss ha inntil to ting i stabelen vår. Og så kommer det morsomme: selve bytekodeinstruksjonene. Det at det står IL0000 og sånn er bare merkelapper, og ikke spesielt interessant i dette tilfellet. De er mest interessante når man skal lage forgreninger i koden, med andre ord if-setninger og løkker. Vi skal ikke gjøre noe så fancy.

Selve IL-koden er egentlig ganske grei å lese, så lenge man husker på at vi primært bruker stacken snarere enn lokale variable til å holde på verdier. Instruksjonen ldarg.0 betyr at vi “pusher” en referanse til “this” på stacken, altså testklasseinstansen. Videre kaller vi konstruktøren til Stopwatch-typen med newobj-instruksjonen. Da har vi både “this” og en referanse til en Stopwatch-instans på stacken. Når vi så kaller stfld med navnet på et felt, lagrer vi Stopwatch-referansen i feltet. Denne operasjonen “popper” begge verdiene vi hadde på stacken. Deretter “pusher” vi “this” på stacken igjen, leser feltet vi nettopp skrev til med ldfld, og kaller en metode på Stopwatch-instansen med callvirt-instruksjonen. Til slutt gjør vi en eksplitt retur fra metoden med ret.

Ikke spesielt vanskelig, altså. Men hvordan i all verden går man fram for å dytte all denne koden inn i DLL’en vi fikk da vi kompilerte det første eksemplet? Det ville vært en uoverstigelig kjip oppgave om det ikke hadde vært for to supre verktøy. Det viktigste av dem heter Mono.Cecil og er skrevet av en fyr som heter Jb Evain. Mono.Cecil gir deg et API for å manipulere .NET-assemblies. Det andre verktøyet er mer valgfritt, men gjør det enklere å bruke Mono.Cecil integrert i Visual Studio. Det heter Fody, og tilbyr en addin-modell for å gjøre bytekodemanipulasjon med Mono.Cecil enklere. Fody sørger for at bytekodemanipulasjonen din blir kjørt når Visual Studio bygger prosjektet ditt, at Visual Studio ikke låser assembly-filen m.m. Tro meg, alt blir så mye lettere! Når man bruker Fody, følger man en konvensjon der man lager en ModuleWeaver-klasse med bestemte properties og en metode som heter Execute. Fody tar ansvar for å gi inn verdier til propertiene og å kalle Execute.

public class ModuleWeaver
{
    private const string TestClassAttribute = "TestClassAttribute";

    public ModuleDefinition ModuleDefinition { get; set; }

    public IAssemblyResolver AssemblyResolver { get; set; }

    public void Execute()
    {
        var typeFinder = new TypeFinder(AssemblyResolver, ModuleDefinition);

        var testTypeDefs =
            ModuleDefinition.GetTypes().Where(
                t => t.CustomAttributes.Any(
                    a => a.AttributeType.Name == TestClassAttribute));

        foreach (var typeDef in testTypeDefs)
        {
            new TypeWeaver(typeDef, typeFinder).Execute();
        }
    }
}

Her ser du min ModuleWeaver-klasse. Den gjør ikke så mye, egentlig. Det eneste som skjer, er at jeg plukker ut alle klasser som er annotert med TestClass-attributtet, og itererer over dem. Den virkelige jobben håndteres av en klasse jeg har kalt TypeWeaver. Den bruker også hjelpeklassen TypeFinder for å lette oppslag av typereferanser når vi skal ta i bruk Mono.Cecil litt mer på ordentlig.

TypeWeaver-klassen er stedet hvor IL-manipulasjonen finner sted. Etter mønster fra ModuleWeaver-klassen har den sin egen Execute-metode.

public void Execute()
{
    AddStopWatchField();
    AddTestNameField();
    AddStartStopwatchSetupMethod();
    AddStopStopwatchTeardownMethod();

    foreach (var methodDef in _typeDef.Methods.Where(
                 m => m.CustomAttributes.Any(
                     a => a.AttributeType.Name == TestMethodAttribute)))
    {
        InjectCodeToStoreTestName(methodDef);
    }
}

Som du kan se gjør vi her de ulike tingene vi fant ut at vi måtte gjøre da vi definerte målbildet vårt. Det blir litt i overkant å gjennomgå all koden i detalj, men la oss se på hvordan vi lager TestInitialize-metoden som vi så på tidligere.

private MethodDefinition CreateStartStopwatchSetupMethod()
{
    var methodDef = new MethodDefinition(
        StartTimingMethodName,
        MethodAttributes.Public | MethodAttributes.HideBySig,
        _types.Void)
    {
        Body = { MaxStackSize = 8, InitLocals = true }
    };

    var initMethodRef = new MethodReference(".ctor", _types.Void, TestInitializeAttributeTypeRef)
    {
        HasThis = true
    };
    methodDef.CustomAttributes.Add(new CustomAttribute(initMethodRef));

    var il = methodDef.Body.GetILProcessor();
    Action<opcode> op = x => il.Append(il.Create(x));
    Action<opcode   , fieldreference> fop = (x, f) => il.Append(il.Create(x, f));
    Action<opcode   , methodreference> mop = (x, m) => il.Append(il.Create(x, m));

    // Push 'this' reference onto stack.
    op(OpCodes.Ldarg_0);

    // Create StopWatch object and push onto stack.
    mop(OpCodes.Newobj, new MethodReference(".ctor", _types.Void, StopWatchTypeRef)
    {
        HasThis = true
    });

    // Store reference to StopWatch object in field.
    fop(OpCodes.Stfld, _stopWatchFieldRef);

    // Push 'this' reference onto stack.
    op(OpCodes.Ldarg_0);

    // Load reference to StopWatch object from field.
    fop(OpCodes.Ldfld, _stopWatchFieldRef);

    // Invoke Start method on StopWatch.
    mop(OpCodes.Callvirt, new MethodReference("Start", _types.Void, StopWatchTypeRef)
    {
        HasThis = true
    });

    // Return from method.
    op(OpCodes.Ret);

    return methodDef;
}

Jeg starter med å lage en MethodDefinition-instans, med signatur som matcher den vi så i den dekompilerte IL-koden. Deretter legger vi til annoteringen med TestInitialize, slik at MSTest vil kjøre metoden vår før testen blir kjørt. For å legge til bytekodeinstruksjoner til metodekroppen, bruker vi noe som kalles en ILProcessor. Jeg synes det er litt mye støy for å opprette og legge til instruksjonene, så jeg lager meg en håndfull actions for å gjøre det litt mer kortfattet. Deretter legger jeg bare til de bytekodeinstruksjonene en etter en: legge “this” på stacken, opprette Stopwatch-instans, skrive til felt, legge “this” på stacken igjen, lese fra felt, kalle Start-metoden, ferdig. Man må naturligvis gjøre seg litt kjent med API’et til Mono.Cecil for å få det til, men det er ikke spesielt vanskelig.

Resten av koden er egentlig ganske lik. Bytekodemanipulering er ikke vanskelig når man først har blitt kjent med verktøyene, og åpner opp for en del unike muligheter og løsninger som er vanskelig å få til på andre måter. Dessuten får man den berusende følelsen av å drive med svartekunst, mens man egentlig gjør ganske enkle ting. Dersom du vil se et litt mer ambisiøst eksempel på bytekodemanipulering kan du ta en titt på Silver.Needle, et prosjekt jeg har laget for å lette livet til Silverlight-utviklere som blir sprø av å implementere INotifyPropertyChanged.

Men ja! Funket egentlig dette her? Du får nesten laste ned kildekoden fra https://bitbucket.org/einarwh/tempo og prøve! Innimellom litt øvrig støy i Output-vinduet i Visual Studio dukket følgende linjer opp hos meg:

Tempo.Test.UnitTest1.TestMethod1: 4298 ms
Tempo.Test.UnitTest1.TestMethod2: 2401 ms

Godt nok for meg!


Om du synes dette var spennende så finer du mer av samme kaliber på Einars posterous-blogg. Og følg med i morgen for en ny luke!

Nyttårsforsetter for 2012

Sunday, January 1st, 2012
5 kommentarer

Da har vi feiret nyttår, og på denne tiden tenker jeg alltid mye på hvordan det nye året vil bli og hva jeg ønsker å gjøre anderledes. Jeg er vel ikke alene om det. Her skal jeg forsøke å samle tankene, og skrive ned noen forsetter – forhåpentligvis i form av konkrete mål. Ting som over tid skal gjøre meg til en bedre, sterkere og raskere utvikler. Fellesnevneren for mye av det er fokus.

skann0001

Mindre random, planløs surfing

Alt for ofte flipper jeg opp laptopen uten å vite hva jeg skal. Jeg surfer på måfå, er innom diverse forum, sjekker infoq og andre relevante aggregator-sites, facebook, twitter, og mail – uten egentlig å oppnå så veldig mye. Dette er sløs med tid! Hvis jeg er opplagt bør jeg i stedet programmere, eller lese noe jeg allerede har planlagt å lese. Er jeg på jobb bør jeg jobbe. Er jeg ikke opplagt bør jeg ikke åpne laptopen i det hele tatt.

Jeg skal ikke slutte helt med sosiale medier eller å hjelpe folk på forumene, men jeg bør begrense det kraftig – det har tatt litt overhånd.

For å få til dette bør jeg nok lage meg en plan for hvor ofte og når jeg faktisk får lov til å sjekke disse tingene. Jeg har ikke kommer opp med noe konkret her enda, men det skal jeg!

Høyere fokus på jobb

Jeg lar meg lett distrahere. Oppdager jeg noe nytt og spennende, eller får en tanke om noe som hadde vært greit å teste ut, så er det ofte vanskelig å konsentere seg om det jeg burde gjøre. Møter og email-kommunikasjon er også forstyrrende, og totalt sett gjør dette at jeg i perioder ikke er særlig produktiv.

Jeg må lære meg å administrere min egen tid og mitt fokus bedre. Pomodoro var en teknikk som hjalp noe. Men jeg trenger mer. Jeg ser for meg at jeg må strukturere arbeidsdagen – sette av tidsbokser for epost, forberedelse til møter, oppfølging av teamet og lignende. Jeg må passe på at jeg ikke må context-switche for ofte, for det er krevende for dem som driver med programmering.

Lese

Jeg har alltid vært flink til å lese, men i høst har jeg lest for lite – og som jeg sa i denne blogposten skyldes det blant annet at jeg har sluttet å reise kollektivt. Planen nå er derfor å sette av én time hver kveld til lesing. Det gjør ikke noe om jeg ikke får lest hver eneste dag, men regelen skal være at jeg leser om det ikke er noe annet jeg skal gjøre.

Fysisk trening

Vi har et fantastisk treningstilbud på jobben som jeg ikke har vært flink nok til å benytte meg av. Trening er noe jeg gjør i perioder – ofte holder jeg på i tre, fire måneder, for så å “glemme det” i en minst like lange periode. God fysisk form er viktig for å kunne holde på konsentrasjonen og for å få utslipp for stress. Dette må jeg bli bedre på.

Mestre tastataturet

Jeg har en gjennomført (eller fastgrodd) tastaturteknikk som fungerer greit nok. Jeg skriver nå opp mot 46 WPM når jeg fokuserer maksimalt (målt på typingtest.com). Men jeg skriver med få fingre, og ser mye på tastaturet.

Skrivehastighet og teknikk er viktig for å komme i god flow. Jeg ønsker derfor å lære meg og øve inn touch. Hvis jeg fokuserer på dette en halvtime hver dag i noen uker bør jeg kunne komme langt. Dette vil kunne hjelpe meg å holde bedre fokus og la tankene flyte bedre mens jeg programmerer (eller mens jeg blogger for den saks skyld).

Øve, øve, øve

Jeg er ganske flink til å trene på mine programmeringsferdigheter, og det må jeg selvsagt fortsette med. I år vil jeg forsøke å fokusere litt mer på metaprogrammering, gjerne i Lisp.

Jeg vil også forsøke å øke størrelsen litt på oppgavene jeg gir meg selv, sånn at jeg får økt sjanse til å eksperimentere med ulike design-teknikker. Jeg implementerer mye algoritmer, ting som løses på 20 til 60 linjer kode, men trenger mer trening på større ting – kanskje spesielt innenfor funksjonell programmering.

En siste ting jeg gjerne vil eksperimentere mer med er arkitekturer for å gjøre systemer “scriptbare”. Embedding av Ruby, JavaScript eller lignende runtime i applikasjoner eller tjenester. Jeg har gjort litt av dette, men vil at det skal bli en helt naturlig del av verktøybeltet mitt, slik at jeg bare kan smyge det inn når behovet dukker opp.

Et større hobby-prosjekt?

Et par ganger i året bruker jeg å starte på et eller annet større prosjekt som jeg håper kan bli noe fornuftig, men som jeg likevel vet er en stør sjanse for at ikke blir noe av. Programmeringsspråket MIST er et bra eksempel fra 2011 – det var et par interessante måneder mens jeg holdt på, men jeg ser ikke for meg at jeg kommer til å fullføre planene mine nå.

Det skremmer meg likevel ikke fra å prøve igjen. Jeg har en idé til et større prosjekt nå også, noe som kan bli ganske så gøy for mange om jeg får det til. Jeg sier ikke mer enda.., vil holde kortene litt tett til brystet en stund til. Kanskje trenger jeg noen av dere som beta-testere utpå våren eller sommeren engang. Vi får se!

Konklusjon

Som vanlig har jeg mange planer og ideer om hvordan året skal bli. Jeg har noen konkrete ting jeg skal jobbe med, og spesielt skal jeg bli flinkere til å holde fokus.

Når det kommer til bloggingen så tenker jeg bare å fortsette som før – blogge når det dukker opp noe som jeg får lyst til å dele. Jeg vil gjerne lage flere videoer, for det har vært gøy. Men det er også tidskrevende, og jeg vil ikke prioritere det fremfor det andre tingene.

Nå gjelder det bare å huske på dette her. Da er det bra jeg har denne bloggposten å komme tilbake til :)

Godt Nytt År alle sammen!!!

Nemerle

Friday, December 9th, 2011
9 kommentarer

Nå skal du få møte det jeg oppfatter som det aller mest spennende språket på .NET-plattformen for tiden. Nemerle er som en krysning mellom C# og F#, med Lisp-lignende makro-støtte som en ekstra bonus. Her har du et veldig kraftig verktøy hvor du kan programmere imperative-, objektorienterte- og funksjons-baserte løsninger proppfulle av meta-features. Eller som hjemmesiden sier, et <<Programming language for “special forces” of developers>>.

nemerle

Versjon 1.0.0 ble lansert i mai i år, men arbeidet med språket startet så langt tilbake som i 2003. Programmeringsspråk skapes ofte av én person, enten som noe han gjør privat eller med backing av et firma som f.eks. tidligere Sun eller Microsoft. Andre ganger står det en kommité bak, men det resulterer sjelden i noe bra. Nemerle derimot er skapt av en gruppe utviklere ved University of Wroclaw i Polen, og deres innsats er imponerende.

(At flagget på roboten ble russisk var en glipp.., sorry! Det skulle selvsagt vært det polske.)

Nemerle er sterkt typet, og har kraftig type inference. Utviklere med bakgrunn fra språk som Java eller C# vil kunne kjenne seg igjen, men språket har også mange egenskaper hentet fra funksjonell programmering som tail call optimization, pattern matching, algebraiske datatyper, partial application, tupler osv.

Du finner også såkalte Computation expressions, som så langt jeg har forstått er det samme som monader.

Videre støtter Nemerle streng-interpolering, noe som ikke er vanlig i statisk typede språk. Det har støtte for LINQ, og du kan benytte deg av aspect-oriented programming (AOP). Dessuten har det XML literals, noe du også finner i språk som Scala og Visual Basic .NET.

Generelt sett er språket proppfullt av features, og det virker som om de er satt sammen på en meget behagelig måte. For å vise at Nemerle er et allsidig språk har jeg laget fire løsninger på Euler-oppgaven

En imperativ løsning

La oss først se hvordan et Nemerle-program ser ut, og om vi kan gjøre “vanlig”, imperativ programmering i dette språket.

Nemerle-program består av klasser og/eller moduler (moduler er som statiske klasser). Et program må ha en Main-metode for å kunne kjøres. Merk at using-statements (import av navnerom) er utelatt fra eksemplene.

10 module Program
11 {
12     Main() : void
13     {
14         mutable sum = 0;
15 
16         for (mutable n = 1; n < 1000; n++)
17             when (n % 3 == 0 || n % 5 == 0)
18                 sum += n;
19 
20         WriteLine(sum);
21     }
22 }

I dette eksempelet opprettet jeg en sum-variabel som det er lov å endre (mutable). Nemerle finner selv ut at dette er en integer. Så kjører jeg en for-løkke, gjør en test, og legger tallet til sum om testen var positiv. Ganske rett frem dette her.

Jeg brukte “when” til testen, fordi “if” krever en else-blokk. Det er vanlig med påkrevd else i funksjonelle språk – Clojure er et eksempel på et språk som har det samme skillet.

Range, filter og fold med Labdas

Men la oss glemme for-løkken.., den er gammeldags! Her følger en såkalt stream-basert løsning hvor jeg oppretter en range, filtrerer den, og til slutt aggregerer summen med FoldLeft.

23 module Program
24 {
25     Main() : void
26     {
27         def numbers =
28             NList.Filter ($[1..999], fun (n) { n % 3 == 0 || n % 5 == 0 });
29 
30         def result = NList.FoldLeft (numbers, 0, fun (n, acc) { acc + n });
31 
32         WriteLine(result);
33     }
34 }

Dette illustrerer først og fremst hvordan lambda-uttrykkene ser ut i Nemerle. Ellers har du jo sett denne løsningen ganske mange ganger nå.

Nøstede funksjoner og pattern matching

En ting Nemerle skiller seg litt fra endel andre språk på er muligheten til å definere funksjoner inne i andre funksjoner. I den følgende løsningen har jeg opprettet to funksjoner inne i Main-metoden. Disse bruker pattern matching og rekusjon til å finne summen – en teknikk du også så meg bruke i F#.

35 module Program
36 {
37     Main() : void
38     {
39         def include(n)
40         {
41             n % 3 == 0 || n % 5 == 0
42         }
43         def euler1(n, sum)
44         {
45             | (1000, _)              => sum
46             | (_, _) when include(n) => euler1(n+1, sum+n)
47             | (_, _)                 => euler1(n+1, sum)
48         }
49         WriteLine(euler1(0, 0));
50     }
51 }

List comprehension

Den enkleste løsningen har jeg likevel spart til slutt. Nemerle har støtte for list comprehensions, som er et kraftig verktøy for å opprette filtrerte serier. Jeg kan dermed skrive ut svaret med en ganske leselig one-liner.

52 module Program
53 {
54     Main() : void
55     {
56         WriteLine($[x | x in [1..999], x % 3 == 0 || x % 5 == 0].Sum());
57     }
58 }

Hvorfor bruke tid på Nemerle

Nemerle er et praktisk og godt verktøy som lar deg kombinere objektorientering og funksjonell programmering. I tilleg har du makroene som lar deg utvide syntaksen og kompilatoren ganske enkelt. Nemerle vil derfor egne seg svært godt til å redusere mengden “boilerplate” i større løsninger, og til å lage interne DSL’er.

Sammenlignet med F# er Nemerle trolig enklere å forstå og å komme igang med for programmerere som ikke har vært eksponert for ML-lignende språk tidligere. Nemerle’s minner nemlig mer om C# gjennom bruk av krøllparanteser, klasser og andre syntaks-elementer. Man kan begynne med objekter om man er vandt til det, og gradvis ta i bruk de andre egenskapene etterhvert som man lærer.

Hvordan komme igang

Nemerle er støttet gjennom en extension i Visual Studio 2008. 2010-støtten er i beta, men fungerte greit nok for meg. Man får farger, IntelliSense, designtime hints og sikkert andre features jeg ikke har oppdaget. Du finner også støtte for Nemerle til SharpDevelop (om du er på Linux, eller foretrekker open source).

Jeg tror det vil være svært enkelt for et team med C#-utviklere å konvertere til å bruke Nemerle. Man kan selvfølgelig bruke språket på enkeltdeler; .NET-løsninger kan fint blande prosjekter skrevet i ulike språk. Men med Nemerle kan man i tillegg inkludere C#-kode i Nemerle-prosjekter – noe lignende har jeg aldri sett før.

Dessuten tilbyr Nemerle-teamet en C#-til-Nemerle converter. Hva med å kjøre den på din eksisterende kodebase, og se hva som kommer ut i andre enden?

Du finner Nemerle på nemerle.org. Språket har også en brukbar wiki med ganske mye informasjon, linker til API-dokumentasjon og tutorials.

Som sagt synes jeg Nemerle er et veldig spennende språk, og jeg anbefaler deg å ta det i nærmere ettersyn!

Hello World, Euler style

Thursday, November 24th, 2011
17 kommentarer

I den oppkommende adventskalenderen, hvor jeg hver dag frem til Jul vil introdusere deg for et nytt programmeringsspråk, har jeg valgt én bestemt oppgave for å vise frem språkene – nemlig den første og enkleste oppgaven på Project Euler.

Oppgaven lyder:

Hvis vi lister opp alle naturlige tall under 10 som er multipler av 3 eller 5 så får vi 3, 5, 6 og 9. Summen av disse er 23. Finn summen av alle multipler av 3 eller 5 under 1000.

Jeg bruker denne oppgaven som min Hello, World når jeg lærer meg nye språk. Den sørger for at jeg raskt lærer meg flere grunnleggende byggestener i språket, som hvordan man itererer, og hvordan man tar avgjørelser basert på numeriske operasjoner.

Jeg har også brukt oppgaven her på bloggen tidligere, i posten Parallellisering av en algoritme i Erlang. I dag gir jeg deg mulighet til å gjøre deg kjent med oppgaven, og viser noen implementasjoner i de språkene du normalt ser på programmeringsbloggen.

Løsning i C#

C# er språket jeg bruker til daglig, så det er et greit sted å begynne. Her følger en komplett løsning som looper gjennom alle tallene opp til 1000, sjekker om de er multipler av 3 eller 5 (ved å bruke modulo), og summerer opp tallene i sum-variabelen. Det siste som skjer er at tallet skrives ut.

10 class Program
11 {
12     static void Main()
13     {
14         int sum = 0;
15         for (int i = 0; i < 1000; i++)
16             if (i % 3 == 0 || i % 5 == 0)
17                 sum += i;
18         System.Console.WriteLine(sum);
19     }
20 }

Som sagt er det en meget enkel oppgave – så sant du kjenner til modulo da.

En alternativ måte å løse oppgaven er å bruke en funksjonell, stream-basert teknikk. I .NET vil dette si Linq. Her er en løsning i C# som bruker Range, Where og Sum:

10 using System.Linq;
11 
12 class Program
13 {
14     static void Main()
15     {
16         System.Console.WriteLine(
17             Enumerable.Range(1, 999)
18             .Where(i => i % 3 == 0 || i % 5 == 0)
19             .Sum());
20     }
21 }
22 

I julekalenderen vil du komme til å se en god mix av disse to fremgangsmåtene, og noen som er helt anderledes.

Løsning i Ruby

Ruby er det språket det er lettest for meg å hoppe inn i om jeg skal lage et kjapt lite verktøy, skal teste ut en algoritme eller noe lignende. Her følger en imperativ løsning:

1 sum = 0;
2 (1...1000).each do |i|
3   sum += i if i.modulo(3) == 0 or i.modulo(5) == 0
4 end
5 puts sum

I Ruby bruker jeg omtrent aldri vanlige for-løkker – å opprette en range, og så kjøre en kodeblokk for hvert element er mere naturlig.

En stream-basert løsning er mere elegant. Da bruker jeg select for å filtrere tallene, og reduce for å summere, slik som dette:

7 puts (1...1000).
8   select{|x| x.modulo(3) == 0 or x.modulo(5) == 0}.
9   reduce(:+)

Løsning i Clojure

Clojure er fortsatt favorittspråket mitt, så jeg må ta med noen løsninger i det også. Selv om det er helt unaturlig å bruke en løkke i Clojure så har jeg kokt sammen en slik løsning for denne ene gangens skyld:

 1 (loop [sum 0, numbers (range 1000)]
 2   (if (seq numbers)
 3     (let [i (first numbers)]
 4       (if (or (zero? (mod i 3))
 5               (zero? (mod i 5)))
 6         (recur (+ sum i) (rest numbers))
 7         (recur sum (rest numbers))))
 8     (println sum)))

Det fungerer, men jeg gremmes! I Clojure er stream-basert programmering det naturlige, og jeg kan bruke range, filter og reduce til å løse oppgaven ganske enkelt:

 1 (println
 2   (reduce +
 3           (filter #(or (zero? (mod % 3))
 4                        (zero? (mod % 5)))
 5                   (range 1000))))

Det er derimot ikke sikkert du synes det er så enkelt å lese denne koden. Trikset med å lese Clojure/Lisp-syntaks er som følger: Skann raskt med øynene fra venstre mot høyre til du kommer til uttrykkets siste del, som i dette tilfellet er (range 1000). Arbeid deg så tilbake mot høyre.

For å gjøre koden litt mere leservennlig tilbyr Clojure deg å gjøre det samme på følgende måte:

10 (->> 1000 range
11      (filter #(or (zero? (mod % 3))
12                   (zero? (mod % 5))))
13      (reduce +)
14      println)

Denne koden kan leses fra venstre mot høyre. “Ta tallet 1000, og lag en range av det. Filtrer med en anonym funksjon som sjekker om tall er delelig på 3 eller 5. Reduser med pluss (altså pluss dem sammen), og skriv til slutt ut”.

Løsning i Common Lisp

Og helt på tampen tar jeg med en løsning i Common Lisp – fordi man der finner den kuleste og mest komplette varianten av en for-løkke som finnes i noe språk, nemlig loop makroen:

1 (print (loop for x below 1000
2              when (or (zerop (mod x 3))
3                       (zerop (mod x 5)))
4              sum x)

Du har nå sett oppgaven løst med fire ulike språk, og i desember vil du få se flere løsninger. Da vil jeg sansynligvis bryte oppgaven opp i flere steg eller funksjoner, slik at jeg får presentert enda flere aspekter ved språkene jeg forteller om.

Jeg håper du gleder deg like mye som meg :)

Programmeringsspråket Mist

Monday, August 15th, 2011
4 kommentarer

logoEn nerd må ha noe å gjøre på. Så i sommer begynte jeg å implementere et nytt programmeringsspråk. Jeg har valgt å kalle det Mist!

Navnet ble valgt før jeg ble gjort oppmerksom på at det på tysk betyr gjødsel (for å si det pent).

Mist skal være et general purpose, dynamisk språk med fokus på den funksjonelle programmeringsparadigmen, og tilhører Lisp-familien. Det kjører på .NET-plattformen, og er implementert i C#.

Hvorfor?

Jeg begynte på dette for å lære, og for å ha det gøy. Alle utviklere med noen år på baken og respekt for seg selv burde vite hvordan man bygger et språk, og den eneste måten å kontrollere at man vet hvordan er å gjøre det.

Følelsen jeg hadde da jeg f.eks. implementerte rekursjon, eller da jeg fikk til closures, var helt hærlig. Følelsen litt senere av å forstå at jeg hadde løst scopes feil (etter å ha lest litt i Structure and Interpretation of Computer Programs), for så å rette det opp slik det burde være, var enda bedre. Jeg har allerede lært mye av dette, selv om jeg er LANGT FRA FERDIG.

Kan det brukes til noe?

Mist kommer ikke til å bli det neste, store språket som alle kommer til å ville bruke. Det kommer ikke til å kunne konkurrere med for eksempel Clojure. Men kanskje finnes det en liten nisje hvor Mist kan komme til nytte? Selv om jeg gjør dette for å lære og å ha det gøy, så har jeg i alle fall tenkt å holde på til jeg har et “ferdig” språk som kan tas i bruk av andre enn meg selv.

Mist kan brukes på flere måter; spåket er implementert i form av en høy-nivå tolker som består av én enkelt .NET dll. Denne kan refereres direkte i .NET-prosjekter for å gjøre dem “skriptbare”. Jeg har også laget en enkel Read-Eval-Print Loop hvor man interaktivt kan eksperimentere med Mist-kode, eller laste og kjøre Mist-filer.

Som en tredje opsjon har jeg tenkt å tilby en slags kompilator som tar en eller flere Mist-filer som input, og genererer en “standalone” exe-fil.

Noen betraktninger

Når man skal implementere dynamiske språk på .NET-plattformen kan det være naturlig å basere seg på Dynamic Language Runtime. Det valgte jeg derimot å ikke gjøre. Jeg ville lære mest mulig som jeg kan benytte uavhengig av plattform, og ikke bruke tid på å sette meg inn i et biblotek hvor deler av jobben allerede er gjort.

Det finnes forøvrig mange beskrivelser på nett og andre steder av hvordan man implementerer Lisp-lignende språk. Jeg valgte å ikke studere disse – mitt fokus var igjen å bruke og lære generelle teknikker for å utvikle parser, tolker og/eller kompilator (hovedinspirasjonen til prosjektet er boken Language Implementation Patternsog så trekker jeg på det jeg allerede kan om Clojure, Scheme og Common Lisp).

Ved første øyekast ser Mist ut som en hvilken som helst Lisp-implementasjon, men det skiller seg nok litt fra de fleste andre likevel. Blant annet har jeg valgt å ikke basere liste-strukturene på såkalte cons-par. I stedet bruker jeg listene i .NET basebibloteket.

Det er også vanlig at store deler av språk i Lisp-familien implementeres i språket selv. Mist består derimot av ganske mye C# – dette er for å utnytte det som allerede finnes i .NET, blant annet i et håp om å gjøre koden raskere enn jeg ellers ville klart.

Veien videre

Men det er tidlig enda. Jeg ser for meg at jeg skal jobbe med Mist – på bussen, fergen, og på kveldstid – i et par måneder til før jeg har noe som kan kalles en beta. Og estimater er til for å sprekke!

Av ting som jeg gleder meg til å gå igang med nå kan jeg nevne reader-macros, syntax quoting og tail call optimalisering. Når det gjelder tail calls så har jeg en ide om at jeg kan løse det med contiuation passing, men jeg må nok gjøre litt mer research før jeg er sikker på hvordan det skal gjøres.

Jeg har også planer om en dyp integrasjon med .NET (bruke .NET-typer fra Mist) som vil skille seg endel i fra hvordan f.eks. Clojure er integrert med Java. Med det gjenstår å se om det lar seg realisere.

Er du interessert i å ta en titt på koden, eller laste det ned og ta Mist på en liten kjøretur, så finner du prosjektet på Github. Bedre dokumentasjon på bruk og API kommer etterhvert.

Programmering er et spill

Friday, June 17th, 2011
Ingen kommentarer

Er du hekta på spill? Digger du å samle poeng og “badges”? Er du alltid nødt til å vinne, og gjør alle situasjoner om til en konkurranse? Den egenskapen kan du bruke til å bli en bedre programmerer!

so_tormaroeDet finnes nemlig mange steder hvor man kan bruke sin programmeringskunnskap til å konkurrere, og å få verdifull erfaring på kjøpet. Blant de mest populære sitene har vi f.eks. StackOverflow, som i praksis har tatt helt over den rollen som internett-forumene hadde for noen år siden. Hvis du er flink kan du svare på spørsmål, hvis du ikke er så flink kan du stille spørsmål. Og samme hva du gjør så får du poeng, låser opp nye ting du kan gjøre, og samler badges i gull, sølv og bronse. Jeg tror de fleste ble ganske overrasket da de så hvor avhengighetsskapende dette faktisk var.

Og ikke glem at StackOverflow har en haug med datter-sites som kan være like interessante, som for eksempel programmers.stackexchange.com, som er mere diskusjonsorientert, codereview.stackexchange.com, hvor du kan få folk til å vurdere koden din, og codegolf.stackexchange.com, som handler om programmeringsoppgaver og konkurranser. Det finnes egne varianter for spillutvikling, brukeropplevelse, QA-prosessen osv.

phpGolf5Code Golf er forresten et begrep som betyr å konkurrere om å lage det minste programmet som løser et gitt problem. Det finnes et hav av sider dedikert til denne formen for programmering. Et eksempel er phpGolf.org, som er utviklet av noen norske entusiaster. Utviklere interessert i Clojure kan prøve seg på 4Clojure.

Et annet sted jeg har tilbrakt endel tid er Euler Project. Her er det et hav av oppgaver man kan løse i valgfritt språk / verktøy. Også her blir man rangert, der er ulike nivåer man kan oppnå, og man får et badge man kan bruke til å skryte til omverdenen.

coderwallCoderwall er en ganske fersk site som utelukkende baserer seg på at folk vil vise seg frem, at de er stolte av hva de gjør, og at det er gøy å samle på “speidermerker” (evt. russeknuter). Siten kobler sammen og analyserer kontoer du har andre steder – som github og codeplex – og gir deg merker basert på hva du faktisk har oppnådd.

Betydningen av å leke og å ha det morro skal ikke undervurderes. Vi lærer lettere når vi har det gøy – dette viser både sosial og neural forskning – og konkurranseelementet stimulerer oss til å stå på og ikke gi opp.

Å bruke tid på disse sitene er derfor positivt for din utvikling som programmerer. De kan holde interessen din oppe over lengre tid, de kan eksponere deg for mange ulike oppgaver du må tenke gjennom, og ikke minst de setter hjernen din i en modus hvor den lærer bedre. At vi lærer mest av våre feil er en myte – det er mange, små suksesser som gjør deg til en bedre utvikler!

Legg igjen en kommentar om du har du tips til andre programmeringskonkurranser eller sites/communities som stimulerer deg på denne måten…

Mange som prøver, men få ninjaer på NDC sålangt

Wednesday, June 8th, 2011
Ingen kommentarer

75617316

Første dag på NDC 2011 er vell overstått. Jeg har fått med meg en god blanding av ulike foredrag som nå må fordøyes før det braker løs igjen i morgen tidlig.

.NET Ninja quizen på standen vår har også vært flittig besøkt. Men det er ikke mange som når helt opp – såvidt jeg vet var det bare kollega Henrik som klarte alle femten spørsmålene i dag, og han fikk strengt tatt hjelp på ett av dem.

Vi hadde Uncle Bob innom også; han hadde ikke tid til å prøve spillet, men sa han skulle komme tilbake. Så hvis du leser dette og deltar på konferansen, så må du komme innom du også, smake på kaffen, og prøve deg på quiz. Kanskje blir du en av ytterst få som kan skyte av å være en .NET Ninja!

Siste kommentarer

Torbjørn
PS: Takk til Børge Hansen, som delte SCARF-modellen med meg!...
Børge Hansen
Denne likte jeg veldig godt. Du skriver godt og har gode betraktninger  Keep it up – flere trenger å tørre å lære mer om ledelse – du l...
Tormod
Er egentlig ikke overrasket. F# sin fortè er programmererens produktivitet/kvalitet og anledning til parallell kjøring. Men kjøremotoren har ...
Stian
Ville også prøvd med et større problem (x100 eller x1000 f.eks). Når man snakker så små brøkdeler av et sekund som her så kan tiden for en ell...
Torbjørn
Har ikke sjekket - tar en titt i morgen hvis tid :)...
Einar W. Høst
Mhp tco: hva sier ILSpy?...
Torbjørn
Har ikke sett noe på PSeq før, men kjenner til den typen funksjoner fra blant annet Clojure. Og problemet med slike funksjoner i sammenhenger som de...
Håvard
Veldig bra sammenligning! Har du sett på ytelsen av PSeq.* fra powerpakken? Tipper den vil gi performancehit på små mengder, men kan kanskje resul...
Torbjørn
Jeg kom på en demonstrasjon-variant til jeg burde inkludere, nemlig bruk av list comprehension (en type computation expression (også kalt monads)). ...
Einar W. Høst
Interessant, det blir en trade-off mellom eleganse og fart på en måte. Den funksjonelle løsningen med vanlig filter er ren og pen, mens den imperat...
Creative Commons-lisens
Innholdet på denne bloggen er tilgjengelig under Creative Commons Navngivelse-Ikkekommersiell-DelPåSammeVilkår 3.0 Norge lisens.

Programmeringsbloggen
Kjempekjekt.com

© 2006-2013 Torbjørn Marø

Jeg har vært en profesjonell programmerer siden 1999, og dette er min blogg. Målet med bloggen er å stimulere meg selv og alle andre til kontinuerlig eksperimentering og læring.

Jeg forsøker å være allsidig, og programmerer blant annet i C#, Ruby, Erlang og Clojure.

Jeg praktiserer TDD og andre smidige utviklingspraksiser. Jeg er opptatt av kvalitet og ren kode.

Dette og ganske mye mer kan du lese om på denne bloggen!