はじめに
レガシーシステムの調査で、こんな経験はないでしょうか。
- 設計書は存在するが「外部API経由」としか書いていない
- 詳しい人はすでに退職している
- ソースを読もうにも、どこから手をつければいいか分からない
あるとき、外部連携の通信方式について確認依頼を受けました。対象の設計書には通信方式の明記がなく、ソースコードから事実を確定する必要がありました。こういう場面こそ、AIが最も威力を発揮する状況です。
ただし、AIに「この設計書を読んでSOAPかどうか教えて」と投げても、曖昧な答えしか返ってきません。AIを本当に役立てるには、何を見せるか が全てなのです。
本記事では、以下の2点を実践的に解説します。
- ソースコードから通信方式を「確定」させる、AIとの調査プロセス
- 得られた複雑な業務ロジックをAIの「記憶ファイル」として構造化し、次の調査に再利用する方法
ドキュメントを信じるな、ソースを読ませろ
AIに調査を依頼するとき、多くの人が最初にやりがちなのが「設計書や仕様書をAIに読ませる」ことです。しかしこれには大きな落とし穴があります。
古いシステムのドキュメントは、しばしばソースと乖離している。
実際に今回の調査でも、設計書に記載された値とソースコードで実際に使われている値が食い違っている箇所が複数見つかりました(詳細は後述)。設計書を正として読んでしまえば、間違った前提でロジックを理解することになります。
ソースコードは嘘をつかない。 動いているシステムの真実は、常にソースコードの中にあります。
AIに正確な答えを出させたいなら、ドキュメントではなくソースコードを「証拠」として渡す。これが全ての出発点です。
SOAP通信を「5つの証拠」で確定する
なぜSOAPの特定が難しいのか
REST APIなら @GetMapping や fetch() をgrepすれば一発ですが、SOAPはそうはいきません。Spring Web Servicesを使ったSOAP実装は、一見するとただのJavaクラスの呼び出しに見えます。
今回の確認対象は、Javaで実装された外部連携サービス群でした。設計書には 外部API経由 としか書いておらず、SOAPなのかRESTなのかがドキュメントから判断できない状況です。
動かぬ証拠を探すgrepコマンド
AIにソースを渡す前に、まず機械的な証拠収集をします。以下の5パターンを ripgrep(rg)で探すだけで、SOAPかどうかはほぼ確定できます。
# ①継承元クラス(これが一番確実な証拠)
rg "WebServiceGatewaySupport" --type java
# ②SOAP送受信の中核メソッド
rg "marshalSendAndReceive" --type java
# ③JAXBアノテーション(XMLバインディング=SOAP用)
rg "@XmlRootElement|@XmlAccessorType" --type java
# ④リクエストのJAXBElementラッピング
rg "JAXBElement<" --type java
# ⑤URLパターン(PortTypeはWSDLの命名規則)
rg "ServicePortType" --include="*.properties"
これらを実行してヒットしたファイルをAIに渡します。
AIへの投げ方
ポイントは「判断を求める」のではなく、「証拠の解説を求める」ことです。
以下のファイルを確認してください。
このサービスクラスがSOAP通信を行っているかどうか、
コードの根拠を示しながら確定してください。
推測ではなく、実装から読み取れる事実のみを答えてください。
[ファイル内容を貼り付け]
今回の調査でAIが返した結論はこうでした:
結論: 対象サービスは SOAP通信を使用しています。
確認ポイント 内容 クラス継承 WebServiceGatewaySupportを継承(Spring Web Services の SOAP 実装基盤)通信メソッド WebServiceTemplate#marshalSendAndReceive()でSOAP送受信DTOアノテーション @XmlRootElement/@XmlAccessorType/JAXBElement<>でXMLラッピングエンドポイントURL ...ServicePortType形式(SOAPのWSDL命名規則)すべての実装が SOAP 1.1 プロトコルに基づいており、REST/JSON は一切使用していません。
根拠がテーブル形式で整理され、「推測ではなく実装から読み取れる事実」として提示されました。これをそのまま問い合わせへの回答として使えます。
なぜこの5点が証拠になるのか
// ①WebServiceGatewaySupport継承 = Spring-WSのSOAP実装基盤クラスを継承
// RESTクライアントがこれを継承することはまずない
public class ExternalSoapClient extends WebServiceGatewaySupport {
public Object callService(String endpoint, Object request) {
// ②marshalSendAndReceive = Spring-WS固有のSOAP送受信メソッド
// 実装内では一度ローカル変数に取り出してから呼ぶことが多い
WebServiceTemplate wsTemplate = getWebServiceTemplate();
return wsTemplate.marshalSendAndReceive(endpoint, request);
}
}
// ③@XmlRootElement = JAXB(Java Architecture for XML Binding)のアノテーション
// SOAPメッセージのXMLシリアライズに使う。REST用DTOには現れない
@XmlRootElement(name = "ReqBillingInquiry")
@XmlAccessorType(XmlAccessType.FIELD)
public class ReqBillingInquiry { ... }
// ④JAXBElementでのラッピング = SOAP名前空間を付与するための典型パターン
JAXBElement<ReqBillingInquiry> requestElement =
objectFactory.createReqBillingInquiry(req);
⑤のURLパターン(...ServicePortType)はWSDLの命名規則です。SOAPサービスはWSDL定義からエンドポイントURLが生成されるため、ServicePortType というサフィックスがURLに現れます。REST/JSONのエンドポイントにこのパターンはまず出てきません。
WebServiceGatewaySupport と marshalSendAndReceive はSpring Web Services固有のAPIで、「この2つが揃っていたらSOAP確定」と言っても過言ではありません。JAXBアノテーションとURLパターンは、その確信をさらに裏付ける補強証拠として機能します。
業務フローの差異を「見つける」調査術
設計書とソースは別の生き物
通信方式の確認が一段落したところで、別の調査が始まりました。「似た構造を持つ2つの申込フローが、DB操作のレベルでどう違うのか」を正確に把握する必要が生じたのです。
対象は「オプションサービスA申込」と「オプションサービスB申込」の2機能。両機能の仕様書は別ファイルとして存在していましたが、内部キューテーブルへの読み書きタイミングと目的を正確に把握するため、ソースコードと設計書を突き合わせて整理することになりました。
ソースを直接読ませる
設計書に頼らず、AIに2つのソースファイルを直接渡して比較させます。
以下の2つのJavaクラスを比較してください。
・OptionServiceAApplyResource.java(オプションサービスA申込)
・OptionServiceBApplyResource.java(オプションサービスB申込)
init()メソッド・complete()メソッドそれぞれについて、
DBアクセスの有無・タイミング・目的の違いを表形式で整理してください。
[両ファイルの内容を貼り付け]
AIが整理した差異がこれです:
| 比較項目 | オプションサービスA申込 | オプションサービスB申込 |
|---|---|---|
| init(): 残留レコードクリーンアップ | あり(ステータス03かつ日付比較で実行) | なし |
| init(): 二重申込チェック | あり(重複でエラー) | なし(重複を許容する設計) |
| complete(): DBへのINSERT値 | service_order_id = "apply_a" |
service_order_id = "apply_b" |
| 申込区分の扱い | 固定値 | リクエストパラメータから変換 |
設計書に差異が明示されていなかったにもかかわらず、init()のDB操作が全く異なることがソース比較で判明しました。
設計書との乖離発見の実例
さらに踏み込んで「設計書とソースを突き合わせて差分を列挙してください」と依頼したところ、以下の乖離が見つかりました。
| 項目 | 設計書の記載 | 実際のソース |
|---|---|---|
| 商品コード(product_cd) | "PROD_OLD_001" |
"PROD_NEW_001"(定数 SERVICE_CODE_CURRENT に統一済み) |
| クリーンアップ処理の条件 | 「既存レコードのクリーンアップ」と簡潔に記載 | 実際は「ステータス=本削除(03) かつ 残留レコードの日付が削除日付より新しい場合のみ」という条件付きロジック |
商品コードの乖離は、テスト設計や後続処理のIF条件に直結する情報です。設計書を正として進めていたら、バグの温床になっていたかもしれません。
AIは「ドキュメントと実装の比較者」として最も力を発揮します。 「設計書に書いてあることをソースで確認して、違う部分を列挙してください」というプロンプトは、レガシー調査において非常に強力です。
解析結果を「AIの記憶ファイル」として構造化する
一度調べたことを消耗品にしない
こうして得た調査結果、どこに保存しますか? Confluenceやドキュメントツールに貼るのもいいですが、そこで終わってしまうと次にAIと同じ調査を始めるとき、またゼロから文脈を説明し直す羽目になります。
より良い方法があります。調査結果をAIが直接読み込める形式の「記憶ファイル」として保存することです。
記憶ファイルの構造
プロジェクト直下の memory/ ディレクトリに、以下のような構造化Markdownとして保存します。
---
name: 外部連携API 通信方式確認結果
description: 対象サービスの通信方式をソースコードから確定した調査結果
type: project
---
## 結論: SOAP通信(確定)
| 証拠ポイント | 確認内容 |
|---|---|
| クラス継承 | `WebServiceGatewaySupport` を継承 |
| 通信メソッド | `marshalSendAndReceive()` を使用 |
| DTOアノテーション | `@XmlRootElement` / `JAXBElement<>` でラッピング |
| URLパターン | `...ServicePortType` 形式(WSDL命名規則) |
## 実装クラス構成
Resource (Controller)
↓
HighLevelService(機能別ビジネスロジック)
↓
SoapCommunicationService(SOAP共通実装)
↓
外部基盤
## 備考
設計書に通信方式の明記なし → ソースコードから確定済み(調査日: 2026-04-30)
## How to apply
外部連携APIの改修・テスト設計時は、このファイルを最初に参照する。
通信方式はSOAP確定なので、REST前提の設計をしないよう注意。
モック作成時はSOAP形式(XML)のスタブが必要。
Claude Code を使っている場合、memory/ ディレクトリ内のファイルは次のセッションで自動的に参照されます。「前回確認済みのSOAP通信の構成を前提に、今回の影響範囲を教えて」と伝えるだけで、AIが文脈を持った状態で会話を始めてくれます。
記憶ファイルを使い回す効果
Before(記憶ファイルなし):
- 調査のたびに「このシステムってSOAP使ってましたっけ?」から始まる
- 前回の結論を人間が覚えていないと、同じ調査を繰り返す
- 担当者が変わると調査結果がリセットされる
After(記憶ファイルあり):
- AIが前回の調査結果を文脈として持った状態でスタート
- 「前回確認済みの構成を前提に、今回の影響範囲を教えて」が通じる
- 記憶ファイル自体がそのままドキュメントとして機能する
記憶ファイルは「AIへの引き継ぎ書」です。人間が読んでも役立つし、AIが読んでも役立つ。一石二鳥の成果物です。
記憶ファイルに書くべき3要素
調査結果を記憶ファイルに落とし込む際は、以下の3要素を必ず含めます。
| 要素 | 書く内容 | 重要な理由 |
|---|---|---|
| 結論(確定 or 推定の明記) | 調査の答えと確信度 | 「確定」と「推測」を混在させない |
| 根拠 | どのファイルのどのコードから判断したか | ファクトチェック可能な形にする |
| How to apply | 次にこの情報をどう使うか | 記憶を「使える情報」にするための文脈 |
REST / GraphQL環境での応用
ここまでJava + Spring + SOAPというレガシー環境の話をしてきましたが、「ソースを証拠にする」アプローチはモダンな環境でも同様に使えます。
共通パターン:何を「証拠」として渡すか
| 技術 | 動かぬ証拠 | grepキーワード |
|---|---|---|
| SOAP (Spring-WS) |
WebServiceGatewaySupport 継承、marshalSendAndReceive
|
WebServiceGatewaySupport, JAXBElement
|
| REST (Spring) |
@RestController, @GetMapping 等 |
@RestController, RestTemplate, WebClient
|
| REST (宣言的) |
@FeignClient アノテーション |
@FeignClient |
| GraphQL |
.graphql スキーマファイル |
*.graphql, @QueryMapping
|
| gRPC |
.proto ファイル |
*.proto, GrpcService
|
REST APIなら OpenAPIスペックファイル(openapi.yaml)が最強の証拠です。存在すればそのままAIに渡すだけで、エンドポイント・型・リクエスト/レスポンス構造を正確に解釈させられます。
# REST: Spring Boot
rg "RestClient|RestTemplate|WebClient" --type java
rg "openapi:|swagger:" --include="*.yaml" --include="*.yml"
# GraphQL
rg --glob "*.graphql" --glob "*.gql" -l .
rg "@QueryMapping|@MutationMapping" --type java # Spring for GraphQL
rg "@Query|@Mutation|@Resolver" --type ts # NestJS等
# gRPC
rg --glob "*.proto" -l .
どの技術でも手順は同じです。フレームワーク固有のシグネチャをgrepで探し、ヒットしたファイルをAIに渡す。
まとめ:「証拠ファースト」調査の3ステップ
今回紹介したアプローチを整理すると、以下の3ステップです。
STEP 1: 証拠収集(机械的・客観的)
rg / grep で「フレームワーク固有のシグネチャ」を収集する
→ 人間が解釈する前に、存在するものを事実として確定する
STEP 2: AIによる解釈・構造化
証拠ファイルをAIに渡し「根拠付きで整理せよ」と依頼する
→ 推測ではなく「実装から読み取れる事実」を求める
→ 設計書との乖離があれば「比較して差分を列挙せよ」と追加依頼
STEP 3: 記憶ファイルへの結晶化
調査結果を構造化Markdownとして保存する
→ 結論・根拠・How to applyの3要素を必ず含める
→ 次のセッションでAIが文脈を持った状態でスタートできる
AIに丸投げするのではなく、AIを「確実な証拠を解釈する専門家」として使う。 これがレガシーシステム調査でAIを最大限に活かすコツです。
設計書が古い・担当者がいない・ドキュメントが信用できない——そんな現場でこそ、ソースコードという「最も正直な証人」とAIを組み合わせた調査が威力を発揮します。
ぜひ次のレガシー調査から試してみてください。
本記事で紹介したコード例・ファイルパスは、実際の調査をもとに一般化・抽象化したものです。