Del 6 av 8

Koda en Stabil Arkitekturgrund

AI lär sig av mönster du redan skapat — inte av mönster du tänkt skapa. Grunden måste kodas manuellt, deliberat och dokumenteras så att AI kan följa den.

Lektion 5 — V3 dag 1 Vi diskuterar varför arkitekturgrunden aldrig ska delegeras till AI, hur man identifierar och dokumenterar designbeslut, och hur man skapar referensimplementationer som AI kan lära sig av.

Varför grunden måste kodas manuellt

AI-modeller är tränade på existerande kod och mönster. De är utmärkta på att reproducera och varitera kända mönster, men de uppfinner inte nya arkitekturer som passar ditt specifika systems kontext. Om du låter AI bestämma arkitekturen från noll riskerar du:

Principen Kod de första 20 % manuellt — de byggstenarna som allt annat vilar på. De återstående 80 % kan AI generera snabbt och korrekt, förutsatt att den 20-procentiga grunden är solid och väldefinierad.

Vad är "grunden"?

Grunden är de strukturella beslut och basklasser som definierar hur resten av systemet ska byggas. I ett typiskt C# DDD-projekt inkluderar det:

KomponentVad det definierarVarför det måste vara manuellt
AggregateRoot<TId> Basklass för alla aggregat, domänhändelsehantering Alla aggregat ärver detta — ett fel sprider sig överallt
Result<T> / Error Felhanteringsmonad för domänoperationer Konsistent felhantering kräver ett genomtänkt kontrakt
ValueObject-basklass Equality, validering, immutabilitet Record-semantiken måste passa domänens krav
IRepository<T> Kontraktet för alla repositories Generics, async-mönster och felhantering måste vara genomtänkta
Projektstruktur / lager Var kod hör hemma och beroendesriktning Felaktig lagerstruktur sprider beroenden som är omöjliga att ta bort
Namnkonventioner Naming för kommandon, events, tjänster etc. AI genererar inkonsistent om konventionen inte är explicit

Referensimplementation — AggregateRoot i C#

En genomtänkt AggregateRoot-basklass som AI sedan kan referera till:

namespace MyApp.Domain.Common;

/// <summary>
/// Basklass för alla DDD Aggregate Roots.
/// Hanterar domänhändelser och identitet.
/// </summary>
public abstract class AggregateRoot<TId> where TId : notnull
{
    private readonly List<IDomainEvent> _domainEvents = [];

    public TId Id { get; protected init; } = default!;

    public IReadOnlyList<IDomainEvent> DomainEvents => _domainEvents.AsReadOnly();

    protected void AddDomainEvent(IDomainEvent domainEvent)
        => _domainEvents.Add(domainEvent);

    public void ClearDomainEvents()
        => _domainEvents.Clear();
}

/// <summary>
/// Markörinterface för alla domänhändelser.
/// Implementeras som records för immutabilitet.
/// </summary>
public interface IDomainEvent { }

/// <summary>
/// Railway-oriented felhantering för domänoperationer.
/// Kasta aldrig exceptions från domänmetoder — returnera Result.
/// </summary>
public sealed class Result<T>
{
    public T? Value { get; }
    public DomainError? Error { get; }
    public bool IsSuccess => Error is null;

    private Result(T value) => Value = value;
    private Result(DomainError error) => Error = error;

    public static Result<T> Success(T value) => new(value);
    public static Result<T> Failure(DomainError error) => new(error);

    public Result<TOut> Map<TOut>(Func<T, TOut> mapper) =>
        IsSuccess ? Result<TOut>.Success(mapper(Value!)) : Result<TOut>.Failure(Error!);
}

public sealed record DomainError(string Code, string Message);
Designbeslut som syns i koden ovan Dessa beslut måste dokumenteras och översättas till instruktionsfiler. Utan dokumentation kommer AI att ta egna beslut i de gråzoner koden skapar.

ADR — Architecture Decision Records

Architecture Decision Records (ADR) är korta dokument som fångar ett arkitekturellt beslut: vad som beslutades, varför och vilka alternativ övervägdes. De är källmaterialet för dina instruktionsfiler.

# Mappstruktur för ADR:er
docs/
└── decisions/
    ├── ADR-001-aggregate-root-pattern.md
    ├── ADR-002-result-type-error-handling.md
    ├── ADR-003-repository-interface.md
    └── ADR-004-event-sourcing-vs-crud.md
# ADR-002-result-type-error-handling.md

# ADR-002: Result<T> för felhantering i domänlagret

## Status
Accepterad

