6月 2019|sitateru tech blog

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

2019年6月3日月曜日

書評『進化的アーキテクチャ ―絶え間ない変化を支える』

こんにちは、シタテルの茨木です。

社内の輪読会でオライリー『進化的アーキテクチャ ―絶え間ない変化を支える』を読みました。
琴線に触れた部分・キーワードを中心に簡単にご紹介したいと思います。

どういう本か・総評

システムの「変更しやすさ」(進化可能性)をいかにして追求し、また経年劣化させないか、というところに主眼を置いています。経年劣化から守る仕組みとして「適応度関数」という考え方を導入します。
具体的な手法や考え方は、継続的デリバリーやドメイン駆動設計などの知見を参照しており、これらの知見を俯瞰的にまとめた内容とも言えます。
個人的には、適応度関数を始めとした本書で導入される概念より、参照されている既存の概念(CI/CD、DDDやその他の設計プラクティス)の方が参考になりました。最近の設計や開発プラクティスを俯瞰する本として読むのもいいかもしれません。

適応度関数

アーキテクチャが満たしているべき要件(本書内では次元)を保護するもの。
循環的複雑度・ユニットテスト・監視・メトリクスといったシステム的・自動的に測定可能なものだけでなく、外部組織によるシステム監査などの人手による測定も包含する概念。
守るべき次元を定め、適応度関数として定義、測定し続けることで、外形的にアーキテクチャを保護する。保護することで、壊さずに変更し続けられることを担保する。
ちょっと理想論すぎるかなという印象もありますが、そういう捉え方もあるな、という感想です。

アーキテクチャの分類・マイクロサービス

本書では下記のような各アーキテクチャを対等に並べて、それぞれの歴史的背景や特性を、主に進化可能性の観点から整理しています。
  • モノリス(3層レイヤ化モノリス等を含む)
  • イベント駆動アーキテクチャ
  • SOA
  • マイクロサービス
  • サーバレス
いわゆるレガシー・エンタープライズ感の強いEDAやSOAから、マイクロサービスまで、しっかり比較の土台に載せている点は非常に良いと思いました。
まあ、最終的にマイクロサービス推しであり、そこに多くの紙幅が割かれてはいますが…
マイクロサービスのどういった特性が優れていて、他のアーキテクチャではその特性は何とトレードオフにされているのか、整理して理解することができただけでも本書を読んだ価値があったと思います。
モノリスを構築できないとき、なぜマイクロサービスがその答えだと思うのか。
マイクロサービスのメリットの多くは、ビジネスドメインを中心としてサービス単位を構成することに由来するものです。(この辺は、後述の逆コンウェイ戦略にも通じます)
従い、仮にマイクロサービスであっても、サービス粒度がビジネス的な境界線(境界づけられたコンテキスト)と乖離していてはメリットの多くは享受できません。
また逆に、モノリスアーキテクチャであっても、ビジネスドメインに基づいてしっかりとモノリス内でモジュール化(疎結合化)が成されていれば、マイクロサービスに近いメリットが得られるということでもあります。
そこのところをしっかり意識して、安易に流行りのアーキテクチャというだけで飛び付かないようにしたいですね。
マイクロサービスという名前にひっかからないようにしてほしい。各サービスは決して小さい必要はない。むしろ有効な境界づけられたコンテキストを捉えることが必要なのだ。

サービス境界分割の手法

何を軸にサービス境界を分割するべきかについては下記3つが挙げられています。
  • ビジネス機能グループ
    既存のビジネスコミュニケーション階層を反映する。コンウェイの法則に従う。
  • トランザクション境界
    トランザクションは最も分離しにくい要素である。
  • デプロイメント目標
    デプロイ頻度が異なる箇所を境界とする。
マイクロサービスであればサービス単位として、モノリスであればモノリス内のモジュール構成として、反映していけると良いですね。

コンウェイの法則/逆コンウェイ戦略

