pablohere/public/writings/conways-law-cuts-both-ways.html

184 lines
9.7 KiB
HTML
Raw Normal View History

2026-09-28 23:13:23 +02:00
<!DOCTYPE html>
<html>
<head>
<title>Pablo here</title>
<meta charset="utf-8" />
2026-09-29 13:36:58 +02:00
<meta name="viewport" content="width=device-width, initial-scale=1" />
2026-09-28 23:13:23 +02:00
<link rel="stylesheet" href="../styles.css" />
</head>
<body>
<main>
<h1>Hi, Pablo here</h1>
<p><a href="../index.html">back to home</a></p>
<hr />
<section>
<h2>Conway's Law cuts both ways</h2>
<p><em>Published: 2026-09-28</em></p>
<p>
This article is a small reflection on a useful way to look at Conway's Law that I think many people working in
software have not observed. I'll assume you're familiar with Conway's Law. If not, here are some nice explainers
so you can get on the same page:
</p>
<ul>
<li>
The original paper: <a href="https://www.melconway.com/research/committees.html" target="_blank"
rel="noopener noreferrer">How Do Committees invent? by Melvin E. Conway</a>
</li>
<li>
<a href="https://martinfowler.com/bliki/ConwaysLaw.html" target="_blank" rel="noopener noreferrer">Conway's
Law by Martin Fowler</a>
</li>
</ul>
<p>
So, to the point: most of the time I bump into someone bringing up Conway's Law, they do so to highlight how the
organizational and communication structure is impacting the systems that get built. "We should split this team
into two so one takes service A, the other takes service B and they can work independently". Or, "it's pointless
that we all try to build on a monolith if the three teams we have are in different time zones, have different
managers and barely talk with each other". I also find it's used more retrospectively than proactively. That
is: more as an explanation of how a system came to be the way it is (and usually used when it's fucky), rather
than a tool to try to influence how a system ends up being. Thoughtworks did introduce the
<a href="https://www.thoughtworks.com/en-us/insights/blog/customer-experience/inverse-conway-maneuver-product-development-teams"
target="_blank" rel="noopener noreferrer">Inverse Conway Maneuver</a>, which at least tries to leverage the
law as a tool of change instead of an a posteriori explainer. Plus: I've never met anyone in real life who was
familiar with the inverse maneuver.
</p>
<p>
Where I would like to bring some attention is to the idea of putting it the other way around, in the direction
of the law: looking at how the code/system changes the org/comms. And to try to use this as a way to influence
the outcomes of the org, not as a postmortem explanation.
</p>
<p>Let me discuss some examples.</p>
<h3>Enforcing boundary contracts</h3>
<p>
In large enough engineering orgs, you end up having Alice's service depend on Bob's public interface. When these
contracts are purely internal, Bob ends up introducing unexpected breaking changes more often than Alice would
like, for a variety of reasons. With the consequences being only internal and attributable to reasonable human
error, I've noticed that serial contract breakers like Bob only get called out if their breakages lead to
serious outages in a very immediate and direct way.
</p>
<p>
In one specific instance, I witnessed this setup, which I found interesting: Alice herself added some automated
CI checks in Bob's repo that enforced what she needed out of his public interface, set up in a way that wouldn't
allow Bob to go to production while breaking that. Furthermore, she leveraged <code>CODEOWNERS</code> to set the
repo up so that only her review was valid for these CI checks.
</p>
<p>Bob would have to align with Alice on every breaking change. This resulted in some behaviour changes:</p>
<ul>
<li>
Bob was not deploying breaking changes on his own anymore. Skipping the CI and <code>CODEOWNERS</code> fences
would have been too daring.
</li>
<li>Bob started to think harder about how to execute his work without breaking his contracts with Alice.</li>
<li>
Whenever Bob knew he <em>had</em> to break them, he would seek alignment with Alice as early as possible, for
he knew she was now a bottleneck to his own execution.
</li>
<li>
Bob started to care about having a smaller public surface, and would push Alice hard to include in the
automated checks only the strict public surface she depended on, and not more.
</li>
</ul>
<h3>The monolith that wanted to couple</h3>
<p>
In another instance, I worked in a small team that revolved around a single repo. The repo itself held a
monolith, which was an intentional architectural decision by the group's technical leader. But another
intentional decision by him was that different modules of that monolith had to stay decoupled from each other:
he wanted to push harder for a modular monolith, hoping to avoid the dangers of microservices while reaping the
advantages of a single monolith and of decoupling at the same time.
</p>
<p>
There were several tricks in his toolbelt to ensure this wasn't broken. One of them was to literally prevent
imports across modules. Each module could only talk to others through shared infra or explicitly defined public
APIs. CI checkers would enforce this hard, flagging PRs that tried to skip it.
</p>
<p>A few consequences of this:</p>
<ul>
<li>
The decoupling-by-decree did a decent job at keeping modules decoupled, which gave the engineers working in
different corners of the monolith good independence to work without being blocked by others. Large reorgs and
refactors that could be done strictly within the private part of modules mostly happened without other
colleagues even having to be warned.
</li>
<li>
But living under the same repo umbrella, testing and many other integration tasks were still shared among the
team, so if you somehow still managed to break someone else's turf, you noticed.
</li>
<li>
The strict no-coupling checks sometimes led to situations where it was extremely tempting to remove the rules
because it would have made our lives so much easier. Those situations were hints at some shortcoming in the
wider architecture of the monolith, and led to some very thoughtful whiteboard sessions that helped shape good
ways to achieve what we wanted without letting the modules talk to each other.
</li>
</ul>
<h3>The keys to the secrets</h3>
<p>
Another org was struggling with a sprawl of SaaS and infra services being hired left and right. The org had
grown from a small team to multiple independent teams, and each team was just going around shopping for
whatever cloud tooling was useful for their work. It quickly grew into a mess of duplicated services, where
common needs such as observability, documentation or even databases were being served by two or three tools
where one would have been enough.
</p>
<p>
The org was lucky enough that at least Git and their pipelines were still centralized in a single place, so the
following single change was made: one single engineering team, led by a very assertive manager, was put in
charge of the secrets manager that was used by their CI/CD pipelines. You could only go to production through
it, and only this manager could actually edit the contents of the vaults to include whatever
tokens/keys/secrets your tooling needed.
</p>
<p>
Once this was decided, the first impact was quick: the sprawl stopped because, if you wanted another tool, you
had to convince that manager, which was anything but trivial. The second effect came in slowly, as certain tools
were promoted over others and deprecation dates were set under the threat of secrets disappearing from the
vaults. Initially, this setup was overwhelming for the team sitting on top of the secrets manager, since they
suddenly became a bottleneck for pretty much every other team in the org. But the pressure incentivized everyone
to adapt: the gatekeeping team quickly standardized all their business-as-usual to make it as fast and scalable
as possible. The teams depending on it quickly learned to plan ahead when secrets management was part of some
line of work, and developed the habit of using what they had available in the org instead of just picking any
shiny SaaS that was walking by.
</p>
<h3>The take away</h3>
<p>
That's just a few. I could add more, and you would suddenly get bored because the pattern becomes obvious. The
overarching story to take away: you make some hard rule in code. Because code is stubborn, people adapt around
it and so your organization and how people work change as a result.
</p>
<p>
As someone who has both technical and managerial responsibilities, I find this mindset of changing the org via
the code interesting and useful. I will often find myself thinking: which technical decision will drive the
behaviour that I want to see in my org?
</p>
<p>
Is the solution to flip-flopping, mind-changing product owners to make messages containing the words "urgent",
"change" and "priority" undeliverable in Slack?
</p>
<hr />
<p><a href="../index.html">back to home</a></p>
</section>
</main>
</body>
</html>