# CI

## Vad det är

CI är en förkortning av continuous integration, på svenska kontinuerlig
integration: ett arbetssätt där alla i ett team lägger in sina ändringar på en
och samma gemensamma kodlinje många gånger i veckan, och där en maskin bygger
och testar resultatet varje gång, så att ett misstag syns medan den som gjorde
det fortfarande minns att det hände. Det fulla namnet används lika ofta som
förkortningen, både på engelska och i den svenska formen.

Ordet används om två olika saker, och att hålla isär dem sparar mycket
förvirring. Den första är praktiken, som handlar om människor. Artikeln i ämnet
av Martin Fowler, den källa som de flesta team till slut citerar, beskriver den
som en uppsättning vanor: håll en enda huvudlinje, automatisera bygget, låt
bygget testa sig självt, skicka till huvudlinjen minst en gång om dagen, bygg
varje push, laga ett trasigt bygge direkt, håll bygget snabbt, göm halvfärdigt
arbete i stället för att hålla det på en gren, och låt alla se hur bygget står
till. Artikeln spårar namnet till Extreme Programming och noterar att Grady
Booch använde uttrycket redan innan dess.

Den andra betydelsen är maskinen. När någon säger ”CI:n är röd” menar de
tjänsten som körde bygget och rapporterade ett fel. GitHub Actions, GitLab CI/CD
och deras likar har alla samma form. En fil i repot beskriver arbetet:
`.github/workflows/*.yml` på GitHub, `.gitlab-ci.yml` i roten på GitLab. En
händelse startar det, som en push, en pull request eller merge request, ett
tidsschema eller en person som trycker på en knapp. En runner, alltså en maskin
som är avsatt för ändamålet, checkar ut committen, kör kommandona i filen och
rapporterar godkänt eller underkänt tillbaka mot committen.

En server ensam är ingen kontinuerlig integration. Ett team som håller arbete på
grenar i en månad och låter en server bygga varje gren har automatiserat sina
byggen, vilket är användbart, men själva integrationen sker fortfarande på en
gång i slutet. Praktiken är de täta sammanslagningarna; maskinen är det som gör
täta sammanslagningar tillräckligt säkra för att fortsätta med dem.

Kontinuerlig leverans och kontinuerlig driftsättning, continuous delivery och
continuous deployment, är stegen som kommer efter. Leverans håller varje grönt
bygge redo för release, och driftsättning släpper vart och ett automatiskt. Båda
förutsätter att CI redan finns på plats, och därför skrivs de tre så ofta ihop
som CI/CD.

## Varför det spelar roll

Kostnaden för att slå ihop två arbetslinjer växer snabbare än tiden de
tillbringar isär. Två personer som båda ändrade samma modul i går kan reda ut
konflikten på några minuter, eftersom båda minns vad de menade. Två personer som
gick isär för sex veckor sedan rekonstruerar avsikter ur diffar. Att slå ihop
små bitar ofta håller varje konflikt liten, och det är det mesta av nyttan innan
någon maskin ens är inblandad.

Bygget vid varje push lägger till en sak till: en ren maskin som håller med.
”Det funkar på min dator” är ett påstående om en enda dator, med dess egna
installerade bibliotek och kvarglömda filer. En runner som börjar från en färsk
utcheckning varje gång återskapar antingen resultatet eller visar vad som var
speciellt med datorn.

Snabbheten är där värdet finns. Artikeln av Fowler sätter ett mål på ungefär tio
minuter för huvudbygget, och resonemanget håller i praktiken. Ett fel som
rapporteras tio minuter efter en push går tillbaka till den som orsakade det
medan ändringen fortfarande står på skärmen. Ett fel som rapporteras nästa
morgon går till den som råkar titta, och kostar först en timmes arkeologi.

Synligheten väger också tungt. När huvudlinjens status visas för alla börjar
ingen nytt arbete ovanpå ett trasigt bygge utan att veta om det, och att laga
det bygget blir teamets första uppgift i stället för någon annans problem.

CI behöver inte heller betyda en tjänst som någon annan driver. pre-commit kör
ett projekts kontroller som git-hookar före varje commit eller push, och dess
dokumentation visar samma uppsättning körd på en server med
`pre-commit run --all-files`. Task ger varje kontroll ett namn i en enda
`Taskfile.yml`, så att en människa och en runner anropar samma kommando. Den här
webbplatsens egna kontroller körs på det sättet: på maskinen där webbplatsen
skrivs, med en fullständig kontroll före varje push och ingen extern byggtjänst
däremellan.

## Så ser det ut i praktiken

Tre problem får här sin lösning i CI: manuella releaser, ett databasschema som
beskrivs på två sätt och en applikation vars två halvor kan glida isär.

