頑張らないように頑張る。

努力と怠惰の狭間

『ソフトウェアアーキテクチャの基礎―エンジニアリングに基づく体系的アプローチ』を読んだのでまとめた。

⚙️はじめに

掲題の通り、『ソフトウェアアーキテクチャの基礎―エンジニアリングに基づく体系的アプローチ』を読み終えたので、まとめておく。

www.oreilly.co.jp


本書は以下の章立てで構成されている。


本ブログでは上記の章立て通りにはまとめず、以下の粒度でまとめる事とする。



⚙️本書に出てくるアンチパターンと回避方法

象牙の塔アーキテクトアンチパターン

  • 発生:開発チームの意見や懸念を無視して、上から目線で何をすべきかを指示しているだけのアーキテクト
  • 回避:開発チームとコミュニケーションを取り、協働してアーキテクチャ決定を下す

汎用アーキテクチャアンチパターン

  • 発生:すべてのアーキテクチャ特性をサポートしようとして、システム全体が複雑になる
  • 回避:設計をシンプルに保つ。最も重要な特性3つを顧客に決めてもらう。

巨大な泥団子アンチパターン

  • 発生:認識できるアーキテクチャ構造が不在の状態。循環依存状態であったり、スパゲッティ状態であったり、パッチワーク状態であったり、とにかく悲惨。
  • 回避:リファクタリング

暗黙のアーキテクチャアンチパターン

偶発的アーキテクチャアンチパターン

アーキテクチャシンクホールアンチパターン

  • 発生:「レイヤードアーキテクチャ」において、各レイヤー内でビジネスロジックが実行されず、リクエストがパススルーされてレイヤー間を移動してしまう
  • 回避:80対20ルールに従う。すべてのレイヤーを開放レイヤーにする。

資産防御アンチパターン

  • 発生:選択誤りの恐れによる、選択や決定の放棄や先延ばし
  • 回避:最終責任時点まで決定を下さない。決定が実現できるように開発チームをサポートする。

グラウンドホッグデーアンチパターン

  • 発生:決定が下された理由の周知不足。
  • 回避:ビジネス価値を付加して、周知・共有する。

メール駆動アーキテクチャアンチパターン

  • 発生:メンバーは決定を失念・忘却してしまう。
  • 回避:本当に関心のある人にだけ決定を伝える。メールではなくWikiにする。

アーティファクトへの不合理な愛着アンチパターン

  • 発生:アーキテクトが自分が作ったものに過度に執着してしまう。
  • 回避:UML、C4、ArchiMateなどを用いて手早く作る。

クッキー型アンチパターン

  • 発生:プレゼンテーション作成者が、スライドを余計な装飾で埋め尽くそうとする
  • 回避:1つのスライドで全てを表現しようとせず、複数のスライドに分けてアイディアを表現する

蜂の巣にされた死体アンチパターン

  • 発生:スライドがプレゼンテーション発表者のメモでしかない状態
  • 回避:プレゼントは「視覚」「聴覚」の2つの情報チャンネルがあるので、うまく使い分ける



⚙️アーキテクチャの概観

ソフトウェアアーキテクチャの法則


ソフトウェアアーキテクチャのモジュール性とコンポーネント

モジュール性

ソフトウェアアーキテクチャに関する言説の95%は「モジュール性」の利点を称賛するために費やされる。

「モジュール性」を計測するには、以下3つのメトリクスがある。

凝集度
  • 尺度としては、以下7段階がある
    • 機能的凝集
    • 逐次的凝集
    • 通信的凝集
    • 手続き的凝集
    • 時間的凝集
    • 論理的凝集
    • 偶発的凝集
