The document discusses monolithic architecture and different types of monoliths. It argues that a physical monolith is often the best initial approach and that problems typically arise from logical monoliths that lack clear boundaries. A modular monolith is proposed as an optimal architecture, with distinct modules but a shared codebase and deployment. The document also covers techniques for implementing modular monoliths, such as defining module boundaries, startup classes per module, and routing.
1. Return of the Monolith
(Episode VI)
@alper_hankendi
github.com/alperhankendi
2. 2
Good and Bad Monolith
Neal Ford stated in his book Building Evolutionary Architectures:
“ If you can’t build a monolith, what makes you think microservices are the
answer ”
Microservice premium(Blog article) by M.Fowler:
“ Don't even consider microservices unless you have a system that's
too complex to manage as a monolith. ”
- In fact, a physical monolith is typically the right thing to do.
Pure evil is monolithic thinking.
7. 7
Good and Bad Monolith
Neal Ford stated in his book Building Evolutionary Architectures:
“ If you can’t build a monolith, what makes you think microservices are the
answer ”
Microservice premium(Blog article) by M.Fowler:
“ Don't even consider microservices unless you have a system that's
too complex to manage as a monolith. ”
- In fact, a physical monolith is typically the right thing to do. Pure
evil is monolithic thinking.
- The disturbing question is: Why is monolith synonymous with a bad
design for some and yet the right thing to do for others
8. 8
Two Kinds of Monolith
Physical Monolith
A physical block of software, typically running
as a single process.
A physical monolith system is developed and
built as a single binary(artifact), deployed all
at once and falling in its entirely.
Resources; database are often shared,
communication is local.
A physical monolith is not anti-pattern. It is a
good thing to start with as it is easy to
build,deploy and operate.
9. 9
Two Kinds of Monolith
Logical Monolith a.k.a Big ball of mud
Logically monolithic codebases lack boundaries,
everything is coupled to everything and no visible
architecture is to be found.
Logical monoliths is unmaintainable on a scale
and complexity grows exponentially.
Logical monoliths are evil and dangerous
constructs that cause high complexity and tight
coupling of building blocks making development
expensive and free error.
10. 10
By doing things right
Modular Monolith
The opposite of a logical monolith is a modular
monolith. Codebase business capabilities are
worked out by services with explicit logical
boundaries.
A Modular monolith is probably the best
architectural approach for most applications. It is
easy to extend,maintain and other reasons.
11. 11
By doing things very wrong
Distributed Monolith
A logically,but not physically, monolithic systems is
named a distributed monolith.
Distributed monoliths have all the drawbacks of
distributed systems with almost none of the
benefits.
With dealing with the big ball of mud is a pain but
distributed monoliths are a real disaster.
Systems often end up as distributed monoliths
while adapting the microservices approach
incorrectly.
12. 12
Types of systems by physical and logical architecture
If you have problem with your monolithic system,
the problem most likely its logically monolithic
design.
The physical of the monolith is usually a secondary
problem, easy to solve after the proper SOA
design has been applied.
One the logical monolith is resolved,You’re very
close to apply microservice architecture.
15. 15
Context is king
Each of our decisions are made in a given
context.
The same decision made in one context can
bring great result, while in another context can
cause devastating failure.
Simon Brown in the book Software Architecture
for Developers describes Architectural Drivers;
“ Regardless of the process that you follow
(traditional and plan-driven vs lightweight and
adaptive), there’s a set of common things that
really drive, influence and shape the resulting
software architecture. ”
src:https://www.neverletdown.net/2014/10/architectural-drivers.html
16. 16
Drivers categorization
src:https://www.neverletdown.net/2014/10/architectural-drivers.html
The main categories are;
- Functional Requirements: what and how
problems does the system solve.
- Quality Attributes: a set of attributes that
determine the quality of architecture like
maintainability or scalability
- Technical Constraints: technology standards,
patterns, tools limitations, team experience
- Business Constraints: Organization,budget, tight
timeline (a.k.a deadlines)
17. 17
There is no one “right” solution
The Software architecture is a continuous choice between one driver and another. There is no Silver
Bullet.
The shape of the architecture of your system is influenced by many factors and everything depends
on your context.
18. 1
8
The Model Code Gap
Your architecture models and your source code will not
show the same things. The difference between them is the
model-code gap.
The gap between executable
code and the abstractions we
use to discuss systems is something
many developers don’t realize
and aren’t familiar with.
https://www.cs.toronto.edu/~gelahi/Ref/Reflexion%20models.pdf
21. 21
Majestic Monoliths
One API can depend on
another API or implementation
can depend on another API,
but implementations can’t
directly depend on
each other.
31. 31
Data Isolation Strategies
❏ Ensure each module accesses its own tables
❏ No sharing of tables between modules
❏ Joins only between tables which in same module
❏ Maintain referential integrity and transactions across modules
33. 33
Modular Monoliths with dotnet
A modular monolith is still a monolith, but the term monolith refers more to the
hosting/runtime model. Each service/part is located in its own module (.NET project)
and is therefore decoupled from other modules
https://abp.io/
https://github.com/thinktecture-labs/aspnetcore-modular-monolith
36. 36
Routing to Module Controllers
To prevent name clashes between controllers in different modules, we should prefix all
routes to modules.
37. 37
Startup per Module
To allow registration of custom services in a module, we should provide a startup file per
module. This can be done by defining an IStartup interface that can be implemented in a
module.
38. 38
Startup per Module
An example implementation of IStartup might look like this. (like bootstrapper)
40. 40
Lessons Learned
❏ Everything is trade-off.
❏ Modular / Majestic Monoliths can move as fast as or faster than Microservices
❏ Monolith first approach is win, Thank me later.
❏ Modules reduce complexity and provide abstractions so that systems are easier
to understand
❏ We are reading code and trying to understand it %95 of our time.
❏ Spend more time defining Module boundaries
❏ Consider merging “chatty” modules
❏ Database Sharding may be a good first step
❏ Carefully plan how you will share data between modules
❏ Modules should be determined with the help of Domain Driven Design
❏ Discover core domain & subdomains
❏ Defining the boundaries
❏ Context Mapping