English Class Presentation - Arturo Ruvalcaba (Sohnen) Onion Architecture

You might also like

Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 4

Onion Architecture

Onion Architecture was introduced by Jeffrey Palermo to provide a better way to build
applications in perspective of better testability, maintainability, and dependability.

Onion Architecture

Domain entities are the core and center part. Onion architecture is built on a domain model in which
layers are connected through interfaces. The idea is to keep external dependencies as far outward as
possible where domain entities and business rules form the core part of the architecture.

Benefits of implementing Onion Architecture:


 It provides flexible, sustainable and portable architecture.
 Layers are not tightly coupled and have a separation of concerns.
 It provides better maintainability as all the code depends on deeper layers or the center.
 Improves overall code testability as unit tests can be created for separate layers without impacting other
modules.
 Frameworks/technologies can be easily changed without impacting the core domain. e.g. RabbitMQ can
be replaced by ActiveMQ, SQL can be replaced by MongoDB
Onion Architecture Principles
Onion Architecture is comprised of multiple concentric layers interfacing with each
other towards the core that represents the domain. It is based on the inversion of control principle. The
architecture does not focus on underlying technology or frameworks but the actual domain models. It is based
on the following principles.

Dependency
The circles represent different layers of responsibility. In general, the deeper we dive, the closer we get to
the domain and business rules. The outer circles represent mechanisms and the inner circles represent
core domain logic. The outer layers depend on inner layers and the inner layers are completely unaware
of outer circles. Classes, methods, variables, and source code in general belonging to the outer circle depends
on the inner circle but not vice versa.

Data formats/structures may vary from layers. Outer layer data formats should not be used by inner layers. E.g.
Data formats used in an API can vary from those used in a DB for persistence. Data flow can use data transfer
objects. Whenever data crosses layers/boundaries, it should be in a form that is convenient for that layer. E.g.
API’s can have DTO’s, DB layer can have Entity Objects depending on how objects stored in a database vary
from the domain model.

Data encapsulation
Each layer/circle encapsulates or hides internal implementation
details and exposes an interface to the outer layer. All layers
also need to provide information that is conveniently consumed by
inner layers. The goal is to minimize coupling between layers
and maximize coupling within a vertical slice across layers. We
define abstract interfaces at deeper layers and provide their
concrete implementation at the outermost layer. This ensures we
focus on the domain model without worrying too much about
implementation details. We can also use dependency injection
frameworks, like Spring, to connect interfaces with implementation
at runtime. E.g. Repositories used in the domain and external
services used in Application Services are implemented at the
infrastructure layer. Data Encapsulation in Onion Architecture

Separation of concerns
Application is divided into layers where each layer has a set of responsibilities and addresses separate
concerns. Each layer acts as modules/package/namespace within the application.

Coupling
Low coupling in which one module interacts with another module and does not need to be concerned with
the other module’s internals. All the internal layers need not be concerned about internal implementation
of external layers.
Onion Architecture Layers
Domain Model/Entities
Domain Entities are the fundamental building block of Domain-Driven
Design and they’re used to encapsulate attributes and entity behavior. It
is supposed to be independent of specific technologies like databases or web
APIs. E.g. In the Orders domain. Order is an entity and has attributes like
OrderId, Address, UserInfo, OrderItems, PricingInfo and behavior like
AddOrderItems, GetPricingInfo, ValidateOrder, etc. Order entity class

Domain services
Domain services are responsible for holding domain logic and business rules. All the business logic should
be implemented as a part of domain services. They are NOT typically CRUD services and are usually
standalone services. Domain services are responsible for complex business rules like computing pricing and tax
information when processing order, Order repository interface for saving and updating order, Inventory
Interface for updating information about items purchased, etc.
It consists of algorithms that are essential to its purpose and implement the use cases that are the heart of
the application.

Application services
Also referred to as “Use Cases”, are services responsible for just orchestrating steps for requests and
should not have any business logic. Application Services interact with other services to fulfil the client’s
request. Let’s consider the use case to create an order with a list of items. We first need to calculate the price
including tax computation/discounts, etc., save order items and send order confirmation notification to the
customer. Pricing computation should be part of the domain service, but orchestration involving pricing
computation, checking availability, saving order and notifying users should be part of the application service.
The application services can be only invoked by Infrastructure services.

Infrastructure services
Also referred to as Infrastructure adapters. These services are responsible for interacting with the
external world and do not solve any domain problem. These services just communicate with external
resources and don’t have any logic. E.g. External notification Service, GRPC Server endpoint, Kafka event
stream adapter, database adapters.

Illustrating Dependency across Layers

When receiving a create order request, we would like to validate the order, save the order in the database,
update inventory for all order items, debit order amount and lastly send a notification to the customer about
order completion.
Onion Architecture Implementation/Testing
Implementation
No direction is provided by the Onion Architecture guidelines about how the layers should be implemented.
The architect should decide the implementation and is free to choose whatever level of class, package, module,
or whatever else is required to add in the solution.

Testing Strategy
Different layers of onion architecture have a different set of responsibilities and accordingly, there are different
testing strategies.

Testing Strategy for Different Layers

Conclusion
Onion architecture might seem hard in beginning but is widely accepted in the industry. It is a powerful
architecture and enables easy evolution of software. By separating the application into layers, the system
becomes more testable, maintainable and portable. It helps easy adoption of new frameworks/technologies
when old frameworks become obsolete.

You might also like