Zum Hauptinhalt springen

Warum Vererbung im UI toxisch werden kann

Einordnung

Vererbung ist ein zentrales Konzept der objektorientierten Programmierung.
Sie dient der Strukturierung von Verhalten und der Wiederverwendung von Code.

Im UI-Kontext – insbesondere in Angular – führt sie jedoch häufig zu strukturellen Architekturproblemen.

Dieses Dokument analysiert warum.


1. Was Vererbung eigentlich bedeutet

Vererbung modelliert eine „is-a“-Beziehung.

class Animal {}
class Dog extends Animal {}

Ein Hund ist ein Tier.

Vererbung eignet sich daher für:

  • stabile Taxonomien
  • echte Spezialisierung
  • Polymorphie im Domänenmodell

2. Was UI-Komponenten sind (und nicht sind)

Eine Angular-Komponente ist:

  • eine Projektion von State
  • ein Rendering-Knoten
  • ein Adapter zwischen Datenfluss und View

Sie ist keine Domänenentität.

Sie ist kein Objekt mit Identität im fachlichen Sinn.

Sie ist eine Ableitung.


3. Das typische Muster

class DestroyableComponent {
protected destroy$ = new Subject<void>();

ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}

class UserComponent extends DestroyableComponent {}

Begründung:

„Wir wollen Unsubscribe zentral lösen.“

Das klingt harmlos.

Ist es aber nicht.


4. Das strukturelle Problem

4.1 Keine echte „is-a“-Beziehung

Eine UserComponent ist keine DestroyableComponent.

Sie hat Lifecycle.
Sie ist nicht Lifecycle.

Hier wird Vererbung für ein Querschnittsproblem missbraucht.


4.2 Vererbung koppelt stärker als beabsichtigt

Mit extends wird gekoppelt:

  • Lifecycle-Implementierung
  • interne Felder
  • Hook-Reihenfolge
  • implizite Seiteneffekte
  • zukünftige Erweiterungen der Basisklasse

Diese Kopplung ist:

  • global
  • implizit
  • schwer sichtbar

4.3 Basisklassen wachsen

Vererbung erzeugt natürliche Akkumulation:

Erst:

  • destroy$

Dann:

  • loading$
  • error handling
  • logging
  • permission checks
  • routing helpers
  • feature flags

Die Basisklasse wird zur Infrastruktur-Gottklasse.

Alle Komponenten hängen daran.


5. Warum das im UI besonders gefährlich ist

Frontend-Systeme sind:

  • lifecycle-sensitiv
  • zustandsabhängig
  • reaktiv
  • nebenläufig

Vererbte Lifecycle-Logik erzeugt:

  • versteckte Kontrollflüsse
  • implizite Hooks
  • schwer nachvollziehbare Ausführungsketten

Debugging wird schwieriger, weil Verhalten nicht lokal sichtbar ist.


6. Vererbung und reaktive Architektur widersprechen sich

Reaktive Systeme basieren auf:

  • Komposition von Datenflüssen
  • Transformation
  • Ableitung

Vererbung hingegen basiert auf:

  • Hierarchie
  • Identität
  • impliziter Strukturweitergabe

Das sind unterschiedliche Denkmodelle.

Reaktivität ist flach und kompositorisch.
Vererbung ist hierarchisch und strukturell.


7. Versteckte Seiteneffekte

Ein häufiger Effekt:

ngOnDestroy() {
super.ngOnDestroy();
}

Oder schlimmer:

Super-Implementierungen werden vergessen.

Oder Hooks werden überschrieben.

Das erzeugt fragile Lifecycle-Ketten.


8. Testbarkeit leidet

Eine Komponente mit Vererbung:

  • ist nicht isoliert testbar
  • hat implizites Verhalten
  • benötigt Knowledge über Basisklasse

Mocks werden komplexer.

Tests werden indirekter.


9. Verletzung des Single Responsibility Principle

Komponente sollte:

UI-Projektion kapseln.

Durch Vererbung übernimmt sie zusätzlich:

  • Infrastruktur
  • Lifecycle-Management
  • Fehlerbehandlung
  • Nebenlogik

Verantwortlichkeiten vermischen sich.


10. Die eigentliche Ursache

Das Vererbungsproblem entsteht oft aus einem anderen Anti-Pattern:

.subscribe()

Manuelles Subscription-Management erzeugt Bedarf nach:

  • destroy$
  • Unsubscribe-Handling
  • Lifecycle-Hooks

Würde man:

  • async pipe
  • takeUntilDestroyed()
  • Signals
  • deklarative Streams

verwenden, wäre keine Basisklasse nötig.

Vererbung ist hier Symptom, nicht Ursache.


11. Architekturprinzip: Composition over Inheritance

Statt:

extends BaseComponent

besser:

  • Utility-Funktionen
  • RxJS-Operatoren
  • Angular Built-ins
  • Dependency Injection
  • Signal-basierte Ableitung

Komposition ist:

  • lokal
  • explizit
  • testbar
  • sichtbar

Vererbung ist:

  • global
  • implizit
  • wachsend
  • schwer entfernbar

12. Wann Vererbung im UI vertretbar ist

Nur wenn:

  • echte Spezialisierung vorliegt
  • Template bewusst erweitert wird
  • polymorphes Verhalten gewünscht ist
  • Hierarchie stabil ist

Nicht für:

  • Lifecycle-Handling
  • Unsubscribe-Logik
  • Logging
  • Error-Handling
  • Infrastruktur

13. Kernaussage

Vererbung im UI wird toxisch, wenn sie verwendet wird für:

  • Querschnittsfunktionalität
  • Lifecycle-Management
  • imperatives Ressourcenhandling

Sie erzeugt:

  • Gott-Basisklassen
  • implizite Kopplung
  • wachsende Komplexität
  • architektonische Fragilität

UI-Systeme profitieren von:

  • flacher Struktur
  • funktionaler Komposition
  • deklarativer Ableitung
  • klarer Datenflussarchitektur

Architekturregel

UI-Komponenten sollen Verhalten komponieren, nicht Hierarchien erben.