Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
/go-clean-templatePublic template

Clean Architecture template for Golang services

License

NotificationsYou must be signed in to change notification settings

evrone/go-clean-template

Repository files navigation

Go Clean Template

Go Clean template

🇨🇳 中文🇷🇺 RU

Clean Architecture template for Golang services

ReleaseLicenseGo Report Cardcodecov

Web FrameworkAPI DocumentationValidationJSON HandlingQuery BuilderDatabase MigrationsLoggingMetricsTestingMocking

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 byEvrone.

This template implements three types of servers:

Content

Quick start

Local development

# Postgres, RabbitMQ, NATSmake compose-up# Run app with migrationsmake run

Integration tests (can be run in CI)

# DB, app + migrations, integration testsmake compose-up-integration-test

Full docker stack with reverse proxy

make compose-up-all

Check services:

Project structure

cmd/app/main.go

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

config

The twelve-factor app stores config in environment variables (often shortened toenv vars orenv). Env vars are easyto change between deploys without changing any code; unlike config files, there is little chance of them being checkedinto the code repo accidentally; and unlike custom config files, or other config mechanisms such as Java SystemProperties, they are a language- and OS-agnostic standard.

Config:config.go

Example:.env.example

docker-compose.yml usesenv variables to configure services.

docs

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

docs/proto

Protobuf files. They are used to generate Go code for gRPC services.The proto files are also used to generate documentation for gRPC services.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.

internal/app

There is always oneRun function in theapp.go file, which "continues" themain 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 theDependency Injection principle.This makes the business logic independent from other layers.

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

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

Themigrate.go file is used for database auto migrations.It is included if an argument with themigrate tag is specified.For example:

go run -tags migrate ./cmd/app

internal/controller

Server handler layer (MVC controllers). The template shows 3 servers:

  • AMQP RPC (based on RabbitMQ as transport)
  • gRPC (gRPC framework based on protobuf)
  • REST API (Fiber 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/amqp_rpc

Simple RPC versioning.For v2, we will need to add theamqp_rpc/v2 folder with the same content.And in the fileinternal/controller/amqp_rpc/router.go add the line:

routes:=make(map[string]server.CallHandler){v1.NewTranslationRoutes(routes,t,l)}{v2.NewTranslationRoutes(routes,t,l)}

internal/controller/grpc

Simple gRPC versioning.For v2, we will need to add thegrpc/v2 folder with the same content.Also add thev2 folder to the proto files indocs/proto.And in the fileinternal/controller/grpc/router.go add the line:

{v1.NewTranslationRoutes(app,t,l)}{v2.NewTranslationRoutes(app,t,l)}reflection.Register(app)

internal/controller/http

Simple REST versioning.For v2, we will need to add thehttp/v2 folder with the same content.And in the fileinternal/controller/http/router.go add the line:

apiV1Group:=app.Group("/v1"){v1.NewTranslationRoutes(apiV1Group,t,l)}apiV2Group:=app.Group("/v2"){v2.NewTranslationRoutes(apiV2Group,t,l)}

Instead ofFiber, you can use any other http framework.

Inrouter.go and above the handler methods, there are comments for generating swagger documentationusingswag.

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(seeDependency Injection).

internal/repo/persistent

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

internal/repo/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 theusecase package.

package usecaseimport (// Nothing!)typeRepositoryinterface {Get()}typeUseCasestruct {repoRepository}funcNew(rRepository)*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 withmockery) andeasily 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 injection.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 anabstract database orabstract 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 throughusecase (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 theinternal/entity folder.In MVC terms, entities are models.
  • Use Cases is business logic located ininternal/usecase.

The layer with which business logic directly interacts is usually called theinfrastructure layer.These can be repositoriesinternal/usecase/repo, external webapiinternal/usecase/webapi, any pkg, and othermicroservices.In the template, theinfrastructure packages are located insideinternal/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 versionofClean Architecture was designed forbuilding 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 dependenciesto 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 andHexagonal (Ports and adapters) are similar to it.Both are based on the principle of Dependency Inversion.Ports and adapters are very close toClean Architecture, the differences are mainly in terminology.

Similar projects

Useful links

About

Clean Architecture template for Golang services

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors19


[8]ページ先頭

©2009-2025 Movatter.jp