チャット生成アプリのリファクタチェックリスト:プロトタイプからコードベースへ
このリファクタチェックリストを使って、チャットで作ったプロトタイプを名前付け、フォルダ、状態、API 境界の整理と重複削除を行い、保守しやすいコードベースに変えましょう。

なぜチャットで作ったプロトタイプはすぐに散らかるのか
チャットプロトタイプは、やりたいことを自然な言葉で説明してツールに生成させることで作るアプリのバージョンです。Koder.ai のようなプラットフォームでは、画面やフォーム、API 呼び出しを頼めば数分で動くものが手に入ります。
その代償は「いま動けばよい」に最適化されることで、あとで変更しやすいかどうかは二の次になりがちな点です。新しいリクエストはたいていもう一つのコンポーネント、もう一つの状態変数、あるいは僅かな修正を加えたコピー関数になっていきます。数回のやり取りの後、アプリは動いているものの、ちょっとした変更でも不安になります。
プロトタイプモードには見覚えのある匂いがあります:
- 名前を変えたりファイルを移動したりすると壊れそうで避ける。
- 単純な UI 変更に複数箇所の編集が必要になる。
- デバッグは多くの仕事を抱えた巨大コンポーネントを読むことになる。
- 同じロジックが二〜三種類の微妙に違う形で存在する。
- データルールが UI、API 呼び出し、ランダムなヘルパーに散らばる。
チャットで素早く変更することは責務をあいまいにします。単一ページがデータ取得、検証、フォーマット、エラー処理、レンダリングを全部やっていることも珍しくありません。名前付けは会話ごとに変わり、コピー&ペーストは共有ヘルパーを設計するより速いため増えます。
「保守しやすい」とは完璧なアーキテクチャを意味しません。個人や少人数のチームなら、すぐに見つけられること、各ファイルに一つの主な役割があること、状態の住み分けが明確(ローカル、グローバル、サーバー)、UI とバックエンドの境界がきれいで、1つの機能を変えても他が三つ壊れないこと、が通常の目標です。
良いリファクタチェックリストは、その散らかったプロトタイプを日常的に保証できる状態に、一歩ずつ安全に近づけます。
リファクタを始める前:振る舞いを守り、目標を定める
目的がぼんやりしているとリファクタは失敗します。何のためにやるのかを一つはっきり決めてください:機能を速く追加したいのか、バグを減らしたいのか、新しい人が午後でプロジェクトを理解できるようにしたいのか。"全部きれいにする" とすると書き直しになりがちです。
スコープを厳しく限定してください。一つの機能領域(認証、チェックアウト、管理ダッシュボード)を選び、他はスコープ外と扱います。その制約が安全な掃除を再構築に変えない要因です。
コードに手を付ける前に、壊してはならないユーザーフローを書き出します。具体的に:"サインイン、ダッシュボードに遷移、レコード作成、一覧に表示、ログアウト" のように。チャットで作ったアプリはしばしばそのフローが誰かの頭の中にしかありません。紙に書いて各小さな変更後に再確認できるようにします。
次に、繰り返し実行できる小さな成功チェックを定義します:
- アプリがビルドし、理解できない新しい警告なしで起動する。
- 選んだ領域の主要画面が正しく読み込まれ、レンダリングされる。
- キーアクションが実データで機能する(保存、削除、検索、送信)。
- エラーは空白画面ではなく有用なメッセージを表示する。
- 変更に驚いたときに戻せる方法がある。
プラットフォームがスナップショットとロールバックをサポートしているなら(たとえば Koder.ai 上で構築している場合)、その安全網を使ってください。小さなスライスをリファクタし、チェックを走らせ、スナップショットを取り、進める、という小さなステップを踏みやすくなります。
次の変更を楽にする名前付け
チャットで作られたアプリでは、名前が会話に引きずられていることが多いです。早めに整理すると、将来のすべての変更が検索とスキャン、推測の回数を減らしてくれます。良い名前はその推測を減らします。
まず履歴を示す名前を目的を示す名前に変えましょう。temp.ts、final2.tsx、newNewComponent のようなファイル名はアプリの実態を隠します。現在コードがしていることに合った名前に置き換えます。
シンプルな命名ルールを決めて全体に適用します。例:React コンポーネントは PascalCase、フックは useThing、ユーティリティは formatPrice や parseDate のような明確な動詞。スタイルそのものより一貫性が重要です。
チェックリスト向けの簡単な規則:
- コンポーネント:ユーザー向けの責務で名前付け(
InvoiceList、DataRendererではなく前者) - 関数:動作で名前付け(
saveDraft、handleSubmit2ではなく前者) - ブール値:
is/has/canで始める(isLoading,hasPaid) - イベントハンドラ:props は
onX、コンポーネント内はhandleX - ファイル:主要なエクスポートと一致させる(
InvoiceList.tsxはInvoiceListをエクスポート)
リネーム中にデッドコードや未使用の props を削除してください。さもないと "もしかして必要" な要素が残り、将来の編集を危険に感じさせます。削除したら UI を集中して走らせ、依存がなかったことを確認します。
コメントは意図が自明でない場合だけ追加します。"検索をデバウンスしてレート制限を避ける" のようなメモは有用ですが、コードを言い換えるだけのコメントは不要です。
スナップショットとロールバックがあれば、リネームや再編成を自信を持って一気に行い、インポートや prop の見落としがあればすぐ戻せます。
成長できるフォルダ構成
チャットで作ったプロトタイプはたいてい "速く作ったファイルが置かれた場所" が始まりです。ここでの目標は完璧さではなく予測可能性:誰でも新機能を追加したりバグを直したり画面を調整したりするときに、十個のファイルを開かずに済むこと。
一つの整理ルールを決め、それを守る
コードをグループ化する主な方法を一つ選び、それに従ってください。多くのチームは機能優先(feature-first)がうまくいきます。変更は機能単位で起きることが多いためです。
機能別にしても、各機能内では責務を分けておきましょう:UI(components/screens)、状態(stores/hooks)、データアクセス(API 呼び出し)。そうすることで "巨大なファイル" が別のフォルダで再発することを防げます。
実用的な出発点
React ウェブアプリ向けのシンプルで読みやすい構成例:
src/
app/ # app shell, routes, layout
features/ # grouped by feature
auth/
ui/
state/
api/
projects/
ui/
state/
api/
shared/
ui/ # buttons, modals, form controls
lib/ # small helpers (date, format, validators)
api/ # API client setup, interceptors
types/ # shared types/models
assets/
この構成を迷路にしないためのルール:
- フォルダは浅く保つ。コンポーネントを見つけるのに4階層も必要なら構造が凝りすぎている。
- "shared" コードはダイエットさせる。あるものが一つの機能でしか使われないならその機能内に置く。
- "api" はサーバーと話すことを意味させる。ビジネスルールをリクエストファイルに混ぜない。
- 定数や型の帰る先を一つに決める。機能固有のものは機能内に、真に共有されるものだけを
shared/typesに置く。 - フォルダ名は名詞(auth, projects)で、ファイル名は実体(ProjectList, useProjects, projectsApi)にする。
Koder.ai 上で早期にコードをエクスポートしていた場合、このような予測可能な構成に移すのが次の一手として有効です。新しい画面ごとに明確な居場所を与えつつ、書き直しを強制しません。
状態管理:何がどこにあるべきか決める
高速なチャットプロトタイプは、いくつかの場所に状態が重複しているために "動いている" ことが多いです。リファクタの目的は単純です:各状態について一つの明確な所有者と、読み取り・更新の予測可能な方法を作ること。
まず自分が扱っている状態の種類を名前付けします:
- UI 状態(モーダル、タブ、選択行、テーマ)
- サーバーデータ(一覧、詳細レコード、権限)
- フォーム状態(入力、検証エラー、dirty フラグ)
- 派生状態(カウント、フィルタ済みビュー、計算合計)
- セッション状態(現在のユーザー、フィーチャーフラグ)
次に各バケットがどこに属するかを決めます。UI 状態は通常それを必要とするコンポーネントの近くに置くべきです。フォーム状態はフォームの中に。サーバーデータは複数のローカル状態に複製せず、一つのサーバーキャッシュ層や共有ストアに置いて、きれいにリフレッシュ・無効化できるようにします。
二重の真実に注意してください。典型的な React プロトタイプの罠は items をグローバルストアに置きつつコンポーネントでも items を持ち、同期しようとすることです。所有者を一つに決めましょう。フィルタ済みビューが必要なら、フィルタ入力を保存して、フィルタ結果自体を複製しないようにします。
データフローを見える化するために、いくつかの重要な値について次を書き出します:
- 誰が所有しているか
- 誰が読み取るか
- 誰が更新できるか
- 何が更新を引き起こすか
一つの状態パターンを選んで一貫して適用してください。完璧である必要はありません。チーム全体で「状態はどこにあるか」「更新はどう扱うか」の期待値を揃えることが重要です。
API 境界:はっきり線を引く
チャットで作ったプロトタイプは UI が "今動けばいい" として生データや内部 ID、画面ごとに違う形のエンドポイントを直接扱うことがよくあります。その速さは後々コストになります。各画面が余分なマッピングをし、変更がリスキーになるからです。
クリーンな境界とは、フロントエンドが小さく安定した操作群だけを知り、返ってくるデータも予測可能であることです。実用的な一手は、UI が呼ぶ唯一の場所となる小さな API クライアント層を作ることです。
UI が知ってはいけないもの
画面がテーブル名や結合ルール、内部 ID を知っているなら境界が漏れています。UI は PostgreSQL の主キーや created_by_user_id のようなデータベース詳細に依存すべきではありません。taskId、title、status、dueDate のようなプロダクトレベルの形を返し、データベースの詳細はサーバー側に留めます。
境界が漏れているサイン:
- コンポーネントが直接 URL、クエリ文字列、ヘッダを組み立てている。
- いくつかのレスポンス形を各画面で "ほぼ同じ" にマップしている。
- エラー処理がページごとにバラバラ。
- UI コードが
deleted_atのようなデータベース専用フィールドを参照している。 - バックエンドの変更で複数の画面が壊れる。
境界を退屈で一貫したものにする
ここでのチェックリスト的思考は:入口を減らし、形を減らし、驚きを減らすこと。リクエストとレスポンスの形を正規化して、各画面のマッピング量を減らします。
読みやすく保つための単純なテンプレート:
- ドメインごとに一つの API モジュール(auth、tasks、billing)
- サーバー呼び出し前に基本入力チェック(必須項目、簡単な形式)
- UI に返すエラー形は常に同じ(message, code, retryable)
- ビジネスルールは UI の外側に置く(コンポーネント内に埋め込まない)
Koder.ai 上で作っているなら、生成されたエンドポイントは出発点と考え、安定したクライアントインターフェースを固めてからバックエンドを調整できるようにします。
よくある質問
チャットで作ったプロトタイプはいつリファクタするべきですか?
小さな変更が「リスクが高い」と感じられるようになったら開始の合図です:ファイル名を変えられない、UI の調整に複数箇所の編集が必要、同じロジックが少しずつ違う形で何度も出てくる、といった状況です。
良いトリガーは、コードを「理解する」ことに費やす時間が、新機能を出す時間を上回ったときです。
全てを壊さずに安全にリファクタを始める最も安全な方法は?
まず ひとつの明確な目的 を決めます(例:「tasks エリアで機能追加を速くする」「checkout のバグを減らす」)。次に、対象の機能領域を厳密にスコープして、それ以外は手を付けないと決めます。
変更ごとに破ってはならないユーザーフローを3~5個書き出し(サインイン、レコード作成、リフレッシュ、削除、ログアウトなど)、小さな変更ごとにそれらを再実行して確認します。
散らかったコードベースでまず何をリネームすべきですか?
まずは日常的に見るものから:ファイル、コンポーネント、関数、主要な変数 を優先的にリネームします。
短く役立つルール:
- コンポーネント:ユーザー責務で命名(例:
InvoiceList) - 関数:動作で命名(例:
saveDraft) - ブール値:
is/has/canで始める(例:isLoading) - ハンドラ:props は
onX、コンポーネント内ではhandleX
作業しながら未使用のコードは削除して、「もしかして必要かも」を残さないようにします。
チャット生成された React アプリにはどんなフォルダ構成が合いますか?
一貫したルールを決めて守ることが第一です。一般的には機能単位(feature-first)の構成が扱いやすいことが多いです。
各機能内は責務ごとに分けておくとよいでしょう:
ui/:画面やコンポーネントstate/:ストアやフックapi/:サーバー呼び出し
フォルダは浅めに保ち、feature 固有のコードを早めに shared/ に移さないようにします。
同じデータが複数箇所に存在するとき、状態をどう整理すればいいですか?
同じデータが複数箇所にあると同期の問題を生みます。各状態カテゴリに一つのオーナーを決めましょう:
- UI 状態(モーダル、タブ、選択行)はそのコンポーネント近くに
- フォーム状態はフォーム内に
- サーバーデータは一つのキャッシュ/ストア層に置く(複数のローカル状態にコピーしない)
"二つの真実" を避け、フィルタ結果を複数で持つのではなくフィルタ入力だけを保存する、といったルールを適用します。
フロントエンドとバックエンドの間にクリーンな API 境界を引くには?
フロントエンドがデータベースのテーブル名や内部 ID、画面依存のレスポンス形に依存していると、境界が漏れています。フロントエンドは小さく安定した操作群だけを知るべきです。
実用的な方針:
- ドメインごとに API モジュールを一つ作る(auth、tasks、billing など)
- サーバー呼び出し前に基本的な入力チェックをする
- UI に返すエラー形は統一する(message, code, retryable)
- ビジネスルールは UI から外す(コンポーネントに埋め込まない)
一つのクライアント層を用意して、UI はそこにだけ依存するようにします。
“utils のジャンクドロワ” を作らずに重複ロジックを減らすには?
まずは変化したときに静かに壊れるルールを探します:
- バリデーション
- 日付や通貨のフォーマット
- 権限チェック
- レスポンスのマッピング
最小単位で抽出し、名前を付けます(例:canEditInvoice())。小さなヘルパーは命名しやすく、テストもしやすいです。汎用 utils をジャンクドロワにしないよう、機能に近い場所に置き、真に複数箇所で使われるようになったら shared に移します。
安全に変更を進めるためのリファクタ手順は?
一番安全なのは画面からデータベースや外部サービスまでの一つのスライスを順に扱うことです(例:「タスク作成」)。
落ち着いた順序の例:
- スライスを選んで今日動くことを確認。振る舞いを固定する。
- リネームしてファイルを移動。小さな変更で元に戻せるように。
- API 境界を抽出し、ビジネスルールを UI から外す。
- 重複を削除し状態を簡素化。
- 整理して終了(スコープを広げない)。
各スライスごとに止まることで安全に進められます。
チャットで作られたアプリのリファクタでよくある失敗は何ですか?
よくある落とし穴:完璧なアーキテクチャを最初に設計しようとして何も進まなくなること。痛みは具体的なところ(名前、フォルダ、状態バグ、API の散らかり)にあることが多いので、そこから直してパターンを見つけます。
他のミス:一気に全アプリを変える、抽象化を早すぎる段階で導入する、重複を「あとで消す」として放置する、サーバールールを UI に混ぜる、などです。
価格計算の例:UI、注文サマリー、バックエンドで同じロジックが別々にあると不整合になります。ルールは一箇所(多くの場合サーバー)に置き、UI は API が返す金額を表示する方が安全です。
Koder.ai のスナップショットやロールバックはリファクタでどう使うべきですか?
スナップショットやロールバックはワークフローの道具として使いましょう:
- 各リファクタスライスの前にスナップショットを取る
- 小さな変更を一つ行い、成功チェックを再実行する
- スライスが安定したら再度スナップショットを取る
Koder.ai を使っているなら、スナップショットとソースコードのエクスポートを組み合わせて、小さなステップで安全に再構成できます。