MENU

「良いコード/悪いコードで学ぶ設計入門」まとめ

設計の初歩:悪しき構造を避け、変更容易性を守るためのチェックリスト

ソフトウェア設計の目的は、機能を増やしても壊れにくく、直しやすい状態(変更容易性)を保つことです。
ここでは「悪しき構造が生む痛み」を知覚しつつ、設計の初歩として押さえたいポイントを、実装のコツとセットで整理します。


目次

悪しき構造の弊害を知覚する

設計が崩れると、最終的に起こるのは「変更が怖い」「修正が増える」「不具合が増える」です。
その入口になりがちな要素を先に潰します。

  • 変更容易性を維持しよう
  • 実装に寄った命名と連番命名は避けよう
  • 例:process1, data2, temp, flagA など
  • 読み手が「意味」ではなく「推測」に頼る構造になる
  • 条件分岐のネストを深くしすぎないように
  • ネストが深いほど、意図と例外条件を追えなくなる
  • データを保持するだけのクラスは避けよう
  • 「データ」と「処理」が離れると、処理が各所に散らばりやすい
  • 結果として修正箇所が増え、影響範囲が読めなくなる

設計の初歩

ここは地味だけど効きます。読む側の理解コストを下げるのが主眼です。

  • 省略せず意図が伝わる名前にしよう
  • “短さ”より“誤読されないこと”を優先する
  • 再代入を避け、目的ごとの変数を用意しよう
  • 1つの変数に別の意味を背負わせない
  • 目的ごとのまとまりでメソッド化しよう
  • 「何をしているか」が見える単位に切り出す
  • 関係し合うデータとロジックをクラスにまとめよう(カプセル化)
  • “同じ理由で変わるもの”は近くに置く

カプセル化の基礎

変更容易性を高める設計の基礎は以下 3 つです。

  • カプセル化
  • 関心の分離
  • 多態性による機能の取り替え

そして、カプセル化の最低ラインはこれです。

  • インスタンス変数は同クラスのメソッドで操作する実装にしよう
  • 外部から直接いじれる状態が増えるほど、破壊の可能性が増える

不変の活用

再代入(破壊的代入)は、変数の意味が変わるため、推測が難しくなります。
可能な限り不変(immutable)に寄せるのが基本方針です。

  • 再代入(破壊的代入)は意味を変え、推測を困難にする
  • final をつけて再代入不可にしよう(言語・環境に合わせて相当の仕組みを使う)

可変なときに起こりがちなこと

  • インスタンス変数が直接更新され参照を共有してしまう
  • 別の箇所で初期化されたクラスと参照を共有 → 変更の伝播
  • 複数の関数・別スレッドから操作される
  • 結果揺れが起こる(常に同じ結果が得られない)

不変に寄せるとどうなるか

  • 関数は変更値を持った新しいインスタンスを生成して返す
  • 副作用が減る/なくなる
  • テストもしやすくなる

関心の分離

  • 関心:ソフトウェアの機能や目的のこと
  • 関心の分離:それぞれの関心でモジュールを独立させ、他の関心と分離する考え方

開発が進むと、インスタンス変数を理由に「全部入りクラス」が生まれがちです。

  • インスタンス変数に強く関係しているという理由で、クラスの概念が肥大化しがち
  • → 目的ごとに分離し、カプセル化しよう

関連する原則:

  • 単一責任の原則(SRP):クラスが担う責任は、たったひとつに限定すべき
  • 目的が違うロジックをDRYしてはいけない
  • 似ている “形” ではなく、同じ “目的” の重複だけを減らす

条件分岐:ネスト地獄から抜ける

  • ネストが深くなると可読性が著しく低下する
  • switch は同じ条件で複数箇所に処理を書きがち
  • → 修正漏れが発生しやすい
  • かといって一つの switch に全ロジックを集中させると肥大化する
  • 分岐の扱いは「集中」ではなく「分配」が必要

インターフェースでロジックをシンプルにする手順

  1. 機能を取り替える単位を見つける
  2. インターフェイスと実装の分離にもとづき、入力と結果を整理する
  3. interface を定義する
  4. interface を実装する
  5. 機能を取り換える仕組みをつくる

分岐をむやみに書かず、ポリシーパターンで機能の取り替えをしよう

(※差し替えたい条件やロジックが増えていく領域ほど、効果が出ます)


コレクション:for文の前に考えること

  • for 文を書きそうになったら、標準メソッドで間に合わないか検討する
  • continuebreak を使って早期離脱させる
  • コレクションに関するロジックをカプセル化してまとめる
  • ファーストクラスコレクション(Collectionを「ただの配列/リスト」にしない)

メソッド:やってはいけないと、やるべきこと

他クラスの内部に踏み込まない

  • 他のクラスのインスタンス変数は使うな
  • getter/setter で他所から値を勝手に出し入れできる状態を増やさない
  • 詳細なロジックは関心を管理するクラスに実装する
  • 尋ねるな、命じろ(Tell, Don’t Ask)

コマンド・クエリ分離(CQS)

  • コマンド:状態を変える(副作用あり)
  • クエリ:状態を返す(副作用なし)
  • これを分けると関心が分離され、テストもしやすい

引数の設計

  • 引数は不変にする
  • フラグ引数を使わない
  • Nullを渡さない
  • 可能な限り少なくする

戻り値の設計

  • プリミティブ値を返しすぎない
  • 型で意図を表明する(ドメインの言葉を返す)

まとめ:変更しやすいコードは「推測が要らない」

  • 名前が意図を説明し
  • 変数が意味を変えず
  • 分岐が増えても差し替え可能で
  • データとロジックが同居し
  • 副作用が見える

この状態を維持できると、設計は自然に“壊れにくい形”へ寄っていきます。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする

目次