Viser opslag med etiketten programmering. Vis alle opslag
Viser opslag med etiketten programmering. Vis alle opslag

mandag den 16. november 2009

Områdeviden

I forhold til databaser, så er jeg typen, som gerne vil udtrykke så meget viden om det domæne, som data omhandler, i databasen. Som minimum helt banalt identitet (og her tænker jeg ikke på kunstige nøgler) og referentiel integritet; og i virkeligheden vil jeg gerne sige meget mere, men som oftest understøtter databasesystemerne det kun i ringe udstrækning. Men lidt har også ret.

Jeg vil gerne have, at databasesystemet hjælper mig med at holde orden i data, så programmerne ikke behøver at gøre det. På den måde bliver programmerne - efter min mening - sikrere og mere koncise.

I modsætning her til står det synspunkt, at databasen sådan set bare er en stor spand, hvor man kan hælde semistrukturerede data i, og det med mindst muligt besvær. Integritetsregler er mest af alt i vejen, og i øvrigt så koster de vist også performance.

Når man opfatter databasen på den måde, så giver det sig selv, at det bliver programmernes ansvar selv at sikre sig, at der er orden i data. Det lægger en større byrde på omhu og på kvalitetssikring.

Selvom jeg har valgt side, så har begge synsvinkler faktisk hver i sær sin rimelighed. Er strukturen i rivende udvikling og/eller er skemaet til at overskue, så er det sandt, at integritetsregler mest af alt er i vejen. Men når kompleksiteten stiger, og når det er vigtigt at have konsistente data, så er det ofte nødvendigt at have databasesystemet som kustoden, som dels kan hjælpe med at vise vej, og dels kan afvise de værste unoder.

Kort sagt, så hjælper integriteretreglerne med fastholde viden om domænet.

I forhold til programmeringssprog, så er jeg typen, som har det bedst med sprog, som har en statisk typestruktur. Statisk typecheck gør det muligt at udtrykke ens forståelse af domænet præcist, og advarer en tidligt, hvis man - populært sagt - prøver at blande pærer og bananer.

I modsætning hertil står programmeringssprog med en dynamisk typestruktur. Hvis domæneforståelsen er under udvikling, og man i har tilstrækkeligt overblik og udviser fornøden omhu, så er statisk typecheck mest af alt en spændetrøje på kreativiteten.

Jeg kunne fortsætte, men i virkeligheden så vil jeg blive ganske skuffet, hvis I ikke allerede har gættet, at min pointe er, at der er tale en interessant parallel: integritetsregler i en database er en måde at udtrykke forretningsforståelse på, og det er typesystemet i et programmeringssprog også.

Min holdning burde også være klar: jeg vil hellere lade compileren sikre konsistensen, end at jeg vil bruge tid på at skrive og vedligeholde unittest, som i bund og grund kun gør det samme.

Alligevel må jeg erkende, at det kan blive belastende hele tiden at skulle bekræfte compileren i, at man godt kan huske, hvad der er pærer og hvad der der bananer. Rigtigt slemt bliver det, når man har noget kode, hvor man egentlig i bund og grund er lige glad med, om det er den ene eller den anden konkrete type - man tager bare imod pærer og giver pærer videre ... og viser de sig på et tidspunkt i virkeligheden at være bananer, så gør det ikke noget, bare man kan få og give dem videre uden at det bliver blandet sammen.

Tag f.eks. følgende lille stump Scala kode:
class Bowl {
def getAFruit = new Pear
def add(fruit: Pear) = "Added "+fruit.toString
}

case class Pear
case class Banana

object Mixer {
def mix(aBowl: Bowl, anotherBowl: Bowl) = {
val fruit = aBowl getAFruit;
anotherBowl add(fruit)
}
}

Her er tale om skåle til een slags frugt, og en mixer, som tager et stykke frugt fra den slags skåle og lægger det over i en anden skål af samme slags. Og
grundlæggende set, så er mixeren faktisk lige glad med frugter - var det ikke lige fordi, at jeg havde kaldt metoder og variable noget frugtagtigt, så kunne det faktisk være hvad som helst.

Ændrer man skålen til at give og tage bananer i stedet, så virker mixeren stadig. Men prøver man at lave om på skålen, så den giver bananer og tager imod pærer, så brokker compileren sig, som den skal - så der er i virkeligheden et typecheck omme bagved - vi bliver bare hjulpet af typeinferensen til at glemme det for et øjeblik. Og sådan bør det også være - det ligner for mig nærmest noget af det gode fra begge verdener.

...og så for at lige at forgribe evt. kommentarer: Ja, det kunne modelleres mere præcist, f.eks. med anonyme typer - men det er helt anden snak.

fredag den 17. april 2009

Git har ingen rename, og er stolt af det

Jeg sidder lige og fjoller rundt med mit seneste for-sjov projekt, og i den forbindelse besluttede jeg mig for at ændre på pakkestrukturen. Det er et Scala projekt, og derfor er sammenhængen imellem filnavne og klasse-/pakkenavne mere en konvention end en regel - men dels kan jeg lide den, og dels så skal man kun bryde konventioner, når man har rigtigt gode grund til det - så det endte med, at jeg også fysisk flyttede rundt på filerne.

Som tidligere nævnt her, så bruger jeg Git til versionskontrol, og da jeg ikke lige finde en oplagt måde at fortælle Git om, at det var en rename (og altså ikke en række sletning og tilføjelser, som det ellers godt kunne ligne), så tænkte jeg, at det kunne være lige meget - projektet er jo i sin spæde opstart, så tabet af historik er bestemt til at overse. Så jeg committede det bare, som det var.

Stor var min overraskelse, da jeg nu ser mit commit beskrevet af Git bl.a. på flg. måde:


Wow! Git har altså opdaget, at der var tale om en rename udfra det forhold, at filerne ligner hinanden; og den har ved samme lejlighed set igennem fingre med, at de ikke var helt ens (pakkenavnet var jo netop opdateret).

"Snedigt", tænker jeg, "den har regnet det ud i forbindelse committet", men så er det, at jeg kigger på commithistorikken på git-hub: der står det som sletninger og tilføjelser (se evt. her). Git-hub er altså ikke nær som snedig som min lokale Git. Men alt er ikke tabt, for under "blame" kan man se, at også git-hub kan spore ændringer på tværs af renames (se evt. her). Det gjorde så lige min antagelse om, at det var noget, som blev regnet ud på committidspunktet, ganske usandsynlig.

Derfor graver jeg lidt mere i det, og det viser sig sandelig, at det er korrekt - der er intet "rename" begreb i Git; og det er en design-feature. Man kan se her, hvordan Linus Torvalds argumenterer for, at man skal tracke indhold fremfor identitet - og her, hvor han illustrerer en yderligere fordel ved konceptet med et eksempel om en fil, der er blevet splittet op i to (begge links har jeg fundet på Wikipedia artikel om Git - søg efter "rename" på siden for nemt at finde det relevante afsnit).

Hvis det virker, så er det altså smart - og det ser ud til at virke! Det virker dog klart bedste, hvis man har disciplin nok til at holde sine refactorings for sig selv, så de ikke bliver blandet sammen med øvrige ændringer ... og det er i grunden heller ikke så dumt.

onsdag den 18. februar 2009

Kærlighed ved første blik

Jeg tror, at jeg er blevet en lille smule forelsket. Det var sådan set nok det, som man kalder "kærlighed ved blik", for det var tydeligt allerede fra starten af, at vi tænkte på samme måde. Jeg har nemlig fundet et nyt program!

Det er faktisk et ret grimt program - der er ingen runde hjørner eller skinnende knapper med metallook. Og så alligevel, for det er helt klart lavet til at blive brugt, og får derfor sin egen funktionelle æstestik ... lidt ligesom en entreprenørmaskine, som kun fås i en farve (gul!), og hvor der ikke er levnet megen plads til gejl og pjat, men som alligevel er smuk på sin egen fascinerede måde.

Og hvad er det så for et program. Jo, det er den grafiske brugerflade, som kommer med git - aka. git-gui. Se selv:



Kan vi ikke blive enige om, at det ikke ligefrem er et program, som gør sig forhåbninger om at vinde nogen form for design-priser?

Men lad os kigge lidt på det: Når jeg arbejder, så starter jeg selvfølgelig med at lave et antal ændringer, og derefter laver jeg en liste over ændrede filer, som jeg så kører en diff på en ad gangen. Her bestemmer jeg med for, hvilke ændringer, som jeg vil have med i committet - og egentlig ret ofte opdager jeg, at jeg ikke var helt færdig: der er ofte noget, som kan gøre lidt bedre eller pænere. Og så tager jeg lige en iteration eller to mere.

Kast nu et blik på screendumpet. I panelet med den røde top er en liste over alle de filer, som er ændrede - eller nye - i mit arbejdsområde. Det var lige første trin, som jeg fik forærende. I panelet med den gule top, kan jeg se diff for den valgte fil - og det var andet trin. Efterhånden som jeg arbejder mig igennem filerne, så kan jeg klikke på ikonet ud for filnavnet, og så smutter de lige ned i panelet med den grønne top, som er en liste af de ændringer, der er planlagt til næste commit; og det er noget, som jeg normalt selv skal holde styr på. Nederst til højre er en god editor til at skrive commitkommentaren i - og selvfølgelig er den fremme hele tiden, så man kan udfylde kommentaren imens man reviewer sine ændringer, og ikke som det er for mig pt., nemlig at jeg må tage noter for mig selv undervejs, inden jeg til sidst får lov at skrive en kommentar.

Eller med andre ord: her er et værktøj lige efter mit hovede - alle de nødvendige dele er placeret nemt og overskueligt, lige inden for rækkevidde, lige hvor man har brug for det. Der er tænkt på det hele. Skønt!

Allerede her var jeg sådan set solgt, men bemærk så lige en ekstra lille detajle (det kan godt være, at du skal klikke på billedet for at se det i stor størrelse): filen Method.scala er nævnt både under unstaged og staged! Det er fordi, at jeg har rettet videre i den efter at jeg stagede den til commit først gang - og det diff, som jeg kan se under unstaged, er det, som er sket siden seneste staging - og det, som jeg kan se under staged er det, som er sket imellem seneste commit og seneste staging (eller det, som kommer med i dette commit, hvis ikke jeg gør yderligere). Det er en rigtig god lille bonus.

...og husk så på, at git er et distibueret versionsstyringssystem - når jeg engang committer, så er det kun imod mit lokale repository - for at det kommer videre, så skal det enten pushes videre af mig, eller pulles af andre.

onsdag den 11. februar 2009

Kloner og gists

Jeg må tilstå: jeg har en temmelig underlig interesse, nemlig versionsstyring og versionsstyringssystemer. Jeg har tidligere skrevet lidt forskelligt om emnet, men på det seneste er jeg så småt begyndt at interessere mig for Git.

Git i sig selv er mange ord værd, men det er faktisk ikke det, som jeg vil skrive om her; mest fordi at mine erfaringer indtil videre er noget begrænsede (for en knap så kort oversigtsartikel om git, vil jeg henvise til Wikipedia).

Næh, det som jeg har på hjerte er, at jeg har fundet git-hub, som er et site, hvor man kan få hostet sine git-repositories. Og hvis man er villig til at dele sin kildetekst med alle (det hedder vist nok "Open Source"), så koster det gratis.

Det, som man giver andre ret til, er at se hele versionshistorikken, og at starte deres egen variant - det hedder meget passende "kloning" - men ikke til at committe direkte til ens eget repository. Klassisk set er det, at få "gaflet" (forked) et projekt noget af det, som har givet anledning til de fleste søvnløse nætter og de største ord-krige, men her er det faktisk noget, som ikke alene er indbygget i både git og git-hub - det er faktisk noget, som man aktivt opfordrer til. For den bagvedliggende tanke er ikke, at vejene skal skilles for evigt, men i stedet at man for en kort bemærkning lige afsøger området omkring den slagne sti, for så at vende tilbage igen med det gode, som man måske fandt. For rettelser fra kloner kan snildt indarbejdes i det oprindelige repository, og herved har man nærmest vendt begrebet på hovedet: hvis kloning er noget man gør hyppigt nok, så er det en ting, som man kan udnytte positivt.

