Mirai Translate TECH BLOG

株式会社みらい翻訳のテックブログ

『ソフトウェアアーキテクチャ・ハードパーツ』完全に理解した

はじめに

こんにちは。プラットフォーム開発部でリードエンジニアをしているchanceです。

私たちのチームは現在、分散モノリスからマイクロサービスアーキテクチャへのアーキテクチャ刷新を推進しています。

さまざまなアプローチを模索する中、2022/10 にオライリーから日本語訳が発売されたこちらの書籍を読みました。

www.oreilly.co.jp

非常に参考になる内容ばかりで、とても助かっています。今回はこちらの書籍の感想エントリです。

書籍の概要

一言で言うと

「マイクロサービスの大きさと通信方式をどう決定するか」について書かれた書籍です。

少なくとも最悪でないトレードオフの組み合わせ

アーキテクチャに絶対の正解はなく「トレードオフを判断して、常に自分たちで決定していくものである」と示されています。この「トレードオフの判断」が本書で一貫した軸となっています。

以下の助言がとても印象的です。

決して最善のアーキテクチャを狙ってはいけない。むしろ、少なくとも最悪でないトレードオフの組み合わせを狙おう。

架空のプロジェクトを題材とした物語

各章の冒頭と末尾で、架空のプロジェクトを題材とした物語が進行します。

各章に関連した課題が提示され、登場人物たちがトレードオフを判断して、決定事項をADRにまとめるまでが描かれていて、理解を助けてくれます。

ADR(Architecture Decision Records)とは何かについては、過去記事も併せてご覧ください。

アーキテクチャディシジョンレコード(ADR)始めました - Mirai Translate TECH BLOG

ところで、ハードパーツとは何か

「ハード」には「難しい」と「堅い」の2つの意図を込めていて、一度決定したら後からの変更が難しい、アーキテクチャの堅い土台部分を「ハードパーツ」としているようです。

書籍の内容

大きく2部構成になっています。

  • 第1部は、アプリケーションやデータベースをどう分割するか、という話。
  • 第2部は、分散するデータの扱いや分散トランザクション、通信方式などの話。

今回は主に第1部の方から、印象的だった部分を抜粋しつつ、学びとして得たことをまとめていきます。

システムを分割するのは、ビジネスが推進するときだけ

分割可能かどうかではなく、ビジネス上の要因が重要だと述べられています。

アーキテクトは、明確なビジネス上の推進要因が存在しない限り、システムを小さなパーツに分割すべきではない。 アプリケーションを小さなパーツに分解する主なビジネス上の推進要因は、市場投入速度や市場での競争優位性の実現などだ。

「分割したら(技術面以外で)何が嬉しいのか」が明らかな場合にのみ、分割を検討すべきです。

闇雲な分割の先にはあるのは更なる混乱

戦略を立てて計画的に分割することが重要

「アプリケーションのすべての部分がマイクロサービスである必要はありません」 「それはマイクロサービスアーキテクチャの最大の落とし穴の一つですよ」

DDDでいうところの集約や境界づけられたコンテキストが完璧に定義できれば、その境界で分割するのでよいかもしれません。しかし、境界づけられたコンテキストの判断もまた難しいものです。あくまでも目的はビジネスを推進することであり、単一責任やその他の品質特性を複合的に見て、トレードオフを判断することが必要です。

分割の副作用を受け止め切れるのか、考えて考えて考える

分割することでそのサービス単体ではシンプルになりますが、サービス間の連携は複雑になります。

  • 通信(同期/非同期)
  • データアクセス/データ連携
  • データの整合性(アトミック/結果整合性)
  • サービス間のオーケストレーション
  • エラー発生時の回復性
  • 運用面での監視
  • などなど

これらにどう対処するかをしっかりと見極め、それでもなお分割するのか、ということです。

また「どう分割するか」だけでなく「どう統合するか(=分割すべきでないか)」も同じように重要です。

多くの開発チームは、粒度分解要因に注力しすぎて、粒度統合要因を無視してしまうというミスを犯す。サービスの適切な粒度に到達する秘訣は、この相反する2つの力を均衡させることにある。

例えば、粒度統合要因としてはACIDトランザクションが必要な場合が挙げられています。サービスを分割すると、基本的には結果整合性とセットで設計することになります。逆に言えば、アトミックな整合性を担保したければ分割するべきではない、と言い換えられます。このようなことをアプリケーションとデータ、両方の側面から検討する必要があります。

分解/統合要因に捉われすぎて思考停止しない

本書では非常に端的にわかりやすく、分割/統合要因を列挙してくれています。

ここで注意したいのは、要因を短絡的に捉えすぎないことです。

トランザクションが単一なら統合すべきだ」のように文章を切り取ってしまうと、それがチェックリストのようになって思考停止してしまうリスクに繋がります。例えば、既存のアプリケーションが単一トランザクションだったとしても、モノリスであったから結果的にそうだったのであって、本当の意味では整合性は不要だったかもしれません。

分解要因や統合要因は考えの切り口と捉えて、柔軟な思考でシステムと向き合う必要があります。

さらに、実際にはチームや組織で設計に取り組むことになるため、このような考え方をメンバー間で共有する必要があります。こういう思考的なものは、一度言ったからといって浸透するものではないと思います。恥ずかしながら私自身も偉そうに人に教えられるほど熟達した者ではありませんので、ともに学びながら、判断力をつけていければと考えています。

単一責任の原則は主観的であり、判断の一要素にすぎない

