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.

Conway’s Game of Life

I kveld har Bergen CodingDojo hatt sitt andre møte. Jeg skulle vært med, men måtte desverre trekke meg i siste liten pga. sykdom.

Oppgaven det skulle jobbes med i dag var Conway’s Game of Life. Dette er en god dojo-oppgave fordi det er mange måter å angripe problemet på, og det finnes flere løsninger med ulike kvaliteter. Corey Haines og de andre som arrangerer Code Retreats rundt omkring i verden bruker også denne oppgaven. Er du interessert i å vite mer om hva det er for noe anbefaler jeg å ta en titt på Corey’s introduksjon til en Code Retreat som ble arrangert i Cleveland.

Jeg løste Game of Life i forrige uke i påvente av kveldens dojo. Da brukte jeg CoffeeScript og HTML. Jeg brukte ingen enhetstester, men testet interaktivt i browseren hele tiden.

Og jeg tok det opp på video. Har du 12 minutter til overs kan du se hva jeg gjorde. Bruk full screen, og pass på at du ser den i HD. Skru også opp lyden, for jeg la på litt kul musikk.

Conway & Coffee from Torbjørn Marø on Vimeo.

Etter at jeg lagde videoen utvidet jeg også løsningen til å støtte et uendelig grid. Har du Chrome (virker i alle fall ikke i IE) kan du se løsningen live her (pass på, den begynner å bli ressurskrevende etterhvert hvis griddet vokser seg stort).

Vi jobbet også med Conway’s Game of Life i en intern coding dojo i PSWinCom i forrige uke, og vi har tenkt å gjøre det igjen i flere uker fremover – som en Code Retreat strukket utover i tid. Og vi begynner på nytt hver gang – fokuset er ikke å fullføre en komplett løsning, men å trene på å skrive “perfekt kode”.

Nå er jeg spent på å høre hvordan det har gått på kveldens dojo…

CoffeeScript

CoffeeScript er et rykende ferskt språk som rett og slett forsøker å fikse alle problemene med JavaScript. Koden kompileres ned til JavaScript, og har en syntaks inspirert av Ruby, Python og Haskell. CoffeeScript gir deg som webutvikler også noen nye muligheter som list comprehensions, pattern matching, og klasse-basert objektorientering.

coffeescript_legacy

CoffeeScript er mye mer kompakt og elegant enn JavaScript, og har blitt godt mottatt av mange utviklere. Språket er blant annet inkludert i Ruby on Rails, og er også mye brukt på serversiden i Node.js. For noen måneder siden gikk også utviklingsteamet mitt over fra JavaScript til å skrive CoffeeScript, uten nevneverdige problemer.

coffeescript

CoffeeScript-compilatoren er skrevet i JavaScript, og selve kompileringen av scriptene kan derfor skje i browseren. Men dette er selvsagt ikke optimalt – det normale er at man som en del av build-prosessen genererer JavaScript-filer fra CoffeeScript’ene.

For .NET, som er vår plattform, finnes det også HTTP-handlers som kompilerer CoffeeScript on the fly, og server ut JavaScript. Dette er veldig praktisk under selve utviklingen.

La oss se på litt kode

Da er det på tide å løse Euler1-oppgaven igjen. Jeg skriver her CoffeeScript-kode som jeg tenker vil bli konvertert til JavaScript og plassert i en webside. Svaret vises ved hjelp av en alert-box.

Her er en enkel, imperativ kodesnutt som finner summen av alle multipler av 3 eller 5 under 1000:

 2 answer = 0
 3 for n in [1...1000]
 4   if n % 3 is 0 or n % 5 is 0
 5     answer += n
 6 alert answer

Koden kompileres til JavaScript’et nedenfor. Her ser du at CoffeeScript blant annet har “ranges” man kan iterere over, og  at koden bruker ord som is og or for å bli mere leservennlig. Du kan også se at den kompilerte koden følger best practises, og er wrappet inn i et funksjonskall, slik at det ikke opprettes noen variabler i det globale navnerommet.

10 (function() {
11   var answer, n;
12   answer = 0;
13   for (n = 1; n < 1000; n++) {
14     if (n % 3 === 0 || n % 5 === 0) {
15       answer += n;
16     }
17   }
18   alert(answer);
19 }).call(this);

Nedenfor har jeg laget en løsning til, som viser hvordan man oppretter funksjoner i CoffeeScript. Den bruker også en if bak et uttrykk, en teknikk arvet fra Ruby. Og numbers-variabelen settes ved hjelp av en list comprehension som utfører selve filtreringen.

10 multipleOf = (n, d) -> n % d is 0
11 
12 multipleOf3or5 = (n) ->
13   for divisor in [3,5]
14     return yes if multipleOf(n, divisor)
15 
16 numbers = (n for n in [1...1000] when multipleOf3or5 n)
17 
18 answer = 0
19 answer += n for n in numbers
20 alert "The answer is #{answer}!"

Den nest siste linjen som summerer opp tallene er også litt snedig, og den aller siste linjen viser at CoffeeScript støtter string interpolation. Og å kunne returnere “yes” i stedet for true fra multipleOf3or5 er jo også litt søtt da :)

Prototyping og monkey patching

JavaScript er jo et språk som støtter prototype-basert objektorientering. Her viser jeg hvordan jeg kan bruke dette i CoffeScript for å løse Euler1-oppgaven. Først oppretter jeg en isMultipleOf-metode på alle tall. Deretter kan jeg lage en fin multipleOf3or5-funksjon som bruker dette.

24 Number::isMultipleOf = (d) -> this % d is 0
25 
26 multipleOf3or5 = (n) ->
27   n.isMultipleOf(3) or n.isMultipleOf(5)
28 
29 Array::sum = ->
30   answer = 0
31   answer += n for n in this
32   return answer
33 
34 alert do (n for n in [1...1000] when multipleOf3or5 n).sum

Den tredje funksjonen opprettes som en metode på Array – den summerer opp alle tallene i arrayet. Til slutt bruker jeg list comprehension til å filtrere en range, og så kalle sum-metoden jeg lagde på resultatet.

Klasse-basert abstraksjon

CoffeeScript introduserer også en abstraksjon for klasse-basert objektorientering. Dette lar deg implementere klasser tilnærmet slik man gjør det i språk som f.eks. Ruby, og kompilatoren gjør dette om til prototype-basert JavaScript-kode.

Her følger klassen EulerProblem1 som har en kontruktør og to metoder. @limit og @sum er instansvariabler – den siste brukes til a cache resultatet av kalkuleringen. Selv om jeg sier calculate flere ganger vil selve kalkuleringen bare skje én gang slik jeg har valgt å gjøre det.

38 class EulerProblem1
39   constructor: (@limit) -> @sum = null
40 
41   include: (n) -> n % 3 is 0 or n % 5 is 0
42 
43   calculate: ->
44     if not @sum?
45       @sum += n for n in [1...@limit] when @include(n)
46 
47 ep1 = new EulerProblem1 1000
48 do ep1.calculate
49 alert ep1.sum

I de tre siste linjene ser du hvordan jeg oppretter en instans av klassen, hvordan jeg kaller metoden calculate, og hvordan jeg henter ut summen.

Hvorfor bruke tid på CoffeeScript

De fleste av oss har et forhold til JavaScript. Dette forholdet er gjerne litt ambivalent. JavaScript blir viktigere og viktigere for å kunne tilfredstille de økte forventningene til dagens webløsninger, men JavaScript er et språk med mange svakheter. Da er det interessant at man ikke kode i JavaScript direkte, men kan velge et renere og rikere språk som “kompileres” til JavaScript.

Det er viktig å poengtere at du kan benytte alle JavaScript-biblotekene du er vandt med også i CoffeeScript.

Er du Python- eller Ruby-utvikler er det nesten garantert at du kommer til å like CoffeeScript bedre enn JavaScript. Du bør uansett forsøke det, og så vurdere om det er verdt å legge denne ekstra abstraksjonen over JavaScript i akkurat ditt tilfelle.

Kan man bruke Coffee uten å kunne JavaScript?

Svaret på dette spørsmålet er desverre nei. Det finnes ikke enda (så vidt jeg vet) noen måte å debugge CoffeeScript på. Får man problemer vil man derfor få behov for å se på og debugge den genererte javaScript-koden. Koden er derimot helt grei, så dette er ikke et stort problem. Men man må kunne JavaScript!

Hvordan komme igang

Den offisielle CoffeeScript-siden finner du her. Den har en god primer som side-ved-side sammenligner CoffeeScript og JavaScript. Der kan du også teste språket direkte i browseren din.

