Effektive technische RFCs schreiben
Wie man RFC-Dokumente schreibt, die zu klaren technischen Entscheidungen führen: Struktur, Zielgruppe, Alternativenanalyse und asynchroner Konsens.

Ein RFC (Request for Comments) ist ein strukturiertes Dokument, das eine technische Entscheidung vorschlägt und vor Beginn der Umsetzung um Rückmeldungen bittet. Es zwingt die Autorin oder den Autor, ein Problem gründlich zu durchdenken, bringt Bedenken der Beteiligten frühzeitig ans Licht und schafft eine dauerhafte Dokumentation darüber, warum Entscheidungen getroffen wurden.
Das Schreiben eines RFCs kostet Stunden. Der Verzicht darauf — das Falsche zu bauen, Integrationsprobleme erst mitten im Sprint zu entdecken oder Entscheidungen zu treffen, die nur eine einzige Person verstanden hat — kostet Wochen oder Monate.
Wann ein RFC sinnvoll ist
Nicht jede Änderung braucht einen RFC. Eine neue Hilfsfunktion zum Beispiel nicht. Aber alles, was mehrere Teams betrifft, neue Infrastruktur einführt, eine zentrale Abstraktion verändert oder sich nur schwer rückgängig machen lässt, sollte einen bekommen.
// Decision framework: does this change need an RFC?
interface ChangeAssessment {
affectsMultipleTeams: boolean; // Cross-team coordination needed
hardToReverse: boolean; // Database schema, API contract, etc.
newInfrastructure: boolean; // New service, new database, new queue
changesCorAbstraction: boolean; // Auth system, data model, caching layer
significantCostOrRisk: boolean; // Large effort, performance implications
controversialApproach: boolean; // Multiple valid approaches, strong opinions
}
function needsRFC(change: ChangeAssessment): boolean {
// If any two of these are true, write an RFC
const factors = Object.values(change).filter(Boolean);
return factors.length >= 2;
}
// Examples
needsRFC({
affectsMultipleTeams: false,
hardToReverse: false,
newInfrastructure: false,
changesCorAbstraction: false,
significantCostOrRisk: false,
controversialApproach: false,
}); // false — just do it
needsRFC({
affectsMultipleTeams: true,
hardToReverse: true,
newInfrastructure: true,
changesCorAbstraction: false,
significantCostOrRisk: true,
controversialApproach: true,
}); // true — definitely write an RFCAufbau eines RFCs
Ein gut strukturierter RFC macht es Reviewerinnen und Reviewern leicht, das Problem zu verstehen, den Vorschlag zu bewerten und gezieltes Feedback zu geben. Hier ist eine Vorlage, die in den meisten Engineering-Organisationen funktioniert.
# RFC-042: Migrate User Sessions from Redis to DynamoDB
**Author:** Jane Smith
**Status:** Under Review
**Created:** 2022-02-15
**Decision Deadline:** 2022-03-01
## Summary
One paragraph that explains the proposal at a high level.
A reader should understand what you want to do after reading this section.
## Motivation
Why are we doing this? What problem does it solve?
Include data: error rates, latency percentiles, cost numbers.
## Current State
How does the system work today?
Include a diagram if the architecture is complex.
## Proposal
The detailed technical plan. What changes, how it works,
and what the migration path looks like.
## Alternatives Considered
At least two alternatives with honest pros and cons.
This section is the most important for building trust.
## Risks and Mitigations
What could go wrong? How will we detect it? What's the rollback plan?
## Open Questions
Things you genuinely don't know yet. Invite specific feedback here.
## Decision
(Filled in after the review period)
What was decided, by whom, and why.Den Motivationsabschnitt schreiben
Am Motivationsabschnitt scheitern die meisten RFCs. Autorinnen und Autoren springen direkt zur Lösung, ohne vorher zu erklären, warum der aktuelle Zustand nicht ausreicht. Wer den Kontext der Autorin oder des Autors nicht teilt, versteht nicht, warum die Änderung wichtig ist.
// ❌ Weak motivation — vague and assertion-based
const weakMotivation = `
Redis is not a good fit for user sessions.
We should use DynamoDB instead because it's more scalable.
`;
// Reviewer thinks: "Redis works fine for sessions. Why change?"
// ✅ Strong motivation — specific, data-driven, problem-focused
const strongMotivation = `
Our Redis session store is hitting scaling limits:
- P99 latency has increased from 5ms to 45ms over the last quarter
as session count grew from 500K to 2.1M (chart: link)
- We've had 3 incidents in the last month where Redis OOM killed
caused session loss for ~12K users each time
- The single-node Redis setup has no replication; failover requires
manual intervention and ~8 minutes of downtime
- Monthly cost: $1,200/mo for an r6g.2xlarge instance that's at 87%
memory utilization with no headroom for growth
We expect session count to reach 5M by Q4 based on current growth
trends (appendix A). The current architecture cannot support this.
`;
// Reviewer thinks: "Clear problem. Let me see the proposed solution."Der Abschnitt zu Alternativen
Der Alternativenabschnitt ist der wichtigste Teil eines RFCs, um das Vertrauen der Reviewer zu gewinnen. Wenn du zeigst, dass du mehrere Ansätze ehrlich abgewogen hast — einschließlich der Option, nichts zu tun —, wissen die Reviewer, dass du deine Hausaufgaben gemacht hast.
// Always include "Do Nothing" as an alternative
interface Alternative {
name: string;
description: string;
pros: string[];
cons: string[];
estimatedEffort: string;
whyNotChosen: string;
}
const alternatives: Alternative[] = [
{
name: 'Do Nothing',
description: 'Keep the current Redis single-node setup',
pros: [
'Zero engineering effort',
'No migration risk',
],
cons: [
'OOM incidents will increase as sessions grow',
'P99 latency will continue to degrade',
'Manual failover remains a risk',
],
estimatedEffort: '0 weeks',
whyNotChosen: 'Growth projections make this untenable within 2 quarters',
},
{
name: 'Redis Cluster',
description: 'Migrate to a Redis Cluster with 3 primary + 3 replica nodes',
pros: [
'Familiar technology — team knows Redis',
'Horizontal scaling via hash slots',
'Automatic failover with Sentinel',
],
cons: [
'Operational complexity increases significantly',
'Cross-slot operations not supported (affects bulk session ops)',
'Still requires manual capacity planning',
'Estimated cost: $3,600/mo for 6-node cluster',
],
estimatedEffort: '3 weeks',
whyNotChosen: 'Higher operational burden than DynamoDB for similar cost',
},
{
name: 'DynamoDB (Proposed)',
description: 'Migrate sessions to DynamoDB with on-demand capacity',
pros: [
'Fully managed — no operational overhead',
'Auto-scales to any traffic level',
'Built-in TTL for session expiry',
'Multi-AZ replication by default',
'Pay-per-request pricing scales with actual usage',
],
cons: [
'Team needs to learn DynamoDB data modeling',
'Migration requires dual-write period',
'Slightly higher per-request latency (single-digit ms vs sub-ms)',
],
estimatedEffort: '4 weeks',
whyNotChosen: 'This is the proposed approach',
},
];Feedback wirksam einholen
Ein RFC, der zwei Wochen lang ungelesen liegen bleibt, nützt niemandem. Der Prozess funktioniert nur, wenn man aktiv und gezielt von den richtigen Leuten zum richtigen Zeitpunkt Feedback einholt.
// ❌ Passive feedback request
const passiveFeedback = 'Please review this RFC and leave comments.';
// Result: no one reads it, deadline passes, author assumes consensus
// ✅ Targeted feedback request with specific questions
const activeFeedback = {
to: [
{ name: 'Platform Team', ask: 'Is the DynamoDB capacity estimate realistic?' },
{ name: 'Security Team', ask: 'Any concerns with session data in DynamoDB?' },
{ name: 'Backend Lead', ask: 'Does the dual-write migration plan have gaps?' },
],
openQuestions: [
'Should we use on-demand or provisioned capacity for the first month?',
'What is the acceptable data loss window during migration cutover?',
'Do we need to preserve session history, or can we start fresh?',
],
deadline: '2022-03-01',
decisionMaker: 'Staff Engineer — Platform',
};Vom RFC zum Entscheidungsprotokoll
Nach der Review-Phase wird der RFC zum Entscheidungsprotokoll. Halte fest, was entschieden wurde, mit welcher Begründung und welche Änderungen sich aus dem Review-Prozess ergeben haben.
interface DecisionRecord {
rfcId: string;
decision: 'approved' | 'rejected' | 'deferred';
decisionDate: string;
decisionMaker: string;
summary: string;
modificationsFromReview: string[];
dissent: string[]; // Disagreements recorded for future reference
reviewParticipants: string[];
}
const decision: DecisionRecord = {
rfcId: 'RFC-042',
decision: 'approved',
decisionDate: '2022-03-01',
decisionMaker: 'Jane Smith (Staff Engineer)',
summary: 'Approved migration to DynamoDB with on-demand capacity',
modificationsFromReview: [
'Added 2-week dual-write period (originally proposed 1 week)',
'Added rollback trigger: if DynamoDB P99 > 20ms, revert to Redis',
'Security review: encrypt session data at rest using KMS',
],
dissent: [
'Backend Lead preferred Redis Cluster for team familiarity — noted ' +
'but overruled due to operational cost analysis',
],
reviewParticipants: [
'Platform Team (3 reviewers)',
'Security Team (1 reviewer)',
'Backend Lead',
],
};Die wichtigsten Erkenntnisse
- Schreibe RFCs für Änderungen, die schwer rückgängig zu machen, teamübergreifend oder umstritten sind — nicht alles braucht einen, aber alles mit erheblichem Wirkungsradius schon
- Beginne mit der Motivation — datengestützte Problembeschreibungen schaffen Vertrauen bei den Reviewern und rechtfertigen den Engineering-Aufwand
- Nimm immer Alternativen auf — eine ehrliche Bewertung der Option "nichts tun" und mindestens eines konkurrierenden Ansatzes zeigt gründliches Denken
- Richte deine Feedback-Anfragen gezielt aus — stelle bestimmten Personen konkrete Fragen, statt pauschal um "Review" zu bitten
- Setze eine Entscheidungsfrist — unbegrenzte Review-Phasen führen zu endlosen Verzögerungen; gib der Diskussion ein Zeitfenster
- Dokumentiere die Entscheidung und abweichende Meinungen — künftige Entwicklerinnen und Entwickler müssen nicht nur verstehen, was entschieden wurde, sondern auch warum und welche Kompromisse dabei akzeptiert wurden


