Ricardo Čerljenko
Posted on October 5, 2020
Coming from a company that has multiple backend developers and even more ongoing projects, it's a normal situation that developers are shared between multiple projects. From the developers point of view that's not the ideal scenario because there will always be a "context switch" time penalty where you have to disengage yourself from you current state of mind and integrate your focus to a completely new project. That includes reading the user stories and tasks that are left to be done on this new project as well as understanding the code itself that the previous developer left on.
While we can't do much about the first part where your teammates must somehow onboard you to the new project, there are some things that we can do with our codebase so that any developer in the company can understand it with ease. Over the past few years we figured out that some developers find it very hard to continue on someone else's code if they vary a lot in coding style - it somehow feels unnatural and wrong don't you agree? There's also a problem of structuring your codebase, especially when you're working with frameworks such as Laravel where you have a multiple ways to achieve the same thing.
Here are some pieces of advice on how we can minimize the differences between coding styles and project structures that we implemented over the past few years.
1. Master project template
In our company we have around 15 developers in three developer divisions: Backend Development (Laravel PHP Framework), Frontend Web Development (Nuxt.js Framework) and Mobile App Development (React Native). Imagine that every developer starts it's project completely on its own without any guidelines and completely from scratch every time. It would be a mess out there. No one could jump in in the middle of the project and continue to work without that person sitting by its side.
Instead, let's create a "Master template" (some companies call that "skeleton project" or "base template") which will be a starting point for all future projects of that division. So in our case, we have a Laravel, Nuxt.js, and React Native master templates and all projects originate from them. Master templates have to be maintained (usually by a team lead) and updated from time to time especially when a new framework version gets out. Templates contain everything that you need to start a fresh new project (eg. UI kit, auth, base controllers and logic, database setup, settings, user management, ...).
Once every developer gets familiarized with the template it's a lot easier to switch to a new project because you know where you can find your Models, Controllers, Custom logic, etc.
2. Enforce coding style
Every developer has its coding style which can be a problem in a shared project sense. Some tools that can help you set up a set of rules that developers have to obey in their coding. You have to think in a way to achieve a silver lining so that most of the team is satisfied with that.
PHP
One of the most popular tools in PHP is PHP Coding Standards Fixer. You can read all about it in the documentation but at this point the developer would have to manually fix its code once in a while. Down the road we'll learn how we can achieve that automatically.
JavaScript
For JS we chose Prettier, one of the most popular libraries for JS code formatting. Again at this point developer should also do this manually once in a while.
Both tools have their own set of rules which I strongly encourage you to take a look at (especially PHP CS Fixer) and tweak it to your needs.
3. Static analysis of the code
This step is the important one. We can leverage from the tool called Larastan which is basically a wrapper for PHPStan with Laravel specific config. The tool will perform a static analysis of our code and find out if we have some errors that we simply didn't catch but they will pop up in the runtime for sure and crash our app.
Like in the steps above, the developer has to do that manually in order to scan the code.
4. Combine and automate
Wouldn't be nice if we could completely automate steps 2. and 3. before every git commit? Yes we can and that's exactly what we're going to do. Before every commit, we're going to scan our entire code, fix the coding style according to our rule set in both PHP and JS, and run the static analysis of the code to catch any hidden errors. On top of that if any of that step catches something, we're not going to let the commit to happen. Instead, we'll force the user to fix the errors and repeat the commit again.
First, we need to set up our "pre-commit" hook that will react every time user wants to commit something. The easiest way for that is to use the package called brainmaestro/composer-git-hooks. The package has installation instructions that allows you to add a custom git hooks on some events like "pre-commit".
After including the package in your composer.json
file you should update your scripts
section and add something like this:
"post-install-cmd": "cghooks add --ignore-lock",
"post-update-cmd": "cghooks update"
It means that the hooks will be updated after each composer install
and composer update
events. While we're here, for the ease of this example, we could also add our custom scripts for steps 2. and 3. like so:
"check-format": "php-cs-fixer fix --dry-run",
"format": "php-cs-fixer fix",
"analyse": "phpstan analyse"
And in package.json
for the JS fixer:
"check-format": "prettier --check resources/assets/js/**/*.js",
"format": "prettier --write resources/assets/js/**/*.js"
With that few scripts we can do this now:
# scans the PHP code and reports for invalid coding style
composer check-format
# fixes the invalid PHP coding style
composer format
# scans the JS code and reports for invalid coding style
npm run check-format
# fixes the invalid JS coding style
npm run format
# runs static code analysis
composer analyse
And now we need to instruct our script what to do when a pre-commit event happens. Let's create a custom script that will automate all of the steps above. First, add the target script in the extra
section of the composer.json
just like in the documentation of the Composer Git Hooks package:
"extra": {
"laravel": {
"dont-discover": []
},
"hooks": {
"pre-commit": "./pre-commit.sh"
}
},
And now create and populate the contents of the pre-commit.sh
script:
#!/bin/bash
npm run check-format
PRETTIER_EXIT_CODE=$?
if [ $PRETTIER_EXIT_CODE -ne 0 ]
then
npm run format
fi
composer check-format
CS_FIXER_EXIT_CODE=$?
if [ $CS_FIXER_EXIT_CODE -ne 0 ]
then
composer format
fi
composer analyse
PHP_STAN_EXIT_CODE=$?
if [ $PRETTIER_EXIT_CODE -ne 0 ] || [ $CS_FIXER_EXIT_CODE -ne 0 ] || [ $PHP_STAN_EXIT_CODE -ne 0 ]
then
exit -1
fi
In English the script does this:
- Check JS coding style
- If there's something to fix, fix it
- Check PHP coding style
- If there's something to fix, fix it
- Perform the static analysis on the code
- Exit with
-1
if any of the steps above reported an error
When pre-commit hook exits with an exit code different than 0
it cancels the commit and user has to do it again (or fix the code first).
Conclusion
Hope you had some insight into how we manage to keep our coding style and project base the same across multiple projects and developers. This can be further upgraded to third party systems like Git Actions or StyleCI and also you can completely customize it to your needs with custom rules and regulations.
Thank you for reading this! If you've found this interesting, consider leaving a ❤️, 🦄, and of course, share and comment your thoughts!
Lloyds is available for partnerships and open for new projects. If you want to know more about us, click here.
Posted on October 5, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.