ブログ記事
変更が怖いコードと変更を歓迎するコードの違い:仙場大也『良いコード/悪いコードで学ぶ設計入門』
コードを追加するたびにどこかが壊れる。レビューで「なぜこう書いたのか」を説明できない。そういった状況は、個別の技術不足というより、設計の基礎知識が体系化されていないことから生じることが多い。
仙場大也(ミノ駆動)の『良いコード/悪いコードで学ぶ設計入門』は、「悪いコードがなぜ問題を起こすのか」を具体的な症状から出発し、それを解消する設計の手法へとつなげる構成をとっている。Java でサンプルコードが書かれているが、考え方自体は言語に依存しない。
1. データクラスが引き起こす「低凝集」問題
バグが繰り返し発生する箇所の多くは、データを持つクラスとそのデータを使うロジックが別々の場所に散らばっている。この状態を「低凝集」と呼ぶ。
金額を int で持つクラスがあるとき、その金額に対する計算ロジックは利用側のあちこちに書かれることになる。似た計算が複数の場所に存在し、仕様変更が発生すると修正漏れが起きる。
本書が提示する対策は「値オブジェクト+完全コンストラクタ」だ。
- 値オブジェクト: 金額を単なる
intではなくMoneyクラスとして扱い、計算ロジックをそのクラス内に持たせる - 完全コンストラクタ: インスタンス化の時点で全フィールドを初期化し、不正な値をガード節で弾く
この2つを組み合わせることで、クラス自身がデータの整合性を守る「自己防衛」の構造が生まれる。外部から不正な値をセットされる経路がなくなり、不変(イミュータブル)にすることで状態変化のトレースが容易になる。
2. 条件分岐のネストを解消する2つのアプローチ
if の中に if が入り込む多重ネストは、コードの見通しを悪化させる代表的なパターンだ。どの条件がどこまで影響するのかを追いかけるだけで時間が奪われる。
早期 return: 条件を反転させて、処理対象でないケースを冒頭で除外する。本来やりたい処理が関数の中心に来て、読み流せる構造になる。
ストラテジーパターン: 同じ条件軸(例: 魔法の種類)の switch 文が複数箇所に散らばっている場合、条件ごとにクラスを作り interface で切り替える構造に変えると、新しい種類を追加しても既存コードを変更せずに済む。
ポリシーパターン: 「購入金額が10万円以上 かつ 購入頻度が月10回以上 かつ 返品率が0.1%以下」といった複合条件は、各ルールを個別のクラスとして定義し、「ポリシー」として束ねることで if 文の肥大化を防げる。
これら3つのアプローチに共通するのは「条件分岐を分散させず、一カ所に集約する」という考え方だ。
3. クラスの設計が読みやすさを決める
第10章以降で扱われる「名前設計」と「コメント設計」は、コーディングの習慣として定着させやすい知見がまとまっている。
- 技術的な仕組みで命名する(
MemoryStateManager)のではなく、ビジネス上の意図で命名する(ShoppingCart) - コメントはコードが「何をしているか」ではなく「なぜそうしているか」を書く。前者はコード自体が語るべきだからだ
命名はリファクタリングの単位でもある。名前がうまく付けられないクラスは、複数の責務を抱えているシグナルとして読める。
4. リファクタリングを安全に進める手順
テストのないコードを変更するのは怖い——この恐怖を乗り越えるために本書が示す手順がある。
仕様化テスト: まず現在のコードに対してテストを書き、「実際に何が返るか」を記録する。振る舞いを固定してからコードを変える。
試行リファクタリング: 本番コードへの取り込みを前提にせず、構造を理解するために「お試し」でリファクタリングしてみる。ゴールが見えたら破棄し、テストを先に書いてから正式に作業する。
2つ帽子の原則も重要だ。「機能追加中」と「リファクタリング中」を同時にやらない。コミットも分ける。バグが発生したとき原因を探しやすくするためだ。
DevBookPath のマップで確認する
この本を読んだあとの次の一冊は、DevBookPath のグラフで辿れます。
本記事のリンクには Amazon アソシエイト等の広告が含まれる場合があります。リンク経由の購入で運営者に紹介料が支払われることがあります。
この記事を共有
この地図を共有