The Engineering Tax · Article 16 of 29
Every Piece of the Product Needs a Single Human Owner
Every module in your product has a single human owner who treats it as their own, and that ownership standard gives you the authority to say no to unnecessary change. The next article reveals why the most well-intentioned engineering teams undermine that authority every day: by pursuing flexible interfaces that dissolve the very boundaries ownership protects. You'll see how discovery-based interfaces become modularity's silent killer, why 'smart modules' that perform operations stay stable while dumb modules invite constant renegotiation, and what a three-gate governance chain from product management to the CTO looks like. The CEOs who understand this before their engineering teams demand interface flexibility will preserve the modular architecture their competitors quietly lose.

Why Flexibility Destroys the Boundaries That Make Modularity Work
1. A Fantasy Worth Examining
Every software architect who has lived through a cross-team coordination meeting has fantasized about the same escape: what if modules could just discover each other’s capabilities automatically? What if the users module added a middle_name field and every consumer simply noticed it, adapted to it, and started using it without a single email thread, a single Jira ticket, or a single argument about who owns the change?
This is the promise of discovery-based interfaces. The idea is that interfaces shouldn’t be rigid contracts carved in stone. They should be living agreements that evolve gracefully as modules grow. Consumers tolerate unknown fields, providers advertise new capabilities, schema registries govern compatibility modes, and everyone wins.
The fantasy goes like this: instead of two teams negotiating a contract, the provider publishes a schema, the consumer reads it, the system adapts, and pure flow replaces the morning meeting. But the pursuit of flexible interfaces is modularity’s silent killer.
2. What the Industry Built, and Why It Fails
The software industry has built an impressive arsenal of tools to make interfaces technically flexible. Each one solves a real problem at the wire level. None of them solve the problem at the human level, which is the only level that matters when you’re trying to keep two teams from spending their mornings in meetings.
Postel’s Law and the Tolerant Reader
A 1981 networking principle by Jon Postel, later formalized by Martin Fowler as the Tolerant Reader pattern, says a consumer should extract only the data it needs and ignore everything else. If a JSON response contains twenty fields but the consumer only needs three, the consumer shouldn’t fail when the provider adds a twenty-first. This prevents breakage but enables ignorance since tolerance is just blindness with good manners. A consumer that ignores a new field stays blind to its existence, its meaning, and its utility.
Protobuf, Avro, and GraphQL
Three popular ways to encode data so old and new systems can keep reading it as the data shape changes. Protobuf uses permanent field numbers on the wire. Avro enforces explicit compatibility rules through a schema registry. GraphQL lets clients request only the fields they need. All three solve the same narrow problem: how to change a data structure on the wire without crashing running software. None of them answer the question that actually matters, which is whether the structure should change at all.
HATEOAS and Field Masks
HATEOAS (a pattern where the server embeds links in its responses so clients discover what actions are available at runtime) works for actions and state transitions. A server returns an order with links for cancel, pay, and track. The client follows what is offered. It doesn’t work for field-level data shape. HATEOAS tells a client what it can do with a resource. It doesn’t tell the client what fields the resource contains or what those fields mean.
Google’s Field Mask pattern lets callers specify exactly which fields they want returned, like GraphQL. The provider can add unlimited fields, and only consumers who explicitly request them are affected. This is powerful for performance and decoupling, but it assumes the consumer already knows the field exists. Field masks are selection, not discovery.
Consumer-Driven Contracts
Pact and similar frameworks create machine-readable contracts that get tested in CI (continuous integration, the automated pipeline that runs every time code is changed). The Pact Broker governs whether a provider change is safe against existing consumers. Academic research frames this as both a technical mechanism and an organizational coordination strategy. It’s closer to the real problem because it introduces governance, but it still frames the question as “how do we allow interfaces to evolve safely?” rather than “how do we stop interfaces from evolving unnecessarily?”
Baldwin and Clark’s Design Rules
Carliss Baldwin and Kim Clark’s book Design Rules: The Power of Modularity uses the IBM System/360 as the central case study. Before System/360, computers were bespoke machines. IBM created a family where the same peripheral could plug into different models because the company established “design rules” for the interfaces. Their core argument: modularity doesn’t just happen. It’s created by establishing visible design rules that everyone obeys, plus hidden parameters that each module team controls independently. The visible design rules are the interface contracts. The hidden parameters are internal implementation details.
They identify “modular operators” that drive evolution: splitting, substitution, augmenting, excluding, inverting, and porting. The key insight for our question: design rules must be stable enough to enable independent work, but the system must also support modular operators to evolve. If design rules never change, the system stagnates. If they change constantly, modularity collapses because no one can rely on the interface. This is the exact tension we are exploring, and Baldwin and Clark give us the frame without giving us the rule for when change is justified.
3. Boundaries as a Human Problem
All the technologies we just reviewed solve the same problem: how to change an interface without crashing software. That’s a technical problem, and it has been solved elegantly. The problem that destroys companies is human, and the real question is whether we should change this interface at all.
Consider the middle_name example. The orders module needs a user’s name for an invoice. The users module provides first_name and last_name. Then the users module adds middle_name. The orders module now faces a choice. Should it update its code to include middle_name on invoices? Should it ignore the new field? Should it ask the users module to provide a full_name field instead?
Here is the truth that no schema registry will tell you: the orders module shouldn’t care about middle names. It processes orders. It doesn’t process names. The precise composition of a user’s display name is the users module’s domain, not the orders module’s. If the orders module starts demanding specific name fields, it has stopped being a consumer of user data and started being a designer of user data. It has crossed a boundary that shouldn’t exist.
This is where the “that’s not your business” rule applies, and it has two sides. When a consumer asks a provider for something new, the first response is “that’s not your business.” The consumer’s job is to use what the provider offers, not to dictate what the provider exposes. By the same token, when a consumer asks for something the provider doesn’t offer, the provider’s response is “that’s not my business.” The provider is responsible for its own domain, and the provider doesn’t expand its scope to satisfy convenience requests from another team. Both sides enforce the boundary when the consumer uses what is offered and the provider offers what its domain demands.
If the consumer needs something the provider doesn’t offer, one of two things is true. Either the consumer is asking for something outside the provider’s domain, or the provider’s original interface was incomplete. Both cases are errors, and neither case justifies making interfaces flexible.

