本番稼働中のSaaSフロントエンドを3ヶ月で作り直した話 — AI時代にリファクタではなく作り直しを選んだ理由 —

梅田 脩平 梅田 脩平 · 27 min read
本番稼働中のSaaSフロントエンドを3ヶ月で作り直した話 — AI時代にリファクタではなく作り直しを選んだ理由 —
目次

はじめに

RECERQAでエンジニア(FDE)をしている梅田です。(このプロジェクト当時はPdMとして関わっていました)

弊社では、RECERQA Scanという、AIを活用した帳票データの読み取り・加工をするAI-OCRサービスを提供しています。2025年夏、このプロダクトのフロントエンドを約3ヶ月で作り直し、リリースしました。

この記事は、「AIで爆速開発しました」という話ではありません。むしろ、AIで開発スピードが上がる時代だからこそ、壊れやすいコードベースの上にそのまま機能を足し続けるのは危ない、という話です。

当時は今ほどAIが安定していたわけでもなく、AIの自信満々の「できました!」を信じた結果「全然できてないやん!」みたいなことは日常茶飯事で、日々試行錯誤の連続でした。半年以上経った今、当時の意思決定や進め方を改めて振り返り、時間が経っても色褪せていない学びを書き残しておきたいと考えています。

技術的負債に悩んでいるチームや、AIを前提にした開発の進め方を考え始めた人に、少しでも参考になれば幸いです。

なぜリファクタではなく作り直しだったのか

壊れやすい基盤からAI前提の設計へ

どこかを触るとどこかが崩れるコードベース

作り直し前のフロントエンドは、機能としては動いている一方で、開発基盤としては厳しい状態でした。

具体的には、次のような問題がありました。

  • コンポーネントが分割されていないため、1つのファイルに画面のレンダリング、API通信、状態管理が詰め込まれており、機能単位のテストも書きづらく、バグは出てから見つけるしかない状態。
  • useEffectがそこかしこで使われており、予測しにくいタイミングで再レンダリングが走り、バグの原因調査に時間がかかる。
  • 仕様の正解がコードにしかないため、ある挙動がバグなのか仕様なのかも判断しづらく、修正の心理的ハードルも高い。
  • 使われていないコードが放置されていて、コードが追いにくい。

恐らく似たような状況を経験したことがある方も多いのではないでしょうか。 影響範囲の見通しが立ちにくく、1つの修正が思わぬ箇所に波及することもありました。

もちろん、当時の実装を単純に否定したいわけではありません。スタートアップにとって、まず顧客に価値を届けることは最優先です。そのスピードがあったからこそ、実際に多くのお客様に使っていただけるプロダクトになっていました。 問題は、その土台のまま次のフェーズに進めるかどうかでした。

事業フェーズが変わり、求められるものも変わった

当時のRECERQA Scanは、ここからエンタープライズ向けに広げていくフェーズに入っていました。安定稼働はもちろん、アクセスコントロール、ワークスペース機能、外部連携のような機能拡張も控えていました。

そうなると、機能を足すたびに壊れやすくなる基盤のまま、次の重要機能を積み上げていくのは現実的でない。そんな感覚がありました。

正直、作り直しはリスクが大きいし、既存機能を再実装するコストも高いので、最初は改善で何とかならないかも考えました。 でもそれでは、問題の先送りにしかならないと考え、作り直す道を選びました。

AI前提で開発するなら、設計思想から変える

もう1つ、AIを前提にした開発へ舵を切るタイミングだったことが大きかったです。

当時、ちょうどClaudeのOpus 4の登場によって、AIによるコーディングの精度の次元が変わったことを今でも強烈に覚えています。今後AIを使った開発が主流になる未来が確実にくる!と社内で盛り上がっていました。一方で使っていくうちに、AIが強力になればなるほど、コードベースの構造の良し悪しがそのまま開発速度と品質に返ってくると痛感しました。