Og der er ingen der siger, at den oprindelige vej, er den bedste, så måske vil de fleste i stedet vælge det, som oprindeligt var en afstikker, hvorved det så bliver hovedvejen. Det vil i sandhed være realisering af begrebet "shared source": ingen ejer kildeteksten; og alle har lige ret til at komme med deres bud på fremtiden.

Nå, men inden dette bliver alt for lomme-filosofisk, så vil jeg lige pege på en sjov lille ting på git-hub, som de kalder for "gists" - det er en slags mini-repository, eller en slags offentligt klippebord for filer med fuld versionshistorik. Om det kan bruges til noget i praksis, ved jeg ikke helt, men jeg måtte simpelthen prøve det af, så jeg har oprettet mit eget lille gist - ikke noget specielt, bare et lille fragment fra mine første eksperimenter med Scala og Xml. Men kom og leg med, hvis du har lyst - det er det, som git-hub går ud på!

lørdag den 4. oktober 2008

Scala i praksis

Jeg har brugt en del tid på det seneste på at kigge på sproget Scala, som er et spændende forsøg på at lave et multiparadigme sprog baseret på JVM'en. Jeg valgte Scala af en række grunde:

Vigtigst af alt, så oversætter Scala kode til JVM class-filer, og andre JVM klasser kan nemt integreres. Som Java kyndig brænder man altså ingen broer - man kan stadig bruge alt det, som allerede findes på platformen, og man kan flette ny Scala kode sammen med sin eksisterende Java.

Der er en ganske hæderlig typeinferens. Typeinferens ligner på overfladen "duck typing", men nedenunder findes et stærkt statisk typecheck. Det er en meget stor behagelighed, når man koder, for hvis typen kan regnes ud af sammenhængen, så klarer compileren det som hovedregel fint. Man undgår med andre ord at skulle gentage sig selv igen og igen overfor noget som virker som en meget tungnem compiler.

På den anden side, så kommer compileren en gang imellem og brokker sig over inkompatible typer. Hver gang har jeg tænkt, at her var den godt nok noget fatsvag, men hvergang har jeg modstræbende måtte erkende, at her havde den altså ret: Jeg havde ikke styr på, hvad jeg lavede og jeg var ved at blande fisk og cykler. Mine to mest almindelige fejl var, at jeg ikke var helt fortrolig med syntaksen for delvist anvendte funktioner (partial applied function), og når der havde sneget sig en anden resultattype ind (så funktionens resultat blev den fælles supertype i stedet for den første resultattype) .

Den tredje grund til at vælge Scala var, at det understøtter et funktionelt paradigme - det er nyt for mig, for jeg har stort set kun programmeret i imparative (procedurale og objekt-orienterede) sprog - med SQL som en mærkbar deklarativ undtagelse. Jeg har stadig meget svært ved at tænke funktionelt (Scala-kode kan også laves imparativt), men det er en stor lettelse for mig, at funktionen nu igen har fået en fornem placering i sproget - i Pascal var den nogenlunde med, men i Java har man holdt den objekt-orienterede fane så højt, at funktionen blev sat godt og grundigt i skammekrogen; det har gjort det nødvendigt for os at lave store og grimme krumspring undervejs for at omgå begrænsningerne. Da Scala er et funktionelt programmeringssprog, så har jeg pludselig fået nogle nye og spændende muligheder, som jeg ikke har set før, og som jeg virkelig kan se et stor potential i (mumle, mumle, golden hammer, mumle, mumle...)

Jeg tror nok, at det var Kung-fu-tze, der engang sagde noget i retning af:
"Læsning skaber en oplyst mand, overvejelse en vis mand - men kun handling den fuldkomne mand".
Jeg har læst, og jeg har overvejet ... og nu har jeg også prøvet at skrive mit første ikke-trivielle program i Scala. Det var egentlig en skrivebordsøvelse og baserer sig på ideen om, at skal man lave et godt hold, så skal man ikke finde folk, som er gode til de samme ting, men derimod folk som kan supplere hinanden.

Jeg havde den første prototype kørende på kun 14 liniers kode! Den havde godt nok hardkodet input, og kun en variant af klassifikationen, men ellers var der ikke snydt; den var fuldt funktionsdygtigt, og viste at princippet fungerede. Den baserede sig på lister, tupler, int og string - og derfor havde jeg tit svært ved at holde tungen lige i munden.

Efterfølgende er ansvaret blevet fordelt ud over diverse klasser, og alle klassifikationsregler blev implementeret. Herved steg antallet af kodelinier til det 10-dobbelte; det er en solid stigning, men stadig imponerede lidt problemstillingen taget i betragtning.

Lige nu er programmet oppe på ca. 230 linier, men så er der også parsning af input i løst formatteret tekstformat og pæn sortering, klassificering og formattering af output. Jeg tror, at et Java program til at det samme nemt kunne være løbet op i det 3-dobbelte antal kodelinier.

Et sprog, som kan spænde over at lave en kompakt teknologi-mockup og direkte op til et fuldt program - og gøre det godt hele vejen - det er da vist ikke helt skørt?

En ting, som jeg har bemærket undervejs, er funktionel programmering hele tiden får en til at overveje muligheden for generaliseringer - det er ikke mindst forklaringen på, hvorfor at koden bliver så kompakt - det ender med at blive noget som næsten ligner one-liners uden at det udarter sig til at blive Perl; man ender med kode præcis som man tænker.

En generalisering, som jeg stadig har til gode, er at eksternalisere kategorierne og klassifikationsreglerne. Jeg har sådan set allerede lavet det grundlæggende arbejde, for selvom de er hardkodet, så er det lister af instanser af nogle få kategoriklasser og nogle få meta-klassifikations-funktioner. Derfor kan programmet godt ende med at blive mindre igen, samtidig med at det bliver mere generelt.

søndag den 14. september 2008

Navngivne parametre

Jeg faldt over Alex Buckleys blogpost Named Parameters, hvor han diskuterer muligheden for explicit navngivne parametre i Java/JVM'en, og det er jo ganske interessant - ikke mindst i betragtning af, at det netop af Alex, som skriver.

For dem, som ikke kender Alex Buckley, så kan jeg fortælle, at han har overtaget Gilad Brachas plads som JVM'en kustode. Hans fornemmeste opgave er derfor at sige "Nej!" til alle de skøre forslag, som alle vi andre kommer med - og kun at lade en lille, vel gennemtænkt smule slippe igennem, så JVM'en og Java aldrig løber af sporet.

Om Gilad Bracha er der en lille anekdote: Jeg oplevede ham til JAOO for nogen tid siden (2005), og hans foredrag var om nye muligheder i JVM'en med henblik på at forbedre understøttelsen af dynamiske sprog (specifikt om invokedynamic). På et tidspunkt under foredraget kommer en slide op, hvor et punkt er markeret med "OMDB" (nederst s. 33 her). Jeg kan huske, at jeg sad og overvejede, hvad det stod for - "Object Method Data Base" eller måske "Overloadet Method Definition Basis". Vi kommer lidt længere hen inden at Gilad afslører, at OMDB står for "Over My Dead Body" - og det var det at jeg tænkte to ting:
  1. Hvor var jeg glad for, at vi havde en så konservativ person til at hænge i bremsen på noget som vigtigt som JVM'en.
  2. Hvis man siger sådan noget, hvad gør man så, hvis folk er villige til at tage en på ordet?

Nå, men jeg løber ud af en tangent - jeg ville jo snakke om Alex' blogpost om navngivne parametre...:

For dem, som ikke lige har tid til at læse Alex' blogpost, så kan jeg sige, at han identificerer to store fordele:
  1. Øgede muligheder for at skrive kode, hvor det er umiddelbart til at forstå hjensigten - og ...
  2. Muligheden for at angive parametre i vilkårlig rækkefølge, hvis de navngives (herunder nogle overvejelser om varargs).

og Alex konkluderer i Gilads ånd, at nr. 2 nok er en ide med store fordele, men at den vil have store problemer rent implementationsmæssigt - hvis man skulle bevare bagudkompatibilitet, vil det ikke er praktisk muligt, og der er andre udfordringer; hans holdning er dog, at nr. 1 allerede give så store fordele, at det er værd at overveje.

Jeg er enig.

...men nu er jeg også typen, som bliver irriteret hver gang jeg ser en metode, som tager en eller flere booleans som parametre, fordi at jeg ved, at jeg ikke om 3 måneder kan huske, om:

udskriv("en tekst", true, false)

betyder, at der skal udskrives med bold og ikke italic, eller omvendt - og derfor ender med at skrive:

final boolean isItalic=true;
final boolean isBold=false;
udskriv("en tekst", isItalic, isBold);


hvilket selvfølgelig øger antallet af kodelinjer med 200% (hvilket er skidt!), men som til gengæld klart giver udtryk for, hvad der var min hensigt, da jeg skrev koden (og det opvejer det efter min mening fuldtud).

Til gengæld er der tale om en noget af et deja-vu: Allerede i forrige årtusinde kunne man angive navngivne parametre i VAX-Pascal (VAX-Pascal fandtes til VAX/VMS mainframes fra DEC, og som sprog var det på mange måder forud for sin tid). Jeg husker ikke klart, om VAX-Pascal havde operator-overloading, men navngivne parametre var helt klart en del af sproget, som jeg brugte (ikke meget - bevares - som Alex er inde på, så er det nok mest en "smell" i grænsefladen, når man finder det nødvendigt) - og som jeg kom til at savne.

På samme måde har jeg stort set altid brugt parameterbinding i mine SQL-udtryk (fordelene er så mange og så indlysende, at jeg ikke vil nævne dem her) - og hver gang er jeg blevet irriteret over, at parameter-markøren i standard-SQL er et anonymt lille spørgsmålstegn. Som oftest har irritationen affødt, at jeg er endt med at skrive min egen lille wrapper, som tager en streng og et map (eller en lignende datastruktur), hvor der i stregen laves substitution på navngivne parametre, og at der formatteres en passende liste af parameterværdier. Det betyder, at man aldrig mere skal sidde og tælle spørgsmålstegn - og det betyder også dels, at man dels kan stoppe nye parametre ind i midten af et udtræk, uden at det hele kommer ud af sync - og dels, at man pludselig kan bruge den samme værdi flere gange uden at skulle gentage den.

Så, Alex, jeg er 100% bag dig - lad os få muligheden for navngivne parametre i Java - det er på høje tid!

lørdag den 23. august 2008

Stop op, og tænk dig om!

Det sidste stykke tid er vi nogle stykker, som har brugt en god del af vores tid på, at sidde og skrive testcases til vores nuværende projekt. Altså ikke småhygget med at programmere automatiske tests, men siddet og skrevet hardcore manuelle tests med "blyant og papir (dvs. vi har heldigvis en god wiki, og det gør arbejdet mange gange nemmere - hvis du er så uheldig, at du ikke ved, hvad en wiki er, så tænk "tekstbehandling", og du er ikke helt galt på den).

Man kan sige, at det er noget sent i forløbet, at vi får taget os sammen til at skrive testen - vores system har, for størstedelen af det, været i produktionslignende pilotdrift i noget, som efterhånden begynder at ligne et års tid. Når vi aldrig fik skrevet en formel test i første omgang, så er det nok fordi, at applikationen er groet langsomt frem, og pilotdriften er noget, som næsten er kommet snigende. Men nu, hvor applikationen bliver godt og grundigt hovedrenoveret, så er det en glimrende lejlighed til at få skrevet sådan en test.

Vi, der skriver testen, kender applikationen så godt, at vi sidder og skriver den "kold". Vi sidder altså ikke med applikationen kørende i baggrunden, imens vi skriver - vi skriver bare testen direkte fra hovedet og ned på papiret. Derfor kom det også som noget af et chok for mig, at min kollega pludselig kigger op og siger: "Bjarne, jeg har fundet en større fejl!" Jeg mener, fejl det er da noget, som man finder, når man prøver at bruge applikationen, ikk'? Og den har været i drift igennem længere tid uden problemer - så hvordan kan han sidde der, og så lige ud af den blå luft sige, at der er en fejl?!?

Men der var en fejl. En måde at bruge applikationen på, som ville give vildledende resultater. Det er nærmest tilfældigheder, som har gjort, at vi ikke er rendt ind i den - og vi introducerer lige om lidt ny funktionalitet, som ville have gjort det ganske sandsynligt, at rigtigt mange ville have oplevet det i praksis. Den eneste grund, til at vi fandt den nu, var, at vi, i og med at vi skulle skrive testen, havde tvunget os selv til at sætte os ned, og tænke applikationens brug systematisk igennem.

