- Published on
Boundaries, modularity and a diaper effect
- Authors
- Name
- Damian Płaza
- @raimeyuu
Look at this magnificent cathedral!
Imagine that two architects - Alex and Adam - discuss a potential architecture for a new part of the system.
The main idea is to modernize technology, as it is pretty outdated and brings friction.
For sure there will be k8s, event-driven architecture and possibly gRPC - because it's fast.
"What what the system does?", some might ask in their curious minds.
Well, it is a system for managing local guided tours - Alex was assigned to architect it.
This pair review process aims at ensuring that the architecture is well thought through, and that both architects agree on the proposed solution, and workers, I mean, software engineers will be able to deliver it.
That is how it works, right?
Architects architect, developers develop.
Alex brings the diagram created in Miro board and starts the conversation:
Architecture pair review was over, rates were given, "The Corporate Architecture Guild"™️ approved the design, as it was modular, reinforcing important terms living in the local tourism domain.
Why so many changes?
Three teams were organized - each for the subsystem.
Kick-off happened, development started, feature factory rushed producing software.
Even "AI" was employed to increase productivity.
Enormous amounts of code was generated, but sooner rather than later, things started slowing down.
Even though there were only three modules, they interacted with each other in so many different ways, making a seemingly simple change a nightmare to introduce.
That made teams overcoordinating, blocking releases and making agility only on paper and daily standups (which were coordinated, by the way).
Lost payments, tours without guides, unplanned tours - all these issues started to pile up.
Alex, an architect was called to investigate what was going on.
He decomposed solution into modules, he paid attention to the language of stakeholders - but what was wrong?
Wasn't DDD supposed to help with that?
Tour, Participants, Guides - all these concepts were clearly defined in the language of stakeholders and have been represented in the code!
Isn't a domain model supposed to help with modularity?
Alex, an architect felt that he got tricked.
The ambiguity, the curse and the fallacy of domain model
Modularity - the holy grail of software design.
Who does not want to have modularized system, with clear boundaries, low coupling and high cohesion?
Often times, it ends up being a mirage, living in the PowerPoint slides, Miro boards and architecture decision records.
"It was decided that system will be modular" - sounds good, but what does it really mean?
Turns out that modularity hardly manifests itself while observing things standing still, motionless.
Drawing boxes, arrows between them, defining interfaces - all these activities are necessary, but not sufficient.
Let's use the tool for testing the design - a change.
What will be the impact of a given change?
How many modules will be affected?
How many teams will need to be involved?
Ultimate goal is reducing the blast radius of a change, the need for coordination and cognitive load on developers (of course, it all depends so that's why we use software architecture to tackle that, right?).
Autonomous teams.
Autonomous modules.
Autonomous models.
So the real deal is establishing boundaries that will yield certain quality attributes.
But why Alex's design faced challenges?
Compile-time hierarchies was one of the main reasons - pursuing "the reality", not taking into account perspectives and time, and more.
Single domain model encompassing all the aspects, in compile-time, makes knowledge gravity mercilessly manifesting itself with every change.
Instead of composing perspectives in runtime, Alex focused on "absolute" concepts, ignoring real abstractions.
A diaper
One of the most crucial aspects of any module is its boundaries.
Boundaries define what is inside and what is outside.
What are provided capabilities (interfaces) for its consumers and what is hidden (implementation details) from its consumers.

A diaper is quite a nice model for understanding boundaries, and problems that can arise when boundaries are not well defined and designed.
As with every model or metaphor, it is designed to be imperfect, highlighting certain aspects, while ignoring others (did I just described abstracting process?)
Nevertheless, a diaper has clear purposes - keep things that are supposed to be inside, inside, and do not let them leak outside.
It has pretty well defined interfaces, with stated capabilities - absorb liquids, contain waste, fasteners to keep it in place.
And a big deal of a module, I mean a diaper, is that it should be easily changeable - when it is full, it should be replaced with a new one, without much hassle.
So whenever a change happens, it should be easy job to be performed.
When we look at diapers when they are unused and there are no changes, they are clean, dry, nicely looking.

Motionlessly laying down, one can't state anything about how the boundaries will behave and be protected.
Until...
A diaper effect
...A change happens.
Parents know that changing a diaper is not a walk in the park.
Sometimes it is easy, sometimes it is messy.
Similar to working with modules - when a change is introduced, the entire architecture is put to the stress test.
And the nightmare begins when modules start leaking.
When one needs to touch many, many places to adjust the system's behavior, we are in the big trouble.

And that is what I call a diaper effect - when models leak, boundaries are established incorrectly (according to the context we are currently operating in), and modules become entangled.
They become entangled because of the shared, leaked knowledge (if you haven't, please grab a copy of Balancing Coupling by Vlad Khononov, it will change how you think about designing systems!).
Such leaked knowledge creates hidden dependencies between modules, due to knowledge gravity.
Each change leaks into many modules, requiring coordination, excessive testing of the entire system, and making delivery slow and painful.
Seemingly unimportant knowledge that gets located in the wrong module, not represented at all, or represented in two or more modules, makes the necessity to touch many places when a change is introduced.
Counteracting a diaper effect?
We don't need to wrestle with big systems to learn how to avoid a diaper effect.
Firstly, let's start learning how to modularize things in the lower levels - application level.
How to ensure that objects interact with each other in a way, that limits the scope of change?
How to ensure that interaction participants have clean interfaces, based on needs, and they follow the correct protocol of communication/interaction?
If you can't modularize in a small scale, how would you do that in a big one?
The art of destroying software is a great starter too.
"Write small things" - easy job, ain't it?
Putting jokes aside, definitely there are some heuristics one can employ to increase chances of avoiding a diaper effect and reduce potential problems.
Taking software dimensions into account might help - separating different perspectives, composing them in runtime, based on use cases.
Trying to escape Inverse Matrix might be also vital - seeing the world behind the code, understanding the real needs of stakeholders.
In general, paying attention to the business area in which we operate and we try to deliver software solutions for.
This also mean not following "the reality" blindly, but actually looking for abstractions that "live" in the given context.
Those abstractions - often are many different perspectives on the "same thing", required in different moments of time.
Eventually, one might understand that there is no single domain model, but rather a set of domain models, each serving its own purpose.
Another great opportunity is to simulate potential changes and see how they would impact the system - have a playful attitude and put a stress test on the architecture.
You might see how boundaries break, where the knowledge gravity attracts more knowledge, and where the modules start leaking.
And what about Domain-Driven Design - weren't it supposed to help with modularity?
Naive approaches, full of noun-based thinking, focusing on compile-time hierarchies, often lead to a diaper effect.
There are other levels from which we can model the domain, representing the knowledge.
Beware a diaper effect, dear Reader.
Beware the knowledge leaks!