Sånn kan det også gjøres

Tiden er moden for hornmusikk og vaiende flagg.

Som nevnt tidligere har jeg innledet et kjærlighetsforhold til et programmeringsspråk. Det ser ikke ut til å gå over.

Vi programmerere, som så mange andre, opplever ofte et tildels stort skille mellom det vi sier og det vi gjør; mellom teori og praksis. Teorien sier oss ting som at:

Og så synder vi litt, enten det er dårlig tid, dårlig motivasjon eller noen annen unnskyldning vi bruker. Så står (sitter) vi der en dag med skjegget i postkassa. Etter noen timer med debugging finner vi ut at vi glemte å endre en filsti i et eller annet perl-script som kjører i helt spesielle tilfeller. Og så sverger vi å aldri gjøre det igjen.

Etter noen uker med Ruby har det slått meg at noen av disse smertene kan avhjelpes hvis man har et språk og verktøy som øker den umiddelbare gevinsten ved å gjøre ting på den riktige måten. Det var jo det som var meningen, sant?

I prosjektet jeg jobber med for tiden lagres dataene i en sql-database. Jeg har (synes jeg sjøl) et fornuftig hierarki av objekter, organisert i tabeller med relasjoner seg i mellom. En User tilhører et Company, og User har n Soknad-er, som igjen har hver sin Soker. Sånn ser det ut i hodet mitt, sånn er databasen organisert (om enn ikke eksplisitt så vil enhver kunne resonnere seg fram til det ved å se på databaseskjemaet) og sånn er programmet mitt. Problemet er bare at dette ikke er eksplisitt uttrykt på ett sted; og programmet håndhever ikke denne regelen til enhver tid. For å være litt streng med meg sjøl kan jeg si at dette betyr at datamodellen min er ugyldig idet noen skriver “DELETE FROM soknad WHERE …”.

Mange SQL-databaser lar deg innføre et regime der rader i andre tabeller (ON DELETE …) blir slettet idet radene i en tabell slettes. Da unngår man problemet med “foreldreløse data”, men forbryter seg mot DRY-prinsippet: man plasserer samme logikk i databasen og i programkoden.

ActiveRecord løser dette problemet for meg. ActiveRecord er implementasjonen av et design pattern Martin Fowler har laget. Her er programkode som på en ganske utvedtydig måte uttrykker datamodellen beskrevet ovenfor:


class Company < ActiveRecord::Base
 has_many :users, dependent => true
end
class User < ActiveRecord::Base
 belongs_to :company
 has_many :soknader, :class_name => "Soknad", dependent => true
end
class Soknad < ActiveRecord::Base
 belongs_to :user
 has_one :soker, dependent => true 
end
class Soker < ActiveRecord::Base
 belongs_to :soknad
end

I tillegg til at dette er den tydeligste måten jeg har sett brukt til å uttrykke en datamodell er det også den kraftigste. Ikke bare forstår ActiveRecord her at det er relasjoner mellom de forskjellige tabellene, men den håndterer avhengigheter for meg også.

Her om dagen hadde jeg bruk for å simulere med noen data i databasen. Jeg startet opp IRB, og skrev noe sånt:


require 'Model' # Importerer datamodellen 
soknad=Soknad.find(2) # Finner Soknad med ID 2
selger=soknad.selger # Returnerer selger for Soknad
comp=selger.company # Returnerer Company for selger
comp.destroy 

Den siste linja her vil effektivt slette alle brukere, alle disses søknader, og alle søknadenes søkere for forhandleren til den gitte søkeren.

For å sitere en annen Ruby-tilhenger:

Can’t you feel the peace and contentment in this block of code? Ruby is the language Buddha would have programmed in.

Code art by Frisk Bris. And, oh, we work too.