Database og lagring i Norscode

Dette kapittelet gir en praktisk start på datasiden av produktene dine. Vi tar for oss filbasert lagring, validering, datamodell, CRUD-mønster, backup og personvern.

Målet er ikke å late som om alle prosjekter trenger en tung database fra dag én. Målet er å lagre data på en måte som er forståelig, trygg nok for formålet og enkel å videreutvikle. Mange små og mellomstore produkter blir mer robuste av en enkel lagringsmodell som faktisk er ryddig, enn av en mer avansert løsning som ingen helt har kontroll på.

Hvordan tenke om lagring i praksis

Lagring er ikke bare et teknisk valg. Det er også et valg om ansvar og forutsigbarhet. Du må vite hva som skal lagres, hvorfor det lagres, hvor lenge det bør ligge, og hvordan du finner tilbake til det når noe går galt. Hvis disse spørsmålene er uklare, hjelper det lite om selve databasen er rask eller moderne.

I Norscode-prosjekter er det ofte lurt å starte med enkel struktur og tydelige regler. Når datamodellen er lett å forklare, blir den også lettere å validere, teste, migrere og feilsøke. Det er som regel dette som skiller en løsning som bare fungerer i dag, fra en løsning som fortsatt er håndterbar om seks måneder.

1) Filbasert lagring (praktisk start)

For små til mellomstore løsninger er filbasert lagring et godt første steg. Hold data i egne filer og les/skriv med enkle hjelpefunksjoner.

funksjon lagringsbane() -> tekst {
    returner "website/data/interesse.log"
}

funksjon lagre_rad(rad: tekst) -> heltall {
    hvis fil_eksisterer(lagringsbane()) da {
        skriv_fil(lagringsbane(), les_fil(lagringsbane()) + "\n" + rad)
        returner 1
    }
    skriv_fil(lagringsbane(), rad + "\n")
    returner 1
}

Fordelen med denne tilnærmingen er at hele datalaget er lett å se. Du vet hvilken fil som brukes, hvordan hver linje bygges og hvor du kan gå for å kontrollere rådata. For enkle innsendinger, køer, små logger eller interne verktøy er dette ofte et helt fornuftig første nivå.

Ulempen er at filbasert lagring stiller krav til disiplin. Du må være mer bevisst på format, separatorer, samtidige skriv og opprydding. Når volumet eller kompleksiteten øker, blir det fort viktig å avgrense hvilke problemer filformatet fortsatt løser godt, og hvilke problemer som bør flyttes til en mer strukturert datakilde.

2) Validering før lagring

All lagring bør alltid ha validering. Valider alt du ikke genererer selv.

funksjon valider_fokustype(fokus: tekst) -> bool {
    returner fokus == "compiler" eller fokus == "runtime" eller fokus == "studio" eller fokus == "web"
}

funksjon lagre_interesse(navn: tekst, team: tekst, fokus: tekst) -> heltall {
    hvis navn == "" da { returner 0 }
    hvis team == "" da { returner 0 }
    hvis ikke valider_fokustype(fokus) da { returner 0 }
    la rad: tekst = navn + "|" + team + "|" + fokus
    returner lagre_rad(rad)
}

Det viktigste her er at validering skjer før data blir en del av den varige tilstanden. Når ugyldige verdier først er skrevet, må resten av systemet enten tåle dem eller rydde dem opp i etterkant. Det er nesten alltid dyrere enn å stoppe feilen ved inngangen.

Validering bør også uttrykke forretningsregler, ikke bare typekontroll. Det holder ikke bare å vite at et felt er tekst. Du vil ofte vite om teksten kan være tom, om den er for lang, om den inneholder tegn som ødelegger lagringsformatet, eller om den peker på en verdi utenfor det systemet faktisk støtter.

3) Datamodell og konsistens

En datamodell er i praksis svaret på spørsmålet: hvordan representerer vi virkeligheten i lagring uten å miste mening? Selv ganske små systemer blir skjøre hvis felter får uklare navn, flere betydninger eller varierende format fra post til post.

Konsistent tegnsett

Bruk tydelige feltadskillelser og rens tegn som linjeskift og pipe før lagring.

Versjonskontrollert data

Planlegg feltutvidelser tidlig ved å versjonere strukturen eller legge til migreringsregler.

Det hjelper å velge noen få regler tidlig og holde dem konsekvent. Bestem for eksempel om datoer skal være tekst i ett standardformat, om tomme felter er tillatt, og om hver rad alltid skal ha samme antall deler. Slike valg virker små i starten, men de avgjør hvor enkel resten av koden blir.

Hvis du forventer endringer, bør du også tenke fremover. Mange systemer får problemer ikke fordi de vokser, men fordi de vokser uten en plan for hvordan nye felt skal innføres. Et enkelt grep kan være å versjonere radformat eller å ha eksplisitte migreringsfunksjoner når strukturen endres.

4) CRUD-struktur

Grunnstrukturen i små tjenester er: Create, Read, Update, Delete.

funksjon parse_rader() -> liste_tekst {
    hvis ikke fil_eksisterer(lagringsbane()) da {
        returner []
    }
    returner del_linjer(tekst_trim(les_fil(lagringsbane())))
}

funksjon hent_tall() -> heltall {
    la linjer: liste_tekst = parse_rader()
    returner lengde(linjer)
}

