You are on page 1of 14

🏗️

Clean architecture
Created @June 28, 2022 10:46 AM

Last Edited Time @February 9, 2023 11:31 AM

Type Architecture Design Pattern

Created By ế
khi t cao

Tags

Table of contents
Table of contents
References
Overview
The dependency rule
General layers (top→ down)
Layers
Models
Repository
Usecase / interactor
Presenter
Delivery
Flow layer
Common question
Communication between layer
In Ahamove project
Conclusion
Implementation of Clean Go
Controllers and presenters
Implementation in official Go-clean-architect

References

Clean architecture 1
Try clean architect and how to test for each layers: https://hackernoon.com/golang-
clean-archithecture-efd6d7c43047
https://github.com/bxcodec/go-clean-arch
Specific implement Go Clean: https://manakuro.medium.com/clean-architecture-with-
go-bce409427d31
http://www.plainionist.net/Implementing-Clean-Architecture-Controller-Presenter/
Quite details, should read, summary some key points: https://github.com/evrone/go-
clean-template
How to organize package-layout: https://medium.com/@benbjohnson/standard-
package-layout-7cdbc8391fc1
Go-clean-mircoservices series: https://medium.com/@jfeng45/go-microservice-with-
clean-architecture-a08fa916a5db
Sample code and test, layers: delivery, usecase and datastore:
https://medium.com/swlh/developing-a-web-application-in-go-using-the-layered-
architecture-8fc13209c808
Organize layers: https://threedots.tech/post/introducing-clean-architecture/
Hexagonal-onion-clean architecture detail
https://herbertograca.com/2017/11/16/explicit-architecture-01-ddd-hexagonal-onion-
clean-cqrs-how-i-put-it-all-together/

Clean architecture 2
Overview
Domain objects and rules doesn’t change often. On the other hand, frameworks,
middlewares, DB change more frequently. So for a long time, we need to separate the
domain logic from technology. Your domain class should never be dependent on the
classes you use technology and libraries for.

Clean architecture 3
Domain services (Use Cases): Business logic consists of codes such as creating,
updating, processing, sharing between services

The dependency rule


Source code dependencies can only point inwards. Nothing in an inner circle can know
anything about outer circle.

Uncle Bob’s architecture has 4 layers (no need to have 4 layers, depend on your
project)

Entities

Usecase

It’s a entry point for business logic. Each business feature is implemented by a
usecase. So no other layers depend on it, but it depends on others layers.

Usecases contain application business rules using a domain model and have
input port and output port

Input port: is in charge of handling data from the outer layer

Clean architecture 4
Output port: handling data from use cases to the outer layer

Interface Adapters (Controllers, Gateway, presenter,…)

Is a set of adapters that convert data from format most convenient for use
cases and entities, to the format most convenient for some external agency
such as DB or the Web (whatever framework is being used). In this layer, will
wholly contain the MVC architecture. The presenters, Views and Controllers all
belong in here. The models are likely data structure that are passed from the
controllers to the use cases, and then back from the use cases to the
presenters and views

Controllers are a set of specific implementation of Input port in use case

Presenter is a set of specific implementation of Output port in use case

Also in this layer is any other adapter necessary to convert data from some
external form, such as an external service, to the internal form used by the use
cases and entities.

Framework & Drivers

The outermost layer is composed of frameworks and tools such as the


Database, the Web framework. Generally you don’t write much code in this
layer other than glue code that communicates to the next circle inwards

Specify in this project, has these layers

Models

Repository

The use case is only layer communicate with datastore. This way each layer
can be tested independently

If the app grows to have gRPC support, only the delivery layer will change.
Datastore and usecase remain the same. This way, it’s easy to isolate any
bugs, maintain code and grow the application

Usecase

It does as business logic. It takes whatever it needs from delivery and


communicate with datastore layer.

Delivery

Clean architecture 5
The delivery layer will received the request and parse anything that is required
from the request. It calls the use case layers, ensures that response is the
required format and writes it to the response writer

General layers (top→ down)


1. Presentation: Responsible for showing information to the user and interpreting user
commands;

2. Application: Defines the jobs the software is supposed to do by orchestrating the


data flow from and to the domain models;

3. Domain: Represents concepts of the business, information about the current


situation and business rules;

4. Data: Responsible for persisting domain models.

Layers

Models
Same as Entities, will used in all layers. Store any struct type and its method. For
instance

Clean architecture 6
type Article struct {
ID int64 `json:"id"`
Title string `json:"title"`
Content string `json:"content"`
}

Any entities, or model will be stored here

Repository
Repository store any Database handler, including query, create/insert into database, act
as a CRUD to DB, only plain function to Database
This layer have responsibility for choose what DB will used in app. If using ORM, this
layer will control the input, and give it directly to ORM services
If calling micro-service, will handled here. Create HTTP request to other services, and
sanitize data. This layer must fully act as a repository

Usecase / interactor
Act as a business process handler (which contains business logic). Any process will
handle here. It decide which repository layer will use. And provide data to serve into
delivery.
Usecase layer will accept any input from delivery layer, that already sanitized, then
process the input could be storing into DB, or Fetching from DB

