アーキテクチャ設計標準とは
アーキテクチャ設計標準は、システム全体の構造・レイヤー・依存関係の方針を定めるものです。コーディング規約よりも抽象度が高く、「なぜこのアーキテクチャを選んだか」という意思決定の記録としての側面が強くなります。
アーキテクチャ標準が整備されていると、新しいメンバーが「このコードはどこに書けばよいか」「どの層がどの層に依存してよいか」を自分で判断できるようになります。口頭での説明や都度のレビュー指摘から解放され、チームのスループットが向上します。
アーキテクチャ標準がないと何が起きるか
実例:あるバックエンドサービスで起きた話
チームAはClean Architectureを意識してドメイン層とインフラ層を分離して実装していた。新しく入ったメンバーBさんはドメインのEntityから直接DBアクセスするコードを書いてしまい、レビューで指摘されたが「どこにそのルールが書いてあるの?」と言われた。口頭で説明したが、Bさんはその後も迷うたびに都度確認してくる状態が続いた。
アーキテクチャの意図が文書化されていないと、「なぜダメなのかが共有されない」問題が繰り返されます。さらに悪いことに、時間が経つとともに「実はルールがあった」こと自体が忘れられ、アーキテクチャが少しずつ侵食されていきます。
レイヤー構成とディレクトリ規約
Clean Architectureを採用したバックエンドサービスのディレクトリ構成を例に、アーキテクチャ標準のドキュメント化を見てみましょう。各レイヤーの責務と依存方向を明確に定義することが重要です。
src/
domain/ # ビジネスロジック・エンティティ(外部依存なし)
user/
User.ts # エンティティ(IDと属性のみ。DBやAPIを知らない)
UserRepository.ts # リポジトリインターフェース(実装はinfraに)
application/ # ユースケース(domainに依存してよい。インフラには依存しない)
user/
CreateUserUseCase.ts
GetUserUseCase.ts
infrastructure/ # DB・外部API実装(domain/applicationに依存してよい)
database/
UserRepositoryImpl.ts # UserRepositoryの実装
external/
MailService.ts # 外部メールAPIのラッパー
presentation/ # コントローラ・ルーティング(applicationに依存してよい)
api/
UserController.ts
UserRouter.ts
ここで重要なのは依存の方向です。ドキュメントには以下を明記します。
| レイヤー | 依存してよいレイヤー | 依存してはいけないレイヤー |
|---|---|---|
| domain | なし(最も内側) | すべての外側のレイヤー |
| application | domain | infrastructure, presentation |
| infrastructure | domain, application | presentation |
| presentation | application | infrastructure, domain(直接は不可) |
依存ルールの自動チェック
TypeScriptプロジェクトでは eslint-plugin-import の no-restricted-imports ルールで「domainからinfrastructureをimportしたらCIエラー」という設定が可能です。アーキテクチャルールをLinterに落とし込むことで、ドキュメントを読んでいないメンバーも自動的にルールに従うことになります。
ADR(アーキテクチャ決定記録)の活用
設計の意思決定を記録するフォーマットとして「ADR(Architecture Decision Record)」が有効です。ADRは短い文書で、「なぜその技術を選んだか」「何を検討して却下したか」を永続的に残します。特に「なぜ〇〇を使わなかったのか」という否定の理由は、後からドキュメントを読む人にとって非常に価値があります。
# ADR-001: データベースにPostgreSQLを採用する
## ステータス
採用済み(2024-03-01)
## コンテキスト
サービス開始時のデータ量は小規模だが、将来的にJSONデータの柔軟なクエリが
必要になる見込み。チームの既存スキルセットはMySQL寄りだが、柔軟性を優先する。
## 検討した選択肢
1. MySQL: チームの習熟度が高い。JSON対応はMySQL 5.7以降で可能だが限定的
2. PostgreSQL: JSONB型によるインデックス付き高速JSON検索が可能。拡張機能が豊富
3. MongoDB: JSON-nativeだがトランザクション管理が複雑になる
## 決定
PostgreSQLを採用する。JSONB型の豊富なサポートと、
スケーラビリティの実績が決め手。
## 結果
- メリット: JSONB型による柔軟なクエリ、豊富なエコシステム、ACID準拠
- デメリット: MySQLより運用知識のあるメンバーが少ない → 学習コストが発生
- フォローアップ: 2024-06-01までにチーム全員がPostgreSQL基礎研修を受講する
ADRはリポジトリ内の docs/adr/ に連番で蓄積していきます。「なぜこうなっているのか」が後から追跡でき、同じ議論を何度も繰り返す「車輪の再発明」を防ぎます。
ADRの運用ポイント
ADRは「決定済み」「却下」「廃止」などのステータス管理が重要です。技術選定が変わった場合は新しいADRを作成し、古いADRのステータスを「廃止(Superseded by ADR-XXX)」に更新することで、最新の意思決定を追跡できます。一度書いたADRは原則として内容を変更しません。
API設計ガイドラインとは
複数のチームや外部クライアントが利用するAPIは、設計の一貫性が特に重要です。インターフェースが一度公開されると変更コストが高くなるため、事前にガイドラインを整備する価値が大きい領域です。
API設計ガイドラインは「どのチームのエンジニアが書いてもAPIの形が同じになる」状態を目指します。命名・構造・エラー形式が統一されていることで、クライアント側の実装コストが大幅に下がります。
API設計ガイドラインがないと何が起きるか
同じシステム内で、APIの設計が一貫していない状態はよく見られます。
GET /getUser?id=123 # クエリパラメータでID指定
GET /articles/456 # パスパラメータでID指定
POST /create-comment # 動詞を含むエンドポイント名
DELETE /api/v1/users/789 # バージョニングあり
POST /updateProfile # PATCHで行うべき操作をPOSTで
ガイドラインなしに開発を続けると、APIを呼び出す側は「このエンドポイントはどの形式なんだっけ?」と毎回確認する必要が生まれます。
エンドポイント命名とHTTPメソッドの使い方
| ルール | Good ✅ | Bad ❌ |
|---|---|---|
| リソース名は名詞・複数形 | GET /usersGET /articles |
GET /getUsersGET /article |
| IDはパスパラメータ | GET /users/123 |
GET /users?id=123 |
| アクションはHTTPメソッドで表現 | DELETE /users/123 |
POST /deleteUser/123 |
| 部分更新はPATCH、完全更新はPUT | PATCH /users/123(名前だけ変更) |
POST /updateUser |
| バージョニングはURLパスに | GET /api/v1/users |
GET /users?version=1 |
レスポンス形式の統一
成功時・エラー時のJSONスキーマを統一することで、クライアント側が一つのパーサーですべてのAPIレスポンスを処理できます。形式がバラバラだと、エンドポイントごとにパース処理を書かなければならず、フロントエンドの複雑さが増します。
{
"data": {
"id": 123,
"name": "山田太郎",
"email": "yamada@example.com"
},
"meta": {
"request_id": "req_abc123"
}
}
{
"error": {
"code": "USER_NOT_FOUND",
"message": "指定されたユーザーが見つかりません",
"detail": {
"user_id": 123
}
},
"meta": {
"request_id": "req_abc123"
}
}
エラーコードは「機械が読めるコード(USER_NOT_FOUND)」と「人が読めるメッセージ(message)」を分離します。コードはクライアントの条件分岐に使い、メッセージはユーザー向けの表示に使います。request_id を含めることで、ログとの突き合わせが容易になります。
ページネーション設計
ページネーションの方式をガイドラインで決めておかないと、APIごとに形式が異なる事態になります。主に2種類の方式があり、それぞれ特性が異なります。
# offset-based(シンプルだが大量データで遅くなる)
GET /articles?page=3&per_page=20
# cursor-based(大量データでも高速、無限スクロールに向く)
GET /articles?cursor=eyJpZCI6MTIzfQ&limit=20
# cursor-basedのレスポンス例
{
"data": [...],
"pagination": {
"next_cursor": "eyJpZCI6MTQzfQ",
"has_next": true,
"total": null # cursor-basedでは総件数を返さない(パフォーマンスのため)
}
}
| 方式 | メリット | デメリット | 向いているケース |
|---|---|---|---|
| offset-based | 実装が簡単、ページ番号で直接ジャンプ可能 | 大量データでSQLのOFFSETが遅くなる。データが追加された際にページのズレが生じる | データ量が少ない管理画面、ページ番号ナビが必要な場合 |
| cursor-based | 大量データでも一定速度、データの追加でズレが生じない | 実装が複雑、特定ページへのジャンプ不可 | SNSのフィード、大量データ、無限スクロール |
次のPARTで扱うこと
PART 03では、UI/UXデザインガイドライン(デザイントークン・コンポーネント設計)とデータモデル設計標準(テーブル命名・論理削除・マイグレーション管理)を解説します。また、どの設計標準から優先的に整備すべきかの判断基準も紹介します。