CITCON 2012 i Budapest

I helgen kom jag äntligen iväg på CITCON (uttalas kit-kon) eller Continuous Integration and Testing Conference. Det är en årlig konferens som i år arrangeras på fyra kontinenter. Formatet är open space och de enda fasta förutbestämda punkterna är när sessioner börjar presenteras, vilka rum som finns och tider för sessioner och pauser – allt annat avgörs på plats av de som deltar. “Come prepared” skickades ut i ett mail och det märktes att en del kom väldigt förberedda och hade funderat länge på olika problem eller frågeställningar de ville ventilera. Majoriteten kom dock oförberedd, men det var nog tur – långt fler sessioner föreslogs än det fanns tid att avhandla.

Hur gick det till?

CITCON är en typisk open space-konferens. Ungefär så här i punktform (YMMV):

  • Alla deltagare samlas i ett rum, var och en får en knapp minut att svara på “vad heter du, en värd/arrangör presenterar formatet, reglerna och det schema som finns. Schemat är tomt förutom information om tillgängliga rum och tider då sessioner startar och slutar.
  • En kö bildas med de som vill föreslå en session. Man får bara föreslå en i taget, och ställa sig sist i kön om man vill man föreslå fler.
  • Personen längst fram i kön berättar i en knapp minut vad han/hon vill göra under sessionen, t ex visa ett verktyg, prata om ett problem, testa en kodkata, visa hur man (inte) testade av mobilappar. Personen sätter upp en lapp på schemat med sessionens titel samt sitt namn. Ingen vikt läggs vid var eller när lappen hamnar på schemat – den kommer ändå flyttas väldigt snart.
  • När kön är slut börjar tre aktiviteter: “röstning” och “planering”. Röstningen – dvs att var och en med ett litet streck markerar de sessioner man är intresserad av – behövs för att försöka sätta sessioner med många deltagare i ett rum som rymmer många deltagare. Planeringen är fullt demokratisk/anarkistisk – vem som helst får flytta runt lappar, men man gör klokt i att stämma av med den som satte upp lappen och andra som står vid schemat just då. Sessioner med relaterade ämnen slås ibland ihop. Nästa person kanske plockar isär dem. Allt eftersom tiden lider så stabiliseras processen och del 1 av open space avslutas. (Den tredje aktiviteten var att det serverades olika saker att knapra på och dricka. :-)
  • Genomförande. Schemat är fortfarande föränderligt ända fram tlll att ett pass starttid nås. Nya sessioner kan föreslås, befintliga slås ihop, flyttas, tas bort etc. Detta förekom också men inte i stor utsträckning.
  • En session startas och avslutas av en facilitator (personen vars namn står på lappen). Facilitatorn berättar hur sessionen skall förlöpa och försöker sammanfatta vad som sagts i slutet. Under CITCON var det vanligaste diskussioner av olika slag där ordet var helt fritt. CITCON förordar starkt att någon utpekad/frivillig för anteckningar.
  • Avslutning. Händer inte alltid men på CITCON samlades alla i samma rum där man startade och sammanfattade konferensen, denna gång genom att svara på frågan “what was your a-ha moment?”

Utöver detta finns bara en regel – regeln om två fötter! Om man känner att “här har jag inget att hämta eller tillföra, då skall jag använda mina två fötter och förflytta mig”. Oartigt? Nej för bövelen – det är oansvarigt att bara sitta av tid och kanske ta upp en skön sittplats för någon som verkligen är intresserad och mycket mer konstruktivt att istället söka upp en aktivitet man har något utbyte av.

Var var det?

Budapest, hos Colabs – ett hus vigt åt att hjälpa startups. Mycket vitt med klara accentfärger, bean bags och sköna citat prydde väggarna, t ex “There is no finish line. So love the journey.” (Tyvärr inte en enda whiteboard!)

Vilka sessioner hölls?

Jag stod en hel del ute i korridoren och pratade öga mot öga med enskilda individer. T ex pratade jag oväntat länge med Željko Filipin (jobbar nu för Wikimedia Foundation) om automatiserad testning av webb. Vi behandlade allt möjligt i ett härligt tempo: git, selenium vs web driver i mix med Watir, EC2, Jenkins plugins, Jenkins i molnet, egna seleniumslavar och “i molnet”. Minst 10 gånger svors det över all kostnad IE medför. Cucumber, Rake, Maven. Specification workshops. Jenkins Project Templates …

Does retail need tests?

Douglas Squirrel berättade bakgrunden som var att han kom från konsulting och i huvudsak bank- och finanssektorn – ett område där man inte gärna tar fel på 1 och 1000. Det senaste halvåret har han dock jobbat i retail/e-handel för ett bolag där man inte har ett enda utvecklartest, dvs test som skrivs av utvecklare, körs av utvecklare, för utvecklare. De har en del “metrics” i form av mätvärden som spottas ut i rapporter lite stup i kvarten. Dessa bevakas av diverse folk. Douglas frågeställning var: “why do I need those stinkin’ tests”? Hela sessionen var alltså ett ifrågasättande av enhetstester, integrationstester – kort och gott alla test som inte finns kvar i produktion. Douglas iklädde sig alltså en annan roll (han är pro-test i vanliga fall) under en timme med förhoppningen att få med sig utmärkta argument för att införa test. Det gick sådär – alla kring bordet var väldigt pragmatiska och det enda argumentet som jag tror höll var att “om utvecklarna vill införa det för att känna sig nöjda i arbetet (så det stannar på bolaget) så bör det vara något man accepterar från ledningen”.

