A few months ago, while enduring one of those useless religious debates about standards and best practices, someone came up with this: “When looking at an application’s code, you should not be able to recognize who wrote which part: the developer’s coding style should not betray him“.
So, basically, our work as developers should be anonymous, formatted to blindly follow all the best practices imposed to us by either the company we work for or by whatever opinion someone posted on the web.
This definition of a developer is insulting and is bringing us down, making us miserable and depressed.
Good Bye Lenin!
As developers, we long to be creative and unique. We want to try things out and be surprised by what our colleagues came up with, so that we can eventually learn something we didn’t know. We need to be able to propose more than one standard way of solving problems! We must be able to innovate! We need to do some introspection and ask ourselves whether there is a better way of implementing that bit of functionality.
So what happens when that freedom is taken from us? What happens when we are forced to work under a common set of conventions, standards and best practices, like a set of commandments carved into stone?
The truth is no decent developer likes to be considered as a deluxe secretary who has absorbed an extensive set of rules, no questions asked: “Do your job, implement the requirements by following the rules, disappear. Yes Sir. Don’t try anything fancy.”
I’ve been there and I’ve seen it happen: we become sad at best, depressed at worst. Some of us will give up and obey, become demotivated and unproductive. The most daring of us will simply quit and look for a happier place.
And that leaves the company wondering why it cannot keep its “resources“…
Chaos… under control!
Alright, so how could we remain free and creative without making a big mess of the project?
Let’s review our primary objectives.
- A team of developers is obviously moving towards a common goal, which is to implement whatever is required for the project at hand. That’s priority number one.
- When coding, each developer has its own style and convictions. But as long as those different styles can coexist together and have little impact on the application’s functionality then we could, at least initially, ignore those inconsistencies.
- No matter what we do, though, we need to ensure the application’s maintainability. We need to be able to understand each other’s code. We must be able to improve it or even rewrite it and be sure we won’t break anything.
Well there we have it: a frame inside which each developer can maintain a certain degree of freedom.
Nothing really matters
I usually take the liberty of grouping my variables by type (static, non-static, final, etc.) and sort them alphabetically. I find it’s a clean way to do, but by no means I ask my team mates to be as obsessive as I am. Why? Because in the end, it doesn’t really matter.
Teams and companies impose code conventions and standards to themselves, believing that it will keep the code maintainable and help developers understand each other’s code. So which one is right: 80 or 120 characters per line of code? Tabs or spaces? How many lines per method? Fields and methods’ naming standards?
Really, who cares! How blocking is it in the end?
With modern IDEs, those inconsistencies are a mere nuisance at best. Extracting methods, moving them, renaming fields or variables… Refactoring has never been easier! So unaesthetic or imperfect code is always potentially temporary, and can always be changed back and forth with little effort.
With something like SonarQube you can keep track of those small deviations and deal with them at the end of the day, when you’re too tired to start working on that “recursive dynamic web-based form editor” feature.
Don’t try to change me, baby
Let’s consider the recurrent “for” versus “for each” argument in Java (and since Java 8 we can probably add streams to the contenders).
A few years ago I kept reading posts urging developers to use local variable iteration (faster) or for each statements (more readable).
The thing is, readability is subjective: maybe older coders prefer that i < 0; i++ syntax better? At least it’s immediately recognizable!
And in terms of maintainability all developers understand both syntaxes, so it won’t slow down maintenance.
Okay, so what’s the point of forcing the usage of one rather than the other? The truth is, unless there is a serious and measurable consequence on the application, you will have a hard time trying to change a developer’s mind!
Look what happens when you try to convert non-practitioners on Test-Driven Development: if they haven’t walked the path, tried the approach and got convinced by its advantages, nothing good will come out of it. They’ll just end up sad and frustrated.
What you could do though is to show a developer how useful, in your humble opinion, it is to automate the specification first, and how much it improves the test coverage of his code.
But in the end, that is really HIS decision. He’ll either be convinced or not. And if he’s not, then let it be.
Imposing a practice, a convention or a standard should be weighted against its negative impact on the developer. Nobody likes to have its hand forced!
The thick red line
This is all nice and well, but what about the system’s architecture? What about those essential engineering decisions at the core of the application?
That’s when we hit the boundaries of the frame we agreed upon here above. A lack of a minimal agreement in terms of architecture and frameworks would be inefficient from the team’s perspective.
Of course one might argue that, if we want to remain in “Agile” mode, we have to view our code as a big lump of clay: malleable, never dry, always potentially changeable. This is certainly something to aim at, and there will always be cases where a misjudgment forces the team to replace big chunks of code. But that’s another story…
Creative, free and happy! How?
I believe automation of specifications is the key to effectively implement this frame, these boundaries inside which developers can freely collaborate.
Think of it: our priority number one is to implement what is requested. To make sure that our desire of freedom won’t bring the project down, we must have a clear indication, an alarm that is set off when boundaries are crossed. This indication can be provided by automated specifications.
Unit tests, integration, acceptance tests… Any kind of automated tests is best because they can be repeatedly executed as many times as we need. Feed your repository to a continuous integration server, and the tests will run at every commit!
Continuously-running tests will also ensure that diverging coding styles do not break our primary goal, which is to build something that works as requested.
Last but not least, those tests will turn the code into clay: the team’s code will become changeable without risking of breaking something. It doesn’t matter if that method is written differently, because the tests show me that it works, the tests show me how the method is meant to behave, so I can safely change it as many times as I want! That definitely contributes to the code maintainability!
Consider this: if you mess up the code too much, an alarm will go off; the test will tell you. Stay within the frame and you can code the way you like and try what you want.
Is that idea bringing a smile to your face?
Is that even possible?
That’s ultimately the question: can this theory actually be applied in real situations?
I am currently spending my spare time working on a pet project in a team of two. We both have our strengths and weaknesses. When we started we used to blame… no wait, I used to blame stuff on my partner and I felt awful!
Now, that’s a pet project we’re talking about. Nobody’s paying us to do it and we put long hours into it. So we can’t start fighting about it, we seriously need remain motivated otherwise we’ll get bored with the project and move on…
Therefore we decided to develop freely: no blames, no prejudices and barely any code conventions or standard. The only rule we have is that every tiny bit of code, every single behavior must be tested.
Of course, the code does not end up the way I would write it. That’s okay, though. It works, that’s priority number one. I simply learned to let go.
And guess what! One year and a half later, we are still happily working on the application. Personally it brings me a lot to come home and work on this project, after a tough day of meetings: it reminds me that coding can be a real pleasure!
Yes we can!
Is trying to give up on imposed standards worth the effort? To answer that, allow me to quote Donald Knuth: “Everyday life is like programming, I guess. If you love something you can put beauty into it“.
Code conventions and best practices make us miserable, and it’s hard to love anything in life if you feel bitter about it.
PS: more than ever, feel free to express your opinion on the subject in the comments!