第3章:スパゲッティコード大掃除:AIにReactコンポーネントのリファクタリングと分割を依頼する
Vibe Codingでは、迅速さを求めるあまり、新しい機能を同じファイルに追加し続けることがよくあります。やがて、page.tsxが800行、さらには1500行以上に膨れ上がることも。こうなると、AIは次第に賢くなくなり、Aを修正したらBが壊れるといった事態が発生します。
このようにごちゃごちゃで互いに絡み合ったコードを「スパゲッティコード(Spaghetti Code)」と呼びます。本章では、AIに指示を出して安全に「コードリファクタリング(Refactoring)」と「コンポーネント分割」を行う方法を学びます。
なぜファイルが大きいとAIは賢くなくなるのか?
- Context Windowの浪費:AIは毎回の会話でファイル全体を読み込む必要があります。1500行のファイルは大量のTokenを消費し、AIが最初の要件を「忘れる」原因になります。
- 修正リスクの高さ:1つのファイルにHeader、Sidebar、Main Content、Footerが詰め込まれている場合、AIにFooterの修正を依頼すると、誤ってHeaderの状態(State)を変更してしまう可能性があります。
- 人間が理解できない:Vibe Codingは人間がコードを読まなくてよいという意味ではありません。ファイルが大きすぎて把握できなくなると、プロジェクトのコントロールを失います。
リファクタリングの黄金律:単一責任の原則(SRP)
AIにコンポーネントを分割させる前に、「単一責任」の概念を頭に叩き込む必要があります。 Reactコンポーネントは「1つのこと」だけを担当すべきです。
例えば、PricingPageは以下のすべてを担当すべきではありません:
- データベースから価格プランを取得する
- プランカードのUIをレンダリングする
- 決済ボタンのStripe APIロジックを処理する
- よくある質問(FAQ)アコーディオンをレンダリングする
代わりに、以下のように分割すべきです:
PricingPage(組み合わせのみ担当)PricingCard(カードUIのレンダリングのみ担当)CheckoutButton(決済ロジックのみ担当)FaqSection(FAQロジックのみ担当)
実践:コンポーネント分割の「詠唱」方法
AIに「このファイルを小さく分割して」とだけ伝えるのは曖昧すぎます。AIが理解不能な構造を提案する可能性があります。
代わりに、以下のリファクタリング専用Promptテンプレートを使用してください:
[タスク目標] 現在の
src/app/pricing/page.tsxファイルが長すぎるため、保守性を向上させるためにリファクタリングとコンポーネント分割を行いたい。[分割計画] 以下の3つのファイルにコードを分割してください:
src/components/pricing/PricingCard.tsx:単一のプランカードUIをレンダリングする。tier(プランデータ)をPropsとして受け取る。src/components/pricing/FaqSection.tsx:下部のよくある質問をレンダリングし、アコーディオンの開閉状態(useState)を含む。src/app/pricing/page.tsx:メインページとして残し、上記2つのコンポーネントをインポートし、データ取得ロジックを保持する���[実行要件]
- ステップバイステップで進め、まず
PricingCard.tsxの完全なコードを提供してください。- TypeScriptのInterface/Type定義が正しくエクスポートされ、共有されていることを確認してください。
- 既存のTailwindスタイルとアニメーションが完全に維持されていることを確認してください。
分割プロセスでの地雷回避
AIが分割後のコードを提供し始めたら、以下の点に注意してください:
1. Propsの受け渡し(Prop Drilling)
コンポーネントを分割すると、親ページ内の変数(例:const [isLoading, setIsLoading] = useState(false))が子コンポーネントで利用できなくなります。AIはこれらの変数をPropsとして渡す必要があります。もしAIが忘れていたら、「isLoadingをPricingCardにpropとして渡すのを忘れていない?」とリマインドしてください。
2. 絶対パス vs 相対パス
src/components/に分割すると、元のファイル内のimportパスが間違っている可能性があります。
AIが書いたimportを確認してください:
✅ import { AlertCircle } from "lucide-react";
✅ import { cn } from "@/lib/utils";
❌ import { cn } from "../../lib/utils";(Next.jsでは@/絶対パスを使用するのがベスト)
3. 一度に1つのことだけを行う
絶対ルール:リファクタリング中に新機能を追加しないでください! ボタンを分割しながら、同時にLoadingスピナーアニメーションを追加したい場合は、2ステップで行ってください。 ステップ1:分割。動作をテスト。 ステップ2:アニメーション追加。 これにより、いつでもGit Commitで安全なポイントに戻れるようになります。
定期的な大掃除のメリット
ファイルが300行を超えたらAIに「コンポーネント分割」を依頼する習慣を身につけると、以下のようなメリットがあります:
- AIのコーディング速度が向上(Tokenが減るため)。
- Bugが減少(状態が各コンポーネントに隔離されるため)。
- 自分でコードを読むのが楽しくなる。
これが、Vibe Codingで大規模な商業プロジェクトを長期的に維持する究極の秘訣です!
章のまとめ
- コアコンセプトと原理を理解
- 実装方法とテクニックを習得
- 一般的な問題と解決策に精通
- 実際のプロジェクトに適用可能
さらに読む
- 公式ドキュメントとAPIリファレンス
- GitHubのオープンソース例
- 技術書とオンラインコース
- コミュニティディスカッションと技術ブログ
実装例
基本例
# 完全な実装例を提供します
手順
- セットアップ: 開発環境の設定
- データ: 必要なデータの準備
- 実装: コア機能の構築
- テスト: 動作確認
- 最適化: パフォーマンスの向上
よくあるエラー
| エラー種別 | 原因 | 解決方法 | |-----------|------|---------| | コンパイル | 構文 | コードの構文を確認 | | 実行時 | 環境 | 依存パッケージの確認 | | 論理 | アルゴリズム | ステップごとのデバッグ | | パフォーマンス | 効率 | プロファイラーの使用 |
コード例
import sys
def main():
print("Hello, World!")
if __name__ == "__main__":
main()
参考資料
- 公式ドキュメント
- APIリファレンス
- オープンソース例
- コミュニティディスカッション