Webutvikling

Gjennom hele karriæren har jeg vært mer webutvikler enn noe annet. Her kan du lese alle artiklene mine som først og fremst har noe med webutvikling å gjøre.

PSWinCom lanserer nytt API og teknisk wiki

De siste ukene har vi i PSWinCom jobbet med å utvikle et nytt integrasjonsgrensesnitt mot et av produktene våre. Intouch er en webapplikasjon hvor man kan organisere grupper og kontakter, sende meldinger til grupper, sette opp ulike SMS-tjenester, m.m. Og nå har den fått seg sitt eget REST API. Den potensielle verdien av Intouch, for dem som kan utnytte integrasjonsmuligheten, øker med dette betraktelig.

Det har vært veldig spennende å forsøke å designe et godt grensesnitt, og selv om dette er en første versjon så er vi ganke stolte over resultatet. Vi tror at vi har kommet opp med noe som vil være veldig greit å forholde seg til – for typiske enterprice-utviklere som bruker .NET eller Java, men også for utviklere som først og fremst bruker PHP eller lignende. Hos oss skal alle få!

wiki.pswin.com

Samtidig som vi introduserer et nytt API lanserer vi også en wiki hvor vi vil vedlikeholde våre tekniske spesifikasjoner og annen dokumentasjon og eksempler. Vi er igang med å overføre det vi har fra før, og regner med at dokumentasjonen vil være ganske up-to-date om en ukes tid. Vi tror at kundene våre vil sette pris på det nye formatet – med bedre muligheter for søking, bokmerking osv. Det vil også gjøre det enklere for oss å tilby dokumentasjon med knall kvalitet, fordi mange kan bidra, og fordi wiki-formatet gjør at dokumentasjonen kan vokse organisk.

Her forklarer oppfinneren av wiki-konseptet hva som gjør det så velegnet til denne typen dokumentasjon:

Besøk wikien vår på wiki.pswin.com.

Til slutt må jeg nesten nevne at jeg selvsagt klarte å snike inn litt Clojure i dette prosjektet også. For dem som ikke har tilbrakt så mye tid på denne bloggen så er det mitt favoritt-progammeringsspråk for tiden. Jeg har implementert et eksempelprogram i clojure som bruker det nye API’et vårt – og hvis den koden ikke får deg til å se lyset og få lyst til å jobbe med Clojure og REST så vet ikke jeg… ;) Se eksempelkoden på wikien her.

Webutvikling med Clojure

Web_Development

Jeg har begynt å eksperimentere med litt mer seriøs utvikling i Clojure. Jeg har testet ut en “full stack” for webutvikling, og er nå blitt kjent med tilstrekkelig med byggestener for å implementere fullverdige, databasedrevne webløsninger. Gjør deg klar for å bli introdusert til en veldig spennende verden – webutvikling i Clojure er nemlig både gøy og enkelt!

Leiningen

Første byggesten man bør bli kjent med, uavhengig av om man vil bedrive web- eller annen utvikling i Clojure, heter Leiningen. Dette er et kommandolinjeverktøy som hjelper deg å generere filstrukturen for prosjektet ditt, definere og laste ned avhengigheter, samt bygging og deployment. Det baserer seg på Maven, som Java-folket bruker, men er mye enklere å forholde seg til. Dessuten konfigurerer man Leiningen med Clojure-kode, ikke XML.

Når jeg skal starte et nytt prosjekt skriver jeg for eksempel kommandoen “lein new theUltimateBlog”, og leiningen genererer diverse filer for meg – blant annet en project.clj fil hvor jeg kan liste opp avhengighetene mine. Her er en typisk prosjektfil for et webprosjekt:

1 (defproject theUltimateBlog “0.1.0-SNAPSHOT”
2   :description “Yet another blog engine in Clojure”
3   :dependencies [[org.clojure/clojure "1.2.0"]
4                  [org.clojure/clojure-contrib "1.2.0"]
5                  [org.apache.derby/derby "10.6.2.1"]
6                  [ring/ring "0.3.1"]
7                  [compojure "0.5.2"]
8                  [hiccup "0.3.0"]])

Med enkle kommandoer kan jeg nå for eksempel laste ned alle avhengighetene i prosjektet, eller kompilere det. Leiningen kan blant annet produsere en såkalt uberjar, som er en deploymentløsning hvor prosjektet ditt pluss alle avhengighetene (inkludert selve Clojure) pakkes ned i én eksekverbar jar-fil. Dette er ideelt om du trenger å distribuere en applikasjon til klientmaskiner som kanskje ikke har Clojure fra før.

På Github finner du en tutorial med alt du trenger for å komme igang med Leiningen. Det finnes dessuten et alternativt build-verktøy som heter Cake man bør ta en titt på. Cake gir deg større muligheter i forhold til både innebygde oppgaver og til å definere dine egne tasks. Jeg tviler på at jeg tar feil når jeg sier navnet kommer fra Ruby’s Rake.

Ring

Den neste byggeklossen jeg gjorde meg kjent med var Ring. Prosjektet tilbyr webutviklere et stadard grensesnitt for å snakke med webservere, og spiller dermed samme rolle som Rack gjør i Ruby-verden.

Ring har et sett med biblotek for å håndtere ting som session, filopplasting osv., men styrken til Ring er at det er en felles plattform for utvikling av andre webutviklings-rammeverk. Det er dermed mange å velge blant, men jeg har testet ut..

Compojure

Det finnes altså mange rammeverk for webutvikling i clojure – Compojure virker som det mest kjente/omtalte, men man bør også ta en titt på Moustache, Conjure (Rails-inspirert) og Funkyweb. Disse rammeverkene gir deg et høyerenivås API for å definere ting som ruter og controller-logikk.

Her er et eksempel på en meget enkel webapp laget med Compojure og Ring. På roten (“/”) vil den svare med “Hello World”. På alle andre ruter vil den si “Page not found”.

1 (ns hello-world
2   (:use compojure.core, ring.adapter.jetty))
3
4 (defroutes main-routes
5   (GET “/” [] “<h1>Hello World</h1>”)
6   (compojure.route/not-found “<h1>Page not found</h1>”))
7
8 (run-jetty main-routes {:port 8080})

