Clean Architecture with GO

Manato Kuroda
Nov 7, 2019 · 7 min read

TL:DR: Introduce Clean architecture to Go.

Clean Architecture with Go

Clean Architecture is designed to separate concerns by organizing code into several layers with a very explicit rule which enables us to create a testable and maintainable project. In this article I’m going to highlight how Clean Architecture works in Go.

Example repo

You can view at: https://github.com/manakuro/golang-clean-architecture

Prerequisites

The target of readers in this post is who:

  • knows basic idea of Clean Architecture
  • wants to implement Go with Clean Architecture

So if you are not familiar with it, you can read some recommended articles to catch up.

Darkness of software design

If you’ve been working as a programmer, you’ve probably run into the code that:

  • is painful to add new features
  • is too difficult to debug
  • is hard or impossible to test without dependencies like a web server or database
  • get view and business logic mixed in widely, even can’t be separated
  • is hardly to understand what its purpose for
  • has a lot of jobs only in one function and too long.

You might be even scared of committing a tiny little change because you don’t know how much it affects other functions and there is no unit tests, even if there is, it’s too complicated and mysterious, which means useless. Even if it is structured in MVC or MVVM, there are still issues around the project, of which business logic is leaking into controllers, domain model is used across entire project for different purposes and so on.

Advantages in Clean Architecture

The Clean Architecture

Clean Architecture is one of software designs of organizing the codebase and provides a solution to these issues you’ve ever seen. By introducing Clean Architecture you’ll get your code:

  • highly decoupled from any UI, web framework or the database
  • focusing more on business logic
  • easily testable
  • maintainable, visible and easier to understand

In Clean Architecture the codebase should be flexible and portable. It should not be dependent on any specific web framework or database, which means you could switch it to an entirely new platform. For instance in the beginning of the project you use RDB but somehow even if you are forced to replace it with NoSQL for some reason, you can switch it without changing any business logic.

The only rules you need to know

When you implement Clean Architecture, you might try to follow the circle diagram completely, but actually the author said:

So you don’t need to implement it as it is, just take it as an example for understanding the architecture. But there are important rules that you need to follow.

1. The dependencies can only point inward

In Clean Architecture the details like a web framework and databases are in the outer layers while important business rules are in the inner circles and have no knowledge of anything outside world. Following Acyclic Dependencies Principle(ADP), the dependencies only point inward in the circle, not point outward and no circulation.

The dependencies only point inward

2. Separation of details and abstracts

The details in Clean Architecture are the data, framework, database and API. Using the details in core layer means it violates the The Dependency Rule. It should always be dependent on abstract interface not specific knowledge of the details so it will be flexible and maintainable. As seen at the right of the diagram, it shows that Controller and Presenter are dependent on Use Case Input Port and Output Port which are defined as interface, not specific logic(the details). But how is it possible to work without knowing the details in outer layer?

The flow of control

The Dependency Inversion Principle (DIP) resolves this contradiction without violating the rules. If you are not sure about DIP, you can check out some article before proceeding.

The Layers

We’ve learned a basic of rule in Clean Architecture. Next, take a look at the layers before implementing.

Entities

Entities is a domain model that has wide enterprise business rules and can be a set of data structures and functions.

ex.) A struct type of user, book and author.

Use Cases

Use cases contains application business rules using a domain model and has Input Port and Output Port.

Input Port is in charge of handling data from outer layer and defined as abstract.

Output Port is in charge of handling data from Use cases to outer layer and defined as abstract.

Interface Adapter

Interface Adapter handles the communication with inner and outer layer. It has only concerns of technological logic not business logic.

Controllers is a set of specific implementation of Input Port in Use Cases.

ex.) Convert form data before saving it in database

Presenter is a set of specific implementation of Output Port in Use Cases.

ex.) Convert data from database before passing to View

Frameworks and Drivers

Frameworks and drivers contains tools like databases, frameworks or API and basically does not have very much code.

ex.) API, database and web framework

Implementation of Clean Architecture in GO

Next, we’ll introduce Clean Architecture to Go and see how this works using a real use case. Let’s suppose that we’ll create a simple API responding to user data.

Now that we have the project structure as below:

.
├── 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
│ └── user_registry.go
├── usecase
│ ├── presenter
│ │ └── user_presenter.go
│ ├── repository
│ │ └── user_repository.go
│ └── interactor
│ └── user_interactor.go

Each directories has a role of each layers as following:

Directory and Layer

There’s no rule that you must always have just these four layers in Clean Architecture so actually it depends on the teams or the projects.

Entities Layer

First off, we create a user domain model as Entities layer in domain/model/user.go :

Use Cases Layer

In Use cases layer we have three directories, repository, presenter and interactor . interactor is in charge of Input Port and presenter is in charge of Output Port. interactor has a set of methods of application specific business rules depending on repository and presenter interface.

Let’s create a findAll interface in usecase/repository/user_repository.go:

And a usecase/presenter/user_presenter.go :

Create a Get as a function of finding all users in usecase/interactor/user_interactor.go :

Interface Adapter Layer

In Interface Adapter layer there are controllers , presenters and repository folders. controllers is in charge of C of MVC model and handles API request come from outer layer. repository is a specific implementation of repository in Use Cases and stores any database handler as Gateway.

Let’s create interface/controllers/user_controller.go :

In GetUsers it calls interactor in usecase and respond to a user data.

And we add interface/controllers/app_controller.go :

That is a set of controllers defined to use in infrastructure/router/router.go later.

Next, create interface/presenters/user_presenter.go :

ResponseUsers handles a user data before passing it to view basically but in this case we add some text to user name before responding to client.

And add interface/repository/user_repository.go :

FindAll is an actual implementation of interface in usecase/repository/user_repository.go that we’ve defined above and it’ll be injected as a method of handling database.

Frameworks and Drivers Layer

We have datastore and router folder in infrastructure. datastore is used as creating a database instance, in this case we use gorm with mysql. router is defined as routing request using echo.

Let’s create datastore/db.go :

And router/router.go :

Registry

registry plays a role of resolving dependencies using constructor injection.

Let’s create registry/registry.go :

NewRegistry takes a db instance to pass down to interface/repository .

And add registry/user_registry.go :

NewUserController generates a controller with interactor. NewUserInteractor returns a interactor with repository and presenter. NewUserRepository returns repository of interface passed with a database instance which fulfills usecase interface.

Booting

Now that we’re ready to boot a server with users endpoint. Let’s add some code to main.go :

We have echo framework for routing and pass it to router and controllers created by registry.NewRegistry .

Let’s try to see how it woks at http://localhost:8080/users : (Make sure that there’s some record in your database)

It seems work fine.

Conclusion

That’s it. We’ve created a very simple API responding to a user data with Clean Architecture. I like the idea of separating the different aspect of product as highly decoupled layers.

I hope you’ll find the benefits I highlighted in this article.

You can view final codebase: https://github.com/manakuro/golang-clean-architecture

manato

Web Development Blog

Manato Kuroda

Written by

Web Developer, JavaScript, Angular, Vue.js, React, TypeScript, Go, PHP and Ruby on Rails https://twitter.com/manakurooo

manato

manato

Web Development Blog

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade