A couple of weeks ago we talked about intelligently compromising development and how engineering is the art of intelligent compromise. This week we are going to continue on the same vein by talking about intelligently uncompromising development, i.e. those things you can’t afford to compromise on or to put it better, those things that should have a higher bar of when they can be compromised on.
and they are probably not what you’d expect…
Contrary to the naive view most non-functional requirements in software engineering are open to some sort of compromise—I’m leaving functional requirements out as that is another can of worms that involves your product manager, your client and possibly a bunch of other stakeholders as well. You don’t need to guarantee a 99.9% SLA on a service that runs two batch jobs a day and you probably don’t need sub 50ms latencies on an API that only serves another back-end service that trawls it once a day. Those examples are obviously a bit contrived, but the idea should be obvious. You look at what you are trying to achieve and then devise reasonable requirements with reasonable compromises in order to accomplish your goals.
There are some things though where you can’t really afford to compromise. There are generally two reasons for this. First, there are the kinds of issues where compromising even on the short term will end up making your life immediately harder. Second, there are the kinds of issues where compromising will come back to bite you hard down the line.
and they are called testing and code quality…
Imagine writing a fix for a particularly gnarly part of the code-base. This is a client facing issue and you are on a deadline. You think you don’t have time to make it pretty, just enough to make it work, so you hack together a fix with a mental note or a TODO to refactor this code at some later point in time and call it a day. You’ve taken care of the issue and you can go back to working on your feature now.
There are just a couple of problems with this…
- First, that magical “later point in time” will likely never come. There is usually only one direction the amount of pending work goes and that is not down.
- Second, there are very few changes you can make to code without fully understanding exactly what that code does and they tend to be of the very trivial and superficial kind. Delegating this sort of refactoring for a later point in time means that you have to go again through the effort of understanding how that code works which means the task will take longer.
- That brings us to the last point which is code base understanding or lack thereof. Gnarly code is code that is hard to read and by extension code that is likely to have bugs hiding in it, because it’s hard for people to reason about it. If you don’t do something to improve it then that time you just spend on a tight deadline trying to wrap your head around it, is time you are going to have to spend again when the next bug surfaces itself. You’ll probably be on a deadline then as well.
Now let’s imagine writing a fix for a particularly gnarly part of the code-base. This is a client facing issue and you are on a deadline. You think you don’t have time to make it pretty, just enough… blah blah blah… so you don’t write any tests for it with a mental note or a TODO to add some at some later point in time and… blah blah blah… back to working on your feature now.
Getting a bit of a deja-vu? That’s because the problems with this are exactly the same as the above with the addition of one more thing. If you haven’t written a test for your change then you can’t guarantee that you have actually fixed anything except via manual testing and you have absolutely no way to guarantee that you won’t suffer a regression 30 commits later.
“Live code tends to get worse unless an explicit, intentional force is applied against the natural tendency to entropy increase”, Arialdo Martini
When doing research for this article I found the above quote which I believe expresses quite well the point I am trying to make. Every time you take a shortcut when developing you are making the codebase just a little bit worse for the next person and the next person is you and your coworkers. So…
- Code like a perfectionist. There is no magical future time that you will take care of all the corners you are cutting now.
- Apply the boy scout rule. Leave the campsite a little bit cleaner than how you found it.
If you enjoyed the read, drop us a comment below or share the article, follow us on Twitter or subscribe to our #MetaBeers newsletter. Before you go, grab a PDF of the article, and let us know if it’s time we worked together.