テストがない 10 万行の Perl システムを、Claude Code で TypeScript へ書き換えた話

01 「AI が書いたコード、読んでますか?」
最近よく見かけるこの議論に、正直に答えます。
全部は読んでいません。10 万行、読みきれません。
これは無責任に聞こえるかもしれません。「AI が書いたコードの 80% は負債だ」という研究もありますし、「理解していないコードをリリースするな」という意見はもっともだと思います。
ただ、10 万行のコードを1行ずつ目で追って品質を担保するのは、現実的に難しいですよね。人間が書いたコードでも、全行レビューはしていないはずです。
じゃあどうしたか。
読む代わりに、検証する仕組みを作りました。 AI に書かせたコードを、AIに検証させ続ける。24 時間、何百ラウンドも、バグが出なくなるまで。読んで理解する代わりに、正しさを証明する。
この記事は、その話です。
02 前提:テストがほぼない
私が担当しているのは、ある企業の EC サイトのバックエンドです。
Perl で書かれていて、10 年以上動いています。認証、注文、決済、予約、LINE連携、クーポン。API のエンドポイントは 133 個あります。
そしてこのコードベースには、まともな自動テストがほぼありませんでした。
初めてソースを開いたときのことは覚えています。10 年分のビジネスロジックがぎっしり詰まっていて、でもそれを検証する手段が何もない。仕様書もない。何かを変えたとき、壊れたかどうかを知る方法がない。よくこれで 10 年動いてきたなと、率直に思いました。
これを TypeScript に書き換えろ、というのが今回のミッションでした。
03 普通にやったら詰みます
テストのないコードの移植は、ソフトウェアエンジニアリングでも最悪の部類に入る仕事です。
教科書的にやるなら、まず既存の Perl コードにテストを書きます。挙動を固めてから、TypeScript で書き直す。でも 10 年分のコードにテストを書く工数は、移植そのものと同じかそれ以上かかります。しかも、Perl の挙動をちゃんと理解してテストに落とせる人材は限られています。
詰んでます。
04 Claude Code に「書かせる」のは1週間で終わりました
Claude Code には、カスタムスラッシュコマンドという機能があります。自分でコマンドを定義して、繰り返し使える仕組みです。
私はまず /migrate-endpoint というコマンドを作りました。
Perl のコントローラのファイルパスを渡すと、Claude Code が関連するモデルやエンティティ、DB スキーマまで全部読みに行って、TypeScript の実装コードとテストを一気に生成してくれます。

テストがないなら、テストごと作ればいい。
この割り切りで、移植前にテストを書くという工程を丸ごとスキップできました。
133 エンドポイント、約 10 万行。実装が終わるまで、約 1 週間でした。最初のエンドポイントが動いたときは「本当にこれでいけるのか?」という気持ちが正直ありましたが、2 つ目、3 つ目と進むうちに、コマンドの精度がどんどん上がっていくのがわかりました。
05 でも「書けた」は「正しい」じゃない
1 週間で 10 万行。数字だけ見ればすごいです。
でも、テストのほぼない Perl から移植したコードです。「動くけど微妙に違う」コードが量産されている可能性は大いにあります。
Perl は未定義値を空文字やゼロとして黙って処理します。TypeScript ではそうはいきません。タイムゾーンの扱いも違う。数値と文字列の暗黙変換もある。こういう差異は、普通のテストでは見つかりません。
そこで、これも仕組みで解決することにしました。
06 パリティ監査という仕組みを作りました
もう 1 つのカスタムコマンド、/parity-audit を作りました。
やることはシンプルです。
- Perl のコードと TypeScript のコードを突き合わせて、挙動の差異を見つける
- 差異があればバグとして修正し、テストを追加する
このコマンドを実行すると、1 ラウンドで 20 の AI エージェントが並列に起動し、それぞれが違う切り口でコードを調べていきます。

