Classi開発者ブログ

教育プラットフォーム「Classi」を開発・運営するチームの開発者ブログです。

Backbone.js画面をAngularへ。Claude Codeと挑んだレガシー移行

こんにちは、エンジニアの鳥山(to_lz1)です。

皆さま、AIを用いた開発は快適に行えていますでしょうか?Claude Code, Cursorなどなど多様なツールが現れ、「開発にAIを取り入れる」ということはもはや当たり前になってきていますが、その具体的な使い方となるとまだ模索しているチームも多いのではないでしょうか。

最近、我々の開発するClassiに残っていたレガシーコードを駆逐したのですが、その過程でClaude Codeが大いに役立ってくれました。今回はその事例を紹介するとともに、その過程で工夫したことや考えたことをお伝えしていきたいと思います。「AIやLLMは古いライブラリからの移行やリアーキテクチャに向いている」といった言説はしばしば聞きますが、その具体的な事例はまだそれほど充実していないように思います。今回の話が少しでもご参考になれば幸いです。

発端

ことの起こりは、今回とまったく別の案件で自分が普段触らないリポジトリ「設定・登録」1画面の文言修正が必要になったときのことでした。

大前提として、ClassiのフロントエンドではAngularが最も広く採用されています2。共通の技術が使われていることもあるし、ちょっとした変更なら自分でやっちゃえば良いよね、ということで文言を変更してローカルで起動してみたのですが...なぜか変更内容が反映されません。さっそくこのリポジトリを担当する同僚に質問してみました。

私「この部分に変更入れたんですけど反映されなくて。ビルドスクリプトこれで合ってますよね?」

同僚「あれ、合ってますけどこの画面ってAngularじゃなかった気が...」

私「え、じゃあこのコードは一体……!?」

同僚「たぶんかつて移行しようとしたことがあって、それが未完のまま残ってる感じですね...」

私「なるほど?ってことは今どこで動いてるんですかねこの画面」

同僚「Backbone.jsですね……

私「え……ほんとだ……」

ということで、このリポジトリにはAngularとともにBackbone.jsのコードが残存していたのです。Classiは2014年から存在するプロダクトですから、フレームワークの混在や変遷があるのは仕方のないところではあります。しかし、明らかに同じ領域(この場合、フロントエンド)に属するフレームワークが複数混在しており、あまつさえ移行をやり切れなかった残滓が残ってしまっているというのはあまり良い状況ではありません。

「なんとかしたいな」という気持ちになった私はClaude Codeや同僚とリポジトリの分析を始め、「私が触ろうとしていた画面がほぼ唯一のBackbone.jsが残存している画面であり、ここさえAngularに移行すればBackbone.jsを消せそうだ」ということを突き止めます。

とはいえ元々このリポジトリを管理しているチームは他の機能も担当しており、すぐにこれに着手するのも難しそうでした。そこで、コードレビューや壁打ちだけ手伝って頂きつつ、私が時間を見つけて徐々に移行を進めていく運びとしました。

Claude Codeと働く上で、良かったと思う考え方・Tips

型定義やデータマッピングはまず丸投げして損はない

今回の対象画面はいわゆる「新規作成」「編集」系のフォームで、情報項目も20〜30程度ありました。こうなってくるとバックエンドに渡したり渡されたりする項目も多く、またそれらを受け渡すバックエンドAPIの既存実装にもいくらか改善の余地はあったのですが、今回はここには極力手を入れず、フロントエンドの改修に注力してスコープを狭く保った方が良いだろうと判断しました。

しかしその判断によって工数を削減したとしても、これまでBackbone.jsで書かれていたモデルやフォームの定義はすべてAngular+TypeScriptで書き直さねばなりません。ここで早速Claude Codeを使うことにしました。具体的には、バックエンドから返ってくるレスポンスのデータ3をChrome DevToolsで取得し、これを丸ごとClaudeに渡して「型定義を作って!」とお願いしました。

当然ながら圧倒的に高い効率で生成してくれるのですが、このアプローチの真に優れている点は「生成結果が不完全だったらすぐに気づける」ところにあります。モデルの型定義のようなコードは複数の業務ロジックが依存するコアとなるコードです。従って、実装を進めたり、単体テストを書く中で、生成された項目の不足や名前誤りはTypeScriptの型エラーや不整合として即座に明るみに出て来るのです。データマッピング系のコードに関しても同様のことが言えるため、こうした作業はまず生成AI系のツールを第一選択にして間違いなさそうに思いました。

「良いお手本は何か」を真っ先に学び取る

一方で、慣れない技術や業務領域のコードを触るとやはりAIへの指示出しも完璧にはいかず、ぎこちない部分が出てくるものです。最初のうちに作ったコードに対しては同僚からは暖かくも厳しいレビュー指摘を頂きました。ですが結果的に、このことが後半の開発を大きく加速させたと思います。

というのも、歴史のあるリポジトリではすべてのコードが理想通りになっていることなど稀で、それこそ古いフレームワークのコードが混じっていたり、あるいは古いバージョンの書き方が残存しています。こういう局面で何も考えずに生成AIを頼ると、AIがリポジトリ内に残る古いコードの書き方をサンプリングし、レガシーな実装を再生産してしまうという罠があります。

