We at Mews really like RFCs. What started more as an experiment has now become widely adopted. In the first two years, we wrote 50 RFCs(!), making it slightly more than two per month on average. This year (2022), we already see 34 of them – and there’s still a long way to go to the end of the year. We use them mainly (but not exclusively) to explore and propose bigger changes with broader impact, usually beyond the scope of one team. Other usages might be smaller and shorter, such as proposing adoptions of new code rules.
In the last two and half years of writing these documents, we have figured out some practices that help us make writing RFCs successful and enjoyable which I’d like to share with you. But first, let’s clarify what an RFC is.
What is an RFC?
RFC stands for Request for Comments and is a technical document with a standardized structure. The first RFC was written in 1969, and now they are managed by the Internet Engineering Task Force (IETF). If you dig through them, you find out that pretty much the whole Internet and its infrastructure has been defined in these documents for over the course of more than 50 years. What an amazing collection of knowledge!
If you want to learn more about RFCs, this Wiki page might be a good start.
Over the years, a similar practice of writing RFC-like documents has been adopted by many companies and projects to help them align and scale (for example, React). Writing is thinking, as they say, and it helps you see all the details and really polish your ideas. A written document is much easier to share and review than trying to bring every stakeholder into a single room to discuss in person.
If you want to know more about the benefits of writing RFCs and how it could help your company, the Pragmatic Engineer has a great article about it.
Now, let’s move on to the promised practices.
Start with a template
To start writing RFCs, it is a good idea to have a common template first. A template will guide people through the writing process by prescribing what an RFC should contain and giving explanations for each requirement. Having an origin in a shared template ensures that each RFC maintains a similar structure, which makes it easier to review.
Early on, you can take inspiration from existing templates. For example, ReactJS project has a nice and simple one.
Don’t overcomplicate it in the beginning, though. You can always come back and improve the template to suit your needs once you have written a few RFCs and have better insight into what you want them to look like.
Align on a problem
There is nothing worse than your peers and colleagues telling you that the problem you want to solve is not a problem at all after all the time you spent writing your RFC!
It happened to us in the past that we had an RFC fully written, then in review, we couldn’t even agree on the problem itself. This risks the rest of the RFC being thrown away and the time spent writing it becoming a waste. Because of that, we recommend all our authors make sure they have a good problem statement before they dive into writing solutions. Even a slight change in the statement might lead to different solutions becoming viable and vice versa.
An easy way to see if there’s an alignment on a problem or need for a solution is to first talk about it. Raise it in your internal chat channels or at some team meetings. If you get positive feedback, you might be on to something worth solving.
Consider multiple types of RFCs
After we had written several RFCs, we realized that not every RFC comes the same. We had a few big, chunky proposals with detailed examples and algorithms that had a huge impact on how we do things. But we also had some small ones, like proposals for the adoption of newer syntax or settling on more controversial linter rules.
You can see that the size and scope of these RFCs are vastly different. Initially, we were thinking about introducing a distinct type of document to address the difference (like ADR, for example). But that would make things unnecessarily more complex, with differing document names and processes.
Rather than that, we figured out we could solve it simply by introducing multiple RFC templates for the different types of problems we want to address while keeping the existing process the same.
We now keep two templates for two types of RFCs: one is the original for proposing solutions to big problems, while the other is more lightweight and used to settle on smaller decisions (and by the way, we established this in an RFC, too 🙂).
Would you like to write the 35th RFC of the year?
And talk about it with Petr whenever the mood is right?
Invest in RFC organization
Once you have written several RFCs, you might want to address their organization, too.
Just as we require internal structure through templates, we should necessitate some structure of the files themselves. As the collection of RFCs grows, keeping standard names and order will help with their discoverability in the future.
For this, we number each RFC with an ever-increasing number sequence. For now, we keep it to four digits – If we ever get to an RFC 9999, we can easily add more digits. We use this number to prefix a filename of an RFC (e.g., “0042-the-meaning-of-life.md”). This gives us a natural ordering of RFCs by their date of creation.
The second usage is when referring to some other RFC. Instead of remembering a vague title or referring through descriptions (“you know, the RFC about that architectural thing I was writing half a year ago”), you can refer to it directly with the number. If it’s an RFC that’s being referenced often, the number might be well-known and remembered.
If you keep your RFCs organized, you can also build some nice indexes or UI on top of them. For example, we use Guru for internal knowledge management, which supports synchronization with external sources. This way, we can provide access to RFCs (and other tech documents) to the rest of the company with much better UI than with raw GitHub access (where we store the actual documents):
But don’t overstress organization and take all the fun from writing new proposals. It does not need to be perfect and can always (and easily) be fixed later!
Don’t delete RFCs, reject them
Sometimes it can happen that even through all the discussions, arguments, and reviews from your colleagues, you don’t agree on an RFC.
We used to just close pull requests of such RFCs, essentially losing them in GitHub’s pull request history. However, sometimes you want to reference these discussions, especially those arguments on why an RFC wasn’t accepted. Sometimes, other people come up with similar ideas, and you want to point them to these old RFCs so they can go through the old arguments and see if they can continue or if the rejection reasons apply to their ideas too. But how do you do that? The RFC is lost in history and the only way to find it is to dig through closed RFCs. And the only people who know where this RFC is are usually just the authors themselves, and maybe a few others who were involved in the review.
Instead, we want to keep the rejected RFCs around the same way we keep the accepted ones. Well, the answer to that is simple: merge every RFC pull request, whether you agree on the solution or not!
To distinguish between rejected and accepted RFCs in the main branch, we write the outcome just under the title of each RFC in the form “Status: Accepted” or “Status: Rejected.” We also include a link to the RFC’s pull request to keep a quick reference to any related discussions. And now we archive all RFCs in a single place so it’s easier for anybody to explore past ideas and proposals.
I hope you find some of these practices useful and applicable in your company too. And if you are not using RFCs in your company yet, you might want to try them out. It’s an amazing tool for proposing and aligning changes in an organization!