フレームワーク設計原則 - CoC, DRY, SoC
このドキュメントの目的
フレームワークが採用している設計原則を理解し、なぜそのような設計になっているかを学びます。
目次
Convention over Configuration (CoC)
「設定地獄」という問題
フレームワークを使う前に、「設定地獄」という問題を理解する。
┌─────────────────────────────────────────────────────────────┐
│ 設定地獄とは │
├─────────────────────────────────────────────────────────────┤
│ │
│ フレームワーク: 「何でもできます!柔軟です!」 │
│ │
│ 開発者: 「じゃあ使ってみよう」 │
│ │
│ フレームワーク: │
│ 「まず設定ファイルを書いてください」 │
│ 「データベースの接続先は?」 │
│ 「URLとコードの対応は?」 │
│ 「ログの出力先は?」 │
│ 「セッションの保存場所は?」 │
│ 「キャッシュの設定は?」 │
│ 「...」 │
│ │
│ 開発者: 「Hello Worldするだけなのに100行の設定...」 │
│ │
└─────────────────────────────────────────────────────────────┘
CoCの考え方
┌─────────────────────────────────────────────────────────────┐
│ CoC = Convention over Configuration │
│ (設定より規約) │
├─────────────────────────────────────────────────────────────┤
│ │
│ 基本的な考え方: │
│ │
│ 「ほとんどの人が同じ設定をするなら、 │
│ それをデフォルトにしてしまおう」 │
│ │
│ 「明示的な設定がなければ、規約(慣例)に従う」 │
│ │
└─────────────────────────────────────────────────────────────┘
日常での例え
┌─────────────────────────────────────────────────────────────┐
│ CoCを日常で例えると │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【CoCなし: 毎回全て指定】 │
│ │
│ コーヒーショップで: │
│ 店員「サイズは?」 │
│ 客 「Mで」 │
│ 店員「温度は?」 │
│ 客 「ホットで」 │
│ 店員「カップは紙?陶器?」 │
│ 客 「紙で」 │
│ 店員「砂糖は何グラム?」 │
│ 客 「普通で...」 │
│ 店員「ミルクの種類は?量は?」 │
│ 客 「もういいよ!普通のコーヒーをくれ!」 │
│ │
├────────────────────────────────────────────────────────── ───┤
│ │
│ 【CoCあり: デフォルトがある】 │
│ │
│ コーヒーショップで: │
│ 客 「コーヒーください」 │
│ 店員「はい、どうぞ」(Mサイズ、ホット、紙カップ) │
│ │
│ 客 「アイスのLサイズで」 │
│ 店員「はい、どうぞ」(変えたい部分だけ指定すればOK) │
│ │
│ 規約(デフォルト)があるから、 │
│ 変えたい部分だけ指定すればいい │
│ │
└─────────────────────────────────────────────────────────────┘
CoCの具体例
┌─────────────────────────────────────────────────────────────┐
│ フレームワークでのCoC 例 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. ディレクトリ構造の規約 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 「設定ファイルはここに置く」という規約があれば │ │
│ │ どこに何があるか迷わない │ │
│ │ │ │
│ │ src/ │ │
│ │ ├── controllers/ ← コントローラはここ │ │
│ │ ├ ── services/ ← サービスはここ │ │
│ │ ├── repositories/ ← リポジトリはここ │ │
│ │ └── config/ ← 設定はここ │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 2. 命名規約 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 「UserController は /users を担当」 │ │
│ │ 「UserRepository は users テーブルを担当」 │ │
│ │ │ │
│ │ → 名前から役割が分かる │ │
│ │ → マッピング設定が不要 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ 3. デフォルト値 │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 「ポート番号は8080」 │ │
│ │ 「タイムアウトは30秒」 │ │
│ │ 「文字コードはUTF-8」 │ │
│ │ │ │
│ │ → 大多数が使う値をデフォルトに │ │
│ │ → 変えたいときだけ設定 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
CoCのトレードオフ
┌─────────────────────────────────────────────────────────────┐
│ CoCのトレードオフ │
├─────────────────────────────────────────────────────────────┤
│ │
│ メリット: │
│ ├── 設定ファイルが減る → コードがシンプルに │
│ ├── 新しいプロジェクトをすぐ始められる │
│ ├── チーム内で構造が統一される │
│ └── 「どこに何を置くか」で迷わない │
│ │
│ デメリット: │
│ ├── 規約を知らないと「魔法」に見える │
│ ├── 規約から外れたいときに面倒 │
│ ├── 学習コストがある(規約を覚える必要) │
│ └── 暗黙的すぎてデバッグしづらい場合がある │
│ │
│ 重要: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 規約はオーバーライド可能 │ │
│ │ │ │
│ │ 「規約に従うと楽、でも強制ではない」 │ │
│ │ 「必要なときは明示的に設定できる」 │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
idp-server での実例
┌─────────────────────────────────────────────────────────────┐
│ idp-server でのCoC │
├─────────────────────────────────────────────────────────────┤
│ │
│ idp-server では「明示性」を重視し、CoCを控えめに使用 │
│ │
│ 採用しているCoC: │
│ ├── ディレクトリ構造の規約 │
│ │ └→ handler/, service/, repository/ の配置 │
│ ├── 命名規約 │
│ │ └→ XxxHandler, XxxService, XxxRepository │
│ └── 設定ファイルの場所 │
│ └→ application.yml │
│ │
│ 採用していないCoC: │
│ ├── 自動コンポーネントスキャン │
│ │ └→ 明示的にBean登録(何が登録されるか明確に) │
│ └── 暗黙的なDI │
│ └→ コンストラクタで明示的に依存を宣言 │
│ │
│ 理由: │
│ 「魔法」を減らし、コードを読めば動作が分かるようにする │
│ │
└─────────────────────────────────────────────────────────────┘
Don't Repeat Yourself (DRY)
繰り返しの問題
┌─────────────────────────────────────────────────────────────┐
│ 繰り返しの何が問題か │
├─────────────────────────────────────────────────────────────┤
│ │
│ 同じ「知識」が複数の場所にあると... │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ 場所A: 「メールは@を含み、5文字以上」 │ │
│ │ 場所B: 「メールは@を含み、5文字以上」 │ │
│ │ 場所C: 「メールは@を含み、5文字以上」 │ │
│ │ │ │
│ │ ある日、ルール変更: │ │
│ │ 「メールは@を含み、3文字以上に変更」 │ │
│ │ │ │
│ │ → 場所Aを修正 │ │
│ │ → 場所Bを修正し忘れ │ │
│ │ → 場所Cの存在を知らない │ │
│ │ │ │
│ │ 結果: システム内で矛盾が発生 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
DRYの本質
┌─ ────────────────────────────────────────────────────────────┐
│ DRYの本質 │
├─────────────────────────────────────────────────────────────┤
│ │
│ DRY = Don't Repeat Yourself │
│ │
│ "Every piece of knowledge must have a single, │
│ unambiguous, authoritative representation │
│ within a system." │
│ │
│ 「すべての知識はシステム内で唯一の、明確な、 │
│ 正式な 表現を持たなければならない」 │
│ │
│ 重要: │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ │ │
│ │ DRYは「コードの重複」だけの話ではない │ │
│ │ │ │
│ │ 「知識」「ルール」「意図」の重複を避ける │ │
│ │ │ │
│ │ ・ビジネスルール │ │
│ │ ・設定値 │ │
│ │ ・データ構造の定義 │ │
│ │ ・アルゴリズム │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
DRYの日常での例え
┌─────────────────────────────────────────────────────────────┐
│ DRYを日常で例えると │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【DRY違反: 住所を複数箇所に記載】 │
│ │
│ 会員カード: 東京都渋谷区... │
│ 配送先登録: 東京都渋谷区... │
│ 請求書送付先: 東京都渋谷区... │
│ │
│ 引っ越したら? │
│ → 3箇所とも変更が必要 │
│ → 1箇所変更し忘れると届かない │
│ │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【DRY適用: 住所は1箇所で管理】 │
│ │
│ マイページ: 住所 = 東京都渋谷区... │
│ 会員カード: → マイページの住所を参照 │
│ 配送先: → マイページの住所を参照 │
│ 請求書送付先: → マイページの住所を参照 │
│ │
│ 引っ越したら? │
│ → マイページの住所を1回変更するだけ │
│ → 全てに自動で反映 │
│ │
└─────────────────────────────────────────────────────────────┘