はじめに
前回の記事(第2章)では、アーキテクトがどのように考え、意思決定を行うべきかという 「アーキテクチャ思考」について整理しました。
では、その思考をもとに、実際のシステム構造はどのように設計すべきなのでしょうか?
第3章では、その答えとして 「モジュール性(Modularity)」 が登場します。
モジュール性は、ソフトウェアの保守性・拡張性・理解しやすさを大きく左右する、 アーキテクチャの中核となる概念です。
本章では、以下のような問いに向き合います。
- 良いモジュール分割とは何か?
- モジュールの「良さ」はどのように測れるのか?
- 結合度や凝集度とは具体的に何を意味するのか?
一見すると古典的にも見えるこれらの概念ですが、
マイクロサービスやクラウドネイティブな時代においても、その本質は変わりません。
むしろ、分散システムが当たり前になった今だからこそ、
モジュール性の重要性はより高まっていると言えるでしょう。
📖ソフトウェアアーキテクチャの基礎
本書は、O’Reilly Media から出版された『Fundamentals of Software Architecture: An Engineering Approach』 の日本語版です。著者の Mark Richards と Neal Ford が、アーキテクチャを工学的視点から捉え直し、理論と実務を橋渡しする知見をまとめた一冊です。
https://www.oreilly.co.jp/books/9784873119823/