Micheal Feathers beskriver det samme fænomen i sin blog-post "The flawed theory behind unit testing". Det spørgsmål, som han stiller sig selv, er egentlig meget simpelt: Hvordan kan det være, at programkode, som er blevet unittestet, indeholder færre integrationsfejl? Og her tænker han ikke på fejl, som kunne være fundet af en unittest, men som på grund af utilstrækkelig unittest, først bliver fundet i integrationstesten - næh, det som undrer ham er, at det at lave unittesten tilsyneladende forhindrer flere fejl i at opstå, end hvad selve testen rent faktisk verificerer. Læs selv hans blog, den er kort og letlæst, og den kommer også forbi andre emner, som f.eks. TDD.

Michaal Feathers konklusion er, at unittestens umiddelbare værdi ikke så meget af selve testen (selvom han ikke er blind for, at automatiseret test øger muligheden for at lave efterfølgende ændringer på en sikker måde), men derimod at det tvinger os til at sætte os ned og tænke systematisk over det, som vi vil lave (eller måske lige har lavet). Han siger selv afslutningsvist:
The truth is more subtle than that. Quality is a function of thought and reflection - precise thought and reflection. That’s the magic. Techniques which reinforce that discipline invariably increase quality.

Det var det, som min kollega oplevede - og jeg har selv oplevet det, når jeg har siddet og skrevet unittest: Pludselig finder man grundlæggende logiske fejl i det, som man har implementeret - altså ikke fejl i implementationen, men i præmisserne for den. Jeg har bare ikke rigtigt tænkt over det, førend Michael Feathers satte sin finger på det.

Kelly Waters er inde på noget af det samme i sin blog-post "Agile project initiation": Her beskriver han de lange dokumenter, som mange projektmodeller foreskriver, at man udarbejder inden et projekt starter op - dokumenter på over 50 sider, som det er vanskeligt at få nogen til at læse. De fleste folk, som skriver noget med "agil" i deres CV, vil her sige, at hvis der ingen er, som læser det, så skal man helt lade være med at skrive det. Men Kelly Waters bemærker, at det giver ham værdi - det tvinger ham nemlig til at tænke projektet igennem på en systematisk måde. Hans bud på, hvad man så gør, er at lave det som en powerpoint-præsentation, for dels kommer han igennem de samme overvejelser, og dels så kan han bruge det, som en diskussionsoplæg, og derved ydermere få en feedback, som han ikke oplevede ved de lange dokumenter. Powerpoint virker for ham, men pointen er vel, at alt hvad der ville tvinge ham til at arbejde sig systematisk igennem overvejelserne, ville være lige så godt.

Så, stop op, og giv dig tid til at tænke dig godt om - det er bedre, at komme stille og roligt afsted i moderat fart i den rigtige retning, end det er straks at sprinte afsted i den forkerte. Men det er ingen opfordring til at tage en "morfar" i hængekøjen - det virker kun, hvis du tvinger dig selv til at arbejde dig systematisk igennem det.

PS: Måske er det derfor, at COBOL programmer stadig er så udbredte - der er man pinedød nødt til at tænke sig godt om, inden man gør noget! :-)

mandag den 30. juni 2008

Indre klasser

I, mine faste læsere, kender mig godt nok til at vide, at det ikke er samfundskritik, som overskriften lægger op til. I stedet vil jeg filosofere lidt over den syntaktiske finurlig med dette navn, som jeg har stiftet bekendskab med i programmeringssproget Java.

Det, som har inspireret mig, er et indlæg på Michael Feathers' blog: Are Nested Classes Really a Good Idea? Jeg kan godt afsløre her, at det synes han ikke, men han er fornuftig nok til at mene, at det mest er et spørgsmål om stil. Indlægget er ikke længere end, at jeg vil opfordre til, at man selv læser det.

Langt hen ad vejen er jeg enig med Michael Feathers - når de indre klasser har tyngde nok til at være "rigtige" klasser, så er det ofte sådan, at det er bedre at gøre dem til det - altså rigtige klasser for sig selv. Indre klasser er ... ja, ikke sådan direkte forkerte, bare akavede - de ødelægger ofte rytmen i programmet.

Når jeg koder, så skriver jeg ofte og gerne indre klasser. Det sker, når jeg under kodningen ser et skift i abstraktionsniveauet, eller måske identificerer jeg et afvigende ansvarsområde; det er de her små urenheder, som måske - måske ikke - er starten til udkrystalisering ... og det er her, at jeg ofte bruger indre klasser. Man kan mene, at jeg her lige så godt kunne have lavet en rigtig klasse fra starten af, men det meget hurtigere - og på sin vis også langt mere uforpligtende - lige at lave en indre klasse.

På det tidspunkt, hvor jeg kan mærke, at nu har koden fundet et naturlig leje, så er der en tendens til, at jeg løber de indre klasser igennem. De indre klasser, som har tyngde og substans, vil jeg som tommelfingerregel forfremme til "rigtige" klasser - og for de øvrige vil jeg ofte overveje, om ikke der findes alternativer, som lige så vel kan kommunikere den "lille" indre klasses struktur og hensigt. Det er sjældent, at jeg committer kode med indre klasser, som bare er klasser (i modsætning til closure-agtige indre klasser, men det kommer jeg til).

Måske er min fremgangsmåde opstået fordi, at jeg kommet til Java via Pascal - jeg husker stadig smerten ved ikke at kunne lave lokale funktioner og procedurer: Jeg følte, at jeg blev tvunget til at gøre klassen ujævn i sin natur, og jeg havde svært ved at leve med, at jeg ikke kunne begrænse scope for en metode til en sub-kontekst. I virkeligheden, så har det vist sig, at jeg kan komme langt med at dele klassen op i interface og implementation (og understrege dette med bevidst brug af synlighed) - og hvor det ikke er nok, så er det ofte fordi, at jeg prøver at gøre for meget på en gang.

Det, som normalt får mig til at tøve en kende, er, når den indre klasser er meget tæt koblet til den ydre klasse, og måske endda nært forbundet til implementationen af den. Tit er det bare dovenskab eller manglende klarhed i ansvarfordelingen - men tit er det også ubehaget ved at forurene pakkens interface med noget alt for detajleret og måske internt af natur; for den oprindelige ydre klasse var ment til at skulle bruges for andre udefra, mens den indre klasse mere var en service for den oprindelige yde klasse. Løsningen er den samme, som for metoder i klasser: man erklærer kun det, som er del af interfacet for public (en lille sidebemærkning: lige så vel som klasser har et interface, så har pakker det også - og ofte drevet af de samme overvejelser; og når Java får et eksplicit modulbegrebet, så får vi endnu et niveau, at definere interfaces på ... men det er en anden historie).

Javas "far", James Gosling, skrev for nyligt under titlen Closures bl.a. flg.:
In the early days of Java the lack of closures was pretty painful, and so inner classes were born: an uncomfortable compromise that attempted to avoid a number of hard issues.
Indre klasser er mao. noget, som ikke engang dets ophav vil kendes ved!

Closures er (eller måske rettere: har indtil for nyligt været) meget omdiskuteret i Java kredse, og det er vel netop det sted, hvor jeg selv anvender indre klasser mest eksplicit, nemlig når jeg gerne vil skille det generelle fra det specifikke. Man kan selvfølgelig prøve med template method og nedarvning, men personligt, så fortrækker jeg ofte noget, som i stedet bruger komposition (og derfor mere ligner strategy): I den generiske del erklæres et indre interface, og når det generiske skal anvendes, så bliver interface som oftest implemeteret ved en indre klasse hos anvenderen.

Closures vil da gøre dette nemmere, og den typiske indvending imod closures, nemlig at de ofte er anonyme, er, på samme måde som ved anonyme indre klasser, selvvalgt - og vel også i bund og grund et spørgsmål om stil. Men netop her er smerten ikke så stor, for indre klasser løser faktisk den del rimeligt OK - der findes værre dele af Java. Synes jeg.

Så, for lige at vende tilbage, og svare på spørgsmålet i Michael Feathers' overskrift: Nej, indre klasser er ikke ligefrem nogen genial ide - men på den anden side heller ikke nogen udpræget dårlig ide ... hvis bare man bruger den med omtanke og omhu. Og det kan man jo sige om så meget!

søndag den 1. juni 2008

Er syntaktisk sukker tomme kalorier?

Jeg havde i denne uge fornøjelsen af, sammen med Rasmus, at deltage i et gå-hjem-møde om "C# 3.0 og LINQ" arrangeret af Niels Ladegaard Beck fra Trifork. I forbindelse med gennemgangen af nye features i C# 3.0 lød det på et tidspunkt som om, at Niels nærmest undskyldte, at der nok mest var tale om "syntaktisk sukker". Det fik mig til at sidde og tænke over, om hvorfor syntaktisk sukker nærmest er blevet et skældsord, og på om det er rimeligt?

Lad os starte med at prøve på at definere begrebet "syntaktisk sukker". Her er et godt bud:
Syntactic sugar gives the programmer an alternative way of coding that is often more practical, more conducive to a better programming style, or more natural to read. However, it does not typically affect the expressiveness of the formalism or permit the language to do something new.
(kilde: Wikipedia: Syntatic sugar).

Syntaktisk sukker er altså en anden, og måske mere bekvem, måde at sige det samme på. Hvis man kan sige noget nyt, så er det per definition ikke syntaktisk sukker. Og så er det, at asketer og purister siger fra - en måde at gøre tingene på, det må da være mere end rigeligt, vil de mene!

Men hvad er det så lige, at formålet med et programmeringssprog egentlig er? Ja, vel indlysende nok, at være medie for en instruktion til en computer, men vel mindst lige så indlysende, at gøre det på en human og forståelig måde.

Hvis man har prøvet at være i en situation, hvor man er normsættende, så har man sikkert også på et tidspunkt hørt sig selv sige: "Du skal ikke gøre, som jeg gør - du skal gøre, som jeg siger!" Med computere er problemet lidt omvendt, og havde man kunnet tale til dem, så ville man sikkert kunne høre sig selv sige: "Du skal ikke gøre, som jeg siger - du skal gøre, som jeg mener!" På samme måde, så har man, når man har prøvet at forklare noget til andre, sikkert også hørt sig selv sige: "...lad mig prøve at forklare det på en anden måde".

Et godt sprog skal derfor dels kunne give utvetydige instruktioner, men samtidig formidle en præcis forklaring af hensigten. En præcis forklaring uden unødige omsvøb er en god forklaring - også selvom den måske ikke lige overholder den gængse opfattelse af formalia og regler for, hvad der er den rette tone. Syntaktisk sukker er derfor et spørgsmål om forklaringsevne, og ikke et spørgsmål om udsagnskraft. Syntaktisk sukker giver os muligheden for at formulere os på mere end en måde, og derfor muligheden for at vælge den mest hensigtsmæssige.

Syntaktisk sukker behøver derfor ikke at være et spørgsmål om bekvemmelighed eller dovenskab (i en sidebemærkning vil jeg så mene, at de to vigtigste menneskelige egenskaber er nysgerrighed og dovenskab, så ikke et ondt ord om dovenskab - vi havde aldrig opdaget hjulet, hvis ikke vi var nysgerrige, og vi havde aldrig fået det udnyttet, hvis ikke vi var dovne!) - syntaktisk sukker er i mindst lige så høj grad et spørgsmål om, at kunne udtrykke det, som man mener. Når man skriver programmer, så formidler man forståelse af en fremgangsmåde - dels til computeren, men også til mennesker, både ens fremtidige jeg, men også alle andre, som bliver konfronteret med ens kreation. Jo mere præcist at man er i stand til at udtrykke sig, jo bedre bliver meningen formidlet.

Eller for at sætte det på spidsen: Computeren skal nok forstå, hvad du siger - men kan du selv og andre forstå, hvad du mener?

Niels fra gå-hjem-mødet i indledning vil sikkert være enig med mig i ovenstående, for hans foredrag var i høj grad et eksempel på, hvordan man med de nye ting i C# 3.0 og LINQ kunne skære ned på formalia, og dermed øge læseligheden.

