Tilbake
8.4
Dokumentasjon og vedlikehold

8.4 Dokumentasjon og vedlikehold

Teknisk dokumentasjon, README og vedlikeholdsstrategier.

50 min
5 oppgaver
DokumentasjonREADMEVedlikeholdKommentarer
Du leser den tradisjonelle versjonen
Din fremgang i kapitlet
0 / 5 oppgaver

God dokumentasjon er nøkkelen til langsiktig vedlikehald av programvare. Kode blir lesen langt oftare enn han blir skriven, og godt dokumentert kode gjer det enklare for andre (og deg sjølv om 6 månader!) å forstå kva som skjer.

I dette kapittelet skal vi sjå på ulike former for dokumentasjon – frå kodekommentarar og docstrings til README-filer og teknisk dokumentasjon. Vi skal også diskutere teknisk gjeld og refaktorering.

Nivå av dokumentasjon

1. Kodekommentarar

Inline-kommentarar forklarer kvifor, ikkje kva:

# DÅRLIG: Forklarer det åpenbare
x = x + 1  # Øk x med 1

# BRA: Forklarer hvorfor
x = x + 1  # Kompenserer for zero-indexed arrays

Når bruke kommentarar:
- Kompleks logikk eller algoritmar
- Workarounds for kjende bugs
- Forklare business logic
- TODOs og FIXMEs

Når IKKJE bruke kommentarar:
- I staden for god namngiving
- Forklare sjølvforklarande kode
- Gammal, utdatert kode (slett i staden!)

2. Docstrings

Docstrings dokumenterer funksjonar, klassar og modular:

def calculate_discount(price, discount_percent, customer_tier):
    """
    Beregner rabattert pris basert på kundekategori.

    Args:
        price (float): Opprinnelig pris i NOK
        discount_percent (float): Rabattprosent (0-100)
        customer_tier (str): Kundekategori ('bronze', 'silver', 'gold')

    Returns:
        float: Rabattert pris

    Raises:
        ValueError: Hvis discount_percent er utenfor 0-100

    Example:
        >>> calculate_discount(1000, 10, 'gold')
        850.0
    """
    if not 0 <= discount_percent <= 100:
        raise ValueError("Discount må være mellom 0 og 100")

    base_discount = price * (discount_percent / 100)

    # Ekstra rabatt basert på tier
    tier_bonus = {'bronze': 0, 'silver': 0.05, 'gold': 0.10}
    extra = price * tier_bonus.get(customer_tier, 0)

    return price - base_discount - extra

Docstring-format:
- Google style (mest lesbar)
- NumPy style (for vitskapeleg kode)
- reStructuredText (Sphinx-dokumentasjon)

3. README.md

Kvar repository bør ha ein README med:

# Prosjektnavn

Kort beskrivelse av hva prosjektet gjør.

## Funksjoner
- Feature 1
- Feature 2

## Installasjon
\`\`\`bash
pip install -r requirements.txt
\`\`\`

## Bruk
\`\`\`python
from myapp import MyClass
obj = MyClass()
\`\`\`

## Bidra
Se CONTRIBUTING.md

## Lisens
MIT License

4. API-dokumentasjon

For bibliotek og API-ar:
- Sphinx (Python) – Genererer HTML frå docstrings
- JSDoc (JavaScript)
- Swagger/OpenAPI (REST APIs)

Teknisk gjeld (Technical Debt)

Teknisk gjeld er kompromiss i koden som gjer framtidig utvikling vanskelegare:

Typar teknisk gjeld:
- Forsetteleg: "Vi fiksar dette etter lansering" (men gløymer det)
- Uforsetteleg: Dårleg design pga manglande erfaring
- Miljømessig: Verktøy/bibliotek som blir utdaterte

Konsekvensar:
- Lengre tid på nye features
- Fleire bugs
- Vanskeleg å onboarde nye utviklarar
- Låg motivasjon i teamet

Handtere teknisk gjeld:
- Aller tid til "refactor sprints"
- Boy Scout Rule: "Leave the code better than you found it"
- Dokumenter kjend gjeld i TECH_DEBT.md
- Prioriter gjeld som blokkerer nye features

Refaktorering

Refaktorering er å forbetre kodestrukturen utan å endre funksjonalitet:

Vanlege refaktoreringar:
- Endre variabelnamn
- Trekkje ut metodar (Extract Method)
- Flytte kode til rett klasse (Move Method)
- Fjerne duplikat kode (DRY principle)
- Forenkle komplekse if-setningar

Gylne regel: Ha testar før refaktorering!

# FØR refaktorering
def process(data):
    result = []
    for item in data:
        if item['status'] == 'active' and item['age'] > 18:
            result.append(item['name'].upper())
    return result

# ETTER refaktorering
def process(data):
    return [
        item['name'].upper()
        for item in data
        if is_eligible(item)
    ]

def is_eligible(item):
    """Sjekk om item er eligible for processing."""
    return item['status'] == 'active' and item['age'] > 18

Code smells (teikn på dårleg kode):
- Long Method – Funksjonar over 50 linjer
- God Class – Klassar som gjer for mykje
- Duplicate Code – Copy-paste mellom filer
- Magic Numbers – Hardkoda tal utan forklaring
- Long Parameter List – Funksjonar med > 5 parameter

✏️Eksempel: God vs dårleg dokumentasjon
DÅRLEG dokumentasjon:

def calc(a, b, c):
    # Beregner noe
    x = a * b
    if c:
        return x * 1.25
    return x

Problem:
- Uklare parameternamn (a, b, c)
- Uklar kommentar ("noe")
- Ingen docstring
- Magisk tal (1.25)

GOD dokumentasjon:

TAX_RATE = 1.25  # Moms 25%

def calculate_price(quantity, unit_price, include_tax):
    """
    Beregner totalpris for en bestilling.

    Args:
        quantity (int): Antall varer
        unit_price (float): Pris per vare i NOK
        include_tax (bool): Om moms skal inkluderes

    Returns:
        float: Totalpris i NOK

    Example:
        >>> calculate_price(5, 100, True)
        625.0
    """
    subtotal = quantity * unit_price

    if include_tax:
        return subtotal * TAX_RATE

    return subtotal

✏️Eksempel: Refaktorering av kompleks kode
FØR refaktorering:

def process_order(order):
    # Valider ordre
    if 'items' not in order or len(order['items']) == 0:
        return {'status': 'error', 'msg': 'Ingen varer'}
    if 'customer' not in order or 'email' not in order['customer']:
        return {'status': 'error', 'msg': 'Ugyldig kunde'}

    # Beregn total
    total = 0
    for item in order['items']:
        if 'price' not in item or 'qty' not in item:
            return {'status': 'error', 'msg': 'Ugyldig vare'}
        total += item['price'] * item['qty']

    # Sjekk lager
    for item in order['items']:
        if item['qty'] > item.get('stock', 0):
            return {'status': 'error', 'msg': f"{item['name']} ikke på lager"}

    # Rabatt hvis over 1000kr
    if total > 1000:
        total = total * 0.9

    return {'status': 'success', 'total': total}

ETTER refaktorering:

BULK_DISCOUNT_THRESHOLD = 1000
BULK_DISCOUNT_RATE = 0.10

def process_order(order):
    """Prosesserer ordre og returnerer resultat."""
    validation_error = validate_order(order)
    if validation_error:
        return {'status': 'error', 'msg': validation_error}

    total = calculate_total(order['items'])
    total = apply_bulk_discount(total)

    return {'status': 'success', 'total': total}

def validate_order(order):
    """Validerer ordre, returnerer feilmelding eller None."""
    if not order.get('items'):
        return 'Ingen varer'

    customer = order.get('customer', {})
    if not customer.get('email'):
        return 'Ugyldig kunde'

    for item in order['items']:
        if 'price' not in item or 'qty' not in item:
            return 'Ugyldig vare'

        if item['qty'] > item.get('stock', 0):
            return f"{item['name']} ikke på lager"

    return None

def calculate_total(items):
    """Beregner totalpris for alle varer."""
    return sum(item['price'] * item['qty'] for item in items)

def apply_bulk_discount(total):
    """Gir rabatt på store ordrer."""
    if total > BULK_DISCOUNT_THRESHOLD:
        return total * (1 - BULK_DISCOUNT_RATE)
    return total

Forbetringar:
- Mindre funksjonar med tydelege namn
- Konstantar i staden for magiske tal
- Enklare å teste kvar del isolert
- Enklare å forstå kva som skjer

Oppgåve 1 (Flerval)
Kva er hovudformålet med docstrings?

A) Å forklare kvar einaste linje kode
B) Å dokumentere kva funksjonar, klassar og modular gjer
C) Å gjere koden lengre
D) Å erstatte variabelnamn

Oppgåve 2 (Flerval)
Kva er teknisk gjeld?

A) Pengar ein skuldar til utviklarar
B) Kompromiss i koden som gjer framtidig utvikling vanskelegare
C) Talet på bugs i systemet
D) Tid brukt på testing

Oppgåve 3
Forklar skilnaden mellom kommentarar og docstrings i Python.

Oppgåve 4
Skriv ein god docstring for denne funksjonen:

def filter_users(users, min_age, country):
    return [u for u in users if u['age'] >= min_age and u['country'] == country]

Oppgåve 5
Kva er "Boy Scout Rule" i programmering?

Oppgåve 6
Nemn tre "code smells" (teikn på dårleg kode).

Oppgåve 7
Refaktorer denne funksjonen for betre lesbarheit:

def x(a, b):
    r = []
    for i in a:
        if i > b:
            r.append(i * 2)
    return r

Oppgåve 8
Kva bør ei god README.md-fil innehalde?

// --- Samleoppgåver ---

Samleoppgåve 1
Du overtek eit prosjekt med denne koden:

def f(d):
    t = 0
    for i in d:
        if i['s'] == 'a' and i['p'] > 100:
            t += i['p'] * i['q']
        elif i['s'] == 'b':
            t += i['p'] * i['q'] * 0.8
    if t > 5000:
        t = t * 0.95
    return t

a) Forklar kva koden gjer (gjett basert på logikken).
b) Refaktorer koden med betre namn, konstantar og struktur.
c) Legg til passande docstrings.
d) Kva for "code smells" fann du i originalkoden?

Samleoppgåve 2
Du leier eit team som vedlikeheld ein 5 år gammal webapplikasjon. Teamet rapporterer:
- Ny funksjonalitet tek 3x lengre tid enn før
- Mange bugs dukkar opp etter kvar deploy
- Ingen tør å endre visse delar av koden
- Inga dokumentasjon finst

a) Kva for teikn på teknisk gjeld ser du her?
b) Lag ein plan for å adressere problemet over 3 månader.
c) Kva for typar dokumentasjon bør prioriterast først?
d) Korleis kan teamet unngå å samle opp ny teknisk gjeld framover?

Oppsummering

I dette kapittelet har du lært:

- Dokumentasjon: gjer koden forståeleg for andre.
- Kodekommentarar: forklar kvifor, ikkje kva.
- README: skildrar prosjektet og bruk.
- Vedlikehald: halde koden oppdatert over tid.
- Refaktorering: forbetre kodestruktur utan å endre funksjon.

Nøkkelomgrep


OmgrepForklaring
DokumentasjonSkriftleg info som forklarer prosjektet
RefaktoreringForbetre kodestruktur utan å endre åtferd

Dette kapitlet er skrevet av Anthropics toppmodeller (Claude Opus og Claude Fable) og er foreløpig ikke manuelt gjennomgått — kvalitetskontrollen gjøres av uavhengige KI-agenter, og innmeldte feil rettes fortløpende. Funnet en feil? Meld fra, så retter vi den. Les mer om hvordan innholdet lages.