ソフトウェアアーキテクチャの基礎を読んだ

「ソフトウェアアーキテクチャの基礎」を読んだので、印象に残った点などをまとめていきます。

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

本書では冒頭で、「ソフトウェアアーキテクチャとはなにか」について定義しており、ソフトウェアアーキテクチャとは、以下の4つの組み合わせであるとしています。

  • システムの構造
    • そのシステムを実装するアーキテクチャスタイルの種類(マイクロサービスやレイヤードなど)を指します
  • アーキテクチャ特性
    • いわゆる非機能要件と言われるものがこれに該当します。
    • 例としては、セキュリティ、パフォーマンス、可用性、テスト容易性などが挙げられます。
  • アーキテクチャ決定
    • システムをどのように構築すべきかのルールを定めるものです
    • 例えば、レイヤードアーキテクチャ上でビジネス層とサービス層のみがデータベースに直接アクセスできるというアーキテクチャ決定を行うことで、プレゼンテーション層が直接データベースを呼び出すのの制限する、といった決定が該当します。
  • 設計指針
    • アーキテクチャ決定との違いがわかりにくいですが、設計指針は、堅苦しいルールではなくガイドラインであるという点で、アーキテクチャ決定とは異なります。
    • 本書では「開発チームはマイクロサービスアーキテクチャのサービス間の非同期メッセージングを利用してパフォーマンスを向上させるべき」といったものが設計指針の例として挙げられていました。

ソフトウェアアーキテクチャといった言葉は、万人が合意する明確な定義がなく、私自身なんとなくの雰囲気で使用していたように思います。 本書では、ソフトウェアアーキテクチャという言葉の明確な定義を示してくれています。 本書を読む前の自分は、「アーキテクチャ決定」「設計指針」といった概念をうまく整理できていなかったので、勉強になりました。

また、システムの構造を構成するものには、「アーキテクチャスタイル」と「アーキテクチャパターン」があるとしており、本記事では「アーキテクチャスタイルについてもう少し書いていきます。

アーキテクチャスタイルとは

アーキテクチャスタイルとは、システムの構造を構成するもので、本書では以下のように定義されています。

私たちはアーキテクチャスタイルを、フロントエンドやバックエンドのソースコードがどのように編成されているか(モノリス内のレイヤー、あるいは個別にデプロイされるサービスとして)、そしてそのソースコードがどのようにデータストアと相互作用するかについての包括的な構造と定義している。

本書で紹介されているアーキテクチャスタイルはいかになります。

私はWebシステムを開発していることもあり、レイヤードアーキテクチャやイベント駆動アーキテクチャ、マイクロサービスアーキテクチャなどは知っていました。

一方で、本書で紹介されているアーキテクチャの中には私が全く知らなかったものもありました。 特に、マイクロカーネルアーキテクチャは、とても興味深かったです。 マイクロカーネルアーキテクチャは、エディタやIDE、ブラウザなど拡張機能を提供しているソフトウェアに使用されているアーキテクチャです。 私は普段からこのアーキテクチャが採用されているソフトウェアを使っているのにも関わらず、このアーキテクチャの存在を全く知りませんでした。。

ソフトウェアアーキテクチャトレードオフ

本書では、トレードオフという言葉が至ることろに出てきます。

ソフトウェアアーキテクチャトレードオフがすべてだ。ソフトウェアアーキテクトにきれいなスペクトルは存在しない。すべての決定は、多くの相反する要素を考慮しなければならない。アーキテクトが、トレードオフではない何かを見出したと考えているなら、まだトレードオフを特定していないだけの可能性が高い。

 

アーキテクチャではすべてがトレードオフだ。だからこそ、アーキテクチャのあらゆる問いに共通する答えは、「場合による」のだ。この答えにいら立つ人は多いだろう。しかし、残念ながらそれが真実だ。RESTとメッセージングはどちらが良いか。マイクロサービスは正しいアーキテクチャスタイルなのか。こういった問いに対する答えをGoogleで見つけることはできない。それは場合によるからだ。答えは、デプロイ環境やビジネスドライバー、企業文化、予算、期間、開発者のスキルセット、その他ビジネスドライバー、企業文化、予算、期間、開発者のスキルセット、その他多くの要因に依存する。環境や状況、問題点はそれぞれに異なるものだ。だからこそ、アーキテクチャは難しい。

 

プログラマーは利点はわかっているが、トレードオフはわかっていない。アーキテクトはその両方を理解する必要がある。アーキテクチャ的に考えるとは、与えられたソリューションの利点を見るだけでなく、マイナス面も含めてトレードオフを分析するということだ。

