Go Microservice With Clean Architecture — A Major Upgrade

Jin Feng
The Startup
Published in
5 min readAug 3, 2020

Last year, I created a framework for Microservice, which is a powerful one but a little heavy. I wrote a series of articles talking about it, please read “Go Microservice with Clean Architecture” for detail. I also pointed out some drawbacks in the design and expected to come back and fix those later. I finally got time to improve it. The result exceeds my expectation.

The changes I made are relatively small, but the improvement is huge. The main project structure and layout is still intact, most of what I wrote in those articles are still held, but it fixed all major problems in the old framework. It now almost has everything I want from a framework. It is lightweight, powerful, and pluggable cable.

The followings are the main difference:

  • Self-evolved design
  • pluggable Third-party libraries
  • The major change to the transaction management system
  • Other changes

Self-evolved design

This is the best feature of all changes. The old framework was a little heavy and was not a good fit for a lightweight project. Now, the framework can evolve with your project when it becomes more complex. The best part is that you don’t need to change your business code during the process. I wrote a separate article for it. Please read “A Self-Evolved Microservice Framework in Go” for detail.

Pluggable third-party libraries

One nice piece in the old framework is a common logging interface, with which I can switch to any other logging library without changing my code (I only need to change the configuration file). The only drawback is that it is tied to the framework and can’t be used independently. In the upgraded framework, I made it an independent lib and broke it out of the framework, so it can be used without the framework. The key is to create a generic interface for the component so you can plug any implementation libs as long as they implement the generic interface. By now, I have created three pluggable components, “glogger” for logging, “gmessaging” for messaging, and “gtransaction” for transaction management. I will add new ones when there is a need. Please take a look at “How to write a pluggable third-party component in Go” on how to write a third-party lib.

The major change to the transaction management system

I also created a transaction management system with the old framework. I created a non-intrusive one that fits into the Clean Architecture. Even though it is non-intrusive to the business logic, but it is intrusive to my framework. It also has some problems that broke my design as I laid out in the article “Go Microservice with Clean Architecture: Transaction Support”.

In the new framework, I made some major modifications to the transaction management system. Now, I moved most of the code out to a third-party library, and you only need to add two lines of additional code to make a function transactional in your application. It is not only non-intrusive to the business code but also non-intrusive to the framework. As it is a lib, it can be used without the framework. Please read “A Non-Intrusive Transaction Management Lib in Go — How to Use It” for detail.

Other changes

There are other changes, but they are all small ones.

Container Interface

This is the interface between the container and the business logic. I created three models for the application container, from the simplest to the most complex. I can replace the model to a different one without changing business logic. So, the interface has to fit all models. The original interface is created for the most complex model, I changed it a little to fit better to other models.

Moved the persistence code to the application service layer

The persistence code was in the domain layer and most people do it that way. However, according to the Domain-driven design, it should be in the service layer, so I moved it out to the application service layer. At first glance, it looked wired because most people don’t do it this way. But, let’s be consistent and see if it cause any problems.

Removed the “Simplified Factory” in the application container

I described “dependency Injection” in detail in the article “Go Microservice with Clean Architecture: Dependency Injection”, where I explained two types of factory, one is “Second Level Factory” and the other is “Simplified Factory”. “Simplified Factory” is created to write less code.

However, as I reflect on the design, I have a different understanding of program complexity. The principles that I follow have not changed, it is reducing the code complexity. But I used to think that the longer the code, the more complicated it is, but now I will add another dimension, which is the complexity of the code structure. Although the code of the “secondary factory” is much longer, the structure is simple. After one factory is created, many copies can be made. The structure is almost the same, so it is very easy to expand factories and also easy to read. Its complexity increases linearly, and there are no other side effects. Also, you can use tools such as a code generator to automatically generate it to improve efficiency. Although the “simplification factory” has less number of code, its structure is complex, its complexity increases rapidly, and its side effects are too large to manage. So, the “secondary factory” looks complex but is simple. In the new design, I decided to remove “Simplified Factory” and only keep the “secondary factory”.

Why make it a new project

I didn’t make the changes in the original project but created a new project called “servicetmpl1” because my old articles are still pointing to the old project and I don’t want to confuse readers. I certainly think the new framework is much better than the old one and encourage you to use the new one if it is possible.

Source Code:

The complete code is in “servicetmpl1”

Reference :

[1]”Go Microservice with Clean Architecture”

[2]”A Self-Evolved Microservice Framework in Go”

[3]”glogger”

[4]”gmessaging”

[5]”gtransaction”

[6]”How to write a pluggable third-party component in Go

[7]”Go Microservice with Clean Architecture: Transaction Support”

[8]”A Non-Intrusive Transaction Management Lib in Go — How to Use It”

[9] “Go Microservice with Clean Architecture: Dependency Injection”

[10] “servicetmpl1”

--

--

Jin Feng
The Startup

Writing applications in Java and Go. Recent interests including application design and Microservice.