The Homomorphic Force: When Software and Team Structures Reinforce Each Other
Designing an appropriate software structure is one of the core parts of developing a successful software product. It describes how the code of a system is grouped into modules and how those modules depend on each other. Being very hard to get right, it is one of the main drivers for maintainability issues development teams struggle with. Highly interdependent parts, changes that necessitate adjustments in almost all modules, and unexpected side effects are symptoms of a poor software structure. Intentions to restructure and refactor often fail because the mess already made is too hard to untangle. However, I think one aspect is usually overlooked but crucial for designing software structures: organizational structure and (inter-team) communication.
Every organization has a communication structure. The fact that people work in teams means that members within teams talk to each other more often than to members of different teams. What follows is that members of the same team will develop a shared understanding of their problem domain and a common language to describe it. This creates dependencies: a team's shared understanding and language is naturally and easily described in tightly integrated code. Now, let's take two teams, each having their own understanding of the problem domain and language they use to describe it. This situation leads to two codebases, each filled with one team's knowledge, separated by module boundaries and explicit APIs.
Furthermore, teams often depend on each other because they cooperate in feature development, introducing communication between teams. Some teams communicate more often, some less often. This communication brings their language and understanding closer together over time. Teams with more similar understandings of the problem domain will use informal ways to integrate their code. Due to closer and more frequent integration, their code will become more entangled over time.
Meanwhile, teams that communicate less (or not at all) will probably use more explicit integration patterns and APIs, leading to a lower degree of coupling. Melvin Conway described this effect in 1968, in which the term Conway's Law was coined. It describes how an organization's communication structure imposes itself on the software's structure.
Any given communication structure will, over time, influence and form the software’s structure. You can think of it as a kind of force that is shaping the software system. Moreover, Conways Law (should we call it Conways Force?) is not the only force affecting software structure. If this were the case, a single person writing software would do so within a single module and without structure. There are other forces at play as well. Depending on the context, some forces are stronger, and some are weaker.
Here are some forces that also influence software structure:
Functional forces describe the software's functionality, what it should do, its purpose, and its feature set. Software development teams structure accounting software differently than a system controlling rail network switches.
Quality force, which includes essential quality aspects, plays a crucial role in shaping the software's structure. For example, teams might split an application into different modules to separate confidential and non-confidential data.
When organizations use political means to control and guardrail aspects of the software solution, such as mandates on the programming language, technology, or patterns to use, they exert political force on the software's structure. For instance, an organization that enforces direct and synchronous communication between modules and forbids messaging systems will shape the software's structure, influencing communication channels, data modeling, and decisions on where data is stored.
Cultural forces describe how independently teams make decisions, the extent to which responsibility is assumed in teams, and how well knowledge-sharing disciplines such as pair programming are established.
What is interesting about Conway's Law is that it also works the other way around. Imagine a development team that takes over the responsibility of maintaining and extending two existing and non-trivial modules. I think the team will probably split into two parts over time, one working primarily on Module A and the other on Module B. If the modules are complex enough, some people will become proficient in Module A while others will be in Module B. This means that the understanding and language of the team will further drift apart since both modules do not depend on each other whatsoever. Maybe they start splitting discussions, planning and review sessions. Over time, the team will disintegrate into two different teams.
This enforcing of software structure on organizational and communicational structures is especially common when organizations inherit software they did not develop themselves. This mutual enforcement of software and communication structure also has a name: it’s called the homomorphic force because both systems are mutually structure-enforcing. On top of that, the homomorphic force reinforces itself: software and communication structure are both difficult to change. As soon as the software structure has taken the form of the communication structure, it enforces that communication structure - which in turn will enforce the software structure - which will enforce the communication structure … you get the point. The problem is that this self-reinforcing loop is challenging to break. Each change to the software structure will conflict with the communication structure - and vice versa.
Let’s take the following situation as an example: a software product consists of three modules, each being developed separately by a development team and integrated via APIs:
Imagine you need to change the system, and Team 2 decided to split Module B into two modules. The first question is: do you start by dividing the module into two, which are both maintained by a single team afterward? Do you split the team first and let two teams work on the same code base, gradually breaking the module into two (e.g., using something like change by split)? This would mean that (at least temporarily) Teams 1 and 3 need to talk to both successors of Team 2 since they depend on changes to both their modules. The homomorphic force is at play here because dependencies in the module structure also project themselves onto the organizational structure by introducing new communication channels.
You can leapfrog the homomorphic force with the Inverse Conway Maneuver. When developing a new software product, structure the teams first to resemble the software structure you intend to build. You can use that to your advantage before the homomorphic force takes hold, making changes much more challenging due to its reinforcement loop.
I want to point out two ways you can use the concepts in this post to your advantage.
First, design team boundaries along value streams. Enable teams to deliver working software with minimum dependencies to other teams. As soon as you make multiple teams responsible for a single value stream, you have more than one team involved in delivering functionality to customers. The homomorphic force will then cause your software’s modules to be interdependent as well. I’ve seen software teams being responsible for providing a great product discovery experience for online shop visitors. It was their value stream, so they were fully responsible and autonomous in building their solution. If you have decoupled development teams, make sure to decouple the modules themselves as well. Use technical patterns like asynchronous communication, independently deployable services, and decentralized data storage. Use communication patterns to decouple teams. Co-locate teams that need to work tighter together and actively separate teams that don’t. Make sure that only the communication channels that are necessary due to product dependencies are the ones being actively used. Not all communication is good; what we want is focused communication between specific teams. Check out Team Topologies, which describes several team interaction patterns.
Second, think product over project. As by Conways Law, taking requirements from “business” and transforming them into projects that need coordination over several teams leads to an interdependent software system. This is mainly due to tightly-knit communication and necessary coordination during project execution (i.e., development). Instead, teams should develop a product (or part of a product) for which they are fully responsible. Let them cover the entire value stream, including determining and prioritizing what features to build, develop, deploy, and even gather and reincorporate customer feedback.
Conclusion
Which should we design first? The organizational and communication structure? Or the software's structure? Consider that an organization's product has more external value than its organization and communication structure. An organization's customer experiences a product but does not experience its communicational or organizational structure. In that sense, getting the product right is more important than getting the organization right. But as we've discussed, we can use organization and communication structures to influence our software product in beneficial ways. As the Inverse Conway Maneuver suggests, we should use the explicit design of organization and communication structures as a tool to develop a great software product.
Further Reading & References
“What do I think about Conway’s Law now?” by Lise Hvatum and Allan Kelly
“Continuous Delivery and Conway’s Law” by Allan Kelly
“Shades of Conway’s Law” by Thierry De Pauw