• Stars
    star
    6,198
  • Rank 6,472 (Top 0.2 %)
  • Language
    Go
  • License
    MIT License
  • Created almost 4 years ago
  • Updated 3 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Clean Architecture template for Golang services

Go Clean Template

Go Clean template

🇨🇳中文

Clean Architecture template for Golang services

Go Report Card License Release codecov

Overview

The purpose of the template is to show:

  • how to organize a project and prevent it from turning into spaghetti code
  • where to store business logic so that it remains independent, clean, and extensible
  • how not to lose control when a microservice grows

Using the principles of Robert Martin (aka Uncle Bob).

Go-clean-template is created & supported by Evrone.

Content

Quick start

Local development:

# Postgres, RabbitMQ
$ make compose-up
# Run app with migrations
$ make run

Integration tests (can be run in CI):

# DB, app + migrations, integration tests
$ make compose-up-integration-test

Project structure

cmd/app/main.go

Configuration and logger initialization. Then the main function "continues" in internal/app/app.go.

config

Configuration. First, config.yml is read, then environment variables overwrite the yaml config if they match. The config structure is in the config.go. The env-required: true tag obliges you to specify a value (either in yaml, or in environment variables).

For configuration, we chose the cleanenv library. It does not have many stars on GitHub, but is simple and meets all the requirements.

Reading the config from yaml contradicts the ideology of 12 factors, but in practice, it is more convenient than reading the entire config from ENV. It is assumed that default values are in yaml, and security-sensitive variables are defined in ENV.

docs

Swagger documentation. Auto-generated by swag library. You don't need to correct anything by yourself.

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.

internal/app

There is always one Run function in the app.go file, which "continues" the main function.

This is where all the main objects are created. Dependency injection occurs through the "New ..." constructors (see Dependency Injection). This technique allows us to layer the application using the Dependency Injection principle. This makes the business logic independent from other layers.

Next, we start the server and wait for signals in select for graceful completion. If app.go starts to grow, you can split it into multiple files.

For a large number of injections, wire can be used.

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 shows 2 servers:

  • RPC (RabbitMQ as transport)
  • REST http (Gin framework)

Server routers are written in the same style:

  • Handlers are grouped by area of application (by a common basis)
  • 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/controller/http

Simple REST versioning. For v2, we will need to add the http/v2 folder with the same content. And in the file internal/app add the line:

handler := gin.New()
v1.NewRouter(handler, t)
v2.NewRouter(handler, t)

Instead of Gin, you can use any other http framework or even the standard net/http library.

In v1/router.go and above the handler methods, there are comments for generating swagger documentation using swag.

internal/entity

Entities of business logic (models) can be used in any layer. There can also be methods, for example, for validation.

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

Repositories, webapi, rpc, and other business logic structures are injected into business logic structures (see Dependency Injection).

internal/usecase/repo

A repository is an abstract storage (database) that business logic works with.

internal/usecase/webapi

It is an abstract web API that business logic works with. For example, it could be another microservice that business logic accesses via the REST API. The package name changes depending on the purpose.

pkg/rabbitmq

RabbitMQ RPC pattern:

  • There is no routing inside RabbitMQ
  • Exchange fanout is used, to which 1 exclusive queue is bound, this is the most productive config
  • Reconnect on the loss of connection

Dependency Injection

In order to remove the dependence of business logic on external packages, dependency injection is used.

For example, through the New 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 usecase 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()
}

It will also allow us to do auto-generation of 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.

Clean Architecture

Key idea

Programmers realize the optimal architecture for an application after most of the code has been written.

A good architecture allows decisions to be delayed to as late as possible.

The main principle

Dependency Inversion (the same one from SOLID) is the principle of dependency inversion. The direction of dependencies goes from the outer layer to the inner layer. Due to this, business logic and entities remain independent from other parts of the system.

So, the application is divided into 2 layers, internal and external:

  1. Business logic (Go standard library).
  2. Tools (databases, servers, message brokers, any other packages and frameworks).

Clean Architecture

The inner layer with business logic should be clean. It should:

  • Not have package imports from the outer layer.
  • Use only the capabilities of the standard library.
  • Make calls to the outer layer through the interface (!).

The business logic doesn't know anything about Postgres or a specific web API. Business logic has an interface for working with an abstract database or abstract web API.

The outer layer has other limitations:

  • All components of this layer are unaware of each other's existence. How to call another from one tool? Not directly, only through the inner layer of business logic.
  • All calls to the inner layer are made through the interface (!).
  • Data is transferred in a format that is convenient for business logic (internal/entity).

For example, you need to access the database from HTTP (controller). Both HTTP and database are in the outer layer, which means they know nothing about each other. The communication between them is carried out through usecase (business logic):

    HTTP > usecase
           usecase > repository (Postgres)
           usecase < repository (Postgres)
    HTTP < usecase

The symbols > and < show the intersection of layer boundaries through Interfaces. The same is shown in the picture:

Example

Or more complex business logic:

    HTTP > usecase
           usecase > repository
           usecase < repository
           usecase > webapi
           usecase < webapi
           usecase > RPC
           usecase < RPC
           usecase > repository
           usecase < repository
    HTTP < usecase

Layers

Example

Clean Architecture Terminology

  • Entities are structures that business logic operates on. They are located in the internal/entity folder. In MVC terms, entities are models.

  • Use Cases is business logic located in internal/usecase.

The layer with which business logic directly interacts is usually called the infrastructure layer. These can be repositories internal/usecase/repo, external webapi internal/usecase/webapi, any pkg, and other microservices. In the template, the infrastructure packages are located inside internal/usecase.

You can choose how to call the entry points as you wish. The options are:

  • controller (in our case)
  • delivery
  • transport
  • gateways
  • entrypoints
  • primary
  • input

