DEV Community

Sachin Saini πŸ¦„
Sachin Saini πŸ¦„

Posted on

Clean Architecture in Practice

Organizing your project can be as important as the business logic of your app, especially in the long run. Ease of maintenance and integrating new functionality are core parts of the software development lifecycle. So it makes sense to organize your project in such a way that it welcomes change instead of opposing it.

Full example code can be found here.

Clean Architecture (CA)

This is my take on clean architecture, you don’t have to agree with me :)

Clean architecture lays out a set of rules to allow your apps to be easily extensible. Following these rules, you can build systems that are:

  • Independent of frameworks. You can easily swap one framework for another without rewriting your whole app.
  • Testable.
  • Independent of the database. You can swap PostgreSQL for MySQL or a NoSQL database.

Layers in CA

CA is a layered architecture, the diagram below tries to show various layers.

CA Layers

There can be more than 4 layers depending upon your project and the complexity.

Models

Think of a model as an object or data-structure that contains a blueprint of an entity in your business logic.

package user

type User struct {
    Name    string
    ID      int64
    Email   string
}
Enter fullscreen mode Exit fullscreen mode

In the code example above, the User struct contains the blueprint for the user. The same structure applies to all the entities in your business logic.

Repository

The repository is responsible for talking with the persistence layer. We are abstracting it with an interface.

package user

// ...snip

type UserRepository interface {
    GetByID(id int64) (*User, error)
    Update(u *User) error
    Delete(id int64) error
}
Enter fullscreen mode Exit fullscreen mode

Whatever persistence layer you are using in your system be it PostgreSQL or MongoDB, must satisfy this interface. This way we have decoupled the database from our system.

Usecase

This layer implements business-specific logic and communicates with the repository. We are abstracting away the usecase layer with the help of an interface.

package user

// ...snip

type UserUsecase interface {
    GetByID(id int64) (*User, error)
    Update(u *User) error
    Delete(id int64) error
}
Enter fullscreen mode Exit fullscreen mode

The Usecase and the repository happen to be same, it's not a rule.

Delivery

The delivery layer is responsible for the exchange of data between your system and the clients. The communication can take place with the help of a REST API or RPC or any other protocol or many protocols at the same time. the delivery layer is also responsible for serialization/de-serialization of data.

The data should be passed between the layers using only data-structures or as function parameters.

Dataflow

CA Dataflow

Understanding how the data flows in CA can be a bit confusing at first but it's quite simple in practice.

The client makes a request using a delivery protocol supported by your system. The delivery layer de-serializes the data from the request and passes it to the usecase layer. The usecase layer processes the data and talks to the repository if necessary. The processed data is sent up the chain to the delivery layer where it's serialized and sent back to the client.

Useful Links

Top comments (0)