フロントとバックを分業しているチームに入ったとき、「これはフルスタックをやっていないと気づきにくいな」と思う場面がいくつかあった。逆に、フルスタックをやっていることで陥りやすい罠もある。設計で意識していることを、失敗談も交えて書いてみる。
API 設計は「誰が使うか」から考える
バックエンドエンジニアが「できること」ベースで API を設計しがちだと感じる。自分がバックエンドを書くとき、フロントも自分でやる前提があると「このレスポンス構造、画面から使いにくいな」という感覚がリアルに持てる。
以前、一覧 API で全フィールドを返すようにしていたが、フロント側で必要なのは id・title・thumbnail だけで、重いフィールドを毎回引いていたことに気づいたのはパフォーマンス計測してからだった。
// ❌ なんでも返す汎用エンドポイント
GET /api/posts → { id, title, body, thumbnail, author, tags, metadata, ... }
// ✅ ユースケースに合わせた設計
GET /api/posts?fields=id,title,thumbnail
GET /api/posts/summary // 一覧専用の軽量レスポンス
「フロントが欲しいもの」をバックエンドが知っているかどうかで API の使いやすさは大きく変わる。
状態管理の責務をどこに置くか
自分の判断基準はざっくりこうだ。
- サーバー状態(DB や外部 API から取得するデータ)→
React QueryやSWRに任せる。自前の状態管理に持ち込まない - UI の状態(モーダルの開閉、フォームの入力値)→
useStateでローカルに持つ - 複数コンポーネントをまたぐ UI 状態→
ZustandやContextに上げる
以前やらかしたのが、サーバーから取得したデータを Redux に突っ込んで、更新のたびに手動で同期する処理を書いていたこと。React Query に切り替えたら、キャッシュ管理・リフェッチ・エラーハンドリングがほぼ自動になって、コードが半分くらいになった。「状態管理ライブラリ」と「サーバー状態管理ライブラリ」は別物だと理解できていなかったのが原因だった。
「何をどこに置くか」の判断基準
バックエンドとフロントエンドを行き来していると「このロジック、どこに書くべきか」という場面が頻繁に出てくる。自分の基準はシンプルで、セキュリティに関わるものと、信頼できるデータが必要なものはサーバーに置く。
// フロントのバリデーション → UX のため(あくまでプレビュー)
const schema = z.object({ email: z.string().email() });
// バックエンドのバリデーション → セキュリティのため(必須)
// フロントのバリデーションを通ったからといって信頼しない
価格計算・ポイント付与・権限チェックはすべてサーバー側に書く。フロント側での計算はあくまでプレビュー表示用と割り切っている。
フルスタックの「全部わかる」を「全部ごちゃまぜ」にしない
フロントとバックを分業しているチームに入ったとき、コミュニケーションコストが自分の想像より高かった。フルスタックで一人でやっているとこのコストがゼロなので自由に設計を変えられる。ただ、一人だと「フロントに引っ張られすぎた API」や「バックエンドの都合に寄りすぎた状態管理」を作ってしまいがちだ。
全部わかるからこそ、意識的に役割を分けて設計する習慣が必要だと感じている。API 契約を OpenAPI で明文化する、フロントとバックを分けてレビューする視点を持つ——これらはチームの大小にかかわらず有効だ。