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.

Mist får en side

Sunday, September 4th, 2011
6 kommentarer

Denne blogposten presenterer den nye websiden jeg har laget for programmeringsspråket Mist, samt de rundt 20 linjene Ruby-kode som skulle til for å generere siden.

Ethvert programmeringsspråk trenger en egen side – i alle fall om andre enn designeren selv skal bruke det. Og nå har jeg som sagt begynt på en side for Mist. Den har ikke så mye innhold enda, men design og struktur er på plass. Her er et screenshot (klikk for å gå til siden):

mist_page

Siden skiller seg bort fra ting jeg har gjort tidligere på flere punkter. Blant annet har jeg innsett at HTML ikke er XML, og har nå gått for mere pragmatisk HTML5, hvor jeg blant annet har droppet ting som HTML, HEAD og BODY-tags (de skal faktisk være helt unødvendige). Jeg har også brukt mye absolutt posisjonering, og til og med litt fixed. Jeg har satset på rent design og ren markup, og er ikke nervør om noen skulle velge å titte på koden.

Jeg har også oppdaget Google Web Fonts, som lar meg inkludere et hav av ulike skrifttyper på sidene uten store problemer. Eneste faren er at jeg kanskje går litt for langt, sånn som man ofte gjør når man får et nytt leketøy. Synes du jeg har gjort det?

Generering av statiske websider med Ruby

Mist-siten er hostet som Github Pages, tilknyttet Github repositorien. Sider som serves på denne måten må være statiske html-sider. Jeg ville derimot basere siten min på en template, så for å ikke måtte repetere meg selv måtte jeg generere sidene før jeg lastet dem opp.

For dette formålet støtter Github Pages et verktøy som heter Jekyll, som jeg har brukt tidligere, og som lar deg generere statiske websider basert på maler. Denne gangen valgte jeg likevel å lage mitt eget opplegg basert på kun noen få linjer Ruby.

Først lagde jeg en fil som jeg kalte genlib.rb. Den inneholder to funksjoner: Den første leser malen som er lagret i filen template.html, og returnerer den som en streng. Den andre – generate – tar inn en hash med parametre, henter ut malen, fletter inn det som er sidespesifikt i malen, og lagrer resultatet som en html-fil.

10 def template
11   template = ''
12   File.open('template.html', "r") do |file|
13     while (line = file.gets)
14       template += line
15     end
16   end
17   return template
18 end
19 
20 def generate args
21   name = args[:file] + ".html"
22   File.open(name, "w") do |file|
23     file.puts template.
24       gsub(/\{CONTENT\}/, args[:content]).
25       gsub(/\{QUOTE\}/, args[:quote]).
26       gsub(/\{TITLE\}/, args[:title])
27   end
28   puts "Generated file #{name}"
29 end

For hver siden jeg skal generere lager jeg så en ny fil som skal kalle generate-funksjonen. Nedenfor er gen_download.rb, som genererer download.html. Den definerer ønsket filnavn (linje 13), sidetittel (14), et sitat som skal brukes i toppen av siden (16-23) og selve innholdet på siden (25-33). Til slutt kaller den generate, og siden blir produsert.

10 require "./genlib"
11 
12 page = {}
13 page[:file] = "download"
14 page[:title] = "Download Mist"
15 
16 page[:quote] = <<EOF
17 <p class="quote">
18     "Language designers are not intellectuals.<br/>
19     They're not as interested in thinking as you might hope.<br/>
20     They just want to get a language done and start using it."<br/>
21     - Dave Moon
22 </p>
23 EOF
24 
25 page[:content] = <<EOF
26 
27 <h1>Download Mist</h1>
28 <p>
29   No downloads here yet! Get the source from 
30   <a href="https://github.com/tormaroe/mist">Github</a> 
31   if you're interested.
32 </p>
33 EOF
34 
35 generate page

Til slutt laget jeg en fil jeg kalte gen.rb. Den henter ut og kjører alle filer som har et navn som begynner på “gen_”. Ved å kjøre gen.rb vil jeg dermed få generert opp alle de statiske sidene mine, klare for opplasting til serveren.

1 if __FILE__ == $0
2   Dir.foreach(".") {|f| f.match(/gen_/) { load f } }
3 end