Et oplagt eksempel, hvad mange vil kalde syntaktisk sukker, er Type inference (hvordan oversætter man i øvrigt"type inference" til dansk?). Ortodokse tilhængere af statisk type check vil sikkert bruge begrebet nedsættende, i det de argumenterer for, at den reducerede formalisme forringer sprogets evne til i kraft af sin opbygning at medvirke til at undgå fejl. Det er da også muligt at komme på eksempler, hvor det er tilfældet. Men den anden fløj i debatten vil mene, at det som oftest i stedet tvinger os til at gentage det indlysende grænsende til det absurde. Ved at fylde teksten op med unødvendige trivialiteter, så fjerner man opmærksomheden fra det væsentlige - eller men andre ord, ved at gøre det nemt at finde fejl i formalia, så gør man det sværere at se fejl i logikken. Jeg hælder nok mest til det sidste synspunkt - og er det sandt, så er det da at smide barnet ud med badevandet!

Hvis du er med så langt, så vil du sikkert have fornemmet, at mit holdning til spørgsmålet i overskriften er, at syntaktisk sukker ikke nødvendigvis er tomme kalorier - og måske endda som oftest det modsatte. Det er så her, at jeg bliver nødt til at padle baglæns, for mit argument står og falder med at syntaktisk sukker kan gøre det nemmere at formidle overblik og hensigt. Men engang imellem, så er der udelukkende tale om bekvemmelighed og dovenskab - og desværre på måde, som gør det sværere at få overblik eller forstå hensigten. Oftest er der tale om et tveægget sværd - det, som kan give fornuft, kan også misbruges. Ikke alt sukker er godt sukker - og nogen steder er selv lidt sukker for meget sukker!

Et eksempel på det tveæggede sværd kunne være operator overloading. Det er oplagt, at man her har muligheden for på en kompakt måde hurtigt at formidle overblik og indsigt. Men det kommer med en betydelig risiko for at blive misforstået (eller, hvis det kommer i de forkerte hænder, at blive direkte vildledt!).

Et andet eksempel stod gå-hjem-mødet for, nemlig C# 3.0 extension methods. Her var der tale om adskillige løftede øjenbryn, og en af deltagerne slog hovedet på sømmet med en bemærkning om, at det ville gøre det meget vanskeligt at finde ud af, hvor funktionaliteten stammede fra uden understøttelse fra ens IDE (og her vil jeg så tilføje, at det altid er en Beck'sk "stank", når ting bliver så komplicerede, at man bliver afhængig af værktøjer til at hjælpe en med at håndtere kompleksiteten - her skal man altid spørge sig selv, om kompleksiteten er iboende eller tilfældig!). Jeg tror, at alle kunne se meget af det gode, som extension methods ville gøre muligt, men jeg er også overbevist om, at vi var adskillige, som havde et dårligt deja vu - sikkert forårsaget af konkrete oplevelser med f.eks. operator overloading.

Til slut vil jeg lige svare på mit spørgsmål til mig selv i indledningen: Jeg tror, at syntaktisk sukker som begreb har et dårligt rygte på grund af alt for mange eksempler på dårlig implementering. Men et princip kan sagtens være godt, selvom der findes eksempler på dårlig anvendelse - og derfor vil jeg også mene, at det dårlige rygte er uretfærdigt. Eksemplerne på dårlig anvendelse skal dog mane til forsigtighed, og vi skal vælge vores leverandør af sukker med omhu, og tilsvarende selv være bevidst om faren ved overdreven eller forkert brug af sukker.

(en lille og helt urelateret regi-bemærkning: Jeg startede med at skrive dette på en smuk sommerdag, og jeg lå derfor ude i skyggen under det store æbletræ i vores have - jeg kunne derfor have skrevet en lovsang om den frihed, som de såkaldt trådløse teknologier giver os ... men jeg nåede kun halvvejs, førend det væltede op med advarsler i stærkt stigende streghed om, at nu var der altså snart ikke mere strøm på batteriet! Jeg endte derfor med at sidde indenfor i lummerheden bundet til en stikkontakt - jeg glæder mig til den dag, hvor energiforsyningen også reelt bliver trådløs!)

søndag den 4. maj 2008

Læsning

Jeg læste engang et interview med en person, som mente, at skrev man af efter en bog, så var det plagiat - men skrev man af efter tre bøger, så var det forskning. Jeg er ikke i gang med at skrive, men derimod med at læse, og jeg læser for tiden i tre bøger på en gang - og det er vist af alt besværligt!

Grunden til, at jeg er havnet i denne noget håbløse situation, ikke mindste det aktuelle vejr taget i betragtning, er, at jeg har fundet en virkelig spændende bog på nettet. Dels så er det faglitteratur og dels, så er det meget lidt transportabelt, så jeg har også gang i noget skønlitteratur og en "død skov" version af noget andet faglitteratur.

Den bog på nettet, som jeg er ved at tygge mig igennem, er Scala by Example, og den indeholder en eksempelorienteret introduktion til programmeringssproget Scala. "Hvorfor lige Scala?", er der sikkert en del af jer, som nu sidder og spørger jer selv. Ikke for noget specielt, er mit svar - jeg havde bare brug for at prøve noget nyt. Jeg synes lidt, at Java/C# og venner er ved at have nået så langt, som de kan komme, og at udviklingen på den front er blevet lidt ukoordineret "sådan en må vi også have" - og så lød Scala, som et spændende bud. Men jeg regner nu ikke med at komme til at skrive særligt megen kode i Scala, om nogen overhovedet.

Det er måske heller ikke så vanvittigt interessant, at netop jeg lige i denne tid kigger i retning af netop dette sprog. Det mest interessante for mig er såmænd heller ikke selve sproget - jeg er nemlig pludselig blevet meget klogere på ting som f.eks.:
  • funktionel programmering
  • currying
  • generiske typer
  • covarians og contravarians
  • lister
...bare for lige at nævne det, som jeg kunne komme i tanke om på stående fod (ok, currying skal jeg nok lige vende en gang eller tre mere inden jeg helt har styr på det - enten er det ufatteligt simpelt, eller også har jeg overset noget - og min fornemmelse siger mig, at det godt kunne være det sidste).

Jeg kan også godt lide den eksempelorienterede tilgang. Det er jo ret mange interessante ideer, som sproget prøver at give et fornuftigt bud på en implementation af, og selv hvis man ikke lige har lyst til at hænge sig i den præcise syntaks, så vil man få ganske meget ud af eksemplerne - de prøver nemlig også at forklare den bagvedliggende ide. Og det bedste af det hele for mig er, at sproget ikke ligger længere fra mit nuværende hovedsprog (Java) end at jeg faktisk allerede har kunnet bruge elementer og ideer fra bogen.

For jer hardcore dataloger derude, så er der sikkert ikke så meget at hente, men hvis du er en halvstuderet røver som jeg, og har mod på at få udvidet horisonten, så kommer ovenstående "bog" med mine anbefalinger.

søndag den 30. marts 2008

Udvidbarhed

Jeg har lige siddet og læst Jeff Atwoods blog The dark side of extensions, hvor han argumenterer for, at ulempen ved at basere sig på udvidelser (extensions) er, at mange ikke benytter sig at tilbuddet om personalisere produktet - de bruger den basale version.

Hans eksempel er Firefox i forhold til Safari, og hans budskab er, at Firefox er en platform, hvor Safari er et færdigt produkt. Nu kan man altid diskutere, hvem som "slår" hvem, men jeg er enig i Jeffs præmis om, at Firefox først virkelig skinner igennem, når man har fået personaliseret den med en god håndfuld udvidelser. Og sådan skal det i følge firefox-bagmændene være, også selvom det betyder at Safari er milevidt foran Firebox, hvis man tager begge "out-of-the-box".

Så langt er jeg enig med Jeff - og havde jeg været helt enig med ham, så var der ikke kommet en blog ud af det. Men jeg er kun enig med ham i præmisserne. Hans konklusion er, at man med jævne mellemrum skulle folde de mest populære plugins ind i platformen. Hans holdning er mao. at man skal lave programmerne udvidbare og tilpasningsvenlige i håbet om at få et "community" op og stå, og så jævnligt og systematisk høste de ideer, som har den største overlevelsesevne (hvordan oversætter man i øvrigt "community"? - "software-økosystem" er mit bedste gæt, og det lyder alt for højstemt) .

Ja... - og så alligevel nej. Selvfølgelig skal man høste det bedste af det bedste, og selvfølgelig skal man hele tiden holde et vågent øje med, hvordan verden udvikler sig. Men ideen om rutinemæssigt at udvide platformen med det mest populære er, efter min mening, helt forkert. Det er tanken om at "one-size-fits-all", og det er i direkte modstrid med tanken om en fleksible platform. Hvis det får lov at løbe over nogen gange, så vil det slide systemet ned, og det vil miste sin dynamik. Man vil godt nok stå med et fint produkt, men det vil være et produkt, som kun er fint lige nu (og kun for "flertallet" - som jo som oftest ikke er så stort, som det lyder til - og et "flertal" som vil svinde ind over tid). Jeg vil personligt ikke bryde mig om det - for mig er retten til at kunne vælge fra mindst lige så vigtigt, som muligheden for at kunne vælge til.

Det man i stedet - efter min mening - bør gøre, er at kigge i retning af færdigpakkede løsninger. Der kan være en basismodel for den omkostningsbevidste, en mellemmodel til os almindelige, og en luksusmodel til dem, som vil have det bedste af det bedste - eller modeller, som retter sig imod forskellige brugsmønstre. Men stadig med frie muligheder for at vælge en anden radio (hvis det er biler) eller en bedre adblocker (hvis der er en browser).

Hvis man vil se, hvordan det kan gøres, så kan man kigge på Eclipse (Eclipse er - i sin traditionelle form - et java-udviklingsmiljø). Eclipse er både en platform og et community, og der er også til Eclipse et hav af udvidelser. Og alligevel har man, trods det faktum, at man henvender sig til mere professionelt orienterede brugere, lavet pakkeløsninger. Det startede Callisto, som var et forsøg på en samlet release af platformen og toneangivende plugins, og det havde i sig selv stor værdi (Callisto er senere blevet fulgt op af Europa, og snart den kommende Ganymede). Men det helt store værdi ligger efter min mening i, at det muliggjorde at man kunne lave gennemprøvede og sammenhængende standardkonfigurationer af Eclipse.

Eller man kan kigge i retning af Linux. Her har man også en platform og et community - og en række forskellige tilpasningsvenlige pakkeløsninger (man kalder det så godt nok for "distributioner"). Personligt startede jeg i sin tid med Slackware, har siden arbejdet meget med Redhat og Mandrake, og har senest kastet min kærlighed på Ubuntu. Alle har kørt fint "out-of-the-box", men det har alligevel haft stor værdi, at jeg over tid kunne file dem til og justere på dem.

Og det samme bør man efter min mening overveje med Firefox. Det vil give det bedste af begge verdener - en "færdig" løsning, som man alligevel kan tilpasse og forbedre.

tirsdag den 11. marts 2008

Sikkerheds-bjørne-tjeneste

Jeg har - de facto - opgivet den digitale signatur.

"Hvad...", vil nogen måske sige, "...nu er den jo lige ved at blive sikker?" - ja, netop, vil jeg så svare. "Og hvad så...?" vil andre sikkert bemærke - og ja, det har jo aldrig rigtigt været en folkesag, den der digitale signatur, så det er vel ikke noget særligt at vende den ryggen. Men det som dog (forhåbentlig) gør det en lille smule interessant er, at jeg faktisk har været rigtig glad for den.

Men først tror jeg lige, at jeg vil tale lidt om sikkerhedsseler. Kan I huske dengang at sikkerhedsselerne begyndte at komme frem? Kan I huske de der faste seler, som altid var for lange - eller for korte - og som altid snoede og krøllede, så det var et større puslespil at få dem på? Når man så havde fået dem på, så var de enten for løse eller også sad man snøret ind, så man blev helt gasblå i ansigtet. Og skulle de endelig sidde tåleligt, så opdagede man, at man ikke kunne læne sig frem og nå det, som man havde lagt i handskerummet, uden først at skulle tage dem af igen.

Dengang var der mange gode kræfter, som prøvede at få os til at bruge selen, og der var rigtigt mange gode undskyldninger for ikke at gøre det. Hvorfor? Tjo, min påstand er, at det simpelthen var for besværligt. Glem alt om den store risiko og alle de andre gode argumenter - det var en sten i skoen i hverdagen. Nu, hvor rulleseler stort set er standardudstyr, så tænker man ikke længere over det - man spænder bare selen. Ja, og tiden var en anden dengang - dengang kunne man også gå og prale af at have kørt en ordentlig brandert hjem - og det skulle man bare lige prøve på i dag.

