クリーンアーキテクチャをパン工場で説明する【Go】
はじめに
本記事は技術書典16(2024)で一部執筆させていただいた「CA Tech Lounge note #2」のクリーンアーキテクチャとパン工場を元に、一部抜粋&変更したものです。
本記事の対象読者
本記事では、クリーンアーキテクチャを全くわかっていない筆者が、一度個人開発したものをクリーンアーキテクチャにリファクタリングしていく過程で学んだことをまとめていきます。そのため、以下のような読者を想定しています。
- クリーンアーキテクチャを聞いたことがあるけどわからない人
- コードは書くけれどアーキテクチャを意識したことはない人
- アーキテクチャを意識して開発したい人
- クリーンアーキテクチャを一度学んでもピンと来なかった人
- Goが好きな人!
リファクタリング前の筆者の状況
バックエンド歴は半年弱ほどで、実務経験としてはPythonで簡単なAPIを実装するアルバイトのみになります。アーキテクチャに関しては、数ヶ月前にその存在をしっかり知ったくらいのひよっこエンジニアです。Goは育成型のインターンシップで少し学び、その後ハッカソンで使用しました。今回は、個人開発したプロダクトをクリーンアーキテクチャにリファクタリングすることでアーキテクチャへの理解を深めようという狙いでした。
Clean Architecture とは
ボブおじさんの本を読んで考える
クリーンアーキテクチャを学びはじめた人が一度は読むであろうRobert C. Martin(通称ボブおじさん)が書いた "Clean Architecture" という本があります。この本は2018年に発売されましたが、表紙に「アーキテクチャのルールはどれも同じである!」と書かれており、普遍的な考え方が述べられているとされ現在でもアーキテクチャにおける教科書のようになっています。この本で述べられているクリーンアーキテクチャの説明は以下の通りです。
4つ特性を持つシステム
- フレームワーク非依存: フレームワークに縛られるのではなく、あくまでもツールとしてフレームワークを使う
- テスト可能: 外部要素がなくてもテストできる
- UI非依存: UIを変更したとしても、システムに影響を与えることはない
- DB非依存: DBの種類に束縛されない
- 外部エージェント非依存: ビジネスルールは外界のインターフェースについて何も知らない
初見でピンとは来ないかもしれないですが、なんとなく外部と切り離して考えたい
のかな?というのは伝わってきますね。
依存の方向性を考える
この画像もクリーンアーキテクチャを一度でも勉強しようと思った人ならほとんどが見たことがあるのではないかと思います。この画像が述べているのは、ざっくり言うと 「責務を分けて、依存の方向性を考えよう」 ということです。責務とは言葉通りに見れば責任と義務のことですが、コードを考える上ではそのコードが持つ機能やレイヤーのことです。責務を明確化して段階分けすること、各層がデータをどのような順番で処理していくのかのルールを決めておくことが依存の方向性を考えることにつながります。
責務を分ける
-
エンティティ層 (ドメイン層)
ビジネスまたはプロダクトのロジックをカプセル化したものです。プロダクトの一番核となるようなことがこの層には含まれ、外部のフレームワークや操作がこの層に影響を与えることはありません。 -
ユースケース層(アプリケーション層)
システムの全てのユースケースがここに書かれています。ユースケースはエンティティに入出力されるデータの流れを調整し、エンティティのどのユースケースを呼び出すかを管理します。 -
インターフェースアダプター層(プレゼンター層やコントローラー層)
この層では、外部(入力値や DB への保存など)と、内部のロジックを繋いでいます。例えば、DBへの挿入にSQL文が必要なのであれば、この層で行うことになります。実際に実行ボタンを押している場所だとも言えるでしょう。 -
フレームワークとドライバ層
この層では、DBやフレームワークの接続を行います。そのため、コード自体を長く書くことはあまりありません。
生まれる利点
- 高い保守性
- 高い機能拡張性
保守性が高いというのは、プロダクトを維持、運用していくコストが低いと言うことです。機能拡張性が高いと言うのは、新しい機能を追加するときに元々の機能を大きくいじらなくても変更が容易だということです。
さて、ここまでボブおじさんのClean Archtectureについて説明させていただきましたが、これらを聞いて具体的なコードが思い浮かぶ人は少ないと思います。また、この本ではオブジェクト指向などまだまだ盛りだくさんかつ馴染みのない人にとっては少し噛み砕くのに時間がかかる内容が多くありました。ちなみに私は初見では1割も理解できませんでした。そこで次の章では、クリーンアーキテクチャが表しているのがどう言うものなのか、少しポップに私なりの考え方をお伝えします
アーキテクチャをパン工場にする
それでは、突然ですがパン工場でパンを作ることを例に考えてみます。先ほどのクリーンアーキテクチャの説明にそって、パン工場での流れを層ごとに分けてみましょう。
実装したい機能:パンの生地セットをパン工場に送ったら、賞味期限と商品番号が割り当てられたパンがプラスチックの袋に入れられて出荷される
ドメイン層
ビジネスまたはプロダクトのロジックをカプセル化するのがドメイン層なので、パンというものの定義と、パン工場のざっくりとした流れの定義を行います。
パンの構造体{
パン本体,
賞味期限,
商品ID,
}
パン工場における流れ {
製造,
商品IDからパンを特定,
廃棄,
etc.
}
ユースケース
ここでは、パン工場における全てのユースケースの流れを細分化し全て記述します。ユースケースは実行の手順書とも考えることができます。ここではパンを製造するユースケースで考えてみます。
パン生地セット構造体の定義
商品IDを生成するロジック
賞味期限を定義するロジック
受け取ったパン生地セットをこねて焼くというインターフェース
ドメイン層の'パン工場における流れ.製造'を呼び出しパン作成ユースケースをまとめる
etc.
インターフェースアダプター層
ここでは外部(パン工場の外やラッピング)と内部(パン)を結びつけます。
パン製造のユースケースを呼び出し、実際の生地の材料セットを内部に渡します(ハンドラー)
内部で出来上がったパンをラッピングしして出荷します(DBとの接続)
フレームワークとドライバ層
ここでは外部のものを定義します
ラッピングの袋はプラスチックである
メリットを考える
例えば、このパン工場で急にラッピング袋を紙にしたいとします。その場合、フレームワークとドライバ層しか変える必要はありません(実際のコードだとインターフェースアダプター層も少し変わる可能性があります)。これが機能拡張性の高さになります。
感想
以上が、パン工場の仕組みをクリーンアーキテクチャで考えた場合の例になります。
色々調べていくうちに、クリーンアーキテクチャに完璧な正解がないことに気がつき驚きました。もちろんルールは一定程度決まっているものの、各プロダクトに合わせてある責務がどのレイヤーに属するのかを考える必要があります。
また、クリーンアーキテクチャが全てのプロダクトにとってベストというわけではないことも勉強するうちにわかってきました。クリーンアーキテクチャは大規模開発や、ある程度メンバーがアーキテクチャに対する理解があることによってメリットが大きくなります。なぜならば、多くのメリットはあるものの工数は多くなりますし、実装コストがかかるためです。
具体的なコードの実装については、技術書典の合同誌の中に記述してあるのでこの記事では端折らせていただきます。読んでいただきありがとうございました!
Discussion