スポンサーリンク
概要
オライリーから発売されている、「ソフトウェアアーキテクチャの基礎 エンジニアリングに基づく体系的アプローチ」を読んだので感想を書こうと思います。
技術書のセールとおすすめ書籍を紹介しています。合わせてご覧ください。
スポンサーリンク
書籍概要
どんな本?
ソフトウェアアーキテクチャとは、ソフトウェアシステムの成功に欠かせない重要な土台です。そのためソフトウェア開発者には、効果的なアーキテクチャを実現するスキルが求められます。
本書は、そうした効果的なアーキテクチャを設計、構築、維持するアーキテクトになるために必要なスキルや知識を、現代的な視点から整理して包括的に解説する書籍です。
ソフトウェアアーキテクチャの定義から、アーキテクトの役割、モジュールや結合、アーキテクチャスタイルといったアーキテクチャ設計の基礎、チームやステークホルダーと効果的にコラボレーションしていくために必要なソフトスキルまで、さまざまなトピックについて実践的な例とともに説明します。
- Mark Richards、Neal Ford 著、島田 浩二 訳
- 2022年03月 発行
- 438ページ
- 定価4,180円(税込)
スポンサーリンク
内容のまとめと感想
ソフトウェア全体の構造を設計するアーキテクチャの設計技法に関してまとめた書籍です。
具体的なクラス構造や実装ではなく、システム全体としてどういった構造にするのかといった抽象度としては高めの内容になっています。
ですので、最初は??となるような部分が多いものの、何度か読み返したり、しばらく寝かして経験を積んだ後などに読むと新たな発見や理解が進むかもしれません。
(実際に私も1周目は結構眠くなる事が多かったですが、このブログ用に再度読み込んで要点を書き出す事で理解が進んだポイントも多かったです。)
個人的には定期的に、何度か読み直したい本だと思いました。
書籍内で何度も出てくるワードとして、「トレードオフ」があります。
全ての要望や要件を満たすような設計は難しく、相反する特性(例:セキュリティとパーフォーマンス)の中で何を優先するのかを選択する事が、アーキテクチャの設計であると語られています。
その判断を行うための画一的な答えはなく、要件に応じて何が重要なのか見つけ出す事がアーキテクチャの設計作業である、という事が繰り返し述べられています。
ですので、本書ではアーキテクチャの設計において、どうやって決定を行うかといったヒントや考え方のヒントが多く示されているのが特徴です。
またアーキテクチャの設計だけではなく、実際にシステムとして落とし込むために必要となる、様々なメンバーとのコミュニケーション手法なども書かれてて面白いです。
全体の構造を決めるような設計には、それを実装するチームはもちろんのこと、運用管理や経営などのステークホルダーが多く関わってくるので、そういった人たちといかに協調的な関係を作るのかが大事になってくるので、必要になるスキルなので当然なのかもしれません。
Design It!との違い
このようなアーキテクチャを設計するための手法や思考をまとめた書籍として、同じくオライリーから発売されている「Design It!」といった書籍が存在します。
(本ブログでも以前紹介しています。)
「Design It!」と内容的に重複する箇所は見受けられるものの、本書はより具体的なアーキテクチャパターンの紹介に紙面を多く割いているのが大きい違いかと思いました。
一方でソフトウェアのデザインに関わる全般的なプラクティスや手法、ツールに関して幅広くカバーしているのが「Design It!」となっていて、両書を読むことでより理解が進むのではないかと思いました。
どちらも抽象度が高めで読み込むのに労力を要しますが、本書の方が技術的な例や説明も多く、若干抽象度としては低めでで読みやすいと思うので、先に読んだ方がいいと思います。
良かった点
例ベースでの補足
各章では比較的抽象度の高い説明の後に、具体的な例をベースにどのようにアーキテクチャを作っていくのかを補足してくれており理解を助けてくれます。
(オークションシステム、サンドイッチ店などを例にして説明してくれています。)
様々なアーキテクチャスタイルの提示
レイヤードアーキテクチャ、マイクロサービスアーキテクチャなど、具体的なアーキテクチャのスタイルを図等を使って説明してくれます。
それぞれの特徴やメリット、デメリットを説明し、各スタイルのまとめには各アーキテクチャ特性に対しての評価も星1〜5で評価した表も載っていて、スタイルの採用の際には参考になると思います。
具体的なコードによる説明等はほとんど無いので、スタイルによってはあまり具体的なイメージがしにくいといった点もありました。
サンプルでも良いので具体的なコード例もついていると個人的にはもっと良かったです。
とはいえ、昨今多く目にするマイクロサービスアーキテクチャをはじめ、こういったアーキテクチャのスタイルを幅広く紹介されており、「なんとなく聞いた事はあるけど・・・」から踏み込んで内容を知る機会が得られるので、参考になるのではないかと思います。
気になった点
詳細は後述するといった内容が多い
文章内で「A」に関しては、X章で詳細を説明するといった記載が多く、読む際に冗長に感じました。
1度読んである程度全体の内容がわかると、そこまで違和感はないかもしれませんが、結構頻繁に出てくるのでちょっと読んでいて気になりました。
抽象度が高く一部読みにくい
こういった抽象度が高い翻訳本においては必ず問題となるのですが、一部の文章は冗長で読みにくく感じました。
前提知識が多く求められる
DDD(ドメイン駆動開発)などを中心に、本書以外でも多く取り上げられる開発関係の用語や概念が多く出てきます。
本書でも説明などはありますが、そういった用語や知識に関してある程度の理解がないと、理解が難しいかもしれません。
読書ノート(個人的なまとめ)
イントロダクション
本書におけるソフトウェアアーキテクトおよびアーキテクチャとは何なのか?を定義している。
- ソフトウェアアーキテクトの定義は難しい
- 理由1:定義が業界で定まっていない (定義するのは難しい)
- 理由2:役割が広範囲に広がり続けている。
- 10年前は技術的な側面だけをメインに考えておけばよかった。
- 現在はマイクロサービスのような広範囲な能力を求められるものが台頭してきている。
- 理由3:エコシステムの急激な進化により常に変化するものとなった。(決定後も常に変化が必要になる)
- 理由4:資料の多くが歴史的な経緯となってしまっている。(役割を終えたものや失敗したものが多い)
- アーキテクチャの多くは直面する環境(文脈)の中で初めて理解できるものである
- 2000年ごろにマイクロサービスを唱えても現実的ではなかった(Windowsのライセンス費用など)
- その後のOSSの台頭とDevOpsの普及によって現実化されたものである
- ソフトウェアアーキテクチャの定義
- システムの構造、アーキテクチャ特性、アーキテクチャ決定、設計指針の組み合わせで構成されるもの
- システム構造:システムを実装するアーキテクチャのスタイル(マイクロサービス、レイヤードアーキテクチャなど)
- アーキテクチャ特性:システムがサポートしなければならない特性(可用性、信頼性、など)
- アーキテクチャ決定:どのように構築するのかのルール。構想から具体化を進めたもの。開発チームの指針となる。
- 例:レイヤードアーキテクチャ(構造)で、ビジネス層とサービス層のみがDBにアクセス可能とする
- 設計指針:決定のようなルールではなく、設計におけるガイドライン。
- 例:プロセス間の通信は非同期メッセージングを使用する
- アーキテクトへ期待されること
- アーキテクチャ決定を下す:技術的な選択の指定ではなく、ガイドであるべき。(フロントエンドにReactを使うと決定するのではなく、リアクティブベースのものを使用する決定をする。)
- アーキテクチャを継続的に分析する:継続的に分析を行い、健全性が保たれているかチェックする
- 最新のトレンドを把握し続ける:下した決定に伴う変更が難しいので、業界の動向を把握し、それに沿う事で適切な判断を下すのに役立つ。
- 決定の遵守を徹底する:決めたルールが守られているかの継続的な確認が必要。
- 多様なものに触れ、経験している:技術的な幅が求められる。(1種類の技術の専門家よりも10種類の技術の長所と短所を抑えている方が価値がある。)
- 事業ドメインの知識を持っている:ビジネス上の問題や課題を把握し、ステークホルダーとの信頼を構築するのに必要
- 対人スキルを持っている:チームワークやファシリテーション、リーダーシップなどチームを引っ張っていく能力が求められる。
- 政治を理解し、かじ取りをする:多くのアーキテクチャの決定は反発を生む。それらを承諾してもらう必要がある。
アーキテクチャ思考
アーキテクトは開発者と異なる、より幅広い視点を持つ必要がある。
本章はアーキテクチャ思考として、どういった観点で物事を考えていけば良いのかを示している。
- アーキテクチャと設計
- アーキテクチャと設計の違い
- アーキテクチャ:ビジネス用件からアーキテクチャ特性などを定義する (1章で定義した各種定義) => アーキテクトが担当
- 設計:アーキテクチャ特性からクラス設計やコードの製造などを行う => 開発者が担当
- 従来のようなアーキテクチャ=>設計の一方方向の開発ではなく、アーキテクトとチームが一緒にコラボレーションしていく事が必要
- トレードオフを分析
- アーキテクチャは全てがトレードオフ:あらゆる問いに対する答えは「場合による」となる。
- 例:オークションシステムにおける2つの実装方法に関して
- Pub/Subメッセージング:
- メリット:拡張性
- デメリット:データセキュリティに関する
- P2Pメッセージング:
- メリット:サービスの分離
- デメリット:それぞれに固有のコントラクト、監視によるロードバランシング
- Pub/Subメッセージング:
- アーキテクティングとコーディングのバランスを取る
- 全てのアーキテクトがコードを書き、一定レベルの技術的な深さを維持すべきである
- ボトルネックの罠を避ける:基礎となるコードを自身で担当せずにチームに委ねる。代わりに1〜3回程度のイテレーションで完成可能な機能の開発を行う。
- 技術的負債やアーキテクチャに関わる機能を担当したり、バグを担当、またはコードレビューを行うなどしてコーディングスキルの維持を図る方法なども考えられる
- アーキテクチャと設計の違い
アーキテクチャ特性
ドメインやビジネス要件を定義するだけではなく、ドメインの機能に直接関与しないが見たさなければならない内容をアーキテクチャ特性と定義される。
(非機能要件とも言えるが本書ではこの呼び方には否定的)
- アーキテクチャ特性
- ドメインに依らない、設計に関する考慮事項を明らかにしたもの:パフォーマンス、技術的負債を防ぐことなど
- 設計の構造的な側面に影響を与えるもの:セキュリティ
- アプリケーションの成功に不可欠な重要なもの:可能な限りではなく、一握りの特性のみを選びとる必要がある
- 特性の部分的なリスト
- システムによって特性はケースバイケースであり、完全なリストは存在しない。ここでは代表的な特性のみをリストアップしている。
- 運用特性:パフォーマンス、スケーラビリティ、弾力性、可用性、信頼性などDevOpsの関心事と大きく重なっている
- 構造特性:コードの構造に関する特性。構造容易性、拡張性、インストール容易性、ローカライゼーションなど。
- 横断的特性:分類できないが設計において重要な特性。アクセシビリティ、認証認可、プライバシー、セキュリティなど。
- 多くの決定は競合するため、最終的にはトレードオフが発生する。
- 例:セキュリティを満たすためには、暗号化などによりパフォーマンスは低下する。
- 決して最善のアーキテクチャを狙わず、むしろ少なくとも最悪でないアーキテクチャを狙う事
- システムによって特性はケースバイケースであり、完全なリストは存在しない。ここでは代表的な特性のみをリストアップしている。
アーキテクチャ特性を明らかにする
アーキテクチャ特性を要件から見つけ出す方法を本章では説明している。
具体的な例として、あるサンドイッチ店を想定した要件からどのようにアーキテクチャ特性を見つけ出すかを示している。
また、要件から直接的にわかる特性以外にも、セキュリティなどの暗黙的な特性が必要となることも示されている。
- アーキテクチャ特性をドメインの関心事から捉える
- 全ての特性をサポートするような設計はせず、ステークホルダーと協力し、可能な限り絞る事が大切
- 必要な特性に順位をつけずに、最も重要な3つを選んでもらうのが有効(順位をつけると同意を得るのが難しい
- ドメインの関心事と特性は一致しないため、翻訳が必要(例:合併買収=>相互運用性、スケーラビリティ、拡張性など)
コンポーネントベース思考
プログラムをクラスや関数単位でまとめたものを「コンポーネント」と呼ぶ。
このコンポーネントをどのように定義していくのかを本章では説明している。
- アーキテクトのコンポーネントにおける役割
- アーキテクチャを構成するコンポーネントを定義、改良、管理、統制する。
- コンポーネントを構成するクラスや関数をアーキテクト自身が設計しても良いが、開発者に決定を委譲した方が良い。(次世代のアーキテクトを育成するためにも。)
- コンポーネントの発見はアーキテクチャをどのように分割するのか見極める必要がある
- アーキテクチャの分割
- 分割にはいくつかの一般的なスタイルがある。(それぞれにトレードオフがある)
- 2つの最上位分割の例
- 技術による最上位分割(レイヤードアーキテクチャ):システムの機能を技術能力ごとに分割(例:プレゼンテーション、永続化, etc)
- 特定の処理ごとにコードが分割される(DB、UIなど)
- グローバルな結合が多い(共通なCommonモジュールなどができる)
- ドメインによる最上位分割(モジュラーモノリス)システムの機能をドメインによって分割(ドメインごとに技術能力を持つ)
- ビジネス機能に近い形でモデル化される
- 似たような共通処理がドメインごとに重複する
- 技術による最上位分割(レイヤードアーキテクチャ):システムの機能を技術能力ごとに分割(例:プレゼンテーション、永続化, etc)
- どちらが正しいということはなく、トレードオフに基づいて決断を行う必要がある
アーキテクチャスタイル基礎
プログラムのデザインパターンのように、アーキテクチャにはアーキテクチャスタイルといった様々な代表的なパターンがある。
- モノリシックアーキテクチャ:全てのコードが単一のデプロイメントユニットで構成
- レイヤードアーキテクチャ
- パイプラインアーキテクチャ
- マイクロカーネルアーキテクチャ
- 分散アーキテクチャ:リモートアクセスプロトコルを介して接続された複数のデプロイメントユニット
- サービスベースアーキテクチャ
- イベント駆動アーキテクチャ
- スペースアーキテクチャ
- サービス指向アーキテクチャ
- マイクロサービスアーキテクチャ
- 分散アーキテクチャのメリットと誤信
- 分散アーキテクチャはパフォーマンス、スケーラビリティの面でモノリシックより優れている
- ただしトレードオフも多い
- ネットワークの信頼性に依存
- レイテンシー
- 帯域に制限がある
- ネットワークは必ずしも安全ではない (エンドポイントの保護による性能低下)
- トポロジーの変化による影響(機器のアップデートやリプレースなど)
- 管理者が複数(ネットワーク管理者など
- コスト(サーバー、ネットワーク機器の増加
- ネットワークは均一ではない(複数のベンダによる機器
- 分散ロギング、分散トランザクションへの対応
- コントラクトやバージョンの管理
レイヤードアーキテクチャ
おそらく一番よく耳にするであろう、レイヤードアーキテクチャの説明の章。
- 関心事の分離
- レイヤーによる責務の分離(プレゼンテーション、ビジネス、永続、DB)
- 技術的な関心事による分割、ビジネスドメインが散らばってしまうのが問題(ドメイン駆動開発とは相性悪い)
- 開放レイヤー、閉鎖レイヤー
- 閉鎖レイヤー:各レイヤーは隣り合ったレイヤとのみ相互作用がある
- 開放レイヤー:レイヤをスキップしてアクセスできる(例:プレゼンテーションからDBに直接アクセス)
- 開放レイヤを許すと層の分離ができず、アプリケーションの変更に脆くになる(例:プレゼン層をJSFにReactに置き換えといった事が難しくなる)
- その他の考慮事項
- どのアーキテクチャスタイルでいくかの確信が取れていない場合に出発点として使用される(階層は浅く、モジュール性を適切に保つ必要がある)
- 各層が何もせずにそのまま次の層にスルーする割合が20%を超えるならば、他のアーキテクチャを考慮すべき
- 特徴
- 小規模でシンプルなアプリケーション、Webサイトに適している
- 予算と時間に厳しい制約がある際に適している
- デプロイや容易性、スケーラビリティ等で問題を抱え、大規模システムには向いていない
パイプラインアーキテクチャ
単機能なフィルターと呼ばれる機能をパイプで繋いでいき、最終的なアウトプットを出力するパターン。
Unixのシェルのようなイメージ。
- パイプとフィルター
- パイプ:フィルター間の通信、一方方向でP2P
- フィルター:独立し、一般的にステートレス。単一のタスクのみを行う。
- プロデューサー:処理の開始点。出力のみ。ソースとも呼ばれる。
- トランスフォーマー:入力を受け、データの一部または全てを変換し、出力する。(map)
- テスター:入力を受け、基準に基づいて検査し、フィルタしたもの出力する(reduce)
- コンシューマー:終了点。最終結果をDB等に永続化したりする責務。
- 特徴
- 技術によって分割されたアーキテクチャ
- フィルタの独立性により、モジュール性が高く、変更容易性が高い
- スケーラビリティは低い(複雑なマルチスレッドなどが要求される)
マイクロカーネルアーキテクチャ
パッケージソフトウェアのようなスタンドアローンアプリケーションによく用いられるパターン。
- コアシステム、プラグインコンポーネント
- コアシステム:
- システムを実行するのに必要な最低限の機能を定義したもの
- カスタム処理をプラグインコンポーネントとして切り出して複雑さを減らし、拡張性と保守性を保つ
- レイヤード、ドメインのどちらの構造も採用できる
- プラグインコンポーネント:
- コアシステムを強化、拡張するための処理や機能
- RESTを使用して実装することもで可能(この場合は分散アーキテクチャとなり、トレードオフが発生する。)
- コアシステム:
- 特性
- シンプルさと低コストがメリット
- スケーラビリティ、耐障害性が弱い
- プラグイン形式による保守性の高さ
サービスベースアーキテクチャ
分散アーキテクチャだが、マイクロサービスなどのような複雑さやコストがなく、人気のアーキテクチャ。
柔軟性の高さからもっとも実用性の高いアーキテクチャスタイルの1つとして考えられている。
- 構造
- 分散型のマクロなレイヤード構造(UI、粒度の荒いサービス、単一DB)
- サービス
- サービスは個別にデプロイ可能なアプリの一部(ドメインサービス)
- サービスの数は一般的に4〜12個、(平均7)
- UIからRESTなどでリモートアクセスされる
- サービス内はレイヤード構造になる(APIファサード層+α)
- 技術による分割(レイヤード:ビジネス層+永続化層)
- ドメインによる分割
- パターン
- ドメインごとにUIを分割
- DB自体の分割
- DBとエンティティの共有
- 問題点:DBのエンティティオブジェクトのライブラリを共有するとスキーマ変更で全てのサービスに影響を与えてしまう
- 解決策:共通エンティティのみをCommonとして共有、それぞれのサービス固有のエンティティのみを定義する
- 特性
- ドメインによって分割される
- 特定のサービスの変更が他への影響が小
- 高い耐障害性と容易なデプロイ
- 他の分散アーキテクチャほど複雑ではなく、トランザクションの調整などが比較的容易
イベント駆動アーキテクチャ
スケーラブルで高パフォーマンスなアプリケーションを実現するのに適した分散型アーキテクチャ。
ブローカーとメディエータといった2種類の処理方式があり、それぞれにトレードオフがある。
- ブローカーとメディエーター
- ブローカー:
- チェーン状にイベントを繋いでいく
- 軽量なメッセージブローカー(RabbitMQなど)が使用される(Pub/Sub型)
- 中央でのイベントの制御や調整は行わない
- メリット:スケーラビリティ、耐障害性、パフォーマンス
- デメリット:ワークフロー制御、エラー処理、回復性、データ不整合などの制御を必要とする処理に対応が難しい
- メディエーター:イベント処理のワークフロー制御に利用される
- 複数のイベント処理のワークフローを制御する(最初はAというプロセッサにイベント通知、Aが終わったら次はBへ)
- 各イベントの詳細は知らず、ステップのみを管理する。各イベントは作業が完了した事をメディエーターに通知する。
- 複雑度に応じて様々な実装フレームワークが存在する
- シンプル:Apache Camel, Mule ESB, Sprint Intergration
- 複雑:Apache ODE, Oracle BPEL
- メリット:ワークフロー制御、エラー処理、回復性、データ不整合などの制御が実現可能
- デメリット:イベント処理との結合が強くなる、スケーラビリティ、パフォーマンス、耐障害性の低下
- 非同期通信:イベント駆動アーキテクチャは非同期通信にのみ依存する
- 処理を受け取ったというレスポンスだけを受け取るので応答性が高い
- 代わりにエラー処理が複雑になる
- イベント処理側でエラーが発生した場合には、別のイベント(ワークフロープロセッサ)に処理を委譲する
- ワークフロープロセッサは処理の回復(データ修復後、再度イベントキューに再び投げる)やユーザーへのエラー通知を行う
- データロス;非同期通信にはデータロスのリスクが存在する、その対策方法
- メッセージがキューに到達しない:永続的なメッセージキューに同期送信する(キュー側はDB等にメッセージを保存する
- キューからイベントを取得した処理がクラッシュ:クライアント応答モードを使用(取り出されたキューにIDを付与して、完了まで管理し削除しない。)
- イベント処理がDBへの保存できない:DBのトランザクションを利用する
- リクエスト、リプライメッセージング(擬似同期通信)
- メディエータなどのイベント発行側が処理を依頼したイベントから、応答を受け取りたい場合に使用
- 注文イベントにキュー=>注文処理が完了したら注文IDを返す
- リクエストキュー、リプライキューという2つのキューを使用して、相互に通信を行う
- 発行側はリプライキューからの応答まで高濁の処理をストップする
- メディエータなどのイベント発行側が処理を依頼したイベントから、応答を受け取りたい場合に使用
- リクエストベースモデルとイベントベースモデルの使い分け
- 従来のリクエスト、レスポンス型の処理はデータ取得処理のようなものに適す
- イベントベースモデルは複雑で動的なワークフローや処理で、高いスケーラビリティが求められるものに適す
- 2つを組み合わせたハイブリッド型も可能
- ブローカー:
- 特徴
- 技術によって分割
- パフォーマンス、スケーラビリティ、耐障害性が高い
- 単純性とテスト容易性が低い(複雑で管理が難しい
スペースベースアーキテクチャ
高いスケーラビリティ、弾力性、同時実行性に対処するためのアーキテクチャスタイル。
DBへのアクセスをリーダーとライターを経由した非同期アクセスとキャッシュベースの利用にすることで、ボトルネックになりがちなDB層のスケールを可能としたもの。
(かなり複雑な構造で、自前で一から作ろうと思うと大変なので、基本は商用なりOSSのフレームワークを組み合わせて実現する?)
コンサートのチケットシステムやオンラインのオークションなど一定のタイミングに大量にアクセスがあって、高頻度更新のシステムに向いている。
- 構成
- 処理ユニット:アプリケーションコードを含む
- 仮想ミドルウェア:処理ユニットの管理、調整
- データポンプ:更新されたデータを非同期にデータに書き込む
- データライター:データポンプからのデータをDBへ更新する
- データリーダー:起動時にDBを読み込んで、処理ユニットに配信する
- 処理ユニット
- アプリケーションのロジック(規模に応じて分割する)
- インメモリデータグリッド、レプリケーションエンジンを含む(Hazelcast、Oracle Coherenceなどの製品)
- 仮想ミドルウェア
- リクエスト処理の制御を行う。様々なコンポーネントから構成される。(独自もしくは製品として購入する)
- メッセージンググリッド
- 入力されたリクエストをどの処理ユニットに依頼するかを制御(ルーティングではなく、ロードバランシング)
- データグリッド
- インメモリデータグリッドとしてデータキャッシュを行う
- 各処理ユニット内で非同期で高速なデータ同期を行なっている(レプリケーション
- 基本は処理ユニット内にあるが、コントローラの役割がある場合仮想ミドルウェアにも存在する
- DBにアクセスせずに高速にスケールが可能(グリッド内でレプリケーション可能なため)
- 処理グリッド
- 複数の処理ユニットをオーケストレーションする必要がある際に使用する
- デプロイメントマネージャー
- 負荷に応じて処理ユニットの起動と停止を行う
- データポンプ
- データベース内のデータを非同期更新する
- 処理ユニット内のインメモリキャッシュ(データグリッド)を更新すると、合わせてデータポンプを経由してDB更新を行う
- 実際のDB更新処理はデータライターが行う
- メッセージングによる通信が適している
- データライター
- 実際にDBへの書き込みを行うロジックを持つ(SQLなど)
- 処理ユニットからデータポンプを経由して更新依頼を受け取る
- 実装形式は様々に考えられる(1つのライターにn個のデータポンプ(1:n),、1:1など)
- データリーダー
- 各処理ユニットにデータポンプを経由してデータを送信する
- 呼び出し頻度は低い。(初回起動、全てがクラッシュした場合、再デプロイ、キャッシュしないアーカイブデータなど
- データ衝突
- データグリッド内で同時に更新が走った場合にタイミングによっては衝突が起きる(解決方法には何も触れていない・・・?)
- 発生確率は同期間隔とキャッシュサイズなどに応じて変わるので計算する必要がある(ただし、要因変化が大きいため実測データを使用するのが望ましい)
- レプリケーションキャッシュと分散キャッシュ
- 処理ユニット間での同期にはサイズに限界があるため、中央集権的なキャッシュサーバを用意する方法もある(分散キャッシュ)
- 処理ユニットがキャッシュを持たない代わりにアクセスへのレイテンシが発生、耐障害性も低下する
- ハイブリット型のニアキャッシュもある(全てのデータを持つ分散キャッシュ、限られたサイズを持つ処理ユニット内のキャッシュ)
- 特徴
- 弾力性、スケーラビリティ、パフォーマンスで最高の評価
- シンプルさとテスト容易性は低い、コストも高くつく
オーケストレーション駆動サービス指向アーキテクチャ
時代背景的な問題もあり現代は無用の長物と化した。省略する。
処理コンポーネントをドドメイン起点で細分化して再利用するという考えで作られているが、様々な処理で流用される関係で1つの修正が多くのドメインの機能に影響を与えてしまうという事になってしまった。
この失敗の背景からマイクロサービスアーキテクチャが生まれた。
マイクロサービスアーキテクチャ
オーケストレーション駆動サービス指向アーキテクチャの失敗から、ドメインによる分割をしつつ、再利用による結合を回避し分離によって影響を最小化したもの。
DBを含め、処理モジュールと依存コンポーネントがそれぞれ独立して動作する。(サービス)
リソースがスケール可能なクラウドサービス、コンテナ技術の発展により各リソースのハードウェア上での制限を受ける事なくこのような仕組みが可能になった。
- 境界づけられたコンテキスト
- DDDにおける境界づけられたコンテキストによる分割がマイクロサービスのキモ
- 各サービスがドメイン、サブドメインを表す(適切な粒度の分割が重要)
- 適切なドメインによる分割ができない問題が発生(トランザクション制御、通信量の増大)
- 運用面での再利用
- ロギング、モニタリングなどの運用に必要となる共通機能に関してはサイドカーパターンを利用して実装する
- サービスとは分離し、サイドカーとしてサービスメッシュを構築して全体で制御を行う
- フロントエンド
- 当初はUIもドメイン分割を想定していたが、WEBアプリでは制約から分割は難しいため単一のフロントエンドを持つ形となった
- フロントエンド=>APIレイヤ(各サービスと1:1)=>サービス という形で接続される
- 別の選択肢として、Reactのようなフレームワークを使用する事で、コンポーネント単位でAPIレイヤを対応づけてサービスの境界を分割できる
- サービス間で連携が必要なケース
- サービス間で直接通信 or サービスの呼び出しを管理するメディエータのようなサービスを作る
- サービス間でトランザクションが必要とならないように最適な粒度設計を行う
- 例外的に特性が異なるサービスでトランザクションが必要となる場合には、サーガパターンを用いる
- メディエータとなるサービスが、各サービスの実行を管理
- 関するサービスが失敗した場合には、処理を打ち消すような処理を実行する
- 複雑な方式になるので、極力サーガパターンを実装が必要にならないように設計する事がキモ
- 特徴
- ドメインによる分割
- 弾力性、スケーラビリティ、耐障害性、モジュール性で高評価
- コストが高く、シンプルさが無い
適切なアーキテクチャスタイルを選ぶ
これまで紹介されたようなアーキテクチャスタイルをどのように選択すべきか?の方式を示した章。
内容としては基本的にこれまで様々な章で箇所で出てきた内容の集合体といったイメージ。
- 判断基準(アーキテクトが必要となる知識)
- ドメイン:専門家である必要は無いが、一般的な理解を持っていないといけない
- 構造に影響を与えるアーキテクチャ特性
- データアーキテクチャ:既存のデータと相互作用が必要な場合には特に理解が必要
- 組織的な要因:M&A、クラウドベンダーの動向など
- プロセス、チームおよび運用上の関心事に関する知識:現在の仕組みを把握していないとうまくいかない(例:アジャイルやっていないのに、インクリメンタルな開発が必要な構造は難しい
- 主要な決定事項
- モノリスか分散か?
- アーキテクチャ特性が1つだけで良いならばモノリス
- 複数の特性が必要ならば分散が適している
- データをどこに置くべきか?
- 分散システムならば、どのサービスがどういったデータを持つか決定しなければならない
- 通信スタイルは同期か非同期か?
- 同期:大抵の通信では便利だが、スケーラビリティ、信頼性などのトレードオフが発生する
- 非同期:パフォーマンスやスケールでメリットだが、データ同期、デッドロックなどのトレードオフが発生する
- モノリスか分散か?
アーキテクチャ決定
アーキテクチャ決定するために避けるべきアンチパターンや、決定を他のメンバーが把握するための方法に関してまとめられている。
- アーキテクチャ決定におけるアンチパターン
- 資産防御アンチパターン:選択を誤ることを恐れて、決定を下すことを避けたり先延ばしすること。(決定をするのに十分な情報が揃うまで伸ばすことは問題ではない)
- グラウンドホッグデータアンチパターン:決定が下された理由がわからずに、繰り返し何度も議論されてしまう。(下した決定の根拠が示されていないため発生)
- メール駆動アーキテクチャアンチパターン:人々が決定を見失ったり、忘れたり、知らないことで発生。(Wikiなど単一のシステムへリンクを貼る事が大切
- アーキテクチャデシジョンレコード(ADR)
- アーキテクチャ決定を文章化する効果的な方法の1つ
- Markdown等で書かれた1〜2ページのシンプルなドキュメント
- WikiやGit等などに階層的に保存する
- 基本構造:
- タイトル、ステータス
- コンテキスト:この決定を行なった状況、背景
- 決定、影響:決まった決定とその影響
- コンプライアンス:決定が守られているかを確認する方法
- 備考:メタデータ。著者、更新日など
アーキテクチャのリスクを分析する
アーキテクチャ内の欠陥に対処し、リスクを軽減する措置を取るために継続的に必要となるリスク分析に関してまとめている。
- リスクマトリックス
- リスク評価における主観を減らすのに有効
- リスクの全体的な影響と発生する可能性をそれぞれ3段階で評価(低、中、高)
- どちらも高:9、中と高:6といった感じでスコア付けがされるため、リスクの評価が可能になる
- リスクアセスメント
- リスクマトリックスを用いてアーキテクチャ全体のリスクをまとめたもの
- リスク基準(可溶性、セキュリティなどの特性)、ドメイン(機能)におけるマトリクスとなる
- それぞれにリスクマトリクスにおけるスコアを付けて、全体の評価を行う
- 1回作成したら終わりではなく、継続的にこのアセスメントを行い、前回からの増減を示す
アーキテクチャの図解とプレゼンテーション
作成したアーキテクチャを図解してプレゼンテーションを行い、他のメンバーに誤解のないように伝える事もアーキテクトに求められるソフトスキルである。
この章の内容はどちらかというと、一般的な図解、プレゼンテーションスキルに関するノウハウ本で出てきそうな内容をピックアップして簡単に説明している印象。
(それだけこういったスキルは普遍的な内容という事でもあるかもしれない。)
- 図解におけるノウハウ
- 表現の一貫性:アーキテクチャ図の関係性を図や側面を変える際に関係性を示す事(マクロな関係図=>詳細な関係図に移行する際にマクロ側にそれがわかるような図を示すなど)
- 初期段階ではアナログで一時的な図で示すのが良い(時間をかけてしまうと愛着がわいてしまう。)
- プレゼンテーション
- 時間を操る:過剰な装飾は不要だが、1枚に収まらないようなアイディアなどはアニメーションで繋いで、1連の内容として見せるのは効果的
- 段階的な構築:スライドに多くの図や文章を一度に配置せずに、アニメーション段階的に見せていく
効果的なチームにする
チームの生産性を高められるような最適なアーキテクチャを設計するためのテクニックに関してまとめた章である。
- 箱(制約)を作り、伝える
- 制約が多く窮屈:システムを効果的に作るためのツール、ライブラリ、プラクティスへのアクセスを妨げ、フラストレーションの原因となる
- 制約があいまいで緩い:混乱を招く(ガイダンスなしでの実証実験、設計上の争い)。フラストレーションの原因となる
- どうやって管理する?
- 5つの要因に関して評価を行い、どの程度制約をかけるべきかを決める
- チームの親しさ:チームメンバーのお互いの親密さ。親密なほどコントロールはいらない。
- チームサイズ:12人以上は大きいチーム、4人以下は小さいチーム。小さいほどコントロールはいらない。
- 全体的な経験:シニアとジュニアの比率。シニアが多ければコントロールは最小限に。
- プロジェクトの複雑さ:シンプルなWebサイト?。シンプルならばコントロールは不要
- プロジェクトの機関:期間が短ければコントロールはいらない
- 5つの要因に関して評価を行い、どの程度制約をかけるべきかを決める