4. Dumb Modules Break, Smart Modules Don’t
In Article 15 we established that every module is a mini-product. It has its own owner, its own domain, and its own demand.
The mini-product discipline has a direct implication for interfaces, and it’s the heart of this article: modules should be less dumb. A dumb module returns raw data and leaves every consumer to figure out what the data means. A smart module performs operations and returns outcomes. The difference between the two is the difference between an interface that invites change requests and an interface that stays stable for years.
Consider the users module again. A dumb version returns first_name, last_name, and email. The orders module takes those three fields and tries to build a billing label, then a shipping label, then a marketing email, then a support ticket header. Every new use case becomes a new field request, a new change request, a new meeting between the orders team and the users team. A smart version accepts a request like “generate a billing label for user 123” and returns “Jane Doe.” It accepts “generate a shipping label for user 123” and returns “Jane A. Doe, 123 Main St.” The name composition is hidden behind the interface. The consumer receives the output without seeing the internals. The fields inside the users module stay invisible to outsiders. It asks for an outcome, and the users module delivers it.
The smart version is also the stable version. When the users team later decides that shipping labels should include a phone number, the orders module doesn’t need to change. The users module either already has the phone number in its domain, or it realizes that phone numbers aren’t part of its domain and the original interface was wrong. In either case, the fix happens inside the users module, not at the boundary. The interface stays still.
This is why the “everything needed payload rule” from Article 6 fits here perfectly. The caller gathers all data the called module needs to do its job. The called module doesn’t reach out to other modules to fulfill the request. The orders module passes the user’s ID and the shipping address to the users module. The users module doesn’t call the profiles module or the addresses module. It uses what it was given.
This is also why the interface changes I’ve seen are error correction. When a consumer asks a provider for something new, the question is why this wasn’t included in the original design, not how to accommodate the change now. Someone failed to understand the domain. Someone failed to ask what the module would need to deliver. Someone built a dumb interface that returns raw data instead of performing an operation. Fixing that error is legitimate. Expanding the interface to make future errors cheaper compounds the damage, because the next error will also need accommodation, and the one after that, and the boundary dissolves one field at a time.
5. What SpaceX Can Teach Us
SpaceX and Tesla are physical product companies, not software companies. But their internal operating principles are the best available model for how autonomous modules should interact. Musk’s five-step engineering process, in strict order, is worth learning in full.
-
Make requirements less dumb. Every requirement must come from a named person, not a department. “Everyone’s wrong some of the time. All designs are wrong, it’s just a matter of how wrong.” If a requirement can’t be justified by a specific individual, it’s deleted.
-
Delete the part or process, because “the best part is no part.” If the team isn’t adding parts back at least 10% of the time, they aren’t deleting enough. The bias toward “adding this just in case” is treated as a failure mode.
-
Simplify and refine. “The most common error of a smart engineer is to perfect a thing that shouldn’t exist.” Only after deletion comes refinement.
-
Accelerate cycle time. Go faster, but don’t go faster until you’ve worked on the other three things first. If you’re digging your grave, don’t dig it faster.
-
Automate. Only after the process is fully simplified, reliable, and production-friendly does automation make sense. “Automating a thing that shouldn’t exist simply makes the problems occur faster.”
The interface between teams at SpaceX is a set of hard requirements justified by named owners. SpaceX produces approximately 85% of rocket components in-house. Manufacturing engineers engage from early design concept through shipment, serving as the point of contact between design intent and production execution. There are no “discovery” meetings where teams figure out what each other needs. The requirements are defined by what the system must do. The teams comply.
Musk mandates direct communication across departments. Managers who enforce chain-of-command for operational matters “will soon find themselves working elsewhere.” All capital expenditures above $1 million require direct approval with first-principles justification. SpaceX operates no traditional receiving and stocking infrastructure. All material flows directly to final manufacturing locations.
The parallel to software modularity is exact: modules are components. Interfaces are design rules. The system architect is the chief engineer. The requirements are declared, challenged, and either justified or deleted. SpaceX teams don’t tolerate interface evolution because “it would be nice to have more flexibility.” They eliminate the need for evolution by eliminating dumb requirements before they become interfaces.

