🤖 AI 駆動開発でオブジェクト指向が必要な理由
AI コーディングツールは 「動くコード」を高速に書く のが得意だが、 「責務がどこに置かれるべきか」 の判断は苦手。ユーザーが「ドメイン層を追加して」と指示できるかどうかが、そのまま生成コードの保守性を決める。
オブジェクト指向の理解は、 AI 駆動開発における次の 3 つの判断を支える。
| AI 駆動開発での判断 | オブジェクト指向の知識 |
|---|---|
| 「この処理をどこに書くか」を指示できる | 責務・階層分離の考え方 |
| AI 生成コードが「肥大化している」と見抜ける | カプセル化の侵食・God Class 検知 |
| 「変更に強い」コードかを即座に判断できる | ポリモーフィズムによる拡張点の存在 |
本記事は開発手法ガイド:概要のシリーズ 2 本目。すべての設計原則の土台となるオブジェクト指向を、AI 駆動開発の文脈で整理します。
📐 オブジェクト指向の本質は「責務」
Alan Kay の元々の意図
Alan Kay が Smalltalk で体系化したオブジェクト指向の核は、 「オブジェクト同士がメッセージを送り合う」 というモデル。クラス・継承・カプセル化は手段であって、目的ではない。
手続き型が「処理の手順」を中心に書くのに対し、オブジェクト指向は 「誰が何の責務を持つか」 を中心に書く。AI 駆動開発においては、この「誰が」をユビキタス言語で明確にしておくことが、指示の精度を上げる第一歩になる。
3 つの基本概念
| 概念 | 説明 | AI 駆動開発での意味 |
|---|---|---|
| カプセル化 | データと操作を 1 つにまとめ、内部状態を隠蔽する | AI が private 状態を直接触る提案を出したら要警戒 |
| 継承 | 既存クラスの責務を引き継ぎつつ拡張する | AI は継承を過剰に使う傾向。has-a の関係(部品として持たせる)への置き換えを指示 |
| ポリモーフィズム | 同じインターフェースで異なる実装を切り替える | 拡張点の有無が AI への「機能追加」指示の可否を決める |
現代的には「継承より合成」 — is-a より has-a で考える
「合成(Composition)」という言葉は分かりにくいので、まず オブジェクト同士の関係には 2 種類ある ことを押さえます。
| 関係 | 読み方 | 意味 | 例 | 実装手段 |
|---|---|---|---|---|
| is-a | 〜である | A は B の一種 | 犬は動物である | 継承(extends) |
| has-a | 〜を持つ | A は B を部品として持つ | 車はエンジンを持つ | 合成(フィールドとして保持) |
「合成」とは要するに 「他のクラスを部品として持つこと」 。Car クラスの中に new Engine() を持たせる、というだけのイメージです。
has-a なのに継承で書いてしまう典型例
「Square extends Rectangle」のような継承の失敗例(LSP 違反)は古典ですが、AI が生成するコードでは 「少し似ているから継承しておこう」 というパターンが頻出します。本当は has-a の関係なのに継承で書いている例:
| 継承で書きたくなる(is-a に見える) | 実は has-a なので部品として持つ |
|---|---|
AdminUser extends User | User が 権限を持つ → User.permissions |
LoggingService extends Service | Service が ロガーを持つ → Service.logger |
EmailNotifier extends Notifier | Notifier が 送信手段を持つ → Notifier.sender |
PdfReport extends Report | Report が 出力形式を持つ → Report.exporter |
書き換え例
継承で書いた場合(is-a のつもり):
class AdminUser extends User { ... }
合成で書き直す場合(has-a として):
class User {
constructor(private permissions: Permissions) {}
}
// 管理者は AdminPermissions を持った User
const admin = new User(new AdminPermissions());
// 一般ユーザは GeneralPermissions を持った User
const general = new User(new GeneralPermissions());
判断基準: 「これは is-a か、has-a か?」を毎回問う。 has-a なら継承ではなく部品として持つ 形に書き直す。
AI への指示では「継承ではなく has-a の関係で(部品として持たせて) 」と明示すると、AI が無闇に継承ツリーを深くするのを防げます。
🏢 業務要件の理解なしにオブジェクト指向は設計できない
オブジェクト指向の責務をどう切るかは、 業務の理解度 で決まります。AI に「ドメイン層を作って」と指示しても、開発者自身が業務を理解していないと AI も推測で埋めるしかありません。 ビジネスケイパビリティ — 「組織は何ができるのか」 — を粒度別に把握することが、責務分離の出発点です。
業務フローをそのままコードにすると破綻する
現場の業務フローは、紙・口頭・属人運用といった制約の上で組まれています。これを そのままコード化すると確実に破綻 します。
| ありがちな失敗 | なぜ破綻するか |
|---|---|
| 紙の承認フローを画面で再現 | クリック数増・入力ミス頻発・属人運用が固定化 |
| Excel の手作業を画面に引き写す | 業務改善の機会を逃す。「Excel + α」止まりの SaaS に |
| 既存の組織縦割りに合わせてシステム分割 | 組織変更のたびにシステム改修が走る |
| 例外運用をすべて分岐で吸収 | if 文が指数関数的に増殖 → AI が触れないコードに |
業務フローはあくまで 「現状の制約下で組まれた最適解」 であり、システム化前提なら別の最適解があります。
ベストプラクティスは「業務改善 + システム導入」をセットで進める
業務フローを見直してからシステム化することで、はじめて AI 駆動開発のスピードが事業成果(コスパ・タイパ)に転換します。
× 業務フロー → そのままコード化
(現場の制約をシステムが永久固定化)
○ 業務フロー → 改善 → システム整合性を取る → 業務改善
(コスパ・タイパ向上)
業務フローとシステムの整合点に昇華させるための問い:
| 視点 | 問い |
|---|---|
| 廃止可能か | 「このステップは必要か?やめたら何が起きるか?」 |
| 自動化可能か | 「人が判断する必要があるか?ルールで決まらないか?」 |
| 統合可能か | 「複数のステップを 1 操作にまとめられないか?」 |
| 並列化可能か | 「順次でなく並列に進められないか?」 |
| 例外を例外のまま扱うか | 「例外パスを業務側で吸収できないか?」 |
これらの問いを業務担当者と一緒に回せるエンジニアが、AI 駆動開発で成果を出せる人材です。
ドメインロジックは業務理解の結晶
設計においても、業務理解が薄いと ドメインロジックがインフラ層・UI 層に流出 します。これは AI 生成コードで特に発生しやすい劣化パターン。
業務理解が薄い設計:
Controller → 業務ルールが画面に書かれる(「金額が 5,000 円以上ならボタン非表示」)
Repository → 業務ルールが SQL に書かれる(「WHERE で承認済みのみ取得」)
ドメイン層 → 単なるデータバッグ(アネミックドメインモデル)
業務理解が厚い設計:
Controller → 入力受付・整形のみ
Repository → 永続化のみ
ドメイン層 → 業務ルールがすべてここに集まる
(Order.canApply()、Stock.reserve() 等)
業務担当者と一緒に 「これは業務ルールか/入力ルールか/表示ルールか」 を分類するのが、ドメイン層の責務を正しく切る出発点です。AI に「Order クラスにキャンセルメソッドを追加して」と指示できるのは、業務側で「キャンセル」の定義(タイミング・条件・副作用)を握っている開発者だけです。
AI 駆動開発は「業務理解 × 設計原則」の両輪
業務理解だけ厚くても、設計原則を知らないと AI 生成コードが構造的に腐敗します。逆に設計原則だけ知っていても、業務理解が薄いと「美しいけど業務に合わない」コードができます。
| 状態 | 結果 |
|---|---|
| 業務理解 ◯ × 設計原則 × | 動くが構造が腐る。リファクタ不能に |
| 業務理解 × × 設計原則 ◯ | 美しいが業務に合わない。作り直しが頻発 |
| 業務理解 ◯ × 設計原則 ◯ | AI 駆動開発が事業成果に転換する |
両輪のスキルセットを段階的に養うには、 ビジネスケイパビリティ の理解と、 DDD のユビキタス言語が出発点になります。
🧱 なぜ階層分離が必要なのか
オブジェクト指向の真価は「クラスの数」ではなく 責務の分離 。ドメインロジック・アプリケーション制御・インフラアクセス・UI を別レイヤーに配置することで、変更理由ごとにコードが孤立し、AI 生成コードの修正範囲も予測可能になる。
標準的な 4 層
| レイヤー | 責務 | 変更頻度 | AI 駆動開発での意味 |
|---|---|---|---|
| ドメイン層 | ビジネスルール | 低(仕様変更時のみ) | 業務要件の指示はここに届く |
| アプリケーション層 | ユースケース調整 | 中 | 「処理の流れ」の指示はここ |
| インフラストラクチャー層 | DB・外部 API | 高(基盤交換時) | 技術交換の指示はここに閉じる |
| インターフェース層 | UI・REST 入口 | 高 | UI 変更の指示はここに閉じる |
依存方向のルール
階層分離の肝は 依存方向が一方向 であること。
インターフェース層 ──→ アプリケーション層 ──→ ドメイン層
↑ ↑
└── インフラストラクチャー層 ────────────┘
インフラ層はドメイン層が定義したインターフェース(例: IOrderRepository)を実装する。ドメイン層がインフラ層を知ることはない。この向きを守る限り、DB 交換も AI 生成コードでも影響範囲が閉じる。
詳細は ヘキサゴナルアーキテクチャ ・ クリーンアーキテクチャ で整理されている。
🎯 AI への指示に階層分離を組み込む
指示テンプレート
層: {ドメイン / アプリケーション / インフラ / インターフェース}
対象: {クラス名 or 追加する責務}
禁止事項: {依存してはいけない層}
テスト方針: {どの層でユニットテストを書くか}
例:
層: アプリケーション層
対象: PlaceOrderUseCase に在庫チェックを追加
禁止事項: EF Core / HTTP クライアントを直接呼ばない。
ドメイン層の IInventoryRepository を経由する。
テスト方針: IInventoryRepository をモックしてユースケースを単体テスト
依存してはいけない層を明示することで、AI が「動くから良いや」と一段飛ばしで書く危険を減らせる。
レビュー観点
AI が生成したコードが階層分離の観点で健全かを確認するチェックリスト:
- ドメイン層のクラスに
using EntityFramework/import expressが混入していないか - アプリケーション層が SQL を直接組み立てていないか
- インフラ層がビジネスルールを持っていないか(「DB 保存前に 5,000 円以上なら管理者承認」等)
- インターフェース層に業務ロジックが流れ込んでいないか
- 依存方向が一方向(下流 → 上流)になっているか
🪨 レガシーシステムとの関係
COBOL や RPG は手続き型だが、 サービスプログラム(*SRVPGM) や コピーブック で「責務の単位」を切り出す運用 は、オブジェクト指向の発想を先取りしている。
モダナイゼーション時には、この単位がそのままクラス・サービスの境界候補になる。 手続き型の資産を、責務分離という視点で読み直す ことが、AI に段階的移行を指示するための前提。
⚠️ AI 生成コードに現れやすい失敗パターン
1. God Class / God Service
AI は「動くこと」を優先するため、関連するロジックを 1 クラスに詰め込みがち。OrderService が在庫引当・決済・通知・ログ出力を全部抱える状態になりやすい。
是正: レビュー時に「このクラスが変更される理由は何個あるか」を問う。2 個以上なら分割を指示。
2. カプセル化の侵食
AI が「楽に動かすため」に、private プロパティへ直接アクセスする getter/setter を機械的に生やす。結果、エンティティが単なるデータバッグ(アネミックドメインモデル)になる。
是正: order.setStatus(SHIPPED) ではなく order.ship() のように、業務上の操作を表すメソッドを求める。
3. 継承の過剰使用
「似ているから継承しよう」で継承ツリーが深くなる。Liskov 置換原則(LSP)違反が生まれやすい。
是正: 「これは is-a 関係か、has-a 関係か」を問い、has-a なら合成に書き換えを指示。
4. 階層を飛ばすショートカット
インターフェース層のコントローラから直接 DB を触る。「早いから」という理由で AI が出しやすい。
是正: 「アプリケーション層のユースケースを必ず経由して」と明示的に指示。
📚 まとめ
- オブジェクト指向の本質は 責務の分離 。クラス・継承・カプセル化は手段
- 責務をどう切るかは 業務理解度で決まる 。 ビジネスケイパビリティ を粒度別に把握することが出発点
- 業務フローをそのままコード化すると破綻 する。業務改善 + システム導入をセットで進めると、AI 駆動開発のスピードが事業成果(コスパ・タイパ)に転換する
- ドメインロジックは 業務理解の結晶 。業務理解が薄いと Controller / Repository に流出し、ドメイン層がアネミックになる
- 階層分離(ドメイン / アプリケーション / インフラ / インターフェース)を理解していると、 AI への指示が具体的になり、生成コードの影響範囲が予測できる
- 継承(is-a)より合成(has-a)、getter/setter より業務メソッド、 God Class より責務分割 — AI 生成コードのレビュー観点として常備する
- 依存方向は 一方向(下流 → 上流) 。ドメイン層はインフラ層を知らない
- レガシーシステムの資産も、責務分離の視点で読み直せば AI 駆動のモダナイゼーション対象になる
- AI 駆動開発は 「業務理解 × 設計原則」の両輪 。片輪では事業成果に届かない
🔗 関連記事
- 開発手法ガイド:概要 — シリーズ全体の位置づけ
- 開発手法ガイド:SOLID 原則編 — オブジェクト指向設計を保守可能に保つ 5 原則
- 開発手法ガイド:DDD 編 — オブジェクト指向を業務ドメインに適用する
- COBOL × DDD 設計パターン — 手続き型言語に責務分離を適用する例
📖 関連用語
- オブジェクト指向 — 基本概念の要約
- ビジネスケイパビリティ — 責務分離の出発点となる業務能力単位
- SOLID 原則 — オブジェクト指向設計の 5 つの基本原則
- DDD — オブジェクト指向を業務ドメインに適用した設計手法
- リポジトリパターン — 永続化詳細から切り離す責務分離パターン
- ヘキサゴナルアーキテクチャ — 階層分離をアーキテクチャ全体に適用した形
- クリーンアーキテクチャ — 依存方向ルールを明文化した整理
- SoC(関心の分離) — 階層分離の上位原則