This is the first of a series of posts about a software development story. It starts in troubles, but it has a happy ending, and hopefully some interesting insights along the way.
The journey is about my personal discovery of how relationships, team dynamics and morale affect the success of a project and – more surprisingly – how these apparently unrelated aspects affect the technical quality of our products.
I’m tempted to claim that I know what happened and why it happened. I’m tempted to claim that I can pinpoint the reasons why things were problematic, and why they dramatically improved.
But it wouldn’t be completely honest. The truth is, I’ve learned that in the evolution of a complex system like a software project and even more, a dynamic and self-organising team, so many different variables are involved and interconnected.
We naturally tend to remember and highlight according to our personal bias. Someone could look at the same project and only be aware oft the technical issues. Someone else may stress that even if we were following Agile practices, we were “doing it wrong”.
You can look at it form the point of view of the managers, of the developers, of the business stakeholders or the users, and you’ll see different things.
What you are about to read is from a particular perspective. Please remember: it is not the only one or necessarily “the one”.
But it’s a bit unique, unusual, and so, hopefully, interesting.
Imagine a software development team, focused on building a low-traffic e-commerce application. The team is following a pretty standard Scrum process, with 2-weeks long sprints, regular retrospectives and planning games, a dedicated Scrum Master, a Tech Lead, a Business Analyst and a Product Owner.
Developers are quite keen on following well-known best practices, such as Pair Programming, Continuos Integration, and a proper Test (First) Driven Development (all production code is written after a test).
The architecture of the application is solid: a cluster of load-balanced web servers and app servers. Corporate backend services, hidden behind a uniform façade, handle all the complex business logic and data management requirements.
So, here is the question: how successful do you think this team and its project could be?
Or in other words, how much the technical and process-oriented aspects I’ve described can tell us about it’s success?
As a matter of fact, not that much. After one year since I joined the team as a developer, and since the project started, the situation looked quite grim.
Even if real users where already using the app as part of a trial, and we were gradually ramping up to a full release, we were significantly late on the plan. The project turned out to be more expensive than estimated, and the development pace slower than expected. The team doubled in size to cope with the workload, but that wasn’t enough.
Tech Debt was accumulating in every direction: the core of the application was a bundle of over-complicated design patterns, the acceptance test suite become extremely slow and in need of some TLC, the conceptual domain was fragmented and inconsistent. And all of this, under growing pressure to deliver, and meet the now twice-postponed deadline.
I had been doing overtime on the weekends for about three months, when a couple of developers contractors were fired.
…and this is, dear reader, when our story hits rock bottom (yes, don’t worry, it’s not going to get worst than that!).
So, what happened?
Let’s rewind, go back from the beginning, and explore some of the deeper issues.
During the first months of the project, everything was quite fun. The project was brand new, the code base was shiny and clean. We were a small team, gradually ramping up to a group of 3 developers + 1 tech lead, 2 testers, a business analyst and a scrum master.
With the increase in size, communication problems become more evident. Technical meetings were especially painful. As often, we were a bunch of opinionated developers who loved to argue about the design patterns, technical decisions and sometimes technical processes. But we were not able to come to clear conclusions, take proper actions and move on.
Some started to become disillusioned about our capacity to listen, learn and adapt – as advertised by the Agile-oriented management.
Some meetings were so bad I wished I could be somewhere else. Unsolved and unmanaged conflicts between ideas become personal conflicts.
That’s when I started to realise something quite amazing. Despite having a robust TDD approach, despite following Pair Programming and having static code analysis tools running as part of our CI system, the areas in our codebase that were more troublesome were not the ones with higher cyclomatic complexity or too much nested logic; they were not the ones with lower unit tests code coverage, and not even the ones written without doing Pair Programming.
The biggest technical issues were on those areas of the code involved with some unmanaged personal conflicts.
Relationships between developers and testers were problematic too. Automation testers were writing and maintaining a suite of acceptance tests. Was their responsibility to ensure that the final product matched the product-owner expectations, while developers were just focused on writing great code.
The conflict and the gap were somehow intentional – consequences of the belief that those two concerns (developing and testing) were better if specialised and antagonised.
The result was a huge amount of waste. Developers were writing a truck load of micro unit tests to be sure that “this time” their code was rock solid, only to witness it being rejected with tons of bugs from testers.
Testers, on the other side, being completely unaware of how the software was developed, were writing loads of ineffective and repetitive tests.
It become normal for our acceptance tests suite, in it’s fast mode, to last more than 9 hours, and never to pass 100% ( yep, you can imagine…).
But the most serious communication problems were between developers and the management. As the already postponed deadlines were approaching, managers started to worry about the delivery and to ask for more productivity. But developers were already in troubles for all the tech debt accumulated, and were – at the opposite – asking for more time to refactor.
Absence of mutual trust become the main dysfunction of our team.
So, at this stage, who would you like to blame? Who would I like to?
Well… no-one really.
As you read the story you may naturally start to connect issues with responsibilities, and eventually start to blame and to imagine culprits.
But I’d like to keep all of that out of this story.
I’ve never found blame useful to understand or to improve.
I prefer looking at the issues on a system-level.
Let’s now go back to our finale.
When the day of the full launch was on the horizon, the clash came to a climax.
On the surface it appeared as if the whole team (quite big at that time: about 7 developers and 4 testers) was focused on delivering the remaining features. But on the inside, developers were totally doing their own things. After months of unkept promises from the management about getting some time for improving the code base, they lost their faith and trust, and started to unionise on their own, sneaking in refactoring tasks as possible, ignoring the delivery pressure from the business as a fake concern.
The final straw ended up being a missed deadline, due to an unplanned piece of refactoring that, days before the date, turned into an epic two-weeks-long task.
This is where we hit rock bottom, and a couple of developers (contractors) were fired on a Friday afternoon.
But this is also where the story become a bit more personal, because then our Tech Lead moved to another team, and being the only developer permanent employee left on the team, I stepped into that role.
And here I was, for the first time with that kind of responsibility, in the middle of a highly dysfunctional and now wounded team.
To know what happened next, you’ll have to wait for the next episode….