.net ninja

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

Jeg leker litt med Clojure i .NET

ClojureCLR

Nå har jeg endelig fått testet ut ClojureCLR, dvs. Clojure kjørende på .Net-rammeverket. Det er kjempeenkelt å komme igang – du bare laster ned en zip med bits herfra (anbefaler clojure-clr 1.2.0), pakker det ut et sted, starter et command-vindu og eksekverer Clojure.Main.exe. Hvis du ikke sender med en clojurekildefil som argument startes den interaktive REPL’en (Read Eval Print Loop) hvor du kan leke deg med språket.

CropperCapture[87]

Jeg jobber mye med MSMQ, og da jeg skulle teste ut Clojure i .NET føltes det derfor naturlig å starte med det. Denne blogposten består av noen eksempler på hvordan man kan bruke System.Messaging og meldingskøer fra ClojureCLR – og illustrerer dermed .NET-interopen, og hvordan den eventuelt skiller seg fra Java-interopen i “vanlig” Clojure.

Jeg begynner med en tom fil jeg kaller testqueue1.clj. Det første jeg må gjøre er å laste System.Messaging dll’en, og gjøre klassene jeg har tenkt å bruke tilgjengelige. Det gjør jeg på denne måten:

1 (System.Reflection.Assembly/LoadWithPartialName “System.Messaging”)
2 (import (System.Messaging MessageQueue
3                            MessageQueueTransaction
4                            XmlMessageFormatter))

Jeg har allerede en lokal, transaksjonell kø som heter testqueue, og jeg vil bruke denne fra koden min. Jeg definerer symbolet *queue* til å være en instans av MessageQueue, og setter også Formatter-propertien til en XmlMessageFormatter som håndterer strenger:

6 (def *queue*
7      (doto (MessageQueue. “.\\private$\\testqueue”)
8            (.set_Formatter (XmlMessageFormatter.
9                              (into-array Type [String])))))

Opprettelse av objekter og kall av metoder er akkurat som i Clojure for JVM. Der er ingen spesiell syntaks for properties, i stedet bruker man funksjonene som ligger bak propertiene (get_PropertyName og set_PropertyName). I linje 9 ser du også hvordan jeg konverterer en PersistanceVector om til et array av typen System.Type, som er det konstruktøren til XmlMessageFormatter trenger.

Og nå kan jeg opprette min første funksjon. Denne er en ganske enkel en som returnerer antall meldinger i køen:

11 (defn count-messages []
12       (-> *queue*
13           (.GetAllMessages)
14           (.Length)))

Deretter vil jeg lage én metode for å sende en melding og én metode for å hente ut en melding. Felles for disse to er at jeg trenger å opprette og bruke en transaksjon. For å unngå kodeduplisering lager jeg en “høyereordens funksjon” jeg kaller with-transaction. Den tar som innput en lambda som definerer hva som skjer i transaksjonen.

