ソフトウェアアーキテクチャの基礎を受けてアーキテクトのあり方を整理

2022-05-03

はじめに

最近チームでも話題1になっているソフトウェアアーキテクチャの基礎 ―エンジニアリングに基づく体系的アプローチを読んだので本の内容を参考にしつつソフトウェアアーキテクチャを考えるためのエッセンスをまとめる。

この本はアーキテクチャの種類を学ぶというよりはソフトウェアアーキテクトとしての考え方を身につけるための本だ。 どんな問題でも解決できる完璧なアーキテクチャなどは存在せず全てトレードオフであり、アーキテクトはチームの人数・専門分野・練度などを鑑みて、得られるメリットとリスクを天秤にかけてアーキテクチャを選択する。

特に小さい会社で CTO をしているとソフトウェアアーキテクトとしての役割の比重も大きく、ビジネス要求の早期実現とプロダクトの長期的な持続性を天秤にかけ、 取って良いリスクと残すべきでないリスクを選ぶ場面も少なくない。
この本はそういった場面で暗黙知的に判断していることを言語化してくれており、どういったポイントをなぜ気にするのかの共通認識を醸成してくれる本である。

以下ではまずソフトウェアアーキテクチャを考えるために知るべき事に触れ、後にソフトウェアアーキテクトとして振る舞うために意識したいことを挙げる。

ソフトウェアアーキテクチャとは

ソフトウェアアーキテクチャを定義するのは以下の要素である。

  • システム構造
    • アーキテクチャスタイルの種類
  • アーキテクチャ特性
    • システムの成功基準
  • アーキテクチャ決定
    • システムの制約
  • 設計指針
    • 開発の方針となるガイドライン

"Done is better than perfect."という言葉2にある通り、ソフトウェアは動いてこそ価値があり、必要に応じて負債を背負いつつも素早く利用可能な状態のものを構築することは間違っていない。 しかし、アーキテクチャの指針がないまま「動くから OK」という判断基準で開発を進めてしまうと大きな泥団子となり、 長期的なメンテナンス性を損ない、機能の改修なども必要以上に時間がかかる様になる。
そういった状態を防ぐために開発者や、特に設計を任される人はソフトウェアアーキテクチャを考えるにあたって何を気にするべきなのかを知る必要がある。

システム構造

システム構造とは「ソフトウェアアーキテクチャ」と聞いたときにまずイメージするコードやコンポーネントの構成である。 本書ソフトウェアアーキテクチャの基礎でも以下に挙げるような主要な構造は挙げられており、それぞれのアーキテクチャの強み・弱みを整理している。

  • レイヤードアーキテクチャ
  • マイクロカーネルアーキテクチャ
  • SoA (サービスベースアーキテクチャ)
  • イベント駆動アーキテクチャ
  • マイクロサービスアーキテクチャ

本記事ではシステム構造については深くは触れないが、これについて知りたければ他にも参考にするべき良い本・記事は多くある。 ソフトウェアアーキテクチャの基礎内ではドメイン駆動設計(DDD)の知識は持っている前提で触れられていたり、 マイクロサービスアーキテクチャもネットワーク越しでのやり取りの難しさ(リトライの必要性、サーキットブレイク)や分散トランザクションの扱い(二重コミット v.s. Saga パターン)などの前提知識を持っていたほうがアーキテクチャの特徴への理解がよりスムーズになる。

以下では私がこれまでに触れた、システム構造の理解に役立つであろう参考を挙げる。

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

DDD

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

その他

アーキテクチャ特性

アーキテクチャ特性とはシステムの成功基準を定義するもので、システムの機能とは直接関係しない。 例えば開発者がプロダクトマネージャーや現場の意見ばかり聞いているとボタンの追加や検索機能など目に見える機能の実現ばかりに注力してしまう。
しかし、システムとして成功するためにはここに挙げられるような特性を意識し取捨選択していかなければいけない。

ここで挙げられてるアーキテクチャ特性は選んだシステム構造に強く影響され、項目からわかるようにソフトウェア開発者の視点だけでなく、SRE 的な視点を持たないと見落としがちになる。
ソフトウェアアーキテクチャを考えるにはシステムがどう有るべきかを機能・非機能含めて考慮する必要がある。
ここで挙げられるものは ISO-25000 に記述がある。

運用特性

  • 可用性
  • 継続性
  • パフォーマンス
  • 回復性
  • 信頼性・安全性
  • 堅牢性
    • 障害発生時にエラーや境界条件を処理できるか
  • スケーラビリティ

構造特性

  • 構成容易性
    • エンドユーザーがかんたんに設定を変更できる
  • 拡張性
  • 活用性・再利用性
  • ローカライゼーション
  • メンテナンス容易性
  • 可搬性
    • 複数のプラットホームで動作するか
  • アップグレード容易性

横断的特性

  • アクセシビリティ
  • 長期保存性 (Archivability)
  • 認証
  • 認可
  • 合法性 (legal)
  • プライバシー
  • セキュリティ
  • サポート容易性
  • ユーザビリティ
  • 耐障害性
  • テスト容易性
  • デプロイ容易性
  • アジリティ
  • セキュリティ

アーキテクチャ決定

アーキテクチャ決定とはどのようにシステムを構築するのかを実装レベルで考え、ルール化することである。
例えば、レイヤードアーキテクチャで構築する場合はビジネス層とサービス層のみデータベースにアクセスでき、プレゼンテーション層からは不可視にしたり、DDD であればリポジトリ層をデータへアクセスするためのインターフェースにする。 そして決定した方針をメンバーに順守させる。

システム構造を一貫性を持って実現するためには、アーキテクチャの根幹となる部分はある程度ルール化して必ず守るべきものとして共有するべきである。

設計指針

設計指針は開発におけるガイドラインを提供することである。 アーキテクチャで決定では、決定した方針を順守させるがプロダクト全体で細かく具体的な方法をアーキテクトが示すのは非効率である。 設計指針として具体的な方法を示すより、望ましいアプローチの方向性を示すことで開発チームが特定の状況下で適切な選択が行えるようにする。

ソフトウェアアーキテクト

これまでにソフトウェアアーキテクチャを選び、それを実現するために必要な項目の知識に触れた。 ここからは、得た知識を基にソフトウェアアーキテクトとして考えるべき事に触れる。

ソフトウェアアーキテクトに期待すること

ソフトウェアアーキテクトはソフトウェアに向き合うだけでは役割の半分も達成できない。 ソフトウェアアーキテクトとして振る舞うためにはアーキテクチャの種類や特徴の理解に加えて、作るものが何を達成したいのかを非エンジニア視点で理解するためにステークホルダーとの折衝、 開発のルールをチームに守らせるといった対人スキルも重要となる。

以下にソフトウェアアーキテクトが期待されていることを例示する。

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

ビジネスドライバーの理解

アーキテクトらしく考えるためにはシステムの成功に必要なビジネスドライバーを理解する必要がある。
アーキテクチャ特性の部分ではシステムの要求毎に重要視するべき特性が異なる事に触れた。 この選択をするためにはソフトウェアアーキテクトがビジネスドメインの知識を持ち、ステークホルダーの期待値を理解する必要がある。

ドメインの関心事

システムに必要なアーキテクチャの特性はドメインの関心事を整理することで定義できる。以下に例を示す。

ドメインの関心事求められるアーキテクチャ特性
市場投入までの時間アジリティ・テスト容易性・デプロイ容易性
ユーザー満足度パフォーマンス・可用性・耐障害性・テスト容易性・デプロイ容易性・セキュリティ
競争優位性アジリティ・テスト容易性・デプロイ容易性・スケーラビリティ・可用性・耐障害
合弁・買収相互運用性・スケーラビリティ・適応性・拡張性

資金の限られたスタートアップなどではとにかく素早い製品の市場投入やフィードバックを元にした改善が求められるため、アジリティや手早くバージョン更新が行いやすいアーキテクチャが必要となる。 一方で、時間的・人的リソースのある大企業が既存プロダクトの上位互換で価格は高くとも良いものを提供しようと考えるのであれば、パフォーマンスや可用性・セキュリティの高さなどの特性を特に重視したアーキテクチャを構築するべきだろう。

アーキテクチャ決定

ソフトウェアアーキテクトはあらゆる情報を整理した上でアーキテクチャを決定しなければいけない。

Architecture Decision Records (ADR)

アーキテクチャを決定する時は ADR を残すことが望ましい。ADR は特定のアーキテクチャを決定した短いテキストファイルで構成される。

ADR は Markdown などで以下のような項目を記述する。

  1. タイトル
  2. ステータス
    • 提案済み
    • 承認済み
    • 破棄
  3. コンテキスト
    • 決定を行った状況
  4. 決定
    • 決定と根拠
  5. 影響
    • 決定による影響
  6. コンプライアンス
    • この決定が順守されていることを確認する方法

アンチパターン

アーキテクチャを決定するときに陥りがちなアンチパターンがある。いかに挙げるものは現実に起こりうるため、アーキテクトは特に意識したい。

資産防御(Covering Your Assets)

選択を誤ることを恐れてアーキテクチャ決定を先延ばしにすること。

克服するためには、2 つの案がある。

  1. 重要な決定は最終責任時点まで先延ばしにし、検証するのに必要な情報が得られるまでは決定を遅らせる。ただし、開発チームをまたせたり、分析麻痺3に陥るほど先延ばしてはいけない
  2. 決定したことが期待通りに実装できるよう開発チームに継続的に強力すること。アーキテクトがすべてを把握するのは不可能なため、開発チームと密に連携して問題が発生してもアーキテクチャ決定を変更して問題に迅速に対応できるようにする

