Guide

Standarder som gjør dataplattformen konsistent

Navneregler, nøkler, historikk og eierskap. Slik lager dere standarder for dataplattformen, og derfor bør de håndheves automatisk.

Nettbutikken har tre team som bygger tabeller. Ett av dem kaller kundenøkkelen kunde_id, et annet kundenr, og det tredje bare id. Én tabell markerer aktive kunder med aktiv, en annen med er_aktiv_flagg. Ordredatoen heter dato i én tabell og ordre_ts i en annen, og bare den ene sier om tiden er norsk eller UTC. Hver for seg er valgene forståelige. Til sammen gjør de at en analytiker må åpne hver tabell for å finne ut hva kolonnene betyr, og at to rapporter kan koble kunde og ordre på ulike måter.

En standard er en liste med avgjørelser som er tatt én gang, slik at ingen trenger å ta dem på nytt for hver tabell. Denne artikkelen går gjennom de avgjørelsene som gir mest igjen: navn, nøkler, systemkolonner, historikk og eierskap. Til slutt handler den om hvordan standarden faktisk blir fulgt.

Begynn med hvilket lag tabellen hører til. Nettbutikkens dataplattform har tre lag: et lag med rådata slik de kom fra kilden, et lag der dataene er vasket og samordnet, og et lag med tabeller bygget for bestemte formål. Hvorfor den felles modellen hører hjemme i det midterste laget, sølvlaget, står i artikkelen om felles datamodell. Her er det nok at laget skal synes i navnet, enten som et prefiks eller som et eget skjema.

For nettbutikken kan det se slik ut:

Lag Mønster Eksempel
Bronse brz_<kilde>__<objekt> brz_nettbutikk__ordre
Sølv slv_<objekt> slv_kunde, slv_ordre, slv_produkt
Gull dim_<objekt>, fakta_<prosess> dim_kunde, fakta_ordrelinje

brz_ og slv_ er ett av flere mulige mønstre. Det viktigste er å velge ett og bruke det overalt.

I bronselaget står kildesystemet i navnet, fordi samme objekt kan komme fra flere kilder. Det samme mønsteret bruker dbt Labs i sin stilguide for dbt-prosjekter: stg_[kilde]__[objekt], med dobbel understrek mellom kilde og objekt slik at de to delene er lette å skille når et kildenavn består av flere ord. I sølvlaget er kilden borte fra navnet, fordi kunden fra nettbutikken og kunden fra kundeservice der er blitt én kunde. I gullaget sier prefikset om tabellen er en dimensjon eller en faktatabell, slik det er beskrevet i dimensjonsmodellering i praksis.

Bruker dere Databricks, kan laget også ligge i katalogen eller skjemaet i stedet for i tabellnavnet, for eksempel silver.kunde. Databricks skriver at kataloger ofte svarer til et miljø, et team eller et forretningsområde, og Unity Catalog lagrer alle objektnavn med små bokstaver. Velg den ene måten og bruk den overalt. To systemer for det samme er verre enn hvilket som helst av dem.

Bestem også om tabellnavn står i entall eller flertall. dbt-guiden anbefaler flertall, customers og orders, fordi SQL da leses mer som vanlig tekst. Artiklene her bruker entall, kunde og ordre. Begge deler fungerer. Det som ikke fungerer, er å ha kunde ved siden av ordrer.

For kolonner er de viktigste reglene enkle å skrive ned:

  • Små bokstaver og understrek. ordre_dato, ikke OrdreDato. dbt-guiden sier det samme: skjemaer, tabeller og kolonner i snake_case.
  • Ingen forkortelser. kunde, ikke kd eller kunde_nr i én tabell og kundenummer i en annen. dbt-guiden sier rett ut at lesbarhet går foran korthet.
  • Forretningens navn, ikke kildens. Kaller kildesystemet kunden bruker, men forretningen sier kunde, heter kolonnen kunde_id i sølvlaget. Begrepet bak navnet bør være definert ett sted, slik det er beskrevet i fra forretningsbegrep til kolonne.
  • Samme navn overalt. En nøkkel til kunden heter kunde_id i alle tabeller som har den, ikke kunde_id i ordretabellen og id i kundetabellen. dbt-guiden bruker nettopp dette som eksempel.