Alternativt kunne jeg har brukt Ruby ERB templating (ala klassisk ASP eller PHP), eller kanskje et annet templating system, for å generere filene. Men for mitt formål valgte jeg altså denne gangen en mere basic løsning.

Har du noen bemerkninger til Mist, webdesignet, det kommende innholdet, eller til Ruby-koden min? Nøl ikke med å legge igjen en kommentar!

Følgefredag: @magnars

Friday, September 2nd, 2011
1 kommentar

magnarsDet er fredag igjen, og jeg fortsetter med å anbefale spennende folk å følge på twitter om man er norsk utvikler. Og i dag presenterer jeg Magnar Sveen, en glad framsideutvikler med Mastergrad fra NTNU, som jobber og er deleier i konsulentselskapet Kodemaker. For tiden er det først og fremst FINN som får nyte godt av Magnars kompetanse og kreativitet.

Magnar er ganske aktiv på Twitter. I tillegg har han en meget solid blogg han kaller Framsideutvikling, hvor han blogger om ting som HTML5 og JavaScript – inkludert jQuery og testdreven webutvikling. Dessuten har han startet et meget kult screencast-prosjekt om testdreven javascript, zombier og mafia på zombietdd.com. Veldig lærerikt!

zombietdd

Sjekk også ut pomodoro-verktøyet Magnar har laget på mytomatoes.com, og eventyrspillet Adventur Delux. På twitter avslørte han også for noen dager siden at han holder på å lage et nytt scriptspråk for Adventure, så det er klart at Magnar behersker litt av hvert.

Så hvis du driver med webutvikling er dette en fyr du helt sikkert kan lære mye av!

Min første Node.js server

Wednesday, July 6th, 2011
3 kommentarer

Node.js er en cutting edge plattform som skal gjøre det enkelt, eller i alle fall enklere, å lage skalerbare nettverksprogrammer. Den er bygget på toppen av V8, Googles JavaScript-motor som kompilerer JavaScript til maskinkode før den kjøres (i motsetning til å kompilere til bytekode, eller tolke koden).

I motsetning til de fleste, tilsvarende plattformene baserer ikke Node.js sin skalerbarhet på tråding. Node-kode består i å knytte en rekke callbacks opp mot events, og så sover programmet til et av disse eventene inntreffer. Hvert event – f.eks. hver connection i en webserver – bruker veldig lite minne, og blokkerer aldri prosessen. Dessuten er dead-locks helt umulig, for siden det ikke finnes tråder finnes det heller ingen locks.

Node.js integrert med Intouch

Som et første eksepriment med Node.js har jeg laget en mini-website som lister opp mine Intouch-kontakter. PSWinCom Intouch er en webbasert klient for mobil kommunikasjon. Den eksponerer et REST-api som gjør at jeg blant annet kan hente ut informasjon fra kontoen min i XML eller json-format.

Først lager jeg en statisk html-fil som skal vise kontaktene. Den bruker litt jQuery-magi for å hente kontaktene fra Node.js-serveren og viser dem i siden. Jeg kunne selvsagt generert html’en for kontaktene på server-siden, men synes egentlig det er bedre å bruke en Ajax-løsning.

nodejs

UML-diagrammet over viser kommunikasjonsflyten. Jeg har også forsøkt å illustrere forskjellen på en Node.js-basert server og en vanlig webserver som Intouch-serveren representerer; Node.js blokkerer ikke, men er bare aktiv når den har noe å gjøre.

index.html ser ut som dette:

 1 <html>
 2   <head>
 3     <title>My Intouch Contacts</title>
 4     <script type="text/javascript" src="jquery.min.js"></script>
 5     <script type="text/javascript">
 6 
 7     var loadContacts = function() {
 8       var formatContact = function(contact) {
 9         return $("<div>").append(
10           "<b>Name:</b> " + contact.Firstname + 
11           " " + contact.Lastname +
12           " <b>Phone:</b> " +  contact.PhoneNumber);
13       };
14       $.getJSON("/contacts", function(contacts) {
15         $.each(contacts, function() {
16           $("#contacts").append(formatContact(this));
17         });
18       });
19     }
20 
21     $(function() {
22       loadContacts();
23     });
24     </script>
25   </head>
26   <body>
27     <h1>Intouch Contacts</h1>
28     <div id="contacts"></div>
29   </body>
30 </html>

