0% found this document useful (0 votes)
3 views

Lecture4Notes (2)

Monolithic architecture is a traditional software design model where all components are integrated into a single executable unit, making deployment and development simpler but potentially hindering scalability and flexibility. While it offers advantages like easy deployment and simplified testing, it also presents challenges such as slower development speed and deployment coupling, which can complicate updates. The document discusses various forms of monoliths, including modular and distributed monoliths, and emphasizes the importance of managing coupling and domain interactions effectively.

Uploaded by

suayilseven764
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
3 views

Lecture4Notes (2)

Monolithic architecture is a traditional software design model where all components are integrated into a single executable unit, making deployment and development simpler but potentially hindering scalability and flexibility. While it offers advantages like easy deployment and simplified testing, it also presents challenges such as slower development speed and deployment coupling, which can complicate updates. The document discusses various forms of monoliths, including modular and distributed monoliths, and emphasizes the importance of managing coupling and domain interactions effectively.

Uploaded by

suayilseven764
Copyright
© © All Rights Reserved
Available Formats
Download as PPTX, PDF, TXT or read online on Scribd
You are on page 1/ 34

COMP 301 Week 5

Monolithic Architecture
Monolithic Architecture
• A monolithic architecture is the traditional unified
model for the design of a software program.
• Monolithic, in this context, means "composed all in
one piece."
• In a monolithic architecture, each component and its
associated components must all be present for code to
be executed or compiled and for the software to run.
• When all functionality in a system had to be deployed
together, we consider it a monolith.
Context
• You are developing a business-critical enterprise
application.
• You need to deliver changes rapidly, frequently and
reliably in order for your business to thrive in today’s
volatile, uncertain, complex and ambiguous world.
• Consequently, your engineering organization is
organized into small, loosely coupled, cross-functional
teams.
• The team delivers a stream of small, frequent changes
that are tested by an automated deployment pipeline
and deployed into production.
Context A team is responsible for one or more
subdomains.

A subdomain is an implementable model


of a slice of business functionality

It consists of business logic, which


consists of business entities that
implement business rules, and adapters,
which communicate with the outside
world.

The subdomains implement the


application’s behavior, which consists of a
set of (system) operations

An operation is invoked in one of three


ways: synchronous and asynchronous
requests from clients
It mutates and queries business entities
in one or more subdomains.
Problem
• How to organize the subdomains into one or more
deployable/executable components?
• Design an architecture that structures the application as
a single deployable/executable component that uses a
single database. The component contains all of the
application’s subdomains. Since there’s a single
component, all operations are local.
Solution
Monolitic Arc.
Example: E-commerce
Application
• Let’s imagine that you are building an e-
commerce application that takes orders
from customers, verifies inventory and
available credit, and ships them.

• The application is deployed as a single


monolithic application.
• For example, a Java web application
consists of a single WAR file that runs on a
web container such as Tomcat.
• A Rails application consists of a single
directory hierarchy deployed using either,
for example, Phusion Passenger on
Apache/Nginx or JRuby on Tomcat.
• You can run multiple instances of the
application behind a load balancer in order
to scale and improve availability.
Resulting context:Advantages

• Easy deployment – One executable file or directory makes


deployment easier.
• Development – When an application is built with one code base,
it is easier to develop.
• Performance – In a centralized code base and repository, one
API can often perform the same function that numerous APIs
perform with microservices.
• Simplified testing – Since a monolithic application is a single,
centralized unit, end-to-end testing can be performed faster than
with a distributed application.

Easy debugging – With all code located in one place, it’s easier
to follow a request and find an issue.
Resulting context:Disadvantages
• Slower development speed – A large, monolithic application
makes development more complex and slower.
• Scalability – You can’t scale individual components.
• Reliability – If there’s an error in any module, it could affect the
entire application’s availability.
• Barrier to technology adoption – Any changes in the framework
or language affects the entire application, making changes often
expensive and time-consuming.
• Lack of flexibility – A monolith is constrained by the technologies
already used in the monolith.
• Deployment – A small change to a monolithic application requires
the redeployment of the entire monolith.
Single Monolith
The most common example that comes to mind
when discussing monoliths is a system in which all of
the code is deployed as a single process.

