CS/SE Fundamentals

システム設計の基礎 (System Design Fundamentals)

はじめに

システム設計とは、要件を満たすソフトウェアシステムのアーキテクチャを決定するプロセスだ。単一のサーバーで動くアプリケーションから、数百万ユーザーをさばく分散システムまで、規模は様々だが考え方の基本は共通している。

医療 SaaS では、データの正確性・可用性・セキュリティが特に重要になる。


基本概念

スケーラビリティ (Scalability)

負荷の増加に対してシステムが対応できる能力。

垂直スケーリング (Scale Up): サーバーのスペックを上げる (CPU, メモリ増強)

  • メリット: シンプル、アプリケーション変更不要
  • デメリット: 物理的な上限がある、単一障害点

水平スケーリング (Scale Out): サーバーの台数を増やす

  • メリット: 理論上は無限にスケール可能
  • デメリット: データの一貫性、セッション管理が複雑に
垂直スケーリング:            水平スケーリング:
┌──────────┐               ┌──────┐ ┌──────┐ ┌──────┐
│          │               │Server│ │Server│ │Server│
│  大きな  │               │  1   │ │  2   │ │  3   │
│ サーバー  │               └──┬───┘ └──┬───┘ └──┬───┘
│          │                  │        │        │
└──────────┘               ┌──┴────────┴────────┴──┐
                           │   Load Balancer       │
                           └───────────────────────┘

可用性 (Availability)

システムが正常に稼働している時間の割合。

可用性年間ダウンタイム呼び方
99%3.65 日Two nines
99.9%8.77 時間Three nines
99.99%52.6 分Four nines
99.999%5.26 分Five nines

医療 SaaS での考慮: 診療時間中のダウンタイムは直接的に医療行為に影響する。可用性目標は慎重に設定し、それに見合った冗長化を行う。

CAP 定理 (CAP Theorem)

分散システムでは、以下の3つを同時に完全に満たすことはできない:

  • Consistency (一貫性): すべてのノードが同じデータを返す
  • Availability (可用性): すべてのリクエストにレスポンスを返す
  • Partition Tolerance (分断耐性): ネットワーク分断が起きてもシステムが動作する

分散システムではネットワーク分断は不可避なので、実質的には CP (一貫性優先)AP (可用性優先) の選択になる。

医療データの場合: 患者データの一貫性は極めて重要。誤ったデータを返すより、エラーを返す方が安全 → CP 寄りの設計が基本。


主要コンポーネント

ロードバランサー (Load Balancer)

トラフィックを複数のサーバーに分散させる。

主な分散アルゴリズム:

  • ラウンドロビン: 順番に振り分け。シンプルだが均等性の保証はない
  • 最小接続数: 接続数が最も少ないサーバーへ
  • IP ハッシュ: 同一クライアントを同一サーバーへ (セッション維持)

実務での選択: AWS ALB (Application Load Balancer) を使うケースが多い。パスベースのルーティングや、ヘルスチェックによる異常サーバーの自動除外が可能。

キャッシュ (Cache)

頻繁にアクセスされるデータを高速な場所に保持する。

キャッシュの階層:

クライアント (ブラウザキャッシュ)
    ↓
CDN (静的アセット)
    ↓
アプリケーション (Redis/Memcached)
    ↓
データベース (クエリキャッシュ)

キャッシュ戦略:

  • Cache-Aside: アプリがキャッシュを確認し、なければ DB から取得してキャッシュに保存
  • Write-Through: 書き込み時にキャッシュと DB を同時更新
  • Write-Behind: キャッシュに書き込み、非同期で DB に反映

キャッシュの難しさ: キャッシュの無効化 (invalidation) はコンピュータサイエンスで最も難しい問題の一つ。医療データではキャッシュの整合性に特に注意が必要。

メッセージキュー (Message Queue)

非同期処理を実現するためのコンポーネント。送信者と受信者を疎結合にする。

Producer → [Message Queue] → Consumer
             (SQS, etc.)

使いどころ:

  • メール/通知の送信
  • レポート生成
  • 外部システムとの連携
  • 時間のかかる処理のバックグラウンド実行

医療 SaaS での例: 検査結果の通知、予約リマインダー、診療レポートの PDF 生成など。

データベースの設計パターン

レプリケーション (Replication):

  • Primary-Replica 構成: 書き込みは Primary、読み取りは Replica に分散
  • 読み取りが多いワークロード (典型的な Web アプリ) に有効

シャーディング (Sharding):

  • データを複数のデータベースに分割して格納
  • 分割キーの選択が重要 (例: テナント ID、地域)
シャーディングの例 (テナント ID で分割):

テナント A, B → DB Shard 1
テナント C, D → DB Shard 2
テナント E, F → DB Shard 3

アーキテクチャパターン

モノリス vs マイクロサービス

観点モノリスマイクロサービス
デプロイ全体を一括サービスごとに独立
複雑さアプリ内は単純、規模拡大で複雑化分散システムの複雑さ
チーム小〜中規模チーム向き大規模組織向き
データ一貫性トランザクションで容易Saga パターン等が必要
初期コスト低い高い

現実的な判断: 多くのスタートアップ・中規模企業では、モジュラーモノリス (モノリスだが内部的にモジュール分割されている) が良い出発点。必要に応じてマイクロサービスに分離する。

API ゲートウェイ

クライアントとバックエンドサービスの間に位置し、以下を担当:

  • ルーティング
  • 認証・認可
  • レート制限
  • リクエスト/レスポンスの変換

イベント駆動アーキテクチャ

コンポーネント間をイベント (出来事) でつなぐ。

予約サービス --[予約作成イベント]--> 通知サービス
                                --> カレンダーサービス
                                --> 課金サービス

メリット: サービス間の疎結合、拡張性の高さ デメリット: デバッグが難しい、イベントの順序保証に注意が必要


医療 SaaS のシステム設計で考慮すべきこと

データの取り扱い

  • 監査ログ: 誰がいつ何のデータにアクセス・変更したかを記録
  • 論理削除: 医療データは物理削除せず、論理削除 (soft delete) を基本とする
  • データの暗号化: 保存時 (at rest) と通信時 (in transit) の両方

マルチテナンシー

複数の医療機関が同一システムを利用する場合の設計:

  • データ分離: テナント間でデータが漏洩しないことの保証
  • パフォーマンス分離: 一つのテナントの負荷が他に影響しない設計
  • カスタマイズ性: テナントごとの設定・ワークフローの違いへの対応

障害への備え

  • サーキットブレーカー: 外部サービスの障害が連鎖しないよう遮断
  • リトライとバックオフ: 一時的な障害に対する自動復旧
  • グレースフルデグラデーション: 一部機能が使えなくても中核機能は維持

Agent-first 開発においてこれが重要な理由

システム設計は、AI コーディングエージェントが最も支援を必要とする領域の一つだ。

  • 全体のアーキテクチャは人間が決める: エージェントはコンポーネントの実装は得意だが、「このシステムをどう分割するか」の判断は人間がすべき
  • 非機能要件を明示できる: 「可用性 99.9% を目標に」「読み取り:書き込み = 100:1 の比率を想定」といった制約をエージェントに伝えられる
  • トレードオフを言語化できる: 「ここはキャッシュを入れてレイテンシを下げたいが、一貫性のリスクを許容する」のような判断を伝えられる
  • レビューの質が上がる: エージェントの提案するアーキテクチャが適切かどうかを評価できる

Further Reading