# Bibliotek

## Hva det er

Et bibliotek, eller programbibliotek, er en samling ferdige rutiner som et program låner i stedet
for å skrive dem selv: noen løste et problem én gang, som å tolke datoer, komprimere filer eller
tegne en QR-kode, og publiserte løsningen med et sett navngitte inngangspunkter som ethvert program
kan bruke. C-biblioteker på Linux har ofte navn med prefikset lib-, Windows kaller den delte
varianten en DLL, og Rust-programmerere sier crate, et ord som Rust-boken påpeker brukes om
hverandre med bibliotek. De fleste språk leveres også med et standardbibliotek, modulene som finnes
i hver installasjon uten at noe må legges til.

Et bibliotek er en form for gjenbrukbar kode, og det er lettest å definere mot naboene sine. En
applikasjon kjører av seg selv og har en bruker; et bibliotek har ingen av delene og kjører bare
inne i et program som kaller det. Et rammeverk er den nærmeste sammenligningen. Med et bibliotek er
det koden din som styrer, og den kaller biblioteket når den trenger noe; et rammeverk styrer selv og
kaller koden din på de punktene det har definert. En programvarepakke, til slutt, er esken et
bibliotek leveres i, med et navn, en versjon og en liste over hva det trenger, og biblioteket er
koden inne i esken.

Det som gjør et bibliotek brukbart, er grensesnittet: funksjonene, typene og konstantene det lover å
beholde. Semantic Versioning bygger hele ordningen sin på det løftet. Et prosjekt som følger den, må
deklarere et offentlig API, og hovedversjonen går opp hver gang det API-et endres på en måte som
ikke er bakoverkompatibel.

Program Library HOWTO sorterer biblioteker på Linux etter når de blir en del av programmet. Et
statisk bibliotek kopieres inn i den kjørbare filen når den bygges. Et delt bibliotek lastes inn når
programmet starter, og brukes av alle programmer som trenger det, så det kan oppdateres uten at de
bygges på nytt. Et dynamisk lastet bibliotek åpnes mens programmet kjører, og det er slik systemer
for programtillegg som regel virker.

## Hvorfor det er viktig

Hvert bibliotek et prosjekt tar i bruk, er en avgjørelse med tre mulige svar: ta et eksisterende,
skrive koden selv, eller kopiere en liten, avgrenset bit inn i repoet og eie den fra da av, noe som
kalles vendoring.

Å ta inn et bibliotek er som regel riktig. Forfatterne har allerede møtt grensetilfellene, og andre
brukere har allerede meldt inn feilene. Kostnaden kommer senere og er lett å overse: bibliotekets
egne avhengigheter følger med, sikkerhetsvarslene for det blir dine, utgivelsesplanen bestemmer
takten i oppgraderingene dine, og lisensen blir med inn i produktet ditt. Et bibliotek som
vedlikeholderen har forlatt, blir liggende i byggingen din til noen erstatter det.

Å skrive det selv gir kontroll og koster alt biblioteket ville ha spart deg for: grensetilfellene,
testene og vedlikeholdet, på ubestemt tid. Det er riktig valg når problemet er smalt og sentralt,
når de tilgjengelige bibliotekene er langt større enn behovet, eller når et prosjekt har en grunn
til å holde antallet avhengigheter lavt.

Hvordan et bibliotek lenkes inn, betyr også noe. Et program bygd med et statisk bibliotek bærer med
seg en fast kopi, så en sikkerhetsrettelse i biblioteket når brukerne først når programmet bygges og
leveres på nytt. Et delt bibliotek kan rettes én gang for hele systemet, mot at programmet stoler på
den versjonen systemet til enhver tid leverer. Lisensieringen bryr seg ikke om forskjellen:
GNU-lisensenes FAQ slår fast at å lenke et GPL-dekket verk statisk eller dynamisk med andre moduler
gir et kombinert verk, og at vilkårene i GPL da dekker hele kombinasjonen.

For den som bestiller programvare, er de praktiske spørsmålene hvilke biblioteker resultatet er
avhengig av, under hvilke lisenser, og hvem som eier biblioteker leverandøren tar med seg.

## Slik ser det ut i praksis

En dokumentgenerator trengte en QR-kode som pekte til nettversjonen av hvert dokument. Ethvert av de
eksisterende QR-bibliotekene ville ha gjort jobben, men prosjektet hadde bevisst begrenset seg til
to avhengigheter under kjøring, en malmotor og en PDF-renderer, en grense valgt for at generatoren
fortsatt skulle kunne installeres uten problemer lenge etter utgivelsen. Svaret ble å
[vendore en QR-koder på 522 linjer](/nb/portfolio/vendored-a-qr-encoder-in-522-lines-148/): koding i
byte-modus, Reed-Solomon-feilretting over GF(256), posisjons-, tids- og justeringsmønstrene, format-
og versjonsinformasjon og alle åtte maskemønstre vurdert mot de fire straffereglene. En dekoder
skrevet for seg leser hver genererte kode tilbake ved hver kjøring og sjekker at den gir tilbake
inndataene. Siden er nøye med påstanden sin: koderen dekker bare modusene og versjonene disse
dokumentene bruker, og grunnen til den er avhengighetsbudsjettet, ikke en tro på at den slår et
modent bibliotek.