Den siste regelen er den som gjør det mulig å koble tabeller uten å slå opp. Kimball Group sier at dimensjoner er konforme når attributtene i dem har de samme kolonnenavnene og det samme innholdet. Det er det som lar salg og retur bruke den samme kundedimensjonen.

Den andre halvdelen av kolonnenavnet sier hva slags verdi kolonnen har. Standarden ISO/IEC 11179 setter sammen et dataelement av et objekt og en egenskap, for eksempel kunde og kommune, og har en egen del om navngiving, del 5. Der beskrives et representasjonsledd: den delen av navnet som sier hvilken type verdi elementet har, som beløp, kode, dato, identifikator, indikator eller navn. I praksis blir det faste endelser og prefikser:

Type verdi Regel Eksempel
Naturlig nøkkel <objekt>_id kunde_id, produkt_id
Surrogatnøkkel <objekt>_nokkel kunde_nokkel
Sann/usann er_ eller har_ foran er_aktiv, har_samtykke
Dato _dato bak ordre_dato
Tidspunkt _tidspunkt bak, alltid i UTC betalt_tidspunkt
Beløp _belop bak, valuta i beskrivelsen ordre_belop

dbt-guiden har tilsvarende regler på engelsk: is_ og has_ foran sannhetsverdier, <hendelse>_at for tidspunkt i UTC, <hendelse>_date for datoer, og et suffiks som sier fra når et tidspunkt ikke er i UTC. Med en slik regel vet den som leser betalt_tidspunkt, at verdien er et tidspunkt i UTC, uten å åpne dokumentasjonen.

Nøkler, systemkolonner og historikk

Hver tabell skal ha en primærnøkkel, og standarden bør si hvilken type. I sølvlaget kan dere beholde den naturlige nøkkelen fra kilden, kunde_id, fordi den gjør det mulig å spore en rad tilbake. I gullagets dimensjoner trenger dere i tillegg en surrogatnøkkel. Kimball Group skriver at primærnøkkelen i en dimensjon ikke kan være den naturlige nøkkelen fra kildesystemet når endringer spores over tid, fordi det da finnes flere rader for den samme naturlige nøkkelen. Surrogatnøkkelen er et tall som dataplattformen lager selv. Hvorfor og hvordan står i dimensjonsmodellering i praksis. Det standarden skal avgjøre, er navnet og typen, slik at kunde_nokkel er et heltall i alle tabeller.

Systemkolonner er kolonnene plattformen legger til selv, uavhengig av innholdet. Standarden bør si hvilke som er påkrevd, og hva de heter. For nettbutikken kan det være:

  • lastet_tidspunkt: når raden ble lastet inn i plattformen.
  • kilde_system: hvilket system raden kom fra, i sølvlaget der flere kilder er slått sammen.

Historikk krever flere systemkolonner. Når en dimensjon tar vare på gamle versjoner av en rad, det som kalles SCD type 2, får den en ny rad hver gang en sporet verdi endres. Kimball Group sier at en slik dimensjon trenger minst tre kolonner i tillegg: når raden begynte å gjelde, når den sluttet å gjelde, og en markering av hvilken rad som gjelder nå. Gi dem de samme navnene i alle tabeller, for eksempel gyldig_fra, gyldig_til og er_gjeldende. Da kan en analytiker som har lært å hente gjeldende kunde, hente gjeldende produkt på samme måte.

Standarden bør også si hvilken type historikk som er utgangspunktet. Et enkelt valg er at sølvlaget bare har gjeldende verdi, og at historikk lages i dimensjonene i gullaget når noen trenger den. Det viktigste er at valget står skrevet, slik at det ikke tas på nytt for hver tabell.

Eierskap og påkrevd dokumentasjon

To ting bør være påkrevd for hver tabell: en eier og en beskrivelse.

