Don't Repeat Yourself

Don't Repeat Yourself (DRY) is a principle of software development aimed at reducing repetition of all kinds. -- wikipedia

『ソフトウェアアーキテクチャ・ハードパーツ』

『ソフトウェアアーキテクチャ・ハードパーツ』を訳者の方からご恵贈いただきました。ありがとうございます。献本については基本的にすべて書評を書こうと思っているため、今回も記事にします。発売は10/27のようです。

おことわり

まず指示語についてです。記事中で「本書」「この本」と書く場合は『ソフトウェアアーキテクチャ・ハードパーツ』を指します。また、「著者」は本書を執筆した人を指すものとします。「筆者」といった場合、それは私のことです。

いわゆるスキミングをした状態で一旦書評をするため、本書の細かい議論の見落としや用語の誤認識が含まれる可能性があります。この書評はあくまで「どういった本か」「他の書籍と比較してどういった新規性がありそうか」などを紹介することを目的としています。逆に細かい議論の是非についての議論は目的とはしていません。

概要

本書はソフトウェアのアーキテクチャを考える際に避けては通れない、適切なアーキテクチャを選定するために必要になる「選択肢を提供」する一冊です。具体的にはマイクロサービスをどう分割するかといった話題や、どうコンポーネントを再利用できるようにするか、トランザクションをどう考えていけばいいかといった話題について具体的にパターンを紹介しています。ただしそれらのパターンは「これがベストプラクティス」として一つに定められるほど単純なものではないため、トレードオフを考えつつ「選択するパーツ」として紹介されています。

また、最近話題になっていた『ソフトウェアアーキテクチャの基礎』(以降、「基礎」)を執筆した著者陣が書いたもう一冊の本でもあります。「基礎」はアーキテクトとしての姿勢や、それぞれのアーキテクチャの簡単な概要が中心でしたが、この本はより実践に近く方法論寄りです。「基礎」が「What」を扱うとすれば、本書は「How」を扱うといった関係性でしょうか。

普通は一冊の中で語られることが多いであろう What と How が、なぜ分冊になったのかという疑問が浮かぶかもしれませんがこれには理由があるようです。ソフトウェアアーキテクチャにおける方法論は現実のシステムにナイーブに適用するのは難しく、こうした込み入った話はいわゆる原則を扱いたかった「基礎」では扱えなかった話題という事情があったためのようです。本書の冒頭でまず下記のように説明されています。

Neal と Mark は前著『ソフトウェアアーキテクチャの基礎』(オライリー・ジャパン)を執筆していた際に、内容を取り上げるのを諦めざるを得ない、込み入ったアーキテクチャの例に何度も遭遇した。そうした例は、簡単なソリューションを持たない、厄介なトレードオフの塊だった。二人はそうした例を「ハードパーツ」と名づけ、脇に避けていった。

現代ではデータをどのように設計し、分割しつつ整合性を保って保管しておくかといった一連の流れの重要度が増しています。この問題についても本書は拾い上げるよう努力しています。[*1]従来のアーキテクチャの議論では、マイクロサービスはどう分割するかとか、コードの関心事がどうこうとかそういったアプリケーションに限った範囲が中心だったように私は思っています。が、そうではなくデータをどう分割、配置、保管していくかといった問題についても議論に含めるようにしています。本書は「Modern Trade-Off Analyses for Distributed Architectures(”現代の”分散アーキテクチャのためのトレードオフ分析)」という副題になっていますが[*2]、そうした意味においてまさに現代版に刷新された新しいアーキテクチャ方法論ではないかと私は思いました。

構成

目次だけを拾い上げると下記のような構成になっています。

  1. 「ベストプラクティス」がないとどうなる?
  2. ソフトウェアアーキテクチャにおける結合の見つけ方
  3. アーキテクチャのモジュール化
  4. アーキテクチャの分解
  5. コンポーネントベース分解パターン
  6. 業務データの分解
  7. サービスの粒度
  8. 再利用パターン
  9. データの所有権と分散トランザクション
  10. 分散データアクセス
  11. 分散ワークフローの管理
  12. トランザクショナルサーガ
  13. コントラクト
  14. 分散データの管理
  15. 独自トレードオフ分析を構築する

2〜7章はいわゆるマイクロサービスの分解に関する章です。そして8〜14章はマイクロサービス間をどのように繋ぎ合わせていくか、そのプラクティスが紹介される章です。最後の15章では、実際にアーキテクトが自分自身のトレードオフ分析を本書のように作り上げる手法について簡単に解説されています。

私がとくに熱心に読んで印象に残ったのは5章と7章でした。本書の雰囲気を感じ取ってもらえるように、簡単に内容を引用しておきたいと思います。

5章ではモノリシックなアプリケーションをマイクロサービスに分解していくまでに、どういった手順を踏んでいけばよいかについての例が示されています。こうした形で体系的にまとめられた例はあまり見たことがなく、私自身も仕事で活かしていきたいなと思いました。

