Allt du lärt dig om webutveckling är fel

Ett uttryckligt designmål för lagen.nu har varit att göra så mycket som möjligt med statiska filer. Det var en nödvändighet av prestandaskäl när tjänsten körde på en 166Mhz Pentium, och det är även idag en vettig målsättning, inte minst ur robusthets- och säkerhetssynpunkt.

Så länge som en webtjänst inte förändras på grundval av användarnas interaktion finns det inte någon strikt anledning att göra den med dynamisk teknik som ASP, PHP, CGI-script, servlets/JSP etc. Det kan förstås finnas utvecklingsmässiga fördelar; i princip alla nya tekniker för webutveckling utom möjligtvis XSLT är anpassat för dynamisk sidgenerering, så man når kanske sina utvecklingsmål snabbare med en dynamisk lösning. Men jag har ingen brådska på det viset.

Etiketteringen är dock den första funktionen som tar emot data från användaren, och har som sådan berett lite extra problem. Det första problemet jag hade att lösa var att jag ville att funktionen bara skulle vara tillgänglig för de som explicit ville ha den under en testperiod. I dynamiska system gör man oftast liknande saker med inloggningsförfaranden och sessionsobjekt, samt villkorlig kod som, beroende på inloggningsstatus, spottar ur sig lämplig HTML-gränssnittskod.

Men i en statisk lösning kan man inte göra sådant på servern. Däremot kan klienten åläggas att göra en hel del dynamiska trick! Lösningen fick bli att den gränssnittsdetalj som används för etiketteditering initialt gömdes med en style="display: none;", för att sedan, när sidan laddats klart, eventuellt göras synlig baserat på om kakan tags är satt till enabled med javascript i den här stilen (elementet heter ”comment” av hysteriska skäl):

    if (GetCookie('tags') == 'enabled')
    {
	if (document.getElementById('comment'))
        {
	    document.getElementById('comment').style.display="block";
         }
    }

Naturligtvis kan man inte använda en sådan här lösning om den detalj som man eventuellt vill gömma innehåller någon typ av hemlig information — det är trivialt för en angripare att kolla på HTML-koden för att hitta informationen.

Ett annat designmål med lagen.nu är att så långt som möjligt undvika att använda en traditionell RDBMS som MySQL, SQL Server, Postgres etc. Även här rör det sig om en önskan att hålla saker så enkelt som möjligt genom att undvika en separat körande process, som dessutom implementerar sin helt egen rättighetsmodell (vanligtvis), kräver sina egna backup- och synkroniseringsrutiner. En databasserver är, om man tänker efter, bara ett uppsvällt userland-filsystem med en väldigt bra ls 🙂

På lagen.nu jobbar jag framförallt med dokument – lagtexter och liknande, som är väldigt naturligt att representera som filer i ett filträd, snarare än BLOBar i en databas. Men även för datamodeller som traditionellt skulle representeras i en RDBMS har jag valt att använda filer – XML, närmare bestämt. Ett exempel är kopplingen rättsfall – lagparagrafer. Varje rättsfall kan referera noll eller flera lagparagrafer (inklusive i olika lagar), och varje lagparagraf kan naturligtvis refereras från många rättsfall. Istället för att ha en Verdicts-tabell, en LawParagraphs-dito, och sen en många-till-många-mappingtabell har jag ett stort XML-dokument med grundläggande uppgifter om alla rättsfall, ordnade efter lagar och paragrafer. Sen länkar jag in relevanta rättsfall under XSLT-transformationen, beskrivet här (under ”Accessing data in other documents”). XML-dokumentet innehåller redundant data, men eftersom det inte är den ursprungliga källan till informationen (det skapas av bara farten under den vanliga transformationen av rättsfallen) är det ok.

Den stora fördelen med detta är att mycket funktionalitet kan implementeras i XSLT istället för python eller SQL (vissa skulle ifrågasätta om det är en fördel, men jag tycker det har sin inneboende charm).

Etiketter har en liknande datamodell med en många-till-många-relation mellan etiketter och lagar, och även här är tagdatabasen en stor XML-fil (eller, än så länge är den ganska liten, men ge den tid).