Mye av det som finnes for å ta i bruk CoffeeScript er tilrettelagt for Linux og node.js-brukere. Hvis du er en Windows-bruker bør du ta en titt på CoffeeSharp, som gir deg det meste av hva du trenger.

JavaScript revolution

JavaScript har i løpet av 15 år gått fra å være et forferdelig mareritt til å bli en av de mest spennende og pulserende teknologiene man kan holde på med. Det skjer så mye rundt JavaScript for tiden at det rett å slett er vanskelig å henge med.

Denne artikkelen er et forsøk på å skape en oversikt over viktige open-source biblotek det kan være nyttig å vite om. I takt med modningen av HTML5 har jeg blitt mer og mer interessert i JavaScript-utvikling det siste året. Denne listen inneholder noen ting jeg har testet ut, men vel så mange ting jeg ikke har jobbet med, men ønsker å få sett nærmere på i tiden fremover.

Finner du noen åpenbare mangler i listen min – spennende biblotek eller rammeverk jeg har utelatt – så må du slenge inn en kommentar!

De generelle bibloteken

Først og fremst bør alle webutviklere kjenne til det jeg tenker på som de store, generelle JavaScript/Ajax-biblotekene. Jeg tenker da på Prototype, DOJO, Moo Tools, YUI Library, og sist men ikke minst jQuery, som er det som nå er aller mest populært. Siden jeg bruker jQuery selv, ser jeg ingen åpenbar grunn til å se på de andre.

jQuery har som kjent også et hav av plugins for alt mulig man kan komme til å trenge. Det kan være viktig å lete litt blant dem før man begynner å lage noe selv.

JavaScript også utenfor browseren

JavaScript er et kraftig språk med noen av de raskeste, dynamiske tolkerne (interpreters) som finnes. Og det brukes til langt mer enn å bare lage websider. Node.js er det mest populære rammeverket som tar JavaScript server-side, og er basert på Google’s V8-motor som kjører i Chrome. Jeg har lekt meg litt med Node tidligere, og synes det er veldig spennende.

CommonJS er et initiativ som skal definere et standard API for JavaScript utover det som språket selv definerer. Fokuset her er nettopp på det å bruke JavaScript utenfor browseren – til å lage server-applikasjoner, kommandolinje-verktøy, desktop GUI-applikasjoner, og hybridapplikasjoner i f.eks. Titanium og Adobe AIR. Titanium har jeg også testet litt, og det er et veldig spennende alternativ hvor du lager programmer som kjører på Windows/Mac/Linux ved å bruke HTML og CSS pluss en valgfri kombo av JavaScript, Ruby og Python.

Når jeg sier JavaScript så mener jeg forresten egentlig CoffeeScript. Dette er en rykende ferskt språk som kompileres ned til JavaScript. Man kan bruke alt som finnes av biblotek fra JavaScript-verdenen, men koder selv i en mye mere behagelig syntaks. Jeg har allerede konvertert teamet mitt på jobben til å bruke CoffeeScript fremfor JavaScript, og anbefaler deg til å vurdere det samme.

Noen sentrale byggeklosser

RequireJS laster JavaScript-filer og moduler. Å bruke dette vil gjøre løsningen din både raskere og enklere å holde oversiktelig etterhvert som den vokser seg større. RequireJS gjør det enklere for deg som utvikler å lage større JavaScript-løsninger, samtidig som den optimaliserer selve deploymenten av løsningen.

Underscore.js er en verktøykasse som gir JavaScript bedre støtte for funskjonell programmering. Her finner du rundt 60 generelle funksjoner som each, map, select, reduce, range osv.

HTML5_Logo_128

Modernizr er et biblotek som skal hjelpe deg å bygge neste generasjons HTML5- og CSS3-løsninger som også vil virke for dem som bruker browsere som ikke støtter de nye featurene. Dvs., Modernizr utfører ikke mirakler – det får ikke disse nye tingene til å virke i gamle browsere – men det forteller deg hva som virker, slik at du kan ta høyde for det og kode deretter.

WebSockets har potensialet til å revolusjonere hvordan vi lager rike webapplikasjoner, og er noe av det aller mest spennende som ligger i HTML5-standarden (en bra presentasjon om dette). Socket.IO er et biblotek som skal gi deg realtime apps, uavhengig av hvilken browser eller mobil-device brukeren har. Det bruker WebSockets om det er tilgjengelig, og faller tilbake på andre løsninger om det ikke er det. Socket.IO kan også brukes på server-siden i f.eks. Node.js.