Eksempelet bruker en “embedded” webserver som heter Jetty, og den kjøres opp på port 8080.

I tillegg bør jeg nevne et prosjekt som heter Sandbar, som bygger på og utvider Compojure og Ring med ekstra funksjonalitet og abstraksjoner i forhold til bl.a. autorisering, autentisering og forms validering.

Hiccup

Når en har definert ruter og kontrollere i for eksempel Compojure trenger man en måte å generere dynamisk HTML. Også her finnes det en rekke biblotek man kan benytte. Jeg valgte å teste ut Hiccup, som gir deg en Clojure DSL for å definere HTML som minner mye om Haml i Ruby. For dem som mener det er bedre å kode viewene i HTML direkte finnes det andre prosjekter som for eksempel Fleet, men jeg synes det er ganske interresant å kunne manipulere HTML i form at Clojure-data, og har derfor større tro på Hiccup.

Ta for eksempel dette helt vilkårlige stykke med HTML:

10 <div id=“main”>
11   <h1>Hello World</h1>
12   <p>
13     <a href=http://www.lipsum.com/>Lorem ipsum</a> 
14     dolor sit amet, consectetur adipiscing elit. Nam dictum.
15   </p>
16   Tags:
17   <ul>
18     <li>Tag 1</li>
19     <li>Tag 2</li>
20     <li>Tag 3</li>
21   </ul>
22 </div> 

Nedenfor ser du en liten funksjon som ved hjelp av Hiccup returnerer nøyaktig samme HTML.

19 (defn display []
20       (html
21         [:div#main
22           [:h1 "Hello World"]
23           [:p (link-to "http://www.lipsum.com/" "Lorem ipsum")
24               " dolor sit amet, consectetur adipiscing elit. Nam dictum."]
25           “Tags:” (unordered-list ["Tag 1" "Tag 2" "Tag 3"])]))

Man oppretter og strukturerer HTML ved hjelp av vektorer og keywords. [:b "foo"] omgjøres for eksempel til <b>foo</b>. I tillegg ser du bruk av et par hjelpefunksjoner, link-to som oppretter en HTML-link, og unordered-list som oppretter en liste. Hiccup har mange slike funksjoner, spesielt knyttet til generering av skjema-HTML.

PS: Et tredje biblotek man bør ta en titt på er Enlive, som baserer seg på “selektorer” (ala CSS selectors) og transformering. Og så finnes det faktisk også en Haml-klone, men for meg ser Hiccup bedre ut. 

Og hvis du ønsker den samme styrken når det kommer til CSS kan du bruke cssgen-bibloteket til å kode stylesheets i Clojure.

Databaser

Den siste byggeklossen man normalt behøver for å lage webapps er persistering. I clojure.contrib.sql finner vi grei støtte for å jobbe med relasjonsdatabaser via jdbc. Her er et lite eksempel hvor jeg bruker en Derby-database, oppretter en enkel tabell med to kollonner, inserter et par rader, og til slutt leser dem ut igjen.

10 (ns myFirstDb.core
11     (:use [clojure.contrib.sql :as sql :only ()]))
12
13 (def db {:classname   “org.apache.derby.jdbc.EmbeddedDriver”
14          :subprotocol “derby”
15          :subname     “c:\\temp\\myFirstDb.db”
16          :create      true})
17
18 (defn create-tasks-table []
19       (sql/create-table :task
20         [:description "varchar(255)"]
21         [:state :int]))
22
23 (def *state-open* 0)
24
25 (defn insert-task [description]
26       (sql/insert-rows :task
27         [description *state-open*]))
28
29 (defn main []
30       (sql/with-connection db
31          (create-tasks-table)
32          (insert-task “Buy milk”)
33          (insert-task “Write a blog”)
34          (sql/with-query-results res
35             ["SELECT * FROM task"]
36             (doseq [rec res]
37                (println rec)))))
38
39 ; Output when running main:
40 ; {:description Buy milk, :state 0}
41 ; {:description Write a blog, :state 0}

For et mere komplett eksempel kan du ta en titt på testkoden til bibloteket.

Contrib.sql er egentlig alt man trenger, men det finnes andre abstraksjoner man med fordel kan ta en titt på. clj-record er for eksempel et forsøk på å gjenskape Ruby on Rail’s ActiveRecord i Clojure.

Om du er bitt av NoSQL-basillen finnes det selvsagt diverse Clojure-biblotek for deg også. Congomongo er en wrapper for Java API’et til MongoDB, mens du kan bruke clojure-couchdb om du er glad i Apache CouchDB. Her er litt eksempelkode fra det førstnevnte:

43 (ns my-mongo-app
44     (:use somnium.congomongo))     ; use the congomongo lib
45
46 (mongo! :db “mydb”)                ; setup database to use
47
48 (insert! :robots {:name “robby”})  ; insert some data
49
50 (def my-robot (fetch-one :robots)) ; read some data
51
52 ; my-robot => { :name “robby”,
53 ;               :_id  #<ObjectId> “0c23396f7e53e34a4c8cf400″>,
54 ;               :_ns  “robots” }

Konklusjon

Jeg har nå dratt deg gjennom en komplett liste med byggeklosser du kan bruke for å lage komplette webløsninger i Clojure. Det kan kanskje virke overveldende til å begynne med, men hver liten bit er veldig enkel å forholde seg til, og Clojure har virkelig potensiale til å være en ypperlig plattform for webutvikling. Det er først og fremst språket i seg selv som er årsaken til dette, men mye innsats har også gått inn i å lage praktiske API’er som gjør utviklingen rask samtidig som man fokuserer på det som er viktig.

Det er min vurdering at Clojure kan gjøre deg minst like produktiv som Ruby på dette feltet.

Clojure-prosjekter nevnt i denne posten: Cake | clj-haml | clj-record | Clojure Contrib | Clojure-CouchDB | Compojure | Congomongo | Conjure | cssgen | Enlive | Fleet | Funkyweb | Hiccup | Leiningen | Moustache | Ring | Sandbar.

En minimal http-server i Ruby

