クリーンなアーキテクチャーに従って設計されたGoアプリケーションの構築方法


9

ここで説明するように、私はクリーンなアーキテクチャを使用してプロジェクトを構築しようとしていますGoでこれを行う方法についての素晴らしい記事を見つけました。

この例は非常に単純なものであり、作成者はコードをパッケージ内のレイヤーに基づいて名前が付けられたパッケージに入れます。ボブおじさんのアプリケーションのアーキテクチャはその意図を明確に伝えるべきだという考えが好きです。したがって、ドメイン領域に基づいたトップレベルのパッケージをアプリケーションに持たせたいのです。したがって、私のファイル構造は次のようになります。

/Customers
    /domain.go
    /interactor.go
    /interface.go
    /repository.go
/... the same for other domain areas

これの問題は、複数のレイヤーが同じパッケージを共有することです。したがって、依存関係のルールがいつ違反されているかは明確ではありません。何が何に依存しているかを示すインポートがないためです。

私は、これはあなたが個々のファイルをインポートすることができますので、問題の限りではありませんので、Pythonの背景から来ているcustomers.interactorインポートすることができcustomers.domain

パッケージをネストすることにより、gOで同様のことを実現できます。その結果、customersパッケージにはドメインパッケージとインタラクターパッケージなどが含まれます。これは不格好に感じられ、同じ名前のパッケージは扱いが面倒です。

別のオプションは、ドメイン領域ごとに複数のパッケージを作成することです。1つはcustomer_domainと呼ばれ、もう1つはcustomer_interactorと呼ばれます。しかし、これも汚い感じがします。これはGoのパッケージ命名ガイドラインにうまく適合せず、名前には共通のプレフィックスが付いているため、これらの個別のパッケージはすべて何らかの方法でグループ化する必要があるように見えます。

では、これに適したファイルレイアウトは何でしょうか。


アーキテクチャレベルだけでパッケージを編成したアーキテクチャに苦しんでいる人として、機能ベースのパッケージに対する私のサポートを表明させてください。私はすべて意思疎通を図っていますが、1つの新しい機能を追加するためだけに、すべてのあいまいな隅や隅をクロールしないでください。
candied_orange 2017

意図的に、パッケージはアプリケーションの内容を伝える必要があることを意味します。ですから、ライブラリアプリケーションを構築している場合は、その他の本パッケージ、貸し手パッケージを、持っていると思います
bigblind

回答:


5

これにはいくつかの解決策があります:

  1. パッケージの分離
  2. レビュー分析
  3. 静的分析
  4. ランタイム分析

それぞれに長所/短所があります。

パッケージの分離

これは、追加のビルドを必要としない最も簡単な方法です。これには2つのフレーバーがあります。

// /app/user/model/model.go
package usermodel
type User struct {}

// /app/user/controller/controller.go
package usercontroller
import "app/user/model"
type Controller struct {}

または:

// /app/model/user.go
package model
type User struct {}

// /app/controller/user.go
package controller
import "app/user/model"

type User struct {}

ただし、これはの概念の全体を壊しUserます。理解または変更Userするには、いくつかのパッケージに触れる必要があります。

しかし、それはmodelインポート時により明白controllerであり、ある程度までは言語のセマンティクスによって強制されるという優れた特性を持っています。

レビュー分析

アプリケーションが大きくなく(30KLOC未満)、優れたプログラマーがいる場合、通常は何も構築する必要はありません。値に基づいて構造を整理することで十分です。例:

// /app/user/user.go
package user
type User struct {}
type Controller struct {}

多くの場合、「制約違反」はほとんど意味がないか、簡単に修正できます。明快さと理解しやすさを損なう-それが手に負えないようにしない限り、あなたはそれについて心配する必要はありません。

静的/ランタイム分析

静的または実行時分析を使用して、アノテーションを介してこれらの障害を見つけることもできます。

静的:

// /app/user/user.go
package user

// architecture: model
type User struct {}

// architecture: controller
type Controller struct {}

動的:

// /app/user/user.go
package user

import "app/constraint"

var _ = constraint.Model(&User{})
type User struct {}

var _ = constraint.Controller(&Controller{})
type Controller struct {}

// /app/main.go
package main

import "app/constraint"

func init() { constraint.Check() }

静的/動的のどちらもフィールドを介して行うことができます:

// /app/user/user.go
package user

import "app/constraint"

type User struct {   
    _ constraint.Model
}

type Controller struct {
    _ constraint.Controller
}

もちろん、そのようなものの検索はより複雑になります。

他のバージョン

このようなアプローチは、型の制約だけでなく、関数の名前付け、APIなどにも使用できます。

https://play.golang.org/p/4bCOV3tYz7

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.