Making mistakes: Part 3
Saturday, 31. Jul 2021
Never underestimate a coder’s pride.
I did that a few years back, when I joined a project with a new customer. The team consisted of four developers on site, led by a senior software architect and a group manager. Three more developers were also hired from another country to help create highly encapsulated features. This was the first customer project where I was presented with continuous integration, gated check ins, automated tests and code analysis tools like SonarQube. The software architect – let’s call him Stephen – had put a lot of effort into this development process, and he had done a really great job with it. Naturally, I was very enthusiastic about the project and I immediately felt that this was going to be great fun. We had some fantastic talks about the system and how it could be improved. Stephen and I were on the same page most of the time, and we got along well.
We noticed a really hard to explain and even harder to debug malfunction roughly four months into the project. The system, consisting of three individual computers communicating and interacting with one another asynchronously, stopped working on rare occasions. Since Stephen was too busy to do the digging, I was left with the problem to figure out by myself. It turned out to be a small copy and paste error in the job queue implementation of the communication mechanism. Another work item that I had on my plate was about expanding that mechanism with further functionality, so I figured I’d hop right in and dig a little deeper. As it turned out, the core implementation used a producer consumer pattern for the handling of network packages. But there wasn’t a base implementation of a job or a common interface. Instead, I found forty or so almost identical job classes and another forty or so almost identical job handler classes. Since the job and handler classes were just shy of one hundred lines of code each, I decided that it was easier and more robust for me to refactor the entire job queue rather than to create the jobs and handlers for three more types using copy and paste as the work item suggested. As a result, the job classes came down to just fifteen lines of code and the handlers to about ten. I added generic interfaces, base implementations and adapted the job processor to handle generics. This refactoring also fixed a few more copy and paste errors that hadn’t surfaced yet, but that would have caused trouble further down the line. The unit tests didn’t show these, as the test code was also just copied every time.
I am positive that my changes were very well-made and solid. Most importantly, they were very necessary and improved maintainability of the code big time. And it only took half a day to do it, with another four hours to adapt the unit tests. Unfortunately, Stephen didn’t share my point of view when we did the code review. He was the author of the entire communication implementation and the job processing was his baby. My changes had replaced almost all of his original code, so I was denied the check in. Apparently, I wasn’t supposed to dig that deep without a corresponding work item and without his blessings. Furthermore, Stephen had the rule of not using generics. He literally told me that ‘You can never be sure about what’s going to happen and if it will work correctly’. From this day on, Stephen never accepted my code in reviews ever again, and I couldn’t do any more work. After consulting the group manager and my co-workers and trying to fix my issues with Stephen without success, I decided to pull the plug. I explained every detail to my boss and asked him to reassign me to another customer. In my last week, the group manager came to me, asking me to stay. He told me that Stephen would leave the team. He also asked if I’d be willing to take his place. Unfortunately, I had already been accepted by another customer, so there was no chance for me to accept without letting someone down.
I have been told by several individuals who have worked with Stephen, that I might have lost the project eventually. Apparently, this wasn’t the first time that Stephen had trouble with co-workers, but my conflict with him was avoidable at this stage. Instead of mending the issues right away, I should have filed a bug against the implementation. This would have cost at least another week to get to the same result due to discussions and explanations, but I wouldn’t have lost a very interesting project. Keeping Stephen in the loop would have increased the chance of him accepting my changes by a big margin.
The work with Stephen has taught me that sometimes, a developer can feel personally attacked if their code is touched without their explicit consent. It also taught me to never underestimate the pride that a developer can feel for a piece of code, even if it smells badly and hurts the reader’s eye. This is by far not the norm, and luckily, it only happens rarely. I’ve since been trying my best to communicate a lot more with my co-workers in situations like this, and avoid an avoidable conflict from the get-go. It isn’t always easy, but I’ve had good success so far, and I hope that the streak continues.
Fortunately, all this didn’t come back to haunt me. My boss told me not to worry, since sometimes people just don’t get along. I’ve learned from the experience, and getting the support from my own company was very helpful in dealing with this myself.