Clean Architecture
About
It is a model with the objective of decoupling the application independent business rules (or domain), from external resources (like frameworks, DBs).
Independent Business Rules, are business rules that are independent of context (should be followed despite of where are executed).
Ex.: Business Rules that aren't valid only in specific Usecases.
Clean Architecture is Usecase driven.
The project folder names is completely irrelevant to the Layers.
You can have Layers without folders separating the files.
Rules
The inner layers (high level) should not know implementations of external layers (low level), which is SOLID #D (Dependency Inversion Principle - DIP).
4 Layers

Entities
They are responsible for abstracting the Independent Business Rules, which can be from an object with methods to a group of functions.

What are Independent Business Rules?
Ex.:
Is
CarPlatevalid?What is the distance between two
Coords?How much is the
Ride Fare?How the
Ride Statuschange?
Domain Objects vs ORM Objects
Entity ORM object entity. (Which is a mere database table representation)

Clean Architecture + DDD (Domain Driven Design)
Entities can be broken in Aggregate, Entity, Value Object and Domain Service by using DDD (Domain Driven Design).
Clean Architecture don't clearly specify what an Entity can be as DDD does.
DDD strongly complements Clean Architecture Entity Layer.
Anemic Domain
Anemic means that an Object only handles Properties (State) OR Behavior, but not both.
Use Cases
They orchestrate the entities and external resources, meaning they will be sort of a bridge between Entities and Interface Adapters.
Usecases are behaviors offered to the Clients. (You application exists because of your exposed Usecases)
Very rarely a Usecase A will call another Usecase B.
But this still increases coupling in the Usecase A, increases time to complete the Usecase A.
So, instead of calling Usecases inside another Usecase, use Behavioral #Mediator Design Pattern to decouple these Usecases by using a bus/channel like a queue, for communication between them. (Not necessarilly an external tool like RabbitMQ)

Interface Adapters
These are the bridges between Usecases (High level) and External Resources (Low level).

External Interfaces
Here lies the lowest level of abstraction.
Where you actually interact with technology, with the components that connect to the Database, that deal with the HTTP requests, that interact with the filesystem or access S.O resources.
The ideia in here is to abstract only some level of the technology used, so that the Interface Adaptors won't know for instance if they will connect to a Postgres or MySQL database.
export default interface DatabaseConnection {
query(statement: string, params: any): Promise<any>;
close(): Promise<void>;
}export default class PgPromiseAdapter implements DatabaseConnection {
connection: any;
constructor() {
this.connection = pgp()('postgres://...');
}
query(statement: string, params: any): Promise<any> {
return this.connection?.query(statement, params);
}
async close(): Promise<void> {
await this.connection?.$pool.end();
}
}But there is a certain level of restriction for decoupling External Interfaces.
Ex.: You may not be able to write a contract for the Database connection that works on unsimilar technologies. (Like Postgres and Mongo)

Interface Adapter vs External Interfaces
Interface Adapter vs External InterfacesIn Hexagonal Architecture (Ports and Adapters), there is no difference between Interface Adapters and External Interfaces, they are the same.
An example of mixing Interface Adapters with External Interfaces would be:
Having the code that connects to the Database inside a Repository like this.
class UserRepository {
async getUserById(userId: string): Promise<User> {
const connection = pgp()('postgres://...');
const user = connection.query('SELECT * FROM user WHERE id = $1', [userId]);
await connection.$pool.end();
}
}So, there is a certain level of coupling of Postgres with our Interface Adapter that is called from the Usecase.
Examples of Folder Divisions
Simpler
/src
├── /core
├── /exceptions
└── /entities
└── <entity-name>.ts
├── /usecases
└── <usecase-name>.ts
├── /infra
├── /repositories
├── /gateways
├── /http
└── ...
└── main.ts
/tests
├── /unit
├── /integration
└── /e2eMore complex
Last updated