Hvad har det så med den digitale signatur at gøre? Jo, hvis sikkerhed skal fungere, så skal det være nemt at bruge - ja, helst så nemt, at man ikke tænker over det, når man bruger det. Bliver det for besværlig - eller såmænd bare for tydeligt - ja, så er der en stor chance for, at man begynder at omgå eller undgå det i stedet.

Den digitale signatur var (i det mindste for mig) løftet om en digital identitet - om muligheden for et signon - om et sted, som kunne sige god for, at jeg var mig. Den ting, som betød, at jeg ikke længere behøvede at oprette brugernavne med tilhørende passwords alle mulige steder. Og, ikke mindst, en sikkerhed, som jeg kunne administrere hos mig, fremfor at skulle stole på at alle mulige rundt omkring forvaltede fornuftigt.

Men, som med alle gode sager, så havde den mange ejere, og deres dagsordner var desværre ikke altid den samme som min:

Bankerne mente ikke at den var sikker nok - og selvom den holdning oprindeligt nok mest at alt var politisk, så er det nok sandt, at vi skal over i noget med en to-faktor autentifikation, for at de kan opnå tilstrækkelig sikkerhed imod misbrug - ikke mindst hvis den ene faktor er fysisk, og derfor ikke så nem at kopiere.

Det offentlige blev udfordret på, at deres professionelle brugere er langt mere mobile end gennemsnittet - og på at computere hos dem sjældent er personlige, men snarere noget i retning af "public terminals". Tid blev derfor en faktor - det var ikke nok, at man havde logget ind, næh, man skal med jævne mellemrum bekræfte, at man stadig er den samme, for jo længere tid der går, jo større er sandsynligheden for, at nogle andre har snuppet skærmen og tastaturet (for en mere teknisk diskussion af udfordringerne, se f.eks. SOSI-projektet).

Begge aspekter har trukket den digitale signatur i en retning, hvor den er blevet mere og mere besværlig at kopiere (desværre også for den retmæssige bruger) - og mere og mere besværlig at bruge.

Jeg bruger normalt Ubuntu, når jeg skal en tur på nettet - opstartstiden slår Windows med en størrelsesorden, og trods det, at den er mere tidssvarende, så kører den væsenligt bedre på utidssvarende hardware som min. Og skulle jeg endelig lige have en Windows kørende, så bruger jeg altid Firefox - den passer simpelt bedre til mine vaner, og hvor den før simpelthen var bedre, så er den udslagsgivende faktor i dag, at jeg har kunnet tilpasse den præcist til mine ønsker. Desværre har jeg efter sidste fornyelse af min digitale signatur, ikke længere kunnet få den til at fungere i andet end Internet Explorer. Og det er simpelthen for besværligt at skulle skifte browser - eller måske endda reboote - bare for at skulle bruge digital signatur.

Det andet problem er, at jeg nu bliver tvunget til at afgive mit password langt oftere end tidligere. At man lige skal aktivere signaturen, er en fin ting - og det ville have været rart, hvis den ikke, som før, var en del af den rodebunke af sager med stærkt varierende grad af følsomhed, som udgør en browsers keystore . Men nu er den simpelthen blevet for hysterisk. Og - som for at føje spot til skade - så tror de websites, som bruger den, heller ikke rigtigt på den, så har man først sagt "logout", så kommer man ikke ind igen, førend hele browseren er blevet genstartet, hvorved hele cirkusset starter en gang til.

Så det kan godt være, at den digitale signatur er blevet mere sikker, og derfor nu kan nå grupper, som før måtte vende den ryggen, men samtidigt er den blevet for besværligt for en casual user som mig. Og jeg vurderer, at det nu, trods alt, er blevet nemmere at rekvirere tastselv-koder og oprette brugerlogins de steder, hvor jeg nu kommer på nettet. Hvad ejerne af projekt "digital signatur" ser som et fremskridt, ser jeg som et tilbageskridt.

...og nu var jeg ellers lige blevet så glad for den!

PS: Jeg ved, at der en af mine læsere som nu sidder og griner, for han har vist mig, hvordan jeg alligevel kan få den flyttet - det husker jeg skam udemærket, pointen var såmænd også kun, at det nu er blevet alt for besværligt set i forhold til alternativet.

torsdag den 28. februar 2008

God SOA

Det har været en mærkelig uge. Jeg har læst to artikler om SOA, som fik mig til at tænke.

