what’s this about?
In general, it’s gone pretty well—we’ve managed to communicate well, keep on top of things, and deliver the intended features quite rapidly. However there has been one recurring problem that “slightly” soured my mood. That problem is the occurrence of regressions.
Regressions typically occur when code modifications from multiple team members conflict, often very subtly. In this particular project, a freshly-started one with a lot of web-based front-end work, various circumstances intensified the risk:
- The rapid nature of the work.
- The lack of pre-established application structure, leading to constant refactoring as part of feature development.
- Differing hours, reducing the ease of quick communication.
As I said before, none of this was insurmountable, though it did cause frustration at times. But what were the lessons – how could the frustration be reduced in the future?
(Please note: this list is somewhat Git-specific, and also intended as much for my own consumption as anyone else’s.)
Obviously the best way to have confidence that the application has not been broken is to test it. Automatically. From the UI to the API.
Sadly, we literally did not have time to do that in this case.
Fortunately, I’m 90% sure that the amount of time lost to regression fixing in the two weeks was still less than the time that would have been needed to establish and maintain these tests, given our collective lack of experience with the specifics. So at least it’s nothing worth feeling too bad about in this case (although it must still be a priority before the project can be called “maintainable”).
The amount of time wasted could still have been less, however. So what practices might we observe for reducing regression risk, in the high-risk environment of untested code?
version control is the finish line
A feature is not finished when the code is written. It is finished when the code is on the master branch and all code on the master branch still works.
This means that the merge is basically the most critical operation of the whole feature, with the ability to doom the whole thing to technical failure in one step. Or, to put it backwards and/or over-simply, an easy merge means a happy life.
By this I mean:
- Commit frequently, so you know what you’ve done / what you were thinking.
- Push frequently (to a feature branch) so your team-mates know what you’re about to do.
If everything is always pushed, not only is your work protected from sudden laptop explosions and unexpected relocation, your teammates can in idle/contemplative moments have a quick look at your branch (or even do speculative merges!) to find out what’s about to break/conflict and solve it through early discussion.
keep things tidy
This really means two things:
Keep master sane!
- Don’t merge anything in that you already know is flawed, except in genuine emergencies (where the commit should be properly logged as BREAKING or TODO… or BODGE… CRAP… or whatever).
- Do interactively rebase/squash before merging feature branches in, where possible—an easy-to-read history is probably one of the easiest ways to make the whole project look better.
Keep master current!
Quite often while working on a feature, it’s easy to spot a bug or style problem that’s immediately fixable. This is clearly an excellent idea—best to keep the code quality high whenever possible.
The mistake at this point, which we’ve all at some point made due to natural laziness, is to just fix it and keep working. No. Make it a separate commit (so it’s easy to spot and to merge against), and get it into master now!!!
This rule applies whenever you do any non-breaking fix or improvement. Branches are for speculative, incomplete work. Master is for the current best code. There should be no exceptions to this—almost every breaking conflict we just had originated with a formatting fix that wasn’t clearly logged or wasn’t merged soon enough.
The reason is, if fixes go straight to master, it’s clear to everyone else that they should be taken into account immediately. On the other hand, if they stay rotting on a feature branch, someone else might well push code in the meantime, unaware of your improvement, and then it is suddenly your responsibility to both understand their changes and remember/reapply your fix, when your branch goes in later.
pull even more often!
The converse of the earlier point about publishing fast is that in an idle/contemplative moments, the best way to fill in keyboard time is to do the opposite—git fetch and see if anyone else just did anything / if any surprises are coming up. Again—it’s best to know as soon as possible.
So those were my conclusions drawn from the most irritating moments of the last week. I hope to remember to follow these rules myself in the future.
Does anyone else have any different opinions / comments / suggestions? Please comment etc. Cheers!