アーキテクチャ設計標準とは

アーキテクチャ設計標準は、システム全体の構造・レイヤー・依存関係の方針を定めるものです。コーディング規約よりも抽象度が高く、「なぜこのアーキテクチャを選んだか」という意思決定の記録としての側面が強くなります。

アーキテクチャ標準が整備されていると、新しいメンバーが「このコードはどこに書けばよいか」「どの層がどの層に依存してよいか」を自分で判断できるようになります。口頭での説明や都度のレビュー指摘から解放され、チームのスループットが向上します。

アーキテクチャ標準がないと何が起きるか

実例:あるバックエンドサービスで起きた話

チームAはClean Architectureを意識してドメイン層とインフラ層を分離して実装していた。新しく入ったメンバーBさんはドメインのEntityから直接DBアクセスするコードを書いてしまい、レビューで指摘されたが「どこにそのルールが書いてあるの?」と言われた。口頭で説明したが、Bさんはその後も迷うたびに都度確認してくる状態が続いた。

アーキテクチャの意図が文書化されていないと、「なぜダメなのかが共有されない」問題が繰り返されます。さらに悪いことに、時間が経つとともに「実はルールがあった」こと自体が忘れられ、アーキテクチャが少しずつ侵食されていきます。

レイヤー構成とディレクトリ規約

Clean Architectureを採用したバックエンドサービスのディレクトリ構成を例に、アーキテクチャ標準のドキュメント化を見てみましょう。各レイヤーの責務と依存方向を明確に定義することが重要です。

Text — ディレクトリ構成(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なし(最も内側)すべての外側のレイヤー
applicationdomaininfrastructure, presentation
infrastructuredomain, applicationpresentation
presentationapplicationinfrastructure, domain(直接は不可)

依存ルールの自動チェック

TypeScriptプロジェクトでは eslint-plugin-importno-restricted-imports ルールで「domainからinfrastructureをimportしたらCIエラー」という設定が可能です。アーキテクチャルールをLinterに落とし込むことで、ドキュメントを読んでいないメンバーも自動的にルールに従うことになります。

ADR(アーキテクチャ決定記録)の活用

設計の意思決定を記録するフォーマットとして「ADR(Architecture Decision Record)」が有効です。ADRは短い文書で、「なぜその技術を選んだか」「何を検討して却下したか」を永続的に残します。特に「なぜ〇〇を使わなかったのか」という否定の理由は、後からドキュメントを読む人にとって非常に価値があります。

Markdown — 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の設計が一貫していない状態はよく見られます。

Text — 一貫性のないAPIの例(Bad)
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 /users
GET /articles
GET /getUsers
GET /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レスポンスを処理できます。形式がバラバラだと、エンドポイントごとにパース処理を書かなければならず、フロントエンドの複雑さが増します。

JSON — 統一レスポンス形式(成功時)
{
  "data": {
    "id": 123,
    "name": "山田太郎",
    "email": "yamada@example.com"
  },
  "meta": {
    "request_id": "req_abc123"
  }
}
JSON — 統一レスポンス形式(エラー時)
{
  "error": {
    "code": "USER_NOT_FOUND",
    "message": "指定されたユーザーが見つかりません",
    "detail": {
      "user_id": 123
    }
  },
  "meta": {
    "request_id": "req_abc123"
  }
}

エラーコードは「機械が読めるコード(USER_NOT_FOUND)」と「人が読めるメッセージ(message)」を分離します。コードはクライアントの条件分岐に使い、メッセージはユーザー向けの表示に使います。request_id を含めることで、ログとの突き合わせが容易になります。

ページネーション設計

ページネーションの方式をガイドラインで決めておかないと、APIごとに形式が異なる事態になります。主に2種類の方式があり、それぞれ特性が異なります。

Text — offset-based vs cursor-based ページネーション
# 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デザインガイドライン(デザイントークン・コンポーネント設計)とデータモデル設計標準(テーブル命名・論理削除・マイグレーション管理)を解説します。また、どの設計標準から優先的に整備すべきかの判断基準も紹介します。