We've all heard about them: Code conventions and best practices that will help create high quality code that will be more maintainable, less buggy and generally make our lives easier. So when a new project rolls around you decide to implement a detailed set of conventions from the very beginning to ensure the code quality. You notice that for the language you intend to primarily use in the project, there already exists a detailed set of ready made conventions, so you're in luck – no need to think too deeply about these things. Someone else has already spent the time to do that; you can just pick up the fruits of their labour and carry on.
You put together the team that will code the project and among all other things they'll need to know before getting started you also brief them on the conventions, asking them to read up on them before the project gets off the ground. In a meeting just before you're about to get coding for real one of the developers brings up some doubts he has about the standard. He has indeed read up on them but he disagrees with their decision to limit the line width to 80 characters. He goes into a brief history lesson about IBM 3270 model 2 terminals and the punch cards the preceded them. (Apparently their size was determined by the size of the post-civil-war US dollar bill). He then proceeds to question the relevance of these conventions in the year 2017 when every programmer has at least 1920 horizontal pixels at his disposal.
Another programmer on the team strongly disagrees with the usage of 4 spaces for indentation. Using tabs is a far superior approach on a new project like this where we are free to choose, he argues. Tabs will allow everyone to set the level of indentation to something they're comfortable with, rather than enforcing one size that fits all (or doesn't). We always try to separate the actual data from the representation of that data anyway, and he sees no reason to make code indentation an exception. A third one complains that the convention goes way too far into nitty-gritty details that aren't really relevant for anything, and expresses his hope that “we won't have to follow it slavishly” because even the authors themselves only consider it a “set of guidelines”.
You can (sort of) understand what they're saying, but you picked a pre-made standard because you wanted to avoid having this discussion, and surely the people who made the standard knew about these things and were able to make better choices than your developers would on a whim. Furthermore you still remember that nightmare of a project from two years ago where the developers got into a huge formatting war, “correcting” the formatting of each others code – and nobody wants that again. So you overrule their objections and push ahead.
Fast forward a couple of months: the project seems to be progressing nicely, but at a meeting one of the developers raises a complaint about the agreed upon conventions not being followed. At the beginning of the project each developer was mostly concerned with his own part of the code base, but as the whole thing is beginning to come together into a unified application the developers are having to increasingly interact with code written by someone else. You take a look through the code base, and indeed, the person who is complaining is just about the only one who has been adhering to the standard. The code of the others vary from looking “pretty convention-like with the exception of ignoring line width” to “this guy probably never even bothered to look it up”. Clearly something needs to be done.
You hold a meeting where you emphasize the importance of adhering to convention, and explain that part of the next sprint will be dedicated to bring the code into compliance. Furthermore no code should go into the repository without a proper code review. Some of the people who initially complained about the convention grumble, but you know what anarchy leads to, and won't relent. You hope that the problem is solved, but a month later the developer who originally complained about the lax compliance brings up the issue again. Again looking at the code, you can see little improvement. People still ignore the line length, and the guys who don't think very highly of the conventions seem to be happy to review each others code, or just ignore that requirement. Further measures are clearly required. You ask the person who brought this to your attention for suggestions, and he's more than willing to comply. He has in fact already found a pre-made tool that will check code committed to the repository for compliance – see how clever it was to pick a ready-made standard – and reject the commit if it fails the compliance test. You tell him to go ahead with the implementation and have it ready for the next sprint, because now you're determined that the code is to be brought into compliance. He seems very pleased with your decision.
You expect that the sprint might generate some complaints, but beyond a comment about prioritising things you don't hear a lot. At the end of the sprint the developer who put the compliance checker in place is pleased to report that over 80% of the code is now compliant, and the rest should be soon to follow. Everything is looking good – until a week later one of the developers inform you that he will be “pursuing an exciting opportunity” at another company. That's bad because the project obviously has a deadline, but then again things like these happen, and you're prepared. No single developer is irreplaceable. When a mere three days later another developer makes the same announcement, things start to look hairy. This means you'll have to seriously scramble for resources to throw at the project, and even though programmers aren't irreplaceable, that doesn't mean they're fungible. Getting a programmer up to speed with a project takes time. When another two weeks later you get a third resignation you start to feel pretty resigned yourself.
You've read somewhere that holding exit interviews is recommended in a situation where you find yourself suddenly losing a lot of people, so you decide to do just that, and the findings surprise you. In their own way and in different words the ex-employees all describe a nice job that turned increasingly toxic. The decisive turning point it seemed, was the forceful implementation of what everyone felt was a misguided, anal retentive standard. Comments included:
“The stupid thing even complains about stuff like there being only one space between the code and the inline comment instead of the convention imposed two. I can't think of anything that will suck the joy out of working more effectively than that level of micromanagement.”
“You write a piece of code. You test it. You make it work. You commit the code to the repository, and get to enjoy the satisfaction of a job well done – except you don't, because as you commit, the <expletive deleted> script slaps you in the face with a: On line 143 there is a comma the you haven't <expletive deleted> gently enough. DO IT OVER!”
“The 80 character limit is just moronic. It might work when you have function names like 'strlen' or 'malloc', but we make libraries to be used by testers, and they should have human readable names like 'configure_icon_colour_scheme_for_device_foobar_with_frontend_barbaz'. In the worst cases I've had to name my variables 'a', 'b' and 'c' just to stay within the ridiculous line length – but apparently that's what's considered readable code nowadays. Of course this is made worse by wasting characters on 4 spaces for every indentation...”
Eventually you manage to finish the project – though it went way over time and over budget. Afterwards you ask one of the replacement developers what they thought about the coding convention and the script that enforced it. You get a puzzled look: “What script?” It would seem that the new people don't have a clue what you're talking about – which is strange. When you investigate you find that the script has been quietly disabled – or to be more precise, it's still running on the server, but has been subtly modified to always accept commits regardless of compliance status. The code is of course all over the place with regards to compliance. You suspect that one of the remaining original developers (beside the person pushing for compliance) took advantage of the others quitting and quietly sabotaged the script to get it out of their face, but you decide not to press the issue. You also notice that almost all the compliant code has been submitted by one person (the same one who supported the conventions) thus rendering any “blame” operations on the repository pointless, because they produce his name rather than the name of the one who actually wrote the code. This suggests that even during the “cleaning up” sprint, he was the only one who cared about compliance – everyone else just kept on working normally. You sit down, lean back and ponder what went wrong. Why did your good intentions frustrate people to the point that several left, and many of those who remained became disaffected?
The scenario above is of course made up (even though it contains far more connections to reality than I would care to admit). So the question is: What did go wrong? How is it possible to start out with such noble intentions, and yet end up so horribly wrong?
To answer this question let's start by taking a step back, and then another and look at something that at first may seem completely unrelated: religion. In religion too the moral ambitions are generally set very high, yet paradoxically history is littered with things like religious wars – something that on the face of it seems like it should be a contradiction in terms. The wars have at times been so bad, that some people have even drawn the conclusion that religion is inherently harmful, though arguably that's throwing the baby out with the bathwater. Furthermore, it's not just religion that suffers from this internal inconsistency. Non-religious ideologies often seem to fare just as bad, if not worse. Two of the most influential ideologies of the 20th century that set out to make the world a better place were national socialism and communism. Looking at the body count, neither experiment ended well.
It seems to be a human paradox that when we think we've found the keys to making a better society, we can get surprisingly inhumane. The problems seem to stem from the fact that morality is defined in theory by those with the highest ambitions, but in practice by those with the lowest. (E.g. it only takes one slob in a student collective to turn the place into a pigsty.) Morality isn't something that can be practised in isolation – it's a team effort. This means that in the eyes of those with the high ambitions, those with lesser ambitions become a hindrance and a problem. If they can't be converted to your side they – whether they be infidels, Jews or capitalists – need to be punished or exterminated. CS Lewis famously framed the problem like so:
“Of all tyrannies, a tyranny sincerely exercised for the good of its victims may be the most oppressive. It would be better to live under robber barons than under omnipotent moral busybodies. The robber baron's cruelty may sometimes sleep, his cupidity may at some point be satiated; but those who torment us for our own good will torment us without end for they do so with the approval of their own conscience.”
The source of the problem therefore seems to lie in the ancient pitfall of morality versus moralism. Morality is indispensable. Unless we live on a deserted island, we can't live without it. We need it to get along with other people. Moralism on the other hand, is morality's evil twin. Moralism adheres to the rules regardless of whether they make sense or not because it has lost sight of its goals. It accepts no exceptions, because it is convinced of its own superiority and infallibility. In what is perhaps the most famous conflict in all of history between a moral person and a faction of moralists, the moralists decided that it would be better to crucify the moral person than have him spread his common sense “anarchy”. He on the other hand accused them of losing sight of the purpose of morality, and therefore being moralists and hypocrites.
“The Sabbath was made for man, not man for the Sabbath.”
-Jesus Christ (to the Pharisees)
Let's get back to our fictional project. The real mistake was in fact made before the project even started. It was made in the very first sentence of this post. It's a very common misunderstanding that “Code conventions and best practices will help create high quality code that will be more maintainable, less buggy and generally make our lives easier.” They don't. Code conventions exist for one single purpose only. They exist so that many different people might work with the same code base without driving each other crazy. It's fundamentally a question of morality and that's why you get all of the “religious war” dynamics, albeit on a smaller scale. Your office conflicts won't result in mass murder or gulags, but they can – and if improperly dealt with will – result in people leaving, the holdouts being miserable and the project failing.
Code conventions will not give you better code. They will not give you more readable code. They will not give you more bug free code. They will if (and only if) properly implemented, give you a happier coding team, which in turn will hopefully be able to produce all of the above. If you decide to implement a convention that drives the developers crazy on its own, you have already become a moralist and gained absolutely nothing. In fact you've probably made things worse.
The problem with moralism is of course that it looks so good on the surface. It resembles morality so much that you're tempted to believe that the rules and their enforcement will surely give wonderful results. The tiny thing that tends to be forgotten, is that the enforcement part itself is bad morality. Of course when it comes to things like murder, arson and robbery we need some enforcement – i.e. the enforcement part is still a lesser evil than just allowing these things. When it comes to code conventions, we might need to exercise restraint rather than going full on SWAT team. Enforcement is likely to have far more devastating consequences than the consequences of letting people ignore them.
Of course, if you've already begun your descent toward the eighth circle, you'll be faced with the problem that it may be hard to back out. Some people may already have invested time and effort into following the standard, and these “Pharisees” may protest any effort back out. They will in fact think you're crazy for “giving up on code quality”, and they might not take kindly to the people who don't share their zeal and ambition. They are far more likely to double down on their position: “After all this is what we agreed on...”
So how do you deal with this problem? While there is no silver bullet, there are some things to keep in mind:
Never lose track of the purpose behind code conventions. Code conventions exist to serve the developers, the developers do not exist to serve the code conventions. If you don't remember anything else, at least remember this: The conventions exist to help developers get along. If they start getting in the way of this, you're better off without any conventions at all.
It's a lot easier to add legislation than it is to get rid of old laws that don't serve their intended purpose. It's better to start a project with no (or very few) conventions, and add them as deemed necessary, than to start with a huge set only to discover that they drive some people crazy, but others are now emotionally invested in them.
Your developers are not stupid. Respect their opinions. You probably won't be able to please everybody, but at least try to accommodate the majority.
Favour flexibility. If there are two ways of doing things, pick the one that people themselves can configure to match their preferences. This means among other things that tabs are superior to spaces for indentation. (Alignment is another matter.)
“Parempi laiha sopu kuin lihava riita.” A Finnish saying meaning that even strained peaceful coexistence is better than a huge fight. Humility will go a long way, and if Christendom had actually listened to Jesus' words on that, we would have had fewer wars – at least in Europe.
There you have it. I hope that this post will serve as an eye opener to at least some people, and as a reminder to others. You wouldn't think that these things can cause so many problems, but then again you wouldn't think that moral ambitions about improving the world could cause wars and misery either. Yet they do. Seeing things for what they are, and stepping back to see what's important does help avoiding these pitfalls.