Go-clean-template: Clean Architecture template for Golang services
We open-sourced go-clean-template, a Golang template project based on Robert “Uncle Bob” Martin’s Clean Architecture principles, ready for you to clone and use as a starting point for your next Golang app.
Go-clean-template is a Golang template project based on Robert "Uncle Bob" Martin’s Clean Architecture principles, ready for you to clone and use as a starting point for your next Golang app.
The Clean Architecture
The Clean Architecture is a way of arranging complex — or potentially-complex — systems which, like most good sets of architectural principles, promotes a strict separation of concerns.
That is, software is broken down into independent functional components which interface with one another only through well-defined and reliable means, with only the state and resources which need to be exchanged in order to perform the task at hand passed between them.
A strict separation of concerns can help minimise the complexity of each component, reducing the likelihood of bugs being introduced, and making them easier to fix when they do arise — provided the offending component can be readily identified. A separation of concerns is key to adhering to the least privilege security principle.
The Clean Architecture achieves this separation of concerns through conventions (rules) which make it clear where within the architecture an entity, component, or part of a component exists, and the extent to which each is visible and accessible to other parts of the system.
For example, the high-level enterprise business rules of a system cannot, if you conform to the Clean Architecture principles, have direct access to data structures passed between an API server and a mobile app, nor even have awareness that such details exist — although their content can of course be passed through the layers from the low-level components to the higher ones through well-defined means if that is required functionality.
Of course, like all architectural foundations, the Clean Architecture is a framework that you have to choose to adhere to throughout the lifecycle of a piece of software, it won't physically prevent you from writing poor code. Hopefully, though, starting with this template will help you start as you mean to go on!
Quick Start
Once you've checked out the template, you can dive into internal
and start writing code. The provided Makefile
has a number of targets for building and running your app, but the most useful ones are:
Run with Docker (starts Postgres and RabbitMQ):
$ make compose-up
Run locally with migrations:
$ make run
Run integration tests with Docker:
$ make compose-up-integration-test
Project Structure
Full details are included in the project's README, but some areas of particular interest include:
cmd/app/main.go
Configuration and logger initialisation, before control is passed to Run in internal/app/app.go
.
internal/app
The Run function (invoked by Main) in app.go
performs object initialisation and dependency injection (more on this below), starts the server, and waits until it's time to gracefully terminate.
The migrate.go
file is used for database auto migrations. It is included if an argument with the migrate tag is specified. For example:
$ go run -tags migrate ./cmd/app
internal/controller
Server handler layer (MVC controllers). The template includes two servers:
- RPC (RabbitMQ as transport)
- REST HTTP (Gin framework)
Server routers are written in the same style:
- Handlers are grouped by area of application
- For each group, its own router structure is created, the methods of which process paths
- The structure of the business logic is injected into the router structure, which will be called by the handlers
internal/entity
Business logic models that are common to the system and can be used in any layer.
internal/usecase
Business logic.
- Methods are grouped by area of application (on a common basis)
- Each group has its own structure
- One file - one structure
config/config.yml
Application configuration. Environment variables will override configuration file values. Configuration options with the tag 'env-required: true'
in config.go
are required, and a value must be provided in either config.yml
, the environment, or both.
docs/
Swagger documentation. This is auto-generated by swag library, so don't make any changes, as they'll be lost.
integration-test/
Integration tests. They are launched as a separate container, next to the application container. It is convenient to test the Rest API using go-hit.
Dependency Injection
We make use of dependency injection in order to enable a weak coupling between components and minimise direct dependencies.
For example, through the NewService constructor, we inject the dependency into the structure of the business logic. This makes the business logic independent (and portable). We can override the implementation of the interface without making changes to the service
package.
package usecase
import (
// Nothing!
)
type Repository interface {
Get()
}
type UseCase struct {
repo Repository
}
func New(r Repository) *UseCase {
return &UseCase{
repo: r,
}
}
func (uc *UseCase) Do() {
uc.repo.Get()
}
This also allows us to auto-generate mocks (for example with mockery) and easily write unit tests.
We are not tied to specific implementations in order to always be able to change one component to another. If the new component implements the interface, nothing needs to be changed in the business logic.
If you find you need to managing a large number of injections, wire is a popular choice.
Alternative projects
Of course ours isn't the only Clean Architecture template for Golang, so you may be interested to explore these alternatives and choose the one that suits you best:
- go-clean-arch
- courses-backend
Our work on open-source projects proves our initiative & understanding of what developers love and need. Reach out to us via the form below if you need to update your project to the latest versions of the technology stack!