The Secret To Better APIs: You're NOT Using It
Have you ever started a project full of excitement, only to find yourself tangled in a web of confusing code and unclear APIs? You're not alone.
What if I told you there's a secret method that top developers use to create better APIs and smoother projects - a method you're probably not using?
Today I'm going to share with you a little-known technique for better API design: README-Driven Development (RDD).
What is README-Driven Development (RDD)?
So, what exactly is RDD?
It's simple: you write a README before you write any code.
In this README, you describe the API of your code. You write it as if the code, the REST API, the package, the framework - whatever you're building - already exists.
Then, you share your README with your coworkers for job-related projects or with friends for side projects, so they can provide feedback. You improve the README based on their input. Repeat this process until everyone is happy with the API and all possible edge cases have been addressed.
RDD often goes hand-in-hand with Test-Driven Development (TDD). You capture your API in your tests, and then you write the code to make those tests pass.
Here's how it works:
- Write the API in the README as if it already exists.
- Get feedback from your coworkers and implement it.
- Capture the API by writing tests.
- Write the code to make the tests pass.
Why RDD?
RDD has a ton of benefits:
- Design First Approach: It forces you to think about the inputs and the outputs first. By focusing on the API upfront, you prevent implementation details from leaking into your API design.
- Early Feedback Loop: Writing out the API first lets your coworkers critique it and discuss technical design implications. The goal is to come up with an API that offers the best developer experience.
- Clarity of Purpose: RDD helps to define the purpose and scope of the project from the start. This clarity reduces bugs caused by a misunderstanding of the feature being built. It can also prevent scope creep, keeping the project focused on its intended goals.
- Avoids Redundant Work: By solidifying the API upfront, you can avoid the redundant work of rewriting code to change the API later, when changes can be more costly and complex. When you think about all edge cases early, you can avoid unnecessary rework.
- Better Documentation: By focusing on the README first, you ensure that documentation is NOT an afterthought but a core part of the development process. This leads to better, more comprehensive documentation that benefits users and maintainers.
- Onboarding Efficiency: A well-documented codebase with a clear README makes it easier for new team members to understand the project quickly, significantly reducing the onboarding time.
- Enables Parallelization: When you write the documentation first, teams can work in parallel because everyone knows what to expect from each other.
In other words, RDD aligns closely with a fundamental principle in software development:
“Program to an interface, not an implementation.” - Gang of Four
What To Include In The README?
Include everything that a normal README would include:
- Features: List the features of your project. Write down why you're creating it and what problems you're solving. This helps users - and yourself - understand what the project should be able to do. Based on these features, you can plan your API.
- Installation Instructions: Include how to install your package or library. If your module depends on other packages, list the dependencies.
- Usage Examples: Show how to use your package or library and what configuration options are available.
- API Documentation: Include the API of your package or library. Make sure you cover common use cases. This is similar to the usage examples but helps you think about the API from different perspectives, like the user and the developer.
- Contributing: Explain how to contribute to your package or library. When working on an internal development team, you can capture or challenge existing development processes.
- License: Include the license of your package or library.
RDD Example
Let's look at an example.
Suppose you want to create a simple package that allows you to generate random integers.
Step 1: Write the README
First, you capture what your project should do and what problems its features solve.
Again, this step helps you to be clear about the scope of your project.
Once you figured out what you want to do, you want to show your users how they get started and how they can use your project. So, include the missing sections like installation instructions, usage examples, API documentation, contributing, and license.
Step 2: Get Feedback
Now, let's say you take your README to your coworkers so they can critique it.
Your coworkers point out a few ways to improve the random integer generator:
- You should be able to call the
generateRandomInteger
function without arguments. - It should have a default range of 0 to 100.
- It should take named parameters using an options object.
- Lastly, it should be a named export, so you can easily add more functions in the future.
You agree with your coworkers and update the README. Your full README now looks like this:
You show your coworkers the updated README, and they're happy with it.
Step 3: Write the Tests
Now, it's time to create your project so you can write some code.
Add your README.md
to the project.
Then install your testing library of choice. In this case, we will use Vitest.
Add a test command to your package.json
.
Now you can write your tests in index.test.js
.
A good technique to write tests for a function with random output, is by calling it many times and checking that the results conform to the expected behavior.
Export an empty function in index.js
.
Now run your tests and watch them fail.
You'll see that the tests fail because the function doesn't do anything yet.
Step 4: Write the Code to Make the Tests Pass
Now, it's time to implement the code that fulfills the README and passes the tests.
Vitest runs in watch mode by default, so once you hit save, the tests will run again, and you can see that they pass.
When To Use RDD?
There are two main scenarios where RDD can be helpful:
1.) When there's a complex API that you need to get right, usually used by many stakeholders.
- Open Source Projects: When you're working on a team and want to offer something as open source. For example, an SDK that connects to the service you're building.
- Internal Libraries: If you're building an internal tool that will be used by multiple teams in your company, it's important to get the API right and receive feedback from your future users - your teammates.
- Complex Subsystems: When working on an app or service where multiple components interact, RDD helps outline how these components will work together, promoting better understanding and consistency across the system and your team.
2.) When large cross-functional teams need to work in parallel, and you want to make sure one team isn't blocked by another.
For example, the backend team can use RDD for their API, allowing the frontend team to know exactly what requests and responses will look like.
Trade-offs
You might be asking:
"Doesn't this take more time?"
Yes, it does ... sort of.
Writing the README and asking teammates for feedback adds an extra step, making this approach initially slower than regular development.
But think about it: you'll need to discuss your code with the team anyway. So, is it really costing extra time? And why not use a streamlined, developer-friendly process? On the other hand, RDD offers a high return on investment under the right circumstances.
When working solo, there's no need for RDD unless you want to use it to plan a tool or service that you're building. Otherwise, when you're working alone and doing TDD, RDD adds little value since you already benefit from better API design by writing your tests first.
Be Careful of Scope Creep
Once you have your README for your dream API for your 10x vision that handles every edge case you and your coworkers or friends can think of, it's important to decide the order in which you'll implement features.
Think of it like building a startup: capture the big vision first, but start by building the MVP (Minimum Viable Product). Focus on the core functionality for version 1, and plan to add additional features in future releases.
Also, don't be afraid to push back if too many people want to add extra features or edge cases. It's perfectly fine to scope your project to do certain use cases well in the first version and leave the additional functionality for later.
Why You're Not Using RDD
Many developers skip RDD because:
- They've Never Heard of It: It's less widely discussed than other methodologies.
- Eager to Code: The excitement of coding can overshadow planning.
Now that you're in on the secret, you know when and how you can use RDD to build better APIs and drive more successful projects.
Before you start your next project, launch a new feature, or create a new library, take a moment to write the README first. It might feel a bit unusual at first, but the benefits are substantial.