Serveren jeg lager må altså både kunne levere ut index.html og sende kontaktene. Her følger server-koden i sin helhet. Merk at jeg er helt n00b i Node.js, og har klippet og limt litt fra diverse eksempler for å få dette til å virke. Følgende kildekode lagret jeg i en fil jeg kalte server.js.

 1 var sys = require("sys"),
 2     http = require("http"),
 3     url = require("url"),
 4     path = require("path"),
 5     fs = require("fs"),
 6     rest = require("restler");
 7 
 8 function load_static_file(uri, response) {
 9   var filename = path.join(process.cwd(), uri);
10   path.exists(filename, function(exists) {
11     if(!exists) {
12       response.writeHeader(404, {"Content-Type": "text/plain"});
13       response.write("404 Not Found\n");
14       response.close();
15       return;
16     }
17 
18     fs.readFile(filename, "binary", function(err, file) {
19       if(err) {
20         response.writeHead(500, {"Content-Type": "text/plain"});
21         response.end(err + "\n");
22         return;
23       }
24 
25       response.writeHeader(200);
26       response.end(file, "binary");
27     });
28   });
29 }
30 
31 http.createServer(function(request, response) {
32     var uri = url.parse(request.url).pathname;
33     if(uri === "/") {
34       load_static_file("index.html", response);
35       return;
36     }
37     else if(uri === "/contacts") {
38       rest.get("http://intouchapi.pswin.com/1/contacts", {
39           username: 'myuser@mydomain',
40           password: 'mypassword',
41         }).on('complete', function(data) {
42           response.writeHeader(200, { "Content-Type" : "application/json" });
43           response.end(JSON.stringify(data));
44       });
45     }
46     else {
47       console.log("Not supported request " + uri);
48       response.writeHeader(404, {"Content-Type": "text/plain"});
49       response.end("404 Not Found\n");
50     }
51 }).listen(8080);
52 
53 sys.puts("Server running at http://localhost:8080/");

Linje 8 til 29 er kun en funksjon for å serve statiske filer, og det aner meg at det finnes enklere måter å gjøre dette på. Selve serveren registreres på linje 31, hvor jeg legger opp til tre muligheter…

Hvis requesten er “/”, leverer jeg ut index.html-filen. Hvis requesten er “/contacts” gjør jeg et REST-kall til Intouch, og når jeg får svar tilbake derfra sender jeg det bare videre. For alle andre requester svarer jeg tilbake med status 404 Not Found.

Og det var det! Når jeg kjører kommandoen “node server.js” i konsollet, og deretter åpner opp http://localhost:8080/ i en browser, får jeg et resultat som ser ut omtrent som dette:

Intouch Contacts

Name: Ola Nordman Phone: 90807060
Name: Kari Nordman Phone: 90807061
Name: Thor Divel Phone: 90807062
Name: Bob Kåre Phone: 90807063

Mulige utvidelser av denne mini-siten, som vil være ganske enkelt å få til, kan for eksempel være å gi brukeren mulighet til å trykke på en kontakt for å sende ham/henne en SMS-melding. Jeg kunne også ha listet ut kontakt-gruppene mine fra Intouch, og gitt mulighet for å distribuere en SMS til hele gruppen. Mulighetene er mange!

Hackaton

Sunday, May 22nd, 2011
2 kommentarer

CIMG0625

Forrige uke hadde utviklerne i PSWinCom noe vi kalte for et Hackaton. Vi skulle lage en ny versjon av vår kontoweb; ikke en av de viktigste løsningene våre, men viktig nok for kundene som bruker den. Vi satte av to dager hvor vi skulle fokusere 110% på denne oppgaven. Og så leide vi et egnet lokale med to prosjektører, slik at vi kunne sitte sammen alle fire og jobbe på to mega-skjermer, uforstyrret av kontorets daglige “kjas og mas”.

Vi var forberedt på å kutte noen hjørner for å få til så mye som mulig, og vi var veldig spente på hvor mye funksjonalitet vi kunne få på plass på de ca 18 timene vi hadde til rådighet.

Noen tekniske valg

