僕のオレオレClean Architectureの構造
#CleanArchitecture #golang
Clean Architectureはレイヤードアーキテクチャの中でも比較的柔軟なイメージがあります。
レイヤーは4層である必要がなくて、少なくてもいいし、多くてもいいとされています。
必要なのは依存が一方向に流れることで、内部は外部に依存しないことで疎結合に開発ができます。
疎結合にできるおかけげ、テストしやすかったり、変更に耐えられたりします。
過去に僕が勉強した時のログは下記にあります
「Clean Architectureで実装するバッチ処理」についての勉強
今回説明しないのは下記です
DIの方法
interfaceの置き方
実際のコーディング
今回のシナリオ
僕はどちらかというとバックエンド担当のサーバサイドのエンジニアです。
今回は直接的な入力はなく、フロントからDBに放り込まれたデータをもとに動き続けるシステムの構築をします。
投資エンジニアとしてそれらしい、移動平均のゴールデンクロスを検知して注文を出すところまでをやってみたいと思います。
Clean Architectureを少し復習
https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg
一番よく見る図ですが、各レイヤーに何があるのかはちょっとわかりにくかったりします。
なのでとりあえず丸をほどいて横に並べます。
https://gyazo.com/2145cff541c3827e7124dcf2df571d65
名前は変わっていますが色で見てください。
一番左から、Frameworks & Driversに対応するInfra
Interface Adaptersに対応するAdapter
Application Business Rulesに対応するUse Case
Enterprice Business Rulesに対応するDomain
という4構成です。
Infraはドメインの外側にあるものを定義します。
例えばFTPの実装とか、Slackへの通知の実装とか、DBへの操作とか、HTTPリクエストとかがそうです。
他にも定期的に処理を実行するためのスケジューラもここにおいたりしています。
Adapterは外側と内側をつなぐ役目をします。
つなぐとは、基本的には入出力データの変換と、正しいユースケースへの振り分けですです。
外からのデータをそのまま内側に入れてしまうのはよくありません。
例としてWebAPIサーバの場合、HTTPリクエストをそのまま内側にいれてしまえということがあるかもしれません。
しかし、それは内側が外側に依存していることになります。これじゃあレイヤー分けしたうまみがなくなってしまいいます。
なので、外側で定義されたオブジェクトを内側で定義したオブジェクトに変換して内側に渡してあげるのです。
Use Case と Domain は言葉での説明が難しいのですが、
DomainはMVCでいうModelに当たる部分です。model、repository、serviceって感じのあれです。
Use CaseはDomainのserviceを組み合わせて一つの処理の流れを作る場所です。
復習はこんなもんで。
シナリオをレイヤーにわける
https://gyazo.com/a59734b83ac42dff4528156702d5c854
今回はスケジューラで動かされるものなので、Adapterがありません。
外から入ってくるものも、中から出すものもないので。
なので、Infra、Use Case、Domainの3層です。
Infraにはスケジューラの他に、DB操作とWebAPIを叩くものが入っています。
実際は他にもロガーとか、日時関連のものもあったりします。
メモリ上に展開するのとかもここに置いたりします。
Use Caseはおっきな処理の単位をイメージしてます。
例えば新規注文を出す!とか、約定確認をする!とか、返済注文を出す!とかがそうです。
Use Caseの中にも処理は書きますが、複雑なのはすべて細切れにしてDomainに任せます。
あくまでUse Caseは複数の処理を組み合わせるところというイメージです。
Domainでは複雑な処理とか、Infraを利用しなくてはいけない処理とかをさせます。
あとで実際のディレクトリ構成も出しますが、DomainはService、Repository、Modelにわけています。
Serviceが処理の本体、RepositoryはInfraに直接依存しないためのinterface、Modelにはシステムで利用するデータ全般を入れます。
ServiceはDBからデータを取ったりもするので、ServiceがInfraを参照していますが、これはDIを使っているので直接的な依存はしないようにします。
ディレクトリ構成
code:Tree /f
D:.
│ main.go
│
├─domain
│ ├─model
│ │ enum.go
│ │ error.go
│ │ order.go
│ │ strategy.go
│ │
│ ├─repository
│ │ clock.go
│ │ security.go
│ │ strategydb.go
│ │
│ └─service
│ businessday.go
│ clock.go
│ indicator.go
│ order.go
│ strategy.go
│
├─infra
│ │ clock.go
│ │ scheduler.go
│ │
│ ├─db
│ │ db.go
│ │ strategy.go
│ │
│ └─logger
│ logger.go
│
└─usecase
order.go
見やすさのためにテストコードはすべて消しています
他にもlogsのようなディレクトリや、環境構築のためのDocker関連のファイルも消してます。あとgo.modとかも。
おわりに
今回はDIのことを度外視した記事なので表面をさらーとなぞった程度ですが、
それでもどんな形になるのかを雰囲気だけでも残せたらいいなーと思います。
実際のコードにまで触れたものを書こうとすると、何かしら公に公開してもいいもので開発しないとなので、
なかなか難しいんですよねー
僕のオレオレClean Architectureの実装編はまた後日
#2020/05/24週
更新履歴
#2020/05/25 公開