かっこうのブログ

何かしら飲んでるエンジニア

「良いコード/悪いコードから学ぶ設計入門」悪いコードが生まれる原因を考える本

adventar.org

アドカレ5日目〜

昨日に引き続き設計本。今年のITエンジニア本大賞でも大賞になっていたので読んだ人も多い気がします。通称ミノ駆動本と呼ばれているのをみて笑いました。

内容としては、先日の現場で役立つシステム設計の原則より一歩、クラス設計の方向に近づいている書籍になります。また、実際に悪魔のコードが掲載されているため失敗をより肌で感じながら読めるのものこの本のいいところです。

お気に入り箇所

良いクラスの構成要素

インスタンス変数と インスタンス変数を不正状態から防御し、正常に操作するメソッド

データクラスの欠点の1つとして、設計に興味のない人がデータクラスの中からドメインを流出させ、同じ処理が複数で書かれることがあります。これは先日の本でも「getterで処理を書き出したら気をつけろ」と言われていましたね。

この本では、もう少し踏み込んでクラスの自己防衛責務や防御的プログラミングと呼ばれるような以下のことについて話しています。

  • 「一度データクラスを作ったら値を変えられないようにする」すなわちsetterをなくす
  • 間違いない値のみしか登録できず、値を書き換えられないようにすべき

この辺りの話は、texta.fmでt-wadaさんも語っているので興味のある人は是非聞いてみてください。

open.spotify.com

凝集度を高める

「クラス内における、データとロジックの関係性の強さを表す指標」を凝集度として話を進めます

本書ではクラスについて扱うため、粒度を「クラス」にすることで凝集度を上記のようにわかりやすく説明してくれています。

データオブジェクトにロジックを記載する。などは凝集度を高める手法の1つと言えます。

初期化ロジックがあちこちに分散して低凝集になってしまう場合があります。

これはインタンスを生成する時にconstructで値を挿入する際の値が異なる場合、ドメインが流出してしまうことを言っています。

例えば以下の場合です。

  • 一般ユーザーは100ポイント付与する new UserPoint(100)
  • プレミアユーザーは500ポイントを付与する new UserPoint(500)

これらの100や500は本来UserPoint内で決めてもいいものにも関わらず、インスタンス生成のロジックに流出しています。

そのため、UserPointのコンストラクタをプライベートにし、値の生成でのみ使えるstaticメソッドを使うことでロジックの流出を防ぐことができます。

このようにすると、「継承を使ってポイントをオーバーライドすればいいのでは?」と考えるでしょう。僕も考えました。

継承に絡む密結合

継承については非常に議論のあるところですね。実際Go言語など、継承の概念がない言語も存在します。ミノ駆動さんも、本書では継承は推奨しないというスタンスをとっています。

負わすべき責任を負わせず何でもやってあげてしまっている、過保護な毒親です。過保護な毒親のように責任を多重に負うクラスをつくると、ほかのクラスは未熟になります。

これは単一責任の原則を無視している親クラスへの言及です。こういった当時は意図していなくとも、「この方が楽だから」と毒親になってしまっているクラスを見たことありますよね?

これを避けるために、コンポジション構造にし依存性注入でインターフェースに依存する形にすることが良いと記されています。

名前重要

名前の重要性は前回の書籍でも語られていました。この本でも語られており、さまざまな臭いの見つけ方が示されています。

会話に登場する重要な概念が、ソースコード上で名前も付けられず、雑多なロジックの中に埋没していることが本当に頻繁に見受けられます。

これは雰囲気で実装が進むとよく起きるイメージがあります。しっかり会話をしていく中で、名前が見つかることも多いですし、ドメインに詳しいメンバーやユーザー(または普段ユーザーと話しているCSメンバー)と話すことでしっくりくる名前が見つかります。