Living Architecture - Crafting Code that Thrives with Us


„I should do better.“
„There has to be a smarter way.“
„We need a full rewrite.“
„Let’s switch to microservices.“
Sound familiar?
Wall of entanglement
Most of us who create software have hit a wall — or several — and found ourselves like this. The more projects we’ve seen, the more often those thoughts surface. Project after project. Again and again.
Or maybe you’ve been lucky. Maybe you haven’t hit that wall yet.
Or perhaps you’ve simply concluded:
„Software is hard. That’s just how it is. Oh well.“
We have Layered Architecture, Hexagonal architecture, Clean Architecture. There’s Domain Driven Design. There’s Object Oriented Design (yes, that’s a thing).
We’ve got clever frameworks. We have powerful IDE-s. We have access to amazing AI Agents.
And of course, we have the Microservices.
And still — with all of these (or despite) — we hit the same wall.
The path into that wall is familiar to most of us:
Services and layers intertwine, as codebases expand
Teams shift, as different people come and go
Rules bend and structure crumbles, as deadlines and requirements steer development.
Put plainly — over time, our system becomes a jungle. Its „architecture“ slowly withers into wilderness.
At one point, when we look for structure, we only find accidental architecture.
What once may have had structure has now grown tangled — dense, chaotic, impenetrable. Eventually, just making a change feels like hacking your way through the bushes.
You know that feeling — discovering code that’s almost right, but it’s unclear. Tricky to grasp. Maybe there are tests. Maybe they help. Maybe they don’t. Either way, you don’t trust it. You’re not even sure you understand it. You hesitate.
So instead — you copy. Paste. Tweak. Finally, you add an „if“.
Voilà — task complete. And best of all? You didn’t touch that code.
Because once you touch it... „it becomes yours“.
(Credit to Robert C. Martin for that honest twist)
And just like that — you’ve thickened the jungle. Entangled one more vine.
Once again, the thought returns:
„I should do better.“
Sound familiar?
We become overwhelmed by our hard-built system.
Eventually, we yearn for a rewrite.
Our once shiny new „green field“ project is now „the old system“ — jungled
And it all usually just takes about 5 years — give or take a few.
At least, I know I’ve been there. Over 25 years of creating software — over and over, project after project — I’ve seen and been there, time and time again.
Why does this happen?
Often, we just haven’t found a better way. And it’s perfectly normal. But we wish we did. We struggle and deep down, we feel — there must be a better way to do things. Better than the randomness we see in our codebases.
Randomness — accidental architecture — gains ground, when intention is lacking. It proliferates, where clear boundaries and close responsibilities aren’t cultivated. Where loose coupling and high cohesion isn’t prioritized.
The result: tight coupling and poor cohesion. Or simply — bad design.
We should do better.
After years of twists and turns — discoveries, mistakes, rebuilds — I humbly suggest:
We can do better.
There is a better way to work.
We can stay productive without burning quality.
We don’t need to rewrite everything every 5 years.
And no — we don’t need microservices just to feel in control.
It’s possible to work in a system that continues to feel fresh. Flexible. Alive.
A green garden of code with living architecture — nurtured, evolving, and embracing change.
How can we do better?
Not with religiously applied Agile processes and countless ceremonies.
Not through the clever features of our frameworks — or the next new one.
Not by slicing systems into dozens of tiny services.
But through structure with intention.
Through thoughtful design with explicit boundaries and clear responsibilities.
Through craft, practiced with continuous care — the kind of focus we give to things that really matter.
Modular monoliths — moduliths — are quietly becoming the new default in many top tech companies. They offer the simplicity of a monolith while delivering on the promise of loose coupling and high cohesion we once hoped to find in microservices.
But most monoliths aren’t modular — not really.
Boundaries are unclear.
Domains leak, contexts intertwine.
Dependencies sprawl.
Business logic tangles with technical concerns.
Levels of abstraction mix and blur.
Code is produced, to work, run and be forgotten — not crafted, to evolve and be understood.
We can do better — by reversing the above.
Crafting gardens
This blog is a living series of articles, growing over time, where I share the real-world principles, patterns and practices I’ve found helpful in my work — in cultivating sustainable modular architecture across different teams.
We’ll explore
Flourishing flowerbeds — anatomy of a thriving domain module
Solid pathways — integrations between different bounded contexts
Cultivated layout — thoughtfully separating concerns of application runtime, business domain and technical infrastructure
Detailed craftsmanship — practical techniques on code quality, automated testing and data consistency
Clearing the rocks — resolving issues with frameworks and libraries, to keep them as our tools, not as our masters.
We’ll start by crafting the foundation of a living, breathing, vibrant codebase — the domain module (which I’ve nicknamed DAIR). Step by step, we’ll reconstruct its anatomy and illuminate its pros and cons. We’ll then lay the groundwork to connect modules to the open world — integrating the system as a whole.
In subsequent chapters, we’ll play around with the freedom gained for sculpting the architecture — when adapting to ever-changing environments. Along the way, we’ll dive into common issues, patterns and practical solutions on setting up the system with build tools, frameworks and databases.
Of course, not all software can or should be built like this. Some problems dissolve in completely different ways. We will also visit some of these. However, the complexity of most business systems benefits greatly from domain-centric architecture. They remain thriving and resilient — in the true test of time.
The approaches shared aren’t new — they’re simply a synergy. Dozens of ideas and patterns, gathered over time, clicked together through trials. They stand on the shoulders of giants — fathers of Hexagonal Architecture, Domain-Driven Design and Clean Architecture.
What these writings convey, isn’t structure alone — it’s a mindset.
One of craftsmanship, care and cultivation.
A mindset for sustainable, thriving architecture.
A Living Architecture.
No silver bullet.
No map to blindly follow and hit gold.
No shortcut to success and mastery.
But a path — true to our craft. It works, if we do the work.
Ultimately, when these ideas help even a few more great developers like you move from withering jungles to flourishing code gardens — perhaps together we’ve shaped a much cleaner, greener world.
Up next on the horizon:
We’ll look at what Living Architecture means in practice and explore the makings of a sustainable, thriving Domain Module — from its inner structure, to its outer boundaries.
—> Chapter 1: Domain Modules — Structure with Intention
Appendix - sample code listings
A typical Order Processing flow (Java backend)
Order Processing flow in a domain-centric architecture (Java backend)
Subscribe to my newsletter
Read articles from Risto Uibo directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
