Tips to make your codebase future developer friendly
Starting to work on a new codebase is always exciting. You know your programming language, but you don't know the codebase. Getting up to speed is a challenge. And even a bigger challenge when your predecessor didn't leave a clean codebase. Hopefully you can use these tips and tricks to become that appreciated predecessor.
Language version constraints
Which language version do you need? Maybe it’s somewhere in a README file and hopefully that one is up-to-date. Not very reliable.
The dependency manager can help you with this. The language is a dependency of your app, like frameworks and packages. Add a version constraint to your dependency file. When you try to install the dependencies it will fail when the installed language version doesn’t match the constraints.
Composer supports both the language version and required extensions. Documentation
// composer.json
"require": {
"php": "~8.0",
"ext-dom": "*",
"ext-json": "*",
...
}
Yarn and NPM can do the same. Documentation
// package.json
"engines": {
"node": "~16"
},
Deploy automatically
Getting code correctly on the right server(s) can be tricky. Doing it manually can easily cause errors. Especially when in a hurry. By automating it, a lot of risks can be eliminated. Even if it’s a small or old project. It greatly reduces the chance of having errors.
An example. One of our projects needs a .htaccess
file on a specific location. (It’s the best solution for this situation 🤷♂️) We created a separate deploy workflow for it. In this case the workflow file is way longer then the single file it deploys. But it’s a critical part of the system and nobody wants to think about it. So we automated it.
The tools we use:
- Deployer to deploy PHP projects.
- GitHub Actions to run the tools with workflows, triggered by events in GitHub like push and tag. How GRRR uses GitHub Actions
- Serverless to deploy Lambda functions.
- Bref to give Serverless PHP support.
- Terraform to manage infrastructure.
Code style
In 2020, we decided to use Prettier for our all codebases. It’s an opinionated code formatter, so take it or leave it. We took it because we prefer consistent code style over the ability to tweak code style. Or have code style rules that can’t be automatically enforced. prettier --check .
runs on every push and offloads code style responsibility from the developer to Prettier.
Beside the out of the box Javascript, JSON and YAML support. We use plugins for sorting imports statements, PHP and Go templates.
Static analysis
Static analysis tools can find issues in your code and help you to write more robust code. We use PHPStan for PHP projects. It runs on every push and fails when it finds issues.
Should you immediately get everything to the highest level? No, that’s not realistic and useful. Start with a low level. Overtime you can decide to set a higher level. We pick a level with a reasonable amount of errors, add them to an ignore file and fix them when we are working on the project.
For one big project we run PHPStan on level 7 with a baseline file that ignores 2500 errors. PHPStan generates that baseline file for us and when an ignored error doesn’t occur anymore it fails. So PHPStan enforces a clean list of ignored errors.
We wrote about PHPStan on this blog earlier.
Sort lists alphabetically
Sort lists of things in your codebase alphabetically. What are those “things”? You can think of constants, classes, routes, you name it. Very often those lists are sorted “logically”. But what is logical? It’s different for every developer. And it’s not always clear what the logic is. So sort them alphabetically. Add comments when more explanation is necessary.
It’s easier for developers to read. It’s immediately clear where to add new entries. And, as a bonus, Git conflicts are less likely to happen and easier to solve.
README file
Add a README file to your codebase. It’s an easy starting point for developers. Topics you can add to a README file:
- information about the stack such as language, framework, database versions
- how the project came about
- link to the documentation
- link to the designs
- link to the ticketing system
- how to set up the project locally
- how to create a new user
- how to run tests
- how to seed data
Keep in mind that the README file is a starting point. Always write with the assumption that the reader doesn’t know anything about the project.
Solve warnings
A warning is usually not a problem, because it’s not an error. But there is a reason tools give warnings. For example a deprecation warning tells you to stop using something, because it will be removed in the next release. Every warning can cause confusion which takes precious development time.
If you know how to solve it, solve it. Or at least document it in the README file, at the “set up the project” section. So other developers don’t waste time on figuring out whether the warning is an actual problem.
Add a working .env.example file
Save time setting up the project by giving environment variables a developer friendly default value. I try to limit it for Laravel applications to DB_*
and APP_KEY
. The others are optional. So use the log driver for e-mails instead of requiring the developer to set up an email service. Use the array cache driver. Use the sync driver for the queue. And disable external services when not configured instead of failing.
When a developer starts to work on a part of the application that requires a specific service, they can enable it.
Unit tests
Unit tests are great to ensure code keeps doing what is has to do. That’s the primary function, but there’s another one in my opinion. I see unit tests as documentation. Reading the unit tests gives me a lot of insight into the project and its features.
When writing a unit test try to write a story. Try to focus on features not on classes and coverage percentages.
Comments
Code should be easy to understand, with nice variable names and clear function names. But let’s be honest, sometimes it’s just not. Complex business rules, backwards compatibility, legacy code, it can all cause code that’s hard to understand. In those cases comments can help a lot. Figure out why it’s the way it is and add a comment.
There’s no limit to the length of comments. If you need 300 words to explain something, go for it. It takes the next developer less time to read those 300 words than figuring out what you just found out.
Use long flags in shell scripts
Who knows what tar -xzf file.tar.gz .
does? I don’t. I have to look it up every time. I prefer tar --extract --gzip --file file.tar.gz --directory .
. So when you write a shell script use the long flags. It’s easier to read and understand for the next developer.
That’s it. I hope this will save you, your colleagues and successors a ton of time. Happy coding!