13. Qualität im Team
Qualität im Team
Abschnitt betitelt „Qualität im Team“Das Abschlussprojekt dieses Jahres wird in Teams gebaut, und Teamarbeit ändert die Spielregeln: Code, den nur seine Autor:in versteht, ist eine Hypothek; ein Fehler auf dem Hauptbranch blockiert alle; ungetestete Änderungen brechen fremde Arbeit. Dieses Kapitel richtet die drei Schutzmechanismen ein, mit denen professionelle Teams arbeiten: einen verbindlichen Branch-Workflow mit Merge Requests, Code-Reviews mit belastbaren Regeln und automatisierte Tests, die bei jedem Push laufen. Eine Woche Theorie, danach sind sie Projektalltag.
Der Branch-Workflow, jetzt verbindlich
Abschnitt betitelt „Der Branch-Workflow, jetzt verbindlich“Die Git-Grundlagen (Commits, Branches, Merges, Remotes) werden vorausgesetzt; neu ist die Verbindlichkeit und der Weg über die Plattform. Die Regeln für das Projekt:
mainist geschützt. Niemand pusht direkt; der Branch enthält jederzeit einen lauffähigen Stand (am Schul-GitLab als Protected Branch konfiguriert, die Regel wird also erzwungen, nicht erhofft).- Jede Änderung reist per Feature-Branch:
feature/job-export,fix/delete-running-job. Kurzlebig, ein Thema, sprechender Name. - Der Weg zurück führt über einen Merge Request (MR; andere Plattformen sagen Pull Request): Der Branch wird gepusht, der MR beschreibt die Änderung (was, warum, wie getestet), mindestens ein Teammitglied reviewt, erst dann wird gemergt.
- Grüne Pipeline ist Merge-Bedingung: Die automatisierten Tests (unten) müssen durchlaufen, sonst ist der Merge-Knopf gesperrt.
Der MR ist dabei mehr als ein Genehmigungsschritt: Er ist die Einheit, in der über Code gesprochen wird, mit Kommentaren an konkreten Zeilen, nachvollziehbar für alle und dauerhaft dokumentiert.
Code-Reviews: freundlich, konkret, begründet
Abschnitt betitelt „Code-Reviews: freundlich, konkret, begründet“Reviews sind das wirksamste bekannte Mittel gegen Fehler und zugleich das Mittel, mit dem Wissen im Team wandert; beides funktioniert nur mit Kultur. Die Regeln, in beide Richtungen:
Für Reviewer: Kritisiert wird Code, nie die Person (“diese Funktion prüft den Fehlerfall nicht”, nicht “du hast vergessen”). Jede Anmerkung ist konkret (Zeile, Vorschlag) und begründet (welches Kriterium ist verletzt); “gefällt mir nicht” ist kein Befund. Fragen sind erlaubt und erwünscht (“warum reicht hier kein PATCH?”), Lob für gute Lösungen ebenso. Und: Ein Review, das nur Tippfehler findet, hat die Architektur nicht angesehen.
Für Autoren: Kleine MRs schreiben (ein reviewbarer MR hat eher 100 als 1000 geänderte Zeilen), die Beschreibung ernst nehmen, Anmerkungen nicht als Angriff lesen. Jede Anmerkung wird beantwortet: umgesetzt oder mit Begründung abgelehnt; stilles Ignorieren ist keine Option.
Die inhaltliche Review-Checkliste dieses Jahrgangs, abgeleitet aus den Kapiteln:
- Hält die Änderung den API-Vertrag (Statuscodes, Fehlerformat, dokumentierte Felder)?
- Respektiert sie die Schichten (Importe prüfen: kein HTTP im Service, kein SQL in der Komponente)?
- Wird jede Eingabe an der Grenze validiert; laufen Mutationen gegen Doppelauslösung geschützt?
- Sind asynchrone Abläufe korrekt (kein vergessenes
await, kein unnötig sequentielles Laden)? - Gibt es Tests für neue Logik, und sagen die Namen, was geprüft wird?
Tests für Logik und API
Abschnitt betitelt „Tests für Logik und API“Die Mehrschichtarchitektur zahlt hier ihre Dividende: Die Geschäftslogik hängt nur am Repository-Interface und ist damit ohne Server, ohne HTTP und ohne Datenbank testbar. Als Testframework verwenden wir Vitest, den Standard im TypeScript-Umfeld; die Konzepte (Testdateien, sprechende Testnamen, Arrange-Act-Assert, erwartete Fehler) sind die üblichen jedes Testframeworks.
import { describe, expect, it } from "vitest";import { JobService, ConflictError } from "./job-service";import { MemoryJobRepository } from "@/lib/repository/memory-job-repository";
describe("JobService", () => { it("creates a job with state queued", async () => { const service = new JobService(new MemoryJobRepository()); const job = await service.createJob({ filename: "intro.mp4", preset: "web-1080p" }); expect(job.state).toBe("queued"); expect(job.id).toBeGreaterThan(0); });
it("refuses to delete a running job", async () => { const repository = new MemoryJobRepository(); const service = new JobService(repository); const job = await service.createJob({ filename: "a.mp4", preset: "web-1080p" }); await repository.update({ ...job, state: "running" });
await expect(service.deleteJob(job.id)).rejects.toThrow(ConflictError); });});npx vitest führt alle *.test.ts-Dateien aus und bleibt im Watch-Modus; npx vitest run läuft einmal durch (die Form für die Pipeline). Die zweite Testebene prüft die API von außen, als Konsument gegen den laufenden Dev-Server; das testet zusätzlich Routing, Validierung und Fehlerformat:
// tests/api.test.ts: run against `npm run dev`it("rejects a job without filename with 400 and the error format", async () => { const response = await fetch("http://localhost:3000/api/jobs", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ filename: "" }), }); expect(response.status).toBe(400); const body = await response.json(); expect(body.error.code).toBe("VALIDATION_FAILED");});Die Arbeitsteilung: Viele schnelle Service-Tests für die Regeln, wenige API-Tests für den Vertrag und das Zusammenspiel. Wer eine Regel nur über die API testen kann, hat sie vermutlich in den Handler statt in den Service gelegt; Tests sind damit auch ein Architektur-Frühwarnsystem.
CI: Tests laufen bei jedem Push
Abschnitt betitelt „CI: Tests laufen bei jedem Push“Tests, die nur manuell laufen, laufen irgendwann nicht mehr. Continuous Integration (CI) heißt: Die Plattform führt sie bei jedem Push selbst aus. Am Schul-GitLab genügt dafür eine Datei im Projektwurzelverzeichnis:
test: image: node:22 script: - npm ci # clean install from package-lock.json - npx vitest runAb jetzt zeigt jeder Push und jeder MR eine Pipeline: grün oder rot, für alle sichtbar, und als Merge-Bedingung verdrahtet. Das ist CI in einfachster Form, und mehr braucht das Projekt nicht; entscheidend ist der Kulturwechsel: Ob die Tests laufen, ist keine Erinnerungsfrage mehr, sondern Infrastruktur.
Projektorganisation: startklar
Abschnitt betitelt „Projektorganisation: startklar“Mit den Werkzeugen steht die Organisation des Abschlussprojekts; drei Festlegungen pro Team, schriftlich vor dem ersten Commit:
- Rollen: Wer verantwortet was (API, Frontend, Persistenz, Review-Koordination)? Verantwortung heißt kümmern, nicht alleine bauen.
- Board: Aufgaben als Issues am GitLab-Board (offen, in Arbeit, im Review, fertig), jede Aufgabe klein genug für einen MR.
- Definition of Done: Wann ist eine Aufgabe fertig? Referenzfassung: Code auf
maingemergt, Review beantwortet, Tests grün in der Pipeline, Vertrag/Doku aktualisiert. “Läuft bei mir” kommt in der Liste nicht vor.
Lernergebnisse: Was Sie nach diesem Kapitel können sollten
Abschnitt betitelt „Lernergebnisse: Was Sie nach diesem Kapitel können sollten“Nach Abschluss dieses Kapitels sollten Schülerinnen und Schüler in der Lage sein:
- Anwenden: im geschützten Branch-Workflow arbeiten: Feature-Branch, Merge Request mit Beschreibung, Review, Merge nach grüner Pipeline.
- Anwenden: Code-Reviews nach den Regeln geben (konkret, begründet, respektvoll) und Anmerkungen als Autor professionell beantworten.
- Anwenden: Geschäftslogik mit Vitest gegen das Memory-Repository testen und die API von außen gegen den Vertrag prüfen.
- Erklären: die Arbeitsteilung zwischen Service-Tests und API-Tests begründen und Tests als Architektur-Indikator nutzen.
- Anwenden: eine minimale CI-Pipeline einrichten, die Tests bei jedem Push ausführt.
- Entwerfen: die Projektorganisation (Rollen, Board, Definition of Done) für ein Teamprojekt festlegen.
Passende Übungen
Abschnitt betitelt „Passende Übungen“- Aufgabe 21 - Review-Runde
- Aufgabe 22 - Projekt: Client-Server-Anwendung (Start)