目次(全24章)
1章 イントロダクション
1.1 ソフトウェアアーキテクチャの定義1.2 アーキテクトへの期待
1.2.1 アーキテクチャ決定を下す
1.2.2 アーキテクチャを継続的に分析する
1.2.3 最新のトレンドを把握し続ける
1.2.4 決定の順守を徹底する
1.2.5 さまざまなものに触れ、経験している
1.2.6 事業ドメインの知識を持っている
1.2.7 対人スキルを持ち合わせている
1.2.8 政治を理解し、かじ取りをする
1.3 アーキテクチャと交わるもの
1.3.1 エンジニアリングプラクティス
1.3.2 運用とDevOps
1.3.3 プロセス
1.3.4 データ
1.4 ソフトウェアアーキテクチャの法則
第I部 基礎
2章 アーキテクチャ思考
2.1 アーキテクチャと設計2.2 技術的な幅
2.3 トレードオフを分析する
2.4 ビジネスドライバーを理解する
2.5 アーキテクティングとコーディングのバランスを取る
3章 モジュール性
3.1 定義3.2 モジュール性の計測
3.2.1 凝集度
3.2.2 結合度
3.2.3 抽象度、不安定度、主系列からの距離
3.2.4 主系列からの距離
3.2.5 コナーセンス
3.2.6 結合度とコナーセンスのメトリクスを統合する
3.3 モジュールからコンポーネントへ
4章 アーキテクチャ特性
4.1 アーキテクチャ特性の(部分的な)リスト4.1.1 アーキテクチャの運用特性
4.1.2 アーキテクチャの構造特性
4.1.3 アーキテクチャの横断的特性
4.2 トレードオフと少なくとも最悪でないアーキテクチャ
5章 アーキテクチャ特性を明らかにする
5.1 アーキテクチャ特性をドメインの関心事から捉える5.2 要件からアーキテクチャ特性を抽出する
5.3 事例:シリコンサンドイッチ
5.3.1 明示的な特性
5.3.2 暗黙的な特性
6章 アーキテクチャ特性の計測と統制
6.1 アーキテクチャ特性の計測6.1.1 運用面の計測
6.1.2 構造面の計測
6.1.3 プロセス面の計測
6.2 統制と適応度関数
6.2.1 アーキテクチャ特性の統制
6.2.2 適応度関数
7章 アーキテクチャ特性のスコープ
7.1 結合とコナーセンス7.2 アーキテクチャ量子と粒度
7.2.1 事例:Going、Going、Gone
8章 コンポーネントベース思考
8.1 コンポーネントの分類8.2 アーキテクトの役割
8.2.1 アーキテクチャの分割
8.2.2 事例:シリコンサンドイッチにおける分割
8.3 開発者の役割
8.4 コンポーネントを識別する流れ
8.4.1 初期コンポーネントを識別する
8.4.2 コンポーネントに要件を割り当てる
8.4.3 ロールや責務を分析する
8.4.4 アーキテクチャ特性を分析する
8.4.5 コンポーネントを再構成する
8.5 コンポーネントの粒度
8.6 コンポーネント設計
8.6.1 コンポーネントの発見
8.7 事例:「Going、Going、Gone」におけるコンポーネントの発見
8.8 アーキテクチャ量子再び:モノリシックアーキテクチャと分散アーキテクチャの選択
第II部 アーキテクチャスタイル
9章 基礎
9.1 基礎的なパターン9.1.1 巨大な泥団子
9.1.2 ユニタリーアーキテクチャ
9.1.3 クライアント/サーバー
9.2 モノリシックアーキテクチャと分散アーキテクチャ
9.2.1 誤信1:ネットワークは信頼できる
9.2.2 誤信2:レイテンシーがゼロ
9.2.3 誤信3:帯域幅は無限
9.2.4 誤信4:ネットワークは安全
9.2.5 誤信5:トポロジーは決して変化しない
9.2.6 誤信6:管理者は一人だけ
9.2.7 誤信7:転送コストはゼロ
9.2.8 誤信8:ネットワークは均一
9.2.9 分散コンピューティングにおけるその他の考慮事項
10章 レイヤードアーキテクチャ
10.1 トポロジー10.2 層の分離
10.3 レイヤーの追加
10.4 その他の考慮事項
10.5 このアーキテクチャスタイルを採用する理由
10.6 アーキテクチャ特性の評価
11章 パイプラインアーキテクチャ
11.1 トポロジー11.1.1 パイプ
11.1.2 フィルター
11.2 事例
11.3 アーキテクチャ特性の評価
12章 マイクロカーネルアーキテクチャ
12.1 トポロジー12.1.1 コアシステム
12.1.2 プラグインコンポーネント
12.2 レジストリ
12.3 コントラクト
12.4 事例とユースケース
12.5 アーキテクチャ特性の評価
13章 サービスベースアーキテクチャ
13.1 トポロジー13.2 トポロジーの種類
13.3 サービスの設計と粒度
13.4 データベース分割
13.5 アーキテクチャ例
13.6 アーキテクチャ特性の評価
13.7 このアーキテクチャスタイルがふさわしいとき
14章 イベント駆動アーキテクチャ
14.1 トポロジー14.2 ブローカー
14.3 メディエーター
14.4 非同期の能力
14.5 エラー処理
14.6 データロスの防止
14.7 ブロードキャスト能力
14.8 リクエスト・リプライ
14.9 リクエストベースとイベントベースの間を取る
14.10 ハイブリッドなイベント駆動アーキテクチャ
14.11 アーキテクチャ特性の評価
15章 スペースベースアーキテクチャ
15.1 一般的なトポロジー15.1.1 処理ユニット
15.1.2 仮想ミドルウェア
15.1.3 データポンプ
15.1.4 データライター
15.1.5 データリーダー
15.2 データ衝突
15.3 クラウドとオンプレミス
15.4 レプリケーションキャッシュと分散キャッシュ
15.5 ニアキャッシュの考慮
15.6 実装例
15.6.1 コンサートチケット販売システム
15.6.2 オンラインオークションシステム
15.7 アーキテクチャ特性の評価
16章 オーケストレーション駆動サービス指向アーキテクチャ
16.1 歴史と哲学16.2 トポロジー
16.3 分類
16.3.1 ビジネスサービス
16.3.2 エンタープライズサービス
16.3.3 アプリケーションサービス
16.3.4 インフラストラクチャサービス
16.3.5 オーケストレーションエンジン
16.3.6 メッセージフロー
16.4 再利用...と結合
16.5 アーキテクチャ特性の評価
17章 マイクロサービスアーキテクチャ
17.1 歴史17.2 トポロジー
17.3 分散
17.4 境界づけられたコンテキスト
17.4.1 粒度
17.4.2 データ分離
17.5 API層
17.6 運用面での再利用
17.7 フロントエンド
17.8 通信
17.8.1 コレオグラフィとオーケストレーション
17.8.2 トランザクションとサーガ
17.9 アーキテクチャ特性の評価
17.10 参考文献
18章 適切なアーキテクチャスタイルを選ぶ
18.1 アーキテクチャにおけるトレンドの変遷18.2 判断基準
18.3 モノリスの事例:シリコンサンドイッチ
18.3.1 モジュラーモノリス
18.3.2 マイクロカーネル
18.4 分散型のケーススタディ:Going、Going、Gone
第III部 テクニックとソフトスキル
19章 アーキテクチャ決定
19.1 アーキテクチャ決定に関するアンチパターン19.1.1 資産防御アンチパターン
19.1.2 グラウンドホッグデーアンチパターン
19.1.3 メール駆動アーキテクチャアンチパターン
19.2 アーキテクチャ上重要なもの
19.3 アーキテクチャデシジョンレコード
19.3.1 基本構造
19.3.2 ADRを保存する
19.3.3 ドキュメントとしてのADR
19.3.4 標準のためにADRを用いる
19.3.5 事例
20章 アーキテクチャ上のリスクを分析する
20.1 リスクマトリックス20.2 リスクアセスメント
20.3 リスクストーミング
20.3.1 特定
20.3.2 合意
20.3.3 軽減
20.4 ユーザーストーリーリスク分析
20.5 リスクストーミング例
20.5.1 可用性
20.5.2 弾力性
20.5.3 セキュリティ
21章 アーキテクチャの図解やプレゼンテーション
21.1 図解21.1.1 ツール
21.1.2 標準ダイアグラム:UML、C4、ArchiMate
21.1.3 図解ガイドライン
21.2 プレゼンテーション
21.2.1 時間を操る
21.2.2 段階的な構築
21.2.3 インフォデッキとプレゼンテーション
21.2.4 スライドは物語の半分
21.2.5 不可視化
22章 効果的なチームにする
22.1 チーム境界22.2 アーキテクトのパーソナリティ
22.2.1 コントロールフリーク
22.2.2 アームチェアアーキテクト
22.2.3 効果的なアーキテクト
22.3 どうやって管理する?
22.4 チームの警告サイン
22.5 チェックリストの活用
22.5.1 開発者のコード完成チェックリスト
22.5.2 ユニットテストと機能テストのためのチェックリスト
22.5.3 ソフトウェアリリースのためのチェックリスト
22.6 ガイダンスの提供
22.7 まとめ
23章 交渉とリーダーシップのスキル
23.1 交渉とファシリテーション23.1.1 ビジネスステークホルダーとの交渉
23.1.2 他のアーキテクトとの交渉
23.1.3 開発者との交渉
23.2 リーダーとしてのソフトウェアアーキテクト
23.2.1 アーキテクチャの4つのC
23.2.2 プラグマティックでありながらもビジョナリーであること
23.2.3 手本を示してチームをリードする
23.3 開発チームに溶け込む
23.4 まとめ
24章 キャリアパスを開く
24.1 20分ルール24.2 パーソナルレーダーの開発
24.2.1 ThoughtWorksテクノロジーレーダー
24.2.2 オープンソースのビジュアライゼーションビット
24.3 ソーシャルメディアの使用
24.4 別れの挨拶
付録A 自己評価のためのチェックリスト
参考文献
訳者あとがき
索引
関連書籍
第3章モジュール性
今回は、 第3章「アーキテクチャ思考」 を要約・紹介したものになります。
3.1 定義
モジュール性とは何か
本書では、モジュールを次のように定義しています。
「より複雑な構造を構築するために使用できる、標準化された部品または独立した単位の集合」
少し噛み砕くと、 「関連するコードを論理的にグルーピングしたもの」 です。
つまり、システムを「意味のある単位」に分割し、それぞれを独立して理解・変更できるようにする考え方です。
モジュールは物理的な分離ではなく、論理的な分離です。
| 観点 | 誤解されがち | 実際 |
|---|---|---|
| 分割方法 | フォルダ・ディレクトリ | 意味・責務単位 |
| 判断基準 | 見た目 | 振る舞い・変更単位 |
左の図に関して、グループA、B、Cと一見モジュール化されているように見えますが、
- モジュール間で依存し合っている
- ロジックが分散している
- どこからでもアクセスできる
状態であり、「高結合・低凝集」のモジュール性が低い設計です。
一言で言うと:
「変更に強い構造をどう作るか」
これがモジュール性の本質です。
3.2 モジュール性の計測
モジュール性は「大事そう」では済ませられません。
本書では、アーキテクトがモジュール性を把握するための手がかりとして、主に 凝集度・結合度・コナーセンス という3つの考え方に注目しています。
ここで重要なのは、モジュール性は「なんとなく良さそう」で語るのではなく、複数の観点から観測し、比較し、改善の方向を考える対象 だということです。
ただし、メトリクスは万能ではありません。数値はあくまでヒントであり、最終的には文脈を踏まえた解釈が必要です。
3.2.1 凝集度(Cohesion)
凝集度とは、モジュール内の要素がどれだけ自然にまとまっているか を表す考え方です。
言い換えると、「そのモジュールに入っている要素同士は、本当に一緒にいるべきか?」を見る指標です。
本書では、関連する要素がすべて1か所にまとまっている状態が理想だと説明されています。
逆に、まとまりを細かく分けすぎると、今度はモジュール間の呼び出しが増え、結合が強くなってしまいます。
つまり、凝集度を上げたいからといって、何でも細かく切ればよいわけではない というのが重要なポイントです。
「凝集度の高いモジュールを分割しようとしても、結合が増えて可読性が低下するだけだ」
というLarry Constantineの引用は、この節の本質をよく表しています。
凝集度の種類
本書では、凝集度をいくつかの種類に分けています。ざっくり言うと、上に行くほど望ましく、下に行くほど危険です。
-
機能的凝集(Functional Cohesion)
モジュールが1つの明確な責務のために存在している状態。最も理想的です。 -
逐次的凝集(Sequential Cohesion)
ある処理の出力が次の処理の入力になるなど、流れとしてまとまっている状態。 -
通信的凝集(Communicational Cohesion)
同じデータや出力に関係する処理がまとまっている状態。 -
手続き的凝集(Procedural Cohesion)
決められた順番で実行される処理がまとまっている状態。 -
時間的凝集(Temporal Cohesion)
初期化処理のように、「同じタイミングで動く」ことだけが共通点のまとまり。 -
論理的凝集(Logical Cohesion)
似た種類の処理が雑にまとめられている状態。StringUtils的なクラスが典型例。 -
偶発的凝集(Coincidental Cohesion)
同じ場所にあるだけで、意味的な関連がほとんどない状態。最も危険です。
実務での見方
例えば CustomerMaintenance に「顧客の追加」「顧客の更新」「顧客への通知」だけでなく、「顧客注文の取得」「注文キャンセル」まで入っていたらどうでしょうか。
これが適切かどうかは、実は機械的には決まりません。本書でも「答えは場合による」としています。
注文関連の操作がわずかしかなく、顧客の知識に強く依存するなら同じモジュールでもよいかもしれません。
一方、注文管理が独立した責務として育ってきたなら、別モジュールに分けるべきかもしれません。
つまり、凝集度を見るときは
- 一緒に変わるか
- 一緒に理解した方が自然か
- 独立させたときに逆に結合が増えないか
を考えるのが実務的です。
LCOMについて
本書では、凝集度の欠如を測るメトリクスとして LCOM(Lack of Cohesion in Methods) も紹介されています。
LCOMは、クラス内のメソッド群がどれだけ同じフィールドを共有しているかを見て、「偶発的に同居しているメソッドが多くないか」を検出する考え方です。