手順は(英語版のもののスクリーンショットから引用していますが)下記の図のようにまとめられています。次のような手順を踏んでいくと、ぶれなくマイクロサービスに分類していけるはずだという手法が示されています。著者らはマイクロサービスへの移行について、「思いつきで移行していい結果を生むことはほとんどない」とp.128で語っていますが、まさにその通りで勘に頼らず明文化した手順で取り組むのは何事においても重要です。

コンポーネントベースの分解の流れと使い方(電子書籍版の原著より引用)

7章ではより細かい単位でサービスを分割する分析基準について扱われています。5章ではいわゆるドメインサービスの分割に関する粒度までが扱われていたのですが、7章では「粒度分解要因」と「粒度統合要因」の2つの観点から、もう少し小さくサービスを分解する分析基準について議論されます。

粒度分解要因については「サービスの範囲と機能」「コード変動率」「スケーラビリティとスループット」「耐障害性」「セキュリティ」「拡張性」の観点に着目し、分離できるポイントを探していくとよいとされています(各観点の詳細は本書をご覧ください)。マイクロサービスの分解については私は正直ドメイン駆動設計で言われるような「境界づけられたコンテキスト」単位での分割しか考えたことがなかったのですが、それでは粒度が大きすぎるケースが多々あるのもまた悩みでした。これらの着目点によってもう少し分解できるという新たな視点を得られたように思います。

粒度統合要因は分解の逆です。逆に小さくなりすぎて不便になったサービスを統合するための着目点について議論されます。「データベーストランザクション」「ワークフローとコレオグラフィ」「共有コード」「データ関係」の4つの観点に着目し、結合できるポイントを探すとよいとされています(各観点の詳細は本書をご覧ください)。私が知らないだけかもしれませんが、マイクロサービスはついつい分解の方法に焦点が当たりがちで、分解しすぎたものを結合する手法についてはこれまであまり解説されてこなかったように感じています。

それぞれの「要因」についてはただ手法が解説されるだけではなく、何を目的として行われるべきかも補足説明されているので、導入の際に手段が目的化することも避けられそうでよさそうに感じました。私も今の現場で、サービスの構成に関して個人的に思うところがあるので、この手法を議論の土台にして問題提起してみたいなと思いました。

新規性

概要時にある程度書ききってしまったようにも思いますが、私が思った本書の新規性を紹介しておきたいと思います。

まず全体に通ずる話として各プラクティスを「ベストプラクティス」ではなく「トレードオフ」として紹介しています。ベストプラクティスとして紹介されてしまうと「本当にこれがベストなの?たとえばXX(目的から外れたもの)の場合はどうなの?」をはじめとした本来の目的を忘れたコーナーケースを突く不毛な議論や「これがベストなのだから他を選択する必要はない」といった思考停止が発生してしまう可能性が考えられます。一方で「このプラクティスはトレードオフである」としておくことで、「このケースではこういうデメリットはあるが、それは問題なさそうなのでこれが使えそう」といった選択の考慮と余地が生まれることになります。これは結果的に建設的な議論になり得ると私は考えています。著者の「(そのシステムにとっての)最悪のアーキテクチャを選択しない」という信条ともマッチしています。

アプリケーション内におけるデータ周りの管理に関してかなり明文化されたプラクティスを紹介しています。たとえばマイクロサービス化の文脈において、デプロイの単位が分けられたデータベースの分割は切っても切り離せないという話は多くのソフトウェアエンジニアが認知するところと思います。しかし、分割時に具体的にどういう手法があって、それらにどういうメリットデメリットがあるか整理されている資料は、単に私の認識の範囲が狭いだけかもしれませんがあまり見たことがありません。システムの柔軟性担保やデプロイ容易性を目的としたマイクロサービス化のために「データベースをきちんと分割しましょう」はわかるのですが、「でも具体的にどうやって?」の部分が暗黙知だったように思っています。少なくとも私はそうでした。同様に現在多くのシステムで利用されているであろうサーガパターンについても、本書ではなんと8つもトレードオフの分析込みでプラクティスが紹介されています。

感想

最後に雑多な感想を記しておきます。

定義づけて不毛な議論を避ける

まず、暗黙的に意味を受容してしまいがちな用語の定義をきちんとしてから話題に入っていくのがよかったです。これは「基礎」のときから継続的に著者らが気をつけていることかもしれませんが。たとえば印象的だったのは「1.6」の用語集でした。下記の引用は「結合」という単語の定義です。これは「疎結合」などさまざまな場面で登場してくるような、ソフトウェアエンジニアリングの文脈では非常に一般的な用語ではあるのですが、改めて「本書での意味」をきちんと定義づけしてから議論がはじまっていきます。