I det första hängde utleveransen av mjukvara på manuella steg som var och en
gjorde lite olika.
[Automatiserade pipelines för bygge, test och driftsättning ersatte dem](/sv/portfolio/streamlined-ci-cd-processes-saving-4-000-hours-42/),
så att vägen från en ändring till produktion blev standardiserad i stället för
improviserad. Sidan anger att ungefär 4 000 timmar gavs tillbaka, och releaserna
blev både snabbare och mer tillförlitliga.

En långlivad databas har här två beskrivningar av samma schema: den initiala
uppsättningen och de 1 022 migreringarna ovanpå den, med nummer som börjar på
036 och slutar på 1102.
[Ett CI-jobb bygger databasen på båda sätten vid varje ändring](/sv/portfolio/kept-the-schema-honest-across-1022-migrations-99/),
en gång från det färska schemat och en gång med varje migrering uppspelad i
ordning, och jämför sedan strukturen och grunddatan. Varje avvikelse fäller
bygget, med skillnaden utskriven, så en ny miljö och en långlivad miljö är samma
databas genom kontroll i stället för genom antagande.

I det tredje genereras API-beskrivningen och frontendens klient i en kedja som
börjar i databasen och slutar i en typad TypeScript-klient på 44 076 rader.
[En kontraktskontroll i CI jämför det frontenden skickar med det API:et förväntar sig](/sv/portfolio/built-a-request-schema-validation-contract-with-automated-61/)
och stoppar bygget när de skiljer sig åt. Resultatet som sidan redovisar är det
som CI finns till för: ett fält som ändras på bara ena sidan fäller ett bygge,
minuter efter ändringen, i stället för att nå en användare som ett fel i
webbläsaren.

## Var det går fel

De flesta CI-uppsättningar förfaller snarare än går sönder. Var och en av de här
börjar smått och slutar med ett bygge som teamet har lärt sig att arbeta runt.

**Bygget tar längre tid än arbetet.** När en push tar fyrtio minuter att komma
tillbaka slutar folk vänta på den, samlar flera ändringar i en push och pushar
mer sällan, vilket är motsatsen till praktiken. Mät var tiden går innan du
lägger till hårdvara. Cacha beroenden, kör de snabba kontrollerna först och
flytta de långsamma testsviterna till ett andra steg eller till en schemalagd
körning, så att huvudbygget håller sig nära tio minuter.

**Huvudlinjen förblir röd i ett dygn.** Ett trasigt bygge som ingen lagar blir
det normala, och ett andra fel kommer obemärkt bakom det första. Regeln som
hindrar det är enkel: den som bröt bygget lagar det nu, eller backar ändringen
och lagar den på egen tid. En grön huvudlinje är det som alla andra bygger
vidare på.

**Grenar lever i veckor medan servern bygger var och en.** Varje gren visar
grönt, och problemen kommer på dagen då de slås ihop, allihop på en gång. Det
här är automatiserade byggen utan själva integrationen. Slå ihop till
huvudlinjen minst en gång om dagen, och håll ofärdiga funktioner avstängda i
stället för isärhållna.

**Servern kontrollerar en lista och datorn en annan.** Två listor med kommandon
som underhålls för hand glider isär, och sedan går en ändring igenom lokalt och
fäller på servern, eller tvärtom, och ingen litar på någon av dem. Ge
kontrollerna en enda ingång och anropa den från båda ställena. Med pre-commit
kan servern köra exakt de hookar som varje utvecklare kör:

```yaml
# .gitlab-ci.yml
check:
    image: python:3.13
    script:
        - pip install pre-commit
        - pre-commit run --all-files --show-diff-on-failure
```

**Ett instabilt test lär alla att trycka på kör igen.** Ett test som fallerar en
körning av tjugo, av skäl som inte har med ändringen att göra, tränar teamet att
köra om i stället för att läsa. Efter det får ett verkligt fel samma behandling.
Sätt testet i karantän, laga det eller radera det, och behandla en knapp för
omkörning som trycks ofta som ett fynd i sig.

## Läs mer

- [Continuous Integration](https://martinfowler.com/articles/continuousIntegration.html)
  — den långa artikeln av Martin Fowler: varje praktik, tiominutersbygget och
  var namnet kom ifrån.
- [Understanding GitHub Actions](https://docs.github.com/en/actions/get-started/understand-github-actions)
  — arbetsflöden, händelser, jobb och runners så som GitHub definierar dem.
- [GitLab CI/CD](https://docs.gitlab.com/ci/) — filen `.gitlab-ci.yml`,
  pipelines, steg, jobb och runners med de begrepp som GitLab själv använder.
- [pre-commit](https://pre-commit.com/) — kontroller som deklareras en gång i en
  konfigurationsfil, körs som git-hookar och en gång till som ett steg på en
  CI-server.
- [Task](https://taskfile.dev/) — en `Taskfile.yml` som ger varje kontroll ett
  namn, så att en människa och en runner skriver samma kommando.

<https://engineer.company/sv/glossary/ci/>