Den første artikel, var Computerworld's (ja, ja, og jeg læser også Jumbobøger - og hva' så?) artikel om, hvordan PFA selv mente at SOA havde gjort det muligt for dem at skifte leverandør med meget mindre smerte end ellers (jeg kender ikke CW's holdning til dybe link, så find den selv - den er fra 26. febr. og hedder "PFA-direktør: SOA sikrer nem fyring af mægtige CSC").

Artiklen beskriver, hvordan det at man har kunnet opbygge et grundlæggende antal services for forretningen, og så lade applikationerne tilpasse sig forretningen, fremfor som det klassisk set sker, nemlig at forretningen tilpasser sig applikationerne.

Og som så ofte, så er det mest interessante det, som ikke står der. Der står ikke et ord om teknik. Ingen "Enterprise Service Bus", ingen "WSDL", ingen "UDDI", ingen "MOM". Intet af alt det, som man ellers altid hører soft- og hardwaresælgere fra det store firmaer sige, er den magiske ingrediens i sovsen, som uden hvilken succes ikke vil være muligt.

Den anden var en knapt så konkret blog fra Kaare Kjelstrøm om spader og skovle, hvor han beskriver behovet for en fælles forståelse af domænet som forudsætning for kunne implementere fælles services. "Nåe ja", fristes man til at sige, "det vidste vi da egentlig godt (det havde vi bare lige glemt...)". Eller som Peter Nørregaard siger i en af kommentarerne til Kaares blog: "Hvis ikke det fungerer på papir, så kommer til heller til at fungere elektronisk."

Det fik mig også til at tænke over en af de overvejelser, som jeg i sin tid gjorde mig i min hovedopgave. Den handlede om objekt-orienterede databaser, som lige var ved at blive stort dengang, og der filosoferede jeg over sammenhængen imellem programmer og data:

Mit postulat var dengang, at vi var i den anden af 3 faser (og - mente jeg - lige ved at komme over i den tredje):

Første fase var dengang, hvor programmer og data havde været rodet ubehjælpeligt sammen, så hver program havde sine egne data, og kun programmet selv kunne forstå dem.

Anden fase var, at databaser havde gjort det muligt for data at blive frigjort fra programmerne og blive delt på en abstrakt og generelt tilgængelig form.

Til gengæld, så savnede jeg dengang, at det som jeg kaldte "viden om data" blev frigjort fra programmerne - at vi kom ind i det, som jeg så som den tredje fase. Dvs. at de datanære forretningsregler - som f.eks. at debet og kredit skal stemme i en postering - kom til at følge data. For nok var data delt, men forståelse og håndhævelse af forretningsreglerne lå stadig spredt ud over de forskellige programmer, med alle ulemperne ved redundans. Men data og forretningsregler kunne jo kombineres i forretningsobjekter. Tanken var så, at applikationerne ikke skulle operere direkte på data, men i stedet på forretningsobjekter.

Nu vil jeg ikke påstå, at jeg forudså SOA dengang, for det var jeg slet ikke fremsynet nok til - faktisk så mente jeg dengang i høj grad, at det var de objekt-orienterede databaser, som var det der skulle redde os. Historien har alt for tydeligt vist, at det var forkert - det er alt for detajlenært og slet ikke omfattende nok. Man genbruger ikke objekter - næ, vi skal helt op på service eller komponent niveau, før genbrug virkelig kan give mening.

Så måske er SOA løsningen? Det har i hvert fald større potentiale end objekt-orienterede databaser...

mandag den 11. februar 2008

Hybrid versionsstyring

Jeg har før blogget lidt om distribueret versionsstyring (DVCS), og her kommer lidt mere.

En af de store fordele ved at have en decentraliseret opfattelse af versionshistorikken er, at man ikke har alle sine æg i en kurv. Et centralt repository kan være mere eller mindre utilgængeligt, og har man prøvet det, så ved man hvor fortabt man føler sig. Det kan være så alvorligt, at man skal til at have fat i backuppen, selvom det heldigvis er yderst sjældent. Men det kan såmænd også være noget så simpelt, som at man er udenfor rækkevidde (ja, det kommer nok som et chok, men det er faktisk stadigt muligt at finde steder, hvor der ikke er nogen form for netadgang!).

Skulle man så være helt uden mulighed for at kigge i historikken - eller for at kunne checkpointe udviklingen undervejs med velplacerede commits? Nej vel. Og her kommer distribueret versionsstyring virkelig til sin ret. Og der er jo ikke noget som forhindrer en decentraliseret struktur i netop at have struktur, og derfor i at have et repository, som er mere lige end alle de andre.

Men hvad nu, hvis der allerede er truffet en klog og velovervejet beslutning om at bruge f.eks. Subversion? Er man så tvunget til hele tiden at være online for at få det fulde udbytte?

Ja, i princippet, og så alligevel ikke. For der er jo som udgangspunkt ikke noget som forhindrer en i at versionsstyre de samme filer i to forskellige versionsstyringssystemer, som f.eks. Subversion og Git. Så ville man kunne have en offline historik, offline commits og alligevel kunne koeksistere fredeligt med de andre brugere af det centrale repository.

Dvs. ikke ud over, at det bliver et koordineringsmæssigt mareridt. F.eks. skal ændringer fra det ene skal committes manuelt i det andet.

Men heldigvis er der andre, som har fået samme tanke. Det er f.eks. lavet en integration imellem Git og Subversion med titlen git-svn. Er man mere til Mercurial, så bør man nok holde øje med hgsvn, selvom der vist stadig er plads til forbedring der.

Hvis man kaster sig ud i hybrid versionsstyring af denne slags, så husk at det ikke skal være for at kunne styre at lave sjældne monster-commits - der skal stadig committes de samme sammenhængende klumper af funktionalitet så ofte som praktisk muligt. Når det er interessant, så er det for at dels at kunne arbejde offline, og dels for at kunne lave lokale commits - commits, som ikke behøver være så afrundede eller komplette som ellers - ja, faktisk behøver de slet ikke kunne compilere, og som derfor kan ske undervejs - og ikke først når man er helt sikker på at være færdig.

søndag den 3. februar 2008

Giv mig en anden virkelighed

To history, choices are merely directions. The Trouser of Time opened up and Vimes began to hurtle down one leg of them. And, somewhere else, the Vimes who made a different choice began to drop into a different future.
Terry Pratchett: Jingo
Jeg har før skrevet om versionsstyring, og dengang forholdt jeg mig mest til det paradoks, der er i, at en merge-strategi som oftest er en låsestrategi overlegen - også selvom det umiddelbart føles forkert. Denne gang vil jeg dykke lidt mere ned i branching, som mange har et had-kærlighedsforhold til (de fleste endda uden ret megen kærlighed...). Og det er egentlig både synd og uforståeligt.

Lad os starte med at slå fast, at vi gør det hele tiden:

Branching er det, hvor man fastfryser virkeligheden, og arbejder sig ud i en alternativ retning.

Når vi tager en fil ind i en editor, så gør vi det samme - vi skaber en lille alternativ virkelighed, som kun eksisterer i vores editor. Gode editorer lader os måske endda sammenligne med det, som var vores udgangspunkt, nemlig det som stadig ligger på det eksterne lager. Avancerede brugere vil endda kunne editere flere filer på en gang. Denne lille "branch" består indtil vi vælger at gemme vores ændringer - indtil det punkt har vi faktisk en reelt mulighed for at fortryde.

En anden almindelige måde at lave en lille "branch" på, er at tage en kopi fra et fælles netværkdrev, og så arbejde på kopien et stykke tid. Herefter kan man vælge at lægge kopien tilbage igen (eller lade være).

I de fleste versionsstyringsværktøjer har hver bruger sin egen arbejdskopi, og vælger selv hvor tit denne arbejdskopi skal bringes i sync med repository. Samtidig kan brugeren have sine egne ændringer, og dermed sin egen virkelighed, indtil det tidspunkt, hvor brugeren beslutter sig for at flette ændringen ind i den egentlige version i repository. Her er også en lille tidslomme.

Vi har hele tiden brug for at lukke døren til virkeligheden - at melde os ud for en kort bemærkning - imens vi laver vores arbejde uden at blive forstyrret af den flux, der er omkring os. Og også brug for at kunne eksperimentere uden at forstyrre vores omverden. Varer det længe nok, så bliver vi nødt til at en gang imellem at åbne døren og bringe os selv up-to-date med, hvad der er sket omkring os. Når det har stået på længe nok, så vil vi på et tidspunkt åbne døren igen og åbenbare vores resultatet af vores omverden.

Sådan er det også med branches. Bare i en større målestok, og noget mere formaliseret. Men rationalet, udfordringerne og effekten er den samme.

Der er to store beslutninger, som følger med beslutningen om at branche.

Når man brancher, så skal man gøre sig klart dels, om man vil vende tilbage, og i givet fald, hvordan og hvornår.

Selvom man godt kan forestille sig, at man laver en branch, for at gå i en helt anden retning uden noget behov for nogensinde at kigge sig tilbage igen, så er det som oftest ikke tilfældet. Som oftest, så er det man laver, en ændring, som giver god mening - man skal bare lige have fred til at gennemføre den. Og i så fald skal man overveje, hvordan man kommer tilbage.

Den første overvejelse er, hvordan man kan skal håndtere, at andre kan have ladet udviklingen gå i en anden retning imens. Versionsstyringsværktøjer vil hjælpe os med dette i en vis udstrækning, men specielt i de to første eksempler, hvor vi bare havde en lokal kopi som vi kopierede tilbage igen, vil der klart kunne opstå en konflikt, hvis ikke man er omhyggelig.

Risikoen for konflikter stiger med tiden, så en god strategi er oplagt ikke at bruge for lang tid inden afslutter sin branch.

Overvej, hvordan man kan holde sig opdateret undervejs.

Det er klart, at jo længere man har været væk, jo sværere bliver det at komme tilbage. Modtrækket imod dette er at lægge en strategi for, hvordan man løbende holder sig opdateret.

Det koster helt klart tid og kræfter, så det er ikke noget, som skal gøres for tit. På den anden side, så skal man heller ikke vente for længe, for så stiger prisen ved at være ude af sync for meget.
_________

Her burde et være klart, at branching dels ikke er noget magisk, men derimod noget som vi helt naturligt foretager os, og dels at det først for alvor bliver besværligt, når vi lader det løbe for længe. Der er tre altså store udfordringer i det: At starte det, at håndtere det undervejs, og at afslutte det (doh!).

Opstarten vil jeg ikke sige så vanvittigt meget om. Der er flere former for best practice for det - for en grundig oversigt se f.eks. denne Branching and Merging Primer, som oplister ti typer af branches, fem strategier for branching og en pæn mængde antipatterns.

Selv har jeg med rimelig succes talt for en kombinationsløsning imellem clean og dirty trunk. Som udgangspunkt sker udviklingen på trunk, men ikke andet end hvad der stadig med rimelighed kan nå at komme med i næste release. Når denne nærmer sig, så branches der ud i en releasespecifik branch, som så får lov at stabilisere sig. Tilsvarende vil aktiviteter, som rækker længere ud end næste release blive sendt ud på featurebranches. Man vil kunne se, at dette er meget stærk inspireret af afsnitttet Common branching patterns i online bogen Versioncontrol with Subversion.

Afslutning vil jeg her faktisk slet ikke sige noget om, udover det lidt som allerede er sagt. Så resten af dette indlæg går med at snakke om det "ind imellem".

Det burde nu være klart, at det vigtigste ved det "ind imellem" er, på en kontrolleret måde at holde sig opdateret med det, som sker omkring en. I eksemplet med en lokal arbejdskopi af et fælles repository er det rimeligt simpelt, i det at værktøjet går langt for at hjælpe en. Man skal bare finde en passende rytme for at holde sig opdateret, så skal det nok holde styr på, hvilke opdateringer man har brug for, og om de evt. skulle konflikte med det, som man nu har gang i.

For de mere manuelle eksempler er der ikke andet at sige, end at man må håbe på det bedste, og så ellers holde tungen lige i munden.

For "rigtige" branches i versionsstyringsværktøjer, findes der fine beskrivelser af best practice for håndtering af, hvordan bogholderiet ifm. f.eks. succesive opdateringer skal håndteres. Det lyder besværligt og bureaukratisk, og det er det faktisk også. Se f.eks. ovenstående bog om Subversion - der er der fint beskrevet. Og mon ikke at det er dette bogholderi, som er pæn del af grunden til at branches er blevet lagt sådan for had?

Men der er i hvertfald to ting, som for nyligt at kommet til min opmærksomhed, som vil lette denne byrde mærkbart:

Den ene af disse er, at der i næste version af Subversion kommer noget som de kalder "merge tracking" (det er scheduleret til version 1.5, og i skrivende stund er den aktuelle version 1.4.6). Her lover subversionfolkene, at de vil hjælpe os med bogholderiet vha. snedige markeringer i metadata, så alt hvad vi skal gøre er, med jævne mellemrum at skrive "svn merge". Se f.eks. Subversion: Merge Tracking og Merging og branching in Subversion. Udover problemstillingen med succesive merges, så skulle det kunne håndtere "cherry picking" (dvs. merging af udvalgte ændringer alene) og tilbagerulning at merges uden at blive forvirret. Se det er efter min mening grund nok til at skifte til Subversion, hvis man ikke allerede har gjort det! At have branches og at holde dem opdateret, burde da ikke blive mere omstændeligt end at have lokale arbejdskopier og holde dem opdateret i forhold til det fælles repository - og dermed er en stor administrativ byrde fjernet.

Den anden ting er et markant brud med det grundlæggende vilkår ved branches, at man skilles på et bestemt punkt, og at dette punkt som udgangpunkt ligger fast. I værktøjet AccuRev erstatter man begrebet branches med et andet begreb kaldet streams. Tanken er, at man baserer streams på andre stream - det som vi vil opfatte en som branch, vil være en stream baseret på trunk. Men en stream ligger ikke fast - den er så at sige transparent alle de steder, hvor der ikke er lokale ændringer. Det betyder, at sker der ændringer i de stream, som en given stream baserer sig på, så vil man få disse ændringer med næste gang man opdaterer. Når man er klar, så kan man sende sine ændringer op til den overliggende stream, og så fremdeles, hvis der er tale om flere niveauer af streams. Se evt. mere i Streambased architecture for SCM.

Det er efter min mening et yderst interessant alternativ, da det umiddelbart ser ud til, at man her helt kan undvære at skulle merge imellem branches undervejs. Om man kan håndtere den "støj", som det vil være altid at få alting med, kan jeg ikke overskue - og det betyder i hvertfald at der er en lang række af vores etablerede mønstre for brug af versionsstyringsværktøjer, som skal gentænkes.

Jeg håber at jeg her har fået afdramatiseret brug af branches lidt, så flere nu tør give sig ud i at branche, hvor det giver mening. Vedr. citatet i indledningen, så kan jeg fortælle at de to Com. Samuel Vimes formår at få fat i den andens "disorganiser" (en "disorganiser" svarer nogenlunde til vore dages PDAere). Resultatet er ganske mange forviklinger, bl.a. at "vores" Vimes på et tidspunkt får reminders om sit alternative jegs begravelse. Parallelle virkeligheder er forvirrende - hold jer fra det i større målestok!

mandag den 28. januar 2008

Agil opsplitning

Hvordan kan det være, at lige når man har trykket "Udgiv"-knappen, så går der mindre end et døgn inden man opdager noget, som burde have haft med? Jeg har prøvet at gå og vente med at skrive indlægget og jeg såmænd også prøvet at skrive det, og så ladet det ligge, men ingen af delene virker - effekten er uløseligt forbundet til "Udgiv"-knappen.

Og selvfølgelig er der lige sket igen. Jeg skrev så sent som i går om udfordringerne ved off-shoring under titlen Lost in translation, og allerede i dag falder jeg over blog-posten med titlen Agile India, som undrer sig over at der dels er en stor interesse for agil udvikling i Indien, men samtidig også bemærkelsesværdigt få succeshistorier. Forfatteren overvejer, om ikke dette skal tilskrives de udfordringer, der ligger i at kommunikationen ikke er så god, som hvis man sad lige ved siden af hinanden.

Men en egentlige perle i blog-posten er henvisning til Martin Fowlers artikel med titlen Agile Software Process with Offshore Development. Her beskriver Fowler en lang række snusfornuftige overvejelser omkring udfordringerne i at få agil udvikling til at fungere med Thoughtworks teamet i Bangalore. Bemærk at mange af overvejelser går på at få distribuerede teams til at fungere, så læs den endeligt selvom det ikke er Bangalore, men derimod Bagsværd eller Ballerup. Og læs den også selvom at det "kun" er kunden og udviklingsteamet som er adskilt, for Fowler prøver at få alt til at foregå offshore, men erkender at kravsspecifikation naturligt kun kan ske on-shore - og det svarer til det setup, som desværre er meget almindeligt med en offsite kunde.

Fowler har desuden flere pointer, som i bund og grund ikke er relateret til distribuerede teams, men som faktisk er generelt gode råd:

Han nævner, at en effektiv måde at få et nyt team introduceret til kodebasen på, er ved at lade dem lave fejlrettelser den første tid. Hans argument er, at fejlrettelser naturligt involverer langt mere kodelæsning end kodeskrivning. Det kan jeg skrive under på, og det gælder ikke kun for teams, men også når man skal introducere nye folk på projektet. Dels tvinger det en ud i hjørnerne af koden og dels så er det nemt at få en succesoplevelse - det er svært tilfredsstillende at få noget til at fungere, også selvom det i virkeligheden kun bestod i at skrive "not" foran en betingelse i en if-sætning. En anden effekt er, at det er nemmere at finde en fejl i en eksisterende programstump, når man ved hvordan den manifesterer sig, end det er en skrive en rimeligt fejlfri implementation fra bunden af.

Det er også med en vis glæde at jeg ser hans anbefaling af at foretrække en funktionelt opdeling. Han fodrer her en af de kæpheste, som jeg i går spændte foran min vogn, og det ser man specielt, hvis man følger linkene helt ud og ser at hans definition af funktionel opdeling er, at lade forretningen (eller med lidt god vilje, problemdomænet) determinere grænsernes placering.

Fowler har to pointer om distribuerede team, som jeg vil fremhæve:

Dels bemærker han, at hvis man påtænker at påtage sig det overhead der ligger i at have distribueret udvikling, så skal man gøre sig klart, at man i høj grad fraskriver sig en af de helt store fordele ved at være agil, nemlig at man kan erstatte store dele af den formelle dokumentation med uformel kommunikation, som jo er mange gange mere effektivt. Men i kraft af adskillelsen, så bliver det igen nødvendigt med en større formalisme i kommunikationen.

Desuden er hans klare anbefaling, at hvis man skal retfærdiggøre distribuerede teams og de udfordringer, som det bringer med sig, så skal man gøre det i forhold til at kunne tiltrække de rette kompetencer. Forskellen i produktivitet overstiger langt forskellene i aflønning, så det er dyrt i længden, hvis man køber billigt.

En enkelt ting, som jeg umiddelbart har svært ved at se, hvordan man skal implementere hvis udviklingen sker i Bagsværd fremfor Bangalore, er hans anbefaling af at udveksle lokale informationer og specialiteter. Så spændende er det heller ikke at høre om Bagsværd BK, og lokale specialiteter fra Bagsværd og omegn kan jeg ikke rigtigt komme i tanke om (selvom jeg har hørt øst-sjællændere beklage sig over de usle hotdogs, som de mener at vi har her i Jylland...).

lørdag den 5. januar 2008

Personlig versionsstyring

Da jeg tidligere skrev om versionsstyring kom jeg kort ind på den skelnen, som er opstået imellem centrale systemer som f.eks. CVS og Subversion på den ene side, og decentrale systemer som f.eks. Bazaar, Git og Mercurial på den anden side. Der bliver for tiden sagt meget om det, set fra begge sider, også selvom det måske umiddelbart ligner en lille forskel. Det vil jeg sådan set også godt sige noget om, men jeg vil først og fremmest sige, at jeg har (igen) valgt side.

For at forstå det, så skal der nok lidt historie på banen. Personligt mener jeg, at programudvikling uden versionsstyring er temmeligt absurd, også for projekter som er så små, at de må betegnes som hobbyprojekter.

I starten var der ikke rigtigt nogle værktøjer for menigmand, så vi klarede os med strategiske backupkopier, med alle de begrænsninger, som det medførte (f.eks. havde jeg en god ven og kollega, som på et tidspunkt arbejde på et stort og vigtigt WordPerfect dokument, og som derfor tog en jævnlig backupkopi - desværre til en og samme 5¼" diskette, og der er jo fysisk kontakt - og han havde taget backuppen tit nok til at han havde slidt disketten op, da han fik brug for den...!).

Jeg tænkte dengang meget på, om ikke jeg skulle bruge CVS, men CVS kræver en server, og serveren kunne ikke være Windowsbaseret, så det blev længe ved drømmen. Men så en dag fik jeg hardware nok til overs til, at jeg kunne installerede en linux, og så kunne jeg pludselig få en CVS server op og køre. Det gav nogle udfordringer, og CVS er jo - ja, det er jo CVS med sine egne underligheder - og selvom jeg brugte det meget en overgang, så var det korte af det lange, at jeg blev træt af at have repository liggende på en anden maskine.

Så kom Subversion, og det blev hurtigt modent nok, til at jeg kunne installerede en version på min maskine. Det krævede også nogle overvejelser, og har givet sine unikke kvaler, men den kører den dag i dag, og jeg et aktivt repository på min eksterne harddisk.

Men det føles stadig som en meget stor kanon at rulle ud for at skyde en meget lille gråspurv, at have dels et repository og dels en arbejdskopi af det, som man ønsker at versionsstyre. Afledt dels af min egen blog (se ovenfor), og dels af nogle konkrete udfordringer med lige hurtigt nok at få de rette rettigheder på vores lokale CVS server på arbejde, så kom jeg til at kigge på Mercurial. Og hold op, hvor er det nemt at bruge i det scenarie, hvor man kun er sig selv, og "bare" ønsker at have en "tidsmaskine" og en mulighed for en "en anden virkelighed". Det var oppe og køre stort set med det samme, og der er ikke mange udfordringer i det, hvis man bare har prøvet at prøve andre versionsstyringsværktøjer før.

Derfor har jeg nu valgt Mercurial som mit personlige versionsstyringssystem (Subversion kommer ikke ud i kulden lige med det samme - jeg har for mange data i den, som jeg ikke lige vil konvertere, men fremtiden tilhører altså Mercurial...).

Hvordan Mercurial er at bruge, hvis man er andre end bare sig selv, skal jeg ikke kunne sige noget om. Men det er der så heldigvis andre som kan: F.eks. har Mozilla valgt Mercurial, omend deres valgt vist mest havde overskriften "det var så det mindst ringe...", og Sun har valgt Mercurial til OpenJDK projektet. Jeg vil tro, at begge parter har givet valget en del overvejelse.

Inden man tager mine (og ovenståendes) ord for gode varer, så overvej alternativerne grundig. Git bruges så vidt jeg ved af Linux kerne udviklerne efter BitKeeper kontroverset, så det er bestemt heller ikke at kimse af. Bazaar folkene har gjort sig tanker om, hvad de kan at tilbyde i forhold til andre (ikke overraskende foretrækker de Bazaar), og der findes også denne sammenlignende artikel fra JavaWorld.

torsdag den 3. januar 2008

IKEA kvalitet

Jeg har været i IKEA den sidste uge tid. Rigtigt meget - ja, faktisk hele tre gange. Og det skyldes IKEA kvalitet - på mere end en måde.

Det hele startede med, at vi skulle bruge nogle billige og funktionelle skabe til børnene, nu hvor de var flyttet ind på det store værelse. Vi havde grundlæggende set to krav: Det skulle være solidt nok til at kunne holde til dem, så længe at de kunne bruge det - og billigt nok til at vi kunne holde tanken ud om at skulle kassere det, når behovene engang ikke længere er de samme.

Jeg har selv købt adskillige møbler i min tid, og af det, som jeg startede med at købe, så er det stort set kun tingene fra IKEA, som har fulgt med mig rundt alle de gange jeg siden har flyttet siden (og det er efterhånden blevet til fem flytninger...).

Dengang, hvor jeg startede med købe hos IKEA, da forlød det i folkemunde, at bilerne fra Skoda var lavet af støbejern og møblerne fra IKEA af appelsinkasser. Og ja, der var (og er...) sparet på materialerne, hvor man kunne, specielt i de billige møbler af spånplade og hvid melanin. Og der var sparet andre steder, som på transport (ved at have alt pakket ned i flade kasser), og på montage (ved at lade folk selv stå for samlingen). Men der var aldrig sparet på det, som skulle holde, det var bundsolidt tenderende til det overdimensionerede. Og konstruktionen var altid af en god håndværksmæssig udførelse, og gennemtænkt i den grad, så selv en akademiker som jeg, snildt kunne samle det, når bare man ved, hvilken del af en hammer og en stjerneskruetrækker, som man skal holde fast i.

Så det kan godt være, at det er billigt (og såmænd også ser billigt ud), men det fungerer og det holder. Og derfor kom vi i IKEA første gang.

Vi fandt os da også et par skabe, og lånte en trailer, så vi kunne få dem transporteret hjem på forsvarlig vis. Og jeg gik fuld af glæde og optimisme i gang med at samle skabene - men så løb jeg ind i problemer: Midterhylden er lavet med ekstra stærke samlinger, så den kan være med at holde skabet sammen på midten (der er sket, at man er kommet til at proppe et skab lidt for fuldt, så det er en rigtigt god ide - og faktisk typisk IKEA at tænke på det), men i det ene skab var hullet til en af holderne boret skævt. Det havde man åbenbart opdaget, for der var såmænd bare boret en gang til oveni. Da holderne er nogle dimser med modhager for at kunne holde fast, så vil det at hullet er for stort gøre, at det ikke vil virke. Som om det ikke var nok, så var den ene af holderne kun halvt så stor som de andre, og lignede nærmest noget som Dali havde malet - noget var gået helt galt i støbningen.

Det første overraskede mig, for dels er det sjusk at bore skævt, og dels er det disrespekt overfor mig som kunde at tro, at man bare kunne bore oveni, og slippe afsted med det. Det er ikke IKEA kvalitet, som jeg husker det. Det andet, med en billig plasticdel, som åbenbart var smuttet igennem kontrollen, er vel nærmest hændeligt uheld.

Under alle omstændigheder, så betød det, at vi kom til IKEA anden gang, og besøgte deres reklamationsafdeling. Der var ovenhovedet ingen problemer (bare man husker bonen med stregkoden aht. deres edbsystem!) - vi fik straks nye stumper, og humøret var faktisk efterfølgende så højt, at vi gik en tur igennem butikken, når vi nu alligevel var der. Og så kom vi til at købe en CD-reol!

Det skulle vi nu nok ikke have gjort, for da vi kom hjem og jeg igen var i gang med skruetrækker og hammer, da kunne jeg ikke få bagpladen ind i falsen. Det viser sig, at dyvelhullerne i bundpladen er boret over to millimeter for langt ude, så bundpladen forskubber sig ud over falsen til bagpladen. Igen sjusk, for selv når jeg står og fumler ude i garagen på egen hånd, så borer jeg dæleme ikke over to millimeter ved siden af - og da slet ikke, hvis jeg har en lære eller skabelon at bore efter!

Det er en klar ommer, og så kom jeg i IKEA for tredje gang for at besøge reklamationsafdelingen. De var igen meget venlige (jeg havde også bonen med stregkoden til deres edbsystem med...), og de så faktisk endda en anelse flove ud, så de reddede æren denne gang.

Her efterfølgende vil jeg godt indrømme, at jeg har mistet meget af min hidtidige respekt for IKEA, men jeg må sige, at reklamationsafdelingen fungerer, og møblerne virker bundsolide, nu hvor jeg har fået alle de rette stumper hjem - så selvom der nok lige skal gå lidt tid, så kommer jeg nok igen engang.

Nu er mine oplevelser med at samle møbler jo ikke i sig selv voldsomt interessante, hvis ikke de - skulle jeg mene - siger noget om kvalitet:
  1. Det er helt i orden at lave billige løsninger af simpel spånplade og melanin, hvis bare man lægger stor omtanke og omhu i konstruktionen, og ikke sparer på det, som gør at det kan holde på langt sigt.
  2. Der er ingen undskyldning for sjusk - heller ikke i billige løsninger.
  3. Der er slet ingen undskyldninger for at mangle faglig selvrespekt, og prøve at skjule egne fejl.
  4. Det tager lang tid, og hårdt arbejde, at opbygge tillid til kvaliteten, og det kræver kun få smuttere, at miste den igen.
  5. Selvom det bedste ville have været, selv at have fanget fejlene fremfor at lade kunderne finde dem, så kan meget alligevel reddes ved på kompetent vis at vedstå sig sit ansvar ved reklamationer - det kan godt være, at det ikke hjælper på tilliden, men det giver tryghed.
Tænk over det, næste gang du er med at fremstille noget - også selvom det ikke er møbler lavet af "appelsinkasser"...

onsdag den 10. oktober 2007

Det, som ikke var der...

For the world is changing: I feel it in the water, I feel it in the earth, and I smell it in the air.

Engang imellem er det vigtigste det, som ikke er der. Og sådan var det, efter min mening, med JAOO i år. I år var der megen snak om, hvad det vil sige at være en professionel udvikler, og hvad det vil sige at have en profession. Der var til gengæld ikke meget snak om tekniske finurligheder - det som om, at vi har fundet ud af det.

Erich Gamma nævnte det selv i sit foredrag - at han var blevet kontaktet med kommentaren om, at han ikke længere snakkede om "the hard stuff" - han ville godt medgive, at han snakkede mere om proces end om teknik, omend han nu nok ville mene, at det ikke var mindre "hard stuff" af den grund.

Gamma var ikke alene - bevares, .NET folkene havde vist en skøn dag med deres nye "legetøj" LINQ, og alle de, som interesserede sig for Ruby, havde vist stadig mere behov for at diskutere værktøj end proces. Men generelt var tekniksnakken blevet mere eller mindre væk.

Hvorfor mon det? Den ene del af forklaringen er sikkert, at vi er fragmenterede - der er efterhånden så mange forskellige fornuftige forslag til værktøjer, frameworks og teknologier, at man kan blive helt svimmel. Skal persistens være JDBC, Hibernate, JPA eller lign.? Skal webservices laves med Axis, JSON eller XFire - og skal stilen være RPC, SOA eller måske endda RESTful? Hvad med unittest? IDE? Buildtool? Webframework? Chancen for at finde to udviklere, som er enige, er efterhånden ganske lille.

Men den anden del af forklaringen er, at de forskellige alternativer faktisk efterhånden er blevet ganske udemærkede. Kigger man på funktionaliteten, så kan de faktisk alle stort set alt, bare på en lidt forskellig måde - og valget bliver ofte mere et spørgsmål om tradition eller smag. Teknikken er, med andre ord, ikke så interessant i sig selv længere.

Nogle vil sikkert mene, at det skyldes at det nuværende procedurale (eller, mere generelt, imparative) programmeringsparadigme, eksemplificeret med f.eks. Java og C#, er ved at løbe tør for damp. Vi har nået så langt som vi kan komme, er påstanden, og hvis vi skal videre, så skal vi seriøst have skeen over i den anden hånd.

Et alternativ er mere målrettet valg af sprog - og udnyttelsen af muligheden for at blande flere sprog, så man bruger det sprog som aktuelt er bedst til lejligheden. Det være sig fulde sprog på eksisterende platforme, som f.eks. Python implementationen Jython, eller sprog i sig selv, som f.eks. Ruby. Men det kunne også være mere domænespecifikke sprog, som kunne være sprog opfundet til lejligheden, f.eks. for at gøre beskrivelsen mere forståelig for dem som kender domænet - eller det kunne være gamle kendinge, som f.eks. SQL eller Ant's buildfiler. Personligt har jeg svært ved at se det nyskabende i det, men der er mange kloge folk, som siger mange kloge ord om det... (og husk, at gode ideer kan implementeres dårligt).

Et andet godt bud på, hvor fornyelse kunne komme fra, er fra de funktionelle (eller, mere generelt, deklarative) sprog. Synspunktet er, at eksisterende sprog i høj grad kommer til at håndtere flerkerne processorer og den deraf følgende høje grad af parallelitet, eksplicit som en udvidelse. Derimod vil funktionelle sprog i langt højere grad kunne håndtere det implicit. Det er lidt forskellen på at bygge læhegn, eller at bygge vindmøller, som svar på forandringens vinde.

Et af de funktionelle sprog, som man lige nu bør holde øje med, er Erlang. Sproget har - i modsætning til mange alternativer - allerede en god ballast i kraft af, at det dels allerede har været anvendt i praksis (det blev oprindeligt udviklet af Ericsson), dels har været OpenSource allerede før årtusind skiftet. Det har allerede bevist, at det virker.

Men vi er der ikke endnu, og der er gode chancer for, at fremtiden bliver noget, som vi slet ikke har fantasi til at forstille os i dag. Min pointe er, at vi for tiden mest er afventende, og at det kan være forvarslet til opbrud.

PS: Citatet i indledningen er store ord, og den angivelige ophavsmand vil helt sikkert føle sig misbrugt i en for ham, så flygtig og foranderlig sammenhæng, som programudvikling er for tiden. Jeg er nu ret sikker på, at når vi om ikke så frygteligt mange år kigger tilbage, så vil vi mene, at verden er blevet forandret. Bonuspoint til dem, som kan regne ud, hvor citatet stammer fra, og hvem som angiveligt skulle have sagt det!

tirsdag den 2. oktober 2007

Versionsstyring

(Opdateret 4. februar 2008: Der er kommet en opfølgning om branches)

Indledning

Så vidt jeg husker, så er versionsstyring danske oversættelse af revision control. Man undgår normal ordet version og det er sikkert for at skelne det i forhold til software configuration management, som jo er det at styre forskellige versioner af software - og typisk endda i forskellige konfigurationer. Revision control er det, som hjælper os med at kontrollere de små skridt, som tilsammen udgør den rejse, som configuration management kontrollerer.

Jeg vil her skrive lidt om værktøjer til versionsstyring. Jeg vil ikke skrive om, hvorfor - det antager jeg, at vi er enige om.

At det ikke altid har været en selvfølgelighed med versionsstyring, oplevede jeg på egen krop for efterhånden nogle år siden. Jeg sad som "schweizerkniv" (projektleder, arkitekt, udvikler, 2nd level supporter og underviser i en og samme person) på et produkt, som havde været længe undervejs. Faktisk havde der allerede været to andre personer på dette før mig og begge var forlængst over alle bjerge. Jeg spurgte derfor ofte mig selv om, hvordan en given del af programkoden kunne have været opstået. Derfor gik jeg til min chef og bad om et versionsstyringsværktøj.

"Hvorfor det?" lød svaret, "du er da alene på projektet". Ja, men nogle gange, så har man brug for at kunne gå tilbage til en tidligere version. "Jamen, kan du ikke bare gemme en kopi et sted på din harddisk?". Jo, men det ville være rart at kunne gå længere tilbage. "Hvad med at gemme flere kopier...?". Her gav jeg så op.

Nu får jeg min tidligere chef til at fremtræde lettere naiv, og det er uretfærdigt, for han var alt andet. Og man kan ikke ligefrem sige, at jeg præsenterede ham for det, der på nydansk hedder en god business-case. Jeg kan ikke fortænke ham i at se store umiddelbare udgifter, og kun magre og usikre gevinster langt ude i fremtiden. Jeg skulle - set i bagklogskabens tydelige skær - have forberedt mig bedre.

Men tiderne har heldigvis ændret sig, og i dag er versionsstyringsværktøjer allestedsnærværende - hvis man har glemt hvorfor, så kan man kigge i indledningen til denne artikel, for en god og dejlig kort introduktion (artiklen er i øvrigt også god at blive klog af, idet den sammenligner fire rimeligt almindelige versionsstyringsværktøjer).

Men selvom versionsstyring er blevet så udbredt, at det nærmest falder i et med tapetet, så er der stadig nogle overvejelser, som man skal gøre sig. Der er flere grundlæggende forskellige tilgange, med hver deres fordele og ulemper.

Granularitet

Det første man skal gøre sig klart er, hvad der er en grundlæggende enhed for versionsstyringen. Nogle værktøjer versionsstyrer filer (f.eks. CVS), mens andre værktøjer versionsstyrer hele arkivet (f.eks. Subversion).

Hvis ændringer kun er helt uafhængige skridt i en fil ad gangen, så betyder denne skelnen ikke noget, men når ændringer begynder at spænde over flere filer ad gangen, så vil det være en fordel at kunne håndtere ændringerne samlet (i såkaldte change sets).

Værktøjer, som versionstyrer hele arkivet, vil naturligt kunne tilbyde atomare (dvs. "alt eller intet") ændringer, og ændringerne vil være samlet naturligt. I filbaserede værktøjer, vil kan kunne opleve at ændringer kun sker halvt, hvis der er problemer undervejs, og man kan efterfølgende kun gætte sig til sammenhængen ud fra f.eks. tid og kommentar til ændringen (nyere versioner af CVS forsøger at lappe på dette ved at give et unikt "commitid" til alle filer, som sendes til CVS i samme kommando).

Atomare ændringer er specielt vigtigt, hvis man ønsker at håndhæve forretningsregler vha. f.eks. precommit-triggere - det kan ikke hjælpe noget, at man har fået opdateret de to første filer i et change set, hvis man under behandlingen er den tredje fil opdager, at hele ændringen skulle have været afvist.

Bemærk også, at selvom understøttelse af change sets er en stor hjælp til change management, så er det ikke nok. Ændringer vil tit opstå ad flere omgange, og den fulde beskrivelse af ændringen vil derfor være det samlede antal skridt.

Låsning vs. fletning

Den anden store skillelinje er i metoden til at undgå konflikter ved samtidige ændringer (helt uden versionsstyring vil det være den ændring, som gemmes sidst, der vinder...).

Den ene metode er den klassiske låsningssematik: Man kan kun fortage en ændring, når man forud har fået en eksklusiv ret til dette. Dette tvinger ændringerne til at ske serielt i forhold til hinanden, idet en ændring ikke kan starte førend den forgående er afsluttet. Ændringskonflikter vil derfor ikke eksistere. Ulempen er, at man med låsen kan komme til at blokere for andre, og der er de klassiske eksempler på deadlocks og låse som ikke bliver frigivet rettidigt (f.eks. pga. ferier). Låsning fungerer bedst, når der er høj granularitet, lavt overlap og kort låsningstid.

Den anden metode er fletning: Enhver kan foretage ændringer - til gengæld vil man efterfølgende kunne konstatere, når en ændring kommer til at konflikte med en anden ændring - og ansvaret for at løse konflikten påhviler den som kom sidst.

Den typiske måde at løse konflikten på, vil være fletning, som kan ske mere eller mindre automatiseret: hvis en ændring er foretaget i den øverste 1/3 af en fil, og en anden ændringen i den nederste 1/3, så vil en automatisk fletning typisk lade begge ændringerne ske, idet de ikke overlapper. Dette kan selvsagt medføre et resultat, som er absurd eller direkte forkert - i praksis sker det dog yderst sjældent, og hvis der er en passende stringent fortolkning - f.eks. fordi det, som er flettet, er kildetekst til et program - så vil det ofte være åbenlyst, når dette sker.

Fordelen er, at man aldrig bliver stoppet undervejs - medmindre at man rent faktisk render ind i en konflikt.

Ulempen ved fletning er, at det ikke er alt som umiddelbart lader sig flette. Ved billedfiler vil det f.eks. sjældent være indlysende, hvordan to resultater skal kombineres (nogle billedformater indeholder originalen uændret samt en liste af efterfølgende operationer, og i så fald vil man måske kunne flette - men det er absolut specieltilfælde).

Et andet eksempel er typiske tekstbehandlingsdokumenter. MS-Word dokumenter lader sig trods alt manuelt flette i Word, så der kan man slippe omkring det med en vis egen-indsats. OpenOffice's ODF format lader sig heller ikke umiddelbart flette: ODF dokumenter er en zip'pet samling af XML-dokumenter - zip-filer lader sig i praksis kun flette ved at flette indholdet, og XML-dokumenter er godt nok tekstfiler, men jeg mangler stadig at se en god flettealgoritme til XML-dokumenter (hint: tekstbaserede flettealgoritmer er som oftest liniebaserede, og det er XML ikke - derimod er XML hierarkisk i opbygningen, så det hjælper heller ikke at "normalisere" dokumentet).

Central vs. decentral

Den tredje store forskel imellem implementationerne er opstået relativt fornyligt, nemlig decentrale systemer.

Førhen var det altid sådan, at der var et centralt "opbevaringssted" (repository). De fleste værktøjer tillod en eller flere arbejdskopier, men der var altid et sted, hvor man dels kunne finde originalen, dels havde en autoritativ kilde til historikken.

I den centrale løsning vil man hente de seneste opdateringer fra det centrale repository (hvor andre tidligere har sendt deres ændringer hen), og samtidig er det her, at man selv sender sine ændringer hen, så andre også kan få glæde af dem. Der er altså et fast centralt holdepunkt og en lang række satellitter rundt om dette.

Nu er der så kommet decentrale eller distribuerede løsninger til, hvor enhver kopi som udgangspunkt er lige så god som alle andre kopier.

I den decentrale løsning vil man kunne hente ændringer et vilkårligt andet sted fra (hvis dette medfører konflikter vil man selv skulle løse dette) og tilsvarende vil man kunne sende sine ændringer vilkårlige steder hen (inden man kan gøre dette, så vil man selv skulle løse eventuelle konflikter). Der er altså ingen fast rollefordeling. Hvor den centrale løsning nærmest er et hjul med eger, så er den decentrale løsning nærmere et netværk - og vel at bemærke ikke et fast netværk, men derimod mere ad hoc baseret.

Det er oplagt, at modellen med et centralt repository lader sig realisere i den decentrale model (hvis alle er enige om, at lade en knude være "master"). Man kan også forstille sig et hierarki i flere niveauer, hvilket kunne bruges til at modellere states, som f.eks. "under udvikling", "under kvalitetssikring" og "produktionsmodent".

Samtidigt er en decentral udgave af den centrale model langt mindre sårbar. Hvis den centrale knude falder ud - permanent eller midlertidigt - så kan de tilbageværende knuder reorganisere sig og køre videre fra det punkt, som svarer til deres kollektive viden om tilstanden inden udfaldet.

Eller med andre ord: den decentrale model "...gives you plenty of rope to swing with - and plenty of rope to hang yourself!".

Afsluttende bemærkninger

Det lyder indlysende, men det er faktisk vigtigt at kende sin implementation godt.

Et eksempel er, at det med CVS er nemt at finde ud af, hvor slettede filer oprindeligt lå - man laver bare en søgning på den del af serverens filsystem, hvor repository ligger, og når man finder filen i en "Attic"-folder, så ser man, hvor denne folder er placeret.

Et andet eksempel er, at CVS er case-sensitiv/in-sensitiv afhængigt at det underliggende filsystem. Arbejder man med forskellige filsystemer på hhv. server og klient, så vil det være en god ide, at have en klippefast konvention for case.

Et tredje eksempel er, at man i CVS kan slette eller flytte filer permanent inkl. historik, ved at manipulere filsystemet på repository direkte (det ødelægger til gengæld godt og grundigt muligheder for at reproducere tidligere versioner (forstået i videste forstand) ud fra reposity...!)

Et fjerde eksempel er, at Subversion i fsfs formatet for repository gemmer hele changesettet i en enkelt fil - det er altså ikke muligt at committe en ændring, som samlet set er større end den største filstørrelse på det underliggende filsystem, også selvom de enkelte ændringer ikke overstiger den.

Et femte eksempel er, at Subversion i working copy gemmer en kopi svarende til repositoryversionen til sammenligning (det gør dels at netværkstrafikken bliver minimeret, idet der kan kommunikeres med deltaer, dels at ændringsdetekteringen bliver mere robust, men også at pladsforbruget bliver fordoblet).

Hvordan finder man ud af det? Som så meget andet ved at få praktiske erfaringer. Så der er ikke andet for end at komme i gang med et eksperimentere, vel?