This layer will depend to Repository layer

Clean architecture 7
Presenter
It doesn’t contain business logic, main job is map the data structure returned by use
case interactor into structure most convenient for view

Delivery
This layer act as a presenter, decide how data will be presented. Could be as a REST
API, or HTML File, or gRPC. This layer also accept input from user. Sanitize the input
and sent it to Usecase layer
For instance, using REST API as the delivery method. Client will call the resource
endpoint over network, and the Delivery layer will get the input or request, and sent it to
Usecase Layer.
This layer will depends to Usecase Layer.

Flow layer

main.go

router.go・・・Infrastructure

user_controller.go・・・Interfaces

user_interactor.go・・・Use Cases

Clean architecture 8
user_repository.go ・・・Use Cases

user.go ・・・Domain

Common question

Q: What are these Use Cases/interactors supposed to do?

A: They implement the dataflow logic.

Q: Why can’t I call directly the repository from the


Presenter/ViewModel?

A: Because we want to avoid God objects that deals with both presentation logic
and dataflow logic. We also want the dataflow logic to be reusable across
different ViewModels.

Q: Why should I have a Use Case that does nothing other than just
calling a Repository, isn’t this an overkill for my app?

A: Because of consistency, protection from future changes and for having a


“Screaming Architecture”

Q: Do I really need a Use Case for each repository method?

A: Not always, but for sure you need at least a repository method for each Use
Case.

Communication between layer


Except Models, each layer will communicate through interface. For ex, Usecase layer
need the Repository layer, so Repository will provide an interface to be their contract
and communication

Example of Repository’s interface

Clean architecture 9
package repository

import models "github.com/bxcodec/go-clean-arch/article"

type ArticleRepository interface {


Fetch(cursor string, num int64) ([]*models.Article, error)
GetByID(id int64) (*models.Article, error)
GetByTitle(title string) (*models.Article, error)
Update(article *models.Article) (*models.Article, error)
Store(a *models.Article) (int64, error)
Delete(id int64) (bool, error)
}

Usecase layer will communicate to Repository using this contract, and Repository
layer MUST implement this interface so can used by Usecase
Example of Usecase’s Interface

package usecase

import (
"github.com/bxcodec/go-clean-arch/article"
)

type ArticleUsecase interface {


Fetch(cursor string, num int64) ([]*article.Article, string, error)
GetByID(id int64) (*article.Article, error)
Update(ar *article.Article) (*article.Article, error)
GetByTitle(title string) (*article.Article, error)
Store(*article.Article) (*article.Article, error)
Delete(id int64) (bool, error)
}

Same with Usecase, Deliver layer will use this contract interface. And Usecase layer
must implement this interface.

In Ahamove project
we will inject repository and service interface into usecase. And inject usecase into
handlers.

Conclusion

Clean architecture 10
No matter of your library, architecture is clean and testable also independent

Implementation of Clean Go

.
├── domain
│ └── model
│ └── user.go
├── infrastructure
│ ├── datastore
│ │ └── db.go
│ └── router
│ └── router.go
├── interface
│ ├── controller
│ │ ├── app_controller.go
│ │ ├── context.go
│ │ └── user_controller.go
│ ├── presenter
│ │ └── user_presenter.go
│ └── repository
│ └── user_repository.go
├── main.go
├── registry
│ ├── registry.go

Clean architecture 11
│ └── user_registry.go
├── usecase
│ ├── presenter
│ │ └── user_presenter.go
│ ├── repository
│ │ └── user_repository.go
│ └── interactor
│ └── user_interactor.go

Each directory has a role of each layer

Directory Layer

domain Entities

infrastructure Framework & Driver

interface Interface & adapter

usecase Use cases

Controllers and presenters

Clean architecture 12
Flow of user interact with a system

1. The user interacts with the view.

2. The view creates a request (object) which is passed to the controller.

3. The controller converts the request into a request model and passes it to the use
case interactor through its input port.

4. The use case interactor processes the request model and creates a response
model which is passed through the output port to the presenter.

5. The presenter converts the response model to view model which is then passed to
the view.

6. The user sees the result of his interaction in the view.

The left (blue) section where the frameworks live (e.g. an HTML/JavaScript view)

The middle (green) section where the adapters live (controllers and presenters)

Clean architecture 13
The right (red) section where the business logic (use case interactors) live

For example: HTTP router → Controller → Service → Repository. Repository doesn’t


know anything about Service, and the Controller and so on. —> Independent

Implementation in official Go-clean-architect

models
├── article.go
├── author.go
└── errors.go

article
├── delivery
│ └── http
│ ├── article_handler.go
│ └── article_test.go
├── mocks
│ ├── ArticleRepository.go
│ └── ArticleUsecase.go
├── repository //Encapsulated Implementation of Repository Interface
│ ├── mysql_article.go
│ └── mysqlarticle_test.go
├── repository.go // Repository Interface
├── usecase //Encapsulated Implementation of Usecase Interface
│ ├── articleucase_test.go
│ └── artilce_ucase.go
└── usecase.go // Usecase Interface.

Domain-Driven Design

Clean architecture 14

You might also like