After writing my story about my experience : “Trying Clean Architecture on Golang” here : https://hackernoon.com/golang-clean-archithecture-efd6d7c43047
I’ve learned a lot things, from people and other gophers there. I’ve receive many emails, comment and even github issue in my project, and everything is more made me understand what I miss and mistaken.
With my old project and story here: “Trying Clean Architecture on Golang”, I can say, this project and structure is limited for Golang. One of the biggest issue I faced is when having multiple dependencies in the models. It’s drive the cyclic import, as mentioned by daf0rth here : https://github.com/bxcodec/go-clean-arch/issues/7.
Another thing is, Golang is different with other programming language. It is using package system. In other word, it’s better if all the project’s struct
, or function
stored in one package, it will more safe. I can see this in many of golang project’s library or open source in github. We take example of logrus. All the struct
and function
is stored in one package, it is in the root of the projects package itself. So we can easily import the logrus
as a package to our any entire projects.
So then, after realizing this, I tried many approachment, without missing the concept of “Clean Architecture”, that was independent, testable, and also maintainable and clean, and also without losing the Golang identity. And at the end, I made an update to my old projects, here for example: https://github.com/bxcodec/go-clean-arch
To avoid the Cyclic import, I separate the models into one package. So if we have relationship between models, we can solve it know because they already stored in one package.
And without losing the Golang identity, as a package programming language, I move the Interface (Usecase and Repository layer ) to their root domain package.
domain package golang clean architecture
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.
So, from this structure projects, other domains like Author
’s domain, only know about the interface and the function, not the implementations.
Well, actually, I just moving the interface repository
and usecase
into their domain root.
article/usecase/usecase.go >>>> article/usecase.goarticle/repository/repository.go >>>> article/repository.go
And leave their implementation stay behind in their old folders. And by these design, I still can change their implementations without changing the contract. I can still can change the repository implementations from MySQL to MongoDB, or I can still change the usecase logic, without changing the output and input of the functions.
The concept is still not changed. And also the test. Is still the same. This changes is only about avoiding cyclic import and also restoring the golang identity as a package programming .
All this design is based my own experience and learning from others. Some feature maybe I took from other source code, and some of them I made a few improvement. And I will really appreciate any question, comments, or any revision, if I make something wrong or missing something in my article.
In Golang life, there are no standard architecture, we can freely tried many approachment as we can do and learn. For some people, my proposed architecture is helpful, but some others, it’s really doesn’t fit and didn’t solve the real problem. But, what I want to say is, Golang is free and never have standard, you can develop your own standard, or you can try what others do out there, there so many clean architecture proposed by others, that maybe help you more.
But if you found this good and fit to your problem, kindly share and give a claps to help others to reach this out.