2つのアーティファクト(サービスを含む)は、適切な機能を維持するのに一方の変更が他方の変更を必要とする場合、結合されている。

ソフトウェアアーキテクチャに関連する本の多くはこうした定義づけがなく、ボヤッとした状態で議論が進むように感じます。[*3]一部のディスカッションを見ていると、そのボヤッとした土台をもとに読者(識者?)が独自の解釈を生み出し、肝心のソフトウェアをどう作り上げるかの議論ではなく、用語の意味をどう解釈するかについての議論でなぜか盛り上がる印象があります。これについては解釈のできる限り余地をなくすよう、概念を導入する側が定義づけをきちんとするべきだと個人的には思っています。

用語の定義づけというのは、こうした自転車置き場の議論というか、「解釈学」の発生をある程度防ぐことができるため非常に重要です。とくに「結合」のように、もはやソフトウェアエンジニアの間で暗黙的に利用されている用語についてきちんと定義づけをし、適用範囲を閉じてから議論を始めるのは重要です。また、仮に既存の定義づけを利用するとしてもどの識者の学説や発言に依って議論を進めるかを明示するだけでも十分効果があると思います。

「最悪を避ける」ための「トレードオフ」 = 「その状況によりあったもの」を探す旅

「基礎」に引き続き「これが唯一の正しいベストプラクティス」として本書の中のパターンを紹介しないのもよかったなと思いました。トレードオフという言葉はまさに言い得て妙です。私も日常業務で経験がありますが、アーキテクチャの考案というのは「どちらかを立てるとどちらかが立たなくなる」選択の連続のゲームです。

一方で本書では「ケースバイケースだよね」とか、「唯一の絶対正しい解はこれだ。議論の余地なし」として思考停止して片付けず、「最悪でないもの」を探るべく対話を繰り返しながらトレードオフの選択をひとつひとつ決めていきます。アーキテクチャの議論をしていると、ついつい「こうしなければならない」といった思考に陥りがちですが、実はとった選択肢にも何かしらの不味い点があることが多いです。たとえば思いつく単純な例ですと、レイヤードアーキテクチャを選択して各レイヤー間の依存を分けておくと、一部に変更が生じたとしても影響範囲が狭まるというメリットがあるかと思います。一方で、影響範囲を抑えるために多くのデータ変換を行う必要が出てくるわけですが、このデータ変換のメンテナンスコストが意外とかさみ、結果開発を遅らせることがある…などでしょうか。

少し話が逸れてしまいますが、現代は「ケースバイケース」の時代ではあると思います。(私は学生の頃哲学が専攻でしたので少しこの話を掘っておくと、)これを哲学の用語で相対主義と言ったりします。[*4]ただこのケースバイケース、「ケースバイケースである」としてそれ以上の議論を避ける傾向にあります。「ケースバイケース」が一つの結論になってしまうからです。しかしこの結論では議論によって合意をし、何かひとつ選ぶという行為を放棄してしまうため、そもそも何かが新しく判明したりはしません。仕事で言えば、何度ミーティングを開いたとしてもいつまでも物事が決まらず前に進んでいないのです。

私たちはアーキテクチャを考える際、相対主義に取り憑かれることなく、著者らのいう「最悪でないもの」、つまり裏を返せば「より適切」を見つける旅に出る必要があります。歴史が証明してきた通り唯一の正解というものはこの世界にはありませんが、その状況に合ったより適切な選択は合意によって導き出せます。その議論の際に「トレードオフ」の形で本書のプラクティスをひとつひとつ見つめ、その中から一つを吟味して選びとるのはとても有意義な結果を我々にもたらすはずです。

合意を取り物事を決める様は、本書の「Syspos Squad」の例を通じて一部知ることができますが、私も日々の開発の現場でこうした対話をできるようになりたいなと思わされました。本書を読み終えた後の次なる課題は「チーム全体にこのようなディスカッションをできる土壌をどう育てていくか」だったりするわけですが、それはまた別の解を探すことにしましょう。

*1:同じくオライリーの『データ指向アプリケーションデザイン』という本を読んでそれを熱心に考えた方も多かったはずです。

*2:邦訳時になぜか Modern の部分がまるっと落とされているのが気になりましたが。

*3:DDD の青い本とか。解釈するのは一つの享楽ではあるのですが、ただそれは何か別の学問のように感じます。そもそも読みが複数生まれる本は、少なくとも工学的な書籍においてはあまりいいものとは思えません。というのも、よく人文系学問で言われるような「読みの余地」は工学の目標ではないはずだからです。

*4:相対主義も哲学の分野によって微妙に定義づけが異なりそうなので補足ですが、私が念頭に置いているのは倫理学で一般に言われる相対主義の方です。『現代倫理学入門』(加藤尚武)や、あるいは『「みんな違ってみんないい」のか?』(山口裕之)などが念頭にあります。