16 (defn with-transaction [f]
17       (let [transaction (new MessageQueueTransaction)]
18         (.Begin transaction)
19         (let [result (f transaction)]
20           (.Commit transaction)
21           result)))
22
23 (defn send-to-queue [message]
24       (with-transaction
25         #(.Send *queue* message %)))
26
27 (defn receive-one []
28       (with-transaction
29         #(.Receive *queue* (TimeSpan. 0 0 1) %)))

Når jeg utvikler i Clojure bruker jeg den interaktive REPL’en ganske flittig. Typisk jobber jeg i en eller flere tekstfiler samtidig som jeg har en REPL kjørende. I den kan jeg laste filene, og reloade dem når jeg har gjort endringer. REPL’en lar meg test/kjøre funkjonene jeg definerer med ulike innput, eller teste ut kode før jeg skriver den i kildekodefilen. Jeg kan til og med re-definere enkeltfunksjoner underveis om jeg ønsker det.

Nedenfor er et lite eksempel på hvordan jeg kan bruke REPL’en med testqueue1.clj som jeg nettopp har laget. Først laster jeg skriptet. Deretter kaller jeg funksjonene for å telle meldinger, sende melding, og hente ut melding. Legg merke til at jeg velger å lese ut Body-propertien på meldingen jeg leser, selv om receive-one returnerer et Message-objekt.

CropperCapture[88]

Det som skjedde i virkeligheten var at jeg gjorde disse tingene mens jeg definerte funksjonene. Og mellom hver gang jeg gjorde en endring kjørte jeg (require 'testqueue1 :reload) slik at REPL’en ble oppdatert med mine endringer. For et bra innblikk i hvordan det er å jobbe på denne måten anbefaler jeg blogposten Interaktiv programmering: utforsking, læring og produktivitet – skrevet av Thomas Kjeldal Nilsson.

.NET events i ClojureCLR

En annen ting jeg føler jeg bør vise er hvordan man bruker eventer i ClojureCLR. Når man skal bruke meldingskøenes asynkrone funskjonalitet trenger man å sette opp eventhandlere for å motta meldinger. ClojureCLR har en macro som heter gen-delegate for å opprette delegater. I linje 12 nedenfor bruker jeg den til å opprette on-receive-completed. Og i linje 26 ser du hvordan jeg kobler delegatet på eventet. Følgende er plassert i en fil jeg kalte testqueue2.clj:

1 (System.Reflection.Assembly/LoadWithPartialName “System.Messaging”)
2 (import (System.Messaging MessageQueue
3                            MessageQueueTransaction
4                            XmlMessageFormatter
5                            ReceiveCompletedEventHandler))
6
7 (declare handler) ; handler will point to a function later..
8
9 ; generate a delegate of type ReceiveCompletedEventHandler
10
11 (def on-receive-completed
12      (gen-delegate ReceiveCompletedEventHandler
13                    [source async-result]
14                    (let [message (.EndReceive source
15                                               (.AsyncResult async-result))
16                          result (handler message)]
17                      (.BeginReceive source)
18                      result)))
19
20 ; *queue* will have a ReceiveCompleted handler set..
21
22 (def *queue*
23      (doto (MessageQueue. “.\\private$\\testqueue”)
24            (.set_Formatter (XmlMessageFormatter.
25                              (into-array Type [String])))
26            (.add_ReceiveCompleted on-receive-completed)))
27
28 ; function to start receiving, given a specific handler function..
29
30 (defn async-receive [handler-fn]
31       (def handler handler-fn)
32       (.BeginReceive *queue*))

Nedenfor ser du hvordan jeg bruker to REPL’er til å teste ut testqueue2. Det øverste vinduet bruker jeg til å sende endel meldinger. I det nederste vinduet setter jeg opp async-receive til å printe ut alle meldinger som kommer inn. Funksjonskallet avslutter øyeblikkelig. Deretter kommer meldingene fortløpende etterhvert som jeg sender dem.

CropperCapture[89]

For flere detaljer, se CLR-Interop wikisiden på GitHub. Clojure er suverent, og etter å ha kjørt det på Java-plattformen i noen måneder føles det nå som å komme hjem når jeg endelig får benytte .NET-rammeverket. :)

Programmering som sunn livsstil

Her om dagen leste jeg en blogpost kalt some lesser known thruts about programming, som snakker om forskjellen mellom gode og dårlige utviklere. Jeg twitret også et sitat fra bloggen som sa:

“Good programmers think about their work 24/7. They write their most important code in the shower and in their dreams.”

Jeg følte dette var en god beskrivelse av hvordan jeg har det. Sitatet førte derimot til en del reaksjoner, bl.a. fra @fossmo, som sa (jeg har klippet litt..):

Thinking about work 24/7 is also the reason a lot of programmers burn out :-( We are sitting on the buttocks all day, drink lots of coffee, working in the evenings, getting little sleep, little physical activity; a perfect combination for a burnout.

I think it is important that developers who have been in the game for a few years dares speak out about that this is not very good lifestyle over time.

Jeg er enig i det han sier, men ikke i at det er en nødvendig sammenheng mellom å ha programmering som livsstil og at man har en usunn livsstil. For meg vil det å være en dyktig utvikler også si at man er bevisst disse tingene, og innretter seg deretter. Men Fossmo har sikkert rett i at vi bør være flinkere til å opplyse om dette. Vi fokuserer nok litt for mye på de harde tingene, og glemmer at det viktigste i utvikling av software er menneskene – inkludert de som utvikler det.

Programmering er ikke bare rock n’roll! Det er gøy, men man vil få enda mer ut av det om man er disiplinert. Ønsker du å bli en über-ninja-programmerer må du utvikle allsidige egenskaper, og du er nødt til å jobbe med å forbedre ferdighetene dine på fritiden. Men i bunn må du ha en sunn kropp og en allsidig og opplagt hjerne. Vil du være blant de beste må du tenke litt som en idrettsutøver.

Her følger mine råd om hvordan man kan ha prorammering som en sunn livsstil…

Søvn, trening og kosthold

sleep1 En “profesjonell utvikler”, slik Uncle Bob ville ha sagt det, sørger for å få nok søvn – uten det kan han ikke konsentrere seg godt nok til å skrive god kode. En profesjonell utvikler sørger også for å holde seg i form – om kroppen ikke har det bra vil konsentrasjonen også lide. Og det hjelper lite med søvn og trening om man har et dårlig kosthold. Disse tre punktene er et minstekrav, og kutter du ut ett av dem mister du effekten av de to andre.

Når det gjelder søvn er mengden som trengs nokså individuell. Jeg har faktisk snakket med en søvnforsker om dette, og hun sier at sålenge man føler seg opplagt så får man nok søvn. Undersøkelser viser at det er best med mellom 6,5 og 7,5 timer i døgnet. Over 8 timer er ikke bra, det tar man faktisk skade av, og det er mindre problematisk med 5 timer i døgnet. (kilde)

exercise Utviklere sitter mye i ro mens de jobber, og det er ikke kroppen laget for. Vi må derfor kompensere med ekstra, fysisk aktivitet. Personlig går jeg en times tur med hunden hver dag, og trener i alle fall én gang i uka på treningssenter. Dessuten er jeg pappa til en smårolling, og det krever jo sitt. Har du en kontorjobb og ikke gjør noe tilsvarende kan du ikke regne med at kroppen holder så veldig lenge. I stedet kan du forvente deg vond rygg og en rekke, andre plager som vil gå ut over både din evne til å yte på jobb og din livskvalitet forøvrig.

Mens trening krever at man setter av ekstra tid i hverdagen er kosthold kanskje det man kan gjøre mest med for å øke livskvaliteten uten omfattende tiltak. Man må passe på å spise nok, slik at man ikke blir sløv og at man får utbytte av treningen. Man bør også spise ofte, da det øker det gjevne forbrenningen og gir et stabilt blodsukker. Fem måltider pr dag er bra. Og så må man selvfølgelig spise variert, slik at man får alt det man trenger. Tran, tre melkeporsjoner og tre fruktprosjoner hver dag, mye fiber og grønnsaker, og DRIKK MYE VANN!

Ta et Grete Roede-kurs om du trenger hjelp.., jeg har gjort det, og det gav meg MYE!

Ikke bli ensporet

I tillegg til tilstrekkelig søvn og trening og et godt kosthold trenger man også andre input for at programmering som livsstil skal funke over tid. Det er viktig å ha andre interesser, å få impulser fra et bredere spektrum. Det vil ikke bare holde deg mentalt sunn, men potensielt også kunne få deg til å tenke i nye baner når du skal løse utviklingsproblemer. Hjernen må ikke bli for “satt” i én måte å tenke på. Så les bøker eller andre kilder ting som ikke har med programmering å gjøre. Det er ikke alle hobbier som trenger å stjele så mye tid fra det du har aller mest lyst til å holde på med. Selv leser jeg endel science fiction, og synes det er herlig avkobling.

Til sist må man ikke glemme venner og familie. Mennesker er soiale dyr – også utviklere! Det er ingen ting som vil gi deg så mye nyttig avkobling som din sosiale omgangskrets, og et stabilt sosial-/familieliv vil gi deg økt trygghet og yteevne i jobben. Lar du jobben gå ut over dine relasjoner vil det igjen påvirke din evne til å konsentrere deg og gjøre en god jobb.

Hvordan få tid til alt dette

old_tv Det kan kanskje virke som om jeg får tid til usannsynlig mye. En av hemmelighetene er at man orker mer når man er opplagt – ref søvn, trening og kosthold. Men det er også snakk om enkelte prioriteringer. De fleste har tidshull i livet sitt som suger klokketimer uten at man får særlig mye igjen.

Selv har jeg droppet dataspilling, og ser nesten ikke på TV lengre. Aviser leser jeg ikke, og ser bare 5-10 minutter med nyheter hver uke (de resirkuleres stort sett uansett). Dermed får jeg tid til både familie, trening og fritidsaktiviteter, samtidig som jeg både jobber og studerer/øver på ulike teknikker og teknologier, og blogger to ganger i uken.

Ikke stress

@borge3000 twitret noe veldig interessant:

“IMO Burnout happens when you think your work is more important than it really is…”

Utbrendthet skyldes altså ikke nødvendigvis at man har utvikling som en livsstil, eller at hjernen jobber med programmeringsutfordringer og abstrakte problemer nesten hele tiden. Sålenge man sørger for å gi kroppen og hjernen det den trenger av andre ting vil man kunne holde det gående lenge. Problemet kommer når man stresser, når man tenker på deadlines (reelle og/eller kunstige) – når man tar jobben for seriøst.

Har du tenkt å drive med utvikling i mange år – og jeg tar gjerne 30 til 50 år til takk – så må man slappe av. Ting tar den tiden det tar, og dessuten går det alltid raskere når man tar seg god tid (og får nok søvn, trening, adspredelse etc.) uansett.

Ikke forsøk å ri på hver eneste bølge (nye rammeverk/teknologier) som kommer, plukk deg ut noen få av betydning. Ikke forsøk å realisere alle ideene du får, utforsk noen av dem i et fornuftig tempo. Du har resten av karrieren på deg. Gjør litt hver dag, og du vil bli en tilfreds og dyktig utvikler!

Relaterte artikler: Utviklerprofiler og fire ferdighetskategorier | Å bruke av egen fritid

Kassaapparat-kata i Clojure

kodekata

Et gjennomgående tema på denne bloggen er at utviklere selv må ta et aktivt ansvar for å å bli bedre. Blant annet må man trene på de ferdighetene man trenger i jobben sin, og her kommer kodekata’er inn som et viktig hjelpemiddel. Første gang jeg snakket om kodekata var i februar 2009.

Jeg har bl.a. én kata jeg har brukt flere ganger for å komme raskt inn i nye programmeringsspråk, og jeg viste hvordan jeg implementerte den med Erlang her. Det dreier seg om å lage et enkelt “kassaapparat” som et komandolinjeprogram. Det fine med denne oppgaven er at den kan begynne veldig enkelt, men at man kan utvide med ganske mye avansert funksjonalitet om man ønsker det. Man blir også nødt til å sette seg inn i hvordan man kommuniserer med kommandolinjen, noe som alltid er kjekt å beherske, og man må bruke noen enkle datastrukturer.

Jeg fokuserer ikke på automatiserte tester i denne kataen, men prinsippet om clean code er viktig. Når jeg lærer et nytt språk tenker jeg at det er viktig å raskt finne ut hvordan koden bør struktureres for å bli enkel å lese og refakturere.

Siden jeg nå holder på å lære meg Clojure har jeg selvfølgelig nettopp implementert et enkelt kassaapparat. Jeg tenkte det kunne brukes til å vise litt Clojure-kode til andre som kanskje har hørt litt om dette språket, og som vil se hvordan et lite program kan se ut. Så her er det komplette programmet, splittet opp i tre deler, med litt kommentarer.

Merk at Clojure-kode parses fra toppen av fila og nedover. Verdier og funksjoner må derfor deklareres før de kan brukes. Du vil dermed se detaljene først og “program-loopen” til slutt.

  1 ; SHOP INVENTORY, AND GETTING THE PRICE OF STUFF
  2
  3 ; Illustrates: Defining some global data as a Map (key/value)
  4 (def shop-items {“bread” 3.99 “milk” 2.50 “butter” 4.00})
  5
  6 ; Illustrates: Iterating over a collection (Map)
  7 (defn list-items []
  8       (println “Items in shop:”)
  9       (doseq [[key value] shop-items]
10              (println key value)))
11
12 ; Illustrates: Use of Map (like a Hashtable/Dictionary)
13 (defn price [key]
14       (shop-items key))
15
16 ; Illustrates: Function overloading based on arity
17 (defn price-for-selection
18       “Gets the price for X number of a given shop item”
19       ([key quantity] (* (price key) quantity))
20       ([item]  (* (price (first item)) (second item))))
21

Gir det mening sålangt? Etter å ha skrevet Clojure-syntaks i en drøy uke er det plutselig ikke så lett å se om dette kan være vanskelig å tyde :) Jeg har nå definert et Map (tilsvarer Dictionary i .Net) med hvilke varer butikken har, og hva varene koster. Deretter har jeg definert noen funksjoner for å printe ut varene (med pris), for å finne prisen på en vare, og for å finne prisen på et gitt antall av en vare.

Og så kommer funksjonene får å kjøpe, vise innholdet av handlekurven, og for å gjennomføre betaling. Merk at handlekurven sendes inn som en parameter til alle disse funksjonene (i show-cart kalte jeg handlekurven for state, bare for å gjøre det vanskelig for deg).

Handlekurven er en array av arrays (eller Vector av Vectors, vi er tross alt i Java runtime nå), hvor hvert av de indre arrayene inneholder to elementer: navnet på en vare, og hvor mange det er av den. Buy, show-cart og checkout returnerer alle handlekurven – den samme eller en oppdatert kurv.

22 ; SHOPPING CART / BUYING
23
24 ; Illustrates use of higher-order function
25 (defn total [cart]
26       (apply + (map price-for-selection cart)))
27
28 ; Illustrates: Updating the state (cart)
29 (defn buy [what quantity cart]           
30       (println “Bought” quantity “of” what “for” 
31                (price-for-selection what quantity))
32       (conj cart [what quantity]))
33
34 ; Illustrates: Use of if
35 (defn show-cart [state]
36       (if (empty? state)
37         (println “Shopping cart is empty!”)
38         (do 
39           (println “Shopping cart:”)
40           (doseq [item state]
41                  (println (second item) “x” (first item)))
42           (println “Total:” (total state))))
43       state)
44
45 ; Illustrates: Local values using let
46 (defn checkout [cash cart]
47       (let [to-pay (total cart)]
48         (if (> to-pay cash)
49           (do (println cash “is not enough. You have to pay” to-pay) cart)
50           (do (println “To pay:” to-pay “Received:” cash
51                        “You get back:” (- cash to-pay)) 
52             []))))           
53

Og så kommer vi til siste del, som inkluderer en meny, input fra brukeren, og behandling av denne inputen.

54 ; MENU / INTERACTION AND MAIN LOOP
55
56 ; Illustrates: Read from command line using Java interop
57 (defn prompt [text]
58       (print text) 
59       (flush)
60       (let [reader (java.io.BufferedReader. *in*)]
61                   (.readLine reader)))
62
63 ; Illustrates: Anonymous functions used in Dispatch Table pattern
64 (def dispatch-command {
65      “menu” (fn [state] (do 
66                           (println
67                               “Commands: items | cart | buy | checkout | quit”) 
68                           state))
69      “quit” (fn [state] (System/exit 0))
70      “cart” (fn [state] (show-cart state))
71      “items” (fn [state] (do (list-items) state))
72      “buy” (fn [state]
73                (let [item-to-buy
74                       (prompt " Buy what? ")
75                       how-many
76                       (Integer/parseInt (prompt " How many? "))]
77                  (buy item-to-buy how-many state)))
78      “checkout” (fn [state]
79                     (let [money
80                            (Double/parseDouble (prompt " Received money? "))]
81                       (checkout money state)))
82      :default (fn [state] (do (println “* Does not compute”) state))})
83
84 ; Illustrates: Exception handling, and use of a Map
85 (defn get-and-run-command [state]
86       (try
87         ((dispatch-command (prompt “READY> “)) state)
88         (catch NullPointerException e
89                ((dispatch-command :default) state))))
90
91 ; Illustrates: Recursive tail call optimization
92 (defn run-program []
93       (loop [state []] ; starts with an empty Vector as state/cart
94             (let [new-state (get-and-run-command state)]
95               (recur new-state)))) ; resume with new state/cart
96
97 ; Alternative loop: Using pipelining/threading to avoid “let”
98 (defn run-program-2 []
99       (loop [state []]
100             (-> state get-and-run-command recur)))
101
102 (run-program) ; You’ll never guess what this line does :P

De siste funkjonene her er kanskje det som er vanskeligst å skjønne. get-and-run-command prompter brukeren til å taste inn en kommando. Brukerens input brukes så til å velge en lambda-funkjon fra dispatch-table. Denne lambdaen kalles så med state som parameter, og returverdie fra lambdaen returneres som returverdi fra funksjonen. Alt dette skjer i linje 87.

Om det ikke finnes en lambda for det brukeren taster inn vil det bli kastet en NullPointerException, og da velger jeg en default lambda (linje 89).

rect4019 run-program illustrerer hvordan tail-recursion fungerer i Clojure. I kallet til loop (linje 93) defineres det en verdi (variabel) kalt state, som i utgangspunktet er et tomt array – dette er handlevognen. Det gjøres så et kall til get-and-run-command, hvor vi sender inn state. Tilbake får vi returnert verdien vi kaller new-state, den oppdaterte handlevognen.

Til slutt kaller vi funkjonen recur, og sender inn denne nye handlevognen. Recur gjør at vi starter fra loop igjen, som om run-program ble kalt på nytt, men state får nå verdien som sendes inn i recur. Hele programmet vil altså stå og spinne inne i run-program (uten at stacken blir spist opp), og handlevognen oppdateres for hver iterasjon.

Denne måten å sende state/handlevognen rundt i et rekursivt kall var noe jeg lærte meg da jeg så på Erlang. Dette er en helt normal måte å holde på state innenfor funkjonell programmering, hvor man normalt ikke tillater (eller ønsker) variabler som muterer (endrer verdi). I stedet for å ha en global handlevogn som metodene aksesserer og endrer har vi nå metoder som sender handlevogner til hverandre.

(Faktisk implementerte jeg kassaapparatet uten denne teknikken først, for det er mulig å mutere verdier i Clojure. Seriøs refakturering inngår ofte som en del av kodekata’er.)

Ta også en titt på run-program-2, som gjør det samme som run-program, men med pipelining/threading. I linje 100 sendes state som input til metoden get-and-run-command. Resultatet fra det kallet sendes så som input til recur. Altså samme logikk, men enklere å se på :)

Jeg håper noen orket å lese denne blogposten, og ikke ble alt for avskrekket av alle parantesene. Ble du kanskje inspirert til å utføre eller komme opp med egne kataer? Del gjerne erfaringer eller dine egne ideer til lignende oppgaver med oss andre i kommentarfeltet.

En Software Craftsman finner seg en lærling

Synes du folk som Uncle Bob og Corey Haines har mye fornuftig å si? Mener du at vi må hjelpe hverandre å bli bedre utviklere? Har du lyst å kunne kalle deg selv en Software Craftsman? Har du signert Software Craftsmanship manifestet? Svarer du ja på ett av disse er mitt neste spørsmål: Har du funned deg en lærling???

De som støtter ideen om Craftsmanship, og som mener programmerere kontinuerlig må jobbe aktivt med å bli bedre, må ta konsekvensene av dette. Dette betyr blant annet at du bør finne deg en mentor som kan være din veileder, og at du tar deg en lærling som du kan være veileder for. Både du og din mentor vil lære av at han hjelper deg, og på samme måte vil du og lærlingen din begge lære mye av deres sammarbeid.

Så med disse tankene i hodet tok jeg turen innom Norsk Freakforum og registrerte meg som villig læremester. Og etter kort tid tok Olaf kontakt…

Min lærling

CropperCapture[63] Olaf er en 19 år gammel IKT-lærling som har syslet litt med programmering i et års tid (C#, C++, Java, og VB.NET), og som har planer om å ta Informatikk på NTNU. Han hadde lyst til å lære mer, spesielt i C#, og ville gjerne bli min lærling.

Jeg sa at jeg ville fokusere på å lære ham profesjonell softwareutvikling, ting som god bruk av objektorientering, ren kode, og praksiser som testdreven utvikling etc. Han vet nok ikke helt hva dette innebærer enda, men min plan er å gi ham balast han ikke vil få i et Informatikk-studie, som vil gjøre ham til en smidig utvikler av kvalitets-prgramvare. Underveis tetter vi hull i grunnleggende programmeringskunnskaper når de dukker opp.

Jeg begynte med å gi Olaf en rimelig grei programmeringsoppgave. Første gangen fulgte jeg ganske nøye med mens han jobbet, og kunne gi ham noen tips underveis. Når programmet fungerte som spesifisert gjorde jeg en grundigere code review, og gav ham tips om forbedringer han kunne forsøke. Og slik har vi fortsatt – han koder litt, jeg gjør en review og tilbakemelding, og han koder videre. Etterhvert varierer jeg hva jeg fokuserer på, og han lærer forhåpentligvis mer og mer.

Olaf gav meg i alle fall raskt en god tilbakemelding:

“Ja allerede nå føler jeg at jeg har lært mere innen objekter og klasser. Tidligere har de ikke virket så logiske å forstå, men føles nesten som jeg har fått en diger lyspære over hodet. Frem til nå har jeg ikke brukt objekter, rett og slett fordi jeg ikke har forstått det, men nå som jeg måtte bruke objekter, ble det fort enklere å få den motivasjonen til å lære.”

Teknisk oppsett

For å dele filer har vi valgt å bruke DropBox. Olaf kan da dele prosjektene sine med meg, og Visual Studio gir meg øyeblikkelig beskjed når han har lagret en ny endring (f.eks. når han kompilerer programmet). Dermed kan jeg følge med nesten i real time, uten å måtte bruke en eller annen form for delt desktop-løsning. Jeg kan også legge til filer i prosjektet med tips og nye oppgaver, og dette har fungert fint sålangt.

Utover dette kommuniserer vi via epost – så slipper vi å måtte være online og tilgjengelige samtidig, og vi kan gjøre det vi skal når det passer hver av oss best.

Min bønn til dere andre med litt erfaring

Jeg vil på det sterkeste anbefale alle i min situasjon om å forsøke å finne seg en lærling. Det krever ikke så mye – vi snakker om langsiktige sammarbeid hvor læremesteren kan være støttespiller for en som ønsker å bli en bedre utvikler – og man trenger ikke legge så mye tid i det fra uke til uke. Spre litt av den erfaringen du har opparbeidet deg. Hvis vi er mange nok som gjør dette vil kvaliteten i bransjen kunne øke dramatisk.

Råd til blivende softwareutviklere

Det finnes mange utviklere i Norge som brenner for faget sitt, og som har masse erfaring å by på. De samles ofte på såkalte brukergrupper, og jeg vil anbefale alle som er insteressert i å lære programmering om å oppsøke disse. For .NET-utviklere har vi NNUG, som finnes i åtte byer i Norge. Java-utviklere har javaBin, Rubyister i Oslo har irb.no, og det finnes sikkert mange flere (skriv en kommentar om du vet om noen). Det er gratis å bli med på slike møter, og kvaliteten på det man får se er som regel veldig bra. Og så kan man regne med å få litt pizza.

Et annet sted man kan treffe ivrige utviklere er på twitter. Se for eksempel henriksen’s liste over norske .net-utviklere, eller fkalseth’s norwegian-dev-community-liste. Følg med på hva folk snakker om, delta i samtalene, finn ut hvem som kan være potensielle mentorer for nettopp deg – og spør dem om de har lyst til å bli det!

Utviklere må selv ta ansvar for karriæren sin, og må jobbe aktivt med læring. Med en læremester å støtte seg til kan man korte ned tiden det tar å bli en dyktig programmerer.

Programmeringsparadigmer – ulike måter å tenke på

Jeg har tidligere snakket om betydningen av å beherske både statiske og dynamiske språk. En annen akse blivende polygloter er nødt til å se nærmere på er det vi kaller ulike programmeringsparadigmer.

paradigme_tre

(Språk-treet er selvfølgelig ikke komplett, og kategoriseringen er åpen for diskusjon.)

Om du har omtrent samme bakgrunn som meg er du mest kjent med de imperative språkene, som dominerer software-bransjen. Imperativ (eller befalende om du vil) betyr at vi forteller datamaskinen detaljert hva den skal gjøre – vi manipulerer variabler for å oppnå ønsker resultat.

Jeg tror det er veldig viktig at vi også studerer og lærer oss å beherske de mere deklerative (eller beskrivende) språkene. De tvinger oss til å tenke ganske anderledes når vi skal løse problemer. Om vi til syvende og sist likevel benytter oss av et imperativt språk så vil det vi lærer gi oss nye perspektiv som hjelpe oss til å løse oppgavene våre bedre. Dessuten er det mange språk som befinner seg i flere kategorier samtidig, som støtter f.eks. både objektorientering og funksjonsorientering (som alltid er det glidende overganger).

For å illustrere forskjellene mellom et utvalg paradigmer skal vi se på ulike løsninger for å finne den største, felles divisoren mellom to tall (heretter kalt gcdGreatest common divisor). Og vi begynner med det vi kjenner best…

Imperativ programmering

1 // GCD implementert i C
2 int gcd(int a, int b) {
3   while (a != b) {
4     if (a > b) a = a – b;
5     else b = b – a;
6   }
7   return a;
8 }

Den imperative algoritmen er for anledningen implementert i C, og illustrerer hvordan befalende kode fungerer:

For å beregne gcd av a og b, undersøk om a og b er like. Hvis så er tilfelle, returner en av dem. Hvis ikke, bytt den største av dem med forskjellen mellom dem og repeter.

Funksjonsbasert programmering

1 ; GCD implementert i Scheme
2 (define gcd
3   (lambda (a b)
4     (cond ((= a b) a)
5           ((> a b) (gcd (- a b) b))
6           (else (gcd (- b a) a)))))

I et funksjonelt språk som Scheme legger man vekt på det matematiske forholdet mellom input og output. Lambda-nøkkelordet introduserer en definisjon av en funksjon, og (a b) er funksjonens argumentliste. “cond” er en slags switch/case-konstruksjon. (- a b) er et kall til metoden “-” (minus) med a og b som argumenter. Her er metoden i pseudokode:

Gcd av a og b er definert til å være (1) a når a og b er like, (2) gcd av b og a – b når a er større enn b, og (3) gcd av a og b – a når b er større enn a. For å beregne gcd for to numre, ekspander og forenkle denne definisjonen til avslutning.

Rekursjon er en av hovedvirkemidlene i funksjonsbasert programmering. Samme algoritme kunne man selvsagt ha fått til i imperative språk også, selv om det er vanligere å se den første varianten. Det er derimot mye fra imperativ programmering man ikke gjør i funksjonsbasert. Fraværet av (det vi for enkelhets skyld kan kalle) variabel-manipuleringen gjør at funksjonsbasert kildekode i større grad kan analyseres for korrekthet. Det er også enklere å automatisere enkelte optimaliseringer, som å parallellisere programmer.

Logisk programmering

1 % GCD implementert i Prolog
2 gcd(A,B,G) :- A = B, G = A.
3 gcd(A,B,G) :- A > B, C is A-B, gcd(C,B,G).
4 gcd(A,B,G) :- B > A, C is B-A, gcd(C,A,G).

I et logisk språk spesifiserer vi et sett med axiomer og regler som lar systemet finne løsningen. Det kan være enklere å forstå Prolog-koden om du leser “:-” som “hvis” og “,” som “og”. Her er det samme i pseudokode:

Proposisjonen gcd(a, b, g) er sann om (1) a, b og g er alle like, (2) a er større enn b og det eksisterer et nummer c slik at c er lik a – b og gcd(c, b, g) er sant, eller (3) a er mindre enn b og det eksisterer et nummer c slik at c er lik b – a og gcd(c, a, g) er sant. For å beregne gcd av to numre, søk etter et nummer g (og ulike numre c) slik at man kan bevise at gcd(a, b, g) er sant.

Konklusjon

Valget av imperativ, funksjonell eller logisk programmering får som sagt ikke bare betydning for hvordan koden blir seende ut, men også hvordan utvikleren tenker for å komme opp med en løsning. Å beherske disse måtene å tenke på vil gjøre deg til en bedre problemløser. I tillegg vil du ha flere verktøy å velge blant – noen problemer vil alltid være enklere å løse deklerativt enn imperativt.

En annen ting som er interessant med de deklerative språkene er at vi ikke tvinger datamaskinen til å jobbe på en bestemt måte. Det muligjør implementasjon av forbedringer uten å røre program-koden, f.eks. gjennom å utvikle bedre kompilatorer. Den samme effekten har vi f.eks. når vi benytter LINQ i .net; LINQ er et deklerativt subset av C#/VB.net.

Tips til Java og .Net-utviklere

Om du er Java-utvikler, eller C#-utvikler som meg, så skal du være klar over at du har tilgang til funksjonsbaserte språk på favorittplattformen din også. Scala på Java-plattformen er et språk som kombinerer objektorientering og funksjonsbasert programmering. Fra Microsoft har vi fått F#, en variant av ML som støttes fullt ut i Visual Studio 2010 – på samme måte som Scala kombinerer også F# den funksjonelle og den objektorienterte paradigmen.

Hvis du vil ha et språk som er “renere” kan du velge Clojure – en moderne (2007) Lisp-dialekt som kjører på både .Net og Java-plattformen. Er du interessert i logiske språk kan du ta en titt på P#, som gir deg Prolog i .net. Prolog Cafe er tilsvarende for Java.

For komplette lister over språk på Java Virtual Machine og Common Language Infrastructure, se her og her.

Denne blogposten var inspirert av boken Programming Language Pragmatics, hvor kodesnuttene også er sakset fra.

Du må beherske et dynamisk språk

Jeg vil si det så sterkt: Hvis du ikke behersker et dynamisk programmeringsspråk, slik at du er i stand til å designe fullverdige software-løsninger i det, da er du ikke en ferdig utdannet utvikler! [1]

Det har vært mye buzz rundt dynamiske språk de siste årene, og mange utviklere, spesielt i Agile-miljøer, migrerer over fra statiske språk til dynamiske. For å forstå hvorfor dette skjer er det viktig å vite hva vi mener med et dynamisk språk, og hvilke fordeler og ulemper det bringer med seg. Denne artikkelen er en god start for deg som ikke vet så alt for mye om temaet.

Hva mener vi med Dynamic?

Når vi sier at noe er STATIC mener vi at ting er definert og avgjørelser tas ved compile-time, mens DYNAMIC impliserer at det samme skjer i runtime. Det er derimot ingen språk som er fullstendig statiske, og heller ingen som er fullstendig dynamiske – de fleste språk befinner seg et sted mellom disse ytterpunktene.

static_dynamic

Egenskaper som gjør et språk dynamisk er ting som dynamisk typing, dynamisk dispatch, introspection, dynamisk kompilering og dynamisk loading. I språk som er mer dynamiske kan man f.eks. gjøre ting som å endre hvordan typer ser ut – legge til metoder o.l. – mens programmet kjører.

De dynamiske spåkene begynte for alvor å vokse frem på 80-tallet – og språk som Larry Wall’s Perl og Guido van Rossum’s Python hadde stor betydning for internetts vekst på 90-tallet. De dynamske egenskapene hadde derimot en ulempe: Dårlig performance! Grunnen til at de dynamiske språkene har blitt mer populære de siste 10 årene er at vi nå har fått raskere og bedre maskinvare, som gjøre at vi i mange sammenhenger kan se bort fra at programmene kjører noe tregere relativt til kompilert, statisk kode.

Mange språk utvikler seg i dynamisk retning

dynamic-langProgrammeringsspråk utvikler seg hele tiden. De som ikke gjør det er i praksis døde. Og samtidig som dynamiske språk som Perl, Python og Ruby har blitt mer populære, har andre språk beveget seg i en mer dynamisk reting.

C# har for eksempel en rekke dynamiske egenskaper. Du lager dynamiske programmer om du bl.a. benytter deg av reflection (introspection). Det er bare det at reflection er mye enklere i språk som i utgangspunktet er designet for det. Generics er også en nokså dynamisk feature, som gir inntrykk av løsere typing i koden. Type inference – bruk av “var” – gir C# en dynamisk følelse. Og sist men ikke minst innfører man i .NET 4.0 Dynamic, en type hvor metodekall ikke evalueres før runtime (dynamic dispatch), slik at C# bedre kan kommunisere med mere dynamiske språk.

Ved å beherske et dynamisk språk vil man lære seg teknikker som gjør en til en bedre utvikler også når man jobber i mere statiske språk.

PS: Det dynamiske språktreet er ikke komplett, men viser de mest sentrale språkene, og hvordan de i hovedsak har påvirket hverandre.

Fordeler ved dynamiske språk

Jeg mener vi må innse at både statiske og dynamiske språk er viktige. Statiske språk gir en høy grad av kontroll – det er lettere å analysere koden og forutse hva som vil skje i runtime. Det er derimot vist gjentatte ganger at dynamiske språk gjør deg mere produktiv; man kan implementere mer funksjonalitet raskere, og med mindre kode.

Dynamiske språk er også mer fleksible, smidige om du vil, og egner seg til problemer hvor løsning i utgangspunktet er ukjent. Flere velger derfor å prototype i dynamiske språk, for så å implementere endelig løsning i et mere statisk språk om performance og sikkerhet er viktig.

En annen ting man oppdager når man går fra statisk til dynamisk programmering er at skillet mellom data og kode opphører – data og funksjonalitet smelter bedre sammen. Det er litt vanskelig å forklare dette uten et dypdykk, så jeg tror det må bli en fremtidig blogpost.

Et siste område hvor dynamiske språk egner seg spesielt godt er embedding. Sett at du skal utvikle et system hvor det meste skal være fast, og egner seg for et statisk språk. Men du ser at det kan bli behov for å kunne endre visse forretningsregler etter at systemet er tatt i bruk. Tradisjonelt vil man forsøke å forutse disse endringene, og lage et innfløkt konfigurasjonssystem for å dekke behovet. I stedet kan man utvikle selve systemet i C#, men kode forretningsreglene i et dynamisk språk. Den dynamiske koden vil evalueres når den behøves, og kan når som helst endres og utvides uten at man behøver å rekompilere og publisere en ny versjon.

I ytterste konsekvens kan man eksponere et API internt i applikasjonen som de dynamiske kodesnuttene kan få tilgang til – man har da laget et scriptbart system, og man kan lene seg tilbake og se på mens tredjepartsutviklere utvider funksjonaliteten i systemet ditt i retninger du selv ikke kunne ha forrutsett.

Er dynamisk kode bedre enn statisk?

Det kan hevdes at dynamiske språk oppfordrer deg som utvikler til å skrive bedre kode. Et sentralt poeng er at man ikke har en kompilator å støtte seg på, og viktigheten av enhetstester er derfor mye større. I “de dynamske miljøene” er man også mer opptatt av eleganse og enkel kode. Gjennom å praktisere dynamisk kode vil du øke forståelsen av hva kvalitet er for noe, og det vil forbedre din statiske kode også.

Den andre siden av dette er at man ikke lenger har tilgang på mange av de verktøyene man har vendt seg til som f.eks. C#-utvikler: intellisense, god refakturerings-støtte, statisk analyse osv. Visual Studio, ReSharper o.l. gjør oss produktive, og det er en viss overgang å ikke ha disse lengre – man kan føle seg litt naken en stund.

Videre lesing

Til slutt har jeg funnet frem et par “research papers” for dem som er interessert i utviklingen av dynamiske språk.

The End of the Cold War Between Programming Languages:
“Static typing is a powerful tool to help programmers express their assumptions about the problem they are trying to solve and allows them to write more concise and correct code. Dealing with uncertain assumptions, dynamism and (unexepected) change is becoming increasingly important in a loosely couple distributed world. Instead of hammering on the differences between dynamically and statically typed languages, we should instead strive for a peaceful integration of static and dynamic aspect in the same language. Static typing where possible, dynamic typing when needed!”

On the Revival of Dynamic Languages:
“The programming languages of today are stuck in a deep rut that has developed over the past 50 years. Although we are faced with new challenges posed by enormous advances in hardware and internet technology, we continue to struggle with old-fashioned languages based on rigid, static, closed-world file-based views of programming.”

Fotnote:
[1] Jeg hevder ikke at jeg vet når du kan kalle deg ferdig utdannet – bare at det å beherske et dynamisk språk må inngå i den definisjonen. Joe Armstrong, utvikleren av Erlang, sier f.eks. at det tar 30 år å lære å programmere (i boken Coders at Work).

Referanse:
Randal exploring dynamism (InfoQ)

Jeg, Polyglot

rect2590

WikiPedia: Polyglot – someone who aptly and with a high level of fluency uses many languages.

Her skulle du nå ha lest en lengre artikkel om betydningen av å lære mange, ulike programmeringsspråk, men det viser seg at Live Writer hadde bestemt seg for å spise opp den teksten. Her er derfor selve essensen:

Da jeg for over et år siden begynte å for alvor ta tak i min egen utvikling, hadde jeg en lang liste med rammeverk, biblioteker og teknologier jeg ønsket å lære meg – som WCF, WPF, WF, NHibernate, CSLA.NET, nServiceBus m.m. Dette endret seg derimot raskt – min forståelse av hva som er viktig ble mere moden – og jeg begynte i stedet å fokusere på basis-ferdigheter som god objektorientering og testdreven utvikling.

Jeg begynner nå å ane hva neste steg blir; jeg har nemlig blitt veldig opptatt av språk og programmeringsparadigmer. Jeg har begynt å forstå hvorfor erfarne utviklere hevder at man hele tiden må lære seg flere programmeringsspråk. Jeg har også begynt å se hvor mye det er å lære av historien vår. Dette markerer en endring i hva jeg er opptatt av, og jeg spår at det vil komme flere blogposter om språk-relaterte tema her fremover.

Selv om jeg har vært borti mange språk og teknologier siden jeg kodet min første if i AMOS BASIC, har mitt fokus de siste åtte årene utelukkende vært C# og .Net-plattformen. Det er for snevert for en profesjonell utvikler. Mens slagordet mitt i 2009 var “.Net Ninja” har jeg i år bestemt meg for å bli en polyglot, en som behersker en rekke, ulike språk. Jeg tror det vil gi meg en dypere kunnskap om programmering, og gi meg en allsidighet som vil gjøre meg bedre i praksis også.

Et usedvanlig år..

Da nærmer det seg slutten av et veldig spesielt år. 2009 var ikke bare det året jeg slanket meg 10 kilo.., for deretter å legge dem på meg igjen. Det var nemlig også det året jeg tok skikkelig tak i min egen karriære, og jobbet målrettet med å bli en mye bedre utvikler. Jeg byttet også jobb i 2009, jeg blogget ekstremt mye, og jeg ble med i NNUG-styret i Bergen. Og sist men ikke minst vil jeg alltid huske 2009 som det året jeg ble pappa til verdens søteste jente.

Her er noen tanker rundt året som har vært. Jeg er ganske stolt av hva jeg har gjort, så dette kan tendere mot selvskryt. Er du ikke fan av det får du surfe videre…

.Net ninja-initiativet

28. desember 2008 satte jeg meg selv et nyttårsforsett: Jeg skulle jobbe målrettet og strukturert med å utvikle mine ferdigheter som programmerer. Jeg hadde store forhåpninger, men ingen anelse om at det skulle forandre mitt forhold til faget mitt så mye som det har gjort. I løpet av året har jeg lest en rekke med fantastiske bøker, hørt på hundrevis av podcasts, sansynligvis kodet mer enn noensinne (både på jobb og fritid), og diskutert mer programmering med andre enn noen gang før. Jeg har fokusert mye på grunnleggende objektorientering, patterns og refakturering. Jeg har praktisert testdreven utvikling/design, tidvis parprogrammering, og lært meg å bruke mocking og Inversion-of-Control containers. Og jeg har utviklet min daglige bruk av C#, gjennom en dypere forståelse av ting som generics, linq og lambda.

Nå på slutten av året har jeg også tatt opp igjen Ruby. Jeg begynte så smått å lære meg dette programmeringspråket i 2006, men det ble for lite brukt, så da klarte jeg ikke holde kunnskapen ved like. Nå leser jeg The Ruby Way, og har flere småprosjekter på gang. Jeg tror tillegget av et dynamisk språk til “min portefølje” vil kunne gjøre meg til en enda bedre utvikler. Så det blir mer om Ruby her til neste år…

NNUG / Community

Som jeg allerede har nevnt inviterte Jon Arild meg med i NNUG-styret i starten av året, og i februar holdt jeg et foredrag om objektorienterte databaser (del 1 og del 2) som ble svært godt mottatt. Jeg har blitt en mere aktiv deltager i det norske .Net-miljøet, bl.a. gjennom bruk av twitter og gjennom bloggen min. Jeg har blogget MYE i år, et naturlig resultat av at jeg har lært så mye nytt, og jeg tror mine blogposter har vært inkludert i Microsofts nyhetsbev hele fire ganger nå.

NNUG-året i Bergen har forresten også vært helt eksepsjonelt; vi har blant annet hatt besøk av “kjendiser” som Jimmy Nilsson, Mary Poppendieck, Jeremy D. Miller, Greg Young, og sist men ikke minst Scott Hanselmann (introdusert av selveste Carl Franklin). MSDN Live i mars og september var også bra, og årets høydare var Norwegian Developers Conference i Oslo.

Farvel Contiki, hei PSWinCom

I sommer takket jeg farvel til CMA Contiki, og begynte som teamleder/seniorutvikler i telekom-selskapet PSWinCom. Det var en svært vanskelig avgjørelse å ta, men i ettertid er jeg veldig fornøyd med utfallet. I PSWinCom har jeg fått anledning til å innføre og praktisere mange av de smidige prinsippene som var vanskelig å gjennomføre i Contiki. Vi har et dyktig og motivert team som er villige til å lære nye ting.

Domenet vi jobber i har også gitt meg mange, nye utfordringer. Vi jobber med en ekte serviceorientert (SOA), event-drevet, asynkron arkitektur med høy throughput. Vi bruker mye windows-services, køer og parallellprosessering, som fører til mange problemer jeg aldri har måttet forholde meg til tidligere. For ikke å snakke om et utall integrasjonspunkter med protokoller av ulik art. Hva mer kan en utvikler ønske seg?

Og så ble jeg pappa..

Samme hvor mye jeg har fått til i løpet av året så er dette det mest fantastiske. Dette er en blog om programmering, så jeg skal ikke kjede dere for mye, og henviser derfor bare til en liten videosnutt (tidligere publisert på facebook):

Om 2010 blir bare halvparten så spennende som 2009 har vært så kommer det til å bli et fabelaktig år. Mitt nyttårsforsett denne gangen er rett og slett å fortsette som jeg gjør nå. Takk til alle som har fulgt utviklingen på bloggen min – jeg ønsker dere en riktig God Jul og et Godt Nytt År alle sammen!!!

"Vil du bli en .NET Ninja" lansert

I helgen lanserte jeg endelig første release av DotNetNinjaQuiz, min versjon av Vil Du Bli Millionær for .Net-utviklere. Dette er et prosjekt jeg begynte på i januar i år (blogget om det her) som et første forsøk på å lage en WPF applikasjon. Jeg tok opp tråden nå for å kunne spille spillet på høst-kickoff’en til utviklerne i PSWinCom.

Version1_level1

Jeg har gitt DotNetNinjaQuiz et hjem på google code. Etter at jeg la ut versjon 1 twittet jeg om det, og responsen var bra, for etter bare noen få timer hadde nesten 40 personer lastet det ned, og nå – fire dager senere – har over 80 besvart .NET-spørsmål. Det er gøy å lage ting når folk er interessert i å prøve det ut.

Som sagt kodet jeg det meste av dette programmet i januar – i starten på .Net Ninja-initiativet mitt – og det bærer koden preg av. Jeg hadde praktisk talt ikke gjort noe i Windows Presentation Foundation tidligere, og jeg behersket hverken testdreven utvikling eller presentation patterns på den måten jeg gjør i dag. Men gjennom prosjektet fikk jeg prøvd meg på litt av hvert, som for eksempel dynamisk skalering av elementene på skjermen, lasting av grafikk og avspilling av lydeffekter. Jeg brukte også db4objects for persistering, en teknologi jeg akkurat hadde oppdaget på den tiden.

Hvis du ikke har prøvd spillet enda så håper jeg du vil laste det ned og ta en titt. Hva med å for eksempel kjøre et lite “game show” på jobben? Eller foreslå å spille det på neste brukergruppemøte?!

Jeg er forresten veldig interessert i bidrag til neste versjon – spesielt i form av flere spørsmål – så ta gjerne kontakt om du er interessert.

PSWinCom ansetter en ekte .NET Ninja

Jepp, målet er nådd, for nå omtales jeg som en “ekte .NET ninja” :D Her er et utklipp fra min nye arbeidsgivers siste nyhetsbrev:

En ekte .NET Ninja!
Klikk for full størrelse..

Man kan få prestasjonsangst av langt mindre! Er du interessert i å lese hele nyhetsbrevet, kan du laste det ned her. Vær tålmodig, det kan ta litt tid.


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