engineering-backend-architect について
システム設計、データベース、API、セキュリティ、信頼性、性能を扱うバックエンドエンジニア向けの設計ガイドです。判断ルールに加え、既存コードの調査手順、検証チェックリスト、ヘルスチェックと SQL スキーマ解析のスクリプトを含みます。
主な機能
- 01システム・データベース設計の判断ルール
- 02API・セキュリティ・信頼性の指針
- 03性能改善とスケーリング基準
- 04設計変更の検証チェックリスト
- 05ヘルスチェック・スキーマ解析スクリプト
活用シーン
- 01サービス境界やデータベーススキーマの設計
- 02API・セキュリティ・性能設計のレビュー
- 03本番環境での一般的な障害の調査
- 04既存バックエンドコードの把握
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ peterhdd/ agent-skills --skill engineering-backend-architectインストール後、Claude Code で/engineering-backend-architectを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/api-patterns.mdcode-examples.mddatabase-patterns.mddistributed-patterns.mdinfrastructure.mdscripts/analyze_schema.pycheck_api_health.sh詳細
バックエンドアーキテクチャガイド
概要
このガイドでは、スケーラブルなバックエンドシステムの設計、データベースアーキテクチャ、API 開発、クラウドインフラストラクチャのパターンを説明します。データスキーマ、サービス境界、キャッシュ戦略、セキュリティアーキテクチャ、パフォーマンス最適化に関する判断を行う際に活用してください。
アーキテクチャの判断基準
システム設計
- マイクロサービスとモノリスのどちらを選ぶか検討する際は、チームがすでに本番環境で複数のサービスを運用している場合を除き、モジュラーモノリスから始めてください。マイクロサービスはデプロイと可観測性のコストを増やし、小規模なチームの速度を低下させるためです。
- データベーススキーマを設計する際は、一般的な WHERE 句(例:
WHERE is_active = true)で絞り込むカーディナリティの高い列に部分インデックスを追加してください。フルテーブルインデックスは、クエリが参照しない行に I/O を浪費するためです。 - API のバージョニングでは、パブリック API には URL プレフィックスによるバージョニング(
/v1/、/v2/)を、内部 API にはヘッダーによるバージョニングを使用してください。URL プレフィックスのほうが外部の利用者に見つけやすく、キャッシュしやすいためです。 - イベント駆動システムを構築する際は、すべてのイベントに一意の冪等性キーとスキーマバージョンフィールドを含めてください。これにより、コンシューマーは安全に再試行し、スキーマの進化に対応できます。
信頼性
- 下流サービスが不安定な場合は、呼び出しをサーキットブレーカー(例:Node.js の
opossum)でラップしてください。5 回連続で失敗したらオープンし、30 秒後にハーフオープンにし、3 回成功したらクローズします。 - バックアップ戦略を設計する際は、継続的な WAL アーカイブと日次のベースバックアップを組み合わせ、復元を毎週ステージングデータベースでテストして RTO/RPO の目標を検証してください。
- ヘルスチェックを実装する際は、
/health/live(プロセスが稼働中)と/health/ready(依存関係に到達可能)を別々のエンドポイントとして公開してください。Kubernetes のライブネスプローブとレディネスプローブは、それぞれ異なる目的を持つためです。
パフォーマンス
- キャッシュに Redis を使用する場合は、すべてのキーに明示的に TTL を設定し、書き込みレイテンシーが読み取りの一貫性より重要でない限り、ライトスルーではなくキャッシュアサイド(遅延読み込み)を使用してください。
- 大規模なデータセットを処理する際は、OFFSET が行をスキャンして破棄し、ページが進むほど線形に性能が低下するため、OFFSET/LIMIT ではなくカーソルベースのページネーションを使用してください。
- 新しいサービスを設計する際は、ステートレスにして、どのインスタンスでも任意のリクエストを処理できるようにしてください。セッションデータは Redis またはデータベースに保存し、ロードバランサーの背後にインスタンスを追加するだけで水平スケーリングできるようにします。
- 新しいクエリパスを追加する際は、マージ前に
EXPLAIN ANALYZEを実行し、1 万行を超えるテーブルでシーケンシャルスキャンを行うクエリは却下してください。インデックスを追加するか、クエリを書き換えてください。 - キャッシュ層を導入する際は、古いデータの読み取りを防ぐため、実装前に設計ドキュメントで明示的な無効化戦略(TTL、イベント駆動のパージ、またはバージョン付きキー)を定義してください。
セキュリティ
- 認証を設計する際は、ある層が侵害された場合のラテラルムーブメントを防ぐため、API ゲートウェイでトークンを検証し、さらに各下流サービスでも検証することを必須にしてください。
- 認証を実装する際は、有効期間の短い JWT(15 分)を発行し、不透明なリフレッシュトークンをサーバー側に保存してください。盗まれた JWT は、有効期限が切れる前に失効できないためです。
- サービスの IAM ロールを設定する際は、権限をゼロにした状態から始め、必要な特定のアクションだけを追加してください。クラウドプロバイダーのアクセスアナライザーレポートを使い、四半期ごとに未使用の権限を見直して削除してください。
- データを保存する際は、保存時に AES-256(またはプロバイダー管理の KMS キー)で暗号化し、すべてのサービス間通信で TLS 1.2 以降を強制してください。ロードバランサーで平文接続を拒否してください。
- ユーザー入力を受け付ける際は、スキーマバリデーター(例:Zod、Joi)を使って API 境界で検証とサニタイズを行い、必ずパラメーター化クエリを使用してください。SQL クエリや NoSQL クエリにユーザー入力を直接埋め込んではいけません。
モニタリング
- 本番環境にデプロイする際は、すべてのサービスがレイテンシのヒストグラムとエラー率のカウンターをメトリクスシステムに出力するようにします。負荷テストで測定したベースラインの2倍をp95レイテンシが超えた場合にアラートを設定します。
- 外部またはユーザーが指定したURLからのヘルスチェック応答は、信頼できないテレメトリとして扱います。診断にはステータスコード、レイテンシ、ヘッダーを使用し、後続のアクションを決定する際に応答本文のテキストに依存しないでください。
スケーリングのしきい値
- 単一のPostgreSQLノード:読み取り約10k QPS、書き込み約5k QPSです。読み取りが多い場合(読み取りが80%超)、まずはリードレプリカを追加します。
- コネクションプーリング(PgBouncer):接続数が200を超える場合に必須です。PostgreSQLの接続1つにつき約10MBのRAMを使用します。
- シャーディング:単一ノードの書き込みQPSが飽和した場合、またはストレージが約5TBを超える場合に必須です。カーディナリティが最も高く、クエリ頻度が最も高い列をシャードキーに選びます。
- Redisキャッシュ:同一のクエリが1分間に100回を超えて実行される場合に追加します。明示的なTTLを設定したキャッシュアサイドパターンを使用します。ヒット率が80%未満の場合、キャッシュは役に立っていません。キー設計を修正するか、キャッシュを削除します。
- メッセージキュー:単純なジョブ(<256KB、少なくとも1回の配信)にはSQS、ルーティングや優先度が必要な場合(<10k msg/sec)にはRabbitMQ、ストリーミング(>10k msg/sec、再生、ファンアウト)にはKafkaを使用します。
- ロードバランサー:<1k QPSでは単一インスタンスを使用します。1k-50k QPSではALBとオートスケーリング(最小2、CPU >60%でスケール)を使用します。>50k QPSでは、キャッシュ可能な応答にCDNを追加します。
- APIゲートウェイのレート制限:ユーザーあたりデフォルトで100 req/minです。書き込みは10-30 req/min、高コストな操作(検索、エクスポート)は5 req/minにします。
データ移行のルール
- 100万行を超えるテーブルを変更する場合は、オンラインスキーマ変更ツール(pt-online-schema-change、gh-ost)を使用します。本番環境の高負荷なテーブルに対して、直接
ALTER TABLEを実行してはいけません。 - 列を追加する場合は、NULLを許可するか、デフォルト値を指定します。デフォルト値のないNOT NULL列を追加すると、バックフィルの間、テーブルがロックされます。
- 列名を変更する場合は、expand-migrate-contractを使用します。新しい列を追加 → デュアル書き込み → 読み取りを移行 → 古い列を削除します。稼働中のシステムで直接名前を変更してはいけません。
- 1,000万行を超えるテーブルにインデックスを追加する場合は、書き込みのロックを避けるために
CREATE INDEX CONCURRENTLY(PostgreSQL)を使用します。
自己検証プロトコル
バックエンドの変更を設計または実装した後、次の項目を確認します。
- 本番環境に近いデータ量で、新規または変更したすべてのクエリに対して
EXPLAIN ANALYZEを実行します。1万行を超えるテーブルでのシーケンシャルスキャンは許容しません。 - 新しいエンドポイントごとに、有効な入力(200)、認証なし(401)、不適切なロール(403)、無効な入力(400)、および想定QPSの10倍での負荷テストを実施します。
- 下流の依存サービスを停止してサーキットブレーカーを検証し、障害が連鎖するのではなく、サービスが適切に縮退する(キャッシュデータまたは意味のあるエラーを返す)ことを確認します。
- 環境固有の値(URL、認証情報、機能フラグ)がすべて、ハードコードされた文字列ではなく環境変数から取得されることを確認します。
- エンドポイントがクライアントに必要な量を超えるデータを返さないことを確認します。過剰取得(IDだけが必要なのにオブジェクト全体を返す)や、上限のないクエリ(LIMITの欠落)がないか確認します。
- 本番環境と同じサイズのデータのコピーに対して、データベースのマイグレーションを順方向と逆方向の両方で実行します。マイグレーションに30秒を超える場合は、バックグラウンドジョブとして実行する必要があります。
障害からの復旧
- クエリが突然遅くなった場合:
pg_stat_statementsでクエリを確認します。EXPLAIN ANALYZEを実行します。よくある原因は、インデックスの不足(テーブルがしきい値を超えて増加)、肥大化したテーブル(VACUUM ANALYZEを実行)、ロック競合(pg_locksを確認)、古いクエリプラン(テーブルに対してANALYZEを実行)です。 - コネクションプールが枯渇した場合:リークした接続(クエリが終了しても閉じられない接続)がないか確認します。根本原因の修正中は、一時的にプールサイズを増やします。接続タイムアウト(最大待機時間は 5s)を設定し、接続の取得に 1s を超えた場合はすべてログに記録します。
- デプロイ後にキャッシュスタンピードが発生した場合:デプロイによってすべてのキャッシュキーが同時に無効化された場合は、stale-while-revalidate を実装するか、TTL にジッター(基準 TTL の +/- 20% のランダム値)を追加します。
- イベントコンシューマーの処理が遅れている場合:コンシューマーのスループットとプロデューサーのレートを確認します。コンシューマーが CPU バウンドの場合は、並列コンシューマーを追加します。I/O バウンドの場合は、バッチ処理します。バックログが 1 時間を超える場合は、古いイベントをスキップすることを検討します(後で追いつけるように、冪等性キーを使用します)。
- サービスが OOM によって強制終了された場合:ヒープの使用状況をプロファイリングします。よくある原因は、上限のないインメモリーキャッシュ、処理のためにデータセット全体をメモリーに読み込むこと、またはコネクションプールサイズ * 接続あたりのメモリー使用量がコンテナーの上限を超えることです。ストリーミング/ページネーション、キャッシュのエビクションポリシー、または根本原因を修正する間の一時的なコンテナーメモリー増加によって対処します。
既存のコードベースの把握
既存のバックエンドコードベースに参加するときは、次の手順を実施します。
- サービスをローカルで実行する(10 分)— すべての依存関係(DB、キャッシュ、キュー)を起動します。docker-compose がある場合は、それを使用します。
- API の全体像を把握する(10 分)— すべてのエンドポイントを一覧にします(ルート/コントローラーを確認)。テストがあるものとないものを記録します。
- データベースを確認する(10 分)— スキーマを読みます。
\dt+(PostgreSQL)を実行してテーブルサイズを確認します。最大のテーブルとそのインデックスを特定します。 - リクエストを追跡する(15 分)— GET と POST をそれぞれ、ルートハンドラー → ミドルウェア → サービス → リポジトリ → データベースの順にたどります。認証、バリデーション、エラーハンドリングが行われる箇所を記録します。
- 可観測性を確認する(5 分)— メトリクスはありますか?構造化ログはありますか?アラートはありますか?何もない場合、基本的な可観測性の追加が最初のタスクです。
- 直近 10 件のインシデントまたはバグ報告を読む(10 分)— 過去の障害に見られるパターンから、アーキテクチャ上の弱点が明らかになります。
スクリプト
scripts/check_api_health.sh-- 共通のヘルスエンドポイント(/health、/healthz、/ready など)をベース URL 上でプローブし、レスポンス本文を読み取らずにステータス、応答時間、コンテンツタイプを報告します。使い方は--helpを実行して確認してください。scripts/analyze_schema.py-- SQL ファイル内の CREATE TABLE 文を解析し、テーブル数、カラム数、不足しているインデックス、不足している主キー、外部キーの関係を報告します。オプションは--helpを実行して確認してください。
SQL スキーマ、Express API、レートリミッターのパターンについては、コード例を参照してください。
Terraform と CloudWatch アラームの設定については、インフラストラクチャを参照してください。
サーキットブレーカー、サーガ、アウトボックス、分散ロック、冪等なイベント処理のパターンについては、分散パターンを参照してください。
コネクションプーリング、リードレプリカのルーティング、マイグレーション、シャーディング、クエリ最適化、キャッシュについては、データベースパターンを参照してください。
カーソルページネーション、レート制限、バージョニング、バリデーション、Webhook 配信、DataLoader のバッチ処理については、API パターンを参照してください。
リファレンス
データスキーマ設計チェックリスト
- データベースレベルで制約(NOT NULL、CHECK、UNIQUE)を指定してスキーマを定義します。
- フィルター付きクエリには部分インデックスを使用して、I/O を削減します。
- 10 万件以上のエンティティを含む大規模データセットに対応し、クエリ目標を 20ms 未満に設定して設計します。
- データ変換と統合のための ETL パイプラインを計画します。
- スキーマへの準拠を検証し、後方互換性を維持します。
- ユーザー向け入力には、必ずパラメーター化クエリのみを使用します。
ストリーミングとリアルタイム
- 順序が保証された WebSocket 経由のリアルタイム更新をストリーミングします。
- 大量の結果セットには、カーソルベースのページネーションを使用します。
- オーバーヘッドを削減するため、可能な場合はネットワークリクエストをバッチ処理します。