Every new project is an opportunity to improve and get challenged. Might it be your skills, your processes, your performance, etc. We previously wrote about how important it is to learn from big projects. It is important to understand that you can't find the perfect way of working, but you can definitely reach an optimal workflow, that you will keep on iterating and improve project after project. Allow me to share ours with you.
Part of the success of a project is to maintain a very good communication setup between all the active parts. I am not saying anything new here: emails, wiki documentation, a conference calls, you name it, have plenty of "good practices" to dictate how we should use them. But there's a but. Have you ever thought about the passive communication? The one that is hidden in code, in consensuses, in flows. In this final part of our "coding as a team" series, we will tell you some small tricks we use to box passive, micro-communication within a project.
Branching model
Unsurprisingly, we use the git flow model. There isn't much science behind it, but it is a pretty much standardised practice, so any developer involved in a project will quickly be aligned on the development of features, hotfixes or releases. Everyone will use the same flow and structure, which will make the merges a lot more atomic.
It is also important that, besides having a good flow, we keep good practices in... practice. That is, pull often, commit often, push often. This will reduce drastically the amount of potential conflicts. And please, oh please, don't create pull requests that bundle code for different functionalities, or integrate solutions for completely different problems. Your co-workers will be grateful.
Organising your code
Having a proper folder structure is very important, especially on large code bases. Drupal, specifically makes it easy with a clean folder structure from the start. You should, for example, leverage the profiles approach that enforces a folder structure, besides building every site re-buildable.
Remember, code layout is the omnipresent structural documentation for any new developer that is brought into the project. Having good .info files, a rich README.md in each feature or module serving as a piece of technical documentation, is very critical. Bear in mind that your team will be looking at these files first, to get a clear overview, before diving into the actual code. The crucial point is that nobody gets lost in the code base, and can understand it more or less autonomously.
Another fundamental point in good code organisation is to streamline semantically and syntactically the nomenclature of your modules, their components such as fields, views, flags, you name it. Scoping your code and exported configuration with consistent names will remove the overhead of jumping left and right to find it.
At Marzee Labs, we progressively built up our way to organise the code. We are now satisfied with the stable solution we came up with, that helps streamline development, even so when including external collaborators. For the sake of exemplifying but a part of it, let's say you are working in a project called "Train Maps". In a Drupal context, your features or custom modules, and entity/node types will follow the guidelines below:
- Any feature or custom module will be prefixed with tm_.
- There should be a base feature where the meta information, platform configuration and continuous integration code should live. We can call it tm_site or tm_base.
- Have a feature per content type, and standardise on nomenclature, i.e. if you use tm_train, then you'll use tm_station. If you prefer use tm_trains, then keep on using the plural for tm_stations.
Fields are as important as the rest, so make sure you prefix them all to reflect the context they are used in. In the case of content type, for example, we'd have field_train_destination, field_station_location, etc. But even the ones that are site-wide and re-usable should be prefixed to avoid any issue, e.g. field_tm_company. In Drupal, we'd have all the field instances exported to the feature they belong to, as well as field bases if they are feature specific. In case they are site-wide, we would put them in the feature tm_field (or tm_fields, to your taste). This way, it's easy to move them around, and make them reusable if needed.
Code review
There are plenty of great write-ups on how code reviews benefits a team. There are no rules about how to do it whatsoever, but it is important to understand why we do it.
My two only guidelines are the following: 1. Do it. No excuses. If you are by your own, do it anyway. 2. Make it count. If it becomes a formality of having someone else just hitting the merge button, then you are missing the point.
Remember, code reviews aren't meant to point fingers, debate code styles, or test confidence. Code reviewing is ensuring first and above all code quality and, by extension, security. Being human, you'll make mistakes, no matter how experienced you are. So a second pair of eyes is always better. And even then, bugs can still get merged and even go on production. But then again that's the whole point: you improve and learn together, next time you'll be on the lookout.
Having a second person involved, even if passively, in the code you write has many benefits. Not only it will widen the team understanding about the bigger picture of the code, but it will also avoid isolating developers on specific corners of the code. This is of great value, as they might need the same auxiliary methods you just built, and will re-use them in the future, and avoid code duplication, in particular on large code bases.
Not to mention that if tomorrow you go on holidays, or get hit by a bus, someone can take over your work without being lost and starting from ground zero. This is why it's so important that you carefully pick who reviews your code, might it be to validate it or learn from it.
In practice, we use GitHub's own workflow and interface to get it done. The fact we can either write both general and in-line comments makes a pull request page an invaluable piece of documentation on who has been through that code - either by writing or reviewing it -, what decisions or tweaks were made, and why.
Bonus: pair programming
Pair programming is great. If you haven't tried it, you should. It has all the benefits of code reviews, but instead of discussing potential drawbacks once a solution is already done, you actually build it together. Start by being the one driving and having someone sitting on your side and unlocking you. Sometimes, borrowing a fresh pair of eyes can unstuck you in less than 5 minutes. Don't feel guilty. That's exactly what pair programming is all about. The day will come when you will be the one called up and saying "been there, done that"!
We can extend pair programming to actually prepare what we are about to code in pairs. That is, the developers will talk through their implementation plan. It's a great exercise, not only because you get instant feedback but also you do a verbalisation of what's in your head.
Coding as a team
During this series, we've seen how automation, continuous build, and solid flows are crucial to successful development.
Everything must start before you even type a line of code. The preparation phase is utterly important, and must be repeated prior each sprint. It goes from good architecture layout to efficient tasks splitting.
Optimise what makes sense, but don't overdo it. Always remember to use techniques and tools to serve your needs. Don't get enslaved by them.