あるエージェントはエンドポイント単位で、リクエストからレスポンスまでのコードパスを 1 行ずつ比較しています。別のエージェントは DB アクセス層を見ていて、クエリの条件やソート順、NULL の扱いをチェックしています。
決済まわりを専門で見るエージェントもいます。税計算、クーポン適用、支払いステータス。1 円でもズレたらアウトの領域です。認証・セッション管理を集中的に検証するエージェントもいて、ログインや SSO、MFA といったセキュリティに直結する処理を重点的に見ます。
日時処理、暗号化、バーコード生成といった「言語が変わると挙動が変わりやすい」ユーティリティも、専用のエージェントが横断的にチェックしています。
これだけの観点を人間が毎回カバーするのは、まず無理だと思います。
07 「10回連続クリーン」になるまで止めません
パリティ監査には、1 つルールを課しました。
連続10回、差異ゼロが出るまで回し続ける。
1ラウンドでもバグが見つかったら、カウンタはゼロに戻ります。修正して、また最初から。10 回連続でクリーンになって、初めて「OK」です。
このコマンドを夜間も含めて走らせ続けました。
2.5 ヶ月間。
08 監査 379 ラウンド、800件以上のバグを修正
結果として、379 ラウンドの監査を回し、800 件以上のバグを見つけて直しました。
最初のほうはラウンドごとにバグが山のように出てきて、正直なところ気が遠くなりました。でも修正を重ねるうちに、だんだんクリーンなラウンドが増えてきます。連続クリーンが 5 回、6 回と伸びていくのを見ているときは、ちょっとした達成感がありました。
中には、移植元の Perl 側に何年も潜んでいたバグが見つかったケースもありました。テストがなかったから、誰も気づかなかったバグです。パリティ監査がなければ、そのまま TypeScript 側にも引き継がれていたでしょう。
09 これで何が変わったか
移植前と移植後で、テストの状況は一変しました。
移植後のテストは 1,419 件。 しかも全部パスしています。移植プロジェクトとしてだけでなく、テスト資産の構築としても大きな成果だと思っています。
そして、1,419 件のテストがあるということは、ここからのリファクタリングが容易になるということでもあります。テストがなかった頃は怖くて触れなかったコードを、安心して改善できる。移植がゴールではなく、ここからがスタートです。

10 そして、人間の手で確かめました
最後に、フロントエンドとつないで E2E テストをしました。
これは人間が手で動かすテストです。実際のブラウザで、実際の画面を操作して、注文を入れて、決済して、予約して。AI ではなく、人間の目と手で確かめました。
不具合は見つかりませんでした。
10 万行。テストがほぼない状態からの移植。AI が書いて、AI が検証して、最後に人間が触って、壊れていなかった。
正直、自分でもちょっと信じられませんでした。
11 Claude Codeの使い方として伝えたいこと
この経験を通じて、Claude Code の使い方について 3 つのことがわかりました。
- カスタムコマンドで「仕組み」にする
- 属人的な「上手いプロンプトの書き方」ではなく、誰でも実行できるコマンドとして定義します。これで品質が人に依存しなくなります。
- CLAUDE.md に知識を貯める
- プロジェクト固有のルール(アーキテクチャ、命名規則、エラーコードなど)を CLAUDE.md ファイルに書いておきます。セッションが変わっても、Claude Code はこれを読んでくれます。移植が進むほどこのファイルが育ち、後半フェーズほど手戻りが減りました。
- 品質保証を「計算資源」の問題にする
- 1 ラウンド 20 エージェント × 379 ラウンド。この物量の検証を人間がやるのは無理です。でもコマンドにして 24 時間回せば、品質保証は工数の問題ではなく計算資源の問題になります。
12 「読んでない」のその先へ
冒頭に戻ります。
AI が書いたコード、読んでますか?
私の答えは変わりません。全部は読んでいません。でも、全部検証しました。20 エージェント並列で、379 ラウンド、800 件のバグを潰して、最後に人間の手で E2E テストして、不具合ゼロ。
もちろん、コードを読んで理解すること自体の価値を否定するつもりはありません。ただ、「読む」以外にも品質を担保する手段はあるはずです。
読むか読まないかではなく、正しさをどう証明するか。 その仕組みを設計できるかどうかが、AI 時代のエンジニアリングで問われることなんじゃないかと思っています。
13 この 3 ヶ月は長いのか
AI コーディングの事例として、「数時間でアプリを作った」「週末で完成した」といった話をよく見かけます。それと比べると、3 ヶ月という数字は地味に映るかもしれません。
でも、考えてみてください。テストのほぼない 10 万行のプロダクションコードを、133 エンドポイントの挙動を 1 つも壊さずに別言語へ移植する。普通にやったら 1 年はかかるプロジェクトです。見積もりの段階で「現実的じゃない」と却下されてもおかしくない。
それを 3 ヶ月で、しかも人間の E2E テストで不具合ゼロという品質で完遂できました。
同じような課題を抱えている方は、少なくないと思います。テストのないレガシーシステム、移植したいけど踏み切れない、人手も時間も足りない。今回のアプローチは、そうしたプロジェクトにも十分に適用できると考えています。
レガシーシステムの移行でお困りの方がいらっしゃれば、ぜひご相談ください。
注記:本記事で紹介した /migrate-endpoint、/parity-audit は Claude Code のカスタムスラッシュコマンド機能で構築したものです。

S2ファクトリー株式会社
様々な分野のスペシャリストが集まり、Webサイトやスマートフォンアプリの企画・設計から制作、システム開発、インフラ構築・運用などの業務を行っているウェブ制作会社です。
実績
案件のご依頼、ご相談、その他ご質問はこちらからお問い合わせください。






