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!

Ingen kommentarer: