10 tips til deg som vil komme i gang med dbt

12.02.2022 | 10 min lesetid
Emneknagger: #dbt, #data build tool

1. Følg beste praksis, og spør forumet når man er i tvil

Det viktigste man gjør er å bestemme seg for å bruke dbt. Det nest viktigste man gjør er å starte på riktig fot ved å lese seg opp på hva som er beste praksis. dbt Labs, selskapet bak dbt, er heldigvis svært ivrige på å dele av sine kunnskaper, og har tilgjengeliggjort en solid liste med sine tips og triks for hvordan man burde gå frem: dbt best practices

I tillegg til å være rimelig flinke til å dokumentere på nett har også dbt i kraft av å være både mye brukt og open source et levende community som finnes på slack. Her finnes fora for alle mulige behov, og man kan regne med å raskt få respons fra utviklere av produktet eller erfarne brukere.

Slack-kanalene til dbt er en god kilde til informasjon og diskusjon
Slack-kanalene til dbt er en god kilde til informasjon og diskusjon

2. Definer utviklingsstandarden

Et naturlig neste steg, som er så viktig at det nevnes her selv om det også finnes via punktet over, er å definere utviklingsstandarden før man i det hele tatt begynner på en dbt-implementasjon. Dette er særlig viktig i større team, men også svært nyttig når man bare er en utvikler, da dette fremtvinger en del valg som sikrer konsistens i det som gjøres.

Det er ikke helt uvanlig at ting utvikler seg over tid, nye utviklere kommer til, og det blir tatt i bruk alternative måte å gjøre ting på. Tillater man dette vil man fort ende opp med å ha et prosjekt fullt av spagetti-arkitektur.

Gjennom å først tenke igjennom og dokumentere en utviklingsstandard man skal følge blir det enklere å utvikle, enklere å gjøre kodesjekk, og enklere for nye utviklere å komme inn i prosjektet. Gjennom at standarden blir konkret på denne måten blir det også enklere å revurdere den jevnlig etterhvert som man gjør seg nye erfaringer. NB: husk punkt 10 om refaktorering når standarden endres.

Et godt sted å begynne for å lage sin egen utviklingsstandard er å ta utgangspunkt i den som dbt har gjort tilgjengelig: dbt style guide

I tillegg er The Zen of Python evig aktuell.

3. Design lagdelingen i arkitekturen tidlig

På samme måte som at man har en standarden klar tidlig burde man også ha en tydelig plan for de ulike lagene man skal ha i arkitekturen. Da er det ikke kun snakk om hvor mange og hvordan de skal navngis, men det kanskje aller viktigste er å bestemme hvilken rolle de skal spille og hvordan lagene skal interagere.

Uavhengiv av antallet lag man ender opp med er det, som dbt anbefaler, en veldig god praksis å la det første laget være et rent være et rent standardiseringslag som er 1:1 mot kildetabellen. På denne måten sørger man for å endre navn, håndtere datakvalitet og datatyper, samt andre enkle operasjoner på en felles plass, som alle etterfølgende modeller kan dra nytte av.

Utover dette kan det være en god praksis å ha som basisregel at hvert lag i all hovedsak skal hente data fra det foregående laget, da dette sørger for at man slipper uklare avhengigheter på kryss og tvers innad i et lag.

4. Ha en tydelig utviklingsprosess med kodesjekk

Når man først har kommet i gang med utviklingen, og har utviklingsstandarden og arkitekturen på plass, må man så sette rammene og prosessene for å sørge for at alt blir overholdt. Her kan man gjøre mange enkle men effektive tiltak. Når det komme til nye utviklere burde man allerede ha dokumentert ned det man har landet i stegene over, slik at det er enkelt å lese seg opp på. I tillegg er det en god øvelse å utøve parprogrammering i en viss grad i starten.

Utover dette burde man sette prosessen i system gjennom å definere pull request-templates og sette opp branch policies som sørger for at det automatisk blir tilordnet en code reviewer når en pull request opprettes. CI/CD-prosesser vil også hjelpe på her.

5. Tenk alltid DRY

I motsetning til mer tradisjonelle, grafiske ETL-verktøy, får an gjennom et kodebasert verktøy som dbt en del muligheter til å gjøre ting mer i henhold til klassisk beste praksis kjent fra programvareutvikling. DRY er et særdeles viktig prinsipp her - don’t repeat yourself. Med andre ord, skal du løse det samme problemet flere ganger, sørg for å bygg en struktur og funksjoner som gjør at koden kan gjenbrukes, og at man kun må vedlikeholde den ett sted.

I dbt er det(minst) tre ulike komponenter man kan ta i bruk her:

  • Utnytte lagdelingen: En effektiv lagdeling, der navneendring, bytting av datatyper og håndtering av datakvalitet gjøres tidlig og kun på ett sted gjør at alle etterfølgende avhengigheter slipper å løse det samme problemet igjen og igjen.
  • Makroer: En nøkkelkomponent i dbt er jinja. Her kan man bygge macroer for å løse et spesifikt problem. Dette kan være helt enkle ting for å standardisere datatypekonvertering, filtrering eller nøkkelbygging, eller langt mer avanserte ting . Mulighetene er (nesten) endeløse, og for mer avanserte brukere åpner dette også opp for å overstyre innebygd funksjonalitet om man har behov for det.
  • Variabler: dbt har også god støtte for å definere variabler på ulike nivåer som man kan bruke i definisjon av modeller eller som del av macroer.

6. Bruk devcontainer for utvikling

Skal man skalere utviklingen i dbt, gjerne med mange utviklere fordelt på flere team, er man avhengig av at alle får opp utviklingsmiljøet raskt og effektivt, og at det fungerer helt likt hos alle. I tillegg må man også ha muligheten til å gjøre endringer på utviklingsmiljøet hos alle mer eller mindre samtidig ved behov, eksempelvis når dbt oppdateres til en ny versjon.

Den utvilsomt enkleste metoden for å få til dette er ved å bruke devcontainere. Da definerer man utviklingsmiljøet som en del av dbt-repoet, og docker vil sørge for at alle nødvendige komponenter blir installert helt likt overalt. Og det beste av alt, utviklingsopplevelsen er helt lik som om man skulle ha installert alt lokalt (i alle fall gitt at man har noenlunde nok minne tilgjengelig).

version: '3.4'

services: 
  dbt:    
    build: 
      context: ../
      dockerfile: ./.build/container/Dockerfile
    environment: 
      DBT_PROFILES_DIR: ./.devcontainer/
      VARIANT: '3.9'
      DBT_ENVIRONMENT: 'dev'
    init: true
    volumes: 
      - ..:/workspace:cached
    
    command: sleep infinity 

7. Dokumenter og implementer tester samtidig med koden

Det er fort gjort at dokumentasjon og testing blir nedprioritert når man kjenner at tidsfristen nærmer seg og man ennå har mye som må gjøres. Men i dbt er det så enkelt å gjøre begge deler at man har i realiteten ingen unnskyldninger for å ikke gjøre begge deler samtidig som man skriver koden.

Et raskt eksempel kan se ut som følger for tabellen eksempel. Her er det definert både en tabellbeskrivelse, en kolonnebeskrivelse med innhentet datatype, samt to definerte tester for kolonnen - at den skal være unik og at den ikke skal ha null-verdier.

Dokumentasjonen som dbt genererer er svært praktisk og oversiktlig
Dokumentasjonen som dbt genererer er svært praktisk og oversiktlig

Og hva skal til for å oppnå dette? Skarve 9 linjer med tekst.

models:
  - name: eksempel
    description: Dette er et eksempel på en tabell
    columns:
      - name: kolonne_1
        description: Dette er den første kolonnen i tabellen
        tests:
          - unique
          - not_null

Når man først har gjort dette så vil alt dette dukke opp i dbt dokumentasjonen, og om man bruker funksjonen build så vil dbt først kjøre modellen for å opprette den, og så kjøre begge testene som er definert for å se om de passerer. Eller man kan bare kjøre funksjonen test for å gjennomføre alle testene som finnes.

Her er en oversikt over tester som finnes innebygd i dbt. Men husk at man kan alltid definere sine egne etter behov.

8. Utnytt at dbt gjør CI/CD enkelt

State
dbt har en mengde funksjoner som gjør det velegnet for CI/CD-prosesser, og det burde utnyttes.

Et veldig godt eksempel på dette er state. dbt har mulighet til å lagre staten sin, det vil si tilstanden kodebasen var i, etter en kjøring. Ved neste kjøring kan man så sammenligne kodebasen, og så velge å kjøre kun det som er nytt eller endret siden sist, som man kan se i eksempelet under. Her vil også alle etterfølgende avhengigheter kjøre (se +-en etter state:modified), da man ofte er avhengig av det.

dbt run --select state:modified+ --full-refresh

Dette var bare ett eksempel på bruken av dbt sin kommandolinjesyntaks, men den er svært fleksibel og det kan være en nyttig øvelse å få et et intimt forhold til den.

Dokumentasjon
En annen mulighet man gjerne kan utnytte er å bygge og deploye dokumentasjonen hver gang man gjør en deploy til et miljø, slik at man alltid har oppdatert dokumentasjon for hvert av miljøene sine. Det blir da en enkel inngangsport for både utviklere og analytikere, som kan være trygge på at det de ser i dokumentasjonen samsvarer med det de ser i databasen.

Å bygge dokumentasjonen er bare enda en variant av kommandolinjemulighetene til dbt. De genererte filene kan så deployes til sin ønskede lokasjon. Dette er bare en statisk nettside, og kan dermed eksempelvis leveres fra en data lake.

9. Se på det som en modningsreise

Det kan virke overveldende i starten å ta inn over seg alt man burde tenke på i forbindelse med et dbt-prosjekt, men det er det ingen grunn til. Ting går sjeldent veldig feil i dbt - man endrer aldri på kildedataene, og en full rekjøring av alle modeller er bare en dbt run --full-refresh unna. Det betyr at man trygt kan se på det som en modningsreise hvor man bygger på litt etter litt, og etter hvert som man modnes kan man ta i bruk mer avansert funksjonalitet.

Macroer og CI/CD-prosesser gjør livet enklere, men man kan fint leve uten det. Start enkelt, løs de første behovene, og ta det derfra.

10. Refaktorer ofte

Og et siste, men svært viktig tips til slutt - refaktorer ofte! Som nevnt vil ting utvikle seg over tid, man modnes og gjør seg nye erfaringer, og finner smartere måter å gjøre ting på. Det er sånn det skal være.

Men når dette skjer så må man ikke gå i fellen som er å begynne å gjøre ting på en ny måte uten å samtidig justere det gamle - eller minimum legge en plan for når det skal gjøres. Det er oppskriften på å pådra seg teknisk gjeld, og en framtidig spagetti-arkitktur.

dbt gjør refaktorering svært enkelt. Det er bare snakk om vanlige tekstfiler, som dermed kan endres fort. Ønsker man å gjøre større endringer i batch, kan VS Code gjøre relativt avansert søk-og-erstatt-operasjoner, eller man kan skrive en python-fil som gjør jobben. Man får opp endringene i endringsloggen, og kan kjøre dbt-prosjektet for å se om alt kompilerer og kjører som det skal. Gjør man en feil kan often en test oppdage det, eller så har men endringshistorikken i git-repoet og kan gå tilbake igjen ved behov.

Så ikke vær redd for å gjøre ting på en ny måte - omfattende endringer er ikke så omfattende i dbt.

author image

Sindre Grindheim

Sindre er en erfaren Data Engineer som har arbeidet daglig med arkitektur, flyt og tilrettelegging av data i alt fra klassiske datavarehus til moderne dataplattformer i Azure og GCP i hele arbeidskarrieren.