【本メモ】『進化的アーキテクチャ』
『進化的アーキテクチャ』を読んだので、本メモを公開。
業界やコミュニティは絶え間ない変化を期待 変化がいつ起こるのか、変化が持続するのかを予測できない。 しかし、変化も避けられない →技術的な景観が変わるであろうことをふまえてシステムを設計しなくてはならない 重要なアーキテクチャ特性を定義した後、どうすればそれらの特性が腐敗しないように保護できるか。 アーキテクチャ特性の進化可能性は、システムが進化していく中で他の特性を保護するということを意味する 進化可能性とは、他のすべてのアーキテクチャ特性を保護するアーキテクチャのラッパー 進化的アーキテクチャとは、複数の次元にわたる漸進的で誘導的な変更を支援するもの もし進化可能なアーキテクチャを作りたいのなら、変更が影響を与える全ての部分を考慮しなくてはならない
現代のソフトウェアアーキテクチャにおいて進化可能性に影響を及ぼすいくつかのよくある次元
・技術 アーキテクチャの実装部分。フレームワーク、依存するライブラリ、実装言語など。 ・データ データベーススキーマ、テーブルレイアウト、最適化計画など。 この種のアーキテクチャは通常はデータベース管理者が扱う。 ・セキュリティ セキュリティポリシーの定義、ガイドライン、不具合を発見するツールの指定など。 ・運用系 アーキテクチャを既存の物理インフラまたは仮想インフラ(サーバー、クラスタ構成、スイッチ、クラウドリソースなど)に どのようにマッピングするかといった関心事。 次元とは、ある特定の観点を支持する部分を意図的に分割したもの 「システムを設計するあらゆる組織は、必ずその組織のコミュニケーション構造に倣った構造を持つ設計を生み出す」 Melvin Conway Conway は論文において、ソフトウェアアーキテクトはアーキテクチャやソフトウェア設計だけでなく、 チーム間の作業の移譲、割り当て、調整にも注意を払う必要があると警告。 「逆コンウェイの法則」 マイクロサービスなどのアーキテクチャを構築する多くの企業は、サイロ化した技術アーキテクチャによる分割ではなく、サービス境界を中心にチームを組織する。 チームの編成をこうしたやり方で行うのは理想的 なぜなら、チーム構造はソフトウェア開発の無数の次元に影響を与えるもので、問題の規模や範囲を反映すべき。 例えば、マイクロサービスアーキテクチャを構築する場合には、 企業は一般的に、機能的なサイロを横断し、アーキテクチャのビジネス的側面と技術的側面全ての方向を満たすメンバーをチームに含めることで、チームをアーキテクチャに似せて組織する。 「対象のアーキテクチャに似せてチームを組織すること。そうすれば、アーキテクチャの実現はより容易になる。」
進化的アーキテクチャ、2つの重要な特徴
- 漸進的
- 誘導的
順応という言葉よりも進化という言葉を好むのは、継ぎはぎして理解しがたい偶発的な複雑さに適用していくアーキテクチャではなく、 基本的な進化的変化を経るアーキテクチャに興味があるから 真に進化するアーキテクチャを構築するためには、 アーキテクトは応急処置的な解決策ではなく、本物の変化をサポートしなくてはならない。 生物学のメタファーに戻ると、進化とは、目的に沿った、絶え間なく変化する環境で生き残ることができるシステムを持つこと。
進化的アーキテクチャ3つの基本的な側面
- 漸進的な変更
- 適応度関数
- 適切な結合
あるアーキテクチャ特性がどの程度満たされているかを評価する客観的な指標 スケーラビリティ、パフォーマンス、セキュリティ、データスキーマなどの重要な次元を定義することは、 いかなるシステムにおいても、初期のアーキテクチャにおける重要な決定事項 従来のテストや監視をはじめとする各種ツールを含む適応度関数を構築するために、既存の多くの仕組みを活用 テストがアーキテクチャ上の関心事の完全性を証明するのに役立つ場合には、それを適応度関数とみなす。 アーキテクトは、アーキテクチャの重要な部分全てを最初から知ることは決してできない。 →システムが進化する中で適応度関数を明らかにしていく必要がある。 適応度関数を特定しなければ、チームは以下に示すリスクに直面する ・間違った設計を選択し、最終的には環境に適合しないソフトウェアを構築してしまう ・不必要な設計を、時間やお金をかけて選択してしまう ・将来環境が変化したときに、システムをたやすく変化させることができなくなってしまう 適応度関数を早い段階で特定しなければ、チームは最終的にこれらの責務をコードベース全体へ分散 →変更を理解するには幅広い影響分析が必要となり、全体的な変更コストを跳ね上げる
適応度関数3つのカテゴリ
・主要なもの 技術や設計を選択する上で重要 これらの要素を中心とした変更を容易に行えるようにする設計上の選択を探ることにより多くの労力を割かなくてはならない。 例:銀行アプリケーション パフォーマンスと回復力 ・関連性のあるもの 機能レベルで考慮する必要だが、アーキテクチャ上の選択を誘導することはない。 例:コードベースの品質に関するコードメトリクス 重要だが、主要な次元ではない ・関連性のないもの 設計と技術の選択は、この種の次元に影響を受けない。 例:サイクルタイムなどのプロセスメトリクス 重要なものではあるかもしれないが、アーキテクチャとは無関係。 そのため、適応度関数は必要ない。 「適応度関数と実行した結果を共有スペースなどで可視化することで、主要な適応度関数と関連性のある適応度関数の知識を保ち続けよう。 そうすることで、開発者は忘れずに日々の開発作業の中でそれらを考慮することができるようになる。」 適応度関数の定義とメンテナンスは、 アーキテクトと開発者、アーキテクチャの整合性を維持することにかかわる全ての役割による共同責任となる。
コンポーネント粒度
量子とは相互作用に関与する物理的実体の最小量。 アーキテクチャ量子とは、高度な機能的凝集を持つ、独立してデプロイ可能なコンポーネント。 アーキテクチャ量子は、システムが適切に機能するために必要な構造的要素全てを含む。 モノリシックアーキテクチャでは、量子はアプリケーション全体。 モノリシックアーキテクチャは全てが高度に結びつく。 →全てまとめてデプロイする必要がある 対照的に、マイクロサービスアーキテクチャは、 変更可能性のある部分を全てカプセル化したアーキテクチャ要素間の、物理的な境界づけられたコンテキストを定義する。 →漸進的な変更を許容するように設計されている。 マイクロサービスアーキテクチャでは、境界づけられたコンテキストは量子的な境界として機能する。 DDDは、複雑な問題領域の組織的分解を可能にするモデリング手法。 境界づけられたコンテキスト →内部へはドメインに関する全てのことを公開し、外部へはそれを明かさないように境界が引かれた領域 DDD以前 →開発者は組織内の共通エンティティを全体にわたって再利用可能にしようと尽力していた。 しかし、共通の共有成果物を作成 →結合やより難しい調整、複雑性の増加といった、多くの問題を引き起こす。 境界づけられたコンテキストの考え方 →局部的なコンテキスト内で最もうまく機能する各エンティティを識別 したがって、組織全体で統一されたクラスを作成する代わりに、 各問題領域がそれぞれのクラスを作成し、統合点においてその相違を調整 小さな量子 →小さなスコープを意味し、よって、それはより速い変化を意味する。 一般に、小さな部品は大きい部品よりも扱いが容易。 進化的アーキテクチャを構築することのキーの1つ →ソフトウェアアーキテクチャによって支えたい性能に合うように、コンポーネント粒度を決定し、コンポーネント間を結合すること 進化的アーキテクチャでは、アーキテクトはアーキテクチャ量子を扱う。 アーキテクチャ量子は、壊れがたい力でまとまったシステムの一部。 例:トランザクションは強い核力として振る舞い、無関係な部分を共に結び付ける。 トランザクションコンテキスト分割は可能 →それは複雑なプロセスであり、しばしば分散トランザクションのような偶発的な複雑さを招く。 モノリスアーキテクチャ →データベースサーバーなどの依存コンポーネントを含むアプリケーションそのものが量子となる。 大きな量子サイズのシステムを進化させることは難しい。 漸進的な変更 変更が既存のレイヤ内に分離されている場合 →アーキテクチャに何らかの変更を加えることを容易だと感じる。 境界づけられたコンテキストが顧客に関する情報を共有する必要がある場合 →1つの表現へと統一しようとはせずに、メッセージングを介して情報の共有を実現する。 各サービスはDDDのドメイン概念を中心に定義 技術アーキテクチャと他の全ての従属コンポーネント(DBなど) →境界づけられたコンテキスト内にカプセル化 高度に疎結合されたアーキテクチャを形成 各サービスは境界づけられたコンテキストの全ての部分を「所有」 他の境界づけられたコンテキストとメッセージング(RESTなど)を介して通信。 →したがって、他のサービスの実装詳細(DBスキーマなど)を知るサービスは存在せず、不適切な結合が防止される。 問題領域によってはデータを細分化できない 重いトランザクションを処理するシステムは、マイクロサービスにはあまり適していない。 →トランザクションの動作は、サービス間の調整を要するため、コストが高くつきすぎる 複雑なトランザクション要件を持つシステム →DB要件がそこまで難しくないサービスベースアーキテクチャの方がうまく対応 量子の大きさをコントロール アーキテクチャの量子サイズ →開発者が進化的な変更をいかに簡単に行えるかに大きく作用 モノリスやESB駆動SOAのような量子サイズの大きなアーキテクチャは進化が難しい。 →変更ごとに調整が必要になるから。 Broker型EDAやマイクロサービスのような、より疎結合化されたアーキテクチャ →進化を容易にするためのより多くの手段を提供する。 アーキテクチャを進化させる上での構造上の制約は、開発者がどううまく結合や機能的凝集を扱うかにかかっている。 もし開発者が十分に定義されたモジュール式のコンポーネントシステムを構築するなら、進化はより容易に。 コンポーネントの分離に熱心に取り組む→疎結合によってアーキテクチャ量子の大きさが小さくなる →モノリスでも、アーキテクチャの進化可能性は増える 「アーキテクチャ量子が小さければ小さいほど、アーキテクチャはますます進化しやすくなる」 多くのDBリファクタリング手法 →リファクタリングに移行フェーズを設けることで、タイミング問題を回避 このパターンでは、開発者は移行開始時と終了時の2つの状態を持ち、移行中はその古い状態と新しい状態の両方を維持。 移行状態→後方互換性の維持を可能に →企業内の他のシステムが変更に追いつくのに十分な時間も与える。 アーキテクトは時にビジネスにとって自然なレベルよりも細かい粒度でアーキテクチャを構築しようとして間違う。 例:マイクロサービスアーキテクチャは重厚なトランザクションシステムにはあまり適していない。 →サービス粒子の目標がとても小さいから サービスベースアーキテクチャは量子サイズの要件が厳密でないため、うまく機能する傾向あり アプリケーションの全ての結合特性を考慮する必要がある ・クラス ・パッケージ ・名前空間 ・ライブラリ ・フレームワーク ・データスキーマ ・トランザクションコンテキストなど、 これらの次元(またはそれらの相互作用)を無視 →アーキテクチャを進化させようとする際に問題を作り出す。 「DBトランザクションは強力な核力として振る舞い、量子を結びつける」 モノリシックアーキテクチャをより粒度のか細かいアーキテクチャに移行 →まず少数の大きなサービスにするところから始める。 白紙の状態からマイクロサービスアーキテクチャを構築 →開発者はサービスとデータのコンテキストの大きさを制限することについて必死にならなければならない。 進化的アーキテクチャを構築しようとする前 →スキーマと品質の両方の観点で開発者がデータをうまく進化できるようにしてほしい。 ・不十分な構造はリファクタリング ・データの品質を基礎とするために必要な行動を何でもやっていくべき。 これらの問題を永久に処理する複雑で継続的な仕組みを構築するのではなく、これらの問題を早期に解決すること。 レガシーなスキーマとデータには価値がある →進化する能力への重しにもなる。 アーキテクト、DBA、ビジネス担当者は、何が組織における価値を表しているかについて率直な会話をする必要がある。 組織における価値 →レガシーデータを永久に保持し続けることだろうか。 それとも、進化的な変更を作る能力だろうか。 本当の価値があるデータを見定めて、それを保持しよう。 古いデータ →参照用には利用可能にしつつも、進化的な開発の主流からは外すようにしよう。 「スキーマのリファクタリングや古いデータの削除を拒むことは、 アーキテクチャを過去を結びつけ、それはリファクタリングを難しくする」 進化するシステムを構築するには、開発者とDBAは現代の開発プラクティスと並行してデータに関する効果的なプラクティスの実践を促進する必要がある。
進化的アーキテクチャの3つの基本的な要素
- 「適応度関数」
- 「漸進的な変更」
- 「適切な結合」
進化的アーキテクチャ構築3つの手順
1. 進化の影響を受ける次元を特定する どの次元をアーキテクチャの進化とともに保護したいのか特定 2. それぞれの次元に対して適応度関数を定義する アーキテクトは、どの次元を継続的に注視するかを決定し、 それをWikiなどの軽量フォーマットで文書化 3. デプロイメントパイプラインを使って適応度関数を自動化する プロジェクトで進化的アーキテクチャを支える開発者の責務の1つ →サイクルタイムを良い状態に維持する 他の多くのメトリクスがそこから派生するため、サイクルタイムは漸進的な変更において重要な意味を持つ プロジェクトのサイクルタイムが長くなれば、新しい機能を送り出せる速度は遅くなり、それは進化に影響する 開発者はあらかじめ全てを予期することはできないため、ソフトウェアの「未知の未知」問題に悩まされる。 アーキテクチャの一部が厄介な兆候 →適応度関数を構築することで、アーキテクトはこの不全が育つのを阻止可能 非機能要件が壊れる状況を警戒 将来の問題を防ぐために適応度関数とともにアーキテクチャを改良していかなければならない
既存のアーキテクチャに進化可能性を加えられるか3つの要因
・コンポーネント結合 技術アーキテクチャの進化可能性に大きく左右 きれいに疎結合化されたシステムは進化を容易に 生い茂った結合の巣窟はそれを痛めつける 真に進化可能なシステム構築 →影響を受けるアーキテクチャ上の全ての次元を考慮する必要 結合の技術的な側面を超えて、システムのコンポーネントの機能的凝集についても考慮し守る必要 あるアーキテクチャから別のアーキテクチャへ移行 →再構築されたコンポーネントの最終的な粒度は、機能的凝集によって決定される コンポーネントを不合理なレベルには分解できないという意味ではなく、 →コンポーネントは問題のコンテキストに基づいた適切な大きさを持つ 例:重厚なトランザクションシステム →ビジネス上のいくつかの問題は他よりもより結びついている。 この問題に抵抗して究極に疎結合化されたシステムを構築しようとすることは、非生産的。 ・開発プラクティス 継続的デリバリープラクティスは →必ずしも進化的アーキテクチャを保証しない しかし、それがなければ進化的アーキテクチャを実現することはほとんど不可能。 進化的アーキテクチャを構築することにおける最大にして唯一の障害 →扱いにくい運用 もし開発者が変更を容易にデプロイできなければ、フィードバックサイクルの全ての部分が妨害される モノリシックアプリケーションの分解 →正しいサービスの粒度を見つけることが重要。 大きなサービスを作成 →トランザクションコンテキストやオーケストレーションのような問題は生じにくい モノリスを小さな部品へと分解することにはならない。 コンポーネントを細かくしすぎる →過剰なオーケストレーション、コミュニケーションのオーバーヘッド、コンポーネント間の相互依存といった問題が生じることになる。
決定を可逆にする
積極的に進化するシステム →予期しない失敗に陥る 将来の予防として新しい適応度関数を作成する必要がある。 しかし、失敗から回復するには ブルーグリーンデプロイメント カナリアリリース 変更を機能トグルの下にデプロイ →ユーザーの小さなサブセットに対してリリースを行い変更を確認できる。 機能が予期しない動作 →トグルを元の状態に戻し、もう一度試す前に失敗を修正可 要求コンテキストに基づいた特定のサービスへルーティングするサービスルーティング →マイクロサービスエコシステムにおけるカナリアリリースのもう1つのよく見られる方法。
予測可能ではなく進化可能を選ぶ
未知の未知 →予期せずに生じる、誰もそれが登場することがわかっていなかったもの。 アーキテクトは未知の未知を設計できない。 「全てのアーキテクチャは未知の未知のためにイテレーティブになる。 アジャイルはこれを認識し、すぐにそれを行う」 未知のものを何とかできるアーキテクチャ →ない。動的平衡はソフトウェアの予測可能性を無駄にする。 代わりに、進化可能性をソフトウェアに組み入れる アーキテクチャは、最初に作ってしまえばそれで終わりというような代物ではない。 プロジェクトはその生涯を通じて、常に変化し続ける。明白に、しかも予期しないような形で。 アーキテクトは将来の利用量を予測しない →このライブラリをAPIの後ろに置くことで比較的容易に置き換えられるようにした。 最終責任時点で答えるべき質問 「今この判断をしなければならないだろうか」 「仕事を遅らせることなく、この判断を安全に延期する方法はあるだろうか」 「今ここに置くのに十分足りるものは何で、必要に応じて後で変更が容易だろうか」 インターフェースの適切な位置に腐敗防止層を設置 →機能の置き換えを機械的な作業にできる 腐敗防止層を構築 →特定のAPIの構文を考えることではなく、ライブラリから彼らが必要とするものは何かという意味を考えることを促す。 アーキテクチャレベルでは、開発者は根本的に変化する要件と特性に苦労して取り組む。 正しいアーキテクチャを選択できるくらい十分に学ぶ方法の1つ →考えの証明を構築 「犠牲的アーキテクチャ」Martin Fowler 考えがうまくいくことがわかったら投げ捨てるよう設計されたアーキテクチャ 例:eBay 1995 年に Perl スクリプトの集合としてスタート 1997年に C++ に移行 2002年には Javaへと移行 → eBay システムを何回も再構築しているにもかかわらず、うまくいっていることは明らか。 ライブラリの使用 →アプリケーションへの結合が 技術アーキテクチャの進化が必要なときに置き換えが容易 ライブラリとフレームワークを異なるものとして扱う1つの理由 →開発プラクティスに行き着く。 アプリケーションコードの全ては、フレームワークの変更による影響を受ける。 フレームワークのメジャーバージョンが2つ以上時代遅れになる →最終的に更新するための労力(と痛み)はひどいものになる。 アプリケーションの基礎部分であるため、チームは積極的に更新を行わなければならない。 ライブラリは一般的にフレームワークよりも弱い結合点を形成する →更新についてチームはよりカジュアルに行うことが可能 早期に時間費やす場合のコストは、チームが更新を果てなく先延ばしにした場合に比べたら、 ごくわずかで済む。 「フレームワークの依存関係は積極的に更新し、ライブラリの依存関係は受動的に更新すること。」
2種類の悪いプラクティス
- 落とし穴
- アンチパターン
多くの開発者はアンチパターンという言葉を「悪い」の俗語と して使用 →実際の意味はもう少し微妙。 ソフトウェアにおけるアンチパ ターン2つの要素 ・アンチパターンは当初は良い考えのように 見えるものの、結果的に誤りであることが判明する ・ほとんどのアンチパターンにはより良い選択肢が存在する。 多くのアンチパターンは後になってから気づく。 →避けることは困難。 落とし穴は表面的にはよい考えのように見えるが、すぐに筋の悪さが明らかになる。 ベンダーキングアンチパターン アーキテクチャが全体的にベンダー製品を中心に構築され、組織がツールに病的に結合されてしまう 十分に時間をかけても、開発者は必要なものを完全に実装するのに十分なカスタマイズを ERPツールに対して行えず、 ツールの限界や彼らがツールを中心としたアーキテクチャ領域を中心に置いてしまったという事実による無力さを理解する。 「ラスト 10%の罠」 ビジネスプロセスの視点か最適なワークフローをサポートできない。 フレームワークの元で精を出し終えると、ツールのカスタマイズではなく、プロセスを変更する。 →企業間の差別化要因は少なくなる。 「Let’s Stop working and Call It A Success(作業するのをやめて、それを成功と呼ぼう」原則 何百万ドルも無駄にしていることを認めたいCTO はいない ツールベンダーも長年にわたる悪い実装を認めたくはない。 →両方の思惑から、作業することをやめ、それを成功と呼ぶことに同意 けれども、約束されたはずの多くの機能は未実装となる。 「アーキテクチャをベンダーキングと結合しないこと」 ベンダー製品を単なる統合点として扱おう。 統合点の間に腐敗防止層を設置 →ベンダーツールの変更がそのアーキテクチャに影響を与えるのを防ぐことができる。 現代のソフトウェアにおける勝利の鍵の1つ →どれくらいうまくいく効果的な抽象を作れるかどうか。 しかし、抽象化はコストにもなる。 →抽象でないものこそが完全 もし、それが存在し、抽象でないのなら、それは本物。 「自明でない抽象化は全て、程度の差こそあれ、漏れがある」Joel Spolsky 当時流行っていた Accessやそれ以外の 4GL言語 →クライアントが望むことの80%は迅速かつ簡単に構築できる しかし、顧客が望む次の10% は、可能だったが、かなり難しかった。 マイクロサービス →コードの再利用を避け、結合より重複を選ぶという考え方を採用。 再利用は結合を意味 そして、マイクロサービスアーキテクチャは極度 に分離される。 しかし、マイクロサービスの目標は重複を促すことではない。 マイク ロサービスの目標 →ドメイン間のエンティティを分離 共通クラス を共有するサービスは、もはや独立していない。 例:Checkout と Shipping は互いにそれぞれの Customer の内部表現を持つ。 顧客に関 する情報を協調させる必要がある場合 →サービスは互いに関連する情報をやり取 りしあう。 アーキテクトは異なるバージョンの Customer をアーキテクチャ内で一致 させたり統一したりしようとはしない。 再利用の利益は錯覚であり、再利用による結合は全ての不利益を導入 →重複の欠点を理解しつつも、より多く結合することになるアーキテクチャ上のダメージをより局所的に抑える。 コードの再利用 →資産になるだけでなく、潜在的な負債も生む。 「結合点が進化化やその他の重要なアーキテクチャ特性を妨げる場合には、分岐や複製によって結合を壊すこと」 チームが共有コードの所有権を持つことによって結合を壊した。 負担は増えるものの、新しい機能を届ける彼らの能力の足を引っ張ってきたものから彼らを解放した。 他のケース:おそらくより大きな部分 から何らかの共有コードを取り除く →より選択的な結合と段階的な疎結合化が可能に 「アーキテクトは、アーキテクチャの「~性」の適応度を継続的に評価し、アーキ テクチャがまだ価値を持ち、アンチパターンに陥っていないことを保証しなくてはならない」 アーキテクトは何度もその時点で正しい判断だとする判断を行う →動的平衡 のような条件の変化によって、その判断は時間経過とともに悪い判断になってしまう。
ゴルディロックスガバナンス (Goldilocks Governance)モデル
標準化のために、単純、中間、複雑という3つの技術スタックを選定 →個々のサービス要件によってスタック要件が導かれる チームは適切な技術スタックを柔軟に選択しながら、 企業に標準化の利点も提供することができる 例:何年もの間、PenultimateWidgets のアーキテクトは全ての開発をJava と Oracle に標準化しようとしてきた。 より細分化されたサービスを作るにつれて、彼らはこのスタックは小規模なサービスに大きな複雑さを課すということに気が付いた。 →けれど彼らは依然としてプロジェクト間での知識とスキルの移植性を望んでいた マイクロサービスの「全てのプロジェクトが独自に技術スタックを選択する」 というアプローチ →完全には受け入れたくなかった。 しかし、最終的に彼らはゴルディロックスガバナンスの方法をとり、以下の3つの技術スタックを選択 小 スケーラビリティやパフォーマンスの要件が厳しくないとても単純なプロジェク トには、Ruby on Rails と MySQL 中 バックエンド:中規模のプロジェクトには、Go言語と、データ要件に応じて Cassandra か MongoDB、MySQLのいずれかの1つ 大 大規模なプロジェクトには、可変アーキテクチャの問題にうまく対応するため、引き続きJavaとOracle サイクルタイムが速い →アーキテクチャが速く進化できる プロジェクトのサイクルタイム →アーキテクチャの進化速度を決定 進化速度は サイクルタイムに比例 開発者はプロジェクトのサイクルタイムより速くシステムを進化させることはできない。 → チームがソフトウェアをより速くリリースできれば、チームはシステムの一部をより速く進化させることができる サイクルタイム →進化的アーキテクチャの重要なメトリクス。アトミックな適応度関数の優れた候補 サイクルタイムが速ければ、速いほど、進化速度が速い 例:自動化されたデプロイメントパイプラインを使ってプロジェクトをセットアップし、3時間のサイクルタイムを達成 →検証や統合点を増やすにしたがって、サイクルタイムが徐々に増加 チームは サイクルタイムが4時間を超えると警告を出す適応度関数を確立 適応度関数 がしきい値に達する →開発者はデプロイメントパイプラインの仕組みを再構築したり、4時間のサイクルタイムが許容できるかどうかを判断 ほとんどのプロジェクトでは、開発者は 徐々に上昇するサイクルタイム に気付くことはない。 →競合する目標に優先順位をつけることもないため、こうした決定を暗黙的に行っている。 適応度関数を 使用すると、将来の判断点を中心にしきい値を設定できる。 「進化の速度はサイクルタイムの関数だ。サイクルタイムを速めることで、進化を速めることができる」
落とし穴:製品のカスタマイズ
営業は製品を売りたいがために、無限にカスタマイズ可能なソフトウェアを欲しがる。 →カスタマイズ可能性は、実装技術が要する相応コストと引き換え ・顧客ごとの個別ビルド このシナリオでは、営業は厳しい時間スケールの上で機能の固有バージョンを約束 →バージョンを追跡するためにバージョン管理システムの ブランチやタグなどを駆使することを強制する。 ・永続的な機能トグル 機能トグルは、しばしば永続的なカスタマイズを作成するために戦略的に使われることがある。 →機能トグルを使って、顧客ごとに異なるバージョンを構築したり、 製品の「フリーミアム」バージョンを(料金を払うことでプレミアム機能 成形を解除できる無料バージョン)を作成したりする。 製品駆動カスタマイズ 製品の一部は、UIを介したカスタマイズを追加する方へ進む。 →アプリケーションの永続的な部分であり、他の全ての製品機能と同様の注意が必要 機能トグルとカスタマイズ →製品に実行できる経路の組み合わせを多く含めることになるため、テストの負荷を大幅に増加
アンチパターン:レポート機能
組織はビジネスで必要となる可能性のある全ての視点(受注の月次報告など)を提供することに奮闘 特に苦労する点 →全てが同じモノリシックアーキテクチャやデータベース構造によってもたらされる場合 サービス指向アーキテクチャの時代 →アーキテクトは全てのビジネス的な 関心事を同じ「再利用可能な」サービスの集合を介してサポートする試みに苦労 そして、サービスがより汎用的になるほど、それを利用するためにカスタマイズする必要があることを発見 レポート機能 →モノリシックアーキテクチャにおける不用意な結合の良い例 記録のシステムとレポートのシステムで同じデータベース を使いたいと考える。 →両方をサポートする設計はどちらにも最適化されないため、問題が生じる 開発者とレポート設計者が一緒になってレイヤ化アーキテクチャに作ってしまう、 →よくあるこの種の落とし穴:関心事が互いに反目しあっていることを示している。 不用意な結合を減らすため →レイヤ化アーキテクチャを構築し、関心事をレイヤに分離 レポートはその機能をサポートするためにレイヤの分割を必要としない。 ただデータが必要なだけ。さらに、レイヤを介したルーティング要求は待ち時間も増加させる。 したがって、優れたレイヤ化アーキテクチャを持っているにも関わらず、 多くの企業はレポー ト設計者にレポートを直接データベーススキーマに結合することを許してしまう →レポートを壊すことなしにスキーマを変更できる能力を破棄 多くのマイクロサービスアーキテクチャは、動作の分離によってこのレポート問題を解決。 サービスの隔離は →分離には役立つが、統合には役立たない。 「記録のシステム (System of Record:SoR)」領域のデータベースとしてサービスのアーキテクチャ量子内にそれぞれ埋め込まれ配置される、 イベントストリーミングやメッセージキューを使い、トランザクション動作ではなく結里整合性をもって、これらのアーキテクチャを構築。 一連のレポートサービスは、イベントストリームをリッスンし、レポート用に最適化された非正規化レポートデータベース を作成。 →結果整合性を使うことで、調整から解放される。 これは アーキテクチャの観点での結合の一形態 →アプリケーションの様々な用途に対 して異なる抽象化を可能にする。 例:PenultimateWidgets のマイクロサービスアーキテクチャ →アーキテクトは境界づけられたコンテキストに分割されたドメインを持ち、それぞれがドメインの「記録のシステム」用データを持つ。 結果整合性とメッセージキューを使いデータの追加や通信を行い、ドメインサービスとは別の一連のレポートサービスを提供。 UIがCRUD操作 →マイクロサービスとレポート サービスの両ドメインが通知を受け取り、適切な行動を取る。 レポートサービス →ドメインサービスに影響を与えることなしにレポートに関する処理を行う。 ドメインを合成することで生じる不適切な結合を削除することは、各チームがより具体的で単純なタスクに集中することを可能にする。 機能横断型チーム →サイロを超えて責任を指摘することを防ぎ、チームに責任感を生じさせることで、チームメンバーに最善の仕事を行うよう促進。
うまく機能しているアーキテクト →リーダーシップの役割を果たし、技術文化を作り、開発者がシステムを構築するための方法を設計。 進化的アーキテクチャを構築するために必要なスキルを個々のエンジニアに教え、奨励。 次のような質問をすることで、アーキテクトはチームにあるエンジニア文化を理解する質問 ・チームの全員が適応度関数とは何かを理解していて、新しいツールやプロダクトの選択が新しい適応度関数を進化させる能力に与える影響を考慮しているか? ・チームは彼らが定義した適応度関数がシステムとどれだけ合致しているかを計測しているか ・エンジニアは凝集と結合を理解しているか? ・どのドメインと技術概念が一緒に属しているかについての会話があるか? ・チームは自分たちが習得したいテクノロジーに基づいてではなく、変更する 能力に基づいて解決策を選択しているか? ・チームはビジネスの変化にどのように反応しているか? 小さな変更を取り 入れるのに苦労しているか、あるいは小さなビジネスの変更に時間を費やしすぎていないか? チームの振る舞いを調整 →チーム周辺のプロセスを調整。 人々はやるように言われたことに反応するから。 「どのような尺度で私を評価するのか教えてくれれば、どのように私が行動するのか教えてあげましょう」 -エリヤフ・ゴールドラット 「ゴールドラット博士のコストに縛られるな!』 3度目になったらリファクタリング開始 「最初は、単純に作業を行う。2度目に以前と似たようなことをしていると気づい た場合には、重複や無駄を意識しつつも、とにかく作業を続けてかまわない。そして3度目に同じようなことをしていると気づいたならば、そこでリファクタリングをする。 」 多くのチーム →新しい機能を提供することによって最もよく突き動かされ、見返りを与えられる。 コード品質と進化可能性の側面 →チームにとってそれを優先される場合にのみ考慮される。 進化的アーキテクチャを気に掛けるアーキテクト →チームの行動について注意を払う必要。 ・チームが進化可能性を助ける設計判断を優先したり、それを促進する方法を見つけたりしているかどうか
実験の文化
進化を成功させるには、実験が必要 →計画に忙しすぎるために実験に失敗する企業も存在する。 実験を成功させる →小さいアイデア(技術的側面とプロ の期間の両方から)を試す習慣的な小さなアクティビティを実行 うまく行った実験を既存のシステムへと統合することである。 「真の成功基準とは、24時間に詰め込める実験の数だ。 」 トーマス・エジソン
量子
量子あたりのコストは、量子の数が増えると下がることになる。 アーキテクチャがより小さい部分から構成されるため、 関心の分離はより離散的、定義的になることが挙げられる。 物理的な量子数が増加すると、運用面での自動化が必要になる。 特定の時点を超えると、手作業での処理が非現実的。 量子をとても小さくすると、せん断数はより重いコストとなる可能性がある。 アーキテクトは適切な量子サイズと対応する調整コストの間のスイートスポットを見つけようと努力する。 より小さい量子サイズはより短いサイクルタイム 量子サイズ:サービスベースのアーキテクチャを構築することが現実的かも モジュール性を高めて結合を分離、適応度関数と漸進的な変更を実証できる 「実証が議論を打ち負かす」 漸進的な変更にとって、テストは重要 適応度関数はテストを積極的に活用 イノベーションのジレンマとして知られる現象は、 よりアジャイルなスタートアップがエコシステムのより良い変化に対処するにつれて、 十分に確立された市場にいる企業が失敗する可能性が高いことを予測してる。 Amazonは全てを1つのものに結合することが最終的にスケーラビリティを制約することに気づいた。 不適切な結合は進化にとって最大の難題。 スケーラブルなシステムは進化可能なシステムにも対応する傾向 進化は根本的な変化 適応度関数によって破壊から保護された場所でアーキテクチャを変更 内部に潜んだ時代遅れの解決策を増やすことなく、有用な方法で進化し続ける 泥団子は進化できない 修正はしばしば書き直しよりもコスト 既存アーキテクチャを進化可能に変換するための最初のステップ:モジュール性 現在のシステムに存在するモジュール性を何でもよいので見つけ出し、アーキテクチャをそれ中心に再構築 アーキテクチャの絡み合いが減れば、基礎の構造を確認し、再構築に必要な労力について合理的な決定が容易になる 組織の中の慎重な人々を説得するより、その考え方がどう自分たちの仕事を改善するか実証しよう 現代のソフトウェアアーキテクチャを持つ破壊的な企業は、 より優れた情報技術を持っているために、既存の企業の領域に入り込んできて突如支配的になる 進化的アーキテクチャの構築は、チームが自信をもってアーキテクチャレベルで漸進的な変更を行なっていける 進化的アーキテクチャは、漸進的な変更を装って、チームに現代の開発プラクティスを強要する。 これは有益な副作用 それらの実践がアーキテクチャを壊さず変更可能にしリリースの頻度を増やす 進化的アーキテクチャの考えをビジネス側に売り込む最善の方法は、 新しいビジネスを届ける能力を中心に展開する。 アーキテクトが技術的な改善を指摘に語ると、ビジネス側の人間はどんよりする。 彼らの言葉で影響を語るのが良いだろう。
最後に
翻訳は少し分かりづらかったが、それでも面白い箇所が多く、
本メモの量も増えてしまった。削る部分が難しい。
進化可能なシステムを構築する上でキーワードとなるのは、
やはり「疎結合」だと感じた。
進化可能とは、交換可能であり、更新可能であること。
密結合になってしまうと、これらが阻まれることが多い。
本書のマイクロサービス分割でも、
『マイクロサービスアーキテクチャ』と同様、DDDが取り上げられていた。
DDDもおさえておかないといけない技術で、現在本を読んでいるので、
読み終わったら、こちらもブログに公開したい。