← 前へ: Phase 5.7 | 目次 | 次へ: Phase 5.9 →
実行前に共通セットアップと各Phaseの確認手順を確認してください。演習コードはwork/で前のPhaseから引き継ぎます。
このフェーズでは、これまでに構築してきた各Modelの実装を見直し、共通化と抽象化(BaseModel)をTDDで導入します。
Phase 5.7までで、あなたは以下を実現しています:
- データ取得(all / find / where)
- レコードのオブジェクト化
- 永続化(save / update / destroy)
- バリデーション
しかし、現状のコードを見返すと、次のような問題があるはずです:
UserとPostで同じコードが存在する- DB接続処理が重複している
- SQL生成ロジックが分散している
- オブジェクト生成処理が各Modelにある
- バリデーションの仕組みも重複している
このフェーズでは、それらを整理し、
「共通化すべきもの」と「Model固有に残すべきもの」
を切り分けながら、BaseModelを導入します。
以下を説明できる状態になること:
- なぜBaseModelが必要になるのか
- 抽象化の適切なタイミング
- 共通化と過剰抽象化の違い
- フレームワークの内部構造の考え方
- 共通処理をBaseModelに集約できる
- 各Modelは差分だけを持つ構造になる
- Finder / Persistence / Validationが整理される
- 抽象化の判断を説明できる
- Phase 5.7(バリデーション)完了
- User / Post など複数Modelが存在する
class User < BaseModel
end
class Post < BaseModel
end- 共通処理は BaseModel に集約
- 各Modelは最小の記述
まずは現状を観察します。
allfindwheresavedestroy- バリデーション
どの処理が共通かを書き出してください。
UserとPostが同じ仕組みで動く- 共通のロジックで処理される
👉 RED
- 共通クラスを作る
- Modelを継承構造にする
- 継承(inheritance)
- 共通メソッドの移動
- all
- find
- where
- どこまで共通化できるか?
- 何がModelごとの差分か?
共通化すると問題が出ます:
- Modelごとにテーブルが違う
- Modelごとに正しいテーブルを参照する
👉 RED
- Modelごとにテーブル名を扱う仕組みを作る
- クラス名から推測する
- 明示的に指定する
- save
- insert
- update
- destroy
- ほぼ共通処理ではないか?
- バリデーションの仕組みをBaseModelへ移す
- Modelごとの差分は何か?
- DB → オブジェクト変換が重複している
- 共通メソッド化
- 各Modelが同じAPIを持つ
User.all
Post.all👉 RED
- BaseModelは何をするクラスか?
- Modelは何を持つべきか?
- すべてを共通化しない
- 読みにくくしない
- なぜここまで共通化したか
- なぜこれ以上やらないのか
- 抽象化の判断基準
- attr_accessorを自動化したくなる
- define_method など
※ 必須ではない
class User < BaseModel
validates :name, presence: true
end- 複数Modelで同じAPIが使える
- 共通処理が機能している
- BaseModel
- 各Model
以下を説明:
- なぜBaseModelが必要になったか
- 何を共通化したか
- 何を残したか
- 抽象化の判断基準
- TDDが守られているか
- 共通化が適切か
- 可読性が保たれているか
- 過剰設計でないか
- 説明できるか
→ 可読性崩壊
→ 理解が浅くなる
→ 責務崩壊
→ ドメインが消える
このフェーズで得るべき理解は:
抽象化とは「共通化すること」ではなく、 「変化に強い構造を作ること」である
ここまでであなたは:
- フレームワーク
- ORM
- MVC
を自力で構築しました。
最後にやるべきこと:
👉 Phase 5.9: ORMの限界とActiveRecordの理解