設計レビューの観点 — 何をチェックし、どう指摘するか
この章の目次開く
設計レビューは、設計書の誤字を探す場ではありません。実装に入る前に、要件の抜け、責務の曖昧さ、変更に弱い構造、運用時に困る点を見つけるための場です。
レビューの質が低いと、「なんとなく良さそう」で実装が進み、後から手戻りが発生します。逆に、レビューが細かすぎたり攻撃的だったりすると、設計者が防御的になり、議論が進みません。
この章では、設計レビューで見る観点と、相手に伝わる指摘の書き方を整理します。
学習者設計レビューって、何を見ればいいのか毎回迷う。コードレビューより抽象的で、指摘していいのか自信がない…
先生設計レビューは「好み」を言う場ではなく、「この設計で要求を満たせるか」「変更や障害に耐えられるか」を確認する場だよ。観点を持って見れば、指摘はかなり具体的になる。
設計レビューで見る全体像
設計レビューでは、設計書そのものだけでなく、要件・実装・運用とのつながりを見ます。
レビュー観点は、大きく分けると次の6つです。
| 観点 | 確認すること |
|---|---|
| 要件との整合 | 必要な機能・非機能要件を満たしているか |
| 責務の分離 | 画面、API、Service、DBの役割が混ざっていないか |
| データ設計 | 正規化、制約、履歴、削除方針が妥当か |
| 例外・失敗 | エラー、リトライ、部分失敗、権限不足を扱えるか |
| 変更容易性 | 仕様変更時に触る場所が限定されるか |
| 運用・監視 | ログ、メトリクス、調査方法が考えられているか |
観点1: 要件との整合を見る
まず見るべきは、設計が要件を満たしているかです。ここを飛ばして構成や命名を見ても、本質的なレビューになりません。
確認する質問は次のようなものです。
- 機能要件に書かれたユーザー操作が、画面・API・DBのどこかに対応しているか
- 非機能要件(性能、セキュリティ、可用性、監査ログなど)が設計に反映されているか
- 権限ごとの差分が画面・APIの両方で考慮されているか
- 要件にない前提を、設計側で勝手に足していないか
たとえば「管理者だけがユーザーを停止できる」という要件があるなら、画面のボタン表示だけでは不十分です。API側の認可、監査ログ、停止済みユーザーのログイン制御まで設計に現れているかを確認します。
観点2: 責務の境界を見る
設計レビューでは、責務の境界が曖昧な場所を重点的に見ます。責務の境界が曖昧だと、実装時に判断が分かれ、同じロジックが複数箇所に散らばります。
よく見る境界は次のとおりです。
| 境界 | レビューで見ること |
|---|---|
| 画面とService | UIに業務ルールが入りすぎていないか |
| ServiceとRepository | DBアクセスと業務判断が混ざっていないか |
| フロントとバックエンド | 信頼できない入力をフロントだけで検証していないか |
| APIとDB | API都合の形式がDB設計を歪めていないか |
| 同期処理と非同期処理 | 待つべき処理と後でよい処理が分けられているか |
画面遷移図と画面設計 で扱ったように、UIとロジックの境界は特に崩れやすい場所です。レビューでは「この判断は画面固有か、業務ルールか」を確認します。

