はじめに
本記事では、VBA/VB6のOracle接続方式をOO4O(Oracle Objects for OLE)からOLEDB(ADODBプロバイダー)に変換するプロジェクトについて紹介します。Claude CodeとMCP(Model Context Protocol)を活用し、1か月で41件のプロジェクト変換を実現しました。
通常であれば7人月以上かかる約6,800行の改修を、わずか0.75人月で完了。IPA基準比で約90%の工数削減、生産性は約19倍を達成しました。
第1章:背景と課題
OO4O(Oracle Objects for OLE)とは
OO4Oは、VBAやVB6からOracleデータベースに接続するためのCOMコンポーネントです。1990年代後半から2000年代にかけて、Excel VBAやVB6アプリケーションでOracle接続を行う際の標準的な手法として広く使われてきました。
' OO4Oによる接続例
Dim OraSession As OraSession
Dim OraDatabase As OraDatabase
Set OraSession = CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase = OraSession.OpenDatabase("ORCL", "user/pass", 0)
OO4Oサポート終了の影響
Oracleは既にOO4Oのサポートを終了しており、新しいOracle Clientには同梱されなくなっています。これにより、以下の問題が発生します:
- 新しい環境でOO4Oを使用したアプリケーションが動作しない
- セキュリティパッチが提供されない
- 64bit環境での制約
手作業での変換が現実的でない理由
今回の対応では、OO4Oを使用したExcel VBAツールが多数存在していました。これらを手作業で変換しようとすると:
| 課題 | 詳細 |
|---|---|
| コード量 | 1ファイルあたり数百〜数千行、全体で数万行 |
| 変換パターンの複雑さ | DB接続、RecordSet、トランザクション、ストアドプロシージャ等、多岐にわたる |
| 型変換の罠 | OO4OとADODBでNUMBER型の返却値が異なる(後述) |
これを人手で行うのは現実的ではありませんでした。
第2章:プロジェクトの大前提 ― すべてバイブコーディング
変換システム自体もAIに作らせた
本プロジェクトの最大の特徴は、変換システム自体をAIに作らせたことです。いわゆる「バイブコーディング」で、以下のすべてをClaude Codeに生成させました:
| 成果物 | 説明 |
|---|---|
| MCPサーバー(excel-pywin32) | Excel VBAファイルの読み書き、参照設定変更 |
| MCPサーバー(oracle-metadata) | Oracleのテーブル/プロシージャ定義検索 |
| エージェント定義ファイル(CLAUDE.md) | フェーズ管理、変換ルールの定義 |
| サブエージェントファイル | oracle-analyze, oracle-convert, oracle-comment等 |
| チェックロジック | 各フェーズの品質検証 |
| レポートテンプレート | 分析結果、変換結果のレポート形式 |
| 自動テストコード | MCPツールの動作確認テスト |
人間がやったこと
人間の役割は限定的でした:
最初の変換指示を出す
- 「このExcelファイルのOO4OをOLEDBに変換して」
各工程の成果物をチェック・承認する
- WinMergeで3点比較:変更前 / 変更後 / インポート後再エクスポート
- 意図しない変更がないか確認
入れ子構造
バイブコーディングで「開発ツールを開発する」という入れ子構造が生まれました:
人間 → 要件を言語化 ↓ AI → MCPサーバーを生成 AI → エージェント定義を生成 AI → テストコードを生成・実行 ↓ AI → 生成したツールを使って変換を実行 ↓ 人間 → 成果物をレビュー・承認
AIが作ったツールをAIがテストし、AIが使う。人間は指示と承認のみ。
第3章:解決アプローチ
Claude Code + MCPという選択
変換システムの実装にあたり、Claude CodeとMCP(Model Context Protocol)の組み合わせを選択しました。
Claude Codeを選んだ理由:
- 自然言語での指示が可能
- コードの文脈理解力が高い
- 複雑な変換パターンを柔軟に処理できる
MCPを選んだ理由(当時の判断):
- Claude Codeから外部ツールを呼び出す標準的な方法
- Excel操作やDB定義検索を独立したサーバーとして実装可能
- ツールの再利用性
従来のコンバートプログラムとAI活用の違い
この手の変換作業では、正規表現ベースのコンバートプログラムを自作するアプローチがよく取られます。しかし、ルールベースの変換には限界があります。
従来のコンバートプログラムの課題:
- 事前に想定したパターンしか変換できない
- 変換もチェックも同じルールベースなので、ルールから漏れたものは検出できない
- 新しいパターンに遭遇するたびにルールを追加する必要がある
AI活用のメリット:
- 文脈を理解して柔軟に変換できる(コメント内か実コードかの判断など)
- 事前に想定していないパターンにも、それなりに対応できる
- 変数のスコープや使われ方を見て、適切な変換を判断できる
本システムでは、このAIのファジーさを活かしつつ、チェックフェーズではMCPツールによる厳格なルールベース検証を行います。
| フェーズ | 実行主体 | アプローチ |
|---|---|---|
| 変換 | AI | ファジー:文脈を理解して柔軟に変換 |
| チェック | MCPツール | 厳格:ルールベースで網羅的に検出 |
AIが見落としてもチェックツールが拾い、チェックルールにないパターンでもAIが対応する。この相互補完により、変換漏れのリスクを低減しています。
注意点:ファジーさゆえのデメリット
AIにファジーな変換を依頼しているため、コードの完全再現性がないというデメリットがあります。例えば、同じソースがコピペされた複数のExcelを変換した場合、Excelごとに異なる変数名が付けられることがあります。構造的には問題がないため、チェックには引っかかりません。
本アプローチは、このような差異が許容されることが前提です。変換後のコードが完全に同一であることを求める場合は、従来のルールベース変換の方が適しています。
半自動化という設計思想
完全自動化ではなく、半自動化を採用しました:
- 分析結果はユーザーが確認・承認してから変換に進む
- 変換結果もユーザーが確認・承認してからインポート
- 各工程でチェックフェーズを設け、問題があれば再実行
これにより、AIの暴走を防ぎつつ、人間の負担を最小化しています。
第4章:システムアーキテクチャ
全体構成

