「Clean Architecture 達人に学ぶソフトウェアの構造と設計」所感
フランスから帰国しました。「彼女がお盆で家族に会うために帰省するのに同行した」ような感じでした。フランスにお盆という習慣は無いのですが、まあそんな感じです。
父、母、姉家族✖️2、彼女、僕という異様な光景で、さながらサマーウォーズのフランス版とでも言いましょうか。フランスのPoitier, MontMollion, Montpellierの田舎を転々としていました。
家族曰く、娘と3年ぶりに再会する感動的な時に男を連れてくるなんて、、と最初は憤慨していたようでした、僕の人となりを見て安心してくれたようです。
フランスで仕事をしてみて、意外とどこでも仕事できるんだなと感じました。
仕事の質はさておき、、
今回はフランスに行く時に共に持っていった、
「Clean Architecture 達人に学ぶソフトウェアの構造と設計」を読んで学んだことを書きたいと思います。
良いコードとは
良いコードは、シンプルである。シンプルだと他人が読みやすいため、メンテナンスがしやすくなる。「他人」には、「将来の自分」も含まれている。
メンテナンスのしやすいコードを書く上で意識するべきルールがあり、それが
「凝集度、結合度、クリーンアーキテクチャ」だそうだ。
それぞれ下記のような役割を果たしている。
- モジュール内部の実装→凝集度
- モジュール間の実装→結合度
- モジュール群の実装→クリーンアーキテクチャ
引用文献を交えながら、学んだことをまとめていきたい。
Clean Architecture
将来の変更に強いアプリケーションを作るために考案された設計手法。
三つの重要な原則を伝えている。
下記三つを守るとソフトウェアのメンテナンスがしやすくなる。
- 必ず上位レイヤーに依存方向を向ける
- 依存関係と処理方向は分離する
- 関心事の分離
UI→Controller→UseCase→Entityというように、最重要ビジネスルールに向かって依存関係を向けることが原則として説かれている。
最重要ビジネスルール
💡 コンピューターシステムが実装されているかに関わらずマネーを生み出したり節約したりするルールを指す
例
「銀行が貸したローンに利息を何%つけるというルール」
コンピューターシステムに関係ないルールを指している。
Zerokenで考えてみる。
とはいえZeokenに実際にお金を生み出したりコスト削減につながっているルールはない。
別の言い方に変えてみる。
このアプリを作った目的は何か。
それは、誰かの問題を解決するため。
誰かの問題を解決することができたら、それだけで価値である。
つまり、このアプリの最重要ビジネスルールは、解決しようとしている領域を指している。
ということで、 Zerokenの最重要ビジネスルールはいかになる。
「お酒の強さを診断すること」
そのアプリが存在する目的を問うと最重要ビジネスルールが分かる。
最重要ビジネスデータ
💡 最重要ビジネスルールを実現する時に使用するデータを指す
金利、貸付金残高、支払いスケジュールなどを指す
Zerokenでいうところの
質問、ポイント、お酒の強さ、酔っ払いの尺度、アルコール度数等
を指している
エンティティ
💡 最重要ビジネスルールと最重要ビジネスデータを一つのオブジェクトとして表したもの
ドメインと呼ばれることが多い
ユースケース
💡 自動化されたシステムを利用する方法のこと
💡 エンティティの最重要ビジネスルールをいつ・どのように呼び出すかを規定したルールが含まれている
ユーザーがボタンを押して〜からではなく、インターフェースからやってくるデータとそこから出ていくデータを略式で規定しているだけ。
ユーザーインターフェースについては言及していないことに注意。データがどのようにインターフェースに入出力されるかはユースケースの関心ごとの範疇から離れる。
エンティティは入出力から遠いため、上位レイヤーに位置し、ユースケースは入出力から近いため下位レイヤーに属する。
そのため、依存の方向は必ずユースケース⇨エンティティになっていないといけない。
凝集度、結合度のグラデーション
💡 凝集度とは、モジュール内の協調度を指しており、高い程、堅牢性・信頼性・再利用性・読みやすさの点で好ましい。
良いコードとは何か - エンジニア新卒研修 スライド公開|CyberZ Developer|note
レビューを受ける際に、「コントローラーでこの処理を書くのはダメです」「ここでこの処理をするのは良くないと思います」と先輩エンジニアからレビューを受けた。
良い悪いを断言できるのは、経験からなのだろうかと考えていたところ、どうやらコードにはルールというものが存在すると分かった。
そのルールの一つが、凝集度と結合度である。
偶発的凝集〜機能的凝集まで7つの階層で分けられている。
結合度に関しては、凝集度を高めることで自然と低くすることができるとのこと。
例えば論理的凝集は下記のようなものを指している。
userの職位に応じてタスクを振り分けるようなメソッド。
def assignTask(user: nil)
levelA()
levelB()
levelC()
if user == professional
levelD()
else
levelE()
end
これは下記のようにリファクタリングすると機能的凝集、逐次的凝集等の比較的好ましいとされるレベルまで高めることができる。
def assignTaskForProfessional
levelA()
levelB()
levelC()
levelD()
end
def assignTaskForStandard
levelA()
levelB()
levelC()
levelE()
end
条件分岐がなくなったことで、このメソッドが何をしているのかが読みやすくなった。
読みやすくなったことで、他のメソッドに使い回しやすくもなった。
善悪を断言できる時、その裏に根拠が隠されている可能性が高いと勘繰ることができる。
オブジェクト指向のその前に-凝集度と結合度/Coheision-Coupling
分散システムにおける適度な結合とは - Viadik Khononov氏のDDD Europeでの講演より
ドメイン固有モデル(DSL)
💡 分野(ドメイン)に存在する固有の事象を表す特殊な語彙
【23】ドメイン特化言語|プログラマが知るべき 97 のこと
メソッドとメッセージの違い
- メッセージ
レシーバ(オブジェクト)にしてほしい挙動をさす。
下記でいうsubaruにしてほしい挙動
「subaruに皿を洗ってほしい」
subaru = Human.new(name: 'subaru')
subaru.wash_dish
- メソッド
オブジェクトが持つ関数
class Subaru
def wash_dish
prepare_dish
run_faucet
scrub_dish
run_faucet
end
end
「メソッド」と「メッセージ」はどう違うのか - Crieit
ソフトウェアも人生のどちらもクリーンに設計していきたいものです。