図3-1では、クラスXは凝集度が高く、クラスYは低く、クラスZは途中で分割できそうな構造として示されています。
ただし本書は、LCOMにも限界があることをはっきり指摘しています。
LCOMで分かるのは 構造的な凝集の欠如 であって、「なぜその要素が一緒にいるべきか」という意味までは判断できません。
ここでも、メトリクスは答えそのものではなく、リファクタリング候補を見つけるヒント として使うのが正しい姿勢です。
3.2.2 結合度(Coupling)
結合度とは、あるモジュールが他のモジュールにどれだけ依存しているか を表します。
モジュール性を語るとき、「高凝集・低結合」が定番ですが、この“低結合”の部分です。
本書では、グラフ理論に基づく考え方として、次の2つを紹介しています。
直感的な理解
例えば、ある共通ライブラリが多くのモジュールから参照されているなら、求心性結合は高いと言えます。
逆に、あるサービスがあちこちの外部APIや他サービスに依存していたら、遠心性結合が高い状態です。
実務では以下のように考えると分かりやすいです。
-
求心性結合が高い
→ たくさん使われている中心的なモジュール
→ 変更の影響が大きいので慎重な設計が必要 -
遠心性結合が高い
→ 他に頼りすぎているモジュール
→ 変更に弱く、不安定になりやすい
実務での危険信号
たとえば OrderService が、UserService、InventoryService、PaymentService、ShippingService、CouponService など多数に直接依存していたら、遠心性結合が高い状態です。
このとき、依存先のどれか1つの仕様変更でも壊れる可能性があり、修正のたびに連鎖的な確認が必要になります。
一方で、共通モジュールに依存が集まりすぎるのも危険です。
何でもそこに入れてしまうと、そのモジュールが巨大で壊しにくい“中心臓器”になってしまいます。
3.2.3 抽象度・不安定度・主系列からの距離
ここからは、結合度の派生メトリクスとして、抽象度(Abstractness) と 不安定度(Instability) が出てきます。
この2つを合わせて見ることで、モジュールの“立ち位置”をより深く評価できます。