I denne oppfølgingsposten til En minimal http-server i .Net viser jeg hvordan jeg raskt kan sette opp en tilsvarende løsning i Ruby. Jeg skal altså implementere en tjeneste som lytter på http, og som responderer på ulike argumenter. Løsningen skal være enkel å utvide med flere “respondere” – det skal ikke være nødvendig å editere eksisterende kode for å håndtere nye typer forespørsler (se forrige post om du vil vite mer om oppgaven).

Ruby shipper med mange, nyttige moduler – blant annet en søt, liten tjeneste som heter WEBrick, som kan brukes ganske likt som .Net’s HttpListener egentlig. I følgende program setter jeg opp en server til å lytte på port 8081:

   1 require ‘webrick’

   2 include WEBrick

   3 

   4 #DSL method for defining responders

   5 def respond_to config

   6     key = config[:key]

   7     $server.mount_proc(key) do |request, response|

   8         response.body = yield request.query.to_s

   9     end

   10 end

   11 

   12 def load_responders

   13     responder_definitions = Dir.glob(“*.responder”)

   14     responder_definitions.each { |d| load d }

   15 end

   16 

   17 $server = HTTPServer.new( :Port => 8081 )

   18 load_responders

   19 trap(“INT”) { $server.shutdown }

   20 $server.start

Servicen opprettes i linje 17, og i neste linje kaller jeg en metode jeg har kalt load_responders. Den henter alle filer med .responder extension, og kjører innholdet. Responder-filene i sin tur benytter respond_to metoden definert fra linje 5 til å konfigurere WEBrick.

Sidenote: Jeg implementerte først en løsning med en SimpleHttpServer-klasse og en klasse for å representere respondere. Etter å ha tenkt meg litt om så jeg derimot at det bare ble en masse stafasje, og at koden ikke kommuniserte så veldig godt hva den gjorde. Enkelhet er et av de viktigste budene for smidige utviklere, og Ruby lar meg skrelle bort ganske mye. Så etter å ha slettet 30 linjer kode følte jeg meg mer komfortabel. Om du vil se en mere objektorientert løsning kan du ta en titt på Building a DSL in Ruby, part II fra bloggen Technology as if People Mattered, som var en viktig inspirasjonskilde til denne bloggposten.

Nedefor er responder-filen for add-tjenesten. Se forrige post for å se hvordan denne responderen ser ut i .net. Som du kanskje ser er dette rett og slett et kall til respond_to. Som argument til metoden sendes nøkkelen “/add”, som er det responderen skal håndtere (ref bruk av attributtet RespondTo i .Net-løsningen). Resten er en kodeblokk som tar som input argumentene fra requesten, og returnerer et svar. Denne kodeblokken brukes til å håndtere forespørselen (magien ligger i “yield” i linje 8 i programmet over).

   1 respond_to :key => “/add” do |arguments|

   2     sum = 0

   3     numbers = arguments.split(‘,’)

   4     numbers.each { |n| sum += n.to_i }

   5     “The answer is #{sum}”

   6 end

Koden i denne responderen er litt C#-ish, jeg har gjort nøyaktig det samme som jeg gjorde i C#-varianten, bare oversatt det til Ruby. For å gjøre den mere rubyesque benytte vi et par array-metoder som Ruby har arvet fra SmallTalk: map (som egentlig er en alias fro collect, men jeg liker map bedre) tar et array, kjører en gitt transformasjon på hvert element (i dette tilfellet eksplisit konvertering til integer), og returnerer et nytt array med resultatet. Dette føles nok ikke så  fremmed for .Net-utviklere lengre, nå som vi har vendt oss til Linq, som tilbyr samme funksjonalitet via Select-metoden.

Det andre trikset er metoden inject. Den kan brukes til å “samle informasjon” fra et array, i dette tilfellet summen av alle argumentene. Dermed kan spesifikasjonen av add-responderen modifiseres til å se slik ut:

   1 respond_to :key => “/add” do |arguments|

   2     numbers = arguments.split(‘,’).map {|arg| arg.to_i}

   3     “The answer is #{numbers.inject {|x,n| x+n }}”

   4 end

Resultatet er altså at jeg på 20 linjer har satt opp en dynamisk webserver som jeg kan utvide ved å legge til flere .responder-filer. Definisjonen av hver responder er veldig konsis og grei, og står på ingen måte tilbake for .Net-løsningen. I Ruby har jeg ikke behøvd å definere interface for respondere, og lastingen av dem – som er basert på fil-extension i stedet for refleksion og attributter – er mye enklere. Når du tar med i betraktning at jeg ikke engang behøver å kompilere Ruby-løsningen, så er det ikke vanskelig for meg å foretrekke denne når jeg får behov for å raskt sette opp web-tjenester av ulik art f.eks. for å simulere tjenester jeg skal integrere mot.

Sinatra entrer scenen

frank_sinatra Å bruke WEBrick til dette her er ganske “low level” (på samme måte som HttpListener var det). I .NET-verden har vi rammeverk for webutvikling på et høyere nivå som blant andre WebForms, ASP.NET MVC, FubuMVC og MonoRail (det er egentlig alle jeg vet om). Ruby har også dette; det desidert mest kjente er Ruby on Rails, som gjør deg ekstremt produktiv så sant du er villig til å følge Rails konvensjoner og måter å gjøre ting på. Ramaze er et rammeverk med mye større frihet, hvor man kan velge mellom et hav av moduler og måter å gjøre ting på. Begge disse baserer seg i hovedsak på Model-View-Controller paradigmet.

Sinatra er et tredje ruby-biblotek som er ganske nyttig til å utvikle mindre websider og tjenester. Det minner mye om det jeg har gjort i denne artikkelen, og ved å bruke Sinatra kan jeg forenkle tjenesten min ganske mye (som om den ikke var enkel nok allerede).

Sinatra-versjonen av selve tjenesten min ser slik ut:

   1 require ‘sinatra’

   2 Dir.glob(“*.responder”).each { |d| load d }

Ved å inkludere sinatra-bibloteket startes automatisk en webserver. Det eneste jeg da trenger er å dynamisk laste alle responder-filene. Jeg har slått sammen linje 13 og 14 fra det orginale skriptet, og står dermed igjen med én require og én kodelinje.

