How to Build a Knowledge Base for a Dev Team
How to build a knowledge base for a dev team — a practical guide for engineering teams who want a shared knowledge system that engineers actually use
Developer Knowledge
How to write RFCs that get read — a practical guide for engineers who want their technical proposals to receive genuine engagement rather than being
An RFC (Request for Comments) is a proposal document. Its purpose is to gather feedback on a technical decision before it's made — to surface objections, alternatives, and considerations that the author may not have seen, and to build shared understanding before implementation begins.
Most RFCs fail at this purpose. They fail in one of two ways:
The rubber stamp: The RFC is reviewed perfunctorily. Reviewers see it in their inbox, skim the first paragraph, and approve it because declining to engage seems easier than the conversation. The author builds the proposal; the problems the RFC process was supposed to surface appear during implementation or production.
The ignored document: The RFC is circulated and not read. No feedback comes in. The author either proceeds anyway (the RFC becomes a formality that provides the appearance of process without its substance) or waits indefinitely.
Both failure modes have the same root cause: the RFC was too long, too dense, or too poorly structured for busy engineers to engage with productively. An RFC that takes 45 minutes to read in order to have an informed opinion will not get read by the people who have 5 minutes.
Good RFCs are written for the reader, not for the author. They make the problem unmistakably clear in the first paragraph, state the proposed solution concisely, and present trade-offs in a way that tells reviewers exactly what they're being asked to decide.
An RFC is for: Decisions that affect multiple teams or multiple engineers. Significant architectural changes. Adoption of new technologies or major dependencies. Changes to team-wide conventions or processes. Any decision where the cost of being wrong after implementation is significantly higher than the cost of more deliberation before implementation.
An RFC is not for: Implementation details within a service. Routine technology choices that one engineer or team can make independently. Performance optimizations that don't change the public contract. Anything that can be decided in a synchronous conversation.
The RFC process exists to prevent expensive wrong decisions, not to impose process on all decisions. If the decision can be made and reversed cheaply, it doesn't need an RFC. If it can't, it probably does.
An RFC that gets read has six sections in order:
1. Problem statement (required, first, short): One paragraph — ideally two to four sentences — that states the problem the RFC addresses. Not the background, not the context, not the history of how the problem arose. The problem, stated clearly, with enough specificity that the reader understands what's at stake.
Good problem statement: "Our deployment pipeline currently requires manual approval at three stages, adding an average of 4.2 hours to each deployment cycle. At our current velocity (3-4 deployments per week), this costs approximately one engineer-day per week and delays hotfixes by hours when latency is most costly."
Bad problem statement: "Our deployment pipeline has been in place since 2022 and was designed for a team of 5 engineers. Since then, the team has grown to 18 engineers and we now deploy 3-4 times per week. The original design was based on a process from [Company A] and adapted for our specific constraints. Over the past 18 months, several team members have raised concerns about the approval stages..."
The bad version makes the reader work to find the problem. The good version states it directly.
2. Proposed solution (required): What you propose to do. Specific enough that a reviewer can form an opinion — not so detailed that the RFC becomes an implementation spec. The proposed solution should be evaluable in principle before the implementation details are known.
3. Alternatives considered (required): What you considered doing instead, and why you didn't propose it. This section is often skipped or abbreviated; it's one of the most important. Without it, reviewers who have an alternative solution in mind will object to the proposal without a shared context. With it, the conversation moves to "given that we've already ruled out X because of Y, does that reasoning hold?"
Minimum: two alternatives with a one-paragraph explanation of each and the reason for not proposing them.
4. Open questions (required): The things you're not sure about. The tradeoffs you're not sure how to evaluate. The assumptions that might be wrong. The areas where you explicitly want reviewer input.
This section is the most direct invitation for engagement. A reviewer who has nothing to say about a confident proposal often has something to say about an open question. Open questions also signal intellectual honesty — the author knows the limits of their analysis.
5. Consequences (required): What changes if this proposal is adopted. What does it make easier? What does it make harder or foreclose? Who is affected (which teams, which systems)? What's the migration or transition path for existing systems?
6. Appendices / detailed design (optional, separated): The deep implementation details, diagrams, benchmarks, and research that informed the proposal. Placed at the end so readers who want depth can find it without readers who need the summary being slowed down.
# RFC: [Short, descriptive title]
**Author:** [Name]
**Date:** [Date]
**Status:** [Draft | Under Review | Accepted | Rejected | Withdrawn]
**Reviewers:** [Named engineers or teams whose feedback is explicitly requested]
**Decision deadline:** [Date by which feedback is needed — specific, not "ASAP"]
---
[1-3 paragraphs: What problem does this RFC address? Why does it need to be addressed now? What is the cost or impact of not addressing it?]
[2-4 paragraphs or a structured list: What do you propose to do? Specific enough to form an opinion; not an implementation spec. If the solution has multiple components, present them in order of importance.]
[1-2 paragraphs: What this would look like + key reason not proposed]
[1-2 paragraphs: What this would look like + key reason not proposed]
If adopted:
Migration path: [How does existing behavior change? What's the transition for affected systems/teams?]
What this forecloses: [Are there options that become harder or impossible if this is adopted?]
[Detailed design, benchmarks, diagrams, research — for readers who want depth]
---
The single change that most improves RFC engagement is a specific decision deadline.
An RFC without a deadline can be read whenever. Reading something you can do whenever means reading it never. A specific date — "feedback requested by 2026-11-20; the decision will be made regardless of whether feedback is received" — creates urgency and makes clear that silence will be treated as acquiescence.
The deadline should be:
State the consequence of no feedback: "If no objections are raised by the deadline, this proposal will be adopted." This is not aggressive; it's honest. It tells reviewers that their engagement determines the outcome.
An RFC sent to a team distribution list or a Slack channel is reviewed by no one. When review is everyone's responsibility, it's no one's.
Name the reviewers. "This RFC requests feedback specifically from @platform-team, @security-lead, and @principal-engineer." Named reviewers know they're expected to respond; unnamed reviewers know they can defer.
Named reviewers should include:
Two to five named reviewers is sufficient for most RFCs. More than eight and you've named too many; nobody believes they need to respond.
An RFC that presents a conclusion without trade-offs doesn't give reviewers anything to engage with. "We should adopt GraphQL because it's better" produces no feedback — reviewers who agree have nothing to add, and reviewers who disagree don't know what they're disagreeing with.
An RFC that presents trade-offs explicitly gives reviewers a surface to respond to: "Given that the proposed solution prioritizes developer experience at the cost of query complexity management overhead, and we've assessed that complexity management is a solvable operational problem, we're proposing GraphQL. If you disagree with that trade-off assessment, that's the place to engage."
Trade-offs to make explicit:
The proposal may have a preferred direction for each trade-off. State the direction and the reasoning, and note where the reasoning might be wrong.
Target length: 400-800 words for the six required sections. Longer RFCs get read less thoroughly; most RFCs can be written concisely.
Formatting: Headers and bullet points over prose where the content permits. Reviewers scan before they read; headers and bullets make the scan productive. Dense paragraphs of technical analysis require sequential reading — which reviewers won't do unless the problem statement has convinced them it's worth the time.
The executive summary as first paragraph: The first paragraph of the RFC should stand alone as a summary. If someone reads only the first paragraph, they should know: what problem this addresses, what's proposed, and why now. This is not a separate "TL;DR" section — it's how the problem statement section should be written.
An RFC that produces feedback but no documented decision fails its purpose. After the decision deadline:
Record the decision: Add a "Decision" section to the RFC document with: what was decided, the date, and the key factors that informed the decision.
Update the status: Change the RFC status from "Under Review" to "Accepted" or "Rejected."
Close the feedback thread: In whatever channel was used for discussion, post a summary of the decision. Reviewers who engaged should know the outcome; reviewers who didn't engage but are affected should know the decision is final.
Create the ADR: If the RFC resulted in an architectural decision, write an ADR that records the decision formally. The RFC is a proposal process; the ADR is the decision record. They serve different purposes.
Setup: An engineering team needs to decide how to implement API rate limiting for their public API. The senior engineer writes an RFC.
# RFC: API Rate Limiting Strategy
**Author:** Yuki Chen
**Date:** 2026-10-18
**Status:** Under Review
**Reviewers:** @api-team, @security-lead, @product-manager
**Decision deadline:** 2026-10-25
---
Our public API has no rate limiting. In the past two months, two customers have hit pathological usage patterns (automated polling at 10-second intervals) that have degraded service for other customers during peak hours. We need rate limiting before we expand the API's customer base in Q4.
Implement token bucket rate limiting at the API gateway (Kong) with the following defaults:
Limits configurable per customer by support team via Kong admin API. No code changes required in backend services.
Would give us more granular control over rate limiting logic but requires code changes in every service. Kong's token bucket covers our needs without service-level changes. Rejected for higher implementation complexity.
Simpler than token bucket but creates burst-at-window-boundary behavior. A customer can make 1,000 requests at 11:59 and 1,000 more at 12:00. Token bucket smooths this. Rejected for inferior traffic shaping.
If adopted: automated polling patterns that caused September incidents are throttled; API stability improves for other customers. Migration: existing customers receive 30-day advance notice with new response headers before enforcement begins. Forecloses: customers who require > 1,000 req/min at sustained rates will need enterprise pricing discussions.
This RFC is 380 words in the main sections. It states the problem in two sentences, the proposal in one paragraph, two alternatives with reasoning, three specific open questions, and a short consequences section. It has a named deadline and named reviewers. A reviewer who disagrees with the token bucket choice knows exactly where to engage.
---
An RFC that gets read is short, structured for scanning before sequential reading, specific about what decision is required and by when, honest about trade-offs, and explicit about open questions. The rubber stamp and the ignored document are failures of communication, not failures of content — they happen when the RFC asks busy engineers to do too much work to form an opinion. The RFC that reduces that work, by making the problem clear in a paragraph, the trade-offs explicit in a list, and the open questions unmistakable, is the RFC that gets the engagement it was asking for.
Related reading: Clip Articles for Later Reading.
More WebSnips articles that pair well with this topic.
How to build a knowledge base for a dev team — a practical guide for engineering teams who want a shared knowledge system that engineers actually use
How to document a microservices architecture — a practical guide for engineering teams navigating service sprawl, where the challenge is not documenting
How to keep a changelog developers trust — a practical guide for engineering teams who want a CHANGELOG.md that consumers of their API or library actually
How to save and organize design docs — a practical guide for engineers and engineering teams who want their design documents to remain findable, useful
How to take notes during code review — a practical guide for engineers who want to get more from code review than the immediate feedback loop: building a
How to track tech-debt decisions — a practical guide for engineering teams who want to manage their technical debt as intentional trade-offs rather than