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

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