システムを設計するあらゆる組織は、必ずその組織のコミュニケーション構造に倣った構造を持つ設計を生み出す。
一般に人はコミュニケーションコストを避ける。また、チームを跨ぐコミュニケーションはコスト高になる。
ゆえに、チーム外の人間が所管する業務フローやコードにはできるだけ影響を及ぼさないように設計・実装しようとする(調整範囲をチーム内に閉じようとする)力学が働く。
そこから転じて、解決してほしい課題に合わせて、極力チーム内で調整が閉じるように、チーム組成をする、というのが「逆コンウェイ戦略」になります。
ただ一方で、チーム内の結束が維持できるのは精々10人程度が上限(一般的なスクラムでもそう言われますね)、とも述べられていますので、そこにはトレードオフがあります。
本書ではマイクロサービスアーキテクチャを進化可能性の面で優れていると評価していますが、マイクロサービスは「ドメインエンティティ」、「デプロイ単位」、「チーム単位」を一致させながら、かつチームを小さく保ちやすく、結果として逆コンウェイ戦略を満たしやすい、という点も強調されています。

結合よりも重複

結合よりも重複が望ましいという考え方は、本書の中で繰り返されています。
マイクロサービスは無共有アーキテクチャを形成する。その目標は、できるだけ結合を減らすことだ。一般的に、結合よりも重複の方が望ましい。
ツールがあまりにもコードの再利用を容易にしてしまったせいで、現代の開発者は、たやすく結合できてしまう環境の中で適切な結合を行うことに悪戦苦闘している。
例えば、 CatalogCheckout サービスと ShipToCustomer サービスの両方が Item という概念を持つ。両方のチームが同じ名前と同じプロパティを持つので、開発者はサービスをまたいでそれを再利用しようと試みる。それが時間や労力の節約につながると考えるからだ。
けれど、それは労力を増やす結果となる。なぜなら、コンポーネントを共有する全てのチームが変更を伝搬しなければならなくなるからだ。一方、コンポーネントを結合せずに各サービスにItem があり、必要な情報だけをCatalogCheckout から ShipToCustomer に渡す場合は、それらは独立して変更することが可能だ。
開発者が再利用可能なコードを作成する場合、開発者は最終的にコードを使用する無数の方法に対応するための機能を追加する必要がある。その将来の保証全ては、開発者がコードを単一の目的のために使用することをより難しくする
共通化をしたくなる(DRYにしたくなる)のはエンジニアの性ですが、共通化は結合でもあり、変更時の影響範囲を広げるものでもあります。不用意に共通化を行うと変更容易性を損ないます。
あえて重複させるという選択肢を忘れないようにしたいですね。

腐敗防止層を設ける

レイヤを間に挟むことで、将来的な変更可能性を残しておく、という手法です。例えばO/Rマッパであれば、DBMSの変更可能性を残しておく、という意味での腐敗防止層と捉えることができます。
最近、RailsアプリからViewを排除してAPIサーバ化し、フロントを別でSPA化する機会がありましたが、この構成におけるAPIコントローラも腐敗防止層だなー、と思いながら書いていました。
RailsのViewではどうしてもViewからModelへの直参照を止められず、結果として密結合になっていきますが、SPA<->API Controller<->Modelの分離が明確になったことで、かなりモデル層の変更がやりやすくなったと感じます。

デプロイに関するプラクティス

「継続的デプロイは開発側の都合であって、ユーザは頻繁な小規模改修を望んでいない」 という観点はもっともだと思いました。
折衷案として機能トグル(コードベースにはマージするがフラグ制御でユーザオープンしない)を用いる方法などが挙げられています。

個人的には、適応度関数はそこまで刺さらなかったですが、個別のトピックは面白い・参考になるものが多かったです。
ただ個別トピックはおそらく殆どに元文献があるので、本格的な設計本をたくさん読んでいる方には物足りないかもしれません。
取っ掛かりをつかみたい人にはおすすめできるかと思います。
よければ読んでみてください。

, , ,