すべての状況に適応できる万能なソフトウェアアーキテクチャというものは存在せず、どのソフトウェアアーキテクチャにも必ずメリットとデメリットがあります。 そのため、アーキテクトは、その時々の状況(システムの扱うドメインやチームメンバーのスキル)に応じて、トレードオフを考え、適切なアーキテクチャを見極めなければなりません。

新しいアーキテクチャを勉強すると、ついついそのアーキテクチャのメリットにばかり目が行ってしまい、そのアーキテクチャを採用したくなってしまいます。 しかし、どんなアーキテクチャにもトレードオフはあるので、そのトレードオフをしっかり認識し、本当にそのアーキテクチャが最適なのか考えなければなりません。 ただ、これが非常に難しい。。

実践ドメイン駆動設計を読んだ

業務でいわゆる軽量DDDを採用しているシステムを扱っており、そのアーキテクチャの理解を深めるために「実践ドメイン駆動設計」を読んでみました。

戦略的DDDと戦術的DDD

本書を読む前から、DDDには戦略的DDDと言われるものと、戦術的(軽量)DDDと言われるものがあることはなんとなく知っていました。

戦略的DDDとはざっくり以下のようなことを意識してシステム開発をすることで、

戦術的DDDとは、EntityValueObjectRepositoryなどの設計パターンを取り入れたシステム開発のことです。

うすうす気づいていたことですが、私が業務で実践しているのはあくまで戦術的DDDであり、戦略的DDDまでは実践できていないんだなーと改めて思いました。 現在のプロジェクトでは、戦略的DDDが実践できて着ないからと言って問題が起きたりはしていませんが、胸を張って「DDDをやってます」とは言えないですね。。

戦略的DDDについては、もともとふわっとした知識しかなかったので、本書を読むことでとても勉強になりました。 特に、境界付けられたコンテキストは、マイクロサービスアーキテクチャのサービス境界の考える際にもよくでてきる概念だったりするので、それを学べたのは良かったと思います。

また、戦術的DDDに関しては、業務で扱っていることもありそこそこ理解しているつもりでしたが、私の認識が不十分であった箇所があったり、業務と本書で解釈(実装)が異なる部分があったりと色々と収穫がありました。 そして一番の収穫は、業務で実装方針に悩んでいた箇所がピンポイントで解説されていたことです。 これは「複数の集約にまたがる参照系処理をどう実装したらいいか」ということなのですが、これについて少し書いていきます。

複数の集約にまたがる参照系処理

DDDでは、基本的にResopitoryを使って集約単位でオブジェクトを(DBに格納されている値から)復元します。 そのため、複数の集約にまたがるような参照系処理では、複数のRepositoryから集約を復元し*1、それらを合成する処理をすることになります。 コードの保守性という観点では、この実装にすることで他の処理(更新系の処理など)との一貫性を保つことができます。 しかし、パフォーマンスと言う観点では、DBアクセスの回数や不要な値(カラム)も取得してしまうという点が問題になります。 これについてどう実装するのがいいのかもやもやしていたのですが、この問題への言及が本書にありました。

必要なデータをすべてリポジトリから取得してユーザーに表示するのが、難しいこともある。 たとえば、いくつもの集約型とそのインスタンスをまたがったデータ取得が必要になる場合などが、特にそうだ。 ドメインを洗練させればさせるほど、こういった状況は起こりやすくなる。

リポジトリだけを使ってこれを解決することもできるが、あまりやりたくはない。

クライアント側で複数のリポジトリにアクセスさせ、必要な集約のインスタンスをすべて取得させてから、必要なデータを組み合わせてデータ変換オブジェクト(DTO)に格納するという手がそのひとつだ。

あるいは、リポジトリ上に特別なファインダーを用意して、一回の問い合わせで各地のデータを取りまとめるようにするという手もある。

そのどちらも使えないような状況なら、ユーザーエクスペリエンスの設計に何らかの妥協が必要だ。 モデルが用意する集約の境界に沿って、ビューを設計することになる。 その結果できあがるのは、人にやさしくない質素で機械的インターフェイスだ。

もっと違う方法で、ドメインのデータをビューにマッピングできないだろうか? その答えが、CQRSという奇妙な名前のアーキテクチャパターンだ。

本書では、私がもやもやしていた点について以下の3つの解決策を示してくれていました。

  1. リポジトリ上に特別なファインダーを用意して、一回の問い合わせで各地のデータを取りまとめる
  2. ユーザーエクスペリエンスの設計に何らかの妥協をする
  3. CQRSというアーキテクチャパターンを採用する

ただ、これらのどの選択肢もメリットもあればデメリットもあり、それらのトレードオフを考えながら選択する必要があります。 特にCQRSに関しては以下のような注意書きがありました。

あらゆるパターンに共通することだが、CQRSを採用することによって失われてしまうものもある。 十分な検証の元で、賢く使うべきだ。 ユーザーインターフェイスがさほど複雑ではなく、単一のビューに複数の集約が絡むこともあまりないのであれば、下手にCQRSを導入しても、必要以上に複雑性を増す結果になってしまうだろう。