You may have multiple instances of this process for


robustness or scaling reasons, but fundamentally all
the code is packed into a single process
Modular Monolith
• As a subset of the single
process monolith,
the modular monolith is a
variation: the single process
consists of separate
modules, each of which can
be worked on
independently, but which
still need to be combined for
deployment,
Modular Monolith
• For many organizations, the modular monolith can be
an excellent choice. If the module boundaries are well
defined, it can allow for a high degree of parallel
working.
• One of the challenges of a modular monolith is that the
database tends to lack the decomposition we find in the
code level, leading to significant challenges that can be
faced if you want to pull the monolith in the future.
Problem with Modular Monolith
• Some teams attempt to push
the idea of the modular
monolith further, having the
database decomposed along
the same lines as the
modules, as shown.
• Fundamentally, making a
change like this to an existing
monolith can still be very
challenging even if you’re
leaving the code alone
Distributed Monolith

• A distributed monolith is a system that consists of


multiple services, but for whatever reason the entire
system has to be deployed together.
• A distributed monolith may well meet the definition of a
service-oriented architecture, but all too often fails to
deliver on the promises of SOA.
• Distributed monoliths typically emerge in an
environment where not enough focus was placed on
concepts like information hiding and cohesion of
business functionality, leading instead to highly coupled
architectures in which changes ripple across service
boundaries
Challenges of Monoliths

• As you have more and more people working in the same


place, they get in each other’s way.
• Different developers wanting to change the same piece
of code, different teams wanting to push functionality
live at different times (or delay deployments).
• Confusion around who owns what, and who makes
decisions.
On Coupling
• We like cohesion we like, but we’re wary of coupling.
• The more things are “coupled”, the more they have to
change together.
• But there are different types of coupling, and each type
may require different solutions.
Implementation coupling
What is the problem?
• A is coupled to B in terms of how B
is implemented—when the
implementation of B changes, A
also changes.
• A classic and common example of
implementation coupling comes in
the form of sharing a database.
• The Recommendation service
suggests records to our customers
that they might like to buy based
on previous purchases. Currently,
the Recommendation service
directly accesses this data from
the database.
Solution
• Recommendations require
information about which orders
have been placed.
• To an extent, this is
unavoidable domain coupling,
which we’ll touch on in a moment.
• But in this particular situation,
we are coupled to a specific
schema structure, SQL dialect,
and perhaps even the content
of the rows.
Alternative Solution
• We could also have the
Order service publish a
dataset, in the form of a
database, which is meant to
be used for bulk access by
consumers.
• As long as the Order service
can publish data accordingly,
any changes made inside the
Order service are invisible to
consumers, as it maintains
the public contract.
Common thing in both solution
• In effect, with both of the preceding examples, we are
making use of information hiding.
• The act of hiding a database behind a well-defined
service interface allows the service to limit the scope of
what is exposed, and can allow us to change how this
data is represented.
• Another helpful trick is to use “outside-in” thinking
when it comes to defining a service interface:
drive the service interface by thinking of things from the point
of the service consumers first, and then work out how to
implement that service contract.
Tip!
• With “outside-in” thinking, you instead first ask, “What do my
service consumers need?” And I don’t mean you
ask yourself what your consumers need; I mean you actually ask
the people that will call your service!
• Think of your service contract with the outside world as a user
interface. When designing a user interface, you ask the users
what they want, and iterate on the design of this with your users.
• You should shape your service contract in the same way. Aside
from the fact it means you end up with a service that is easier for
your consumers to use, it also helps keep some separation
between the external contract and the internal implementation.
Temporal coupling
• Temporal coupling is primarily a runtime concern that generally speaks
to one of the key challenges of synchronous calls in a distributed
environment.
• When a message is sent, and how that message is handled is
connected in time, we are said to have temporal coupling.

