Subtitle: how to encourage simple code even if it may slow you down in the short term
Less is More!?
For some time, I’ve had a thought that no source code is the best source code. Obviously it has no bugs and requires no maintenance. An ideal software! Then, with no source code, our product will be super-awesome, right? Of course, not. Because our product (game or whatever kind of software it may be) must do something useful and no source code cannot do anything by its definition. Being useful (including giving an enjoyable experience to users) is raison d’etre of any software product (or of any product, for that matter, I guess).
Fight against the temptation to go easy
From time to time, I mulled over how one can incentivize a short code or a refactoring that makes overall code shorter & simpler. A need for such incentives stems from the fact that a shorter code (providing identical features, of course) often requires both deeper consideration, unremitting diligence and courage and usually takes more time to accomplish. Let’s suppose the task of implementing a feature A has been assigned to you because it was a highest priority among backlog items. While figuring out a best way to implement it, you found out some nasty feature duplication and unnecessarily complected part in relevant modules. Now, you have two choices. One is to finish the feature ASAP by working around or conforming to that bad code (while soothing your guilt by telling yourself “Let’s do the refactoring later,” which more often than not never happens) and get a recognition as a coding ninja. The other is to bite the bullet despite a short-term delay it may induce and do the right thing right away even with the risk of breaking some irrelevant part of the code. You might not be lauded right away as a super achiever (rather can be blamed for missing the deadline or for a temporarily broken build/feature), but in the long run this can save not only your time, but also your colleagues’, whether they become aware of an insidious effect of your effort or not. As for me, I have fallen victim to my impatience, short-sightedness and temptation to go easy more often than I’d like to admit.
It should be measured to be encouraged
One naive metric I can think of is to compute (lines_added - lines_removed)
for each commit and give more points if the result is less. This too simplistic approach won’t work, of course. Especially, at the early phase of a project, no (or very few) refactoring can occur since there isn’t that much code to be cleaned up after all and many code lines should be written and added naturally at this stage. Writing much code at this stage is definitely not a thing to be discouraged. The crucial thing is how much more value the code adds to the product by introducing that many additional lines. The key point is how one can measure so called ‘added value’? Quite tricky, if not impossible, even to define one, not to mention computing it. By the way, a plausible approximation will be enough for our purpose. After all, we’re wanting some ways to incentivize good directions overall rather than calculating some absolute numbers.
Tests as a proxy of added values
In test-driven development, each meaningful feature (whether that is a small function in the case of unit-testing or an actual feature for users under a high-level functional test) should have a corresponding test set. So an idea I recently came to my mind is to use the size of test code as an approximation for the added value. Then, an equation for the bonus point can be like below:
score = k1 * number_of_new_test_cases - k2 * net_amount_of_code_added
k1 and k2 are some positive coefficients. So, for example, for a pure refactoring change, the number_of_new_test_cases
will be zero, but the net_amount_of_code_added
will usually be negative through applying DRY rigorously. On the other hand, when actively adding several base features in an early phase, both values will be positive in most cases.
At this point, I should admit that I’ve never succeeded in entreching the TDD in some projects I introduced it to nor had a luck to work in a team with it already established. I think TDD can be very beneficial, but again I’m not in the position of asserting that. Still, if you’re already doing it and reaping some benefit from it, then another merit of this approach, that it also encourages adding tests for any new feature or function, will appeal to you.
Conclusion (or rather lack of it)
The Boy Scout Rule by Uncle Bob is a wonderful motto, but hard to keep following in reality. I think depending purely on an individual’s discipline and conscience for improving the codebase of a team-based project is a losing battle. Since there are usually quice a few existing incentives for an easy/quick/short-term achievement, which can be detrimental to a long-term quality of the codebase, there should be systematic incentives which can counter-balance those and reinforce one’s resolve to keep the code clean.
There are other ways of fighting against the tendency of code complecting like dedicating some portion of time to paying technical debt or having a dedicated sprint/iteration for it periodically. But, it’s usually better to deal with one right off the bat once you find it, as long as some critical deadline is not impending. How do you guys think of this approach? Do you have any other tips or ideas to keep code simple in spite of our very human nature of going easy and complecting?
(This article has also been posted to my personal blog.)