Repurposing LNG terminals for Hydrogen Ammonia: Feasibility and Cost Saving
Onion Architecture / Clean Architecture
1. Onion / Clean Architecture
uh... ogres are like onions!
2. $whoami
• Attila Bertók
• C# technical lead
• Contact:
• bertok.atti@gmail.com
• https://www.linkedin.com/in/bertokattila/
3. What is an Onion Architecture like?
• Shrek: ... uh... ogres are like onions!
• [holds up an onion, which Donkey sniffs]
• Donkey: They stink?
• Shrek: Yes... No!
• Donkey: Oh, they make you cry?
• Shrek: No!
• Donkey: Oh, you leave 'em out in the sun, they get all brown, start sproutin' little white hairs...
• Shrek: [peels an onion] NO! Layers. Onions have layers. Ogres have layers... You get it? We both have layers.
• [walks off]
• Donkey: Oh, you both have LAYERS. Oh. You know, not everybody like onions. CAKE! Everybody loves cake! Cakes have
layers!
• Shrek: I don't care what everyone likes! Ogres are not like cakes.
4. Why do we even need
architecture?
What has the architectures ever given us?
5. Aspects that (used to) define a system
• Programming language
• Frameworks and Libraries
• Database
• UI
• Environment (desktop / web), “natural habitat”
• Delivery method
8. Screaming Architecture
• The blueprint of a church/library/hospital emphasizes different considerations that of
a family residence, as the “use cases“ are different. Considerations on implementation
detail (building material, color, etc.) should be secondary.
9. Architecture as Support Structure
• Architectures are structures that support the use cases of the system.
• A good software architecture is rather similar to a good blueprint: it concentrates on
the use cases, and lets minor decisions (what database engine to use? What
framework(s) to use? What programming language to use? Should web or desktop
environment be used?) be deferred.
• The architecture should clearly communicate the intent (the business domain)
• And not the implementation details (ASP, MVVM, Ruby on Rails)
• “Screaming architecture”
10. Postponing Decisions
• The best decision is a postponed decision.
• You might later learn certain facts that if you knew in advance might have made a
difference.
• It is possible that you might realize that what you thought necessary at a point in
development is not even required, so you can decide on not having a certain component at all.
• You are forced to make your dependencies modular (and it makes it easy to make them
testable).
• You are forced to depend on abstractions.
11. Paradigm Shift:
Implementation Agnostic Architecture
• Database is a detail
• GUI is a detail
• Programming language is a detail
• Delivery method is a detail
These details should be handled independently and arranged around the business logic.
Domain-Driven Design? / Behavior-Driven Development? / Acceptance-Test-Driven
Development?
13. Yes, SOLID again
• It does not only apply on class level, but on method level, or the other way around,
module/project level as well
• Or at least some rather similar principles do apply
• At least most of the principles can be scaled up to modules in a sensible way
14. SOLID
• Single Responsibility Principle – Separation of Concerns:
one module should have one reason to change
• Common Closure Principle:
• Those classes that change for the same reasons and at the same times should be gathered into one
component. Those classes that change for different reasons and at different times should be separated
into different components.
• Connected to the Open/Closed principle as well: components are closed to some changes
15. SOLID
• Liskov Substitution Principle
• Let’s skip discussing this one, does not have serious architectural implications.
16. SOLID
• Interface Segregation Principle:
don’t create dependency on components you don’t need
• Common Reuse Principle:
• Don’t depend on classes you don’t need.
• “Component-segregation”
• If some classes depend on a component, they should depend on all of said component (or at least on an
a significant portion of said component). Independent parts mean that the original component can be
separated to smaller components.
17. SOLID
• Inversion of Dependencies – Loose Coupling:
modules should be easy to be swapped or modified, independently of each other
• Stable Dependencies Principle:
• Depend in the direction of Stability.
• I = R| / (R| + R|)
• Don’t depend on components that are more instable.
• Stable Abstractions Principle:
• A component should be as abstract as it is stable.
• A = Nac / Nc
• SDP + SAP = DIP in the component-world: “Depend in the direction of abstraction”
20. A classical architecture-diagram
• Layers are… well, “layered”, from bottom to top
• References point downwards, from the top to the bottom, layers are only allowed to
reference layers directly beneath themselves.
22. Problems of the classic n-tier solution
• Visualization concerns:
• A lot of boxes with complex dependencies might not be easy to visualize
• There are boxes that intersect layers (cross-cutting concerns)
• These are mostly visualized as high, standing columns, and are usually called “Framework” or
“Infrastructure”
• A more practical concern:
• Strong coupling: “boxes” have some assumptions about each other, generally about boxes
they have beneath them (we generally have assumptions towards the DAL – even from the
level of the UI (they might be transitive dependencies, and not direct ones, still, they are
dependencies))
24. The Onion
• At first glance, it seems to be just a fancy way of visualizing a complex N-tier
architecture
• The visualization is more favorable as low layers generally contain only small
amounts of code, in a small amount of modules – thus drawing only a few big boxes
would be misleading
• What the onion does is it wraps the box diagram around, using a pie diagram instead
• Whatever was on the bottom is now on the inside
25. 3-tier, in an almost-onion format
Client / UI
Business Logic
Data access
26. Onion layer-diagram
• Layers are built on each other from the inside to the outside
• The Dependency Rule: References are pointing inward, layers can only reference
layers beneath their own level, but they can reference other layers any level beneath
themselves.
• There are interfaces defined between the layers
• These interfaces physically belong to the more central layer.
• Modules in the same layer know nothing about each other, they are not connected
directly. Their only knowledge about each other comes through interfaces from lower
layers and DI. (And some sort of Pub/Sub messaging.)
27. So, all I need to do…
Is to start with this… And create this, right?
33. Entities
• Entities represent business objects
• that have application independent business rules.
• They could be
• Books in a library
• Employees in an employee registry.
• All the application agnostic business rules should be located in the entities.
34. Boundaries
• Boundaries (seams) are the link to the outside world.
• Boundaries are functional: they accept data requests and produce responses as result.
• A boundary can define functionality for processing data for a graphical user interface
or a web API.
• These abstractions are concretely implemented by interactors.
35. Interactors
• Interactors are the business logic layer of the application.
• They accept requests through the boundaries and manipulate entities (application
state).
• They know of request and response models.
• Interactors are concrete implementations of boundaries.
37. Layers
• Core (Policies – the most general and high level rules)
• Domain Entity Interfaces (Domain Entity Boundary)
• Domain Entities
• Data Access Interfaces (Data Access Boundary)
• Business Logic Interfaces (Service Interfaces – Use Case Boundary)
• Services (Use Cases)
• Application Services (Business Logic – Interactors)
• Interface Adapters / Infrastructure (Mechanisms)
• Data access (Repositories, Data mappers)
• Common infrastructure / Utility (aspects – Dependency injection, logging, file I/O, etc.)
38. Core
• Domain Entity Interfaces: (IUser)
• Domain Entities: implementation(s) to the above entities (User, Administrator)
• Data Access Interfaces: interfaces for domain entity repositories (IUserRepository).
Beware: implementations are not part of this layer! Remember the Dependency
Inversion Principle: “Abstractions should not depend on details. Details should
depend on abstractions.” Data access is a detail, we should not create a dependency
on it.
• Business Logic Interfaces: interfaces for business logic interactors
40. Application Service Interfaces / Interface Adapters
• Data Access: Implementation of Data Access Interfaces project from the Core layer.
• Common Infrastructure / Utilities: Infrastructural details, such as DI, logging, etc.
• UI
41. Depend in the Direction of Stability
• The Core is stable! (It is generally not modified frequently)
• The Core has very abstract components (Boundaries!)
• Depending on the Core is depending in the direction of stability and abstraction.
• The Services / Use Cases layer is sort of stable, frequently extended, rarely modified
(Open/Closed Principle)
• The Application Service Interfaces depend (implement) the interfaces (boundaries)
from the inner layers (they depend in the direction of stability and abstraction).
42. Summary
• Dependency rule: you can reference inner layers only
• References can reach multiple layers inside
• The innermost layer (Core) contains Entities and Interfaces to outer layers
• Other inner layers (Use Cases) contain Interactors (Business Rules)
• Data Access (as a detail) is not part of the Core, it is instead part of the outermost
layer
• Were this an n-tier diagram, this would be the top layer, not the bottom!
• The GUI (as a detail) is also a part of the outermost layer
• Frameworks and other infrastructure (as details) are part of the outermost layer
• Tests are also part of the outermost layer
43. A tiny bit of history, please?
• Jeffery Palermo, 2008
• MVP, asp.net book author / co-author
• Onion Architecture was born as an extension of Model-View-Controller
• http://jeffreypalermo.com/blog/the-onion-architecture-part-1/
• Robert Cecil Martin, 2011
• Development Evangelist, Clean Code Advocate, God
• https://8thlight.com/blog/uncle-bob/2011/09/30/Screaming-Architecture.html
• https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html
• https://www.youtube.com/watch?v=Nsjsiz2A9mg
44. Q&A
Why is our product not structured like this is not allowed.
Following the control flow, we have an HTTP Request that reaches the Controller. The controller will then:
Dismantle the Request;
Create a Request Model with the relevant data;
Execute a method in the Interactor (which was injected into the Controller using the Interactor’s interface, the Boundary), passing it the Request Model;
The Interactor:
Uses the Entity Gateway Implementation (which was injected into the Interactor using the Entity Gateway Interface) to find the relevant Entities;
Orchestrates interactions between Entities;
Creates a Response Model with the data result of the Operation;
Populates the Presenter giving it the Response Model;
Returns the Presenter to the Controller;
Uses the Presenter to generate a ViewModel;
Binds the ViewModel to the View;
Returns the View to the client.