För att ta emot den nya informationen måste jag tyvärr frångå mina principer om en totalt statisk sajt. Ett litet CGI-script tar emot formulärdatan, uppdaterar etikettdatabasen, och ansvarar för att fixa till HTML-filen: när en användare lägger till en etikett på en lag måste den statiska HTML-filen som utgör den formatterade lagen ändras för att inkludera den nya etikettexten.

Och här råkar vi på ett problem som inte finns i en helt statisk sajt: prestandakrav.

Sidorna på lagen.nu genereras vanligtvis (i sista steget) från XML till XHTML genom en XSLT-transformation från helvetet. Den gör mycket magiska saker, och den tar lång tid – den mest krävande lagtexten, Rättegångsbalken, tar strax under 45 sekunder. Det är inte OK om användaren måste vänta så länge för att sätta en tag. Istället opererar CGI-scriptet på den färdiggenererade HTML-filen genom att mmap’a den, söka sig fram till en markör-kommentar, och dumpar sedan in den nya taglistan.

För att tokfort hitta relevanta taggar för lagen i fråga använder jag cElementTree , och sen spottar jag ut HTML på gammalt klassiskt f.write("<a href='foo'>bar</a>")-manér.

Det är dock fortfarande långsamt att lägga till stora mängder etiketter på en lag, detta på grund av lite suboptimalitet på ett annat ställe som jag för tillfället helst sopar under mattan. Dessutom skalar det inte, men när jag får så mycket etiketter att det blir ett problem ska jag jubla.

Så, för att summera: Undvik dynamiska webutvecklingsramverk, och undvik relationsdatabaser. För att vara mer tvärtemot etablerad webutvecklingskutym skulle jag behöva programmera i assembler.

Gränssnittet för etikettering i sig är däremot en dynamisk HTML-festival i miniatyr. Imorgon ska jag berätta om min nyvunna fascination för den här utskällda webdesigngrenen.

Etiketter på lagen.nu

Under sommaren har jag ägnat en del tid åt att implementera kollaborativ etikettering (”tags”) på lagen.nu. Om du är intresserad av att betatesta systemet är instruktionerna som följer:

  1. hit och klicka för att sätta en kaka som gör att den beigefärgade etikettrutan dyker upp till höger om varje lagtext (security through DHTML, yeah baby!).
  2. Gå till nån lämplig lag och klicka på ”Ändra” för att trolla fram ett inmatningsfält. Skriv in några beskrivande ord för lagtexten i fråga och klicka ”Ändra” igen
  3. Gå exempelvis hit för att se alla lagar taggade med ”tryckfrihet” eller hit för att se alla taggar som skapats hittils (genom ett mycket tidstypiskt etikettmoln).
  4. ”Syntax” och mer information här.

På sikt vill jag göra det möjligt att tagga enskilda paragrafer, kommentera, stryka under… allt som man kan göra med en riktig lagbok, fast gemensamt. Taggning på författningsnivå verkade vara ett bra ställe att starta på. Hittils har jag taggat drygt hundra lagar som har det gemensamt att de råkade komma först i Civilrätt, efter bästa förmåga men utan någon större eftertanke, precis som jag brukar göra med mina del.icio.us-bokmärken.

Upphovsrättsmässigt är det hela ganska odefinerat. Jag utgår från att en enskild tag/etikett inte kan vara skyddad enligt upphovsrätten, eftersom den inte uppfyller originalitetskravet. Den totala samlingen av etiketter (eller ett tillräckligt stort subset) kan dock med tiden åtnjuta skydd enligt 49 § URL . Vad innebär det då om det inte finns en enskild upphovsman eller någon juridisk person som kan hävda rätten till etikettsamlingen?

Oavsett vad ser jag ett egenvärde att vara kompatibel med Wikipedia, så om inga klara anledningar att välja någon annan uppstår, lutar jag åt att licensiera tagdatabasen i sitt ursprungliga tillstånd (om vi nu antar att den når upp til 49§-skydd) under GFDL.

Imorgon blir det en bakom-kulisserna om hur det funkar rent tekniskt.