Testing newer parts of a test suite more often than older parts

En session jag föreslog var att prata om hur man kan köra bara delar av en testsvit. Målet (för mig) är att köra alla nya tester kontinuerligt (vid push) och gamla tester endast nattligen. Orsaken till detta önskemål är att jag sett att detta är ett mönster som jag sett i det team jag jobbast mest de senaste åren: det som går sönder är det som är rörligt, dvs det vi jobbar med “nu” och där alla detaljar inte utkristalliserats ännu. Så gott som aldrig har något som är äldre än 3 månader gått sönder.
För att fortsätta upprätthålla korta snabba feedback-cykler hade det varit trevligt med ett verktyg som gör denna uppdelning åt mig. Man skulle givetvis kunna dela in alla test i två sviter manuellt, men det skulle ge underhållsbörda som är oönskad (ett verktyg borde klara av att göra denna enkla indelning).
Jetbrains CI-motor har visst stöd för att köra test som fallerar ofta oftare än andra men verkade inte ha precis det jag var ute efter. Olika idéer bollades och intressanta diskussioner fördes iaf med kompetent och erfaret folk, även om resultatet inte blev en nu JUnitRunner (iaf inte ännu …)

Andra sessioner

Det fanns fem tidsslottar men utnyttjade man lagen om två fötter så hade man möjlighet att delta i många fler. Fastnade man i bra diskussioner med folk i korridoren kunde man utan tvekan haft ett enormt utbyte utan att “delta” i en enda planerad session. Jag själv deltog även i sessioner om TDD, valuable metrics, men undvek en hel del om “how to motiviate people”. (Någon föreslog att “if a developer’s commit count is too low too long eventually it should be reflected in the salary” så det var emellanåt stora variationer på nivå i inläggen i debatterna.)
Allt eftersom dyker anteckningar från sessionerna upp på CITCON-wikin, som även har anteckningar kvar från tidigare år. En liten guldklimp med värdefullt material bland nätets alla wikis helt enkelt!

Var det värt att åka?

Absolut! I ett sådant här sammanhang kommer verkligen open space till sin fulla rätt och man är fullständigt slutkörd efter en intensiv dag av argumenterande, lärande, provocerande (för att ifrågasätta “axiom”). De som deltog hade över lag en mycket öppen och vänlig attityd och rent tekniskt var det stor blandning från embedded, webb, “native”, desktop och samma gällande plattformar. De som kom var här för att dela med sig och ta del av andras lärdomar och det var en underbar stämning och mycket inspirerande atmosfär som uppstod.
Jag hade endast två förväntningar som inte infriades: att över hälften av deltagarna skulle vara “seniora”; att vi skulle serveras gulash till lunch. Men det var verkligen av mindre vikt – allt övrigt slog in (över förväntan) och konferensen gav nya erfarenheter och uppslag, befäste en del “jag tror att”. På det hela taget var det sammanfattningsvis nästan “för” informations-, kunskaps- och tankeverksamhetsintensiv. Och, alla kör Jenkins, för allt.

Java Labels

Jag kan inte minnas att jag förut sett etiketter används i Java-kod (utanför böcker och studiematerial från kurser), men idag dök det upp i en del av java.util (ComparableTimSort) efter att jag kollade upp en bugg i Mockito som härstammade från just ändring av Arrays.sort och Collections.sort (gällande @InjectMocks):

    private void mergeLo(int base1, int len1, int base2, int len2) {
        assert len1 > 0 && len2 > 0 && base1 + len1 == base2;
 
        // Copy first run into temp array
        Object[] a = this.a; // For performance
        Object[] tmp = ensureCapacity(len1);
        System.arraycopy(a, base1, tmp, 0, len1);
 
        int cursor1 = 0;       // Indexes into tmp array
        int cursor2 = base2;   // Indexes int a
        int dest = base1;      // Indexes int a
 
        // Move first element of second run and deal with degenerate cases
        a[dest++] = a[cursor2++];
        if (--len2 == 0) {
            System.arraycopy(tmp, cursor1, a, dest, len1);
            return;
        }
        if (len1 == 1) {
            System.arraycopy(a, cursor2, a, dest, len2);
            a[dest + len2] = tmp[cursor1]; // Last elt of run 1 to end of merge
            return;
        }
 
        int minGallop = this.minGallop;  // Use local variable for performance
    outer:
        while (true) {
            int count1 = 0; // Number of times in a row that first run won
            int count2 = 0; // Number of times in a row that second run won
 
            /*
             * Do the straightforward thing until (if ever) one run starts
             * winning consistently.
             */
            do {
                assert len1 > 1 && len2 > 0;
                if (((Comparable) a[cursor2]).compareTo(tmp[cursor1]) < 0) {
                    a[dest++] = a[cursor2++];
                    count2++;
                    count1 = 0;
                    if (--len2 == 0)
                        break outer;
                } else {
                    a[dest++] = tmp[cursor1++];
                    count1++;
                    count2 = 0;
                    if (--len1 == 1)
                        break outer;
                }
            } while ((count1 | count2) < minGallop);

Jag trodde först det hängde ihop med kommentaren ovan, men så ovan var jag vid etiketter att jag misstog mig. :-)