Code

Grenzen gehören in den Build

Seit der Ausbildung 2015 schreibe ich C# und .NET, von WebForms bis zu containerisierten Services auf Azure. Heute schreibe ich weniger Code als früher. Ich bleibe aber in Reviews, in den Templates und in den Tests, die Architektur durchsetzen.

Fundament

Architektur, die der Build prüft

Eine Modulgrenze, die nur im Review existiert, existiert nicht. Deshalb steht sie als Test in der Pipeline. Greift ein Modul an seinem Contract vorbei, wird der Build rot, bevor das Review anfängt.

tests/Architektur.Tests/ModulgrenzenTests.cs
// Eine Modulgrenze, die nur im Review existiert, existiert nicht.
[Fact]
public void Abrechnung_kennt_Kurse_nur_ueber_Contracts()
{
    var ergebnis = Types.InAssembly(typeof(AbrechnungModul).Assembly)
        .That().ResideInNamespace("Abrechnung")
        .ShouldNot().HaveDependencyOn("Kurse.Domain")
        .GetResult();

    Assert.True(ergebnis.IsSuccessful);
}
$ dotnet test --filter Abrechnung_kennt_Kurse_nur_ueber_Contracts
Bestanden!  Fehler: 0, erfolgreich: 1, übersprungen: 0, gesamt: 1

Ein Beispiel mit NetArchTest, die Modulnamen sind ausgedacht. So sehen die Tests aus, mit denen bei uns Modulgrenzen im Build stehen statt im Review.

Stack

Womit ich arbeite

Werkzeuge, die ich lange genug benutze, um sie begründen zu können. Die Liste ist kurz, weil ich selten wechsle.

Sprache und Laufzeit

3
.NET 10 LTS

LTS. Neue Projekte starten hier, bestehende ziehen mit, sobald das Support-Ende in Sicht ist.

C# 13 TÄGLICH

Records und Pattern Matching haben die Hälfte meiner Guard-Klauseln ersetzt.

PowerShell 7 GLUE

Skripte, die unter Windows, macOS und im Linux-Container gleich laufen.

Editor und Terminal

3
JetBrains Rider IDE

Refactorings über eine Solution mit 60 Projekten, ohne dass die IDE stehen bleibt.

Windows Terminal SHELL

Vier Profile in einem Fenster: Build, Logs, Git, Notizen.

GitLab REPOS

Privat mein Zuhause für Repos, Issues und Merge Requests. Beruflich auf dem Weg nach draußen.

Bibliotheken

3
EF Core DATENZUGRIFF

Migrationen liegen im Repo und laufen im Deploy. LINQ so lange, bis das Profiling widerspricht.

xUnit TESTS

Ein Test pro Regel, benannt nach der Regel. Der Testname ist die Dokumentation.

NBomber LAST

Lastszenarien als C#-Code neben den fachlichen Tests, nicht in einem separaten Werkzeug.

Daten und Nachrichten

3
PostgreSQL PRIMÄR

Wenn ich wählen darf. Transaktionen, JSONB und ein Backup, das ich selbst zurückspiele.

SQL Server BESTAND

Wenn der Kunde schon dort ist. Kein Grund, eine Migration zu erfinden.

Azure Service Bus MESSAGING

Jede Nachricht trägt einen Idempotency-Key; Duplikate sind der Normalfall, nicht die Ausnahme.

Betrieb

3
Azure HOSTING

App Service und Container Apps. Infrastruktur als Code erst dort, wo sie sich wiederholt.

GitLab CI CI

Dieselbe .gitlab-ci.yml lokal wie in der Pipeline. Ein Build, der nur auf dem Server läuft, ist keiner. Privat.

OpenTelemetry TELEMETRIE

Eine Korrelations-ID vom Request bis in den Consumer. Traces vor Dashboards.

Schreiben

3
Markdown im Repo DOKUMENTATION

Entscheidungen und Specs liegen neben dem Code. Was woanders liegt, veraltet.

dotnet adr ENTSCHEIDUNGEN

Globales Tool für Architecture Decision Records. adr new schreibt die Entscheidung als Markdown nach docs/adr, MADR-Vorlage.

Mermaid DIAGRAMME

Diagramme als Text im Repo, versioniert wie alles andere.

Bewusst nicht dabei

Microservices als Startpunkt

Ein modularer Monolith lässt sich teilen, sobald die Grenze steht. Andersherum wird es teuer.

Ein zweites ORM neben EF Core

Zwei Wege in dieselbe Tabelle sind ein Weg zu viel.

Generatoren, deren Ausgabe ich nicht lese

Code, den niemand im Team erklären kann, ist eine Abhängigkeit ohne Vertrag.

Stand September 2026. Was ich austausche und warum, steht im Blog.

Gerade

KI-gestützte Entwicklung im Team

Das Thema, bei dem ich am meisten lerne und am wenigsten festgelegt bin. Im Team läuft KI-gestütztes Coding über JetBrains AI und eigene Gateways für Modelle aus Azure AI Foundry und IONOS – inklusive Testgenerierung und Wissensaufbau.

Ich sammle Prompt-Muster für Refactorings über Modulgrenzen hinweg und notiere ehrlich, wo ich danach mehr Zeit gebraucht habe als ohne. In einer großen Solution entscheiden Kontextgrenzen und Konventionen darüber, ob am Ende Zeit gespart wird.

Offene Fragen

Wo ist die Grenze zwischen Assistenz und Verantwortung?

Was gehört in eine Konvention, damit ein Agent sie einhalten kann?

Blog

Dazu geschrieben