CTS-KB

開発手法ガイド:オブジェクト指向編 — AI に階層分離を指示するための土台

⏱ 約 10 分で読めます
#開発手法 #オブジェクト指向 #AI駆動開発 #階層分離 #SOLID

🤖 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 UserUser が 権限を持つUser.permissions
LoggingService extends ServiceService が ロガーを持つService.logger
EmailNotifier extends NotifierNotifier が 送信手段を持つNotifier.sender
PdfReport extends ReportReport が 出力形式を持つ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 円以上なら管理者承認」等)
  • インターフェース層に業務ロジックが流れ込んでいないか
  • 依存方向が一方向(下流 → 上流)になっているか

🪨 レガシーシステムとの関係

COBOLRPG は手続き型だが、 サービスプログラム(*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 駆動開発は 「業務理解 × 設計原則」の両輪 。片輪では事業成果に届かない

🔗 関連記事

📖 関連用語