Software engineering loves a neat trajectory. We trace a straight line from structured programming in the late 1960s, through David Parnas’s seminal 1970s papers on information hiding, straight to microservices and beyond. We congratulate ourselves on inventing 'new' paradigms, yet we routinely stare down the same monster: our collective, chronic inability to design, define and maintain appropriate architectural boundaries. By which we mean boundaries between our software elements that are effective, efficient and (most importantly) meaningful.
That doesn’t stop us talking about this modularity constantly, yet it almost never manifests in code and running systems. Instead, we build enterprise codebases that gradually erode into what Brian Foote and Joseph Yoder famously termed the 'Big Ball of Mud' — a state where the internal structure has been eroded beyond all recognition.
Why does a discipline so obsessed with clean abstractions consistently preside over systems that inevitably drift towards the swamp?
The answer isn't a lack of tools or technical aptitude. The forces that drive the BBoM are real, but is there a way to combat them? The root of our challenges could be a fundamental misunderstanding of evolutionary mechanics, arising from a failure to align domain boundaries with actual business models and the systematic elimination of personal 'skin in the game' from modern engineering teams.
Mortality drives modularity
When we examine genuinely successful, highly modular ecosystems, like, for example, WordPress, Drupal, Linux or Android, we find they’re almost entirely powered by extension, plugin or ‘commands and pipes’ architectures.
Let’s take the (perhaps) most controversial example. While many technologists often look at the aesthetic messiness of a platform like Drupal, they also, if they're being honest with themselves, wonder how it achieved such massive, resilient scale.
Its secret isn’t a pristine API or superior initial design; it might, though, be the ever-present threat of mortality. Biologically, evolution involves death. These plugin ecosystems may be thriving because they possess an inherent process for shedding the less fit members over time. If a plugin fails to adapt, becomes bloated or loses its utility, it 'dies' and is never used again.
In contrast, enterprise codebases frequently suffer from absolute immortality. Nothing ever dies. We accumulate layers of technical debt like sedimentary rock, in great part because we deprioritize the forcing functions that might compel clean contracts — a primary prerequisite for the gradual, incremental evolution of individual components.
When you build a plugin for external users, you're forced into a strict separation and a proper contract because you don’t know who your consumers are. But when we build internal enterprise codebases for our colleagues or our future selves, we are too close to each other. The boundaries aren't enforced, so we choose the shortest path to call a function, and the architecture degrades.
Many teams migrate to microservices because they feel the codebase is 'too big to reason about.' But often they fumble the opportunity to meaningfully modularize. Breaking your system down until you have one entity per service isn't modularity; it's an architectural panic attack that leads to a 'distributed monolith'. The issue here is that boundaries which are purely technical rather than conceptual don’t solve the monolith problem. They just introduce another problem, that of network latency, to the already spaghetti-tending code.
The misalignment of the core domain
The means to tackle this are not secret. Domain-driven design (DDD) has been around since 2003. Yet we fail in applying it in one of two key ways. Either we treat it as a tactical handbook, debating ad nauseam whether a concept is an Entity or a Value Object, and treat aggregates as holy writ (without really understanding what they are or what they offer), or we talk about 'bounded contexts' and 'sub domains' without any intent to uncover, design and evolve those meaningful edges and relationships in a way that gets into the code.
Every time we do either of these we completely miss the key breakthroughs Eric Evans offered us.
The key point is that modularity fails when technologists attempt to draw boundaries around a concept they don't sufficientlyly understand. If you cannot map your technical boundaries directly to your specific business model, your modules will be wrong from day one. And when the system evolves, rather than manifesting the suppleness you're hoping for, the cruft simply accumulates.
Consider two airlines booking places on planes. To a budget carrier, a 'seat' might be a volatile value object, fluidly swapped until the moment of boarding. To a luxury liner with bespoke cabins, that same seat is a highly specific, stateful entity. The business processes around both will be very different also. If you design your software based on generic industry nouns rather than your specific workflows and value streams that drive your enterprise, your boundaries will never emerge in a sustainable way.
Modularity is not a top-down architectural blueprint delivered by an all-knowing system or domain architect. Nor is it the encoding of database tables in software. It's the outcome of an ongoing, iterative, bottom-up-plus-top-down discovery process where the language of the code evolves in lockstep with the breakthroughs in business understanding. Domain-driven design knows and supports this at its core; we just keep forgetting it.
Churn, ‘Swamp Guides’ and the erasure of ownership
There’s another level of complexity above that of the code which needs to be considered. The technical decay of a codebase is directly correlated with the organizational dynamics of the teams that build it. Microsoft research famously isolated a single non-code metric that directly correlates with systemic software bugs: ownership churn.
High team/contractor churn ──>
Loss of shared mental model ──>
Short-term tactical wins ──>
The emergence of the 'Swamp Guide'
When engineers rotate rapidly between projects, or when important enterprise systems are handed off to unincentivized third-party partners trading strictly on short-term budgets, the longer-term horizons vanish. Modularity requires domain-understanding and discipline; the former takes time to uncover,and discipline only pays back down the road; weeks, months, or years later. Without a sense of long-term ownership, there’s no 'skin in the game' to develop either. If an engineer knows they can make a messy, short-term architectural compromise to hit a deadline and then leave the company before the bill comes due, the Big Ball of Mud wins.
It gets worse. For those who do stay with organizations, this environment naturally selects for a dangerous corporate archetype: the Swamp Guide (or, as Alberto Brandolino named them, the Dungeon Master). This is the developer who thrives in the chaotic, unmapped depths of broken codebases. They know exactly where the bodies are buried, which undocumented side-effects to leverage and how to get a feature shipped in half the time by ignoring encapsulation.
They might not even like it, but because they can navigate the swamp, they become indispensable. The business rewards them for their speed, completely blind to the fact that their survival strategies are actively making the swamp deeper and ensuring no one else can cross it.
The next challenge for modular boundaries
Why are we concerned about this now? Because there’s a storm coming. As we enter an era where AI agents and LLMs actively write, modify and reason across our repositories, and we struggle to understand how they are composed, the question of modular boundaries might just be shifting from an aesthetic preference to a cognitive prerequisite.
Agents don't think about their future agent selve; nor do they possess intrinsic motivation to preserve clean abstractions. Given free rein across a massive, unstructured repository, an LLM will find the most efficient mathematical path to accomplish a task, even if that means completely obliterating encapsulation, changing visibility modifiers or introducing hidden semantic coupling.
We cannot simply ask the LLMs to 'do a better job of modularization' either. As DDD showed us, the discovery of a meaningful and productive set of boundaries, at a number of scales, is a collaborative, creative and iterative process. It's also one with sensitivity to cognitive load at its core.
In order to safely leverage AI in software engineering, we may have to enforce harder boundaries than humans have traditionally tolerated. This could mean sharding systems into far-stricter subdirectories, separate repositories or isolated sub-modules where an agent is strictly forbidden by a harness from crossing boundaries without an explicit, contract-verified interface. Until LLMs can reliably be relied upon to respect the boundaries we value the most, we’ll need to make sure we both understand and preserve them.
There’s hope arising concurrently from the same source, with particularly fascinating promise in using LLMs as conversational boundary monitors. Tools like Vlad Kononov’s modularity skill demonstrate that AI can surface structural and semantic tradeoffs, explaining different types of coupling to a team in real-time.
Instead of just breaking a build when a relationship construct experiences friction, an intelligent agent can listen for lexical shifts in user stories, architecture decision records (ADRs) and pull requests. It can flag architectural drift early: 'This code is treading on the toes of the billing domain. It's time for the humans to get in a room and talk.'
Advice to technologists
There are some clear actions technologists can take to become 'more modular' in their approach and to mitigate some of the common challenges it throws in our direction. These include:
Design for deletability, not reusability. Stop trying to write the perfect, infinitely extensible module. Instead, focus on building small, autonomous components with clean contracts. The test of this cleanliness and understandability is if it can be ripped out and rewritten in short order when they need a refresh
Align your core and supporting subdomains to your business model. If your software modules rely too much on generic domain nouns (e.g., 'user,' 'product') rather than the unique operational workflows that differentiate your business from your competitors, your architecture is likely built on sand.
Fight team churn to fight code decay. If your organization treats engineers like interchangeable cogs in short-lived 'mission teams,' accept that your architecture will inevitably reflect that fractured, short-term thinking. Prioritize longer-lived, durable teams that own outcomes, not outputs. Also consider the sense of ownership and domain understanding within the teams that own parts of your codebases. It's the difference between short and long-term gains from our new toolsets.
Questions for further exploration
There's a lot to unpack and consider here. The answers will only emerge if we continue to discuss the challenges modularity poses us and if we're honest about what makes this work difficult. To move forward, here are some questions we think deserve further consideration:
If Parnas’s principles of information hiding hold true when the word 'module' is replaced by 'microservices,' does the widespread availability of source code across collaborating internal services inherently doom enterprise architectures to semantic drift?
How will Conway’s Law adapt to agentic environments? If AI coordinates the communication and implementation across domains, what structural mutations will manifest in the resulting software architectures?
Can an engineering organization truly scale if it relies on 'Swamp Guides,' or must a healthy culture actively incentivize the systematic draining of the swamp, even if it temporarily slows down tactical feature delivery?