Claude Code RxJS: Reaktive Programmierung, Observables und Event-Streams mit KI
RxJS ist mächtig — und genau deshalb ist die Lernkurve so steil. Das Observable-Modell, die Dutzenden von Operatoren, der Unterschied zwischen switchMap und mergeMap, die Frage wann ein Subject und wann ein BehaviorSubject sinnvoll ist: All das braucht Zeit, um wirklich zu sitzen. Und selbst erfahrene Entwickler greifen bei Operator-Fragen noch zur Dokumentation.
Claude Code RxJS ändert dieses Bild nicht revolutionär, aber konkret: Es generiert reaktiven Code, der tatsächlich funktioniert, erklärt Operator-Entscheidungen, schreibt Marble-Tests und hilft, Memory Leaks durch fehlende Subscriptions zu finden — also genau die Stellen, an denen RxJS-Entwicklung am meisten Zeit kostet. Dieser Artikel zeigt das anhand echter Prompts und dem Code, der daraus entsteht.
Claude Code Mastery — Reactive Programming, Angular und mehr auf Deutsch
RxJS ist ein Kapitel. Im Kurs lernst du Claude Code vollständig — von den Grundlagen bis zu autonomen Agents, MCP-Servern und professionellen Workflows. Einmalig bezahlt, kein Abo.
Zum Kurs — Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht1. Warum RxJS mit Claude Code anders ist
Das Grundproblem bei RxJS ist nicht das Konzept — ein Observable ist letztlich ein lazy Event-Stream, der Werte über die Zeit liefert. Das Grundproblem ist die Operatorauswahl. RxJS hat über 100 Operatoren. Den richtigen für eine konkrete Situation zu kennen, braucht Erfahrung und Dokumentationslesen.
Claude Code kennt die Semantik aller gängigen Operatoren und entscheidet situativ. Wenn du beschreibst, was du erreichen willst — "bei jedem Tastendruck eine neue HTTP-Anfrage, aber die vorherige abbrechen" — wählt Claude Code switchMap, nicht mergeMap. Wenn du "alle Anfragen parallel starten und auf alle warten" sagst, kommt forkJoin. Und wenn du fragst warum, erklärt es den Unterschied.
Das ist reaktive Programmierung mit KI: nicht Code-Generierung, sondern Operator-Wissen on demand.
Voraussetzung: Dieser Artikel setzt voraus, dass RxJS installiert ist (npm install rxjs) und du ein Projekt hast, in dem Claude Code starten kann. In Angular-Projekten ist RxJS bereits vorhanden. Starte Claude Code aus dem Root-Verzeichnis deines Projekts.
2. Observable und Observer: der Einstieg
Bevor man Operatoren verwendet, muss man verstehen, was ein Observable ist. Claude Code erklärt es nicht abstrakt — es zeigt es an konkretem Code:
claude "Erkläre mir Observable und Observer in RxJS mit einem
minimalen, lauffähigen Beispiel. Keine Theorie, nur Code mit Kommentaren."
Das Ergebnis ist typischerweise ein Beispiel wie dieses:
import { Observable } from 'rxjs';
// Ein Observable ist eine lazy Datenquelle -- es macht nichts,
// bis jemand subscribed.
const zahlen$ = new Observable<number>(subscriber => {
// subscriber ist der Observer: er hat next(), error(), complete()
subscriber.next(1);
subscriber.next(2);
subscriber.next(3);
subscriber.complete(); // Stream ist beendet
// Optional: Cleanup-Logik, die beim Unsubscribe läuft
return () => console.log('Unsubscribed');
});
// Erst jetzt läuft der Code oben:
const subscription = zahlen$.subscribe({
next: (wert) => console.log('Erhalten:', wert),
error: (err) => console.error('Fehler:', err),
complete: () => console.log('Fertig'),
});
// Subscription explizit beenden (wichtig für Memory Management):
subscription.unsubscribe();
Was Claude Code hier auch immer mitliefert: den Hinweis auf unsubscribe(). Memory Leaks durch vergessene Subscriptions sind der häufigste RxJS-Bug in der Praxis. Claude Code erinnert daran, weil es den Kontext kennt — nicht als allgemeinen Hinweis, sondern direkt am generierten Code.
Das Convention-Suffix: das Dollarzeichen
Du wirst in RxJS-Code oft Variablen mit dem Suffix $ sehen: user$, events$, result$. Das ist eine Community-Konvention, kein Pflichtzeichen. Es signalisiert: diese Variable ist ein Observable. Claude Code folgt dieser Konvention standardmäßig. Wenn du das nicht willst, sag es einmal — und es hört auf.
3. Die wichtigsten Operatoren mit Prompt-Beispielen
Operatoren sind das Herzstück von RxJS. Claude Code kennt sie alle — aber die Qualität des generierten Codes steigt mit der Präzision deines Prompts. Hier sind die gängigsten Patterns mit konkreten Prompts:
map und filter: Transformation und Filterung
claude "Ich habe einen Observable-Stream von User-Objekten mit
den Feldern id, name, age, active. Ich will nur aktive User,
deren Name mit 'A' beginnt, und nur die id und name Felder
zurückhaben. Zeig das mit map und filter."
Claude Code generiert:
import { of } from 'rxjs';
import { filter, map } from 'rxjs/operators';
interface User {
id: number;
name: string;
age: number;
active: boolean;
}
const users$ = of<User[]>([
{ id: 1, name: 'Anna', age: 30, active: true },
{ id: 2, name: 'Bernd', age: 25, active: true },
{ id: 3, name: 'Alicia', age: 28, active: false },
{ id: 4, name: 'Alex', age: 35, active: true },
]);
const gefilterteUser$ = users$.pipe(
// Zuerst entpacken (Array zu einzelnen Elementen)
// filter: nur aktive User
map(users => users.filter(u => u.active && u.name.startsWith('A'))),
// map: nur benötigte Felder
map(users => users.map(({ id, name }) => ({ id, name }))),
);
gefilterteUser$.subscribe(users => console.log(users));
// Output: [{ id: 1, name: 'Anna' }, { id: 4, name: 'Alex' }]
switchMap: HTTP-Anfragen bei jedem Input
Das häufigste Einsatzszenario für switchMap in Angular: Suche mit Autocomplete. Bei jedem Tastendruck eine neue Anfrage — aber die vorherige abbrechen, damit keine Race Condition entsteht.
claude "Ich habe ein Angular-Suchfeld. Bei jedem Tastendruck soll
eine HTTP-Anfrage an /api/search?q= gesendet werden. Wenn der
User schnell tippt, soll nur die letzte Anfrage zählen. Zeig das
mit switchMap und debounceTime."
import { Component, OnInit, OnDestroy } from '@angular/core';
import { FormControl } from '@angular/forms';
import { HttpClient } from '@angular/common/http';
import { Subject } from 'rxjs';
import { debounceTime, distinctUntilChanged, switchMap, takeUntil } from 'rxjs/operators';
@Component({
selector: 'app-suche',
template: `
<input [formControl]="suchfeld" placeholder="Suchen...">
<ul>
<li *ngFor="let ergebnis of ergebnisse">{{ ergebnis.name }}</li>
</ul>
`
})
export class SucheComponent implements OnInit, OnDestroy {
suchfeld = new FormControl('');
ergebnisse: any[] = [];
// Subject als Destroy-Signal (sauberes Unsubscribe-Pattern)
private destroy$ = new Subject<void>();
constructor(private http: HttpClient) {}
ngOnInit() {
this.suchfeld.valueChanges.pipe(
debounceTime(300), // 300ms warten nach letztem Tastendruck
distinctUntilChanged(), // Nur bei tatsächlicher Änderung reagieren
switchMap(query => // Vorherige Anfrage abbrechen, neue starten
this.http.get<any[]>(`/api/search?q=${encodeURIComponent(query ?? '')}`)
),
takeUntil(this.destroy$), // Automatisch unsubscribe beim Destroy
).subscribe(ergebnisse => {
this.ergebnisse = ergebnisse;
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
switchMap vs. mergeMap: switchMap bricht die laufende innere Subscription ab, wenn ein neuer Wert kommt. mergeMap lässt alle parallelen Subscriptions laufen. Für Suchanfragen immer switchMap. Für parallele Downloads, bei denen alle Ergebnisse gebraucht werden, mergeMap. Claude Code wählt automatisch richtig, wenn du den Use Case beschreibst.
combineLatest: mehrere Streams zusammenführen
claude "Ich habe drei Observables: user$ (aktueller User),
permissions$ (Berechtigungen) und settings$ (App-Einstellungen).
Ich will reagieren, sobald alle drei den ersten Wert geliefert
haben, und danach bei jeder Änderung an einem der drei. Zeig
das mit combineLatest."
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
// combineLatest emittiert erst, wenn ALLE Quellen mindestens einen Wert hatten.
// Danach bei jeder Änderung an einem der Streams.
const appState$ = combineLatest([user$, permissions$, settings$]).pipe(
map(([user, permissions, settings]) => ({
user,
permissions,
settings,
// Derived state direkt hier berechnen:
isAdmin: permissions.includes('admin'),
theme: settings.theme,
}))
);
appState$.subscribe(state => {
console.log('App-State:', state);
// Reagiert automatisch wenn user, permissions ODER settings sich ändert
});
4. Subject und BehaviorSubject
Ein Subject ist sowohl Observable als auch Observer — es kann Werte empfangen und weiterleiten. Das macht es zum Kommunikationskanal zwischen Komponenten, die kein direktes Parent-Child-Verhältnis haben.
claude "Erkläre den Unterschied zwischen Subject und BehaviorSubject
in RxJS. Wann nehme ich welches? Mit einem Beispiel für einen
einfachen State-Management-Service in Angular."
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
interface WarenkorbState {
items: Array<{ id: number; name: string; menge: number }>;
gesamt: number;
}
const initialState: WarenkorbState = {
items: [],
gesamt: 0,
};
@Injectable({ providedIn: 'root' })
export class WarenkorbService {
// BehaviorSubject: hat immer einen aktuellen Wert (initialState).
// Neue Subscriber erhalten sofort den letzten Wert -- kein "warten auf
// das nächste Event". Das ist der Hauptunterschied zu Subject.
private state$ = new BehaviorSubject<WarenkorbState>(initialState);
// Öffentlich nur als Observable exposieren (readonly nach außen):
readonly warenkorb$: Observable<WarenkorbState> = this.state$.asObservable();
// Derived Observable direkt aus dem State ableiten:
readonly itemAnzahl$: Observable<number> = this.warenkorb$.pipe(
map(state => state.items.reduce((sum, item) => sum + item.menge, 0))
);
// Aktuellen Wert synchron lesen (manchmal nötig für Event-Handler):
get aktuellerState(): WarenkorbState {
return this.state$.getValue();
}
artikelHinzufuegen(artikel: { id: number; name: string }): void {
const aktuell = this.aktuellerState;
const vorhanden = aktuell.items.find(i => i.id === artikel.id);
const items = vorhanden
? aktuell.items.map(i => i.id === artikel.id ? { ...i, menge: i.menge + 1 } : i)
: [...aktuell.items, { ...artikel, menge: 1 }];
this.state$.next({
items,
gesamt: items.reduce((sum, i) => sum + i.menge, 0),
});
}
warenkorbLeeren(): void {
this.state$.next(initialState);
}
}
// Subject wäre hier falsch: neue Subscriber würden keinen Wert erhalten,
// bis der nächste artikelHinzufuegen()-Aufruf kommt. BehaviorSubject gibt
// sofort den aktuellen Warenkorb -- auch wenn der schon gefüllt ist.
Der Kommentar am Ende ist nicht zufällig: Claude Code begründet die Entscheidung. Das ist wichtig für Teams, bei denen nicht alle die Unterschiede auswendig kennen.
5. HTTP-Requests reaktiv machen in Angular
Angular's HttpClient gibt bereits Observables zurück. Aber die Frage ist, wie man sie in echten Anwendungen richtig kombiniert — mit Retry-Logik, Caching, Error-Handling und sauberem Unsubscribe.
claude "Schreib mir einen Angular-Service der Produkte von /api/products
lädt. Der Service soll: 1) das Ergebnis 5 Minuten cachen,
2) bei Netzwerkfehlern dreimal wiederholen, 3) bei permanentem
Fehler ein leeres Array zurückgeben statt den Stream zu beenden,
4) Loading-State und Error-State als Observables exponieren."
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { BehaviorSubject, Observable, of, timer } from 'rxjs';
import {
catchError,
map,
retry,
shareReplay,
switchMap,
tap,
} from 'rxjs/operators';
interface Produkt {
id: number;
name: string;
preis: number;
}
interface LadeState {
laden: boolean;
fehler: string | null;
}
@Injectable({ providedIn: 'root' })
export class ProduktService {
private readonly CACHE_DAUER_MS = 5 * 60 * 1000; // 5 Minuten
private ladeState$ = new BehaviorSubject<LadeState>({ laden: false, fehler: null });
// Öffentliche State-Observables:
readonly laden$: Observable<boolean> = this.ladeState$.pipe(map(s => s.laden));
readonly fehler$: Observable<string | null> = this.ladeState$.pipe(map(s => s.fehler));
// shareReplay(1) cached den letzten Wert und teilt ihn mit allen Subscribern.
// { refCount: false } hält den Cache auch wenn gerade kein Subscriber aktiv ist.
readonly produkte$: Observable<Produkt[]> = timer(0, this.CACHE_DAUER_MS).pipe(
tap(() => this.ladeState$.next({ laden: true, fehler: null })),
switchMap(() =>
this.http.get<Produkt[]>('/api/products').pipe(
// Bei Fehler: 3 Versuche, jeweils 1s Pause
retry({ count: 3, delay: 1000 }),
tap(() => this.ladeState$.next({ laden: false, fehler: null })),
catchError(err => {
// Stream NICHT beenden -- leeres Array zurückgeben
this.ladeState$.next({ laden: false, fehler: 'Produkte konnten nicht geladen werden.' });
return of([]);
})
)
),
shareReplay({ bufferSize: 1, refCount: false }),
);
constructor(private http: HttpClient) {}
}
// In der Komponente:
// this.produkte$ = this.produktService.produkte$;
// this.laden$ = this.produktService.laden$;
// -- kein subscribe() nötig, async pipe im Template übernimmt das
catchError-Falle: Wenn catchError den Fehler nicht behandelt (also weiter wirft), beendet sich der Observable. Dann wird shareReplay nie wieder Werte liefern. of([]) gibt stattdessen einen leeren Wert zurück und der Stream bleibt am Leben. Claude Code beachtet das standardmäßig — aber beim manuellen Schreiben ist das die häufigste RxJS-Falle.
6. Error Handling: catchError und retry im Detail
Fehlerbehandlung in RxJS ist anders als in synchronem Code. Ein nicht behandelter Fehler in einem Observable beendet den Stream — keine weiteren Werte, kein Recovery, der Stream ist tot. Das ist kein Bug, sondern Design.
claude "Zeig mir die verschiedenen Error-Handling-Patterns in RxJS:
catchError mit Fallback, retry mit exponential backoff, retryWhen
für komplexere Retry-Logik, und wie ich verschiedene HTTP-Status-
codes unterschiedlich behandle."
Exponential Backoff mit Claude Code:
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError, timer } from 'rxjs';
import { catchError, mergeMap, retry } from 'rxjs/operators';
// Exponential Backoff: 1s, 2s, 4s zwischen Versuchen
function mitExponentialBackoff<T>(maxVersuche: number) {
return (source$: Observable<T>) =>
source$.pipe(
retry({
count: maxVersuche,
delay: (fehler, versuchsNummer) => {
// Netzwerkfehler wiederholen, 4xx-Fehler sofort weiterwerfen
if (fehler instanceof HttpErrorResponse && fehler.status >= 400 && fehler.status < 500) {
return throwError(() => fehler); // Client-Fehler nicht wiederholen
}
const wartezeit = Math.pow(2, versuchsNummer - 1) * 1000;
console.log(`Versuch ${versuchsNummer} fehlgeschlagen. Warte ${wartezeit}ms...`);
return timer(wartezeit);
},
})
);
}
// Verschiedene Statuscodes behandeln:
function httpFehlerBehandeln<T>(fallback: T) {
return catchError((fehler: HttpErrorResponse) => {
if (fehler.status === 401) {
// Unauthorized: User ausloggen
console.error('Session abgelaufen');
// authService.logout() etc.
} else if (fehler.status === 404) {
// Not Found: Fallback zurückgeben, kein Fehler
return of(fallback);
} else if (fehler.status === 0) {
// Netzwerkfehler (kein Internetzugang)
console.error('Keine Verbindung');
}
// Andere Fehler weiterwerfen
return throwError(() => new Error(`HTTP-Fehler ${fehler.status}: ${fehler.message}`));
});
}
// Verwendung:
this.http.get<Produkt[]>('/api/products').pipe(
mitExponentialBackoff(3),
httpFehlerBehandeln([]),
).subscribe(produkte => { /* ... */ });
7. pipe() richtig einsetzen
Die pipe()-Methode ist die funktionale Kompositions-API von RxJS. Alles was du mit Operatoren machst, geht durch pipe(). Claude Code schreibt automatisch lesbares, gut geordnetes pipe()-Chaining — aber es gibt Konventionen, die den Code wartbarer machen:
claude "Was sind Best Practices für RxJS pipe()-Chains? Wann soll
ich eine lange Pipe aufteilen? Zeig mir ein Beispiel für eine
zu lange Pipe und wie man sie refactored."
// VORHER: eine lange Pipe, schwer zu lesen und zu testen
const ergebnis$ = quelle$.pipe(
debounceTime(300),
distinctUntilChanged(),
filter(q => q.length > 2),
switchMap(q => this.http.get(`/api/search?q=${q}`)),
map(resp => resp.items),
filter(items => items.length > 0),
map(items => items.slice(0, 10)),
catchError(() => of([])),
shareReplay(1),
);
// NACHHER: aufgeteilt in benannte, wiederverwendbare Pipelines
const sucheNormalisieren = () => pipe(
debounceTime(300),
distinctUntilChanged(),
filter((q: string) => q.length > 2),
);
const httpMitFallback = (url: string) =>
switchMap((q: string) =>
this.http.get<{ items: any[] }>(`${url}?q=${q}`).pipe(
map(resp => resp.items),
catchError(() => of([])),
)
);
const ergebnisseBerenigen = () => pipe(
filter((items: any[]) => items.length > 0),
map((items: any[]) => items.slice(0, 10)),
);
// Resultierende Pipe: lesbar, jeder Teil einzeln testbar
const ergebnis$ = quelle$.pipe(
sucheNormalisieren(),
httpMitFallback('/api/search'),
ergebnisseBerenigen(),
shareReplay(1),
);
Das Refactoring in benannte Operator-Funktionen ist besonders wertvoll für Tests: Jede Teilpipe kann isoliert getestet werden, ohne HTTP-Mocking oder komplexes Setup.
8. Testing mit Marble Diagrams
Marble Diagrams sind die Standard-Testmethode für RxJS. Sie beschreiben das zeitliche Verhalten eines Observables als ASCII-String. -a-b-c| heißt: nach einem Frame kommt a, dann b, dann c, dann Complete.
claude "Zeig mir wie ich den sucheNormalisieren-Operator aus dem
vorherigen Beispiel mit Marble Diagrams teste. Verwende TestScheduler
aus rxjs/testing."
import { TestScheduler } from 'rxjs/testing';
import { pipe } from 'rxjs';
import { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators';
// Die zu testende Pipe-Funktion (aus vorherigem Beispiel):
const sucheNormalisieren = () => pipe(
debounceTime(300),
distinctUntilChanged(),
filter((q: string) => q.length > 2),
);
describe('sucheNormalisieren', () => {
let scheduler: TestScheduler;
beforeEach(() => {
scheduler = new TestScheduler((actual, expected) => {
expect(actual).toEqual(expected);
});
});
it('sollte nach 300ms debounced emittieren', () => {
scheduler.run(({ cold, expectObservable }) => {
// Marble-Syntax:
// '-' = 1ms Frame
// Buchstabe = Wert aus values-Map
// '|' = Complete
// '#' = Error
const eingabe$ = cold('a 299ms b 200ms c|', {
a: 'ab', // zu kurz, wird gefiltert
b: 'abc', // lang genug, kommt durch nach 300ms
c: 'xyz', // kommt durch
});
const erwartet = '300ms b 500ms c|';
expectObservable(eingabe$.pipe(sucheNormalisieren())).toBe(erwartet, {
b: 'abc',
c: 'xyz',
});
});
});
it('sollte gleiche Werte ignorieren (distinctUntilChanged)', () => {
scheduler.run(({ cold, expectObservable }) => {
const eingabe$ = cold('300ms a 300ms a 300ms b|', {
a: 'abc',
b: 'def',
});
// Zweites 'abc' wird durch distinctUntilChanged gefiltert:
const erwartet = '600ms a 600ms b|';
expectObservable(eingabe$.pipe(sucheNormalisieren())).toBe(erwartet, {
a: 'abc',
b: 'def',
});
});
});
});
Marble Tests sehen auf den ersten Blick kryptisch aus. Claude Code schreibt sie korrekt — und auf Nachfrage erklärt es die Marble-Syntax Zeile für Zeile. Das beschleunigt das Verstehen erheblich, weil man den Test und die Erklärung zusammen sieht.
9. Memory Leaks finden und beheben
Der häufigste Bug in RxJS-Code: eine Subscription wird nie beendet. In Angular-Komponenten bedeutet das, dass die Subscription noch aktiv ist, nachdem die Komponente zerstört wurde — der Callback läuft weiter, versucht auf die (nicht mehr existierende) Komponente zuzugreifen, und erzeugt Fehler oder still falsche Daten.
claude "Analysiere diese Angular-Komponente und zeige alle möglichen
Memory Leaks durch nicht beendete Subscriptions. Zeig dann drei
verschiedene Lösungsansätze: takeUntil, async pipe, und takeUntilDestroyed."
// PROBLEM: Subscription-Leak
@Component({ selector: 'app-beispiel', template: `...` })
export class BeispielComponent implements OnInit {
daten: any[] = [];
constructor(private service: DatenService) {}
ngOnInit() {
// LEAK: keine Unsubscribe-Logik!
this.service.daten$.subscribe(daten => {
this.daten = daten;
});
}
}
// LÖSUNG 1: takeUntil mit destroy$ Subject
@Component({ selector: 'app-beispiel', template: `...` })
export class BeispielComponent implements OnInit, OnDestroy {
daten: any[] = [];
private destroy$ = new Subject<void>();
constructor(private service: DatenService) {}
ngOnInit() {
this.service.daten$.pipe(
takeUntil(this.destroy$) // Automatisch unsubscribe bei Destroy
).subscribe(daten => {
this.daten = daten;
});
}
ngOnDestroy() {
this.destroy$.next();
this.destroy$.complete();
}
}
// LÖSUNG 2: async pipe im Template (kein subscribe() im Code)
@Component({
selector: 'app-beispiel',
template: `
<ul>
<!-- async pipe subscribed und unsubscribed automatisch: -->
<li *ngFor="let item of daten$ | async">{{ item.name }}</li>
</ul>
`
})
export class BeispielComponent {
// Observable direkt exponieren, kein subscribe() im Code:
readonly daten$ = this.service.daten$;
constructor(private service: DatenService) {}
}
// LÖSUNG 3: takeUntilDestroyed (Angular 16+, modernes Pattern)
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { DestroyRef, inject } from '@angular/core';
@Component({ selector: 'app-beispiel', template: `...` })
export class BeispielComponent implements OnInit {
daten: any[] = [];
private destroyRef = inject(DestroyRef);
constructor(private service: DatenService) {}
ngOnInit() {
this.service.daten$.pipe(
takeUntilDestroyed(this.destroyRef) // Angular kümmert sich automatisch
).subscribe(daten => {
this.daten = daten;
});
}
}
Empfehlung: In modernen Angular-Projekten (ab Angular 16) ist takeUntilDestroyed die sauberste Lösung. Für ältere Projekte ist die async-Pipe im Template bevorzugt, da sie komplett ohne manuelles Subscribe auskommt. takeUntil ist ein guter Fallback wenn beides nicht passt.
10. Praktischer Prompt-Leitfaden für Claude Code RxJS
Reaktive Programmierung mit KI funktioniert am besten, wenn der Prompt den Use Case beschreibt statt die Implementierung vorzugeben. Hier sind die Prompt-Patterns, die zuverlässig gute Ergebnisse liefern:
- "Wenn A passiert, soll B ausgelöst werden, aber nur wenn C": Verhaltens-Beschreibung zuerst — Claude Code wählt den richtigen Operator
- "Erkläre den Unterschied zwischen X und Y in meinem konkreten Fall": Nicht abstrakt fragen, sondern deinen Use Case mitgeben
- "Analysiere diesen Code auf Memory Leaks und fehlende Unsubscribes": Code direkt übergeben, Claude Code liest ihn komplett
- "Schreib Marble Tests für diesen Operator": Gibt den Operatorcode mit, bekommt direkt testbaren Code zurück
- "Refactore diese Pipe so, dass jeder Teil einzeln testbar ist": Architektur-Prompts, die Wartbarkeit verbessern
Was nicht funktioniert: sehr generische Prompts wie "zeig mir RxJS". Der Output ist dann ebenfalls generisch. Je konkreter der Kontext (welches Framework, welcher Use Case, welche Constraints), desto brauchbarer der generierte Code.
Fazit: reaktive Programmierung mit Claude Code
RxJS bleibt komplex — das ändert auch Claude Code nicht. Aber die Stellen, an denen die Komplexität am meisten Zeit kostet, werden besser handhabbar: Operatorwahl, Fehlerbehandlung, Memory-Leak-Erkennung, Marble-Tests. Für deutsche Entwickler die täglich mit Angular und RxJS arbeiten, ist das ein konkreter Zeitgewinn.
Reaktive Programmierung Claude zu nutzen heißt nicht, das Denken abzugeben. Es heißt, die Implementierungsdetails schneller zu klären, damit mehr Zeit für Architektur und Geschäftslogik bleibt.
- Claude Code Debugging — Bugs systematisch finden mit Claude Code
- Claude Code für Python-Projekte — Workflows, Tests und Codequalität
Claude Code Mastery — von RxJS bis zum autonomen Agenten
RxJS ist ein Schwerpunkt — aber der Kurs geht weiter: Agents, MCP-Server, Hooks, Multi-Agent-Workflows, alles vollständig auf Deutsch. Einmalig bezahlt, kein Abo.
Jetzt starten → Einmalzahlung · Kein Abo · 14 Tage RückgaberechtKurs · Claude Code Mastery
Basis ab €29 — Pro ab €49
RxJS. Angular. Agents. MCP. Hooks. Vollständig auf Deutsch, einmalig bezahlt — kein Abo, keine Plattformabhängigkeit.
Einmalzahlung · Kein Abo · 14 Tage Rückgaberecht