En innebygd macOS-klient kaller et kjernebibliotek gjennom C-grensesnittet dets, og tidlig ble det
grensesnittet representert av en håndskrevet headerfil. Kall til tre funksjoner som for lengst hadde
forsvunnet fra kjernen, kompilerte, ble lenket og krasjet så under kjøring, fordi kompilatoren og
lenkeren bare noen gang hadde sett den håndskrevne stedfortrederen og aldri kjernens ekte
deklarasjoner. Løsningen ble
[en parser som verifiserer hvert kallsted](/nb/portfolio/wrote-a-parser-that-verifies-every-ffi-call-site-157/)
mot den ekte headerfilen på 7 308 linjer og dens 268 deklarasjoner, og som får byggingen til å feile
ved ethvert kall eller enhver enum-konstant headerfilen ikke deklarerer. Den sjekker deklarasjoner,
så en funksjon som beholder signaturen sin mens betydningen endres, slipper fortsatt gjennom.

[Vilkårene](/nb/terms/) for hvert oppdrag avgjør hvem som eier hva. Kode som skrives for en kunde,
blir kundens ved full betaling. Biblioteker og generelle verktøy selskapet skrev tidligere, eller
skrev for seg selv, er unntaket: eierskapet blir hos selskapet, og kunden får en tidsubegrenset,
ugjenkallelig lisens til å bruke dem i det leverte arbeidet. Kode med åpen kildekode fra
tredjeparter beholder lisensen forfatterne valgte, og kunden får vite hvilke av de komponentene som
havnet i resultatet.

## Hvor det går galt

### En rutineoppdatering knekker byggingen

En avhengighet går fra 2.3 til 2.4, og kode som kompilerte i går, feiler eller oppfører seg
annerledes. Enten har biblioteket endret det offentlige grensesnittet sitt uten å øke
hovedversjonen, eller så har prosjektet støttet seg på noe biblioteket aldri lovet, som en intern
funksjon eller en udokumentert oppførsel. Lås eksakte versjoner i en låsefil, oppgrader med vilje og
med endringsloggen åpen, og kall bare det biblioteket dokumenterer som offentlig.

### Programmet stoler på en beskrivelse av biblioteket

En ren bygging krasjer første gang en funksjon brukes. Koden ble kompilert mot headerfiler,
typestubber eller bindinger skrevet for hånd, og de har drevet bort fra biblioteket som faktisk
lenkes inn. Generer bindingene fra bibliotekets eget publiserte grensesnitt, eller sjekk hvert kall
mot det som en del av byggingen, slik at et avvik feiler der og ikke foran en bruker.

### Én liten funksjon drar med seg et stort tre

Én enkelt funksjon trengtes, og biblioteket som leverer den, kom med dusinvis av egne avhengigheter,
hver av dem enda et sett med sikkerhetsvarsler, lisenser og oppdateringer. Før du legger til et
bibliotek, se på hva det trekker med seg, ikke bare på hvor stort det selv er. Når behovet er smalt
og godt spesifisert, kan en liten bit vendoret kode med egne tester være det billigste å eie.

### Lisensen følger med koden

Sent i et prosjekt oppdager noen at et bibliotek inne i et produkt med lukket kildekode er under en
lisens der vilkårene gjelder hele det kombinerte verket. Ingen sjekket lisensene da biblioteket ble
lagt til, og å lenke det inn dynamisk endret ingenting. Sjekk lisensen til hvert bibliotek i det
øyeblikket det legges til, hold listen sammen med utgivelsen, og be leverandørene om deres.

## Les mer

- [Program Library HOWTO: Introduction](https://tldp.org/HOWTO/Program-Library-HOWTO/introduction.html)
  — hva et programbibliotek er på Linux, og hvordan statiske, delte og dynamisk lastede biblioteker
  skiller seg fra hverandre.
- [The Rust Programming Language: Packages and Crates](https://doc.rust-lang.org/book/ch07-01-packages-and-crates.html)
  — bibliotek-crates mot binære crates, og hvordan en pakke holder dem.
- [Semantic Versioning 2.0.0](https://semver.org/) — reglene for versjonsnumre som gjør et
  biblioteks offentlige API til et løfte.
- [The Python Standard Library](https://docs.python.org/3/library/index.html) — et standardbibliotek
  i full størrelse: alt som følger med hver installasjon av Python.
- [Frequently Asked Questions about the GNU Licenses](https://www.gnu.org/licenses/gpl-faq.html) —
  hva GPL betyr for programmer som lenker inn et dekket bibliotek, statisk eller dynamisk.

<https://engineer.company/nb/glossary/library/>