Additional layers

The classic version of Clean Architecture was designed for building large monolithic applications and has 4 layers.

In the original version, the outer layer is divided into two more, which also have an inversion of dependencies to each other (directed inward) and communicate through interfaces.

The inner layer is also divided into two (with separation of interfaces), in the case of complex logic.


Complex tools can be divided into additional layers. However, you should add layers only if really necessary.

Alternative approaches

In addition to Clean architecture, Onion architecture and Hexagonal (Ports and adapters) are similar to it. Both are based on the principle of Dependency Inversion. Ports and adapters are very close to Clean Architecture, the differences are mainly in terminology.

Similar projects

Useful links

More Repositories

1

postcss-px-to-viewport

A plugin for PostCSS that generates viewport units (vw, vh, vmin, vmax) from pixel units. The best choice to create a scalable interface on different displays by one design size.
JavaScript
3,023
star
2

quiet_assets

DEPRECATED: As of sprockets-rails version 3.1.0, used in current versions of rails, this gem is deprecated
Ruby
1,415
star
3

factory_girl-seeds

Deprecated: please note, this project is no longer being maintained
Ruby
175
star
4

inboxes

DEPRECATED: please note, this project is no longer being maintained
Ruby
117
star
5

flutter_audio

A Flutter audio-plugin to playing and recording sounds
Java
108
star
6

capistrano-team_notifications

DEPRECATED: please note, this project is no longer being maintained
Ruby
102
star
7

carrierwave-video-thumbnailer

A thumbnailer plugin for Carrierwave that makes easy thumbnailing of your uploaded videos
Ruby
93
star
8

evrone-python-guidelines

Evrone Python team code guidelines
74
star
9

evroneCrop

DEPRECATED: please note, this project is no longer being maintained
JavaScript
53
star
10

normas

Normal Lightweight Javascript Framework for server-side render compatible with Turbolinks
JavaScript
31
star
11

docker-machine-vscale

Vscale docker machine driver
Go
27
star
12

lxc-frontend

DEPRECATED: please note, this project is no longer being maintained
Ruby
23
star
13

omniauth-yandex

Omniauth 1.0 strategy for Yandex.ru
Ruby
22
star
14

glider

DEPRECATED: please note, this project is no longer being maintained
CoffeeScript
19
star
15

evrone-django-template

Simple and ready to go Django Template.
Python
17
star
16

casbin-ruby

An authorization library that supports access control models like ACL, RBAC, ABAC in Ruby
Ruby
16
star
17

yandex-cleanweb

DEPRECATED: please note, this project is no longer being maintained
Ruby
16
star
18

spree_autosuggest

DEPRECATED: please note, this project is no longer being maintained
Ruby
16
star
19

masquito

Deprecated: please note, this project is no longer being maintainedplease note, this project is no longer being maintained
Ruby
15
star
20

vscale_api

Api client for Vscale (http://vscale.io) like godo
Go
15
star
21

capistrano_evrone_recipes

DEPRECATED: please note, this project is no longer being maintained
Ruby
13
star
22

toggl-python

Python
12
star
23

ultimate-helpers

DEPRECATED: please note, this project is no longer being maintained
CoffeeScript
11
star
24

irake

Lightning fast rake (in rails console)
Ruby
11
star
25

rails-settings-ui

DEPRECATED: This project was moved to another location - https://github.com/accessd/rails-settings-ui
Ruby
11
star
26

dev_must_have

Meta gem for must have Rails development gems
Ruby
10
star
27

glider-rails

DEPRECATED: please note, this project is no longer being maintained
CoffeeScript
9
star
28

activerecord-vertica-adapter

ActiveRecord adapter for Vertica database based on pg adapter
Ruby
8
star
29

ultimate-mixins

Simple library of SASS functions, mixins and basic polyfills
CSS
8
star
30

migration_opener

DEPRECATED: please note, this project is no longer being maintained
Ruby
8
star
31

polemic

Commentable engine for Rails 3
Ruby
8
star
32

worldcities

Deprecated: please note, this project is no longer being maintainedplease note, this project is no longer being maintained
Ruby
6
star
33

foreman_export_runitu

Foreman exporter to runit, unlike original runit exporter, does it without sudo
Ruby
6
star
34

localizator

Ruby
6
star
35

liker

Fetches the count of likes for specified URL in social networks
Ruby
5
star
36

evrone_opensource

Improve READMEs of opensource projects
Ruby
5
star
37

gitlab-campfire-hook

DEPRECATED: please note, this project is no longer being maintained
Ruby
5
star
38

runit-bootstrap

Bootstraps runit user instance on Ubuntu
Shell
4
star
39

mega-copy

Automated refactoring for Python (and not only) files
Python
4
star
40

withardry

A simple plugin to DRY models
Ruby
4
star
41

vocabulary

Wrapper for unofficial Google Dictionary API
Ruby
4
star
42

notification_troubleshoot

Java
4
star
43

ekey

Ruby wrapper of API of the ekey.ru
Ruby
4
star
44

bmstu_2024

Ruby
4
star
45

destiny

Dice roller in d&d style for one of our projects
Ruby
3
star
46

terraform-yandex-postgres

HCL
3
star
47

terraform-yandex-vpc

HCL
2
star
48

activejob_nats_adapter

Ruby
2
star
49

yandex_direct_api

DEPRECATED: please note, this project is no longer being maintained
Ruby
2
star
50

octoshell-extend

DEPRECATED: please note, this project is no longer being maintained
Ruby
2
star
51

wheremymates

DEPRECATED: please note, this project is no longer being maintained
Ruby
1
star
52

twilio-sdk

Dart
1
star
53

terraform-yandex-iam

HCL
1
star
54

evrone_open_source_template

Evrone Open Source Template
1
star