A few days ago I came across a tweet in my twitter timeline that made me think and spawned a little discussion:
@diegorlosada Programming is one of the few fields where perfectionism is a really good thing. 😀
— Jonathan (@foonathan) April 23, 2015
Is it really?
Improving the code base should always be a priority. Programming is not only about adding features and “making it work”. Just adding features will make code messy and complicated, so there is always need to refactor and clean the mess up again.
This does not only apply to the code you just have written and its surroundings. It also applies to code you are just reading or debugging. See a poorly named variable? Rename it. Wading through a complicated nested if-else cascade? Refactor it. Ideally you have tests in place to back those changes up. If not, write those tests.
Of course, improvements don’t always only go towards maintainability. You can, for example, improve the efficiency of an algorithm or the performance of a piece of code or the memory footprint of a class. Just remember not to mess up the code during such improvements, especially if they are not needed or not proven to be improvements at all.
Going too far
In a given nontrivial piece of code there is always something you could improve. However, you should not go over board. Take small steps towards the perfect code, but know when it is enough.
If you estimated a small two-line code change to take two hours, it is certainly not good if you spend the next three days refactoring the whole world like crazy. You have to know when it is enough and stop, or else you won’t go anywhere.
In addition, changes that one programmer regards as improvements need not be improvements in another programmer’s view.
In programming we often have to face tradeoffs. A more efficient algorithm may need more memory and vice versa. A more generalized function could prove to be more complicated and harder to maintain.
Make sure your improvements are needed and your changes don’t have an impact that you can’t afford. Improving the performance at the cost of memory footprint is not an improvement if memory is a scarce resource and the few milliseconds you save are not vital.
Also make sure you are on the same page with your team members regarding the priorities. If you have other priorities than another programmer you might end up reverting each other’s changes, effectively gaining nothing.
Especially when it comes to the small things there is much room for personal taste. Changing a function name is OK, if the name does not represent the intent. It is not OK to change it just because the name does not fit your preferred style. Such changes don’t add any value to the code.
Many matters of taste are covered by style guidelines of a software project. Stick to them, even if they don’t exactly match your personal taste. Of course you could propose to change the guidelines, but don’t do that too often, or else the code will be a patchwork of different styles over time.
However, if you are new on a team, speak up once you have an overview of the code and the issues that might linger. You will have different experiences than the rest of the team and they can be of value for them. This applies especially if you get hot-dropped into a legacy code base.
Don’t give up
All this might read like it is a hassle to decide whether an improvement is appropriate and worth the effort. But that does not mean you should not strive for the best possible code. There is nothing as destructive as indifference towards code quality, because it makes your code rot and it will get harder and harder to maintain.
It is better to err on the side of too much improvements than not doing enough. An unnecessary improvement is a one time cost. A missed opportunity to improve code quality is a technical debt that your team will have to pay the interest for a long time.
There is no such thing as perfect code, therefore a real perfectionist will not get happy in software development. Improve your code quality whenever and as much as possible, but know when to stop, to avoid fruitless back and forth refactoring without any real benefit.
In the last tweet of the discussion, Diego summed it up:
@foonathan @arne_mertz Be ambitious on code quality, balance with pragmatism of real product delivery: best quality proof is value for users
— Diego (@diegorlosada) April 23, 2015
Completely agree Arne. In fact I believe perfectionism is nice ideal but not realistic in practise. We can spend so much time tinkering to make things perfect that we miss an opportunity or get to the market too late.
This is even more so in day-to-day development. A perfectionist attitude to code where the perfectionism adds no value is just a drain and a business cost not benefit.
I normally get code to a place where I’m totally happy then if future refactors are required to it later. Make it “clean enough”. Takes experience to judge what “clean enough” means though.
Auch hier gilt:
„Habe keine Angst vor der Perfektion: du wirst sie nie erreichen!“
“Have no fear of perfection, you’ll never reach it.” – Salvador Dali.
There is indeed no perfect code. I have hobby projects which I’ve rewritten many times, each time doing it in a different way that seemed better in some way than the previous version. I’ve also done a workshop once where about 20 programmers made a simple game, with complete freedom to choose whatever tools, languages and design they wanted. It was very interesting to see so many different ways to model the game, which each had their own strengths and weaknesses.
If there was one perfect way, or a single “correct” way to write a piece of software, then our profession would be less creative and more boring, and we would probably have already been replaced by machines doing the programming.
Thanks for your insights. It would indeed be a boring profession!