初期のコードレビューを通し、私は「Angularの最新バージョンで推奨されるのはどういう書き方か」「それとは別に、チーム内で推奨されている書き方やテストフレームワークはあるか」「こうした一連のルールが一番優れた形で取り入れられているのはどこか」といった知識を優先して押さえるようにしました。

こうした「良いお手本に関する知識」をひとたび理解すると、それ以降のClaude Codeへの指示を遥かに効率的に出すことができるので、大きくレバレッジが効きます。例えば

  • 「HTML側で参照していないプロパティはハッシュ (#) 接頭辞を使用してprivate fieldにして」
  • 「Computed Signal4で書き換えられそうな箇所があれば教えて」
  • 「単体テストをTesting Library5を使う形で書いて。要素を簡単にLocateできない場合はaria-labelledbyなど追加で指定すべき属性を指摘して」

などといった指示(プロンプト)は、今回の案件でフロントエンドに詳しいメンバーとの対話・レビュー対応を幾度か繰り返して初めて出せるようになったものです。

なんだかんだ言っても品質保証(QA)は要る

今回、テストに関してもClaude Codeの力を大いに借りました。しかし、生成AIに「単体テストを書いて」と言うと基本的に現状のコードを追認する形でテストを書くため、そもそもプロダクトコード側で考慮が漏れている場合のバグ検知には限界があります。

Classiでは基本的にAutifyを用いた自動化されたE2Eテストを運用していますが、画面を丸ごと新規作成したり移行したりするようなスケールの案件では、QAチームと協力して人手のテストを行うこともあります。今回もそのアプローチを取り入れ、QAチームメンバーのおかげで摘出・修正できたバグも複数ありました。その中には、文言の誤りといったAIが気づきにくいものや、移行前からそもそも内在化していたコーナーケースの考慮漏れなどが含まれていました。こうした実績を見ると、(効率化はしたいものの)やはりまだ人手のテストは必要である、というのが個人的な感触です。

「移行」なら現仕様が維持できてれば良いのでは?

見方によっては「現時点の仕様を全て明文化し、それを完璧に維持するように移行すればAIに全て任せてもうまく行くのでは?」という意見もあると思います。

例えば仕様を明文化しやすいAPIの移行などであれば、そうしたアプローチにも可能性があるかもしれません。しかし、私はこれには大きく二つの弱点があると考えています。

第一に、移行中に見つけた改善点にアプローチするのが難しくなります。今回のケースでも移行前のフォームにいくらか使いづらいと思われる点があり、ステークホルダーと相談して細かい仕様をいくつか変更しました。「現行をそのまま移行する」という考え方では、基本的にこうしたことは行われないでしょう。仮に修正を行うことまではできても「修正が正しく行われたかどうか」の確認までは自動化できず、限界が残ります。

現行仕様について気になった点をディレクターやフロントエンドエキスパートに相談している様子

第二に、移行前からあった潜在バグが見逃されてそのまま移植されてしまう可能性があります。先述したコーナーケースの考慮漏れはまさに潜在バグであり、こうした問題の検知と対応は自分で設計とコーディングをしていなければ難しかったと思います。

概して、全てをAIに任せようとする方針では「移行とともにより良いコード、より良いプロダクトにする」ことが難しくなります。生成AIは開発を強力に支援してくれますが、そうした時代だからこそ、移行や改修のタイミングで「プロダクトをより良くする」ための判断と意思決定を行うことが人間の介在価値として重要になってくるのではないでしょうか。

結果と総括

結果として、2025年12月ごろに着手して、2026年4月にBackbone.jsへの依存を消すリリースが完了しました。短い時間ではありませんでしたが、「他業務やマネジメント業と並行しながら細切れの時間でやり切れた」というのは、Claude Codeという相棒がいたからこその成果ではないかと思います。

2,300行余りを削除するとどめのPRは同僚のすずまささんが引き継いで叩き込んでくれました

もちろん、Claude Codeのみならず、壁打ちやコードレビューに付き合ってくれた開発チーム、精密なテストで画面文言から内部仕様までブラッシュアップしてくれたQAチーム、他の案件もある中で相談に乗ってくれたディレクターなど、各方面にも感謝したいと思います。

以上、Claude Codeをレガシーコードの削除に用いた事例を紹介しました。皆さまのチームでも、AI活用のヒントになれば幸いです!


  1. 学校の情報や、先生の情報とその権限等を設定する、主に学校内管理者向けの機能です。
  2. https://tech.classi.jp/entry/2022/12/10/120000
  3. ちなみにフォームデータ中にマスタデータも全部含んだ形で、1,000行を超えるJSONが返ってくるエンドポイントもありました。「改善の余地」の雰囲気をここで感じ取って頂けると幸いです。そして、Claude Codeの良いところはそんなデータを放り投げて「型定義を作って」と言っても一切文句を言わないところにあります。
  4. https://angular.jp/guide/signals#computed-signals
  5. https://testing-library.com/

© 2020 Benesse Corporation. All rights reserved.