設計の初歩:悪しき構造を避け、変更容易性を守るためのチェックリスト
ソフトウェア設計の目的は、機能を増やしても壊れにくく、直しやすい状態(変更容易性)を保つことです。
ここでは「悪しき構造が生む痛み」を知覚しつつ、設計の初歩として押さえたいポイントを、実装のコツとセットで整理します。
目次
悪しき構造の弊害を知覚する
設計が崩れると、最終的に起こるのは「変更が怖い」「修正が増える」「不具合が増える」です。
その入口になりがちな要素を先に潰します。
- 変更容易性を維持しよう
- 実装に寄った命名と連番命名は避けよう
- 例:
process1,data2,temp,flagAなど - 読み手が「意味」ではなく「推測」に頼る構造になる
- 条件分岐のネストを深くしすぎないように
- ネストが深いほど、意図と例外条件を追えなくなる
- データを保持するだけのクラスは避けよう
- 「データ」と「処理」が離れると、処理が各所に散らばりやすい
- 結果として修正箇所が増え、影響範囲が読めなくなる
設計の初歩
ここは地味だけど効きます。読む側の理解コストを下げるのが主眼です。
- 省略せず意図が伝わる名前にしよう
- “短さ”より“誤読されないこと”を優先する
- 再代入を避け、目的ごとの変数を用意しよう
- 1つの変数に別の意味を背負わせない
- 目的ごとのまとまりでメソッド化しよう
- 「何をしているか」が見える単位に切り出す
- 関係し合うデータとロジックをクラスにまとめよう(カプセル化)
- “同じ理由で変わるもの”は近くに置く
カプセル化の基礎
変更容易性を高める設計の基礎は以下 3 つです。
- カプセル化
- 関心の分離
- 多態性による機能の取り替え
そして、カプセル化の最低ラインはこれです。
- インスタンス変数は同クラスのメソッドで操作する実装にしよう
- 外部から直接いじれる状態が増えるほど、破壊の可能性が増える
不変の活用
再代入(破壊的代入)は、変数の意味が変わるため、推測が難しくなります。
可能な限り不変(immutable)に寄せるのが基本方針です。
- 再代入(破壊的代入)は意味を変え、推測を困難にする
finalをつけて再代入不可にしよう(言語・環境に合わせて相当の仕組みを使う)
可変なときに起こりがちなこと
- インスタンス変数が直接更新され参照を共有してしまう
- 別の箇所で初期化されたクラスと参照を共有 → 変更の伝播
- 複数の関数・別スレッドから操作される
- 結果揺れが起こる(常に同じ結果が得られない)
不変に寄せるとどうなるか
- 関数は変更値を持った新しいインスタンスを生成して返す
- 副作用が減る/なくなる
- テストもしやすくなる
関心の分離
- 関心:ソフトウェアの機能や目的のこと
- 関心の分離:それぞれの関心でモジュールを独立させ、他の関心と分離する考え方
開発が進むと、インスタンス変数を理由に「全部入りクラス」が生まれがちです。
- インスタンス変数に強く関係しているという理由で、クラスの概念が肥大化しがち
- → 目的ごとに分離し、カプセル化しよう
関連する原則:
- 単一責任の原則(SRP):クラスが担う責任は、たったひとつに限定すべき
- 目的が違うロジックをDRYしてはいけない
- 似ている “形” ではなく、同じ “目的” の重複だけを減らす
条件分岐:ネスト地獄から抜ける
- ネストが深くなると可読性が著しく低下する
switchは同じ条件で複数箇所に処理を書きがち- → 修正漏れが発生しやすい
- かといって一つの
switchに全ロジックを集中させると肥大化する - → 分岐の扱いは「集中」ではなく「分配」が必要
インターフェースでロジックをシンプルにする手順
- 機能を取り替える単位を見つける
- インターフェイスと実装の分離にもとづき、入力と結果を整理する
interfaceを定義するinterfaceを実装する- 機能を取り換える仕組みをつくる
分岐をむやみに書かず、ポリシーパターンで機能の取り替えをしよう

(※差し替えたい条件やロジックが増えていく領域ほど、効果が出ます)
コレクション:for文の前に考えること
for文を書きそうになったら、標準メソッドで間に合わないか検討するcontinueやbreakを使って早期離脱させる- コレクションに関するロジックをカプセル化してまとめる
- ファーストクラスコレクション(Collectionを「ただの配列/リスト」にしない)
メソッド:やってはいけないと、やるべきこと
他クラスの内部に踏み込まない
- 他のクラスのインスタンス変数は使うな
getter/setterで他所から値を勝手に出し入れできる状態を増やさない- 詳細なロジックは関心を管理するクラスに実装する
- 尋ねるな、命じろ(Tell, Don’t Ask)
コマンド・クエリ分離(CQS)
- コマンド:状態を変える(副作用あり)
- クエリ:状態を返す(副作用なし)
- これを分けると関心が分離され、テストもしやすい
引数の設計
- 引数は不変にする
- フラグ引数を使わない
- Nullを渡さない
- 可能な限り少なくする
戻り値の設計
- プリミティブ値を返しすぎない
- 型で意図を表明する(ドメインの言葉を返す)
まとめ:変更しやすいコードは「推測が要らない」
- 名前が意図を説明し
- 変数が意味を変えず
- 分岐が増えても差し替え可能で
- データとロジックが同居し
- 副作用が見える
この状態を維持できると、設計は自然に“壊れにくい形”へ寄っていきます。

コメント