ストーリー
アーキテクチャとトレードオフ
すべてのアーキテクチャ決定にはトレードオフが伴います。これはソフトウェア工学における根本的な事実です。
graph TD
A["<b>アーキテクチャの鉄則</b><br/><br/>「銀の弾丸は存在しない」<br/>-- フレデリック・ブルックス<br/><br/>すべての設計判断は、あるメリットを<br/>得るために、別のメリットを犠牲にする"]
style A fill:#f9f9f9,stroke:#333,stroke-width:2px
よくあるトレードオフの軸
| トレードオフ | 一方 | もう一方 |
|---|---|---|
| 一貫性 vs 可用性 | 強い整合性 | 高い可用性 |
| パフォーマンス vs 保守性 | 最適化されたコード | 読みやすいコード |
| 柔軟性 vs 複雑性 | 拡張しやすい設計 | シンプルな設計 |
| 開発速度 vs 品質 | 素早いリリース | 堅牢なテスト |
| コスト vs スケーラビリティ | 低い初期コスト | 高いスケーラビリティ |
CAP定理
分散システムにおける最も有名なトレードオフが CAP 定理です。
CAP定理の3要素
graph TD
C["Consistency<br/>(一貫性)"]
A["Availability<br/>(可用性)"]
P["Partition Tolerance<br/>(分断耐性)"]
C ---|"CP"| P
C ---|"CA"| A
A ---|"AP"| P
style C fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
style A fill:#e8f5e9,stroke:#2e7d32,stroke-width:2px
style P fill:#fff3e0,stroke:#e65100,stroke-width:2px
| 要素 | 説明 | 例 |
|---|---|---|
| Consistency(C) | すべてのノードが同じデータを返す | 銀行の残高照会 |
| Availability(A) | すべてのリクエストに応答する | ECサイトの商品表示 |
| Partition Tolerance(P) | ネットワーク分断時も動作する | 地理分散システム |
CAP定理: 分散システムでは、C・A・P の3つのうち同時に2つまでしか保証できない。
現実的な選択
分散システムではネットワーク分断は避けられないため、実質的には CP か AP の選択になります。
// CP寄りの設計例:金融取引
interface TransactionService {
// 一貫性を優先:全ノードの同期を待つ
transfer(from: string, to: string, amount: number): Promise<TransactionResult>;
// ネットワーク分断時はエラーを返す(可用性を犠牲)
}
// AP寄りの設計例:SNSのタイムライン
interface TimelineService {
// 可用性を優先:最寄りノードから即座に応答
getFeed(userId: string): Promise<Post[]>;
// 少し古いデータが表示される可能性あり(結果整合性)
}
PACELC定理
CAP定理を拡張した PACELC は、分断がない通常時のトレードオフも考慮します。
if (Partition) {
// 分断時: Availability vs Consistency を選択
choose(A or C);
} else {
// 通常時: Latency vs Consistency を選択
choose(L or C);
}
| パターン | 分断時 | 通常時 | 特徴 | データベース例 |
|---|---|---|---|---|
| PA/EL | A優先 | L優先 | 高速・結果整合 | DynamoDB, Cassandra |
| PA/EC | A優先 | C優先 | 可用性重視 | - |
| PC/EL | C優先 | L優先 | バランス型 | - |
| PC/EC | C優先 | C優先 | 厳密な一貫性 | PostgreSQL, MySQL |
Build vs Buy の判断
判断マトリクス
quadrantChart
title Build vs Buy 判断マトリクス
x-axis コモディティ --> 高い複雑性
y-axis コモディティ --> コア競争力に関わる
quadrant-1 Build(戦略的投資)
quadrant-2 Build(差別化)
quadrant-3 Buy(効率化)
quadrant-4 Buy(専門家に任せる)
判断基準
interface BuildVsBuyDecision {
// 自社構築を検討すべき場合
buildWhen: [
"コア競争力に直結する機能",
"市場に適切な製品がない",
"既存製品のカスタマイズコストが高すぎる",
"データの完全な制御が必要"
];
// 購入/SaaS利用を検討すべき場合
buyWhen: [
"コモディティ化された機能(認証、メール送信)",
"市場に成熟した製品がある",
"開発・保守コストが購入コストを上回る",
"専門知識が社内に不足している"
];
}
実践例:認証システム
| 選択肢 | メリット | デメリット |
|---|---|---|
| 自社構築 | 完全なカスタマイズ、ベンダー非依存 | 開発コスト大、セキュリティリスク |
| Auth0 | 高機能、セキュリティ実績 | 月額コスト、ベンダーロックイン |
| Keycloak (OSS) | カスタマイズ可能、無料 | 運用コスト、学習コスト |
技術的負債というトレードオフ
技術的負債は「意図的に品質を下げて開発速度を上げる」トレードオフです。
技術的負債の4象限(Martin Fowlerの分類)
quadrantChart
title 技術的負債の4象限(Martin Fowlerの分類)
x-axis 無謀 --> 慎重
y-axis 無意識 --> 意図的
quadrant-1 "今はリリース優先で後でリファクタする"
quadrant-2 "設計なんて時間の無駄"
quadrant-3 "レイヤーって何?"
quadrant-4 "この設計の問題点が今になって分かった"
負債の管理
// 技術的負債の記録例
interface TechnicalDebtRecord {
id: string;
description: string;
reason: string; // なぜこの負債を許容したか
impact: "HIGH" | "MEDIUM" | "LOW";
interestRate: string; // 放置した場合の影響増大率
repaymentPlan: string; // いつ・どう返済するか
createdAt: Date;
deadline: Date; // 返済期限
}
// 例
const debt: TechnicalDebtRecord = {
id: "TD-042",
description: "注文サービスにハードコードされたビジネスルール",
reason: "Q1リリースに間に合わせるため",
impact: "MEDIUM",
interestRate: "ルール追加のたびにif文が増加、月1回の頻度",
repaymentPlan: "Q2にStrategy パターンでリファクタ",
createdAt: new Date("2025-01-15"),
deadline: new Date("2025-06-30"),
};
意思決定マトリクスと加重スコアリング
ステップ
- 評価基準を定義する
- 各基準に重みを付与する(合計100%)
- 各選択肢を1-5でスコアリングする
- 加重スコアを計算する
実践例:メッセージキュー選定
| 基準 | 重み | RabbitMQ | Apache Kafka | Amazon SQS |
|---|---|---|---|---|
| スループット | 25% | 3 | 5 | 3 |
| 運用の容易さ | 20% | 3 | 2 | 5 |
| チームの習熟度 | 20% | 4 | 2 | 3 |
| コスト | 15% | 4 | 3 | 4 |
| エコシステム | 10% | 4 | 5 | 3 |
| 耐障害性 | 10% | 3 | 5 | 5 |
| 加重スコア | 100% | 3.45 | 3.35 | 3.75 |
// 加重スコア計算
interface Criterion {
name: string;
weight: number; // 0.0 ~ 1.0
}
interface EvaluationResult {
option: string;
scores: Map<string, number>; // 基準名 → スコア (1-5)
weightedScore: number;
}
function calculateWeightedScore(
criteria: Criterion[],
scores: Map<string, number>
): number {
return criteria.reduce((total, criterion) => {
const score = scores.get(criterion.name) ?? 0;
return total + criterion.weight * score;
}, 0);
}
// 使用例
const criteria: Criterion[] = [
{ name: "スループット", weight: 0.25 },
{ name: "運用の容易さ", weight: 0.20 },
{ name: "チームの習熟度", weight: 0.20 },
{ name: "コスト", weight: 0.15 },
{ name: "エコシステム", weight: 0.10 },
{ name: "耐障害性", weight: 0.10 },
];
const sqsScores = new Map([
["スループット", 3],
["運用の容易さ", 5],
["チームの習熟度", 3],
["コスト", 4],
["エコシステム", 3],
["耐障害性", 5],
]);
const sqsResult = calculateWeightedScore(criteria, sqsScores);
// 0.25*3 + 0.20*5 + 0.20*3 + 0.15*4 + 0.10*3 + 0.10*5 = 3.75
注意点
「数字は判断を助けるツールであって、判断そのものではない」と佐藤CTOは注意を促します。
「加重スコアが僅差の場合、数字だけで決めてはいけない。定性的な要素 — チームの士気、戦略的方向性、リスク許容度 — も考慮に入れよう」
まとめ
| ポイント | 内容 |
|---|---|
| トレードオフの不可避性 | すべてのアーキテクチャ決定にはトレードオフが伴う |
| CAP定理 | 分散システムではC・A・Pのうち2つまで |
| PACELC | 通常時のLatency vs Consistencyも考慮 |
| Build vs Buy | コア競争力に関わるかどうかで判断 |
| 技術的負債 | 意図的な負債は記録し、返済計画を立てる |
| 意思決定マトリクス | 基準と重みで定量的に比較する |
チェックリスト
- CAP定理の3要素と実際の選択パターンを説明できる
- PACELC定理でCAP定理がどう拡張されるか理解した
- Build vs Buy の判断基準を挙げられる
- 技術的負債の4象限を理解した
- 加重スコアリングで選択肢を比較できる
次のステップへ
次は ATAM(Architecture Tradeoff Analysis Method)を学びます。SEI(Software Engineering Institute)が開発した、体系的なトレードオフ分析手法を理解しましょう。
推定読了時間: 30分