CRUD er nyttig fordi det tvinger frem et tydelig språk rundt dataflyten. Når du vet hvilken kode som oppretter, leser, oppdaterer og sletter, blir det lettere å plassere ansvar riktig. Det er også enklere å teste og revidere systemet når hver operasjon har sin egen, tydelige inngang.

Spesielt oppdatering og sletting fortjener omtanke. Mange produkter har behov for historikk, revisjonsspor eller myk sletting lenge før teamet tror de trenger det. Å slette en rad fysisk kan være greit i noen tilfeller, men ofte er det tryggere å markere at posten er inaktiv eller utløpt. Da blir både revisjon, support og feilsøking enklere.

5) Hva som ofte går galt i datalaget

Det meste av dette handler ikke om kompliserte databaser. Det handler om manglende grenser og manglende rutiner. Hvis du definerer én tydelig måte å validere, skrive, lese og migrere data på, eliminerer du mange av de vanligste feiltypene før de får feste.

6) Backup og restore

Backup er ikke valgfritt i seriøse løsninger. En enkel strategi:

  1. Daglig kopi av datafiler.
  2. Ukentlig komprimert arkiv.
  3. Test restore minst én gang per måned.
Unngå å lagre backup på samme volum som drift uten rotasjonsstrategi.

Det avgjørende er ikke bare at backupen finnes, men at du stoler på at den kan brukes. Mange team oppdager for sent at de har kopiert feil filer, at data er korrupt, eller at restore-prosessen er uklar. En backup som aldri er prøvd i praksis er mer håp enn beredskap.

Prøv å skrive ned en enkel restore-rutine som kan følges under press. Hvilken fil skal tilbakeføres først? Hvordan verifiserer du at riktig versjon ble gjenopprettet? Hvordan sjekker du at applikasjonen faktisk kan lese dataene etterpå? Jo enklere disse svarene er, jo bedre står du ved feil eller tap.

7) Personopplysninger og sikkerhet

Rens og begrens data du samler inn. Lagring av navn er normalt mulig, men vurder anonymisering der det holder.

Personvern blir mye enklere når du er bevisst fra starten. Spør hva som faktisk må lagres for at produktet skal gjøre jobben sin. Hvis et felt ikke har tydelig nytte, er det ofte bedre å ikke samle det inn i det hele tatt. Hver ekstra personopplysning gir mer ansvar i både drift, sletting, eksport og hendelseshåndtering.

Sikkerhet i datalaget handler også om eksponering. Hvem kan lese filene? Hvem kan skrive til dem? Hvor havner data i logger, feilspor eller e-postvarsler? Mange lekkasjer skjer ikke i “databasen”, men i hjelpeflyten rundt den. Derfor bør datalaget sees i sammenheng med logging, autentisering og operativ drift.

8) Migrasjonstankegang

Når prosjektet vokser over filene, må du flytte til database gradvis uten å stoppe produktet.

funksjon migrer_til_ny_kilde() -> tekst {
    returner "Steg 1: legg ut export av nåværende linjeformat\nSteg 2: importer i testinstans\nSteg 3: valider antall og felter\nSteg 4: bytt leser til ny kilde"
}

Den viktigste migrasjonstanken er at du sjelden ønsker et hardt kutt uten kontrollpunkter. En trygg migrasjon er vanligvis gradvis: først forstå eksisterende data, så eksportere i stabilt format, deretter validere mot ny modell og til slutt flytte lesing og skriving stegvis.

Før du migrerer, bør du vite mer enn bare antall rader. Du bør vite hvilke felt som har avvik, hvilke gamle verdier som ikke passer den nye modellen, og hvordan du vil håndtere hull og spesialtilfeller. God migrasjon er i stor grad godt oppryddingsarbeid.

9) Når du bør gå fra fil til database

Det finnes ikke ett magisk punkt, men noen signaler går igjen:

Poenget er ikke at filbasert lagring er feil. Poenget er å kjenne igjen når produktet har vokst forbi den opprinnelige modellen. Da er en mer strukturert database ikke et statussymbol, men et verktøy for å redusere risiko og manuelt arbeid.

10) Datakvalitets-sjekkliste

Bruk denne sjekklisten før hver release:

En god sjekkliste er nyttig fordi den gjør datakvalitet konkret. I stedet for å si at systemet virker ganske robust, kan du bekrefte at de viktigste kontrollene faktisk er på plass. Over tid kan denne listen utvides med egne behov, som datarensing, arkivering eller kontroller mot dubletter.

11) Hva du bør ta med deg videre

Det viktigste er å behandle datalaget som en del av produktets kjerne, ikke som et tilfeldig vedlegg. Tydelig modell, streng validering, forståelig lagringsformat, testbar restore og en plan for vekst gjør mer for kvaliteten enn å hoppe tidlig til kompliserte verktøy uten struktur.

Når lagringslaget er ryddig, blir resten av systemet også bedre. Web-laget blir enklere å validere. Support blir enklere å drive. Migrasjoner blir mindre skremmende. Og når noe går galt, har teamet et faktisk grunnlag for å forstå hva som skjedde.

12) Neste steg

Se også ytelses-guiden for hvordan lagringsvalg påvirker latens, og integrasjoner for hvordan data flyter