# ADR-004: Ruff als Code-Formatter und Linter

**Status**: Accepted
**Datum**: 2025-11-17
**Entscheider**: Development Team
**Kontext**: Code-Qualität und Dokumentations-Formatierung

## Kontext und Problem

Beim Build der MkDocs-Dokumentation (`poetry run mkdocs build`) erscheint die Warnung:

```
mkdocstrings_handlers: Formatting signatures requires either Black or Ruff to be installed.
```

### Problem

mkdocstrings kann ohne installierten Code-Formatter keine komplexen Funktionssignaturen in der generierten API-Dokumentation optimal formatieren.

**Beispiel - Ohne Formatter:**
```python
def complex_function(param1: str, param2: int, param3: list[dict[str, Any]], param4: Optional[SomeType] = None) -> tuple[str, int]:
```

**Mit Formatter:**
```python
def complex_function(
    param1: str,
    param2: int,
    param3: list[dict[str, Any]],
    param4: Optional[SomeType] = None,
) -> tuple[str, int]:
```

### Anforderungen

1. **Dokumentations-Qualität:** Lesbare Signaturen in der generierten API-Dokumentation
2. **Code-Konsistenz:** Einheitlicher Code-Stil im gesamten Projekt
3. **Performance:** Schnelle Ausführung in CI/CD-Pipeline
4. **Wartbarkeit:** Aktiv gepflegtes Tool mit gutem Ökosystem
5. **Integration:** Einfache Integration in bestehenden Workflow (Poetry, Pre-Commit)

## Betrachtete Optionen

1. **Ruff** - Moderner All-in-One Formatter und Linter (Rust-basiert)
2. **Black** - Etablierter Code-Formatter ("The Uncompromising Code Formatter")
3. **Kein Formatter** - Status Quo beibehalten

---

## Option 1: Ruff (GEWÄHLT)

### Beschreibung

Ruff ist ein moderner, Rust-basierter Code-Formatter und Linter, der mehrere Python-Tools ersetzt (Black, isort, flake8, pylint-Teile).

### Implementierung

```toml
# pyproject.toml
[tool.poetry.group.dev.dependencies]
ruff = "^0.8.0"

[tool.ruff]
line-length = 88  # Black-kompatibel
target-version = "py310"

[tool.ruff.lint]
select = ["E", "F", "I"]  # pycodestyle, pyflakes, isort
ignore = []

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
```

### PRO

- **Geschwindigkeit:** 10-100× schneller als Black
- **Funktionsumfang:** Formatter + Linter in einem Tool
- **Ersetzt mehrere Tools:**
  - Black (Formatting)
  - isort (Import-Sortierung)
  - flake8 (Code-Linting)
  - Teile von pylint
- **Aktiv maintained:** Moderner Standard 2024/2025
- **Große Adoption:** Wird von vielen Open-Source-Projekten genutzt
- **Exzellente IDE-Integration:** VS Code, PyCharm, etc.
- **Black-kompatibel:** Kann Black 1:1 ersetzen ohne Codeänderungen

### CONTRA

- **Jüngeres Tool:** Weniger etabliert als Black (aber bereits sehr stabil)
- **Breaking Changes möglich:** Vor 1.0.0 (aktuell 0.x)

### Verwendungsbeispiel

```bash
# Formatierung
ruff format .

# Linting
ruff check .

# Auto-Fix
ruff check --fix .

# In CI/CD
ruff format --check .  # Exit-Code != 0 bei Formatierungsabweichungen
```

---

## Option 2: Black

### Beschreibung

Black ist der etablierte Python-Formatter mit "uncompromising" Philosophie (minimale Konfiguration).

### Implementierung

```toml
[tool.poetry.group.dev.dependencies]
black = "^24.0.0"

[tool.black]
line-length = 88
target-version = ['py310']
```

### PRO

- **Sehr etabliert:** Seit 2018, breite Akzeptanz
- **Stabile API:** Wenige Breaking Changes
- **Klare Philosophie:** "One way to format"
- **Gut dokumentiert:** Viele Ressourcen und Beispiele

### CONTRA

- **Nur Formatting:** Benötigt zusätzliche Tools (isort, flake8)
- **Langsamer:** Besonders bei großen Codebases
- **Eingeschränkter Funktionsumfang:** Keine Linting-Features

---

## Option 3: Kein Formatter

### Beschreibung

Status Quo beibehalten, manuelle Code-Reviews für Konsistenz.

### PRO

- **Kein Setup-Aufwand:** Keine neue Dependency
- **Flexibilität:** Individuelle Formatierungs-Präferenzen

### CONTRA

- **Inkonsistenter Code-Stil:** Abhängig von individuellen Entwicklern
- **Schlechtere Dokumentation:** Lange Signaturen unlesbar
- **Höherer Review-Aufwand:** Formatierungs-Diskussionen in PRs
- **Kein technischer Mehrwert:** Warnung bleibt bestehen

---

## Entscheidung

**Option 1: Ruff**

