Before I go on let me start with an excerpt from Robert C. Martin’s “The Clean Coder” (I know, I quote it a lot):
• The jury is in!
• The controversy is over.
• GOTO is harmful.
• And TDD works.
Based on my own experience, I will have to agree with both the GOTO and the TDD quotes. Many of you readers have experience on TDD/BDD and swear by it. That’s good. Some of you still shun the technique no matter what. That’s good too, we need controversy to remain alert!
In this post however I will not debate about test-first efficiency and adoption. I will assume that you have nothing against it to start with, alright?
Working together is hard!
As developers, we’re having a hard time working as a team. Maybe that’s because we’re nerds, I don’t know. Heck, they even started throwing Scrum and Kanban at us, hoping that we would learn how to organize ourselves!
Certainly there’s a communication factor in it: we all have to agree what we want to achieve before we decide who does what, so we must have our specifications documents and our user stories.
But, as developers, we also have different levels of knowledge (technical and business) and different styles in coding.
Some companies try to enforce guidelines to make it all neat and tidy, but it’s tedious to learn enterprise guidelines (especially absurd ones!) and in the worst cases they tend to limit our ability to solve problems creatively. He who has enjoyed bending his style to arbitrary guidelines, please raise your hand.
But coding guidelines are not even the problem. We all have our ways in solving a given problem. We come from different backgrounds, we’ve had different experiences and we know different things. Sometimes we know more, sometimes we know less. Different developers see things differently.
And that’s definitely a good thing: we want diversity!
But which solution is best? Who’s right and who’s wrong?
Working on another’s code
When working in a team of developers, you’ll inevitably end up having to deal with one of these situations:
- You need to debug another developer’s code.
- You need to extend another developer’s code.
- You need to debug your code… which you wrote 8 months ago so you don’t have the slightest clue of the logic behind it.
We’ve all debugged or extended another developers code: it can be tricky. We open the file, have a look at the code… Hmm, maybe its that function? What if a change this bit? Okay, it seems to compile but… shit, that function is also called by 362 other functions! Have I broken something? How can I be sure?
Not convinced? Okay, you arrive at the office and a developer (a senior developer!) tells you: “hey, I’ve rewritten that xyz class so that now it’s all faster! Everything compiled fine on my machine!”… But you’re shaking in terror. You know that the features you finished yesterday won’t work anymore. They were working. They won’t now. You naively think that the “hero of the day” maybe verified if anything else than his own components were still working after his changes… But deep down you know you’ll spend the day fixing stuff instead of going forward.
Sounds familiar?
Now, be honest: how many times did you want to murder your team mate for breaking your work?
The indisputable specification
The thing with written specifications is: everyone has its own interpretation of them. If it says that the search functionality must be fast, well… okay. What is “fast”? What do we consider as “fast”?
Well we could “quantify” specifications. We can “measure” a specification or a desired behavior of our application, so that we get some kind of proof or verification that our code actually does what is specified. Basically if our code does what it needs to, the readings reports it.
Measures will mostly be of the boolean type: “it does” / “it does not” what is asked. But we can also measure thresholds: “it is” / “it is not” as fast as we want.
By doing that, we really specify our problem. We define what is acceptable and what is not. We trace the path we need to stay on for our code to match the application’s specifications. Stray out of the path, and the readings will tell it to you!
Repeating those measures again and again to check if all is okay is… repetitive, and a pain in the ass! However things become interesting when we start automating those measures. Now you can obtain a full report at the click of a button!
As such, our specifications have become indisputable. What the application needs to be has been framed by automated measures, and anything out of the boundaries is reported to you!
Not sure if something should be this way? Run the automated measures and see what the report says! How cool is that!
This is how cool it is
Bear with me.
The team has different levels of technical knowledge? It’s okay: if the code is not behaving as expected, the automated measures will tell you.
The implemented solution is not solving the specified business problem? It’s okay: if the code is not solving the right problem, the automated measures will tell you.
Your implementation is different from your colleague’s? It’s okay: if your code strays out of the application’ scope, the automated measures will tell you.
Your code style is not quite identical to your team’s? It’s okay, as long as the code does what’s it’s supposed to. If it’s not, the automated measures will tell you.
You have to add functionality but are afraid of breaking something? It’s okay: if anything breaks, the automated measures will tell you.
You don’t know how well you fixed that bug? It’s okay: if any bug remains or if the fix broke something, the automated reports will tell you.
You’re afraid David Caruso will put in jail after chopping to bits that developer who broke the build this morning? It’s okay, the automated reports will tell Caruso you were right: it was his fault.
(disclaimer: please don’t chop your developer colleagues 🙂
It’s O-KAY! The automated measures tell you when you go off-path. And those measures, those specifications are indisputable.
The final twist
Now read the previous paragraph again and replace “measures” with “tests“.
Shock, gasp, horror! That’s the twist! TESTS SPECIFY YOUR APPLICATION BEHAVIOR! Who would have thought?
… Okay, you saw the twist coming. I’m no James Wan. But at least I hope you now understand the point I’m trying to make.
Well-written tests can measure whether our work is breaking the application we’re building. We will be notified when our code breaks functionality, even if we did not implement that functionality ourselves! We will be able to confidently work on code we don’t know because if we break it, we will be notified. That’s reassuring!
The immediate consequence is that any developer in the team will be able to work on any part of the code without being afraid of directly or indirectly breaking another developer’s hard work! Hopefully, that will lead you to better collaboration as a developer’s team: not hating each others for breaking builds is, at least, a good start!
The second final twist
How to achieve indisputable automated specifications that tell you when you go off-path?
You practice Test-Driven Development and Behavior-Driven Development.
I’m aware that the names are unfortunate (at least for TDD), because it should really be called Specifications-Driven Development (that would make a lot more sense!). But trust me: test-first or behavior-first is the only reasonable way of doing this.
Skeptical?
Okay, so imagine this. You need to draw a round with black borders, filled in red. How do you proceed? Most likely you will take your black pen, draw the round border, then take the big red pen and start filling the inside of that black round perimeter you’ve drawn. Okay?
That’s specifications-first… or test-first, whatever.
Now try to draw that figure by starting with the red filling. When you’re done, draw the black circle’s border. Not as clean and tidy, am I right? I bet that either some red filling is outside the border of the circle, or there’s some red color missing inside the border… or your circle’s black border is not round anymore.
The problem is that, while drawing the circle’s filling, your hand does not know how far it should fill because it has no border to rely on as a reference. So the red filling ends up being irregular, not perfectly adopting the circle’s black border.
Well that’s tests-after.
So… would you rather come up with a clean and neatly-filled circle, or with an irregular and messy one?
Cheers!