クリーンアーキテクチャについて話を聞いたんです。
はじめに
こんにちは!!会津大学学部二年のHAMADAです。
季節も変わり始め、寒くなってきましたが生きております。
今回は、クリーンアーキテクチャについてのお話です。
動機・目的
10月29日~10月30日に会津大学の大学祭があります。その中で、学内でハッカソンが開催され参加することにしました!!!それに際して、チームのつよつよ先輩方に昨日アーキテクチャのお話をして頂いたのでアウトプットとして書きます。アーキテクチャの学習は初めてで、足りないポイント、間違った解釈があるかと思いますが、暖かい目でみていただけると嬉しいです。
クリーンアーキテクチャとは
層の話
- Controller層
外部と内部の変換。一番外側の層。user側に触れるもの。 - UseCase層
ドメインロジック(役割のこと)/アプリケーションサービス
- Service層
ドメインサービス(仕様上これ以上分割できない操作)
- Repository層
外部との接続(APIやDBなどがここに入る)
- Model層
ドメインモデル(仕様上決まっているもの。これを変えることはほとんどない。)
UseCase層とRepository層の関係
UseCase層はRepository層にふんわりとした抽象的なものを要求します。"こんな感じのものが欲しいな〜w"みたいな感じ。UseCase層でinterfaceを実装して、Repositoryで具体性を持たせています。
Service層の必要性
Service層は、必要な場合となくても良い場合の両方が存在するようです。Service層が意味をなさない場合でも、実装して繋ぎ役としてわかりやすい関係性にすることもあります。
先輩からのクイズ
Q.Userを取得するエンドポイントをざっくりと実装してください(id指定で関数名だけでOK)
私が最初に、書いたのがこちら。
なんか汚い字で色々書いてますねw
Controller層は、目的となるUserを取得することから、GetUser(id)と命名しています。
UseCase層は、interface的な定義なので、GetUser(id)と命名しましたが、Controller層と同じ命名で良いのか悩んでいます。
Service層では、Userを取得する方法、手段という点からidを使うという発想によって命名しています。命名に不安を覚えています。
Repository層は、Userを取得するという考えから、この命名にしています。idを使って取得することから、Nameだけでいいのかな?情報という意味でinf(information)にすべきか悩んでいます。
Model層は、先輩から与えられました。
添削
Controller層は、OKでした。
UseCase層は、実際の定義となる部分なのでOKでした。
Service層は、微妙でした。意図するところはあっていましたが、命名としてはFindを用います。FindUserByIdとするのが良さそう。
Repository層は、考え方はOK。しかし、NameにするとModelが違うと不適切なので、FindUserByIdとするとよさそう。
次のクイズ........
Q.UserNameを取得するエンドポイントをざっくりと実装してください(id指定で関数名だけでOK)
(画像がありませんでした.....すみません)
Controller層は、GetUserName (id)。
UseCase層は、GetUserName (id)。
Service層は、FindUserNameById(id) 。これは、ちょっと悩みました。FindUserNameByIdにするか、FindUserByIdにするか。必要なアクションはNameを得ることなので、FindUserNameById(id) に決定しました。
Repository層は、ここで取得するのはUserなので、FindUserById(id)にしました。
Model層は、与えられました。
添削
全てOKをいただきました!!!!!! やった!!!!!
Service層の悩んだところですが、Nameを得るが最低限必要だということで、問題ありませんでした。
実際の構成
APIを作るときの例
1エンドポイント 1Controller
1エンドポイント 1UseCase
//controller/user.go
//ここで使うのはUserUseCase
type UseControllerImpl struct {
u usecase.UseUseCase
}
ここではControllerがUseCaseに依存しています。
usecase/user.go
ここでは、UserUseCase interfaceを定義。これは、ControllerがUseCaseに依存しています。
次に、UseRepositoryを定義。これは、RepositoryがUseCaseに依存しています。
そして、UserUseCaseImplを実装します。ここでは、普通にメソッドとして、実装します。
コンストラクタも実装する。(今回はgoを使いますが、慣例的にNew~という名前をつけます。)
DIPの話
DIPとは、Dependency Inversion Principle。依存性逆転の原則です。
SOLID原則のDです。
今まで、A->BというAの中でBの関数を使うという実装だったとして、B->Aという方向にするには、Aをinterfaceに依存させて、そのinterfaceを継承したBのなかで実装する。ということを行うとできます。
感想と展望
今回初めて、アーキテクチャについて学習しました。難しかったですが、かなり面白い概念だなと思いました。実際身につけて使ったり、説明するのはとても大変ですが少しずつでも理解し使えるようになりたいと思います。続きの話を書くこともあるかもしれません。先輩方に感謝を!!!!間違っているところなどの指摘があれば、アドバイスよろしくお願い致します。ここまでお付き合いありがとうございます!!!!
所属サークル
私のTwitter
私のgithub