結合度
  • 種類としては、以下2つがある
  • これに関連する用語は以下の通り
    • 抽象度     =抽象的なアーティファクト/(抽象的なアーティファクト+具体的なアーティファクト
    • 不安程度    =遠心性結合/(遠心性結合+求心性結合)
    • 主系列からの距離=|抽象度+不安程度-1|
      • 主系列からの距離が、主系列の右上だと、抽象度が高いので使いづらい
      • 主系列からの距離が、主系列の左下だと、抽象度が低いので変更に弱くメンテナンスしづらい
コナーセンス
  • 種類としては、以下2つがある
  • 性質としては、以下3つがある
    • 強さ
    • 位置
    • 度合

コンポーネント

コンポーネント」とは、モジュールが物理的にパッケージ化されたものであり、アーキテクチャの基本構成要素。


コンポーネントの粒度は、以下のトレードオフを持つ。

  • 細か過ぎる:コンポーネント間でたくさんのやりとりが必要になり、一貫性やトランザクションなどの管理が困難になる
  • 粗過ぎる :内部結合度合いが高くなり、デプロイ容易性やテスト容易性の確保が困難になったり、モジュール性に関連した負の副作用をもたらす


コンポーネントの発見には、以下などがある

  • アクター/アクションアプローチ
  • ワークフローアプローチ
  • イベントストリーミング


ソフトウェアアーキテクチャの構成要素

ソフトウェアアーキテクチャは、以下4つから構成される。

構造

システムで使われているアーキテクチャスタイルの種類(詳細は次章で記載)であり、以下のようなものがある。


モノリシックアーキテクチャでは「ACIDトランザクション」が採用される事が多い。

  • A(Atomicity)
  • C(Consistency)
  • I(Isolation)
  • D(Durability)


分散アーキテクチャでは「BASEトランザクション」が採用される事が多い。

  • BA(Basically Available)
  • S (Soft state)
  • E (Eventual consistency)


分散アーキテクチャはモノリシックアーキテクチャよりも強力だが、以下8つの誤信を注意する必要がある。

  • ネットワークは信頼できる
  • レイテンシーがゼロ
  • 帯域幅は無限
  • ネットワークは安全
  • トポロジーは決して変化しない
  • 管理者は一人だけ
  • 転送コストはゼロ
  • ネットワークは均一


上記8つの誤信の他にも、分散アーキテクチャは、以下について注意する必要がある。

アーキテクチャ特性

システムがサポートしなければならない「イリティ(-ility)」であり、以下のようなものがある。

  • 可用性
  • 信頼性
  • テスト容易性
  • スケーラビリティ
  • セキュリティ
  • アジリティ
  • 耐障害性
  • 弾力性
  • 回復性
  • パフォーマンス
  • デプロイ容易性
  • 学習容易性 など


アーキテクチャ特性とは、以下3つを満たすものをいう。

  • ドメインに依らない、設計に関する考慮事項を明らかにするもの
  • 設計の構造的な側面に影響を与えるもの
  • アプリケーションの成功に不可欠ないし重要なもの


アーキテクチャ特性を全乗せした「汎用アーキテクチャアンチパターン」にならないようにする。

  • 常にトレードオフを意識する
  • 最も重要な特性3つを顧客に決めてもらう


アーキテクチャ特性は、以下の特徴を持つ「アーキテクチャ量子」で定め、スコープを絞って考える。

  • 独立してデプロイ可能
  • 高度な機能的凝集性
  • 同期的なコナーセンス


アーキテクチャ特性を【明確】にするには、「アーキテクチャ・カタ」を用いてみるとよい。

  • アーキテクチャ・カタ」には、明確にするのに必要な「関心事」「要件」「暗黙的なドメイン知識」が含まれる
  • 要件定義には、"明示的な特性"は記載されているものの、"暗黙的な特性"は記載されていないため、カタを用いて明確にする


アーキテクチャ特性を【計測】するには、以下の客観的指標を用いる。

  • 運用面の計測  :パフォーマンスなど
  • 構造面の計測  :循環複雑度など
  • プロセス面の計測:テスト容易性など


アーキテクチャ特性を【統制】するには、以下を用いる。


アーキテクチャ特性を【検証】するには、以下のような適応度関数を用いる。


例として、可用性については「9」を意識して設定する。

  • システム全体としてはファイブナイン(99.999%)である必要がない事もあるので、分割統治も考える。

アーキテクチャ決定

システムを構築する際のルール(ガイドラインではない)であり、以下のような例がある。

  • <例>レイヤードアーキテクチャの場合
    • ビジネス層とサービス層は、永続化層に直接アクセスできる
    • プレゼンテーション層は、永続化層に直接アクセスできない
    • サービス層は、開放レイヤとする
    • サービス層意外は、閉鎖レイヤとする など


アーキテクチャ決定については、以下のようなアンチパターンが段階的に発生する事がある。

  1. 資産防御アンチパターン
  2. グラウンドホッグデーアンチパターン
  3. メール駆動アーキテクチャアンチパターン


アーキテクチャ決定を文書化するには、「アーキテクチャデシジョンロード(ADR)」を用いるとよい。

設計指針

システム構築する際のガイドライン(ルールではない)であり、以下のような例がある。

  • <例>マイクロサービスアーキテクチャの場合
    • サービス間の非同期メッセージングを可能な限り活用し、パフォーマンスを向上させる
    • (ルールとして堅く決める事が難しい指針を示すのが目的)



⚙️ソフトウェアアーキテクチャのスタイル

前述した4つの構成要素のうち「構造」について、以下に詳しく記載する。


モノリシックアーキテクチャ

レイヤードアーキテクチャ

  • 別称
  • 構成要素
    • レイヤの種類
      • プレゼンテーション層
      • ビジネス層
      • 永続化層
      • DB層
    • レイヤの分類
      • 開放レイヤ:追加に強いが変更に弱い
      • 閉鎖レイヤ:追加に弱いが変更に強い
  • 特徴
    • コンウェイの法則が働く組織で採用されがち
    • 各レイヤの作業は抽象化されており、各レイヤで役割と責務を持つ
    • 小規模でシンプルなアプリケーションやWebサイトには向いている

パイプラインアーキテクチャ

  • 別称
  • 構成要素
    • パイプ
      • 一方向かつポイントツーポイント
    • フィルター
      • ステートレスでシングルタスク
      • 「プロデューサ」「トランスフォーマ」「テスタ」「コンシューマ」から構成される
  • 特徴
    • Linuxのパイプラインが代表的
    • 拡張性に優れている

マイクロカーネルアーキテクチャ


分散アーキテクチャ

サービスベースアーキテクチャ

  • 別称
    • なし
  • 構成要素
    • ユーザインターフェース
    • リモートサービス
    • データベース
      • 物理的にはモノリスであってもOK
      • 論理的に分割しておくと変更に対応しやすくなる
  • 特徴
    • 柔軟性が高く、実用的で、ドメインによって分割されるアーキテクチャ
    • サービスの粒度は、以下のトレードオフを持つ
      • 細かくなるにつれて、「オーケストレーション」と「コレオグラフィ」にまつわる問題が出てくる
      • 粗くなるにつれて、完全性や一貫性は向上するものの、テスト容易性などが欠如する可能性がある

イベント駆動アーキテクチャ

  • 別称
    • なし
  • トポロジ(構成要素とは違う)
    • ブローカー
      • 分離され独立していてシンプルなため拡張性が高い
      • 単一障害点が発生しやすく、非同期処理なのでどこで問題が発生しているか分かりづらい
    • メディエーター
      • ワークフローに関する知識と制御を持ち、単一障害点も解消できる
      • 結合度が高いため複雑になりがち
  • 特徴
    • 非同期には「リクエスト・リプライ」「ファイア・フォーゲット」があるが、いくつかの問題を抱える
      • エラー処理:解決方法は、ワークフローの委譲
      • データロス:解決方法は、メッセージング技術やACID特性
    • 非同期処理だけでなく、必要に応じて同期処理も検討すべき

スペースベースアーキテクチャ

  • 別称
    • なし
  • 構成要素
    • 処理ユニット
    • 仮想ミドルウェア
      • メッセージンググリッド
      • データグリッド
      • 処理グリッド など
    • データポンプ
      • 処理ユニットとDBの仲介役
    • データリーダ・データライタ
      • データアクセス層ではなく、データ抽象層を採用
  • 特徴
    • 名前の由来は「タプルスペース(複数の並列プロセッサが共有メモリを介して通信する技術)」
    • ハイブリットなシステム構成が作りやすい

オーケストレーション駆動サービス指向アーキテクチャ

  • 「分離」と「再利用」によって効率化を図るつもりが、一つの変更が全てのサービスに影響を及ぼすという、非効率を生み出してしまっている
  • (「再利用」により「結合」が発生し、結合度が上がってしまうという負のトレードオフ

マイクロサービスアーキテクチャ

  • 別称
    • なし
  • 構成要素
    • 粒度を細かくし過ぎないように、以下からサービスの分離を考える
    • フロントエンドは、以下のどちらを採用してもよい
    • 分離したサービスごとに「サイドカー」を設ける
      • 「サービスメッシュ」する事で運用面の関心事を解決する
  • 特徴
    • ドメイン駆動型設計(DDD)の考え方に影響を受けている
    • 高度な分離のために、再利用よりも複製を選んでいる
    • 境界づけられたコンテキストの論理的概念を、物理的にモデル化している
    • マイクロサービスアーキテクチャの通信は、プロトコルを意識した異種間相互運用性を利用する
    • サービスを跨いだトランザクションは作らない
      • もし作るなら「サーガパターン」を用いるとよいが、そもそも作るべきではない



⚙️アーキテクトについて


アーキテクトにキャリアパスがないと言われている所以

ソフトウェアアーキテクトに明確なキャリアパスがない理由は、以下の4つ。

  • ソフトウェアアーキテクチャ自体の定義が業界でよく定まっていない
  • ソフトウェアアーキテクトの役割が非常に広範囲にわたり、拡大を続けている
  • ソフトウェア開発エコシステムが急速に進化しているために、ソフトウェアアーキテクチャが常に変化する対象になっている
  • ソフトウェアアーキテクチャについての資料の大半が、単なる歴史的経緯になってしまっている


アーキテクトに期待する事

アーキテクトは、以下である必要がある。

  • プログマティック
  • ビジョナリー


また、「アーキテクトらしく考える」ために必要な事は、以下の通り。

  • アーキテクチャと設計の違いを理解する
    • 違いなんてものは存在しないので、チームの壁を取っ払って、コラボする
    • (違いを決めてしまうと分業してしまい、最も重要な"コラボレーション"が失われるため、敢えて違いを設けないという意味)
  • 広範的な技術知識を持つ
    • 開発者は深さ、アーキテクトは広さ
    • (ここを履き違えると、機能不全に陥る)
  • トレードオフの理解・分析・調整する
    • トレードオフは、Google検索では見つけられないし、正解も不正解もない
    • (時と場合によるので、その場その場に応じて順応する必要がある)
  • ビジネスドライバーを理解する


つまり、アーキテクトに期待する事は、以下8つ。

  • アーキテクチャ決定を下す
  • アーキテクチャを継続的に分析する
  • 最新のトレンドを把握し続ける
  • 決定の順守を徹底する
  • 多様なものに触れ、経験している
  • 事業ドメインの知識を持っている
  • 対人スキルを持っている
  • 政治を理解し、かじ取りする


アーキテクトのパーソナリティ


アーキテクトのパーソナリティは、以下3タイプに分類される。

  • コントロールフリークアーキテクト:きつめ。開発チームに制約を与え過ぎてしまい混乱を招く。
  • アームチェアアーキテクト:ゆるめ。開発チームに作業が集中してベロシティと生産性が低下する。
  • 効果的なアーキテクト:ちょうどいい。エラスティックリーダーシップを取れる。


アーキテクトが、どの程度コントロールフリークで、どの程度アームチェアであるべきかは、以下により変動する。

  • チームの親しさ(親しければ緩くていいし、組立てのチームならキツめでいい)
  • チームのサイズ(小さければ緩くていいし、大きければ多少の制約は必要)
  • 全体的な経験(シニアが多ければ緩くていいし、ジュニアが多ければ制約やメンタリングが必要)
  • プロジェクトの複雑さ(シンプルなら緩くていいし、複雑なら統制が必要)
  • プロジェクトの期間(短ければ緩くていいし、長ければ統制が必要)


アーキテクトが意識すべき事

アーキテクト自身がボトルネックにならず、かつ現場感が保てるように、以下の方法を取る

  • PoCを頻繁に行う
  • ストーリーを引き受ける
  • イテレーション内でバグ修正に取組む
  • 日常業務を自動化する


「本質的な複雑さ」は仕方ないが、「偶発的な複雑さ」を生まないように、以下の4Cを行う

  • Communication(コミュニケーション)
  • Collaboration(協調性)
  • Clarity(明瞭さ)
  • Conciseness(簡潔さ)

https://www.oreilly.co.jp/books/images/picture_large978-4-87311-982-3.jpeg