There’s a book by Stephen King, called On Writing. I have a lot of respect for Stephen King as a creator. This makes me love the book because it is a great explanation of the process of writing, and his process has obviously produced results for him. Also, it is also a book about how to produce more books…and I love recursion. So in that spirit, I’m going to write about writing…a Request For Change (RFC).
While I use the term RFC, I don’t mean IETF RFCs, but I use the term to describe a planning doc that covers any kind of planning where you have to make a decision among a group of reasonable and logical people. RFCs are useful for communication, documentation, persuasion, and alignment.
The point of an RFC is to explain why a change is needed, what change is being proposed, and why the proposed change is the right one
An RFC is meant to explain a change you want to make. That change could be essentially anything: a new coding standard, replacing a database, or refactoring a component. Usually RFCs are for changes that will impact multiple components or multiple teams.
The point of doing this is to get enough information in writing so that some third party (executive, architect, newly hired engineer) could read the document and understand why a change is needed, what change is being proposed, and why the proposed change is the right one.
The RFC Lifecycle
In general, once you have an idea, you should write down a plan, and then implement it. Writing an RFC is just one part of the planning phase, which can also include prototyping and writing tickets.
Be mindful that this lifecycle isn’t always totally linear. Sometimes planning and implementing can blend together. Avoid this when possible, but if it’s impractical, you should at least write RFC drafts and document your work during the implementation.
In general, your process should feel like it makes sense:
- Write a first draft
- Share the draft with 1-2 close stakeholders to make sure you’re “directionally correct”
- Share the draft with other key stakeholders
- Share the RFC publicly and get it ratified
- Use the RFC to write tickets or any followup actions
The structure of an RFC
You should usually include all of these headings. If (for example) there are no “Key Dates”, it’s generally good to be explicit and write “There are no key dates” instead of removing a heading.
- Title, RFC number, version number, authors, date
- Key Dates
Some general comments:
- Be terse and write in a plain, fact-based style. You want people to read your RFC, and you should value your audience’s time.
- Use diagrams
- Cite your sources. Add links to dashboards, lines of code, tickets, etc.
- Use consistent fonts, headings, etc. Having a polished document matters.
- Assuming your RFC is on a wiki, encourage people to ask their questions in writing as comments.
- RFCs don’t always have tickets associated with them, but they usually do. The RFC is not meant to be a place to store the full implementation plans, but you should have reciprocal links between the RFC and the parent ticket.
Notes on individual headings
I have additional notes on each of the headings below. But above all, keep in mind the whole point is just to write things down in a way that makes sense. If you have an idea that makes your document clearer for your audience, go ahead and make that change.
Title, RFC number, version number, authors, date
This is a general heading section for metadata about the RFC.
My one comment on this section is that it is important to have uniquely numbered RFCs. Go with something simple like RFC-1234 or CRFC-1234 (“CRFC” meaning “Company RFC” to distinguish yourself from IETF RFCs). Having a terse identifier is a subtlety that pays off over time, because you can write it down in many places.
Normally code is linked to a commit, which is linked to a ticket, which is linked to a parent ticket, which is linked to an RFC. When a team is consistently creating these links, it becomes possible to read any line of code and be able to get full context within 5 clicks. But sometimes you have non-code resources that don’t fit this model.
Let’s take the example of a firewall rule that isn’t managed via code. These types of resources usually get manually created because of an email, then forgotten. If there is a comment field, or even just a name field, you can add a string like “rfc1234”, and this serves as a pointer or breadcrumb for someone to find more information. Over time, this tiny habit will increase velocity and decrease errors because these non-code resources are usually difficult to manage.
This can be a tricky section, but it’s a great skill to be able to get good at. If you’re a senior engineer looking to go to staff or management, you need this skill.
Since the Goal section is one of the first sections in the RFC, you know it’s going to be read a bit more than others, so you should make sure it is well-written. In this context, “well-written” means two things:
- First, it must be very clear. Think of an “elevator pitch”. If you explain the goal to someone and they don’t immediately understand the goal, you might need to make an edit. You’ll know you hit the sweet spot when a close stakeholder (an engineer working directly on the project) reads the goal and respond “of course, that’s obvious”, and when a more distant stakeholder (engineer on another team; product manager; business exec) reads it and says “this makes sense”. I mention this because you, as the author, will almost always feel like the goal is “too obvious”, because you have so much context around the project, but you need to explain it for people who have less context than you.
- The other key element of “well-written” is that it should be terse. The goal is often just a few sentences. Resist the urge to put too much detail. As the author, you’ll have a huge amount of context, but you must avoid overwhelming people who are just looking to understand the big picture before getting into details.
My suggestion is to try and use the following format: “We need to A, because B, so that we can C, which is in line with D” where D is some kind of obvious company goal like “provide sufficient uptime to our customers”. As an example, “we need to ensure our order API pods have enough resources to stay healthy. The impact of this will be a reduction in downtime, so that our customers can keep placing orders.”
This section often benefits from having a high-level diagram, but if the diagram is more than ~5 boxes, it might be too much detail. Again, if it’s “too obvious” to you as the author, it’s probably the right level of detail for someone who is less familiar with the context.
One optional element in this section is explaining what business problems the RFC is not intending to solve. This element may or may not be required, but during early draft reviews, you should pay attention to any comments like “oh, you’re doing X? is that going to fix Y?” where Y is some “logically adjacent” business problem. The bigger the scope of your project, the more room there is for misunderstanding. It’s a bit of a self-inflicted mistake if someone thinks that you’re solving a problem that you’re not. Either you’ll look bad, or someone else might reprioritize their work based on a misunderstanding.
Almost any meaningful project has multiple people who are involved with it. Make a bulleted list of their names. It helps share credit and ensures that you have a handy contact list for the project. This also makes it easy to be sure the right people approve the change.
Explain why this change is needed. Your goal is usually to answer the implicit question “why now?”. If you can articulate why this RFC is relevant now, and what has led up to it becoming relevant, your readers will understand the technical context and the urgency.
This is a section where you can start going into detail. For many RFCs, you can just have a bulleted list of sentences, but for a large RFC, you should have a table of IDs, summaries, and detailed descriptions.
I strongly suggest that if you have a large number of requirements, you should manually number them like R01, R02, etc. Don’t rely on rows in a spreadsheet or an auto-incrementing bulleted list where the IDs can change, because over time you’ll inevitably need to add/delete requirements, and you don’t want “Requirement #3” to point to different things at different times.
Most of the RFC should be written in a fact-based style, but the Recommendation section is where your opinions should be (supported by the facts).
I consider this one of the most important sections. If this is well-written, I know the rest of the document can probably be trusted.
In general the purpose of this section is to show you did your homework and didn’t just pick the first idea that came to mind. Sometimes there’s truly only one option and the RFC is required to document it. If that’s the case, write “There are no alternatives”. Usually there are some other options, and you should include enough detail to explain what the option is and why is it not a fit. This can sometimes be accomplished in a few sentences.
If you have to make a tough choice between multiple good options, this section may need to be longer to explain the nuance of why you’re making a certain recommendation. You should support this documentation with in-person conversations, prototypes, and other approaches.
Although I consider this an important section to show your thoroughness, you don’t need to go full ad absurdum. If there’s a possible solution that you expect a reader to think of, but it has an obvious shortcoming, you can write a sentence or two to address it. But as a contrasting example, if you’re considering a new database, you shouldn’t feel the need to do an analysis of every database on the market. Even for a very complex project, you’d probably have 3-5 options that you deeply consider, and as long as you document how you filtered down to those 3-5 options, that is sufficient for most situations.
If you want to go deeper on RFCs, check out the Pragmatic Programmer’s writeup on the subject which includes other templates that you can use for inspiration.