The nature of software is a philosophical problem for the ages. How can something seemingly so abstract have such crucial real-world applications? Those lucky enough to contribute to the software world will usually only touch the surface of something that becomes ever more complex as it grows. Complexity brings difficulty. Difficulty is a challenge for us to overcome. Rather than focusing on ever-better technical solutions, shouldn’t we be optimizing for happiness?
On the one hand, software never does quite what we want it to (because of the inevitable bugs), and on the other, it allows us to do things we could never have imagined. Our software improves as we connect other systems, add users, and incorporate feedback. Sometimes, seemingly simple changes are impossible. But we progress, and with more connections comes more complexity.
As our software grows, the complexity increases. As we try to tame the complexity, we can get distracted by project plans, Scrums and SAFes, Agiles etc. Whatever we choose to use, these frameworks lack the sophistication to match the problems we’re trying to solve – or – more alarmingly – they start to distract us from our core mission of building software.
Complexity and Conway’s Law
While complexity increases quickly, it will be limited by our organization’s ability to handle it. As this happens, the line between the systems we use to build our software and the software we deliver blurs.
Ultimately, our software systems become a part of our organization.
Therefore, we are constrained not only by our requirements but also by the way we work. This effect is known as Conway’s Law. While there are many definitions of this law, probably the shortest is by Eric Raymond:
“If you have four groups working on a compiler, you’ll get a 4-pass compiler.”
In essence, the software you build reflects the organization that builds it.
Martin Fowler notes the importance of Conway’s Law like this:
“Important enough to affect every system I’ve come across, and powerful enough that you’re doomed to defeat if you try to fight it.”
By acknowledging that Conway’s Laws is inevitable, we can at least understand how we must organize to improve the maintainability of our software.
The primacy of Conway’s Law is a founding principle of Team Topologies. This important book shows us how organize ourselves better in teams to directly affect the quality and speed of our software solution delivery.
While acknowledging Conway’s Law and how our organizational setup helps, we should also recognize the other fundamental element of our software engineering organisation: that we, as humans, are imperfect.
We write good software when we feel in a good place and bad software when we are in a bad place. Sometimes, we come up with the worst solutions when we are feeling anarchic. Perhaps we design something elegant when we are inspired.
And while our work environment can dramatically affect how we perform, our performance affects how we feel about the work.
So, organizing ourselves is one thing, but we should also acknowledge that we will make mistakes as individuals. We will have opinions, fall out with each other and do things we cannot design our organizations or systems for.
Therefore we must recognise that our systems are imperfect, our organization is imperfect and that we are imperfect and that we’re going to screw up. And that’s ok.
Therefore, a core part of our engineering effort should be directed towards minimizing the effect our bad days will have on our good days.
This means organising for effectiveness as well as optimizing for happiness. It also means recognising when a task or team does not add value to a process. Potentially it could also mean closing the feedback loop on decision-making by measuring the performance of our applications.
These measures reduce the frustration that engineers can feel. Engineers are, by definition, obsessed with efficiency. Put engineers in a room together and they will argue over the smallest detail. Therefore by reducing the need to make decisions we can make their lives easier – assuming that they agree with these decisions of course.
Additionally, we should determine why we are performing our tasks. Does everything we do now need to be done in order to improve our software? We should remove as many steps, as many obstacles to achieving that as possible. We should remove processes, remove code and remove systems.
Personal and Team
So how can we get better at working with each other? In two ways – personally and organizationally.
As individuals, we should prioritise:
- Respectful communication over writing code
- Discussion over design
- Avoiding “solutions thinking”
- Keeping an open mind to opposing views.
- Being ready to admit we are wrong.
And as an organization and team, we can prioritise:
- Right-sizing our teams and our backlogs. Because overloaded or underloaded individuals are not motivated individuals.
- Effective CI and CD. No flaky tests are allowed to distract us. Fast unit testing. Sensibly automated deployments, infrastructure as code when it doesn’t overcomplicate or slow down our experience.
- Open and honest collaboration and conversation – direct feedback, personally delivered.
- Blame-free post-mortems. We acknowledge that things go wrong, and we focus on the problem not the individual.
- Repeatability and automation of the things that matter to eliminate toil and promote re-use and creative thinking.
- Monitoring and alerting built into everything we do.
These lists could be a good place to start for your organization, but the list goes on and it will be specific to your needs. If you are already a fan of DevOps or Platform Engineering or any current best-practice you probably already have dozens more ideas.
But remember: your culture is defined by how you interact. The way we work is as important as the software we deliver. We aim to improve lives with our software but we can also improve each other’s lives by delivering it well together.