Eieren er den som svarer når noen lurer på hva tabellen inneholder, og den som bestemmer hva som skjer når den skal endres. Databricks anbefaler at eierskap til kataloger og skjemaer i produksjon alltid gis til grupper, ikke til enkeltpersoner. Det samme rådet gjelder tabellene: eieren bør være et team, slik at tabellen ikke står uten eier når noen bytter jobb.

Beskrivelsen sier hva én rad er, hvor dataene kommer fra, og hva tabellen ikke inneholder. «Kundetabell» er ikke nok. «Én rad per kunde, samlet fra nettbutikken og kundeservice. Inneholder ikke kunder som har slettet kontoen» kan leses av noen som aldri har sett tabellen før. Databricks skriver at kommentarer på tabeller og kolonner gjør dataene lettere å finne og å forvalte. Standarden bør kreve beskrivelse på tabellen og på hver kolonne, med unntak for systemkolonnene, som er beskrevet én gang i standarden.

Slik ser en tabell etter standarden ut

Hvis dere beskriver tabellene som datakontrakter, kan standarden leses rett ut av kontrakten. Her er sølvtabellen for kunder i Open Data Contract Standard, med prefiks for laget, et eierteam, beskrivelser og en primærnøkkel:

apiVersion: v3.2.0
kind: DataContract
id: slv_kunde
version: 1.0.0
status: active
team:
  name: Kundedata
schema:
  - name: slv_kunde
    description: Én rad per kunde, samlet fra nettbutikken og kundeservice.
    properties:
      - name: kunde_id
        logicalType: string
        primaryKey: true
        description: Kundenummeret fra nettbutikken.
      - name: er_aktiv
        logicalType: boolean
        description: Sann hvis kunden er aktiv. Beregnes ved nattlig lasting.

Alt en standard sier om denne tabellen, kan sjekkes her: navnet har riktig prefiks, nøkkelen heter kunde_id, sannhetsverdien begynner med er_, og både tabellen og kolonnene har en beskrivelse og et eierteam.

Hvorfor standarden bør håndheves automatisk

Tenk deg at standarden er et dokument. Det blir skrevet, delt og lest av dem som var med da det ble laget. Så skjer tre ting.

Avvikene kommer gradvis. Et nytt teammedlem har ikke lest dokumentet, og lager kundenr. Et annet team har dårlig tid og hopper over beskrivelsen. Ingen av avvikene er store, men etter et år er det like mange tabeller som bryter standarden som tabeller som følger den.

Kommentarene i review blir glemt. Når standarden bare håndheves i review, avhenger den av at den som gjør review, husker alle reglene og orker å skrive den samme kommentaren for tiende gang. Kommentaren «bør hete kunde_id» blir notert som en oppfølging og blir aldri gjort, eller den blir ikke skrevet fordi resten av endringen var viktigere.

Det samme begrepet får flere navn. Når navnet ikke sjekkes, får kunden tre navn i tre tabeller, og ingen vet om kunde_id, kundenr og bruker_id er det samme. Da forsvinner nettopp det Kimball kaller konforme dimensjoner: at samme ting har samme navn og samme innhold overalt.

Løsningen er å gjøre reglene til sjekker som kjører hver gang en tabell lages eller endres, i stedet for kommentarer som avhenger av hukommelsen til den som leser. Prefiks, endelser, påkrevd eier og påkrevd beskrivelse er lette å sjekke maskinelt. Da kan review handle om det som krever vurdering: om tabellen har riktig granularitet, og om definisjonen er den forretningen faktisk bruker.

Hvor dere kan begynne

Dere trenger ikke en standard på tjue sider. Skriv ned avgjørelsene i denne artikkelen for nettbutikkens tre tabeller, slv_kunde, slv_ordre og slv_produkt: prefiks per lag, navn på nøkler, endelser for datoer, tidspunkt og sannhetsverdier, påkrevde systemkolonner, og at hver tabell skal ha en eier og en beskrivelse. Gjør så reglene til sjekker før dere ber noen følge dem. En standard som håndheves automatisk fra første tabell, er lettere å holde enn en som skal innføres i ettertid.

Kilder