精読「ソフトウェアアーキテクチャの基礎」(1)
ソフトウェアアーキテクチャの基礎
本書は、ソフトウェア開発におけるアーキテクチャ設計の基本原則と実践的な知識を体系的に解説した一冊です。初心者から中級者まで、システム設計の基礎を固めたい人に最適なガイドです。アーキテクトだけでなく、チームリーダーや開発者にも役立つ内容が詰まっています。
関連記事
はじめに:公理を疑う
ソフトウェアアーキテクチャは、数学の公理のような不変の基盤ではなく、変化し続けるエコシステムの中で築かれるもの。本書は、過去の前提を疑いながら、現代の動的な環境に適応する方法を探る。特に、コンテナ化やマイクロサービスなどの進化がアーキテクチャ設計に与えた影響を分析し、新しいエンジニアリングプラクティスやトレードオフ分析に基づくアプローチを紹介する。ソフトウェア開発を工芸から工学へと進化させるための実践的な指針を提供し、アーキテクトに必要な技術的・非技術的スキルを体系的に学べる内容となっている。
イントロダクション
ソフトウェアアーキテクチャの定義
ソフトウェアアーキテクチャは以下で構成されている
- システムの構造: システムの実装に使用されるアーキテクチャスタイル(例: マイクロサービス、レイヤードアーキテクチャ、マイクロカーネルなど)
- アーキテクチャ特性: システムの成功基準となる非機能的な特性を指す。これらは直接的な機能ではなく、システムの品質やパフォーマンスを支えるもの。
- アーキテクチャ決定: システム構築時のルールや制約を指す(レイヤードアーキテクチャにおいて、ビジネス層とサービス層のみがデータベースに直接アクセスできる)
- 設計指針: アーキテクチャ決定の堅苦しいルールとは異なり、柔軟なガイドラインを提供する(サービス間通信には非同期メッセージングを使用することでパフォーマンスを向上させるべき)
これらの要素を統合的に考えることで、システムの全体像を明確にし、堅牢かつ効率的なソフトウェアを設計することが可能になる。
アーキテクトへの期待
ソフトウェアアーキテクトに求められる8つの期待が述べられている。これらの期待を実現することが、アーキテクトとして成功するための鍵となる。
アーキテクチャ決定を下す
アーキテクトは、技術的選択を直接決定するのではなく、開発チームが選択を行えるようにガイドする役割を持つ。具体的なツールや技術を指示するのではなく、開発チームがその選択肢を適切に判断できるよう、アーキテクチャ決定を行うことが求められる。
アーキテクチャを継続的に分析する
アーキテクトは、既存のアーキテクチャを継続的に評価し、改善策を提案する責任がある。特に、ビジネスや技術の変化を反映させ、アーキテクチャが効果的に維持されるよう努力することが求められる。
最新のトレンドを把握し続ける
アーキテクトには、技術的な最新トレンドや業界動向を把握し続けることが求められる。これは、将来のアーキテクチャ選択に影響を与えるため、長期的に持続可能な決定を下すための基盤となる。
決定の順守を徹底する
アーキテクトが行った決定が適切に順守されることが重要。開発チームがアーキテクチャの決定を守るように監視し、遵守を確保する役割がアーキテクトには求められる。
さまざまなものに触れ、経験している
アーキテクトには、さまざまな技術やプラットフォームに触れ、異なるシステムや環境との相互運用性について理解することが期待される。これにより、複雑なシステムを設計するための幅広い視点を得ることができる。
事業ドメインの知識を持っている
アーキテクトには、技術だけでなく、ビジネスや事業ドメインに関する理解も必要。ビジネス要件を満たす効果的なアーキテクチャを設計するために、事業ドメインの知識が欠かせない。
対人スキルを持ち合わせている
アーキテクトは、技術的な問題を解決するだけでなく、チーム内外との円滑なコミュニケーションやリーダーシップを発揮する能力も求められる。技術者であっても、人間関係やチームワークにおけるスキルを重要視する必要がある。
これらの期待を満たすためには、技術的な専門知識だけでなく、ビジネス理解や対人スキル、そして継続的な学習が重要。
アーキテクチャと交わるもの
ソフトウェアアーキテクチャの役割の進化と、その運用、エンジニアリングプラクティスとの関わりについて、アーキテクチャが運用と密接に連携するようになり、マイクロサービスのような現代的なアーキテクチャスタイルが、より柔軟で効率的なシステム設計を可能にした。
技術の進歩により、ソフトウェアアーキテクチャにもプロセスの問題が影響を与えるようになったが、プロセスとエンジニアリングプラクティスは分けて考えるべき。プロセスはチームやワークフローの仕組み、プラクティスは再現可能な効果を得る手法であり、特定のプロセスに依存しない。
さらに、アーキテクチャの進化において重要なのは、イテレーティブなプロセスの採用
。未知の問題(未知の未知)への対応が不可欠であり、アーキテクチャ設計も逐次的に進化することが求められている。このため、アーキテクチャとエンジニアリングプラクティスの密接な連携が必須となり、失敗しないためには、アーキテクチャと実際の運用が常に調整される必要がある。
最後に、マイクロサービスアーキテクチャを取り巻く技術として、自動化されたプロビジョニングやテスト、自動デプロイなどが挙げられ、これらを支えるエンジニアリングプラクティスとの相互作用が強調されている。
ソフトウェアアーキテクチャの法則
ソフトウェアアーキテクチャには広範囲な要素があるが、共通する法則がある。
第一法則
ソフトウェアアーキテクチャはトレードオフがすべてだ。 すべての決定は相反する要素を考慮しなければならず、もしトレードオフを避けていると感じたなら、それはまだ見えていないだけかもしれない。
第二法則
ソフトウェアアーキテクチャは「なぜ」の選択が「どうやって」よりも重要だ。 設計決定の背景や理由を理解することが本質的であり、選択肢の中でなぜその決定をしたのかを記録することが重要である。
アーキテクチャ思考
アーキテクチャ思考は、アーキテクトが物事を独自の視点で見る能力を指すもの で、ただ単に「アーキテクチャについて考えること」ではない。アーキテクトらしく考えるためには、以下の4つの側面を持つことが求められる
- アーキテクチャと設計の違いを理解し、開発チームと協力してアーキテクチャを機能させること。
- 広範な技術知識を持ち、他の人が見逃しがちなソリューションや可能性を見出す能力。
- さまざまなソリューションと技術のトレードオフを理解し、分析・調整できる能力。
- ビジネスドライバーの重要性を理解し、それをアーキテクチャに反映させること。
これらの要素を持つことで、アーキテクトはアーキテクチャ的な視点を活かし、広い視野で物事を考えることができる。
アーキテクチャと設計
アーキテクチャと設計の違いはしばしば混乱を招くが、重要なのはその密接な関係を理解することだ。アーキテクトは、ビジネス要件を分析してアーキテクチャ特性を定義し、適切なアーキテクチャパターンを選び、システムの構成要素を設計する責任がある。一方で、開発チームは、アーキテクチャに基づいて具体的なコードやクラス図、ユーザーインターフェイスを作成する責任を持つ。
従来のアーキテクトと開発者の関係は、物理的・仮想的な壁によって隔てられがちだが、これがコミュニケーションの断絶を生む原因となっている。アーキテクチャを効果的に機能させるためには、アーキテクトと開発者が一つのチームとして密接に連携し、双方向のコミュニケーションとメンタリングが求められる。現代のソフトウェアアーキテクチャは、プロジェクトの進行に合わせて進化し、設計とアーキテクチャが常に同期されるべきであり、明確な境界は存在しない。
技術的な幅
開発者とアーキテクトの役割では求められる技術的な深さが異なる。開発者は専門性を深め、技術のピラミッドの頂点を伸ばすことに焦点を当てる一方、アーキテクトは技術的な幅を重視し、複数のソリューションを理解する必要がある。アーキテクトとしての価値は、特定の技術の専門家になることではなく、幅広い技術的選択肢を適切に活用して問題を解決することにある。キャリアの転換に際しては、専門性を維持しつつも、幅を広げることが重要だ。
未知の未知を既知の未知へより
トレードオフを分析する
アーキテクチャにおけるトレードオフ分析の重要。アーキテクチャの選択肢に「正解」や「不正解」がないことは、すべての選択肢がトレードオフであるから。
これらのトレードオフを理解し、状況に応じて適切な選択をすることが、アーキテクトとして求められるスキル。最終的な選択は、ビジネスドライバーや開発環境、予算など多くの要因に依存する。
ビジネスドライバーを理解する
アーキテクトとして重要なのは、ビジネスドライバー(システムに影響を与えるビジネス上の要件) を理解し、それを技術的な要件(スケーラビリティ、パフォーマンスなど)に変換すること。そのためには、事業ドメインの知識とビジネスステークホルダーとの良好な関係が必要。
アーキテクティングとコーディングのバランスを取る
アーキテクトは、アーキテクティングとコーディングのバランスを取ることが難しい課題。アーキテクトはコードを書きつつ、チームのボトルネックにならないようにする必要がある。
バランスを取る方法の一つは、クリティカルパスやフレームワークの開発をチームに任せ、ビジネス関連の機能に集中すること。これにより、チームのオーナーシップを高め、現場感を維持しながら、アーキテクトは技術的な深みを保てる。
また、現場感を維持するためには、以下の方法がある。
- 概念実証(PoC)でアーキテクチャ決定を検証
- 技術的負債の解消やアーキテクチャストーリーに取り組む
- バグ修正で問題箇所を把握
- 自動化ツールを使って開発の効率を向上
- コードレビューでチームのコード品質をチェック
これらを通じて、アーキテクトは現場感を保ちながら、技術的な深さを維持できる。
モジュール性
モジュール性とは、ソフトウェアを管理しやすい部分に分ける原理で、システムの複雑さを管理するために不可欠。モジュールの定義には一貫性がないが、本書では独自の定義を提供し、その重要性を強調している。
優れたモジュール性を維持するためには、アーキテクトが要素同士の繋がりを意識し、秩序を保つためにエネルギーを使い続けなければならない。これにより、システムの複雑さが制御され、持続可能なコードベースが作られるのです。
定義
モジュールは「複雑な構造を構築するための標準化された部品や独立した単位の集合」と定義され、関連するコードを論理的にグループ化する手法として使用される。例えば、オブジェクト指向ではクラスの集合、構造化言語や関数型言語では関数の集合がモジュールとして扱われる。多くの言語は、モジュール化の仕組み(例:Javaのパッケージ、.NETの名前空間)を提供しており、開発者はこれを使ってコードを整理する。
モジュール性の計測
モジュール性は、アーキテクトにとって重要な概念であり、主に凝集度、結合度、コナーセンスの3つの指標を通じて評価される。
-
凝集度(Cohesion): モジュール内の要素の関連性を示す指標。高い凝集度は、要素が密接に関連している状態を意味する。凝集度が高いほどモジュールの分割が難しく、可読性が低下するリスクがある。
-
結合度(Coupling): モジュール間の依存関係を示す指標。低い結合度が望ましく、モジュールが他のモジュールに依存しすぎないことが理想。結合度を計測するためには、コールグラフを使った分析が有効。
-
抽象度と不安定度: モジュールの抽象性や変更の影響を測る指標。抽象度が高いほど、具体的な実装から切り離され、柔軟性が増す。
モジュールからコンポーネントへ
本書では「モジュール」を使うが、プラットフォームでは「コンポーネント」も一般的にサポートされる。コンポーネントはアーキテクトにとって重要な要素で、論理的・物理的な分離の概念が重要だ。多くの研究があるが、理想的な成果を得ることは依然難しい。
アーキテクチャ特性
企業がソフトウェアで問題を解決する際、システムに必要な要件を収集するが、アーキテクトはドメイン要件に加え、アーキテクチャ特性も定義・分析する必要がある。アーキテクチャ特性は、システムの重要な側面であり、非機能要件と呼ばれることもあるが、この表現を避け、著者は「アーキテクチャ特性」を好む。
アーキテクチャ特性の基準は次の3つ
- ドメインに依らない設計上の考慮事項
- 設計の構造的な側面に影響を与える
- アプリケーションの成功に不可欠または重要
特性は暗黙的なものと明示的なものに分けられ、設計に影響を与える。例えば、セキュリティは設計の要素となり、重要な特性がトレードオフを生むことが多い。
アーキテクチャ特性の(部分的な)リスト
アーキテクチャ特性は、コードのレベルからシステム全体に関する運用特性、構造特性、横断的特性まで、さまざまな側面にわたる。
-
アーキテクチャの運用特性
運用特性は、システムがどのように動作するか、特に運用中のパフォーマンスや信頼性に関連する特性。
特性 | 説明 |
---|---|
可用性 | システムが常に利用可能かどうか。 |
継続性 | 障害からの回復能力。 |
パフォーマンス | システムがどれだけ効率的に機能するか。 |
回復性 | 障害後の回復速度。 |
信頼性/安全性 | システムの信頼性や安全性の確保。 |
堅牢性 | 障害に強いシステムかどうか。 |
スケーラビリティ | ユーザー数やリクエスト数が増えてもシステムが機能する能力。 |
-
アーキテクチャの構造特性
構造特性は、コードやシステムの内部品質、例えばモジュール性や拡張性を指す。
特性 | 説明 |
---|---|
構成容易性 | エンドユーザーがシステム設定を変更できるか。 |
拡張性 | 新機能を追加しやすいか。 |
インストール容易性 | 異なるプラットフォームに簡単にインストールできるか。 |
再利用性 | コンポーネントが他の製品でも利用できるか。 |
メンテナンス容易性 | システムの変更や拡張が容易か。 |
-
アーキテクチャの横断的特性
これらは、特定の領域に属さないが重要な設計上の制約や要件。
特性 | 説明 |
---|---|
アクセシビリティ | すべてのユーザーがアクセス可能かどうか。 |
長期保存性 | データのアーカイブや削除に関する要件。 |
認証と認可 | ユーザーが適切なアクセス権限を持っているかどうか。 |
セキュリティ | データや通信の暗号化などのセキュリティ要件。 |
プライバシー | ユーザーのデータが適切に保護されているかどうか。 |
-
アーキテクチャ特性の変化と標準化の問題
アーキテクチャ特性は時折重複や曖昧さがあり、標準化が難しいこともある。例えば、可用性と信頼性は似ているが異なる概念であり、相互運用性と互換性も微妙に異なる。これらの違いを理解し、システムのニーズに最適な特性を選択することが求められる。
このように、アーキテクチャ特性はソフトウェア設計において非常に重要な要素であり、どの特性を重視するかはシステムの目的や要求に応じて決定する必要がある。また、これらの特性はシステム開発のライフサイクル全体を通じて考慮され、進化していくもの。
トレードオフと少なくとも最悪でないアーキテクチャ
アーキテクチャ設計では、特性同士が相互に影響し合うため、最善の選択は難しく、トレードオフが不可避。セキュリティ強化がパフォーマンス低下を招くように、アーキテクトは競合する特性間でバランスを取らなければならない。
最善を追うのではなく、「少なくとも最悪でない」アーキテクチャを目指すべきで、イテレーティブな設計が重要。初期段階で完璧を求めず、繰り返し改善することが推奨される。
アーキテクチャ特性を明らかにする
アーキテクチャ特性を明確にすることは、アーキテクチャの作成や既存アーキテクチャの評価において重要な最初のステップ。アーキテクトは、ドメインの問題を理解し、ステークホルダーと協力しながら、どのアーキテクチャ特性(「イリティ」)が重要かを見極める必要がある。特性を明確にするためには、ドメインの関心事、要件、暗黙的なドメイン知識という3つの視点から考えることが求められる。
アーキテクチャ特性をドメインの関心事から捉える
アーキテクチャ特性は、ドメインの関心事を反映させることで明確にする。ドメインの主要なゴールや状況を理解し、必要な特性(例:スケーラビリティ、耐障害性、セキュリティなど)を絞り込むことが重要。特性が多すぎるとシステムが複雑化し、効果的な設計が難しくなるため、重要な特性に絞って設計をシンプルに保つことが求められる。
ドメインの関心事をアーキテクチャ特性に変換する際、ドメインのステークホルダーと協力して、最も重要な3つの特性を選ぶことが有効。アーキテクチャ特性は、ドメインの関心事に対応する形で選定され、アーキテクトとステークホルダーの間で「ロスト・イン・トランスレーション」を防ぐため、一般的な翻訳が役立つ。
要件からアーキテクチャを抽出する
アーキテクチャ特性は、要件文書に明記されていないものも多く、アーキテクトのドメイン知識が重要。例えば、学生の履修登録システムを設計する際、学生の行動パターンを理解し、システム設計に影響を与えるべき。このような暗黙の知識は要件に記載されないことが多いが、設計の判断に必要不可欠です。
アーキテクチャ・カタは、初心者アーキテクトがドメインの記述からアーキテクチャ特性を導き出す練習。このカタを通じて、問題解決やトレードオフの分析を行い、設計スキルを高める。演習はタイムボックス化され、チームで設計を共有してフィードバックを得ることが推奨される。
事例:シリコンサンドイッチ
シリコンサンドイッチの事例では、アーキテクチャ特性を明示的なものと暗黙的なものに分けて考える。明示的な特性として、スケーラビリティや弾力性、セキュリティなどが挙げられる。
例えば、数千から数百万のユーザーに対応するスケーラビリティは重要で、また注文時に提供される道順情報のためには信頼性が求められる。一方、暗黙的な特性には、トラフィックのバースト対応や、プロモーションメニューのカスタマイズ性などが含まれ、これらは設計の中で考慮されるべき。
アーキテクチャ特性の計測と統制
アーキテクチャ特性の計測
アーキテクチャ特性の計測において、いくつかの課題が存在する。まず、特性(例:アジリティやデプロイ容易性)の定義が曖昧であり、組織内でも部署ごとに解釈が異なる場合がある。また、これらの特性は複数の要素に細分化できることから、複合的に捉える必要がある。たとえば、アジリティはモジュール性やデプロイ容易性などの要素が絡み合う特性。これらの課題を解決するためには、特性を計測可能な形で定義し、組織全体で共通の理解を得ることが重要。
具体的な計測方法として、運用面ではパフォーマンスやモバイル性能に注目する。パフォーマンスについては、平均応答時間や最大応答時間といった指標を設定し、統計モデルを活用してリアルタイム監視や外れ値の検出を行う。モバイル性能に関しては、初回ペイント時間や初回アイドル時間などの指標を使用する。
一方、構造面ではコードの循環的複雑度(Cyclomatic Complexity, CC)を活用する。これはコードの実行経路の複雑さを示す指標であり、値が10以下であれば許容範囲、5以下であれば理想的とされている。循環的複雑度が高いと、モジュール性やテスト容易性に悪影響を与える可能性があるため、注意が必要。
これらの特性の計測には、問題領域の複雑さを理解したうえで柔軟に適用することが求められる。また、チーム内で計測対象の特性や方法について共通の認識を持つことが成功の鍵となる。
統制と適応度関数
統制とアーキテクチャ特性
アーキテクトの重要な役割は、アーキテクチャ特性(モジュール性や性能など)に優先順位をつけ、それを開発チームに尊重してもらうこと。しかし、緊急性が低いが重要な特性(例:モジュール性)は、日々の開発で軽視されがち。そのため、アーキテクトには統制(Governance)という仕組みが必要。この統制とは、ソフトウェア開発プロセス全体に影響を与える枠組みを作り、品質を確保するためのもの。
適応度関数の概念
進化的アーキテクチャの一環として紹介される適応度関数は、アーキテクチャ特性の整合性を客観的に評価する仕組み。この概念は遺伝的アルゴリズムに由来し、特定の目標(例:コストや移動時間の最小化)に向けた指標として機能する。ソフトウェア開発では、適応度関数を使ってモジュール性や結合度などの特性を測定し、開発者がアーキテクチャの指針を守りやすくする仕組みを提供する。
適応度関数の意義
これらの適応度関数は、アーキテクチャ特性を客観的かつ継続的に検証できる仕組み。また、これらを開発チームが理解し実装できる形にすることで、アーキテクトと開発者が協力して高品質なシステムを構築する基盤となる。適応度関数の目的は、特性を測定しつつ開発プロセスの中に自然に統合することにある。
このように、統制と適応度関数は、アーキテクチャの品質を守るための実践的な手法として機能する。それにより、緊急性が低くても重要なアーキテクチャ特性が軽視されることを防ぎ、プロジェクト全体の健全性を保つことができる。
アーキテクチャ特性のスコープ
アーキテクチャ特性のスコープは、モノリシック時代ではシステム全体に適用される前提が主流だが、マイクロサービスの普及により特性のスコープが細分化されている。既存のメトリクスではコード外の依存コンポーネント(例:データベース)の影響を評価できないため、「アーキテクチャ量子」という概念が導入され、より正確な特性評価が可能となった。
結合とコナーセンス
コナーセンスは、コンポーネント間の依存関係を示す尺度。変更が他のコンポーネントを必要とする場合、これらはコナーセントされているとされる。静的コナーセンスはコード解析で、動的コナーセンスは実行時の振る舞いで計測される。マイクロサービス間で共通のクラス定義を使用していれば、静的コナーセンスが生じ、変更時に両方を更新する必要がある。また、動的コナーセンスは同期型と非同期型があり、非同期型はサービスの独立性を保つ。
アーキテクチャ量子と粒度
アーキテクチャ量子とは、高度に凝集し、独立してデプロイ可能なコンポーネントのこと。これには以下の要素が含まれる。
- 独立してデプロイ可能 - 他のシステム部分に依存せず、単独で機能する。
- 高度な機能的凝集性 - コンポーネントがその目的に対して一貫性がある。
- 同期的なコナーセンス - サービス間での同期的な呼び出しが運用特性に影響を与え、動的に調整される。
また、ドメイン駆動設計(DDD)の「境界づけられたコンテキスト」を理解し、アーキテクチャ量子を使ってシステム特性を明確にする方法が示されている。
コンポーネントベース思考
アーキテクトがアーキテクチャを構築する際にコンポーネントを中心に考えることが重要。モジュールはコードの集まりで、コンポーネントはその物理的表現。例として、Javaのjar、.NETのdll、Rubyのgemが挙げられ、コンポーネントに関するアーキテクチャの考慮事項が説明されている。
コンポーネントの分類
コンポーネントは、言語固有の仕組みでアーティファクトをグループ化し、階層化された構造を持つことが多い。例えば、ライブラリはコードをより高度なモジュールでラップし、同じアドレス空間で実行される。
さらに、サービスコンポーネントは独自のアドレス空間で動作し、TCP/IPやRESTを介して通信し、マイクロサービスアーキテクチャで独立したデプロイユニットを形成する。コンポーネントは必須ではなく、マイクロサービスなどでは必要ないこともあるが、アーキテクチャの基本構成要素として重要。アーキテクトは、アーキテクチャ内で最上位コンポーネントの分割方法を決定しなければならない。
アーキテクトの役割
アーキテクチャの分割方法には、技術による分割(レイヤードアーキテクチャなど)と、ドメインによる分割(ドメイン駆動設計に基づく分割など)があり、それぞれにトレードオフがある。
技術による分割
技術能力ごとにシステムを分割する方法。例えば、プレゼンテーション層、ビジネスルール層、永続化層などに分けることが一般的。このアーキテクチャスタイルは、技術的な関心事を分けることで、システム内の各部分が疎結合になり、変更の影響を最小限に抑えることができる。しかし、このアプローチでは、特定のビジネスワークフロー(例えばカタログチェックアウト)が、すべての層にまたがって現れるため、処理が横断的に関わる場合には煩雑になる可能性がある。
ドメインによる分割
一方で、ドメイン駆動設計(DDD)に基づくドメインによる分割は、ビジネスのドメインやワークフローを中心にシステムを分割する。このスタイルでは、技術的な要素に関わらず、ビジネスの重要な領域(ドメイン)を優先してシステムを設計するため、ビジネス変化に柔軟に対応できる。ただし、このアーキテクチャでは、技術層がドメインに組み込まれており、各ドメイン内でレイヤーを持つこともある。
どちらのアーキテクチャスタイルを選ぶかは、プロジェクトのニーズに大きく依存する。技術による分割は、技術的な管理がしやすく、特に異なる技術スタックを使う場合に有効だが、ドメインに関連した変化に対応する際には柔軟性に欠けることがある。ドメインによる分割は、ビジネスドメインに基づいてシステムを構築できるため、ビジネスのニーズに適したアーキテクチャとなりやすいが、技術的な整理が複雑になることがある。
最終的に、選択肢はプロジェクトの特性や要求に基づいて決定されるべき。それぞれのアーキテクチャスタイルには長所と短所があるため、アーキテクトはプロジェクトの目標や状況に最適な方法を選択する必要がある。
開発者の役割
開発者はアーキテクトと共に設計を実装し、設計段階では気づかない改善点を見つける役割がある。設計は最初の下書きと考え、実装を通じて詳細や改良を進めるべき。
コンポーネントを識別する流れ
コンポーネントを識別するためには、イテレーティブなプロセスを用いて、フィードバックを通じて改良していくのが効果的だ。プロセスは以下のステップに分かれる。
- 初期コンポーネントを識別する: アーキテクトは、プロジェクトの初期段階でコンポーネントを識別し、ドメイン機能と振る舞いを割り当てる。
- コンポーネントに要件を割り当てる: 要件とコンポーネントをマッピングし、必要に応じて新しいコンポーネントの作成や統合を行う。
- ロールや責務を分析する: 要件に基づいてコンポーネントの粒度を調整し、適切な責務を割り当てる。
- アーキテクチャ特性を分析する: アーキテクチャ特性を考慮し、コンポーネントの分割や粒度を調整する。
-
コンポーネントを再構成する: フィードバックを受けて、コンポーネント設計を継続的に改善し、未知の問題に対応する。
このように、コンポーネント設計は反復的に行われ、発見や問題に対応しながら改善されるべき。
コンポーネントの粒度
コンポーネントの粒度を適切に決定することはアーキテクトにとって重要かつ難しい課題。粒度が細かすぎると、コンポーネント間でのやりとりが多くなり、効率が低下する。一方、粒度が粗すぎると、コンポーネント同士の結合度が高くなり、デプロイやテストが難しくなるほか、モジュール性にも悪影響を及ぼす。そのため、粒度の調整には慎重さが求められる。
コンポーネント設計
コンポーネント設計には一つの「正しい」方法はなく、多くの手法があり、それぞれにトレードオフが存在する。アーキテクトは要件に基づき、システムを構成するコンポーネントの粒度を決定する。
-
アクター/アクションアプローチ:
要件に基づき、システム内でアクションを実行するアクター(ユーザー)を特定し、そのアクターが行う可能性のあるアクションに基づいてコンポーネントを設計します。この方法は、特に事前設計を重視するソフトウェア開発プロセスで有効です。 -
イベントストーミング:
ドメイン駆動設計(DDD)やマイクロサービスアーキテクチャに基づき、システム間でのイベントやメッセージを中心にコンポーネントを設計します。イベントストーミングは、メッセージングや分散システムに適したアプローチです。 -
ワークフローアプローチ:
イベントストーミングに代わるアプローチで、メッセージングを使用せずに、主要なロールとそのワークフローを基にコンポーネントを設計します。
これらの手法は、使用するソフトウェア開発プロセスやアーキテクチャによって適切なものが変わるため、各手法のトレードオフを理解して選択することが重要。
アーキテクチャ量子再び:モノリシックアーキテクチャと分散アーキテクチャの選択
アーキテクチャ量子は、アーキテクチャ特性のスコープを定義する重要な概念。この量子は、システムがどのように構成され、どの範囲で特性が共有されるかを決定する。具体的には、アーキテクトが最初のコンポーネント設計を終えた時点で、アーキテクチャがモノリシックか、それとも分散型かを判断する助けとなる。
モノリシックアーキテクチャ
モノリシックアーキテクチャは、システムのすべての機能を単一のデプロイ可能ユニットとして組み込んだもので、通常は1つのプロセス内で実行される。また、単一のデータベースと接続し、全ての機能がその中に含まれています。モノリスには以下の特徴がある。
- レイヤードアーキテクチャやモジュラーモノリスが含まれ、1つのユニット内で管理される。
- アーキテクチャ特性が単一の量子で管理されるため、設計が単純化され、開発や運用が一元化される。
分散アーキテクチャ
一方、分散アーキテクチャは、複数のサービスがネットワーク経由で通信する形態。各サービスが独立して動作し、独自のリリースサイクルやエンジニアリングプラクティスを持つことができる。これには以下の利点がある。
- サービスごとに異なるアーキテクチャ特性(スケーラビリティ、可用性、弾力性など)を持たせることが可能。
- 開発チームやシステムの要求に応じた、柔軟なデプロイモデルが採用できる。
アーキテクチャ量子と設計決定
アーキテクチャ量子の数に応じて、アーキテクチャスタイルが決まる。もしシステムが単一の量子で管理できるのであれば、モノリシックアーキテクチャが選ばれることが多い。しかし、GGGのように、異なるコンポーネントに異なるアーキテクチャ特性を適用する必要がある場合、分散アーキテクチャが適切になる。
たとえば、VideoStreamerとBidStreamerは、異なるアーキテクチャ特性(ストリーミングの更新頻度やパフォーマンス要件)を持っているため、分散アーキテクチャを選択する理由となる。
このように、アーキテクチャ量子を用いて、システムのスコープや結合を分析し、モノリスまたは分散型のアーキテクチャの選択が決まる。これは、システム設計の早期段階でアーキテクチャの基本的な方向性を決定する際に非常に有益。
参考
Discussion