明確なディレクトリ構成や責務の分離、実装の正解となる仕様の存在といったものが、人間にとって読みやすいだけでなくAIにとっても理解しやすい土台になります。逆に、構造が曖昧なコードベースの上にAIで機能を足しても、混沌を加速させるだけです。

どうせ直すなら、短期的なコード品質を改善するだけではなく、AIが動くことを前提にした設計へ切り替えよう。そう考えて、作り直しを決断しました。

3ヶ月止まる痛み受け入れ、半年後に詰むことを回避した

この意思決定は軽くありませんでした。約3ヶ月、新規機能開発をほぼ止めることになるからです。営業からの要望もあるし、お客様からの要望も当然溜まっていきます。

それでも、ここで土台を整えなければ、半年後にもっと大きな形で同じ壁にぶつかる。そう考えて、経営判断として一度立ち止まり、未来の飛躍に備えて足場を整える道を選びました。

ただし、単に中身を作り直しただけでは、お客様にとっての価値は伝わりづらいです。そこで旧アーキテクチャでは実装しにくかった新機能もいくつか合わせてリリースし、お客様にとってのメジャーアップデートとして届ける形にしました。これは今振り返っても良い判断でした。

どのように進めたか

1. 問題の棚卸し

開発着手の前に、既存コードの問題点をできるだけ明確にしました。AIにもコードベース全体を読ませて、依存関係の複雑さや未使用コードの量などを整理しました。何を捨て、何を引き継ぎ、何を新しく設計し直すのか。こうした判断材料をそろえてから着手できたことが、結果的にプロジェクト全体の進み方を大きく左右しました。

2. ガードレールの整備

開始当時はCLAUDE.mdにかなり細かいルールを書いていました。たとえば、なかなかClaudeが言うことを聞いてくれず、作業前に運用原則を5つ復唱させるようなことまでしていました(笑)。

当時のCLAUDE.md — 運用原則を5つ復唱させるルール

試行錯誤の中で、AIに毎回言い聞かせるよりも、以下のようなガードレールを先に整備することで品質が安定していくことがわかり、このような仕組みを整えながら進めました。

  • linter
  • TypeScriptのstrict mode
  • ディレクトリ構成のルール
  • コーディング規約
  • テスト
  • CIでの検証

3. AIが読みやすいアーキテクチャを採用

旧版には明確なアーキテクチャも、仕様の置き場もありませんでした。新版では、コードの構造と仕様の流れを同時に整理しました。

全体のイメージは、ざっくりこんな構成です。

scan/
├── CLAUDE.md # AI向け指示書 兼 開発規約
├── web/
│ └── src/
│ ├── components/ui/ # 共通UI
│ ├── features/ # 機能単位の実装
│ │ ├── auth/
│ │ ├── dataCheck/
│ │ ├── dictionary/
│ │ ├── scanConfig/
│ │ └── ...
│ ├── generated/ # OpenAPIから自動生成した型
│ └── providers/
├── api/
└── docs/
└── specifications/ # 機能ごとの仕様書

このディレクトリ構成のポイントは3つあります。

  • Feature-Firstを採用
    候補の1つにAtomic Designもありましたが、UIの分類には向いていても、業務ロジックの配置までは面倒を見てくれません。Feature-Firstなら機能単位で責務を切れるため、「認証」「データチェック」といった境界が明確になりました。複数機能がある業務アプリでは、実装と保守の両面で優れていました。

  • モノレポ化
    モノレポ化したことで、APIの型定義とフロントの実装を同じ文脈でAIに読ませながら進められるようになり、開発速度が上がりました。リポジトリが分かれていると、API仕様はこうですと毎回説明を足す必要があるので、その手間を減らせました。

  • 仕様書駆動で実装
    docs/specifications/へ機能ごとの仕様を置き、PdMが各機能の正しい姿を先に定義してから実装する流れにしました。 PdMが仕様を書く→実装する→テストする→その間に次の仕様を書く。この流れにしたことで、効率的な開発が実現できました。 仕様書のメンテナンスは重たい作業なので、普段の開発でも常にこれが最適かというと、そこはチームやフェーズによるでしょう。少なくとも今回のように短期間で作り直しつつ品質も落としたくない状況では、かなり有効でした。