観点3: データと状態の変化を見る
システムは、画面よりもデータの寿命が長く残ります。画面は作り直せても、DBに入ったデータは簡単には消せません。そのため、設計レビューではデータの状態変化を必ず確認します。
確認するポイントは次のとおりです。
- ステータスの種類と遷移条件が明確か
- 削除は物理削除か論理削除か
- 履歴や監査ログが必要な操作はどれか
- 重複作成や二重送信に耐えられるか
- 外部サービスと状態がずれたときに復旧できるか
原則違反のコード
注文キャンセルの条件がAPIハンドラに直書きされています。
// ❌ 状態遷移のルールがAPIに埋もれている
export async function cancelOrder(orderId: string, userId: string): Promise<void> {
const order = await db.order.findUnique({ where: { id: orderId } });
if (!order) {
throw new Error('ORDER_NOT_FOUND');
}
if (order.userId !== userId) {
throw new Error('FORBIDDEN');
}
if (order.status === 'shipped' || order.status === 'delivered') {
throw new Error('CANNOT_CANCEL');
}
await db.order.update({
where: { id: order.id },
data: { status: 'cancelled' },
});
}この形だと、管理画面、バッチ処理、外部連携でも同じキャンセル可否をコピーしがちです。レビューでは「状態遷移のルールはどこに集約されていますか?」と聞けます。
改善したコード
状態遷移を明示的な関数に切り出します。
type OrderStatus = 'pending' | 'paid' | 'shipped' | 'delivered' | 'cancelled';
type Order = {
id: string;
userId: string;
status: OrderStatus;
};
function canCancelOrder(order: Order): boolean {
return order.status === 'pending' || order.status === 'paid';
}
class OrderService {
constructor(private readonly orders: OrderRepository) {}
async cancelOrder(orderId: string, userId: string): Promise<void> {
const order = await this.orders.findById(orderId);
if (!order) {
throw new Error('ORDER_NOT_FOUND');
}
if (order.userId !== userId) {
throw new Error('FORBIDDEN');
}
if (!canCancelOrder(order)) {
throw new Error('CANNOT_CANCEL');
}
await this.orders.updateStatus(order.id, 'cancelled');
}
}状態遷移のルールが canCancelOrder に集約されるため、レビューでもテストでも確認しやすくなります。さらに厳密にするなら、ステータス遷移表を設計書に載せて、コードと対応づけます。
観点4: 失敗時の振る舞いを見る
設計レビューで差が出るのは、失敗時の確認です。正常系だけなら多くの設計はきれいに見えます。実際のシステムでは、外部APIが落ちる、DB更新の途中で失敗する、メール送信だけ失敗する、ユーザーが二重クリックする、といったことが起きます。
失敗時のレビュー質問は次のように具体化できます。
- 外部APIがタイムアウトしたら、ユーザーには何を見せるか
- リトライしてよい処理か、してはいけない処理か
- 一部だけ成功した場合、どう補償するか
- 同じリクエストが2回来た場合、同じ結果になるか
- エラー調査に必要なログは残るか
観点5: 変更しやすさを見る
設計は、今の仕様だけに合わせて作るとすぐ壊れます。ただし、未来を予測しすぎた抽象化も危険です。レビューでは、「近い将来ありそうな変更」に対して、どこを触ることになるかを確認します。
変更シナリオを1つ置くと、設計の弱さが見えやすくなります。
| 変更シナリオ | 見ること |
|---|---|
| 会員ランクが増える | 分岐の追加が1か所で済むか |
| 決済手段が増える | 既存の注文処理を壊さず追加できるか |
| 管理者権限が細分化される | 権限判定が画面ごとに散らばっていないか |
| 監査ログが必須になる | 重要操作の入口が集約されているか |
| 外部APIを差し替える | 具体実装への依存が閉じているか |
これは SOLID原則 で扱った「変更の影響範囲を小さくする」という考え方そのものです。
学習者将来の変更に備えるって、どこまで考えればいいの?考えすぎると設計が重くなりそう。
先生全部の未来に備える必要はないよ。レビューでは「この機能で現実的に起きそうな変更」を2〜3個だけ置いて、触る場所が爆発しないかを見る。それで十分実用的な判断になる。
指摘の書き方
レビューの指摘は、正しくても伝え方が悪いと議論になりません。設計レビューでは、相手の人格や能力ではなく、設計上のリスクに焦点を当てます。
悪い指摘と良い指摘を比べます。
| 避けたい指摘 | 伝わりやすい指摘 |
|---|---|
| これは微妙です | この設計だと、決済失敗時に注文だけ作成済みになる可能性があります |
| Serviceが汚いです | 注文可否の判定が画面とServiceに分散しているため、ルール変更時に修正漏れが起きそうです |
| なんでこうしたんですか | この案を選んだ前提を確認したいです。外部APIのタイムアウトは何秒想定ですか |
| 普通はこうしません | 将来、支払い方法が増える予定があるなら、分岐をStrategyに寄せる方が変更範囲を小さくできます |
指摘には優先度も付けます。すべてを同じ強さで言うと、相手は何から直せばよいか分かりません。
- must — 要件未達、セキュリティリスク、データ不整合など、直さないと実害が大きい
- should — 変更に弱い、責務が曖昧、テストしづらいなど、直す価値が高い
- nit — 命名や表現の改善など、品質は上がるがブロッカーではない
- question — 前提確認。いきなり修正要求にしない
レビューを受ける側の準備
良いレビューは、レビューを出す前の準備でかなり決まります。設計者は、レビュー相手が判断できる材料を先に置いておきます。
レビュー依頼には、少なくとも次の情報を含めます。
- 何を実現したい設計か
- レビューしてほしい範囲
- まだ迷っている点
- 採用しなかった案と理由
- 特に見てほしいリスク
設計書にすべてを書き込む必要はありませんが、前提が見えないレビューは「質問だけで終わる」ことが多くなります。

よくあるハマりどころ
好みの議論になる
「この構成が好き」「この名前は嫌い」だけだと、合意できません。好みを言いたくなったら、「その選択によって何が変わるのか」に言い換えます。変更範囲、テストしやすさ、障害時の調査しやすさなどに落とすと、議論が前に進みます。
レビュー範囲が大きすぎる
100ページの設計書を一度にレビューしても、深く見られません。画面遷移、API、DB、エラー設計のように観点ごとに分けると、指摘の質が上がります。
レビューが遅すぎる
実装直前まで設計レビューをしないと、指摘されても直せません。大きな設計は、粗い段階で一度レビューし、詳細化した後でもう一度見る方が手戻りを減らせます。
指摘を全部反映しようとする
レビューコメントはすべて正しいとは限りません。前提が違う指摘、優先度が低い指摘、今回のスコープから外れる指摘もあります。受ける側は、対応する・しない・別チケットにする、の判断を明確に返します。
ちゃんと使うためのポイント
- 設計レビューでは、要件との整合、責務の境界、データ状態、失敗時の振る舞い、変更容易性、運用性を見る。
- 正常系だけでなく、権限不足、外部API失敗、二重送信、部分失敗を確認する
- 「この変更が来たらどこを触るか?」という質問で、責務分割の弱さを見つける
- 指摘は、問題点・起きるリスク・確認したい前提をセットで書く
- コメントの優先度を分ける。must、should、nit、question を混ぜない
- レビュー依頼では、見てほしい範囲、迷っている点、採用しなかった案を先に示す
設計は一度書いて終わりではありません。レビューで前提をそろえ、実装で分かったことを戻し、運用で見えた課題を次の設計に反映していくものです。ここまでの章で扱った要件定義、API、DB、エラー、ディレクトリ構成、設計原則、画面遷移を、レビューの場でつなげて確認できれば、チームの設計力は着実に上がっていきます。
参考リンク
- Google Engineering Practices: How to do a code review — レビュー観点とコメントの考え方
- The C4 model for visualising software architecture — アーキテクチャを段階的に図解するための定番モデル
- Architectural Decision Records — 設計判断を記録するADRのリソース集