分割後のサービスの粒度(大きさ)が適切であるかの判断軸として、「単一責任の原則」が挙げられています。しかし、この原則は主観的になりやすいものだと述べられています。

マイクロサービスアーキテクチャでは、マイクロサービスを「単一の目的を持ち、個別にデプロイされる、1つのことをうまくこなすソフトウェアの単位」と定義している。そのため、開発者は、なぜそうするかを考えずに、サービスをできるだけ小さくしたいと考えてしまう傾向がある。何が単一の責任であり、何が単一の責任でないのかという主観的な問題が、サービスの粒度に関して多くの開発者が頭を悩ませるところだ。

どの単位で集約させることが凝集性が高いのか、正解はひとつではありません。

解釈の違いでいかようにも定義できる

分解要因/統合要因と併せて複合的にトレードオフ分析を行い、「結果としてどのような単一責任を持たせることとするか」を考える必要があります。

データベースを分割しないという選択肢

マイクロサービスアーキテクチャでは基本的にデータも分割する前提で考えますが、本書では サービスベースアーキテクチャ というものも紹介されています。

本書におけるサービスベースアーキテクチャとは、個別にデプロイされたユーザーインターフェイスと、個別にデプロイされた粒度の荒いリモートサービス群から形成される分散型のマクロなレイヤード構造と、モノリシックなデータベースにより構成される、ハイブリッドなアーキテクチャスタイルのことだ。

サービスは分割、データベースはひとつ

モノリシックなデータベースとは言っていますが、各テーブルへのアクセス経路をしっかり分割することで、分割しようと思えばいつでもできる状態のことを指します。(ここが複雑に入り組んだ状態では、サービスベースアーキテクチャとは言えない。)

データベースは単一なままサービス間の低結合を実現でき、すでにモノリシックなデータベースが存在する状況においても非常に強力なアーキテクチャです。

データベースの分割に悩みすぎず、まずはテーブルへのアクセスやテーブル間の結合を下げることで、取り回しの良い分散アーキテクチャに近づけられそうです。

技術負債返済だけでなく、ビジネス価値に還元する

コラムのひとつに、アーキテクチャストーリー という概念が紹介されています。

実装や変更が必要な機能を記述するユーザーストーリーとは異なり、アーキテクチャストーリーには、アプリケーションの全体的な構造に影響を与え、何らかのビジネス上の根拠(スケーラビリティの向上、市場投入時間の短縮など)を満たすリファクタリング内容を記述する。

例えば、以下のようなストーリーが例示されています。

アーキテクトとして、私は支払いサービスを分離する必要がある。
支払い方法を追加する際の拡張性とアジリティを高めたいからだ。

これは技術負債の返済とは異なるとも述べられています。

技術的負債ストーリーは、通常、イテレーションの後で開発者が「コードをきれいにする」ために必要な作業を示している。 アーキテクチャストーリーは、それとは異なり、特定のアーキテクチャ特性やビジネスニーズをサポートするために迅速に変更される必要のある事柄を示している。

アーキテクチャの刷新活動も、何らかの「ビジネス推進要因を満たすこと」に紐づいて計画されるべきだと言えます。「技術負債の返済」自体が目的とならないよう、何のためにサービスの分割をするのか、それで得られるビジネス価値を明らかにして、適切な選定をしていきたいと思いました。

技術負債の返済も、チームのリファクタリング活動として取り組みたいですが、こういう修正が後から大掛かりにならないように、ベストな答えは見つからないとしても現時点で考えられることをもってハードパーツと真摯に向き合おう、ということかなと捉えました。

第2部について

第1部で分割(統合)したアプリケーションやデータをどのように繋げるかというお話で、以下のような内容になっています。

  • 共通な処理を個別実装するか、ライブラリや共有サービスとするか
  • 複数のサービスがアクセスするデータの所有権をどこに置くか
  • 他のサービスが所有するデータにどうアクセスするか
  • サービスを跨いだフローをどう制御するか
  • 分散トランザクションをどう制御するか
  • サービス間の通信をどう定義するか
  • 分析のためのデータは一箇所に集めるべきか分散させておくか

どの章も非常に参考になる内容ですが、長くなってしまうのでご紹介は泣く泣く諦めます。

まとめ

書籍『ソフトウェアアーキテクチャ・ハードパーツ』を拝読させて頂き、今回は特に前半部分から、分散アーキテクチャの構築において学びになったことをまとめました。

  • システムを分割するのは、ビジネスが推進するときだけ
  • 分割の副作用を受け止め切れるのか、考えて考えて考える
  • 分解/統合要因に捉われすぎて思考停止しない
  • 単一責任の原則は主観的であり、判断の一要素にすぎない
  • データベースを分割しないという選択肢
  • 技術負債返済だけでなく、ビジネス価値に還元する

書籍で述べられているのは具体的ではありますが一般論であり、そのまま自分達の現場には適用できるものではありません。自分たちにとってはどうかを考えることが重要で、そのために頭の整理の一助になるとてもありがたい書籍でした。

まずは、ソフトウェアアーキテクチャのハードパーツを「完全に理解した」ところです。

引用:ダニング・クルーガー効果

「バカの山」を登った後には、「絶望の谷」が待っています。これに挫けず、「継続の大地」に向けて、ビジネス価値を捉えて、トレードオフを分析して、「少なくとも最悪でない」アーキテクチャを模索していければと思います。

最後に

みらい翻訳では、エンジニアを募集しています。

ご興味のある方は、ぜひ下記リンクよりご応募・お問い合わせをお待ちしております。

miraitranslate.com