Læringsmål

  • Kan forklare DRY-princippet med egne ord
  • Kan genkende gentagen kode og samle den i metoder
  • Kan refaktorere simpel duplikeret logik uden at ændre adfærd
  • Kan skelne mellem DRY og for tidlig abstraktion (KISS)

DRY — Don't Repeat Yourself

DRY betyder: gentag ikke den samme logik mange steder. Hvis du har skrevet det samme (eller næsten det samme) to gange, bør det typisk være én metode — så retter du fejl ét sted.

DRY handler om viden og logik — ikke om at to linjer tilfældigt ligner hinanden. Console.WriteLine("Hej"); og Console.WriteLine("Farvel"); er ikke et DRY-problem.

DRY betyder ikke "lav alt generisk med det samme". Én kopi er bedre end en dårlig abstraktion. Se KISS — forenkel først, derefter samle gentagelser når mønsteret er tydeligt.

Hvad skal samles?

DRY — gentag logik Ikke nødvendigvis DRY
Samme beregning tre steder To Console.WriteLine med forskellig tekst
Samme validering i to if To variabler med samme type
Samme udskriftsformat i en løkke og udenfor Lignende men forskellig forretningsregel

Eksempel 1 — Samme udskrift tre gange

Gentaget (DRY-brud):

Console.WriteLine("=== Rapport ===");
Console.WriteLine($"Navn: {name}");
Console.WriteLine($"Score: {score}");

Console.WriteLine("=== Rapport ===");
Console.WriteLine($"Navn: {teacher}");
Console.WriteLine($"Score: {examScore}");

Console.WriteLine("=== Rapport ===");
Console.WriteLine($"Navn: {guest}");
Console.WriteLine($"Score: {guestScore}");

DRY:

Eksempel 2 — Samme grænseværdi mange steder

Gentaget:

if (score >= 60)
{
    Console.WriteLine("Bestået");
}

// ... 30 linjer senere ...

if (score >= 60)
{
    bonusPoints = 5;
}

// ... igen ...

passed = score >= 60;

DRY:

Nu ændrer du ét sted, hvis grænsen bliver 50 eller 70.

Eksempel 3 — Læs input med samme validering

Gentaget:

DRY:

Senere kan du udvide én metode med TryParse og fejlbeskeder — ikke tre kopier.

Eksempel 4 — Samme loop-mønster

Gentaget:

for (int i = 0; i < names.Length; i++)
{
    Console.WriteLine($"{i + 1}. {names[i]}");
}

// ... senere med et andet array ...

for (int i = 0; i < cities.Length; i++)
{
    Console.WriteLine($"{i + 1}. {cities[i]}");
}

DRY:

Eksempel 5 — Beregning kopieret i if og else

Gentaget:

if (hours > 40)
{
    double pay = 40 * rate + (hours - 40) * rate * 1.5;
    Console.WriteLine(pay);
}
else
{
    double pay = hours * rate;
    Console.WriteLine(pay);
}

DRY:

Reglen for løn findes ét sted — nemmere at teste og forklare.

Eksempel 6 — Validering kopieret til flere felter

Gentaget:

if (string.IsNullOrWhiteSpace(firstName))
{
    Console.WriteLine("Fornavn mangler.");
    return;
}

if (string.IsNullOrWhiteSpace(lastName))
{
    Console.WriteLine("Efternavn mangler.");
    return;
}

if (string.IsNullOrWhiteSpace(email))
{
    Console.WriteLine("Email mangler.");
    return;
}

DRY:

// gf2-setup: string firstName = "Ada";
// gf2-setup: string lastName = "Lovelace";
// gf2-setup: string email = "[email protected]";

if (!RequireText(firstName, "Fornavn")) return;
if (!RequireText(lastName, "Efternavn")) return;
if (!RequireText(email, "Email")) return;

Console.WriteLine("Alle felter er udfyldt.");

static bool RequireText(string value, string fieldLabel)
{
    if (string.IsNullOrWhiteSpace(value))
    {
        Console.WriteLine($"{fieldLabel} mangler.");
        return false;
    }

    return true;
}

Eksempel 7 — Formatér output ens

Gentaget:

Console.WriteLine($"Pris: {price:F2} kr.");
Console.WriteLine($"Rabat: {discount:F2} kr.");
Console.WriteLine($"Total: {total:F2} kr.");

DRY:

Eksempel 8 — Switch med duplikeret kode i cases

Gentaget:

switch (choice)
{
    case "1":
        Console.WriteLine("Starter spil...");
        Console.WriteLine("Indlæser data...");
        StartGame();
        break;
    case "2":
        Console.WriteLine("Starter øvelse...");
        Console.WriteLine("Indlæser data...");
        StartPractice();
        break;
}

DRY:

Eksempel 9 — Array + manuel gentagelse

Gentaget:

int sum = numbers[0] + numbers[1] + numbers[2] + numbers[3] + numbers[4];
double avg = sum / 5.0;
Console.WriteLine($"Sum: {sum}, Avg: {avg:F1}");

Hvis arrayet vokser, kopierer folk ofte mønsteret igen.

DRY:

Eksempel 10 — Konstanter frem for "magic numbers"

Gentaget:

if (attempts > 3) { /* ... */ }
// ...
if (attempts > 3) { /* ... */ }
// ...
maxAttempts = 3;

DRY:

Konstanten er ét navngivet sted for tallet 3.

DRY vs. KISS — hvornår venter du?

Situation Gør
Koden er gentaget 2+ gange med samme regel Overvej metode
Du har kun set mønsteret én gang Vent — lad være med at abstrahere for tidligt
Abstraktionen kræver 8 parametre Forenkl først (KISS)
Metodenavnet er uklart (DoThing) DRY hjælper ikke — navngiv bedre

Rule of Three (tommelfingerregel): Først når noget gentager sig tre gange, er det ofte værd at samle det. To gange kan du leve med — især i små øvelsesprogrammer.

Refaktorering trin for trin

  1. Find to blokke der gør det samme (eller næsten)
  2. Uddrag til en metode med et beskrivende navn
  3. Erstat kopierne med metodekald
  4. Kør programmet — adfærden skal være uændret
  5. Formater med Ctrl+Shift+F i GF2 Learn

Hurtig tjekliste

  • Er samme regel skrevet mere end ét sted?
  • Har jeg magic numbers der burde være const?
  • Kan jeg samle gentagen logik i en metode med et klart navn?
  • Er min abstraktion enklere end kopierne — ikke sværere?

Test din viden

Spørgsmål 1

Hvad betyder DRY?

Spørgsmål 2

Hvilket er et tydeligt DRY-brud?

Spørgsmål 3

Hvad er den bedste DRY-løsning til gentagen "=== Rapport ===" udskrift?

Spørgsmål 4

Hvad er Rule of Three?

Spørgsmål 5

Hvordan arbejder DRY og KISS sammen?

Spørgsmål 6

Hvorfor er const int PassingScore = 60; et DRY-trick?