Clean Architecture, 2 years later

In February 2018 I wrote what would become the most relevant text I have ever published: Clean Architecture using Golang. With more than 105k views, the post generated presentations at some Go and PHP events and allowed me to talk about software architecture with several people.

Using this architecture for the development of Codenation’s products, we gained experience and solved problems. We wrote some posts reporting these experiences:

After this whole experience I can say::

Choosing Clean Architecture was the best technical decision we made!

With this post, I want to share a repository with a new example implementation in Go. It is an update with improvements in the organization of codes and directories, as well as a more complete example for those who are looking to implement this architecture.

In the next topics, I explain what each directory means.

Entity layer

Let’s start with the innermost layer of the architecture.

According to Uncle Bob’s post:

Entities encapsulate Enterprise wide business rules. An entity can be an object with methods, or it can be a set of data structures and functions. It doesn’t matter so long as the entities could be used by many different applications in the enterprise.

The structure looked like this:

entity

In this package, we have the definition of the entity (entity.go) and the interfaces of the Repository and Manager (in interface.go). The Manager will use a Repository to perform basic operations on the entity, such as the famous CRUD.

We also have the implementations of the repository in MySQL (repository_mysql.go) and in-memory (repository_inmem.go), as well as the implementation of the Manager interface (in manager.go).

We also found the mocks generated by Gomock, as explained in this post. The other layers of the architecture will use this mocks during the tests.

Use Case Layer

According to Uncle Bob::

The software in this layer contains application specific business rules. It encapsulates and implements all of the use cases of the system

The structure looked like this:

domain

In packages within domain/usecase we implement the business rules for our product. According to the definition of the architecture, these UseCases make use of the entities and the Managers that deal with them. It is also possible to see the existence of mocks, as the previous layer.

Controller layer

In this application, there are two ways to access the UseCases. The first is through an API and the second is using a command line application (CLI).

The CLI’s structure is very simple:

cli

It makes use of domain packages to perform a book search:

dataSourceName := fmt.Sprintf("%s:%s@tcp(%s:3306)/%s?parseTime=true", config.DB_USER, config.DB_PASSWORD, config.DB_HOST, config.DB_DATABASE)
db, err := sql.Open("mysql", dataSourceName)
if err != nil {
  log.Fatal(err.Error())
}
defer db.Close()
repo := book.NewMySQLRepository(db)
manager := book.NewManager(repo)
all, err := manager.Search(query)
if err != nil {
  log.Fatal(err)
}
for _, j := range all {
  fmt.Printf("%s %s \n", j.Title, j.Author)
}

In the example above, you can see the use of the config package. You can see its structure below, and more details in this post.

config

The API structure is more complex, with three packages: handler, presenter, and middleware.

The handler package handle HTTP requests and responses, as well as using existing business rules in the domain.

handler

The presenters are responsible for formatting the data generated as a response by handlers.

presenter

In this way, the entity User:

type User struct {
   ID        entity.ID
   Email     string
   Password  string
   FirstName string
   LastName  string
   CreatedAt time.Time
   UpdatedAt time.Time
   Books     []entity.ID
}

It can be transformed into:

type User struct {
   ID        entity.ID `json:"id"`
   Email     string    `json:"email"`
   FirstName string    `json:"first_name"`
   LastName  string    `json:"last_name"`
}

This gives us control over how an entity will be delivered via the API.

In the last package of the API we find the middlewares, used by several endpoints:

middlware

Support packages

They are packages that provide common functionality such as encryption, logging, file handling, etc. These features are not part of the domain of our application, and all the layers can use them. Even other applications can import and use these packages.

pkg

The README.md contains more details, such as instructions for compilation and usage examples.

My goals with this post to strengthen my recommendation on this architecture and also to receive feedback about the codes.

If you want to learn how to use this architecture in your favorite programming language, you could use this repository as an example of this learning. That way, we can have different implementations, in different languages, to ease the comparison.

Special thanks to my friend Gustavo Schirmer who gave great feedbacks on the text and the codes.