どの選択肢にもトレードオフがあり、普遍的に正しい選択しがないのはアーキテクチャあるあるですね。。

終わりに

本書を通して戦略的DDDから詳細な戦術的DDDの実装まで、DDDについて幅広く学ぶことができました。 DDDの知識もある程度深まったので、次は難しいと噂の「エリック・エヴァンスのドメイン駆動設計」に挑戦してみようと思います。

*1:Repositoryは集約と1対1で紐付く

クリーンアーキテクチャを読んだ

クリーンアーキテクチャを(2ヶ月前くらいに)読んだので、内容の復習も兼ねて自分なりにまとめてみます。

振る舞いの価値と構造の価値

まず、ソフトウェアの持つ価値には振る舞いの価値構造の価値の2種類があります。 振る舞いの価値とは、いわゆる機能要件のことであり、構造の価値とは、振る舞いの変更のしやすさ、つまり内部品質や変更容易性と表現される非機能要件を指す、と理解しています。 ビジネスエキスパートにとって、後者の価値を評価することは難しいため、どうしても前者の価値が優先されてしまいがちです。 その結果、昨今話題になっている技術的負債が蓄積してしまうという構造があるかと思います。

すべてのソフトウェアシステムは、ステークホルダーに2つの異なる価値を提供する。それは「振る舞い」と「構造」だ。ソフトウェア開発者には、この2つの価値を維持する責任がある。残念ながら、片方だけにフォーカスすることが多く、もう片方が無視されてしまっている。さらに残念なことに、2つのうち価値の低いほうにフォーカスすることが多く、最終的にソフトウェアシステムの価値がゼロになってしまうこともある。

本書では、構造の価値(=アーキテクチャ)を重要視してソフトウェアを作ることはソフトウェアエンジニアの責務であると書かれています。

ソフトウェア開発者のジレンマは、ビジネスマネージャーがアーキテクチャの重要性を評価できないことである。そのためにソフトウェア開発者が雇われている。したがって、ソフトウェア開発チームには、機能の緊急性よりもアーキテクチャの重要性を強く主張する責任が求められる。

ところで、構造の価値を持ったソフトウェアとはどのようなソフトウェアでしょうか。 それは、超ざっくりいうと重要なものと重要でないものの間に境界線が引かれたアーキテクチャを採用したソフトウェアです。

境界線は「重要なもの」と「重要ではないもの」の間に引く。GUIはビジネスルールにとって重要ではないので、その間に境界線を引く。データベースはGUIにとって重要ではないので、その間に境界線を引く。データベースはビジネスルールにとって重要ではないので、その間に境界線を引く。

その重要なものと重要でないものの間に境界線が引かれたアーキテクチャこそ、クリーンアーキテクチャです。

クリーンアーキテクチャ

これは有名なクリーアーキテクチャ(の一例)の図です。

この図では、重要でないもの(UI, DBなど)は外側に、重要なもの(Entitys*1)内側に配置されています。 この円には「ソースコードの依存性は、内側(上位レベルの方針)だけに向かっていなければならない」というルールがあり、重要なものと重要でないものにしっかりと境界線が引かれています。

一点注意点としては、この図はあくまでクリーンアーキテクチャの一例であり、クリーンアーキテクチャの実装がすべてこの図のとおりになるわけではないということです。 円の数などが異なっていたとしても、依存の方向のルールを満たしていれば、それはクリーンアキテクチャーです。 したがって、ヘキサゴナルアーキテクチャ軽量DDDもクリーンアーキテクチャの一種と言えるかと思います。

図221の円は、概要を示したものである。したがって、この4つ以外にも必要なものはあるだろう。この4つ以外は認めないというルールはない。ただし、依存性のルールは常に適用される。ソースコードの依存性は常に内側に向けるべきだ。

終わりに

本書の構成は、ざっくりと以下のようになっています。

  1. 構造の価値を軽視することの問題提起
  2. プログラムの設計原則(オブジェクト指向関数型プログラミングなど)
  3. クリーンアーキテクチャ

「2.プログラムの設計原則」は分量がそこそこあり、クリーンアーキテクチャだけでなく、様々な設計原則などを学ぶことができます。 個人的には勉強になってよかったですが、これは、本書を先頭から読んでいくとなかなかクリーンアーキテクチャにたどり着かないということでもあります。 なので、前半部分をすっとばして後半のクリーンアーキテクチャの部分を先に読む、というのも本書の読み方のひとつかもしれません。(「クリーンアーキテクチャを学びたい」という動機で本書を読む人がほとんどだと思うので)

*1:いわゆるビジネスルールやビジネスデータを扱うクラスたち