Og så må jeg få nevne Date.js, et lite biblotek som lar deg jobbe med datoer i JavaScript på en enkel måte.

MVC-aktige rammeverk

Nå har vi kommet til de rammeverkene som skal legge til rette for å lage JavaScript-tunge webløsninger. Jeg tenker da spesielt på såkalte single-page JavaScript applications. GMail er et typisk eksempel på en sånn app.

Backbone.js gir deg (meget kort fortalt) muligheten til å lage datamodeller, definere views, og å knytte disse sammen med en toveis databinding. Backbone.js bruker også Underscore.js for å tilby et rikt API.

Sammy.js er et lite men veldig spennende rammeverk som lar deg designet single-page JavaScript apps etter en restfull tankegang med ruter (routing). Du kan bruke ulike template/rendering-motorer, og Sammy føles både enkel og elegant.

Brunch beskrives også som et lettvekts rammeverk for å lage HTML5-applikasjoner med fokus på eleganse og enkelhet. Det kombinerer CoffeeScript, Backbone.js, Underscore.js, jQuery og flere andre biblotek til en pakke for å lage MVC-lignende løsninger.

Andre rammeverk jeg har fått med meg som er populære, men som virker noe større (men ikke dårligere av den grunn) inkluderer SproutCore, Cappuccino og Sencha. For rendering / templates finnes det enda flere muligheter, som Eco, Stitch, mustache, EJS, pure og meld. Ett av disse bør man nok lære seg å bruke.

Grafikk og effekter

Det finnes mange, gode biblotek for å lage ulike typer grafer, men jeg orker ikke liste dem her. Det finnes også flere biblotek som fokuserer på å tilby ulike JavaScript-effekter, som f.eks. Script.aculo.us.

$fx() er et annet biblotek for å animere HTML-elementer. Med bare 4k JavaScript lar det deg endre CSS-properties over en tidslinje på en ganske så elegant måte. Er du kreativ kan du lage noen veldig spennende websider med dette kompakte scriptet.

Er du en av dem som behersker 3D-grafikk er WebGL noe du bør se på. Ved å bruke canvas-elementet i HTML5 gir det deg 3D rett i browseren, uten å bruke plug-ins. WebGL er basert på OpenGL.

Og er du helt sprø så lærer du deg Processing.js. Processing er et programmeringsspråk og en utviklingsplattform for å lage elektronisk kunst og visuelt design, og Processing.js er en portering av dette til JavaScript. Ta en titt på linken for å se hva du kan gjøre med det.

Testdreven JavaScript

Når det kommer til testing så virker det som om det mest populære rammeverket en stund har vært QUnit (det er det jQuery bruker). Et alternativ som bruker begreper som er mer kjente for dem som driver med BDD er Jasmine. I tillegg kan det være nyttig å bruke Sinon.JS for mocking, og jsTestDriver for å kjøre testene.

Buster.JS er et annet testrammeverk som det snakkes mye om, men som ikke har nådd noen release enda. Det virker som det vil være kompatibelt med QUnit, bruke Sinon.JS for mocking, ha BDD-syntax for dem som ønsker det, og ha støtte for det samme som man finner i jsTestDriver. Her blir det altså en mere komplett løsning i én pakke.

Headless browser

Helt til slutt vil jeg nevne PhantomJS. Dette er et kommandolinje-verktøy som inneholder en “usynlig” web-browser. Man kan gjøre alt man kan gjøre med en vanlig browser, og styre den med JavaScript. Dette egner seg veldig godt til ting som testing av webapplikasjoner, “webskraping”, og mye, mye mer om du har litt fantasi.

Mye å sette klærne i her altså. Har du noen erfaring med disse biblotekene som du vil dele?

Mist får en side

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

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

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

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

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

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

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?!


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 !...

Bjørn Einar Bjartnes: Jeg har også latt meg fascinere av Clojure, uten at jeg har kommet så veldig l...

Bjørn Einar Bjartnes: Sweet :) Jeg tror egentlig jeg liker det som det er, med musikk. Litt av utford...

 Hold deg oppdatert

Søk i bloggen

Ferske innlegg

  • Template Method del 4: Multippel arv
  • Template Method Intermesso
  • Template Method del 3: Bare funksjoner
  • Template Method del 2: På vei mot funksjonell programmering
  • 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 (20)
  • 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