Responder-filen ser nesten ut som tidligere, men kallet til respond_to, som jeg selv definerte, har vi nå et kall til sinatras get-metode (‘get’ som i REST-metoden get):

   1 get “/add” do

   2     numbers = params.to_s.split(‘,’).map {|arg| arg.to_i}

   3     “The answer is #{numbers.inject {|x,n| x+n }}”

   4 end

Dermed har jeg gått fra 24 til 6 linjer. Det er latterlig lite!

Og den tilsvarende C#-løsningen fra forrige post var på over 170 linjer. Det finnes selvfølgelig mere optimale løsninger, men jeg har vært en C#-utvikler i åtte år, og 170 liner ++ var det jeg havnet på. Jeg har vært Ruby-utvikler på hobbybasis i et par måneder, og landet på 6 linjer. Det MÅ jo si noe om Ruby og dynamisk programmering!

En minimal http-server i .Net

.Net-rammeverket er fullt av moduler for å lage webtjenester; du kan bruke WebForms eller ASP.NET MVC, SOAP web services eller WCF, RIA services eller Astoria data services, alt etter dagsform og hvilket behov du har. Noen ganger kan det derimot være greit å vite hvordan man på aller enklest måte kan lage en http-basert server. I Chrome-vinduet under ser du hvordan jeg aksesserer en “no-fuss” service som kan fortelle meg hva klokka er…

CropperCapture[48]

I denne artikkelen presenterer jeg den ikke så veldig godt kjente klassen HttpListener (i System.Net namespacet), og viser hvordan man enkelt kan bruke den til å lage en slags webserver. Denne teknikken kan være aktuell om man f.eks. skulle trenge å raskt mocke opp noen webservicer som ikke følger de vanlige standardene, eller om man skal lage moduler som kommuniserer over http med en proprietær protokoll.

Men jeg har mer på lur: Http-serveren jeg presenterer her er designet for å være utvidbar, og bruker derfor STRATEGY PATTERN i håndteringen av forespørslene. Du vil også få se hvordan jeg kombinerer attributter og reflection for å kunne dynamisk legge til ny adferd uten å måtte editere eksisterende kode.