Here we see a synchronous HTTP call made from our Warehouse service to a
downstream Order service to fetch required information about an order. To satisfy the
request, the Order service in turn has to fetch information from the Customer
service, again via a synchronous HTTP call. For this overall operation to complete,
the Warehouse, Order, and Customer services all needed to be up, and contactable.
They are temporally coupled.
Solution to Temporal Coupling
• We could reduce this problem in various ways:
1. We could consider the use of caching—if the Order
service cached the information it needed from the
Customer service, then the Order service would be
able to avoid temporal coupling on the downstream
service in some cases.
2. We could also consider the use of an asynchronous
transport to send the requests, perhaps using
something like a message broker. This would allow a
message to be sent to a downstream service, and for
that message to be handled after the downstream
service is available.
Deployment Coupling
• Consider a single process, which consists of multiple
statically linked modules.
• A change is made to a single line of code in one of the
modules, and we want to deploy that change.
• In order to do that, we have to deploy the entire
monolith—even including those modules that are
unchanged.
• Everything must be deployed together, so we
have deployment coupling.
Deploying something carries risk.
• There are lots of ways to reduce the risk of deployment, and one
of those ways is to change only what needs to be changed.
• If we can reduce deployment coupling, perhaps through
decomposing larger processes into independently deployable
microservices, we can reduce the risk of each deployment by
reducing the scope of deployment.
• Reducing deployment coupling doesn’t require microservices,
of course.
• Runtimes like Erlang allow for the hot-deployment of new versions
of modules into a running process. Eventually, perhaps more of us
may have access to such capabilities in the technology stacks we
use day to day
Domain Coupling
• Fundamentally, in a system that consists of multiple
independent services, there has to be some interaction
between the participants.
• For instance, If you want to place an order, you need to
know what items were in a customer’s shopping basket.
If you want to ship a product, you need to know where
you ship it.
Example Case: Music Corp.
• We have a warehouse that stores goods.
• When customers place orders for CDs, the folks working
in the warehouse need to understand what items need
to be picked and packaged, and where the package
needs to be sent.
• So, information about the order needs to be shared with
the people working in the warehouse.
Music Corp.
• An Order Processing service sends
all the details of the order to the
Warehouse service, which then
triggers the item to be packaged up.
• As part of this operation, the
Warehouse service uses the
customer ID to fetch information
about the customer from the
separate Customer service so that
we know how to notify them when
the order is sent out.
What is the problem with given
scenario?
• In this situation, we are sharing the entire order with the
warehouse, which may not make sense—the warehouse needs
only information about what to package and where to send it.
• They don’t need to know how much the item cost (if they need to
include an invoice with the package, this could be passed along
as a pre-rendered PDF).
• We’d also have problems with information that we have to
control access to being too widely shared—if we shared the full
order, we could end up exposing credit card details to services
that don’t need it, for example.
How can I reduce the risk?
• So instead, we might
come up with a
new domain
concept of a Pick
Instruction
containing just the
information the
Warehouse service
needs.
• This is another
example of
information
Further Improvement????
• We could further reduce coupling by removing the need for the
Warehouse service to even need to know about a customer if we
wanted to—we could instead provide all appropriate details via the
Pick Instruction

For this approach to work, it probably means that at some point


Order Processing has to access the Customer service to be
able to generate this Pick Instruction in the first place, but it’s
likely that Order Processing would need to access customer
information for other reasons anyway, so this is unlikely to be
much of an issue.

This process of “sending” a Pick Instruction implies an API call


being made from Order Processing to the Warehouse
service.
Any other alternative???
An alternative could be to have Order Processing emit
some kind of event that the Warehouse consumes

By emitting an event that the Warehouse consumes, we


effectively flip the dependencies.

We go from Order Processing depending on the


Warehouse service to be able to ensure an order gets
sent, to the Warehouse listening to events from the
Order Processing service.

Fundamentally, some information is needed about


an order for the Warehouse service to do any
work.
We can’t avoid that level of domain coupling. But
by thinking carefully about what and how we
share these concepts, we can still aim to reduce
the level of coupling being used.
Shopify Example
• https://www.youtube.com/watch?v=ISYKx8sa53g
When we should use monolithic
architecture?
• At the beginning of the software development lifecycle, it is
usually easier to go with the monolithic architecture since
development can be simpler during the early stages.
• A single codebase also simplifies logging, configuration
management, application performance monitoring and other
development concerns.
• Deployment can also be easier by copying the packaged
application to a server.
• Finally, multiple copies of the application can be placed behind
a load balancer to scale it horizontally

You might also like