抽象度(Abstractness)
抽象度とは、モジュールの中に どれだけ抽象的な要素(抽象クラスやインターフェース)が含まれているか を示す指標です。
完全に具体的な実装だらけなら抽象度は低く、抽象クラスやインターフェースが多ければ高くなります。
ただし、抽象度は高ければよいというものではありません。
- 抽象度が低すぎる
→ 具体実装にべったりで変更に弱い - 抽象度が高すぎる
→ 何をするコードなのか分かりづらく、使いにくい
本書でも、巨大な main() しかない世界と、抽象が進みすぎて理解に時間がかかる世界の両極を例に挙げています。
不安定度(Instability)
不安定度とは、そのモジュールが変更に対してどれだけ壊れやすいか を示します。
本書では、遠心性結合と求心性結合の比率から算出されると説明されています。
ざっくり言えば、他への依存が多いモジュールほど不安定です。
例えば、あるクラスが多数の外部クラスを呼び出して処理を委譲している場合、呼び出し先のどれかが変わるだけで影響を受けるので不安定度は高くなります。
「外に依存しているほど揺さぶられやすい」という、かなり直感的な考え方です。
主系列からの距離(Distance from the Main Sequence)
本書で面白いのは、抽象度と不安定度の理想的な関係を 主系列(main sequence) という線で表していることです。