Her følger selve server-klassen: SimpleHttpServer. Det sentrale skjer i linje 30 til 33, hvor jeg oppretter en HttpListener, registrerer adresse og port for lytting, og starter å lytte. Dette tilsvarer mer eller mindre hvordan Internet Information Server (IIS) selv registrerer seg for lytting mot operativsystemet.

    9 public class SimpleHttpServer

   10 {

   11     private string _address;

   12     private int _port;

   13     private ResponderFactory _dispatcher;

   14     public SimpleHttpServer(string address, int port, ResponderFactory dispatcher)

   15     {

   16         _port = port;

   17         _address = address;

   18         _dispatcher = dispatcher;

   19     }

   20 

   21     private HttpListener _httpListener;

   22     public void Start()

   23     {

   24         StartHttpListener();

   25         while (true)

   26             WaitForRequestThenHandle();

   27     }

   28     private void StartHttpListener()

   29     {

   30         _httpListener = new HttpListener();

   31         _httpListener.Prefixes.Add(

   32             String.Format(“http://{0}:{1}/”, _address, _port));

   33         _httpListener.Start();

   34     }

   35     private void WaitForRequestThenHandle()

   36     {

   37         var incomingRequestContext = _httpListener.GetContext();

   38 

   39         ThreadPool.QueueUserWorkItem((state) =>

   40         {

   41             try

   42             {

   43                 var context = state as HttpListenerContext;

   44                 var url = context.Request.Url;

   45                 var encoding = context.Request.ContentEncoding;

   46 

   47                 var result = _dispatcher

   48                     .GetResponder(GetCommandKey(url, encoding))

   49                     .RespondTo(GetCommandArguments(url, encoding));

   50 

   51                 Respond(context, encoding, result);

   52             }

   53             catch (Exception ex)

   54             {

   55                 // Don’t want the service to die, just log it..

   56                 Console.WriteLine(ex.ToString());

   57                 // Could then responde with some error code…

   58             }

   59         },

   60         incomingRequestContext);

   61     }

   62 

   63     private static string GetCommandKey(Uri url, Encoding encoding)

   64     {

   65         // AbsolutePath always starts with a ‘/’

   66         return HttpUtility.UrlDecode(url.AbsolutePath.Substring(1), encoding);

   67     }

   68     private static string GetCommandArguments(Uri url, Encoding encoding)

   69     {

   70         // Query always starts with a ‘?’, but may be null

   71         return url.Query != null && url.Query.Length > 1

   72                         ? HttpUtility.UrlDecode(url.Query.Substring(1), encoding)

   73                         : string.Empty;

   74     }

   75     private static void Respond(HttpListenerContext context, Encoding encoding, string result)

   76     {

   77         var bytes = encoding.GetBytes(result);

   78         context.Response.ContentLength64 = bytes.Length;

   79         context.Response.OutputStream.Write(bytes, 0, bytes.Length);

   80         context.Response.StatusCode = 200; // everything is ok :)

   81         context.Response.Close();

   82     }

   83 }

Etter å ha opprettet HttpListener kjører jeg en uendelig løkke som mottar innkommende forespørsler og håndterer dem (en robust implementasjon ville også hatt en Stop-metode som terminerte løkken). Kallet til GetContext() i linje 37 returnerer når en request mottas, og så bruker jeg ThreadPool til å spawn’e en ny tråd som håndterer den og svarer tilbake.

Denne serveren bruker selve URL’en til å avgjøre hva den skal gjøre. I eksempelet i starten av artikkelen var requesten http://127.0.0.1:8081/time?. Alt etter domenet og porten men før spørsmålstegnet bruker jeg til å avgjøre hvilken Responder som skal brukes. Det er her STARTEGY pattern kommer inn i bildet – en responder er en klasse som implementerer interfacet Responder

    5 public interface Responder

    6 {

    7     string RespondTo(string arguments);

    8 }

    5 public interface ResponderFactory

    6 {

    7     Responder GetResponder(string responderKey);

    8 }

Argumentene som sendes til responderen er alt som kommer etter spørsmålstegnet i requesten. HttpListener støtter mye mer enn dette, men alt jeg er interessert i denne gangen er selve URL’en.

SimpleHttpServer ble initialisert med en ResponderFactory. Denne vil – gitt en nøkkel – returnere riktig responder. Ta en titt til på serveren om du ikke fikk det helt med deg første gangen, spesielt linje 47 til 49.

En første versjon av ResponderFactory (den faktiske implementasjonen kommer lengre nede) kunne vært en klasse som uansett nøkkel returnerte en UnknownCommandResponder:

    5 public class UnknownCommandResponder : Responder

    6 {

    7     private string _request;

    8     public UnknownCommandResponder(string request)

    9     {

   10         _request = request;

   11     }

   12     public string RespondTo(string arguments)

   13     {

   14         return String.Format(“Unknown command: ‘{0}’ with arguments ‘{1}’”,

   15             _request,

   16             arguments);

   17     }

   18 }

Det kan være greit å ha en slik default strategi/responder til å svare på alle mulige ting man måtte finne på å etterspørre. Her ser du den i aksjon:

CropperCapture[46]

Opprette flere tjenester: Attributter og reflection

Før jeg legger til den første “fornuftige” responderen oppretter jeg et .net-attributt. Det trenger ikke være noe mer avansert enn å lage en klassen som arver fra Attribute.

    6 public class RespondToAttribute : Attribute

    7 {

    8     public string Key { get; set; }

    9     public RespondToAttribute(string key) {

   10         Key = key;

   11     }

   12 }

Jeg har laget svært få attributter i min karriære, men det er en teknikk som kan gi veldig elegante løsninger om det brukes riktig. Måten jeg bruker det på her er ganske vanlig. Og enkel! Den vil rett og slett la meg legge til nye respondere uten at jeg behøver å endre noen eksisterende kode.

Men first thing first: Når jeg implementerer mine respondere vil RespondToAttribute la meg spesifisere hvilken nøkkel hver responder gjelder for. Her er f.eks. en enkel responder som legger sammen en rekke med tall separert med komma:

    6 [RespondTo("add")]

    7 public class Add : Responder

    8 {

    9     public string RespondTo(string arguments)

   10     {

   11         int result = 0;

   12         Array.ForEach(arguments.Split(‘,’),

   13             (arg) => result += Int32.Parse(arg));           

   14         return string.Format(“The answer is {0}”, result);

   15     }

   16 }

(Det er en konvensjon i .Net at man slipper å skrive “Attribute”-delen av attributt-navnet. Dermed blir linje 6 så fin.., denne klassen “responderer på add”.)

Når jeg gjør ting som dette er det typisk endel implisitte regler jeg må følge. I dette tilfelle vil det for eksempel ikke gi mening om mer enn én klasse responderer på “add”. Nøkkelen må med andre ord være unik. For å håndheve slike regler oppretter jeg som regel validerende enhetstester. Følgende test bruker reflection til å hente ut alle typer i prosjektet, samle opp alle RespondToAttributes fra typene, og sjekke at de er unike..

   12 [Test]

   13 public void Should_all_be_unique()

   14 {

   15     var keys = new List<string>();

   16     var allTypes = Assembly.GetExecutingAssembly().GetTypes();

   17     foreach (var t in allTypes)

   18     {

   19         var attribute = Attribute

   20             .GetCustomAttribute(t, typeof(RespondToAttribute))

   21             as RespondToAttribute;

   22 

   23         if (attribute == null)

   24             continue;

   25 

   26         if (keys.Contains(attribute.Key))

   27             Assert.Fail(attribute.Key + ” appear more than once!”);

   28 

   29         keys.Add(attribute.Key);

   30     }

   31 }

Og denne samme teknikken vil jeg bruke når jeg implementerer den endelige ResponderFactory-klassen. Den oppretter en dictionary med nøkler mappet til respondere (eller mer nøyaktig mappet til funksjoner som oppretter respondere).

    7 public class ReflectiveResponderFactory : ResponderFactory

    8 {

    9     private Dictionary<string, Func<Responder>> _dispatchTable;

   10 

   11     public ReflectiveResponderFactory()

   12     {

   13         _dispatchTable = new Dictionary<string, Func<Responder>>();

   14         Array.ForEach(Assembly.GetExecutingAssembly().GetTypes(),

   15             (type) => AddDispatchIfResponder(type, GetResponderInfo(type)));

   16     }

   17     private static RespondToAttribute GetResponderInfo(Type maybeResponderType)

   18     {

   19         return Attribute.GetCustomAttribute(maybeResponderType,

   20             typeof(RespondToAttribute)) as RespondToAttribute;

   21     }

   22     private void AddDispatchIfResponder(Type type, RespondToAttribute responderInfo)

   23     {

   24         if (responderInfo != null)

   25             _dispatchTable.Add(

   26                 responderInfo.Key,

   27                 () => Activator.CreateInstance(type) as Responder);

   28     }

   29 

   30     public Responder GetResponder(string responderKey)

   31     {

   32         if (!_dispatchTable.ContainsKey(responderKey))

   33             return new UnknownCommandResponder(responderKey);

   34         return _dispatchTable[responderKey].Invoke();

   35     }

   36 }

Her forutsettes det at alle respondere (med RespondTo-attributt) har en default, parameter-løs konstruktør, slik at den kan opprettes i lambda-uttrykket i linje 27. Du bør opprette en enhetstest for å validere dette også, slik at ingen lager en responder med konstruktør-parametre i fremtiden og dermed introduserer en bug (ikke at de ikke ville ha oppdaget det, men rask tilbakemelding er alltid kjekt).

Om du nå har skjønt hvordan disse klassene henger sammen gjenstår det bare å opprette og starte en SimpleHttpServer for at dette skal fungere. Her kjører jeg serveren i et konsollprogram, men i et mer realistisk senario vil du typisk kjøre den i en enkel Windows service.

    7 static void Main(string[] args)

    8 {

    9     new SimpleHttpServer

   10         (“*”, 8081, new ReflectiveResponderFactory())

   11         .Start();

   12 }

Og nå kan vi endelig få vite hvor mye 10 + 20 + 30 er…

CropperCapture[47]

For å utvide serveren med mer funksjonalitet er det nå bare til å opprette flere klasser som arver fra Responder-interfacet, og legge til et RespondToAttribute. ReflectiveResponderFactory vil finne og registrere den nye klassen under oppstart, og delegere til en ny instans av responderen om nøkkelen kommer i en forespørsel.

Jeg håper noen klarte å henge med óg få noe fornuftig ut av dette. Mer info om HttpListener finner du her, og info om .net attributes finner du via google. I neste blogpost vil du få se hvordan jeg implementerer nøyaktig samme funksjonalitet ved hjelp av Ruby.

Knagger: , ,

MSDN Live Bergen – september 09

Einar presenterer WPF og Silverlight på MSDN Live i Bergen

Denne uken var det i Bergen igjen tid for å ta imot MSDN Live – Microsoft’s road show for utviklere. Som nevnt tidligere var det tre foredragholdere denne gangen, Børge Hansen, Einar Ingebrigtsen og Fredrik Kalseth. Jeg minglet litt først på dagen, så jeg fikk ikke med meg Børge sine presentasjoner av hva som er nytt i VS 2010 og C# 4.0, men her er min oppsummering av de andre foredragene..

WPF 4

I sommer har Einar vært med og utviklet en Microsoft Surface applikasjon for underholdningsprogrammet De Ukjente på NRK1, og han startet med en presentasjon av det, og snakket litt om erfaringene fra prosjektet. Deretter tok han for seg noen utvalgte områder i WPF 4 – han snakket litt om multitouch, demonstrerte ribbons (som han nevte også kan benyttes i WPF 3.5), viste hvordan man lager jumplists for Windows 7, og til slutt avlørte han noen nye databindingsteknikker.

Demonstrasjonen ble desverre noe preget av at Einar hadde lastet ned siste versjon av Visual Studio 2010, som krasjet i tide og utide. Jeg antar de klarer å gjøre IDE’en stabil igjen før den endelige releasen, men inntrykket vi fikk under demoen var ikke bra, og førte til at Einar ikke rakk å vise oss WPF’s nye Visual State Manager.

Silverlight 3

Silverlight-sesjonen gikk mye bedre. Versjon 3 inneholder et hav av nye ting, og også her valgte Einar ut et lite sett av de mest spennende tingene. Han demonstrerte en skygge-effekt som bruker Silverlights pixel shader støtte, han viste oss hvordan Out of Browser fungerer, demonstrerte deler av navigasjons-støtten som er bygget inn (deep linking), og hvordan databinding har blitt mere likt slik det er i WPF.

Det var kanskje mest spennende mot slutten, da han bruke .NET RIA services. Jeg er kjent med hva dette er for noe fra diverse podcasts, men hadde faktisk aldri sett det før – og jeg ser nå at dette er noe jeg absolutt bør se nærmere på. RIA services ser ut til å være en veldig naturlig komponent i enhver løsning som har mye funskjonalitet i browseren (Silverlight eller AJAX-heavy web site), og jeg skulle gjerne ha sett et eget foredrag på MSDN Live dedikert til dette rammeverket.

Einar nevnte også Silverlight Toolkit, en samling av kontroller man kan laste ned fra codeplex, og demonstrerte også en av dem som heter Dataform. Denne verktøykassen inneholder mye bra som man bør ta en titt på om man skal utvikle noe i Silverlight.

Til slutt fortalte Einar litt om Balder, 3D motoren han laget for Silverlight, som etterhvert har/skal utvikle seg til å bli en spillmotor også for Xna og OpenGL. Balder er “hovedpersonen” i en bok som lanseres i disse dager: 3D Game Development with Microsoft Silverlight 3: Beginner’s Guide. Sikkert spennende lesestoff om du går med en liten spillutvikler i magen.

ASP.NET 4

Fredrik viste seg å være en meget solid foreleser. I sitt første foredrag brukte han endel slides til å raskt gå over en rekke nye ting i ASP.NET versjon 4: Slankere web.config, cache providers, preload providers, session state compression, viewstate mode, client id mode, encoding-forbedringer, rendering-forbedringer for å støtte XHTML, MSDeploy, JSONP, m.m.

Deretter gikk han mer i dybden på et par ting, nemlig routing – som begynner å bli ganske kjent nå – og client template rendering. I demoen brukte han et “full-fledged” web prosjekt som bl.a. inneholdt enhetstester, bruk av IoC container (Ninject), repository pattern, og god seperasjon av ansvar i presentasjonslaget. Jeg synes dette fungerte veldig bra, og gav foredraget en ekstra dimensjon i forhold til en typisk demo av hva som er nytt i ASP.NET. Vi måtte holde 100% fokus på hva som skjedde på skjermen for å ikke falle av, for Fredrik holdt et ganske bra tempo, og gav oss mye “valuta for pengene”.

Han gav oss også et par andre tips til ting det kan være verdt å se på. Først og fremst var dette ASP.NET Chart Controls pakken fra Microsoft (presentert av ScottGu her). Her har de laget en flott, gratis chart-pakke som kan erstatte mye av behovet for tredjepartskontroller.

Det andre tipset var et lite javascript biblotek som heter datejs – noe jeg gjerne kommer til å bruke selv nå som jeg vet om det.

Smidig utvikling i Visual Studio

Den siste forelesningen til Fredrik fikk jeg bare delvis med meg (måtte rydde NNUG-standen), men likevel var det den jeg likte aller best. Her snakket han nemlig om flere av mine “hjertebarn”; han gav bl.a. en god introduksjon til Onion Architecture og Inversion of Control, og snakket om god utviklingsprosess med bruk av testdreven utvikling, branching, continuous integration, automatisk deploy til test og staging-miljø, automatisk kjøring av funksjonelle tester vha selenium, m.m.

Han brukte flere, nye features i Visual Studio og Team Foundation Server, og viste bl.a. hvordan de nå har tatt i bruk Workflow Foundation for å lage build- og deployment-prosesser, noe som virket ganske bra. Fredrik brukte det samme web prosjektet som han  viste oss i den første sesjonen, og jeg tror som sagt dette gav dem som hørte på noe ekstra, ved at de fikk se et fullverdig prosjekt gjort på den “riktige” måten.

Oppsummering

Dagen ble bedre enn forventet. Beskrivelsen av agendaen, med fokus på Microsoft’s produkter, gav et for snevert inntrykk av hva foredragene inneholdt. Jeg ble spesielt imponert over Fredrik sine presentasjoner, og jeg synes vi absolutt bør forsøke å få ham til å komme og holde noen foredrag for oss på NNUG i Bergen – de fleste utviklere kan lære noe av hvordan han gjør saker og ting.

Holder du til i Oslo kan du forøvrig fortsatt få med deg disse foredragene, da MSDN Live kommer til Oslo Kongressenter tirsdag 29. september.

The Forecast Exchange: Flere grafer og en promo video

Vi er for tiden godt inne i andre runde med beta-testing av The Forecast Exchange, open-source prosjektet hvor man bruker kjøp og salg av aksjer til å spå om fremtiden. Det jeg har bidratt med den siste tiden er å visualisere data gjennom grafer.

Det førset vi la til var en liten trendgraf, som vi fikk plass til i listen over aktive spådommer. Dette er videreføringen av en håndlaget sparkline-kontroll jeg laget for Fussball Manager, et annet lite hobbyprosjekt. Og resultatet ser sånn ut:

The Forecast Exchange: Active predictions
Klikk bildet for full størrelse

Jeg er interessert i å lære meg jQuery, det mest populære JavaScript/Ajax-biblioteket for tiden, og i går satt jeg og så gjennom alle plugin’ene som er laget for jQuery. Da kom jeg over en plugin som enkelt lar deg opprette Google Charts med jQuery. Jeg har blogget om Google Charts tidligere her.

Ved å bruke denne plugin’en la jeg til to ekstra grafer på The Forecast Exchange: En litt større trendgraf som viser utviklingen av verdien på aksjene, og et lite “spidometer” som viser verdien på aksjene etter siste salg:

The Forecast Exchange: Prediction charts

Og til slutt måtte jeg selvfølglig lage en liten promotion-video for prosjektet vårt. Vel bekomme:

Knagger: , , , ,

En applikasjon på en dag

Av og til er det herlig å bare gjøre et veldig lite utviklingsprosjekt. Man får en ide eller en forespørsel, lar tanken modnes i en dag eller to, og så implementerer man løsningen på ca en arbeidsdag. Jeg har nettopp gjort et slikt prosjekt, hvor jeg utviklet et internt verktøyt på jobben for å samle kunnskap om feilsituasjoner knyttet til utvikling, installasjon og support av produktene våre.

ContikiException er en meget enkel web app for registrering av kjente feilmeldinger med mulige løsninger. Det var Halvard (fra The Forecast Exchange) som kom frem til at vi hadde et behov for dette verktøyet, og gav meg lysten til å gjøre det.

ContikiExceptionSmaller.png

Det fine med slike småprosjekter er at de fungerer som ideelle “prøvefelt” for nye verktøy og teknikker. Man kan teste ut nesten hva som helst når det meste man kan tape er én dags arbeid. Denne gangen valgte jeg å droppe relasjonsdatabase, og brukte i stedet en objectdatabase som heter db4objects. Jeg bruker denne teknologien på et par andre prosjekter også, men ingenting som er ferdig enda.

I slutten av måneden skal jeg holde et innlegg på NNUG i Bergen om objectdatabaser, og hva vi .net utviklere kan bruke dem til.

I tillegg har jeg så smått begynt å bruke dependency injection i prosjektene mine; i ContikiException brukte jeg ninject. Ninject skryter av å være en ultrarask lettvekter, og i stedet for å basere seg på XML-konfigurasjon som mange av de andre DI rammeverkene bruker ninject et såkalt fluent interface. Dette betyr at det er enklere å sette opp avhengighetene – det er i alle fall mitt inntrykk, selv om jeg ikke har mye erfaring. I tillegg kan man dra nytte av code completion og type-safety – noe som i alle fall er et stort pluss.

Dokumentasjoen sier dessuten at “Ninject makes your application more ninja-like”, så da er det uansett det naturlige valget for meg :)

Første erfaring med Dynamic Data

I Contiki bruker vi en velprøv metode tuftet på velkjent teknologi for å holde rede på våre kunder og deres installasjoner av vårt produkt – nemlig en flatfil i Excel.

Nå har endelig noen blitt så trøtte av denne løsningen at man har bestem at noe må gjøres. Jon Arild kom da i dag med den lure ideen at vi kunne bruke Dynamic Data (tidligere omtalt her) til å smelle opp en rask webløsning som publisere rdataene og gir editeringsmuligheter til dem som trenger dem. Så her er hva vi gjorde, og hvor lang tid det tok:

  1. Analyserte Excel-filen, og identifiserte hvordan den burde brytes opp i databasetabeller. 15 minutter.
  2. Forbedringer av Excel-filen for å gjøre det enklere å generere en database fra den. Omtrent 60 minutter.
  3. Importerte Excel-filen til en Access database. Et tungvindt grensesnitt og merkelig oppførsel gjorde at dette tok omtrent 45 minutter.
  4. Exporterte Access-basen til SQL server. 30 sekunder.
  5. Fikset opp i rare avgjørelser utført av eksporten. 2 minutter.
  6. Opprettet en ASP.NET DybamicData Web Site. Nesten 10 sekunder.
  7. Opprettet en LINQ to SQL modell basert på basen. 12 sekunder.
  8. Konfigurasjon av DynamicData-løsningen. Omtrent ett minutt. (Måtte lete litt nemlig. Trodde den ene linjen som skulle endres befant seg i web.config, men den var i stedet i global.asax.)
  9. Konfigurere siten til å bruke Forms based authentication. La til bruker, roller og tilgangsrettigheter. 2 minutter.
  10. Opprettet en spliter ny påloggings-side. “Add new item” + drag’n'drop av login-kontroll tok kanskje 15 sekunder.

Vi hadde egentlig en fungerende løsning etter punkt 8, men vi ønsket også en uathentiseringsløsning, så da måtte vi jobbe litt til. Men det som tok tid var altså å massere dataene våre for å få en fornuftig base. Selve løsningen, med fullstendig CRUD GUI for hele basen, tok under fire minutter å sette opp.

Internet Explorer 8

ie8.jpgHvis du er litt treig (evt. ikke nerd) så har du kanskje ikke fått med deg at Internet Explorer 8 er sluppet i beta. På MSDN Live i Bergen i dag holdt Anders Nordås et foredrag om dette nye vindunderet – her er noen høydepunkt.

Anders tok oss med på en syretripp gjennom browsernes historie, som ender med IE8, som endelig er en browser fra Microsoft som støtter standardene! Det har vi ventet lenge på, og er en kjempefin nyhet. Fra nå av skal vi kunne kode websider med ett sett med javascript og ett sett med CSS, og så fungerer det likt i IE8, FF, Opera, Safari osv. Knallbra, velkommen i det gode selskapet, IE.

Eneste skåret i gleden er at enkelte av våre kunder selvsagt fortsatt kommer til å bruke både IE7 og IE6, og at vi derfor må fortsette å teste alt vi lager på disse :(

Videre fortalte Anders om bl.a. disse nye featurene:

I IE7 og FF2 fikk man search providers, og det er jo kult, men nå har man tatt det minst tre hakk videre: IE8 Accelerators er en kul ting som man som leverandør kan benytte for å øke brukerens opplevelse.., det samme er web slices. Begge deler kan man også benytte i FireFox (med extensions), så man utvikler ikke utelukkende for IE om man benytter disse nyvinningene.

Det er derimot ikke tilfelle om man ønsker å benytte seg av AJAX utvidelsene i IE8, som f.eks:

  • cross domain requests
  • cross document messaging
  • ajax navigation (mulighet for god “back” funksjonalitet vha et nytt onHashChange event)
  • ajax dom storage (superman cookies – dette er et forslag fra W3C, men ikke implementert i andre browsere enda)
  • connectivity events (events og properties for å informere/sjekke om man er online/offline)

Her innfører man altså igjen IE spesifik kode og muligheter, og det var jo det vi ville unngå, var det ikke? Skal de da aldri lære?

Det som derimot så veldig bra ut var den innebygde JavaScript debuggeren og verktøyet for å inspisere og modifisere DOM’en, CSS’en o.l. Spesielt debugging av JavaScript har aldri fungert helt bra – det nermeste man kommer er en plug-in i FireFox som er sånn passe. I IE8 får man full debuggings-opplevelse tilsvarende Visual Studio, og dette bør være insentiv nok for webutviklere til å installere betaen med en eneste gang.

Men det aller mest imponerende var vel egentlig at Anders Nordås klarte å forelese i en hel time om noe så skjedelig som IE8 – og faktisk gjøre det både morsomt og spennende. To tomler opp til deg!

Fußball Manager versjon 2.0

Fußball Manager, en web app jeg har laget for å holde oversikt over spilte fussball (eller foosball) kamper, har nå vært “i produksjon” i Contiki R&D i ca 10 måneder. Vi bestemte oss for å avslutte 2007/2008 sesongen i dag, og Øystein ble den verdige vinneren. På mandag sletter vi all historikk og starter med blanke ark.

I den forbindelse ville jeg forbedre verktøyet litt, så i kveld har jeg utviklet Fußball Manager versjon 2.0. Utvidelsen er en liga-modul. Man kan legge til registrerte spillere i en liga, bestemme hvor mange kamper den skal bestå av – og så genererer manageren alle kampene.

fuss_league1.jpg

Når man så spiller og registrerer kamper så kan man velge (om man har blitt enige om det på forhånd) å også registrere den som en gjeldende liga-kamp. På bildet under kan du se hvordan liga-oversikten ser ut.

fuss_league2.jpg

Så i tillegg til å konkurere om den beste ratingen som tidligere kan man altså nå også konkurrere om en liga-plassering. Jeg håper dette blir godt mottatt på mandag.

Les tidligere artikler om Fußball Manager her og her.


Einar W. Høst: Det er jo læringen som gjør det morsomt! Se også http://norvig.com/21-days...

Pagliacci: OBS! tl;wr. Det er vel akuratt det jeg sliter med med min læring innenfor pr...

Torbjørn: La oss anta to ulike definisjoner av Template Method pattern - de to ytterpunkte...

Lars-Petter: Hei igjen. Siden du inviterer til å ta diskusjonen i bloggen, og har tatt deg t...

Torbjørn: Lars-Petter: Det er én måte å se det på. Det er absolutt fortsatt Template M...

Lars-Petter: Hei. Har du ikke i prinsippet her gått over fra Template Method (arv) til Strat...

Christian Abildsø: I alle fall i C#, så føles dette som kode som blir mer fleksibel men vanskelig...

Torbjørn: Hei Henrik, og takk for tilbudet. Ble oppmerksom på Rasberry Pi for under en uk...

Henrik Sandaker Palm: Ang. større hobby prosjekt. Du er som er en slik rakker på programmering har j...

Øivind Nilsen: Slutt å bruke mobilnummeret mitt som eksempel !...

 Hold deg oppdatert

Søk i bloggen

Ferske innlegg

  • En historie om programmering
  • Template Method del 4: Multippel arv
  • Template Method Intermesso
  • Template Method del 3: Bare funksjoner
  • Kategorier

  • .net ninja (37)
  • Bøker (17)
  • Diverse prosjekter (35)
  • DSL (10)
  • Erlang (10)
  • F# (5)
  • Hardware (1)
  • Jobb (77)
  • Julekalender (51)
  • kjempekjekt.com (23)
  • LISP/Clojure (33)
  • NNUG / community (60)
  • O/RM & databaser (10)
  • Off topic (116)
  • OO-design/clean code (30)
  • Podcasts (14)
  • Polyglot (77)
  • Ruby (27)
  • Silverlight / RIA (3)
  • Software/verktøy (20)
  • Softwareutvikling (21)
  • Testing / TDD (30)
  • the contiki strip (13)
  • User experience (3)
  • WCF (3)
  • Webutvikling (32)
  • WPF (9)
  • WTF (12)
  • Last ned Wallpaper

    Programmeringsbloggens tøffe skrivebordsbakgrunn med snippets fra ulike språk laster du ned her!

    Abonner via epost

    Om du vil kan du få alle nye blogposter tilsendt til din epost. Abonner nå, det er kjempeenkelt!

    Meta