Vi er først og fremst .net-utviklere, og skulle lage en asp.net-løsninger. Vi har ingen erfaring med ASP.NET MVC, og gikk derfor for WebForms.

For CRUD-funksjonaliteten i kontowebben hadde vi snakket om å benytte DynamicData, men vi så etterhvert at vi ville få behov for ganske mye spesialtilpasninger, og droppet derfor dette til fordel for å designe våre egne CRUD-grensesnitt fra scratch. For databaseaccess brukte vi Linq to SQL, som er veldig enkelt å forholde seg til, og er det vi er mest vandt til fra tidligere.

På forhånd hadde vi snakket om å bruke SQL Server Reporting Services (SSRS) til å lage rapporter i løsningen, men etter litt vurdering frem og tilbake avgjorde vi at det var enklere å bare bruke ASP.NET ReportViewer direkte og lage rapportene i Visual Studio. Vi hadde ikke full kontroll på dette, og det tok lengre tid å finne ut av hvordan det fungerte enn vi hadde håpet, men vi fikk etterhvert til å legge et greit grunnlag for rapporter i løsningen.

første dagen..

..gikk mye raskere enn vi trodde. Det er frustrerende hvor lang tid enkelte ting tar. Men vi fikk på plass en site med et bra design, vi fikk på plass en relativt avansert autentiseringsløsning, vi fikk på plass funksjonalitet for å teste SMS-utsendelse, og vi fikk startet på noen andre ting.

På kvelden var vi ganske slitne, og det smakte godt med en felles middag på en bedre restaurant!

Andre dagen..

..gikk bedre, takket være grunnlaget vi hadde lagt dagen før. Vi fikk fullført mer av CRUD-funksjonaliteten, og fikk på plass grunnstrukturen for rapportering – men et par enkle rapporter.

Alt i alt synes jeg vi skal være fornøyde – eksperimentet var vellykket i mine øyne. Lokalet med en felles pult for fire utviklere og to storskjermer på veggen førte til et godt sammarbeid og god parprogrammering.

Noen uttrykte bekymring for at vi hadde “hacket” litt for mye, og skulle ønske at vi hadde tatt oss litt bedre tid på kodedesign. Det blir en avveining i forhold til hvor mye løsningen skal endres og vedlikeholdes fremover, men jeg tror det meste av det vi gjorde i løpet av disse dagene var godt nok. Det ligger mye verdi i å holde designet enkelt også, sålenge man klarer å unngå kodeduplisering.

Nå ser vi frem til å vise folkene på kontoret hva vi har fått til, få tilbakemeldinger, og etterhvert fullføre oppgaven i normale omgivelser.

PHP ikke djevelens verk likevel

Saturday, May 21st, 2011
6 kommentarer

Jeg har tidligere hevdet at utviklere som ønsker å lære seg et dynamisk programmeringsspråk bør holde seg langt unna PHP. Jeg tviler på at det finnes noe annet språk hvor det er skrevet like mye drittkode. Likevel tok jeg meg selv i å si på et forum nylig at jeg nå faktisk vurderer å anbefale dem som ønsker å begynne med webutvikling å starte med nettopp PHP.

Denne artikkelen handler om hvorfor jeg har endret holdning.

Min PHP-bakgrunn

DevilSom fersk IT-konsulent ble jeg kastet ut i et webprosjekt som skulle benytte PHP. På det tidspunktet hadde jeg bare erfaring fra Java og VB6, og hadde aldri hørt om PHP engang. Men det var lett å plukke opp språket, og jeg var produktiv allerede første dag.

Det er vanskelig å huske hva jeg følte for språket dengang, men jeg er ganske sikker på at jeg produserte en god del grisekode. Rammeverket hjalp meg ikke på noen måte å strukturere koden min orntlig, og det ble mye inline blanding av server-kode og HTML-markup.

Etter dette brukte jeg PHP sporadisk i noen år til å utvikle diverse, enkle registreringsskjema, spørreundersøkelser og lignende. De siste 6 årene har jeg ikke rørt språket i det hele tatt (bortsett fra en og annen minimal tweak på denne bloggen). Jeg har hørt at det har kommet til endel objektorienterte muligheter jeg ikke hadde (eller visste om) den gang, men har likevel ment at PHP stort sett er noe man bør holde seg unna om en har muligheten.

