バイブコーディング時代、フロントエンドはどう書くべきか
はじめに
AI でフロントエンドを書くこと自体は、かなり当たり前になってきた。
ただ、その変化は単に「実装が速くなった」で終わらない。いま起きているのは、フロントエンドを書く人が増えたことだと思う。経験が浅くても画面は作れるし、試作も速い。これは良い変化だ。
一方で、問題もかなり分かりやすい。
- 共通コンポーネントがあるのに使われない
- 似た UI を別の場所でまた作ってしまう
- 既存の API ラッパーや state 管理を使わず、画面ごとに似た処理を書く
- AI が repo の中にある共通部品を見逃す
- 複数人が並行に AI で作ると、似た構造が何個も生まれる
つまり、いま問題になっているのは「作れるかどうか」ではなく、既存資産を見つけて正しく使えるかどうかだ。
この記事では、バイブコーディング時代のフロントエンド設計を、
- 何を問題として捉えるべきか
- どういう構造が AI と人間の両方にとって扱いやすいか
- レビューでは何を見ればよいか
という順番で整理したい。
バイブコーディングで何が起きたか
バイブコーディングが広がると、フロントエンドは「一部の詳しい人だけが書くもの」ではなくなる。これは強い。
ただし、ここで起きる問題はかなり本質的だ。
作れることと、既存の設計や部品を正しく使えることは別である。
たとえば、チームに次のような資産がすでにあるとする。
src/
components/
ui/
Button.tsx
Modal.tsx
Input.tsx
features/
users/
components/
UserTable.tsx
lib/
api/
client.ts
hooks/
useToast.ts
この状態でも、AI や経験の浅い開発者は次のようなことをしがちだ。
- 新しい
PrimaryButton.tsxを別で作る -
fetch('/api/...')を画面内に直接書く - 既存の
Modalではなく画面ローカルのダイアログを新規で作る - 通知のたびに
alert()や画面独自 UI を書く
ここで起きている問題は、「共通化が足りない」ではない。むしろ逆で、共通化されていても見つからないことが問題になる。
なので、バイブコーディング時代のフロントエンドで本当に考えるべきなのは、再利用性そのものより 発見可能性 だと思う。
以前のフロントエンド設計は何を最適化していたか
これまでのフロントエンド設計は、かなりの部分で 人間どうしのレビューと保守 を最適化していた。
- コンポーネントを責務ごとに分ける
- ロジックを Hook に切り出す
- util に共通処理を集める
- 型を別ファイルに出す
- レビューしやすいように責務を小さくする
この考え方自体は今でも大事だ。
ただ、その前提には暗黙に「詳しい人がレビューしてくれる」「既存の資産やルールをなんとなく知っている」という条件があった。
人間だけで書いていた頃は、それでも回った。けれど、AI が実装に深く入ってくると、この前提は崩れやすい。
- AI は repo の全体構造を常に深く理解しているわけではない
- 人間側も、知らない領域の資産は使えない
- 抽象化されすぎていると、どこを見ればよいか分からない
つまり、以前は人間の理解力で吸収できていた曖昧さが、いまはそのまま問題になる。
これから問題になるのは、再利用性より発見可能性
昔から「共通コンポーネントを作ろう」「ロジックを共通化しよう」と言われてきた。
でも、バイブコーディング時代はそれだけでは足りない。
重要なのは、
- それが存在すること
- それが見つかること
- それが選ばれること
- それを使う理由が分かること
まで含めて設計されていることだ。
悪い例: 技術別に散っていて、何を見ればいいか分からない
src/
components/
UserTable.tsx
hooks/
useUsers.ts
utils/
userColumns.ts
types/
user.ts
pages/
users.tsx
この構成でも動く。
ただ、「users を直したい」と思ったときに、見るべき場所が散る。AI にとっても人間にとっても、文脈が飛びやすい。
よい例: 機能単位で寄せて、見る範囲を狭くする
src/
features/
users/
page.tsx
api.ts
schema.ts
components/
UserTable.tsx
hooks/
useUsers.ts
utils/
userColumns.ts
この構成の良さは、「設計として美しい」ことではない。
少ないコンテキストで users に関係するものがまとまって見えることだ。
バイブコーディング時代に必要なのは、この「まずここを見ればよい」が明確な構造だと思う。
バイブコーディング時代、フロントエンドはどう書くべきか
ここからは、実践寄りに整理する。
1. 関連するものは近くに置く
まず大事なのは局所性だ。
- feature 単位で寄せる
- Server / Client の責務を分ける
- 関心の近いコードを近くに置く
要するに、AI も人間も少ない範囲を見れば済むようにする。
2. 使ってほしいものは、見つかる形で置く
共通コンポーネントを作るだけでは足りない。見つからなければ使われない。
たとえば次のような工夫はかなり効く。
- 名前で用途が分かる
- 置き場所に一貫性がある
- 代表的な利用例が近くにある
- 「まずここを見ろ」という入口がある
- 共通 UI 一覧や Storybook がある
例: 共通 UI の入口を作る
src/
components/
ui/
Button.tsx
Input.tsx
Modal.tsx
index.ts
docs/
frontend-rules.md
index.ts や docs に「共通 UI はまずここを見る」と書いてあるだけでも、再利用率はかなり変わる。
3. 抽象化しすぎない
AI を使うと、見た目をきれいにしたくなって、すぐに Hook や util に逃がしたくなる。
でも、抽象化しすぎると逆に困る。
- どこにあるのか分からない
- 使い方が分からない
- 依存関係が見えない
- 結果として誰も使わない
悪い例: 複雑さを Hook の中に隠しているだけ
export function CheckoutPage() {
const {
items,
coupon,
setCoupon,
total,
discountedTotal,
isSubmitting,
error,
handleSubmit,
handleRemoveItem,
handleIncreaseItem,
handleDecreaseItem,
} = useCheckoutPage()
return <CheckoutView /* ... */ />
}
これで useCheckoutPage() の中に
- フォーム状態
- API 呼び出し
- 金額計算
- 通知
- エラー処理
が全部入っていたら、責務は減っていない。
よい例: 再利用境界があるものだけ外に出す
export function CheckoutPage() {
const [coupon, setCoupon] = useState("")
const { items, removeItem, increaseItem, decreaseItem } = useCart()
const { submitOrder, isSubmitting, error } = useSubmitOrder()
const total = items.reduce((sum, item) => sum + item.price * item.quantity, 0)
const discountedTotal = calculateDiscountedTotal(total, coupon)
async function handleSubmit() {
await submitOrder({ items, coupon })
}
return <CheckoutView /* ... */ />
}
この形なら、
- カート操作は
useCart - 送信処理は
useSubmitOrder - 画面専用 state は画面の近く
- 純粋な計算は関数化
と分かれる。
4. ルールは頭の中ではなく repo に置く
AI に少ない文脈で正しい方向へ寄ってほしいなら、前提は repo に置いたほうがよい。
たとえば、こういうルールは置く価値がある。
# frontend-rules.md
- feature 単位で配置する
- 新しく作る前に既存部品を探す
- 共通 UI は src/components/ui を最初に確認する
- Server First を原則にする
- 新規依存追加には理由を書く
これは精神論ではなく、AI が迷わないための補助線だ。
何をレビューするべきか
GitHub Docs の AI コードレビューは、単に「コードを読む」話ではなく、次の 8 つの観点で整理されている。
- functional checks
- context and intent
- code quality
- dependencies
- AI-specific pitfalls
- collaborative reviews
- automate what you can
- keep improving your workflow
ただ、このままだと少し抽象的なので、フロントエンド向けに言い換えるとこうなる。
1. まず本当に動くかを確認する
最初に見るべきなのは、「きれいかどうか」ではなく「動くかどうか」だ。
- ビルドは通るか
- 型チェックは通るか
- テストは落ちていないか
- 新しい warning が増えていないか
- 画面として最低限表示されるか
たとえば、ボタンの見た目は正しくても、クリック時に hydration error が出るなら、その時点でレビュー対象としては不十分になる。
フロントエンドでは特に、次のような確認が最初に欲しい。
-
npm run build/pnpm build tsc --noEmit- lint
- 主要画面の簡単な動作確認
- 既存テストの通過
つまりここは、「このコードはレビューに値する最低ラインを満たしているか」を見る工程だ。
2. そもそも正しい問題を解いているかを確認する
AI が書いたコードは、見た目はもっともらしくても、そもそも解いている問題がズレていることがある。
ここで見たいのは、次のようなことだ。
- この変更は、本当に依頼した要件を満たしているか
- 既存の画面設計やアーキテクチャに合っているか
- その場しのぎの実装になっていないか
- README や設計ドキュメント、既存の実装例と矛盾していないか
たとえば「検索フォームを追加して」と依頼したのに、AI が勝手に state 管理の方式まで変更していたら、それは実装力の問題ではなく、意図のズレだ。
レビューでは「正しく書けているか」の前に、
そもそも正しい方向に書いているか を見たほうがいい。
3. 人間が保守できるコードになっているかを見る
AI は動くコードを出すのは得意だが、読みやすく保守しやすいコードを常に出すとは限らない。
ここでは、次のような点を見る。
- 命名は分かりやすいか
- コンポーネントや関数の責務が過剰に混ざっていないか
- 1 回しか使わないのに抽象化しすぎていないか
- コメントがないと意図が分からない構造になっていないか
- 後から修正するより、いっそ書き直したほうが早いコードになっていないか
たとえば useCheckoutPage() という Hook に、
フォーム state、API 呼び出し、金額計算、通知、エラー処理が全部入っていたら、
見た目はきれいでも保守はしづらい。
レビューでは「短いコード」より、
意図が追いやすいコードか を見たほうがいい。
4. 新しく増えた依存は本当に必要かを見る
AI は気軽にライブラリを追加しがちだ。
でも、依存追加は見た目以上に重い。
レビューでは次を確認したい。
- その package は本当に存在するか
- ちゃんと保守されているか
- ライセンス的に問題ないか
- 既存の依存で代替できないか
- その 1 機能のために追加するほどの価値があるか
フロントエンドでは、
「小さな UI のために別ライブラリを追加する」
「日付 formatting のためだけに重い package を入れる」
といったことが起きやすい。
AI の提案する dependency は、
便利そうだから入れる ではなく、
なぜ今この repo に必要か で判断したい。
5. AI っぽいミスを疑う
ここは AI 時代ならではのレビュー観点だ。
GitHub Docs が挙げている例を、フロントエンド向けに言い換えると次のようになる。
- 存在しない API や prop を使っていないか
- プロジェクトの制約を無視していないか
- 「それっぽい」けど実は間違ったロジックになっていないか
- failing test を直す代わりに、削除や skip でごまかしていないか
- edge case を無視して happy path だけ通していないか
たとえば、
存在しない UI コンポーネントを import している、
server component で使えない hook を使っている、
エラー時の挙動を考慮していない、
といったものは典型的な AI 的ミスだ。
ここは「見た目が正しいか」ではなく、
いかにも AI がやりそうな雑な近道を踏んでいないか を見る。
6. 一人で閉じず、チームの視点を入れる
GitHub Docs では collaborative reviews も独立した観点として挙げられている。
これは単に「誰かに見てもらおう」という精神論ではなく、
AI 生成コードほど、別の視点で見たほうが事故を拾いやすいからだ。
たとえば、
- UI は問題なく見えるが、アクセシビリティが壊れている
- 要件は満たしているが、別画面の共通部品を使うべきだった
- 実装は通るが、運用中の設計ルールとズレている
といったことは、別の視点が入ると見つかりやすい。
AI を使うほど、レビューは「書いた本人が見直す」だけでは弱くなりやすい。
7. 機械で見られるものは機械に寄せる
毎回人間が同じ確認を繰り返すのは弱い。
レビューで毎回見るべきことのうち、
- 型チェック
- lint
- unit test
- E2E の最低限
- dependency 脆弱性確認
のようなものは、自動化できるなら自動化したほうがいい。
AI 時代は差分が増えやすいので、
人間は「自動では拾いにくい判断」に集中したほうがいい。
8. レビューのやり方自体も改善していく
GitHub Docs は最後に workflow 自体を改善していくことも挙げている。
これはフロントエンドだと、たとえば次のような話になる。
- よく起きる AI のミスを checklist 化する
- 「まず既存コンポーネントを探す」ことをルールにする
- 良い実装例を repo に残す
-
CLAUDE.mdや repo instructions に前提を書く - PR テンプレートに確認項目を入れる
レビューは 1 回ごとに終わる作業ではなく、
チームが AI とどう付き合うかを改善していく仕組み として考えたほうがいい。
要するに何を見ればいいのか
フロントエンドの AI 生成コードをレビューするとき、
最低限見るべきことを絞るなら、私は次の 5 つでよいと思う。
- 既にあるものを使えているか
- 同じものをもう一個作っていないか
- 触らなくていい場所まで触っていないか
- エラー・0件・読み込み中で壊れないか
- 後から見た人が意図を追えるか
この 5 つを見られるだけでも、
AI 生成コードのレビューとしてはかなり強い。
おわりに
バイブコーディング時代のフロントエンドで重要なのは、きれいに分割することそのものではない。
もちろん、コンポーネント分割も Hook も state 設計も大事だ。けれど、それだけでは足りない。
これから重要になるのは、
- 使うべきものが見つかること
- 少ない文脈で正しい方向に寄れること
- 既存資産を再利用しやすいこと
- 壊れ方まで含めて確認しやすいこと
だと思う。
つまり、バイブコーディング時代にフロントエンドが目指すべきなのは、
きれいに抽象化されたコード だけではなく、
AI と人間の両方にとって、発見しやすく、再利用しやすく、壊れにくい構造 なのだと思う。
Discussion