システムは3層構造になっています:
Claude Code(最上位)
- CLAUDE.md(フェーズ管理ファイル)を読み込み、全体を制御
10個のサブエージェント
- analyze, convert, comment, import, report(各作業フェーズ)
- 各フェーズに対応するcheckエージェント
MCPサーバー群
5フェーズ × チェックの品質管理モデル

| フェーズ | 処理内容 | 出力 |
|---|---|---|
| 分析(analyze) | OO4O使用箇所の特定、変換計画作成 | diff/0.before/, 分析結果レポート.md |
| 変換(convert) | 変換計画に従ってコード変換 | diff/1.pre-after/ |
| コメント(comment) | OCI対応コメントの付与 | diff/2.after/ |
| インポート(import) | Excelへのインポート、参照設定変更 | excel/1.after/ |
| レポート(report) | 変換結果レポート、動作確認一覧作成 | 変換結果レポート.md, 動作確認一覧.xlsx |
各フェーズの後にはチェックフェーズがあり、Failの場合は作業フェーズを再実行します。
MCPサーバーの役割
excel-pywin32サーバー:
project_export_full → VBAモジュールをエクスポート project_import_converted → 変換後モジュールをインポート vba_file_read → VBAファイル読み込み(Shift-JIS対応) vba_file_edit → パターン置換 vba_add_oci_comments → OCI対応コメント自動付与 vba_add_reference → 参照設定追加(ADODB等) vba_remove_reference → 参照設定削除(OO4O等)
oracle-metadataサーバー:
search_procedure_params → ストアドプロシージャのパラメータ検索 search_table_columns → テーブルのカラム定義検索
第5章:変換パターンの技術詳細
DB接続・切断の変換
' 変換前(OO4O)
Dim OraSession As OraSession
Dim OraDatabase As OraDatabase
Set OraSession = CreateObject("OracleInProcServer.XOraSession")
Set OraDatabase = OraSession.OpenDatabase("ORCL", "user/pass", 0)
' 変換後(OLEDB)
Dim OraConnection As ADODB.Connection
Set OraConnection = New ADODB.Connection
OraConnection.Open "Provider=OraOLEDB.Oracle;" & _
"Data Source=ORCL;" & _
"User ID=user;Password=pass"
OO4OではOraSessionとOraDatabaseの2オブジェクトが必要でしたが、OLEDBではADODB.Connection1つに統合されます。
Recordset(CreateDynaset → Rs.Open)
' 変換前(OO4O) Dim Rs As OraDynaset Set Rs = OraDatabase.CreateDynaset(strSql, 0) ' 変換後(OLEDB) Dim Rs As ADODB.Recordset Set Rs = New ADODB.Recordset Rs.Open strSql, OraConnection, adOpenStatic, adLockReadOnly
トランザクション処理
' 変換前(OO4O) OraSession.BeginTrans OraSession.CommitTrans OraSession.Rollback ' 変換後(OLEDB) OraConnection.BeginTrans OraConnection.CommitTrans OraConnection.RollbackTrans ' 注:Rollback → RollbackTrans
ストアドプロシージャ
OO4OとOLEDBのパラメータ指定方式の違い
OO4OとOLEDBでは、ストアドプロシージャのパラメータ指定方式に重要な違いがあります。
| 方式 | OO4O | OLEDB/ADODB |
|---|---|---|
| パラメータ指定 | 名前指定が可能 | 位置指定のみ |
| パラメータ順序 | 順不同でOK | 定義順に厳密に合わせる必要あり |
OO4Oでは :パラメータ名 で名前を指定できましたが、ADODBのOLE DBプロバイダーでは、パラメータは位置(ordinal)で識別されます。つまり、Parameters.Append する順序がストアドプロシージャの定義順と完全に一致している必要があります。
参考: ADO Command object ignores parameter names when invoking stored procedure - ADOのドキュメントでは、パラメータの "name" プロパティはVBプログラム内でパラメータを識別するためだけのものであり、ストアドプロシージャのパラメータとは位置(ordinal)でのみ対応すると記載されています。
参考: Microsoft Learn - Using Parameters (OLE DB)) - OLE DBではパラメータは名前付きでも無名でも、常にordinalで識別されます。
この違いにより、変換時にはoracle-metadataサーバーを使ってパラメータの定義順序を正確に取得し、その順序通りにパラメータを追加する必要がありました。
変換例
' 変換前(OO4O)- 名前指定でパラメータを追加
OraDatabase.Parameters.Add "p_name", "", 2 ' 2番目のパラメータを先に追加してもOK
OraDatabase.Parameters.Add "p_id", 100, 1 ' 1番目のパラメータを後から追加
OraDatabase.ExecuteSQL "BEGIN pkg.proc(:p_id, :p_name); END;"
result = OraDatabase.Parameters("p_name").Value
' 変換後(OLEDB)- 定義順にパラメータを追加(順序が重要!)
Dim Cmd As ADODB.Command
Set Cmd = New ADODB.Command
Cmd.ActiveConnection = OraConnection
Cmd.CommandText = "pkg.proc"
Cmd.CommandType = adCmdStoredProc
Cmd.Parameters.Append Cmd.CreateParameter("p_id", adInteger, adParamInput, , 100) ' 1番目
Cmd.Parameters.Append Cmd.CreateParameter("p_name", adVarChar, adParamOutput, 100) ' 2番目
Cmd.Execute
result = Cmd.Parameters("p_name").Value
型変換の落とし穴(NUMBER型のDecimal/String問題)
これが最も厄介な問題でした。OO4OとADODBでは、Oracle NUMBER型の値取得時に返却されるVBAのデータ型が異なります。
| 技術 | NUMBER型の返却 |
|---|---|
| OO4O | 精度16桁以上 or 精度未指定 → String |
| ADODB | すべて → Decimal |
この違いにより、既存コードが暗黙的にString型を期待している場合、変換後に実行時エラーが発生します。
対策: convertType() 関数を全Recordsetフィールドアクセスに適用し、OO4Oと同じ挙動を再現するモジュールを追加しました。
第6章:工夫したポイント
AIモデルの使い分けとエージェント分離
当初の問題
当初は、1つのCLAUDE.mdファイルにすべてのプロセス(分析→変換→コメント付与→インポート→レポート)を記述していました。しかし、以下の問題が頻発しました:
- 作業の一部を漏らす: 長い指示の中で特定のステップをスキップしてしまう
- ユーザー確認をせずに勝手に進める: 確認ポイントを無視して次のフェーズに突入
- 指示の解釈ブレ: 同じ指示でも実行のたびに異なる挙動
原因の推測
- コンテキストの肥大化: 1つのファイルに全情報を詰め込むと、AIが重要な指示を見落としやすくなる
- 責任範囲の曖昧さ: 「何をどこまでやるか」が不明確だと、AIが勝手に判断してしまう
- チェックポイントの欠如: 途中で品質確認する仕組みがないと、エラーが連鎖する
対策:メインエージェント + サブエージェント構成
この問題への対策として、以下の設計に変更しました:
| 層 | 役割 | 内容 |
|---|---|---|
| メインエージェント(CLAUDE.md) | フェーズ管理のみ | 次にどのサブエージェントを呼ぶか判断、ユーザー確認ポイントの制御 |
| サブエージェント(oracle-*.md) | 作業の実行 | 1つのフェーズに集中、明確な入力/出力定義 |
| チェックエージェント(*-check.md) | 品質ゲート | 作業結果の検証、Pass/Fail判定 |
モデルの使い分け
処理の特性に応じてAIモデルも使い分けています:
| フェーズ | モデル | 理由 |
|---|---|---|
| analyze, report, check系 | デフォルト(高精度) | 分析・判断の精度が重要 |
| convert, comment, import | sonnet(高速) | 定型処理が多く、速度優先 |
チェックフェーズによる品質ゲート
各作業フェーズの後にチェックフェーズを設け、以下を自動検証します:
- OO4Oコードの残存チェック
- 改行コードの異常(CRLF以外の混入)
- 構文エラーの検出
- インポート前後の差分確認
Failの場合は問題箇所を特定し、作業フェーズを再実行します。
3段階のdiff比較による品質担保
成果物は3段階で保存され、WinMergeで比較確認できます:
diff/0.before/ ← 変換前のオリジナル diff/2.after/ ← 変換・コメント付与後 diff/3.exported_for_check/ ← Excelにインポート後、再エクスポートした結果
インポート→再エクスポートで差異が出れば、インポート処理に問題があることがわかります。
DBメタデータ活用
ストアドプロシージャの変換では、oracle-metadataサーバーを使ってパラメータの型情報と定義順序を取得します。これにより、手動でDB定義を調べる必要がなくなり、パラメータ順序の誤りも防げるようになりました。
第7章:苦労話 ― AIは思い通りに動かない
バイブコーディングは万能ではありません。実際に遭遇した問題を紹介します。
例1:MCPツール接続失敗時の暴走
現象: MCPサーバーに接続できない場合、AIは「問題を解決しよう」として、勝手に代替スクリプトを生成し始めました。
# AIが勝手に生成したスクリプト with open(vba_file, 'r', encoding='utf-8') as f: # ← UTF-8で読もうとする content = f.read()
結果: VBAファイルはShift-JIS(CP932)でエンコードされているため、UTF-8で読み込んで書き戻すと文字化けが発生。日本語コメントや文字列リテラルが破壊されました。
対応: CLAUDE.mdに「MCPツールが使えない場合は処理を中断し、ユーザーに報告すること」と明記しましたが、どんなに指示を加筆してもAIが暴走することはたまにありました。
結局、CLI上で作業フェーズを常に監視し、AIが想定外の行動(独自スクリプトの生成等)を始めたらEscキーで即座に中断してやり直しさせる運用で対処しています。完全な解決には至っていません。
例2:並行セッションによるソース破壊
現象: 作業効率を上げるため、複数のClaude Codeセッションで並行作業させていました。
結果: 同一ファイルを複数セッションが同時に編集し、あるセッションの変換済みコードを別のセッションが上書き・破壊。変換作業が無駄になりました。
対応: AIには排他制御の概念がありません。以下の運用ルールで対処しました:
- プロジェクト範囲を明示する: 本来の作業フェーズと異なる指示を出す場合も「〇〇プロジェクトの範囲で」を枕詞として必ず付ける
- バックアップ指示の明示: ケースによっては「バックアップを取ってから作業すること」と明確に指示
- 並行作業は完全分離: 同時に作業させる場合はプロジェクト単位で完全に分離
例3:指示無視と過剰な「改善」
現象: 変換作業を指示したにもかかわらず、AIが「ついでに」コードの改善を行いました:
- 未使用変数の削除
- インデントの修正
- 変数名のリネーム
結果: OO4O→OLEDB変換とは無関係な変更が混入し、動作確認時に「何が変わったのか」の切り分けが困難に。最悪の場合、意図しない動作変更が発生しました。
対応: 禁止事項を明文化し、繰り返し指示する必要があります。CLAUDE.mdに以下を追記:
## 禁止事項 - OO4O変換と関係ない変更を行うこと - 未使用変数の削除、リファクタリング等の「改善」 - コメントの追加・削除(OCI対応コメント以外)
第8章:実績と効果
変換実績
1か月の作業期間で、41件のプロジェクト変換を完了しました。作業者は1名(約0.75人月稼働)、総修正規模は約6,800ステップです。
IPA基準との比較
IPA(独立行政法人 情報処理推進機構)の「ソフトウェア開発分析データ集2022」に基づき、生産性を比較しました。
IPA基準値
IPAが公開している改良開発の生産性基準値は以下の通りです:
| 生産性(中央値) | 人月換算(160人時) | |
|---|---|---|
| 改良開発 | 3.01 SLOC/人時 | 約482 SLOC/人月 |
工程範囲
今回の作業範囲は、実装とコンパイルの確認までを実施しました。変換結果のテストはサンプリングで動作確認を行い、各Excelファイルごとの単体テストや結合テスト以降は実施していません。
IPA基準の開発工程に当てはめると、基本設計・詳細設計・製造(実装)の52%に該当します。
| 基本設計 | 詳細設計 | 製造(実装) | 製造(単体) | 結合テスト | 総合テスト | 合計 | |
|---|---|---|---|---|---|---|---|
| IPA基準 | 18% | 18% | 16% | 15% | 20% | 13% | 100% |
| 本PJ | ✓ | ✓ | ✓ | - | - | - | 52% |
IPA基準での工数試算
| 計算式 | 値 | |
|---|---|---|
| 総ステップ数 | - | 約6,800行 |
| IPA基準工数(全工程) | 6,800 ÷ 482 SLOC/人月 | 約14人月 |
| IPA基準工数(実施工程52%) | 14 × 52% | 約7人月 |
実績との比較
| IPA基準 | 実績 | 比較 | |
|---|---|---|---|
| 工数(実施工程) | 約7人月 | 0.75人月 | 約90%削減 |
| 生産性 | 482 SLOC/人月 | 約9,100 SLOC/人月 | 約19倍 |
AI支援(Claude Code + サブエージェント)により、IPA基準比で約90%の工数削減を実現しました。
第9章:振り返り ― MCPである必要はあったのか?
結論:MCPでなくてもよかった
正直に言うと、MCPは過剰だったかもしれません。
代替案1:単純なPythonスクリプト
excel-pywin32サーバーの機能は、単純なPythonスクリプトでも実現可能でした:
# これでも十分だった def export_vba_modules(excel_path, output_dir): xl = win32com.client.Dispatch("Excel.Application") wb = xl.Workbooks.Open(excel_path) for component in wb.VBProject.VBComponents: component.Export(f"{output_dir}/{component.Name}.bas") wb.Close() xl.Quit()
Claude Codeはbashやpythonスクリプトを直接実行できるので、MCPサーバーという形式にする必要はありませんでした。
代替案2:Claude Skills(カスタムスキル)
Claude Codeには「Skills」という機能があり、よく使う処理をスキルとして定義できます。MCPサーバーを立てるよりシンプルです。
MCPを選んだ理由(当時の判断)
- MCPが新しい技術で試してみたかった
- 「サーバー」という形式にすることで再利用性が高まると考えた
- 複数のClaude Codeセッションから共有できると思った
MCPを使ったことで被った問題
実際に運用してみると、MCPサーバーへの接続が頻繁に切れるという問題が発生しました。
- 作業中に突然MCPツールが使えなくなる
/mcpコマンドで再接続を試みる必要がある- 再接続しても不安定な場合があり、Claude Codeの再起動が必要になることも
原因は完全には特定できていませんが、以下が考えられます: - MCPサーバープロセスのタイムアウト - Windowsの環境依存の問題 - 長時間稼働による接続の不安定化
この問題により作業が中断されることが多く、シンプルなスクリプト実行の方が安定していた可能性があります。
今振り返っての評価
| 観点 | 評価 |
|---|---|
| 学習コスト | MCPサーバーの実装・デバッグに時間がかかった |
| 安定性 | サーバー接続問題で作業中断が頻発 |
| 再利用性 | 結局このプロジェクト専用になった |
| 代替手段 | スクリプトやSkillsで十分だった |
MCPが活きるケース vs 過剰なケース
MCPが活きるケース:
- 複数のAIツール(Claude, GPT等)から共通して使いたい
- 長時間稼働するサービスとして提供したい
- 複雑な状態管理が必要
過剰なケース(今回のような):
- 単一のClaude Codeセッションで完結する
- バッチ的な処理で、常駐サーバーは不要
- プロジェクト固有の処理で再利用予定がない
第10章:今後の展望・まとめ
他のレガシーコード変換への応用可能性
今回のアプローチは、他のレガシーコード変換にも応用できます:
フェーズ管理とチェック機構の考え方は汎用的に使えます。
バイブコーディングで学んだこと
AIは万能ではない
- 思い通りに動かないことが多い
- 禁止事項の明文化と繰り返しの指示が必要
- 暴走したらEscで止めてやり直し
人間の役割は「指示と承認」
シンプルな選択が正解のこともある
- 新しい技術(MCP)に飛びつく前に、既存の手段で十分か検討すべき
- 安定性 > 新しさ
まとめ
1か月で41件のOO4O→OLEDB変換を、Claude Code + MCPで実現しました。
- バイブコーディングで変換システム自体をAIに作らせた
- フェーズ管理とチェック機構で品質を担保
- IPA基準比で約90%の工数削減、生産性18.9倍を達成
- 苦労もあったが、手作業に比べて大幅な効率化を達成
- MCPは過剰だったかもしれないが、学びは多かった
レガシーコードの移行に悩んでいる方の参考になれば幸いです。
参考文献
- IPA ソフトウェア開発分析データ集2022
- ADO Command object ignores parameter names - Google Groups
- Microsoft Learn - Using Parameters (OLE DB))
- ADODB.Command and Parameter order - Tek-Tips
本記事の執筆にあたり、実際のプロジェクトで使用したCLAUDE.md、エージェント定義、MCPサーバーのコードを参考にしました。



























