4. ロールバックしやすいリリース方式

既存のパイプラインは残したまま、新版のパイプラインを並行で構築しました。リリース時は向き先を切り替えるだけにして、問題があればすぐ戻せる状態を保ちました。

うまくいったこと

まず仕様を明確にした

今回、実装より先に、まず各機能の仕様をきちんと定め、ドキュメント化しました。 当時は、正しい挙動がコードの中に埋もれていて、仕様とバグの区別も付きにくい状態でした。作り直すなら、まずその状態を解消しなければなりません。 具体的には、PdMが各機能について、ユーザーの利用場面や実現したいこと、受け入れ条件をPRDに近い形で先に整理しました。画面の見た目や挙動だけではなく、利用シーンまで含めて言語化してから実装する流れにしました。 これによって、実装やレビューの基準が「なんとなく良さそうか」ではなく、「想定した利用シーンで成立しているか」「受け入れ条件を満たしているか」に変わりました。結果として、AIが実装やテストを書く際の大きなズレもかなり抑えられました。

機能ごとに小さく進めた

複数の機能をまとめて進めるのではなく、1機能ずつ仕様を固め、実装し、テストしてから次に進む形にしました。

この進め方にしたことで、AIの解釈違いや実装のズレに早い段階で気づけました。AIは実装のスピード自体はとても速いのですが、その一方で、もっともらしく間違えることがあります。まとめて複数機能を進めてしまうと、そのズレに気づくのが遅れ、後から大きく手戻りが発生しやすくなります。 その点、機能ごとに小さく区切って進めれば、どこで解釈がずれたのかをその場で確認できます。修正範囲も小さく済むので、結果として手戻りが減り、全体の開発速度も高く保てました。

テストはカバレッジより、メインシナリオを優先した

当初は、AIを活用できるならまずはカバレッジを上げようと考えていました。 ただ、AIに広くテストを書かせると、見た目はもっともらしいのに実際には価値の薄いテストが増えていきました。 そこで闇雲に数を増やすのではなく、ロジックが複雑な箇所や不具合が出たときの影響が大きい箇所を中心に、メインシナリオを優先して厚くする方針に切り替えました。 何をテストすべきかは人間が判断し、テストコードの作成や補強にAIを使う。この分担が結果的にうまく機能しました。

顧客解像度の高い人が、直接プロダクト開発に関与

このプロジェクトはエンジニア2名とPdM1名を中心に進めつつ、社長や役員も必要に応じて仕様や開発、受け入れに関わる体制を取りました。 普通なら属人的になりやすい進め方ですが、あらかじめルールやガードレールを整えていたことで、顧客理解の深いメンバー自身がAIを使って機能を実装しやすい状態を作れました。 お客様がどこで困っていて、どこに価値を感じるのかをよく分かっている人が仕様づくりから実装まで入れるのは大きな強みでした。実際、そうして追加した機能については、お客様からも「使いやすくなった」と好評をいただけました。

うまくいかなかったこと

スコープが膨らんでいく

AIを使っていると、「これもできそう」「ここまで来たなら、これも入れたい」が本当によく起きます。新規開発を止めてまで確保した期間だからこそ余計に、「せっかくならここも」という気持ちが強くなります。実際、開発初期には範囲を広げすぎて中途半端な実装が増えた時期もありました。最初に優先順位は決めていましたが、作りながら見えてくることも多く、どこまで今回やり切るかをその都度見極める必要がありました。

AIがあると実装自体はすぐ進む分、止めどころを決めるのが難しくなります。結局のところ、スコープは最初に完全に引き切るというより、品質と残り期間を見ながら調整していくしかなかったと感じています。

