We shape our buildings; thereafter they shape us
- Winston Churchill
After the destruction of the British Parliament’s Commons Chamber in the Blitz of 1941, the House of Lords debated how it was to be rebuilt. Some saw this as an opportunity to shift to a horseshoe ‘architecture’ but team Churchill argued that they retain the ‘adversarial rectangular pattern’. He believed that the layout itself was a catalyst of the British two party system. Members were either with one side or another, there was no in between. One had to physically walk across the floor in plain view in case they wanted to switch sides.
The adversarial rectangular layout
The horseshoe layout
The way our buildings are structured influence how we communicate and the way we communicate influences how we build. Perhaps Churchill’s idea was the precursor to Conway’s law:
Any organization that designs a system (defined broadly) will produce a design whose structure is a copy of the organization's communication structure
- Melvin Conway
The idea is that software architecture looks remarkably similar to the organization of the development team that built it.
Here are the possible responses to Conway’s Law:
This got me thinking and I couldn’t help but reflect upon the evolution of Hyperswitch’s architecture. How did my team’s communication influence design decisions? What is the right architecture for a payment infrastructure product?
Once the decisions to build in Rust and to open source the project were out of the way, we started building Hyperswitch. It is possible for a handful of developers to have high frequency informal interactions face to face. Conway’s law suggests that they will create a monolith and that is precisely what we started out with.
We worked out of Ferris House (yes, we named our office after the Rust mascot) which had three rooms on the ground floor and two on the first. We were a team of ~15 and the entire dev team worked out of the ground floor during the early days.
Ferris House
Predictably, this is what our architecture looked like:
Initial Architecture
At this stage, we wanted to start building the SDK. This SDK would be the interface between the client application and Hyperswitch’s backend. This would also provide the client with a customizable unified checkout experience across multiple payment processors. We also needed a dashboard for the merchant to configure their connectors (payment processors) and manage their payment operations. We decided to leverage our parent organization’s React team (working out of a different office in the same neighborhood) to build the SDK and the dashboard. This was also around the time we decided to organize the entire team into 3 pods. Pod 1 would build the Rust Backend, Pod 2 would build the SDK and Pod 3 would take care of the dashboard.
Perhaps this was our Inverse Conway Maneuver. The desired software architecture in this case was to decouple the SDK and the open core backend so as to independently develop both. Hence the natural progression was towards the 3 pod structure and we were now a ~35 member team.
Also, the product’s value significantly depended on how many connectors (payment processors) we supported. This meant we needed a way to scale our connector (payment processor) integration process. We needed to improve the integration process so as to make it easy for open source contributors to participate. Thus Pod 4 was born and the connector module was (partially) separated from the core so that the developers working on integrations needed minimal context of the core. The team grew a bit more and Ferris House was starting to get full. We now occupied all the rooms on both the floors. Each pod had its own room and inter-pod communication was largely handled by the respective PMs
Here’s what the architecture had evolved to at this point:
Evolved Architecture
Notice how this architecture screams out the team’s structure. I’m able to (retrospectively) see how the tightly coupled parts were built by the developers that communicated frequently with one another. This also indicates the direction we’re headed towards. Eventually the team working on the connectors would have an independent release cycle and would not depend on the core for deployment.
This was also around the time that we doubled down on improving performance and reliability. As we were only using SQL, it was obvious that this wasn’t enough to deal with the immense traffic that our system was capable of handling, and we didn’t wish to have a bottleneck on the database. Then, what’s the next logical step? Caching. We started adding infra-level caches using redis and application level caches using in-memory key stores.
Communication between the pods influenced the high level architecture and communication within the pods influenced the component level architecture.
A complex system that works is invariably found to have evolved from a simple system that worked
- Gall's Law
The idea that a complex system cannot be designed from scratch and be made to work is an underrated one. So, if Conway's law applies to how a system works at a high level, would it also apply to its subsystems? We can’t help but appreciate the importance of the nature of communication between engineers at the most atomic level.
Perhaps we are headed towards our biggest Inverse Conway Maneuver yet: A complete recognition and acceptance of Conway’s law to make sure the architecture does not clash with the team’s communication patterns. As our application grows and becomes more complex, we find ourselves in need of modularizing further. We’re splitting ourselves into domain oriented modules that are internally layered. We’ve even moved to a new office which is just one big room that can accommodate all of us.
New core team structure
All the blocks represent individual teams that almost mimic the application’s architecture. Even though it might just seem like rearranging blocks of a traditional organogram, thinking about the team in the context of the architecture rather than in isolation can go a long way in making the right decisions both for the team and the product.
By Nishant Joshi and Narayana Aaditya