抽象度が高いなら安定しているべき、逆に具体的なら不安定でもよい、という理想的なバランスが一本の線で示されています。
そして、その線からどれだけ離れているかを 主系列からの距離 として評価します。
無駄ゾーンと苦痛ゾーン
図3-4では、この考え方をさらに視覚化していて、主系列から外れた領域を
-
無駄ゾーン
抽象的すぎて使いにくい -
苦痛ゾーン
具体的すぎて変更に脆く、メンテナンスが難しい
と呼んでいます。
このネーミング、かなり本質を突いています。
実務でも
- インターフェースや抽象クラスが大量にあるのに利用実態が薄い
- 逆に何の抽象化もなく、べた書きの具体実装だらけ
という両極端を見かけます。
どちらも“良い設計”ではなく、責務と変化に応じたバランス が大切だと分かります。
3.2.4 メトリクスの限界
ここで本書はとても大事なことも言っています。
それは、コードレベルのメトリクスは価値あるヒントを与えるが、必ず解釈が必要 だということです。
例えば、循環的複雑度のようなメトリクスはコードの複雑さを測れますが、
- 本質的な複雑さ
(問題そのものが複雑) - 偶発的な複雑さ
(設計や実装が悪くて複雑)
までは区別できません。
つまり、数値が高いこと自体が悪なのではなく、なぜ高いのか を読む必要があります。
これは第2章で出てきた「なぜがどうやってより重要」という話にもつながります。
メトリクスは“観察の出発点”であって、“自動判定のゴール”ではありません。
3.2.5 コナーセンス(Connascence)
この節の後半で、本書は結合度の古典的な考え方を一歩進める概念として コナーセンス を紹介します。
これは第3章の中でもかなり重要です。
コナーセンスとは何か
本書では次のように説明されています。
システムの全体的な正しさを維持するため、あるコンポーネントの変更が別のコンポーネントの変更を必要とする場合、2つのコンポーネントはコナーセントしている。
つまり、一方を変えたら他方も変えないと正しく動かない関係 のことです。
これは単なる“依存している/していない”よりも、ずっと実務感があります。
なぜなら、現場で本当に痛いのは「参照があること」より、「変更が連鎖すること」だからです。
3.2.5.1 静的なコナーセンス
静的なコナーセンスは、コードレベルで分かる結合です。
本書では次の種類が紹介されています。
-
名前のコナーセンス(CoN)
同じ名前に依存する。
例:メソッド名、変数名。比較的望ましい。 -
型のコナーセンス(CoT)
同じ型に依存する。 -
意味のコナーセンス(CoM)
特定の値の意味に依存する。
例:マジックナンバー。 -
位置のコナーセンス(CoP)
引数の順序のように、値の位置に依存する。 -
アルゴリズムのコナーセンス(CoA)
同じアルゴリズムの理解に依存する。
実務でありがちなのは、位置のコナーセンスや意味のコナーセンスです。
例えば updateSeat("14D", "Ford", "N") のような呼び出しは、型が合っていても意味が間違っている可能性があります。
また、TRUE = 1 / FALSE = 0 のようなハードコード値に依存すると、変更時にとても危険です。
3.2.5.2 動的なコナーセンス
動的なコナーセンスは、実行時の振る舞いに関する結合です。
本書では次のような種類が説明されています。
-
実行順序のコナーセンス(CoE)
呼び出し順序が重要。
例:setSubject()の前にsend()してしまうと壊れる。 -
タイミングのコナーセンス(CoT)
実行タイミングが重要。
例:並行処理における競合状態。 -
値のコナーセンス(CoV)
複数のコンポーネントが同じ値を同時に保つ必要がある。
例:分散トランザクション。 -
アイデンティティのコナーセンス(CoI)
同じ特定インスタンスを共有している。
これは、マイクロサービスや分散システムになると一気に厄介になります。
「同じ値でなければいけない」「順番が重要」「タイミングが重要」という関係は、単一プロセス内よりも分散環境で破綻しやすいからです。
3.2.5.3 コナーセンスの性質
本書では、コナーセンスを理解するうえで次の3つが重要だとしています。
強さ
図3-5では、コナーセンスの種類ごとに「リファクタリングしやすさ」の観点から強弱が整理されています。
一般に、名前 → 型 → 意味 → アルゴリズム → 位置 → 実行順序 → タイミング → 値 → アイデンティティ と進むほど、扱いにくくなります。
アーキテクトは、強いコナーセンスをより弱いコナーセンスへ変換する 方向で改善を考えるべきです。
位置関係
コナーセンスは、遠く離れた場所にあるより、近くにある方がダメージが小さいとされています。
同じ意味のコナーセンスでも、同じモジュール内ならまだ許容しやすいですが、別モジュールや別サービスをまたぐと危険度が上がります。
度合い
影響範囲が小さいか大きいか、つまり何個のモジュール・クラスに広がっているかも重要です。
小さなコードベースでの悪いコナーセンスはまだ耐えられても、大規模システムでは小さな問題が大きな痛みになります。
コナーセンス改善のガイドライン
本書では、Page-Jonesのガイドラインとして次の考え方も紹介しています。
- カプセル化された要素にシステムを分割して、全体のコナーセンスを最小化する
- カプセル化の境界をまたぐコナーセンスは、どんな種類でも最小化する
- カプセル化の境界内では、コナーセンスの度合いを最大化する
かなり実務的に言い換えると、
- モジュールの中では多少強く結びついていてもよい
- ただし、モジュール外にはその結びつきを漏らさない
ということです。
これはカプセル化の本質そのものです。
3.2.6 結合度とコナーセンスをどう使い分けるか
本書の最後では、結合度とコナーセンスは別々の時代・別々の対象から生まれたが、アーキテクトの視点では重なり合っていると説明しています。
-
結合度
主に構造上の依存を見る -
コナーセンス
変更がどう連鎖するか、意味や振る舞いまで含めて見る
構造化プログラミング時代の結合度だけでは、特に動的なコナーセンスのような実行時の結びつきは十分に表現できません。
そのため現代では、両方を併せて見ることで、より立体的にモジュール性を評価できるわけです。
この節の実務的な読み方
この3.2節を実務に引き寄せると、次のように整理できます。
-
凝集度
そのモジュール、本当に1つの責務でまとまっているか? -
結合度
他への依存が多すぎて、変更に弱くなっていないか? -
抽象度・不安定度
抽象化しすぎ/具体化しすぎのどちらに偏っていないか? -
コナーセンス
変更の連鎖や、実行時の暗黙ルールが潜んでいないか?
つまり3.2は、「モジュール性が良いか悪いか」を感覚ではなく、
観測可能な兆候として捉える方法 を教えてくれる節だと言えます。
- モジュール性は「なんとなく良い」で判断せず、複数の観点から計測・観察する
- 凝集度はモジュール内のまとまり、結合度はモジュール間の依存を見る
- 抽象度と不安定度のバランスが、健全な構造かどうかのヒントになる
- コナーセンスは「変更が連鎖する関係」を捉える、実務で非常に強い概念
- メトリクスは答えではなく、リファクタリング候補を見つけるためのレンズ
3.3 モジュールからコンポーネントへ
これまで本章では「モジュール性」という観点から、凝集度・結合度・コナーセンスといった指標を使ってソフトウェアの構造を分析してきました。
ここで一歩視点を引き上げて、「モジュール」という単位から、より大きな設計単位である コンポーネント へと話が進みます。
モジュールとコンポーネントの違い
本書では、関連するコードのまとまりを広く「モジュール」と呼んでいます。
これはクラスやパッケージなど、論理的にまとまった単位を指す、比較的抽象的な概念です。
一方で、実際のソフトウェア開発では、多くのプラットフォームが コンポーネント という単位をサポートしています。
コンポーネントとは、
- 明確な境界を持つ
- 再利用可能である
- 他のコンポーネントとインターフェースを通じてやり取りする
といった特徴を持つ、より実践的で物理的な単位 です。
| 概念 | 役割 |
|---|---|
| モジュール | コード整理 |
| コンポーネント | システム構造 |
なぜ「モジュール」から「コンポーネント」へ進むのか
モジュールは「コードの整理」に役立つ概念ですが、実際のアーキテクチャ設計ではそれだけでは不十分です。
なぜなら、アーキテクチャは
- デプロイ単位
- チームの責務分割
- 実行時の境界
- スケーラビリティ
といった観点も含めて設計する必要があるからです。
つまり、
モジュールは「コードのまとまり」
コンポーネントは「システムの構成要素」
という違いがあります。
論理的分離と物理的分離
コンポーネントを理解するうえで重要なのが、
- 論理的分離(Logical Separation)
- 物理的分離(Physical Separation)
という考え方です。
| 種類 | 内容 |
|---|---|
| 論理分離 | モジュール |
| 物理分離 | コンポーネント |
論理的分離
コード上での分割(パッケージ、名前空間など)
- 同じプロセス内で動く
- ビルドも一体
- 変更の影響範囲は広がりやすい
物理的分離
実行単位としての分割(サービス、ライブラリ、プロセスなど)
- 別プロセス・別デプロイ
- インターフェースを介して通信
- 独立して変更・スケール可能
実務では、この2つをどう使い分けるかが非常に重要です。
よくあるアンチパターン
モジュール設計だけで満足してしまうと、次のような問題が起きがちです。
① 見た目だけモジュール分割されている
- パッケージは分かれているが依存はぐちゃぐちゃ
- どこからでもアクセス可能
- 結果的に変更が連鎖する
👉 これは「モジュール性があるように見えて、実はない状態」
② コンポーネント境界が曖昧
- APIが明確でない
- 内部実装に依存してしまう
- 再利用できない
③ 分割しすぎ問題
- なんでも分割してしまう
- 結合が増えて逆に複雑になる
👉 第3章の前半で出てきた「凝集と結合のトレードオフ」がここでも効いてきます
実務でのイメージ
例えば、ECサイトを考えると:
モジュールレベル
- user
- order
- payment
- notification
コンポーネントレベル
- User Service
- Order Service
- Payment Service
- Notification Service
ここで重要なのは、
- モジュール → コード整理
- コンポーネント → システム構成
という役割の違いです。
さらに、
- 同じプロセス内のモジュール分割にするのか
- サービスとして物理分離するのか
は、トレードオフになります。
コンポーネント設計の難しさ
本書でも触れられている通り、コンポーネントや分離に関する研究は古くから存在するにもかかわらず、
開発者やアーキテクトはいまだに良い結果を得るのに苦労している
とされています。
これはつまり、
- 正解が1つではない
- 文脈依存が強い
- トレードオフが常に存在する
ということです。
次章へのつながり
この節の最後では、
- 問題領域からどのようにコンポーネントを導き出すか
- アーキテクチャ特性とそのスコープ
について、後続の章(特に第8章)で詳しく扱うと述べられています。
つまりこの3.3は、
「モジュール性の理解」から「システム全体の構造設計」へ
視点を引き上げるための橋渡しとなる重要な節です。
まとめ
- モジュールは「コードのまとまり」、コンポーネントは「システムの構成要素」
- コンポーネント設計では、論理的分離と物理的分離の両方を考える必要がある
- モジュール分割だけでは、アーキテクチャとしては不十分
- 分割は常にトレードオフ(凝集 vs 結合)で考える
- コンポーネント設計には明確な正解はなく、文脈依存である
終わりに
第2章では「アーキテクトはいかに考えるべきか」を整理しましたが、
第3章ではその思考をもとに、「どう構造に落とし込むか」を見てきました。
ここで見えてきたのは、
アーキテクチャの良し悪しは、特別なパターンや技術ではなく、
モジュールの分け方そのものに現れるということです。
凝集度・結合度・コナーセンスといった概念は一見地味ですが、
これらはすべて、
- 変更しやすいか?
- 影響範囲をコントロールできるか?
- チームで扱える構造になっているか?
といった、実務に直結する問いに繋がっています。
第2章で学んだ「トレードオフ思考」は、ここでもそのまま活きてきます。
分けるほど良いわけでもなく、まとめるほど良いわけでもない。
常にバランスを取りながら、最適な構造を探り続ける必要があります。
“良いアーキテクチャとは、最初から正しい形ではなく、
変化に耐えながら進化し続けられる構造である。”
第3章までで、
アーキテクチャの「考え方」と「構造」の両方が見えてきました。
次章(第4章「アーキテクチャ特性」)では、
この構造を評価するための軸である「可用性・スケーラビリティ・セキュリティ」などの
アーキテクチャ特性について掘り下げていきます。
ここからは、“どんな構造にするか”だけでなく、
“なぜその構造を選ぶのか”という視点がより重要になってきます。
引き続き、一緒にアーキテクチャの理解を深めていきましょう!!