AIの出力を人力で全部追う運用は続かない

プロジェクト初期には、AIが出したコードをできるだけ人間が全部確認しようとしていました。考え方としては正しいのですが、現実には量が多く、ずっと続けられるやり方ではありませんでした。 そこで途中からは、コードの正しさをすべて目視で担保するのではなく、linterや型チェックでルールを守らせつつ、テストやE2Eでの動作確認で挙動を担保する形に寄せていきました。 人間は設計や仕様とのズレを見る。細かなルールの担保や動作確認は仕組みに任せる。そうやって役割分担をはっきりさせていったことで、ようやく現実的に回るようになりました。

作り直して、何が変わったか

厳密な定量比較ができるほど計測できていたわけではありませんが、機能改修時のデグレや障害が減ったことや、開発のしやすさはかなり変わりました。責務の境界が見えやすくなったことで、機能追加や修正のときに「どこまで見ればいいか」の見通しが立ちやすくなり、実装前の認識合わせもしやすくなりました。

また、新規機能については、お客様からも使いやすくなったという反応をいただけました。単にコードを整理しただけでなく、顧客理解のある人が仕様から実装まで関わり必要な新機能も合わせて届けられたことが大きかったと感じています。

さらに、この経験をきっかけに、エンジニア以外もAIを使いながら仕事を進める流れが社内に広がりました。今回変わったのは、コードだけでなく、業務の進め方そのものだったと感じています。

まとめ

今回の作り直しを通して、改めて感じたことは主に3つあります。

1. AIが動く前提で設計する
AIの性能はこれからも上がっていくでしょう。しかしどれだけ賢くなっても、AIに渡す前提情報が曖昧だったり出力を受け止める土台が弱ければ品質は安定しません。linter・型・テスト・ディレクトリ構成・仕様。こうしたガードレールを先に整えることが、AI前提の開発ではますます重要になると感じています。

2. AIは実装を速くするが、優先順位までは決めない
当時を振り返ると、AIでできることが一気に広がったときの感覚はかなり強烈でした。指示を出せばそれっぽいものがすぐ返ってくるので、つい「あれもやりたい、これもできそうだ」と範囲を広げたくなります。 ただ、作るものが増えれば、その分だけ品質を担保すべき範囲も広がります。確認や修正にかかる工数も、当然増えていきます。 「やらないことを決める」ことの大切さは以前から変わりません。一方で、AIによって開発スピードが大きく上がったことでその難しさはむしろ増しました。できることが増えたぶん、どこに絞るかを決めるのが難しくなったからです。 限られた期間とリソースの中で、どこに集中するかを決めるのは人間の仕事です。特にユーザーの課題を深く理解している人が優先順位を握ることの重要性は、以前よりも増しています。

3. 速く作れる時代ほど、壊れにくい作り方が競争力になる
AIによって、モノを作るハードルは確実に下がっています。 その一方で、壊れやすいものを速く量産する危険も増えています。 今回の経験を通して、競争力になるのは単なる実装速度ではなく、速く作っても壊れにくい開発の仕組みを持てるかどうかだと強く感じました。

RECERQAでは、エンジニアだけでなくPdMやセールスも含めて、顧客理解をもとに仕様を言語化し、AIを使いながらプロダクトを前に進めています。実際、今回のプロジェクトでは社長や役員も含めて職種を超えた開発体制でやり切れました。

プロンプトチューニング機能の画面 弊社CEOが実際に開発した「プロンプトチューニング機能」

この経験が土台となり、現在ではSalesチームが営業段階でお客様向けのモックをClaude Codeで作成しています。バックオフィスのメンバーも全員、Claude CodeをはじめとするAIツールで生産性を上げています。

役割を超えてプロダクトに関わりたい人や、AI前提で仕事の進め方そのものを変えていきたい人にとっては、かなり面白い環境です。

最後まで読んでいただき、ありがとうございました!