web/blog/2023-12-05-writing-rfcs.mdx
import { ImgWithCaption } from './components/ImgWithCaption'
Imagine you’ve been tasked to implement a sizeable new feature for the product you’re working on. That’s the opportunity you’ve been waiting for - everybody will see what a 10x developer you are! You open a list of the coolest new libraries and design patterns you’ve wanted to try out and get right into it, full “basement” mode. One week later, you victoriously emerge and present your perfect pull request!
But then, the senior dev in a team immediately rejects it - “Too complex, you should have simply used library X and reused Y.”. What!? Before you know it, you’re looking at 100 comments on your PR and days of refactoring to follow.
If only there were a way of knowing about X and Y before implementing everything. Well, it is, and it’s called RFC!
We’ll learn about it through the example of RFC about implementing an authentication system in a web framework Wasp. Wasp is a full-stack web framework built on top of React, Node.js and Prisma. It is used by MAGE, a free GPT-powered codebase generator, which has been used to start over 30,000 applications.
Let's dive in!
RFC (Request For Comments) is, simply explained, a document proposing a codebase change to solve a specific problem. Its main purpose is to find the best way to solve a problem, as a team effort, before the implementation starts. RFCs were first adopted by the open-source community, but today, they are used in almost any type of developer organization.
There are other names for this type of document you might encounter in the industry, like TDD (Technical Design Document) or SDD (Software Design Document). Some people argue over the distinction between them, but we won’t.
Fun fact: RFCs were invented by IETF (Internet Engineering Task Force), the engineering organization behind some of the most important internet standards and protocols we use today, like TCP/IP! Not too shabby, right?
So, why bother writing about what you will eventually code, instead of saving time and simply doing it? If you’re dealing with a bug or a relatively simple feature, where it’s very clear what you must do and doesn’t affect project structure, then there’s no need for an RFC - fire up that IDE and get cracking!
But, if you are introducing a completely new concept (e.g., introducing a role-based permission system) or altering the project’s architecture (e.g., adding support for running background jobs), then you might want to take a step back before typing git checkout -b my-new-feature and diving into that sweet coding zone.
All the above being said, sometimes it's not easy to figure out if you should write an RFC or not. Maybe it’s a more prominent feature, but you’ve done something similar before, and you’ve already mapped everything out in your head and pretty much have no questions. To help with that, here’s a simple heuristic I like to use: Is there more than one obvious way to implement this feature? Is there a new library/service we have to pick? If the answer to both of these is “No", you probably don’t need an RFC. Otherwise, there’s a discussion to be had, and RFC is the way to do it.
We’ve established how to decide when to write an RFC, but here is also why you should do it:
Wow, this sounds so good that I want to come up with a new feature right now just so I can write an RFC for it! Joke aside, going through with the RFC first makes the coding part so much more enjoyable - you know exactly what you need to do, and you don’t need to question your approach and how it will be received once you create that PR.
Glad you asked! Many different formats are being used, more or less formal, but I prefer to keep it simple. RFCs that we write at Wasp don’t follow a strict format, but there are some common parts:
That’s pretty much the gist of it! Each of these can be further broken down and refined, but this is the basic outline you can start with.
Let’s now go over each of these and see what they look like in practice, on our Authentication in Wasp example.
This one is pretty self-explanatory - you will want to track some basic info about your RFCs - status, date of creation, etc.
Some templates also explicitly list the reviewers and the status of their “approval” of the RFC, similar to the PR review process - we don’t have it since we’re a small team where communication happens fast, but it can be handy for larger teams where not everybody knows everybody, and you want to have a bit more of a process in place (e.g. when mentoring junior developers).
This is where things get interesting. The better you define the problem or the goal/feature you need to implement, and why you need to do it, the easier all the following steps will be. So this is something worth investing in even before you start writing your RFC - make sure you talk to all the involved parties (e.g., product owner, other developers, and even users) to refine your understanding of the issue you’re about to tackle.
By doing this, you will also very likely get first hints and pointers on the possible solutions, and develop a rough sense of the problem space you’re in.
Here are a few tips from the example above:
If you did all this, you’re already well on your way to the excellent RFC! Since defining the problem well is essential, don’t be afraid to add more to it and break things down further.
This is the sub-section of the "Problem" or "Goal" section that can sometimes be super valuable. Writing what we don't want or will not be doing in this codebase change can help set the expectations and better define its scope.
For example, if we are working on adding a role-based authentication system to our app, people might assume that we will also build some sort of an admin panel for it to manage users and add/remove roles. By explicitly stating it won't be done (and briefly explaining why - not needed, it would take too long, it will be done in the next iteration, ...), reviewers will get a better understanding of what your goal is and you will skip unnecessary discussion.
Once we know what we want to do, we have to figure out the best way of doing it! You might have already hinted at the possible solution in the Problem section, but now is the moment to dive deeper - research different approaches, evaluate their pros and cons, and sketch how they could fit into the existing system.
This section is probably the most free-form of all - since it highly depends on the nature of what you are doing, it doesn’t make sense to impose many restrictions here. You may want to stay at the higher level of, e.g., system architecture, or you may need to dive deep into the code and start writing parts of the code you will need. Due to that, I don’t have an exact format for you to follow, but rather a set of guidelines:
The purpose of RFC is to convey ideas and principles, not production-grade code that compiles and covers all the edge cases. Feel free to invent/imagine/sketch whatever you need (e.g., imagine you already have a function that sends an email and just use it, even if you don’t), and don’t encumber yourself or the reader with the implementation details (unless that’s exactly what the RFC is about).
It’s better to start at the higher level, and then go deeper when you realize you need it or if one of the reviewers suggests it.
How you find this out may differ depending on the type of product you’re developing, but there is almost always a way to do it. If you’re developing an open-source tool like Wasp you can simply check out other popular solutions (that are also open-source) and learn how they did it. If you’re working on a SaaS and need to figure out whether to use cookies or JWTs for the authentication, you likely have some friends who have done it before, and you can ask them. Lastly, simply Google/GPT it.
Why is this so helpful? The reason is that it gives you (and the reviewers) confidence in your solution. If somebody else did it successfully this way, it might be a promising direction. It also might help you discover approaches you haven’t thought of before, or serve as a basis on top of which you can build. Of course, never take anything for granted and take into account the specific needs of your situation, but definitely make use of the knowledge and expertise of others.
The main point of RFC is the “C” part, so collaboration (yes, I know it actually stands for "comments"). RFC is not a test where you have to get the perfect score and have no questions asked - if that happens, you probably shouldn’t have written it in the first place.
Solving a problem is a team effort, and you’re just the person taking the first stab at it and pushing things forward. Your task is to lay as much groundwork as you reasonably can (refine the problem, explore multiple approaches to solving it, identify new subproblems that came to light) so the reviewers can quickly grasp the status and provide efficient feedback, directed where it’s needed the most.
The main job of your RFC is to identify the most important problems and direct the reviewer’s attention to them, not solve them.
The RFC you’re writing should be looked at as a discussion area and a work-in-progress, not a piece of art that has to be perfected before it’s displayed in front of the audience.
In this final section of the document, you can summarise the main thoughts and highlight the biggest open questions. After going through everything, it can be helpful for the reader to be reminded of where his attention can be most valuable.
Of course! As mentioned, our format is extremely lightweight, but feel free to take a look at the RFC we used as an example to get inspired. Your company could also already have a ready template they recommend.
Here are a few you can use and/or adapt to your needs:
The exact tool you’re using is probably the least important part of RFC-ing, but it still matters since it sets the workflow around it. If your company has already selected a tool, then of course stick with that. If not, here are the most common choices I’ve come across, along with quick comments:
We currently use Notion, but any of the above can be a good choice.
Just as it is the best practice to write a summary at the end of your RFC, we will do the same here! This article came out longer than I expected, but there were so many things to mention - I hope you'll find it useful!
Finally, being able to clearly express your thoughts, formulate the problem, and objectively analyze the possible solutions, with feedback from the team, is what will help you develop the right thing, which is the ultimate productivity hack. This is how you become a 10x engineer.
And don't forget: Weeks of coding can save you hours of planning.