Golangサービスのクリーンなアーキテクチャテンプレート
テンプレートの目的は、次のことを示すことです。
ロバートマーティン(別名アンクルボブ)の原則を使用します。
Go-clean-templateは、 Evroneによって作成およびサポートされています。
ローカル開発:
# Postgres, RabbitMQ
$ make compose-up
# Run app with migrations
$ make run
統合テスト(CIで実行可能):
# DB, app + migrations, integration tests
$ make compose-up-integration-test
cmd/app/main.go
構成とロガーの初期化。次に、メイン関数はで「続行」し
internal/app/app.goます。
config
構成。最初に
config.ymlが読み取られ、次に環境変数が一致する場合はyaml構成を上書きします。構成構造はにあり
config.goます。タグを使用
env-required: trueすると、値を指定する必要があります(yamlまたは環境変数のいずれかで)。
構成には、cleanenvライブラリを選択しました。GitHubには星があまりありませんが、シンプルですべての要件を満たしています。
yamlから構成を読み取ることは、12の要素のイデオロギーと矛盾しますが、実際には、ENVから構成全体を読み取るよりも便利です。デフォルト値はyamlであり、セキュリティに敏感な変数はENVで定義されていると想定されています。
docs
Swaggerのドキュメント。スワッグライブラリによって自動生成されます。自分で修正する必要はありません。
integration-test
統合テスト。これらは、アプリケーションコンテナの隣にある別のコンテナとして起動されます。go-hitを使用してRestAPIをテストすると便利です。
internal/app
ファイルには常に1つのRun関数があり、これはメイン
app.go関数を「継続」します。
これは、すべての主要なオブジェクトが作成される場所です。依存性注入は、「New ...」コンストラクターを介して行われます(依存性注入を参照)。この手法により、依存性注入の原則を使用してアプリケーションを階層化できます。これにより、ビジネスロジックが他のレイヤーから独立します。
次に、サーバーを起動し、selectのシグナルが正常に完了するのを待ちます。成長し始めたら
app.go、それを複数のファイルに分割できます。
多数の注入には、ワイヤーを使用できます。
この
migrate.goファイルは、データベースの自動移行に使用されます。移行タグ付きの引数が指定されている場合に含まれます。例えば:
$ go run -tags migrate ./cmd/app
internal/controller
サーバーハンドラーレイヤー(MVCコントローラー)。テンプレートには2つのサーバーが表示されます。
サーバールーターは同じスタイルで書かれています:
internal/controller/http
シンプルなRESTバージョン管理。
http/v2v2の場合、同じコンテンツのフォルダーを追加する必要があります。そして、ファイル
internal/appに次の行を追加します。
handler := gin.New()
v1.NewRouter(handler, t)
v2.NewRouter(handler, t)
Ginの代わりに、他のhttpフレームワークや標準
net/httpライブラリを使用することもできます。
v1/router.goハンドラーメソッド以上に、swagを使用してSwaggerドキュメントを生成するためのコメントがあります。
internal/entity
ビジネスロジック(モデル)のエンティティは、任意のレイヤーで使用できます。たとえば、検証のためのメソッドもあります。
internal/usecase
ビジネスの論理。
リポジトリ、webapi、rpc、およびその他のビジネスロジック構造がビジネスロジック構造に注入されます(依存性注入を参照)。
internal/usecase/repo
リポジトリは、ビジネスロジックが機能する抽象ストレージ(データベース)です。
internal/usecase/webapi
これは、ビジネスロジックが機能する抽象的なWebAPIです。たとえば、ビジネスロジックがRESTAPIを介してアクセスする別のマイクロサービスである可能性があります。パッケージ名は目的により異なります。
pkg/rabbitmq
RabbitMQ RPCパターン:
外部パッケージへのビジネスロジックの依存性を取り除くために、依存性注入が使用されます。
たとえば、Newコンストラクターを使用して、ビジネスロジックの構造に依存関係を挿入します。これにより、ビジネスロジックが独立(および移植可能)になります。
usecaseパッケージに変更を加えることなく、インターフェースの実装をオーバーライドできます。
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()
}
また、モックの自動生成(たとえば、モックを使用)を実行し、単体テストを簡単に作成できるようになります。
あるコンポーネントを別のコンポーネントに常に変更できるようにするために、特定の実装に縛られることはありません。新しいコンポーネントがインターフェイスを実装する場合、ビジネスロジックで何も変更する必要はありません。
プログラマーは、ほとんどのコードが記述された後、アプリケーションに最適なアーキテクチャーを実現します。
優れたアーキテクチャにより、決定を可能な限り遅らせることができます。
依存性逆転の原則(SOLIDと同じもの)は、依存性逆転の原則です。依存関係の方向は、外層から内層に向かっています。このため、ビジネスロジックとエンティティはシステムの他の部分から独立したままです。
したがって、アプリケーションは内部と外部の2つの層に分割されます。
ビジネスロジックを備えた内層はクリーンである必要があります。そうすべき:
ビジネスロジックは、Postgresや特定のWebAPIについて何も知りません。ビジネスロジックには、抽象データベースまたは抽象WebAPIを操作するためのインターフェイスがあります。
外層には他の制限があります。
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:
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
Entities are structures that business logic operates on. They are located in the
internal/entityfolder. In MVC terms, entities are models.
Use Cases is business logic located in
internal/usecase.
ビジネスロジックが直接対話するレイヤーは、通常、インフラストラクチャレイヤーと呼ばれます。これらは、リポジトリ
internal/usecase/repo、外部WebAPI
internal/usecase/webapi、任意のpkg、およびその他のマイクロサービスです。テンプレートでは、インフラストラクチャパッケージは内にあり
internal/usecaseます。
必要に応じて、エントリポイントの呼び出し方法を選択できます。オプションは次のとおりです。
Clean Architectureのクラシックバージョンは、大規模なモノリシックアプリケーションを構築するために設計されており、4つのレイヤーがあります。
元のバージョンでは、外側のレイヤーはさらに2つに分割されており、これらも相互に依存関係が逆転し(内側に向けられ)、インターフェイスを介して通信します。
複雑なロジックの場合、内層も2つに分割されます(インターフェイスが分離されています)。
複雑なツールは、追加のレイヤーに分割できます。ただし、本当に必要な場合にのみレイヤーを追加する必要があります。
クリーンアーキテクチャに加えて、オニオンアーキテクチャとヘキサゴナル(ポートとアダプタ)はそれに似ています。どちらも依存性逆転の原則に基づいています。 ポートとアダプタはCleanArchitectureに非常に近く、違いは主に用語にあります。