### Begründung

1. **Beste Performance:** 10-100× schneller als Black → schnellere CI/CD
2. **Konsolidierung:** Ersetzt mehrere Tools → weniger Dependencies
3. **Zukunftssicher:** Aktiv entwickelt, moderner Standard 2025
4. **Löst ursprüngliches Problem:** mkdocstrings kann Signaturen formatieren
5. **Zusätzlicher Nutzen:** Linting + Auto-Fixes für Code-Qualität

### Implementierungsdetails

#### Installation

```bash
poetry add --group dev ruff
```

#### Konfiguration

```toml
# pyproject.toml
[tool.ruff]
line-length = 88
target-version = "py310"

[tool.ruff.lint]
select = [
    "E",   # pycodestyle errors
    "F",   # pyflakes
    "I",   # isort
    "N",   # pep8-naming
    "UP",  # pyupgrade
]
ignore = []

[tool.ruff.format]
quote-style = "double"
indent-style = "space"
docstring-code-format = true  # Formatiert Code in Docstrings
```

#### Pre-Commit Hook

```yaml
# .pre-commit-config.yaml
repos:
  - repo: https://github.com/astral-sh/ruff-pre-commit
    rev: v0.8.0
    hooks:
      - id: ruff
        args: [--fix]
      - id: ruff-format
```

#### CI/CD Integration

```yaml
# .github/workflows/ci.yml (Beispiel)
- name: Run Ruff
  run: |
    poetry run ruff check .
    poetry run ruff format --check .
```

## Konsequenzen

### Positiv

- **Bessere Dokumentation:** Formatierte Signaturen in MkDocs
- **Konsistenter Code-Stil:** Automatische Formatierung
- **Schnellere CI/CD:** 10-100× schneller als Black
- **Weniger Dependencies:** Ersetzt Black + isort + flake8
- **Bessere Code-Qualität:** Linting-Regeln fangen Fehler früh ab
- **IDE-Integration:** Auto-Format on Save möglich

### Negativ

- **Initiale Änderungen:** Kompletter Codebase-Reformat nötig
- **Breaking Changes möglich:** Ruff ist noch Pre-1.0 (0.x)
- **Lernkurve:** Neue Linting-Regeln müssen verstanden werden

### Neutral

- **Git-History:** Initial-Commit mit Formatierung sollte separat erfolgen
- **Team-Alignment:** Entwickler müssen Ruff in IDE konfigurieren
- **Dokumentation:** `CONTRIBUTING.md` sollte Ruff-Usage erklären

## Risiken und Mitigations

| Risiko | Wahrscheinlichkeit | Impact | Mitigation |
|--------|-------------------|--------|------------|
| Breaking Changes in Ruff Pre-1.0 | Mittel | Niedrig | Version-Pinning in pyproject.toml (`ruff = "^0.8.0"`) |
| Merge-Konflikte durch Reformat | Hoch (initial) | Mittel | Separater Format-Commit, Team-Kommunikation |
| Performance-Probleme in CI | Sehr niedrig | Niedrig | Ruff ist schneller als Black |
| Inkonsistenz mit bestehendem Code | Hoch (initial) | Niedrig | Ganzer Codebase-Reformat in einem Schritt |

## Alternativen

Falls sich Ruff als problematisch erweist:

1. **Fallback:** Option 2 (Black) - sehr etabliert, aber langsamer
2. **Hybrid:** Ruff nur für Dokumentation, Black für Code (nicht empfohlen)

## Migration

### Schritt 1: Installation

```bash
poetry add --group dev ruff
```

### Schritt 2: Konfiguration

Konfiguration in [pyproject.toml](../pyproject.toml) hinzufügen (siehe oben).

### Schritt 3: Initial Format

```bash
# Gesamten Codebase formatieren
ruff format .

# Linting-Fehler anzeigen
ruff check .

# Auto-fixable Fehler beheben
ruff check --fix .
```

### Schritt 4: Commit

```bash
git add -A
git commit -m "chore: initial Ruff format

- Add Ruff as dev dependency
- Configure formatting and linting rules
- Format entire codebase with Ruff

Resolves mkdocstrings warning about missing formatter."
```

### Schritt 5: Pre-Commit Hook (optional)

```bash
poetry add --group dev pre-commit
pre-commit install
```

## Verweise

- [Ruff Documentation](https://docs.astral.sh/ruff/)
- [mkdocstrings Python Handler](https://mkdocstrings.github.io/python/)
- [pyproject.toml](../pyproject.toml): Dependency-Konfiguration
- [PEP 8](https://peps.python.org/pep-0008/): Python Style Guide

## Offene Fragen

1. Sollen bestehende Linting-Tools (falls vorhanden) entfernt werden? → Ja, Ruff ersetzt sie
2. Soll Pre-Commit Hook mandatory sein? → Empfohlen, aber optional
3. Welche Linting-Regeln sollen aktiviert werden? → Start konservativ (E, F, I), später erweitern
