Team Self-Assessment: Frontend-Reaktivitäts- und Architekturcheck
Ziel
Diese Checkliste identifiziert typische Frontend-Probleme (Paradigmen-Mismatch, imperatives Angular, State-Spiegelung, Vererbungs-Hierarchien) und macht sie messbar.
Dauer: 30–60 Minuten
Teilnehmer: 2–6 Devs (optional: Tech Lead/Architect)
Output: Score + Top-5 Maßnahmenliste
Scoring
Jede Aussage wird bewertet mit:
- 0 = Nein / trifft nicht zu
- 1 = teilweise / inkonsistent
- 2 = Ja / konsequent umgesetzt
Zusätzlich gibt es pro Abschnitt Red Flags (sofortige Maßnahmen, unabhängig vom Score).
Abschnitt A – Datenfluss & State
A1: Single Source of Truth
- (0/1/2) Pro Feature gibt es eine klare Quelle für State (Signal/Store/Stream).
- (0/1/2) Es gibt keine Doppelhaltung (z.B.
users$undusers: User[]). - (0/1/2) UI-State wird nicht implizit in Services mutiert (z.B.
service.currentUser = ...).
Beobachtbarer Hinweis:
Wenn man fragt „wo kommt der Wert her?“, gibt es eine Antwort.
Typisches Gegenbeispiel:
„Das kommt aus dem Service, aber die Komponente cached es nochmal…“
A2: Ableitung statt Mutation
- (0/1/2) Ableitungen werden explizit modelliert (
computed,map,vm), nicht implizit in Methoden oder Templates. - (0/1/2) Collections werden überwiegend immutabel behandelt (
[...],map,filterstattpush/splice). - (0/1/2) DTOs werden beim Mapping nicht mutiert (kein „DTO als Domain Model“).
Red Flag:
users.push(...), dto.foo = ..., Object.assign(existing, ...) im UI-State.
A3: ViewModel-Disziplin
- (0/1/2) Templates hängen primär am VM (
vm,vm$,computed vm). - (0/1/2) Das Template enthält keine komplexen Berechnungen.
- (0/1/2) API/DTO-Strukturen werden nicht direkt im Template verwendet.
Definition (normativ):
Das Template kennt das VM – nicht die Datenquellen.
Abschnitt B – Subscriptions, Async, Lifecycle
B1: Subscription Hygiene
- (0/1/2) Komponenten enthalten keine
subscribe()außer für echte Side-Effects. - (0/1/2) Unsubscribe wird nicht manuell gehandhabt (kein
destroy$, keinSubscription-Feld). - (0/1/2) Promise-Konvertierung (
firstValueFrom,toPromise) ist selten und begründet.
Red Flags:
- Mehr als 3
subscribe()in einer Komponente. destroy$als Standardpattern in jeder Komponente.- Observable → Promise → imperatives Feld.
B2: Lifecycle Disziplin
- (0/1/2)
ngOnInit()enthält keine Orchestrierungskaskaden (load/setup/register). - (0/1/2)
ngOnDestroy()enthält keine fachliche Logik. - (0/1/2) Keine Vererbungsabhängigkeit in Lifecycle Hooks (
super.ngOnInit()etc.).
Heuristik:
ngOnInit sollte „langweilig“ sein.
Abschnitt C – Struktur, Kopplung, Wiederverwendung
C1: Keine God Base Component
- (0/1/2) Es gibt keine Basisklasse, die viele Komponenten erben.
- (0/1/2) Cross-Cutting Concerns werden nicht per
extendsgeteilt. - (0/1/2) Wiederverwendung erfolgt über Komposition (DI, utilities, operators).
Red Flag:
Eine Basisklasse enthält: loading, error, permissions, routing helpers, subscriptions…
C2: Services sind nicht „Global State“
- (0/1/2) Services enthalten keine öffentlichen mutable Felder als State.
- (0/1/2) Services sind klar klassifiziert: API-Adapter, Facade, Store, Utility.
- (0/1/2) Datenflüsse sind sichtbar, nicht durch Side Effects versteckt.
C3: Validierung & Form-Architektur
- (0/1/2) Validierung ist deklarativ (Validators / schema / derived state), nicht „if-Kaskaden“.
- (0/1/2) Validierungsregeln sind testbar und wiederverwendbar.
- (0/1/2) Form-Status wird abgeleitet statt manuell gesetzt.
Red Flag:
if (!form.valid) { set error; return; } als primäres Validierungsmodell.
Abschnitt D – Nebenwirkungen & Fehlerbehandlung
D1: Side-Effects sind isoliert
- (0/1/2) Side Effects sind klar lokalisiert (effect / tap / handler).
- (0/1/2) Kein Side-Effect in
map/computed. - (0/1/2) Navigation/Toasts/Logging passieren nicht „zufällig“ in Mappingketten.
D2: Fehlerbehandlung ist systemisch
- (0/1/2) HTTP-Fehlerbehandlung erfolgt konsistent (Interceptor/Fassade/VM).
- (0/1/2) UI behandelt Fehlerzustände als State (
errorState), nicht alstry/catchOrchestrierung. - (0/1/2) Loading/Error/Empty sind als States modelliert.
Abschnitt E – Teampraktiken
E1: Code Review Leitplanken
- (0/1/2)
subscribe()in Komponenten ist ein Review-Trigger. - (0/1/2) Vererbung in UI ist ein Review-Trigger.
- (0/1/2) Doppelter State ist ein Review-Trigger.
- (0/1/2) Team hat ein gemeinsames Zielbild (RxJS-first, Signals-first oder Hybrid).
Ergebnisinterpretation
0–20 Punkte: Imperativ dominiert
- Hohe Lifecycle-Kopplung
- Viele Spiegelzustände
- Manuelles Ressourcenmanagement
Empfehlung:
Stabilisieren durch 3 Regeln:
- kein subscribe() außer Side-Effects
- VM/Computed einführen
- keine UI-Vererbung
21–35 Punkte: Hybrid & inkonsistent
- Reaktivität vorhanden
- aber inkonsistent
- hohe kognitive Last
Empfehlung:
Team-Konventionen + Refactoring-Routen definieren.
36–50 Punkte: Reaktiv & deklarativ
- Klarer Datenfluss
- geringere Kopplung
- gute Testbarkeit
Empfehlung:
Signals/VM konsequent standardisieren, Metriken einführen.
50+ Punkte: High Maturity
- Signal/VM-Ableitungen dominieren
- Side-Effects isoliert
- geringe architektonische Reibung
Empfehlung:
Guardrails automatisieren (Lint/PR templates), Wissen multiplizieren.
Sofortmaßnahmen (Top 5)
Unabhängig vom Score:
- Subscribe in Komponenten verbieten (außer Side-Effects).
- Doppelten State eliminieren (eine Quelle).
- VM-Pattern standardisieren (vm / vm$ / computed vm).
- UI-Vererbung verbieten (Komposition statt BaseComponent).
- Side-Effects isolieren (effect/tap/handler, nicht in map/computed).
Optional: Quick Audit (15 Minuten)
Zählt in einem Feature-Ordner:
- Anzahl
subscribe( - Anzahl
firstValueFrom(/toPromise( - Anzahl
extends Base - Anzahl mutable service fields (
public foo: ...) - Anzahl
.push(/.splice(
Wenn ihr hier hohe Werte habt, seid ihr sehr wahrscheinlich in Stufe 0–2.