6. Three Gates for Every Change
If interfaces should be strict, and modules should act as autonomous mini-products, then how does a legitimate interface change actually happen? The answer is governance, and in the ideal software company, no engineering team requests an interface change from another engineering team. That conversation doesn’t happen because it’s structurally inappropriate. If the orders team needs something from the users team, the orders team doesn’t knock on the users team’s door. The orders team files a feature request through the product management layer.
The flow is:
-
Product Manager or Technical Product Manager identifies a market-driven demand that affects revenue, retention, or compliance. An internal preference or a “wouldn’t it be nice” doesn’t qualify.
-
System Architect or Principal Engineer evaluates whether the demand belongs in the provider’s domain, the consumer’s domain, or neither. If the demand is legitimate, the architect determines whether the existing interface can satisfy it through an operation rather than a structural change.
-
CTO or VP of Engineering approves the change. The CTO must be convinced that the change is worth the coordination cost it will impose on both teams.
If the demand originates from an engineering team instead of product management, it’s rejected by default. Not because engineers are wrong, but because engineers shouldn’t be defining cross-module contracts. That’s an architectural decision with business consequences. It requires the same rigor as a capital expenditure.
Before any change enters that flow, the first question to ask is the one that catches the illegitimate requests that would otherwise cost the company a meeting: is this real demand, or is it internal politics? The interface changes that get pushed through “urgent” channels are ego-driven, politics-driven, or boredom-driven, not customer-driven. A manager who needs a visible win inflates a minor cleanup into a “cross-team alignment initiative.” An engineer who wants to use a new tool reframes a personal preference as a “best practice update.” A team lead who wants to defend his budget argues for a rewrite that no customer asked for. None of these are market demand. All of them look legitimate in the meeting where they get approved, because the person proposing them has a title and a slide deck. The governance chain exists to make the speaker answer for the demand, not just the proposal.
This is also why the interface changes I’ve seen are error correction. When a consumer needs something the provider doesn’t offer, the most likely explanation is that the original interface design was incomplete. Someone designed a contract without fully understanding what the module would need to deliver. Now someone else is fixing that mistake. That fix is legitimate. If the same fix repeats across modules, the company has a deeper problem: its architects are designing interfaces without understanding the product domains, or its modules are so tightly coupled that every new feature requires cross-module negotiation.
Both problems are solved by making modules less dumb in their interfaces and smarter in their operations. A module that returns raw data will always face change requests. A module that performs operations will face fewer, because the consumer doesn’t need to know what is inside.
7. When Interfaces Must Change
There are exactly two moments when interfaces legitimately change in a company’s lifecycle.
The first is the decoupling point. When a company reaches product-market fit, its architecture is likely a monolith or a small set of interdependent modules. This is correct for the emergent strategy phase. The company is learning, pivoting, and discovering what the market wants. Interfaces are fluid because the business itself hasn’t decided what it is. At PMF, the company must transition to deliberate strategy. It must split and replace the monolith, draw boundaries, and freeze interfaces. This is a survival requirement and it’s also essential for scalability. A company that keeps its interfaces fluid after PMF will discover that every new feature requires a cross-team meeting. The sync tax will compound until the engineering team spends more time negotiating contracts than writing code.
The second moment is when an existing module grows enough that its purpose has to split. In an early-stage business, one team owns a module that handles two related operations, because the company is too small to justify two modules. The revenue doesn’t yet support two teams, because the volatility of the business makes a clean separation premature. A common case is a single team owning both order processing and shipping. The two operations sit inside one module, share one database, ship through one team. As the company grows, the two operations start evolving in different directions. Order processing needs to handle new payment methods, new compliance rules, and new integration points. Shipping needs to handle new carriers, new regional rules, and new tracking integrations. Working with both together creates friction. Neither can evolve in ways that would be incompatible with the other. The right move at this moment is to split the module into two, with two teams and two interfaces. The interface change is structural and it’s driven by what the business has become according to its new domains.
Both moments are legitimate and expensive. They should require the full governance chain: PM identification, architect evaluation, CTO approval. The cost is justified because the alternative is losing market position or letting the architecture collapse under its own weight.
What isn’t legitimate is the daily drip of small interface changes: adding a field because one team wants it, renaming a field because the API “looks cleaner,” splitting a response because a consumer finds it more convenient. These changes are internal politics wearing technical clothing. They are the reason flexible interfaces destroy boundaries.

8. Conclusion
Discovery-based interfaces are a fantasy. The fantasy is that if we make interfaces flexible enough, friction and coordination costs will disappear. The reality is that flexibility makes interfaces cheap to change, and cheap interfaces invite to change constantly. Every change dissolves the boundary a little more. Every dissolved boundary creates a new meeting. Every new meeting increases the sync tax.
The technologies that enable interface evolution, Protobuf, Avro, GraphQL, HATEOAS, and Field Masks, are useful tools. They solve real technical problems. But they answer a different question: “How do we change data structures on the wire without crashing?”
The question that matters is: “How do we build modules that are so well-defined, so operation-centered, and so domain-bound that their interfaces almost never need to change?” The answer is more discipline, and it starts here: modules are mini-products. They are autonomous companies that happen to share a deployment. Each one offers operations, not raw data dumps, because operations hide the internal domain and let the interface stay still. Each one satisfies demand from its own domain. The moment a consumer asks for something outside that domain, the answer is the same on both sides: “that’s not your business” from the consumer, “that’s not my business” from the provider. Each one enforces the rule that every interface change flows through product management, architecture, and executive approval. Not because the process is slow, but because the alternative is a slow erosion of every boundary the system depends on.
The SpaceX standard applies: make requirements less dumb, delete unnecessary parts, simplify what remains, accelerate only after simplification, and automate only after the process is right.
The best interface is the one you never need to change. The second best is the one you change only after a named person justifies the cost to the CTO. Everything else is noise. And noise is what makes systems collapse.
References
- Jon Postel, “Transmission Control Protocol,” RFC 793, September 1981. https://datatracker.ietf.org/doc/html/rfc793
- Martin Fowler, “TolerantReader,” martinfowler.com. https://martinfowler.com/bliki/TolerantReader.html
- Protocol Buffers (Protobuf), Language Guide (proto3), protobuf.dev. https://protobuf.dev/programming-guides/proto3/
- Confluent, “Schema Evolution and Compatibility,” Confluent Documentation. https://docs.confluent.io/platform/current/schema-registry/fundamentals/schema-evolution.html
- GraphQL Foundation, GraphQL Specification. https://graphql.org/
- Roy T. Fielding, “HATEOAS,” Architectural Styles and the Design of Network-based Software Architectures (PhD dissertation), 2000. https://en.wikipedia.org/wiki/HATEOAS
- Google, “Field Masks,” AIP-161, google.aip.dev. https://google.aip.dev/161
- Pact, “Pact Documentation,” docs.pact.io. https://docs.pact.io/
- Pact, “Pact Broker Overview,” docs.pact.io. https://docs.pact.io/pact_broker
- Carliss Y. Baldwin and Kim B. Clark, Design Rules, Volume 1: The Power of Modularity, MIT Press, 2000. https://books.google.com/books/about/Design_Rules_The_power_of_modularity.html?id=oaBOuo4mId8C
- Carliss Y. Baldwin and Kim B. Clark, “Modularity in the Design of Complex Engineering Systems,” Harvard Business School, 2006. https://www.hbs.edu/ris/download.aspx?name=19-073.pdf
- Elon Musk, “The Algorithm,” Farnam Street (fs.blog). https://fs.blog/elon-musk-the-algorithm/
- Eric Berger (@SciGuySpace), “SpaceX is now about 85 percent vertically integrated,” X/Twitter, May 2022. https://x.com/sciguyspace/status/1526189266627330048
- Elon Musk, “Communication Within Tesla” (internal memo), CNBC, April 2018. https://www.cnbc.com/2018/04/18/elon-musks-productivity-rules-according-to-tesla-email.html
← Previous: Every Piece of the Product Needs a Single Human Owner
Up next in The Engineering Tax · Article 17
Automating a Broken Process Gives You a Faster Broken Process
After you freeze your interfaces and make your modules stand alone, the next trap is automating the old coordination patterns instead of designing a new system. That expensive automation project you greenlit last quarter might be mechanizing waste: running your broken process faster without asking if it should exist at all. The definition of automation has been clear since 1952—redesign the process and make the economics work—but 70 years of business practice have systematically ignored both requirements. The next article shows why your 'automation initiative' is likely a faster broken process, and how to tell the difference before you burn another quarter.
Coming soon
Frequently asked questions
What Is the Decoupling Point for Software Companies
What is the Decoupling Point?
The Decoupling Point, a term from Prof. Clayton Christensen's work on interdependence vs. modularization, is the moment your product becomes good enough for most customers. Before that point, customers care that the product solves their problem: performance means how the product behaves, and interdependent architecture helps you iterate until it does. After that point, the basis of competition shifts. Customers start demanding flexibility and more speed of change. Surviving that shift means moving from interdependent components with no well-defined interfaces to a modular system with well-defined interfaces.
What is the Phone vs. Battery diagnostic?
Compare your components to phone parts. The charger connects through a standard interface. Anyone can swap it, use it with any device, and modifying it won't brick your phone. The battery sits inside and changing it needs special tools and deep knowledge. One mistake and the phone is dead. Count your chargers versus your batteries. If most of your components are batteries, your system fails every time someone changes anything.
How Modules Should Communicate in a Clean Architecture
What is a Domain Interface Contract?
A Domain Interface Contract is the structured agreement between two modules. It has three layers: service identity, transaction identity, and subject data. The caller gathers all required data before making the request, so the receiving module never needs to reach into another system.
What is the Everything Needed Payload Rule?
The Everything Needed Payload Rule says a module must receive all the data it needs in the request itself, not fetch it from other modules during processing. If Module A needs data from Module C to serve Module B's request, Module B must fetch that data from C and pass it to A. From A's perspective, Module C doesn't exist.
Why Dumb Modules Break and Smart Modules Don't
What is the difference between a dumb module and a smart module?
A dumb module returns raw fields and leaves every consumer to decide what the data means. A smart module performs an operation and returns an outcome. A dumb users module hands back a first name, a last name, and an email, and every consumer invents its own billing label. A smart users module accepts a request to generate a billing label and returns the finished label. The name composition stays inside the module.
Why do dumb modules force interface changes?
Every new use case becomes a new field request and a new meeting between teams. When shipping labels later need a phone number, a smart interface stays put because the consumer already asked for a label, not for fields. The fix happens inside the provider. Expanding a dumb interface so the next mistake is cheaper dissolves the boundary one field at a time.
Why Flexible Interfaces Destroy Modularity
Why are flexible interfaces dangerous?
The software industry has built impressive tools for making interfaces technically flexible. They solve the wire-level problem but ignore the human problem. When interfaces are flexible, teams stop negotiating contracts. They stop taking ownership of their boundaries. The system drifts from modular to entangled without anyone deciding to make it so.
What should replace flexible interfaces?
Clear, stable contracts that teams negotiate explicitly. Instead of hoping consumers will tolerate new fields, define what the interface guarantees and what it doesn't. If both sides understand the contract, the system stays modular. If you can change the interface without talking to the other team, you have a trust-based arrangement, not a contract.
Three Gates Before an Interface Changes
Who approves a change to a module interface?
Three gates, in order. A product manager identifies market demand that affects revenue, retention, or compliance. A system architect decides whether that demand belongs in the provider's domain, the consumer's domain, or neither, and whether an operation can satisfy it without changing the structure. The CTO approves the change only when it is worth the coordination cost it imposes on both teams. A request that starts in an engineering team is rejected by default.
When is an interface change legitimate?
Twice in a company's life. At the decoupling point, after product-market fit, fluid interfaces have to freeze. And when one module has grown until its purpose must split into two domains, two teams, and two interfaces. Adding a field because one team wants it, renaming a field so the API looks cleaner, or splitting a response for convenience is internal politics. Both legitimate moments still pass through the three gates.
Newsletter
Be the first to get next articles in this series.