## Kontext
Domänmetoder kan misslyckas av affärsmässiga skäl (t.ex. ogiltig email-adress,
otillräckligt saldo). Vi behöver ett konsistent sätt att kommunicera dessa fel
till application-lagret utan att använda exceptions.

## Beslut
Alla public domänmetoder returnerar Result<T> vid fel. Exceptions kastas
aldrig från domänlagret. DomainError innehåller en string-kod och ett meddelande.

## Alternativ som övervägdes
- Exceptions (DomainException) — avvisat pga. exceptions är dyra och flödesstyrning via exceptions är svår att följa
- OneOf<T, Error> — avvisat pga. extern dependency och mer komplex syntax
- Tuples (T value, string? error) — avvisat pga. saknad semantik och svag typning

## Konsekvenser
- Application-lagret måste alltid hantera Result — kan inte ignorera fel
- Testning förenklas — inga exceptions att fånga i tester
- Lärningskurva för nya teammedlemmar som inte känner mönstret

Checklista — Vad ska vara stabilt innan AI tar vid?

Klar att delegera till AI när du kan bocka av allt:
  1. Minst ett färdigt aggregat som referensimplementation (t.ex. Order)
  2. Minst ett färdigt Value Object som referens (t.ex. EmailAddress)
  3. Minst ett färdigt Repository-interface och implementation
  4. Testsvit för referensimplementationen (minst 10 tester)
  5. ADR:er skrivna för de tre viktigaste designbesluten
  6. copilot-instructions.md skapad med minst sex regler
  7. Minst en .instructions.md-fil med applyTo
  8. Projektet kompilerar utan varningar

Från kod till instruktionsfil — promptmall

När grunden är kodad kan du be Copilot extrahera reglerna automatiskt:

# Prompt för att generera instruktionsfil från referensimplementation:

Du är en senior C#-arkitekt. Analysera filerna:
#file:src/Domain/Common/AggregateRoot.cs
#file:src/Domain/Common/Result.cs
#file:src/Domain/Orders/Order.cs
#file:src/Domain/Orders/OrderItem.cs
#file:tests/Domain/OrderTests.cs

Generera en .instructions.md-fil med applyTo: "src/Domain/**/*.cs".

Filen ska extrahera EXAKTA regler från koden — inte generella DDD-regler.
Täck: strukturmönster, namnkonventioner, felhanteringskontrakt, händelsehantering,
Value Object-mönster och testmönster som framgår av filerna.

Skriv reglerna som imperativa meningar ("Returnera alltid Result<T>...").
Max 40 regler. Gruppera under tydliga rubriker.

Referenser

Elektroniska resurser

Böcker

Övningar

Lös övningarna självständigt. Det finns inget facit — lärandet sker i processen.

  1. Identifiera grundkomponenterna i ett befintligt projekt
    Välj ett C#-projekt du känner väl. Analysera det och identifiera: vilka klasser/mönster är "grunden" som allt annat vilar på? Finns det explicita basklasser, eller är grundmönstren implicita? Vad skulle behöva vara mer explicit för att AI ska kunna följa mönstren?
  2. Skriv ett ADR för ett verkligt beslut
    Välj ett tekniskt beslut du gjort (eller som gjordes på ditt nuvarande/senaste projekt). Skriv ett ADR enligt mallen ovan. Inkludera minst tre alternativ som övervägdes och motivera varför de avvisades. ADR:et ska vara läsbart för en ny teammedlem utan bakgrundskunskap.
  3. Bygg referensimplementationen
    Skapa ett nytt .NET 9-projekt och implementera grunden manuellt: AggregateRoot<TId>, Result<T>, ett konkret aggregat (valfritt domän), och ett repository-interface. Skriv minst 8 tester. Allt ska kompilera och tester ska vara gröna. Denna grund används i del 07.

Soloprojektor

Projekt 1 — Komplett arkitekturgrund med ADR-svit Bygg en fullständig C# .NET 9 projekt-grund med Clean Architecture-struktur. Inkludera: basklasser, Result-typ, minst ett aggregat, ett repository-interface, 10+ tester, och en ADR-mapp med minst tre beslutsdokument. Projektet ska kunna fungera som referensimplementation för hela kursen framöver.
Projekt 2 — Research: Nytt .NET 9-mönster (fördjupning) Välj ett .NET 9-specifikt mönster eller bibliotek du inte jobbat med (t.ex. Keyed Services, TimeProvider, HybridCache). Gör en komplett research-session med Claude Sonnet 4.6 (extended thinking, high): förstå konceptet, implementera ett minimalt exempel i din projektgrund och skriv ett ADR som dokumenterar beslutet att använda eller inte använda det.

← Föregående: Copilot Skills Nästa: AI-genererade Instruktionsfiler →