グラウンドホッグデー (Groundhog Day)

ある決定がされたにも関わらず理由がわからないため何度も繰り返し議論されること。

アーキテクチャ決定の際にその根拠をっ示さないために発生するため、克服するためには技術的な理由・ビジネス的な理由の両方を残すことが必要。

メール駆動アーキテクチャ

電子メールなどで重要な決定が行われており、周りがアーキテクチャ決定を見失ったり、忘れたり、決定されたことさえ知らないこと。

電子メールやメッセージングツールなど会話が流れるような場ではなく Wiki など長期的に参照されることが期待される場に ADR に準じたドキュメントを残す事が必要。

アーキテクチャのリスク

アーキテクチャ決定する為にはアーキテクチャごとのリスクの整理が必要となる。

まず以下の項目を組み合わせたマトリクスによってリスクポイントを定義する。

  1. リスクの全体的な影響
  2. リスク発生の可能性
1\2
123
146
369

次に (a)アーキテクチャ特性と (b)システムが持つべき機能 のマトリクスを作ることで各機能(もしくはコンポーネント)毎のリスクを整理する。

(a) \ (b)顧客登録商品表示注文
スケーラビリティ293
セキュリティ916
完全性639

この結果により、選んだアーキテクチャとリスクの精査を行い、リスクの軽減のための改善が必要なのか、リスクが適格なのかをチームで合意しアーキテクチャを決定する。

ソフトスキル

アーキテクトは技術的なアーキテクチャの構築や決定に加えて、開発チームがアーキテクチャの実装ができるようガイドする必要がある。 アーキテクトと開発チームが分断されていると目指しているアーキテクチャの実現は難しくなる。

ソフトウェアアーキテクトの役割はは実装の制約を定義し伝えることだが、制約をきつくしすぎて開発チームのフラストレーションをためてはいけないし、 緩くして統制が取れなくなってもいけない。

アーキテクトが実装から離れすぎていると「アームチェアアーキテクト」と呼ばれ、トレンドに鈍感になったり、実際の詳細を考慮に入れずにアーキテクチャ決定を行ってしまったりする。 逆に実装に張り付いてしまうと全体を俯瞰できなくなってしまうため、そのバランスが必要となる。 また、ソフトウェアアーキテクトが PoC のつもりで実装し提供するものは開発チームからはリファレンス実装のように扱われてしまうことが多い。 アーキテクトは実装するのであればプロダクションクオリティのものを意識するべきである。

加えて、ソフトウェアアーキテクトはアーキテクチャの実装を通して開発チームをガイドするためにリーダーシップを発揮する必要がある。 ステークホルダーとの折衝も必要であり、ピープルスキル・ファシリテーションスキル・ネゴシエーションスキルも必要となる。 またアーキテクトはドキュメンテーションの機会も多く、役割をこなすためには 4 つのCを意識する

  • Communication
  • Clarity
  • Conciseness
  • Collaboration

おわりに

本記事ではソフトウェアアーキテクチャの基礎 ―エンジニアリングに基づく体系的アプローチの内容を元に自身が普段意識していることも含めつつ、 ソフトウェアアーキテクトとなるために必要な知識や考え方に触れた。
キーポイントとして、万能なアーキテクチャは存在せず全てはトレードオフの選択だ。 少ないメンバーで開発をするならモノリシックな構造のほうが開発オーバーヘッドが少なくアジリティが高く開発サイクルを回せたりするし、 十分に開発リソースがあり特定のドメイン知識を深く理解した開発メンバーを揃えて開発をしたいのであればマイクロサービスアーキテクチャを採用するとスケーラブルで柔軟な開発ができる可能性が高い。
チームやシステムが何を大切にしたいかを整理してアーキテクチャ決定を行うのがアーキテクトの役割だ。

また、本記事の内容はアーキテクトと呼ばれる人だけのためのものではなく、開発チームの一員としてコードを書くことが主の開発者にも有効なものだと思う。 開発者は日々プロジェクトの中で大小の選択を行っているはずであり、その選択の結果としてアーキテクチャ特性にどの様な影響を与えるのか、 システムに求められている特性に沿った結果が得られるものなのかを考えられるようになるとレベルの高い開発者と呼ばれるようになると期待できる。

Footnotes

  1. チームメンバーに「普段 tty さんが言っていることが書いてる」と言う人がいれば、「この本の最初の方がよくわからない」と言う人も居る。先述の発言と合わせると普段私の言っていることをよくわかっていないのか?と少々不安になった

  2. この言葉を作る側が言うのは言い訳のようで好ましくはない

  3. 過度に分析しすぎ、解決策や行動方針が決まらない状態に陥ること