Fordelene med PHP

PHP har derimot noen fordeler man ikke bør avvise sånn helt uten videre. Den viktigste er at plattformen har en enorm spredning. Det finnes knapt nok en webserver i denne verden hvor man ikke kan kjøre PHP – i 2007 var PHP i bruk på 75% av alle webservere. Og i mange tilfeller, som hvis man leier plass på en delt linux-server, kan PHP være den eneste muligheten man har for å lage dynamiske websider.

Det finnes derfor også veldig mange PHP-utviklere, og det er lett å finne hjelp på nettet når man trenger det. Ulempen er at det finnes veldig mange “dårlige” PHP-utviklere, og veldig mange stygge eksempler på kode som er både vanskelig å forstå, er vanskelig å vedlikeholde, og som har andre alvorlige svakheter.

Språket er derimot veldig godt dokumentert på php.net. Det har også utviklet seg endel de siste årene; i versjon 5.3 (i 2009) fikk man f.eks. namespaces og støtte for closures / anonyme funksjoner.

Hvorfor jeg nå revurderer PHP

Grunnen til at jeg nå går tilbake på det jeg tidligere har sagt, og vurderer PHP som en ok plattform å starte på, er at jeg har oppdaget at det har dukket opp endel utviklingsrammeverk på toppen av PHP. CodeIgniter er et eksempel på et av disse, som er et Model-View-Controller-rammeverk som minner svært mye om Ruby on Rails. Symfony, CakePHP og Zend Framework er tre andre jeg har funnet i samme kategori, og det finnes sikkert flere.

Disse rammeverkene, som selvfølgelig er gratis, oppfordrer til utvikling av websites etter samme fornuftige malen som de populære rameverkene i f.eks. Ruby og Python. Det betyr at man går bort fra den grisete “smørja” som lenge har vært normen i PHP-verden – det er i alle fall det jeg håper!

Ikke at MVC er løsningen på alle problemer, eller den beste strategien for alle webapps. Men det representerer en felles forståelse av god kodestrukturering for dagens webutviklere, og nybegynnere bør etter min mening begynne der.

Foreløpig har jeg bare sett et par tutorials, men jeg har nå tenkt å teste ut ett eller flere av disse rammeverkene, og kanskje ta dem i bruk til noe fornuftig.

Script IIS Manager med IronRuby

Wednesday, March 23rd, 2011
3 kommentarer

Det er ikke ofte det går en hel måned mellom hver gang jeg blogger. Men den siste tiden har jeg slitt endel med nakkesmerter, så noe har desverre måttet vike. Energien er på vei tilbake, og jeg satser på å komme igang igjen med å blogge om PingLang og DSLer snart.

Men for å starte litt forsiktig kommer det her en liten blogpost om å automatisere konfigurering av Internet Information Server ved hjelp av IronRuby.

Jeg fikk nemlig nettopp behov for å laget et script som kunne endre den fysiske stien til en website i IIS. Vi har to ulike sites, la oss kalle dem thesite.com og thesite-staging.com. Den første adressen er produksjonsadressen, den andre bruker vi til testing.

På serveren har vi så to ulike, fysiske lokasjoner for disse sitene. Stiene kan for eksempel være c:\sites\thesite-blue\ og c:\sites\thesite-green\. Til enhver tid inneholder én av disse produksjonskoden, og den andre folderen brukes til å teste neste versjon. Når den nye vesjonen er godkjent bytter vi om de fysiske stiene til thesite.com og thesite-staging.com, slik at thesite.com nå inneholder den nye versjonen.

Dette kalles blue-green deployment.

For å kunne programmere slike ting kommer IIS med en assembly som heter Microsoft.Web.Administration – du finner den under katalogen Windows\System32\inetsrv.

The different logical objects available include sites, applications, application pools, application domains, virtual directories, and worker processes. You can use the API to obtain and work with the configuration and state of these objects and to perform such actions as creating a site, starting or stopping a site, deleting an application pool, recycling an application pool, and even unloading application domains.

Du kan bruke den i C#, fra PowerShell, eller hvilket som helst språk som kan kjøre på .net-plattformen. Jeg foretrekker IronRuby til denne typen oppgaver. Her er et script (et noe enklere script enn det jeg faktisk bruker) som henter ut den virtuelle katalogen til to IIS-sites og bytter fysisk sti mellom dem:

10 require 'c:\\Windows\\System32\\inetsrv\\Microsoft.Web.Administration.dll'
11 include Microsoft::Web::Administration
12 
13 # Monkey patch ServerManager: 
14 #   add get_vdir method to get the main virtual dir
15 class ServerManager
16   def get_vdir site
17     self.
18       sites[site].
19       applications['/'].
20       virtual_directories.
21       find {|vdir| vdir.path == '/'}
22   end
23 end
24 
25 server = ServerManager.new
26 
27 a = server.get_vdir 'thesite.com'
28 b = server.get_vdir 'thesite-staging.com'
29 
30 # Swapping to variables in Ruby is easy..
31 a.physical_path, b.physical_path = b.physical_path, a.physical_path
32 
33 server.commit_changes
34 server.dispose

Vanskeligere er det ikke!

C# strukket til det ugjenkjennelige

Tuesday, January 18th, 2011
Ingen kommentarer

serialsebFor en gangs skyld skal jeg poste noen andres kode her på bloggen. Jeg har nemlig kommet over et lite stykke C#-kode som jeg syntes var verdt litt ekstra oppmerksomhet. I vinter brukte vi i PSWinCom et rammeverkt som heter OpenRasta til å implementere et REST-API for vårt Intouch-produkt. OpenRasta er et open source-prosjekt utviklet av Sebastian Lambla, og det var her jeg oppdaget en mildt sagt spesiell utnyttelse av C#.

Du kan jo bedømme selv…

10     public class OperationResultPage : Element
11     {
12         public OperationResultPage(OperationResult result)
13         {
14             Root = this
15                 [html
16                      [head[title[result.Title]]]
17                      [body
18                         [h1[result.Title]]
19                         [p[result.Description]]
20                      ]
21                 ];
22         }
23 
24         protected Element Root { get; set; }
25     }

Når du ser koden for første gang tar det noen sekunder før hjernen aksepterer at det er C#-kode du ser på.

Gjennom serdeles ukonvensjonell bruk av C# har Sebastian rett og slett laget en ganske så fasinerende DSL for å definere HTML-markup. Det minner en god del om (og er helt sikkert inspirert av) tilsvarende DSL’er i mere dynamiske språk – som f.eks. Hiccup i Clojure.

Her er et par utdrag fra den abstrakte klassen OpenRasta.Web.Markup.Elements.Element, som kaster litt mer lys over hvordan koden kombinerer bruk av indeksere og properties for de ulike HTML-taggene til å kjede sammen markup på en helt nye måte.

 47         protected Element this[INode child]
 48         {
 49             get
 50             {
 51                 ChildNodes.Add(child);
 52                 return this;
 53             }
 54         }

..og..

 96         public IHtmlElement html
 97         {
 98             get { return Document.CreateElement<IHtmlElement>(); }
 99         }

Sebastian er en dyktig utvikler med smittsomt humør og pipete stemme som i tillegg til OpenRasta akkurat nå er kjent for prosjektet OpenWrap, et “pakkehåndteringssystem” for .NET (ala gems for Ruby). Jeg vet ikke om det er Sebastian som har kommet opp med denne DSL-teknikken, eller om det er noe du kan finne andre steder også, men det er liten tvil om at fyren er genial.

Så vil jeg bare avslutte med å foreslå en aktivite som garantert vil gjøre deg til en bedre utvikler: Les mer kildekode! Det finnes et hav av prosjekter der ute som du kan lære av. Hvorfor ikke begynne med OpenRasta for eksempel?!

PSWinCom lanserer nytt API og teknisk wiki

Thursday, November 25th, 2010
Ingen kommentarer

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

Monday, October 25th, 2010
5 kommentarer

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

Monday, February 22nd, 2010
6 kommentarer

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!

Siste kommentarer

best seo services company
I'm not sure where you are getting your information, but good topic. I needs to spend some time learning more or understanding more. Thanks for wonder...
Louis Vuitton Outlet
30 years old Kalamazoo-born Vitalia totally likes it barbecuing bicycling. Last but not least she is intrigued by charters and flights as an example, ...
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)). ...
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!