Clean ArchitectureとBuilding Evolutionary Architecturesを読んだ
Clean Architectureという本とBuilding Evolutionary Architecturesという本を最近読んだのでざっくりとしたメモ。(両方共2-3時間ぐらいでざっくりとしか読んでないので、解釈間違いは普通にありそうです)
両方共アーキテクチャに対するメタ的な視点な部分があるので、合わせて読むと面白いかも。
Clean Architecture
Clean Architecture(Clean Codeの人のシリーズ)という本を読んだ。
- Clean Architecture: A Craftsman’s Guide to Software Structure and Design | InformIT
- PDFとかEpubとかMobiが買える
Robert C. MartinのClean *
シリーズでいわゆるクリーンアーキテクチャそのものだけを扱ったという内容ではない。
でもクリーンアーキテクチャについて紹介してる章もある。
#CleanArchitecture Clean ArchitectureがClean Architectureについて書いてる章があった… pic.twitter.com/75EB3FW4U3
— azu (@azu_re) September 25, 2017
アーキテクチャのルール自体はシステム/アプリケーションのサイズにかかわらずいつも同じという話。 これはアーキテクチャのメタ的な感じっぽい。
#CleanArchitecture シングルスレッドのアプリ、マルチスレッドのアプリ、重量プロセスのアプリ、軽量プロセスのアプリ色々作ってきたけどアーキテクチャのルールはいつも同じ
— azu (@azu_re) September 25, 2017
> The architecture rules are the same!
そもそもの話としてアーキテクチャを決めるのはプログラマ(アーキテクト)で、その人のスキルとかチームによって異なる選択をしてる。なので、暗黙的に、異なるチームでは異なるアーキテクチャの決定をする。
アーキテクチャの目的は開発、デプロイ、運用、メンテをやりやすくするため。
#CleanArchitecture 良いアーキテクチャがサポートすべきもの pic.twitter.com/xp1upNzbO5
— azu (@azu_re) September 25, 2017
アーキテクトは境界を見つけることが仕事で、そのboundariesの線を引くこと。 境界はDBとかテストとかアプリケーションとかcontextとか色々なところにある。 それを気をつけて認識しないといけない。また同時に認識した境界を無視しなければならない。 なぜなら、すべてを実装するのはコストが高いため。
後は境界を引いた上でそれぞれのコンポーネントを結合するプラグインの仕組みなどについて。 フレームワークをコードに入れるのではなく、コードに対してフレームワークというコンポーネントをプラグインとして入れるようにするとか。
Don’t marry the framework!
境界をちゃんとして、依存関係をちゃんとしよう的な話が多かった。
Building Evolutionary Architectures
Building Evolutionary ArchitecturesというEvolutionary Architectures(進化的アーキテクチャ)についての本を読んだ。
- Building Evolutionary Architectures | ThoughtWorks
- Building Evolutionary Architectures: Support Constant Change: Neal Ford, Rebecca Parsons, Patrick Kua: 9781491986363: Amazon.com: Books
ThoughtWorksの人達が書いた本なので、アーキテクチャに対するメタ的な目線が多かった。
そもそも、Evolutionary Architectures(進化的アーキテクチャ)とは何かという話や進化的アーキテクチャというのは何を目的にしているか。(adaptable Architectureと言わなかったのはなぜかなど?)
Why Evolutionary? pic.twitter.com/dhWQIhUg4k
— azu (@azu_re) October 9, 2017
進化的アーキテクチャは次の3つのポイントが主になってる的な話。
- Incremental change
- Guided change with fitness functions
- Appropriate coupling
継続的に変更すること(Incremental change)ができ、その変更/進化が目的の方向なのかをチェックできる指標をちゃんと持つこと(Guided change with fitness functions)。 つまりアーキテクチャを選ぶことが目的でなく、Fitness functionとなる指標がありそれに対するアーキテクチャを選べているかを確認できるようにすることが目的。
ある変化に対してその変化が目的に沿ったものだったかを計測できる指標のことをfitness functionと言っているという理解。
A fitness function is a particular type of objective function that is used to summarise, as a single figure of merit, how close a given design solution is to achieving the set aims.
元ネタはFitness function - Wikipediaとのこと。
でてくる用語が抽象的なので次の動画も見たほうが分かりやすいかも。
そのため、何がFitness functionなのかは、作るシステム/アプリケーションによって異なる。 あるシステムではパフォーマンスやセキュリティが大事だったり、作るものによって異なる = 進化の方向はアプリケーションで異なる。
テストとかパフォーマンスとかそれぞれコンポーネント毎にfitness functionがあり、システム全体でのバランスを検証する。 スケーラビリティとか、パフォーマンス、セキュリティとかデータスキーマとかプロジェクトにおける指標となるものをちゃんと決めてないと、都度の変化はただの反応的な変化(reactionary architecture)となるので、最初にシステム全体として進化の指標を決めることは大事という話。 つまり、正しい方向を向いてるかどうかという指標はちゃんと決めないと、正しさが分からずに問題となるよという話だと思う。
その指標が決まっているだけでは継続的な進化はできないので、Incremental changeをするためには継続的インテグレーション(CI)と継続的デリバリー(CD)といったリリースサイクルに関わるもの大事という話が結構でてきた。(また、このデプロイの頻度とかは物理的なものとデジタル的なもので異なるという話とか。)
リリースサイクルの例としてGitHubとかの例がでてきた。
なんでリリースサイクルが大事かというとリリース速度と進化的アーキテクチャに相関が存在する。 つまりプロジェクトのサイクルタイムによってアーキテクチャの進化速度が決まり、より早いサイクルはより早い進化を促すことができるため。
継続的にデプロイするには、そのシステムがモジュール化されていることが大事。 そのモジュール化を行う方法?としていろんなアーキテクチャがあるよという、既存のいろんなアーキテクチャ紹介(モノリシック、レイヤードアーキテクチャ、Event-driven architecture、serverlessとか)
けど
Don’t build an architecture just because it will be fun meta-work.
だよという話。
アーキテクチャの対義語(アンチパターン)として泥団子(Big ball of mud)の話。 基本的に泥団子は進化することができないので、新しい変化を取り込むことができない。 いくかの柔軟性を取り込んでいくことでアーキテクチャ全体を変更せずに、取り入れることができる。
柔軟性についてでどういうものがあるかという話。
- 必要ない変数を取り除く
- Immutabilityを取り入れる
- Immutable infrastructureは必要ない変数を取り除く
- 決定を可逆にする
- Make Decisions Reversible
- Revertable、 blue/green deployment
- Prefer Evolvable over Predictable
- Build Anticorruption Layers
- 腐敗防止を設ける
- Mitigate External Change
- 外部ライブラリの変更の影響を小さく保つ
- left-padの教訓
- Updating Libraries Versus Frameworks
- アーキテクトはライブラリとフレームワークを区別する
- 開発者のコードがライブラリを呼び出す
- フレームワークは開発者のコードを呼び出す
- 多くの場合はライブラリを選ぶことで影響が軽減される
- フレームワークは積極的に依存を更新する(セキュリティアップデート)
- ライブラリは必要になったら更新する(update when neededモデル)
- Prefer Continuous Delivery to Snapshots
- The conflict between Continuous Delivery and traditional Agile - kief.com
- -LATESTみたいなスナップショットじゃなくてタグ切って管理
- これはMake Decisions Reversibleとも繋がる(revert可能にする)
- Prefer Continuous Delivery over snapshots for (external) dependencies.
- 継続的デプロイができる環境では外部依存についての考えかたも変える
- 2つの指標を導入する
- fluid
- 自動的に依存を更新する
- guarded
- 固定 -> fluidに戻すように修正する
- Version Services Internally
- 一度に管理するサービスのエンドポイントのバージョンは2つまで
left-padだ pic.twitter.com/JctKbVAVfH
— azu (@azu_re) October 8, 2017
外部モジュールのバージョン管理の話が結構面白かった。
ライブラリとフレームワークの区別について
— azu (@azu_re) October 8, 2017
開発者のコードがライブラリを呼び出す。一方、フレームワークは開発者のコードを呼び出す。
多くの場合はライブラリを選ぶことで影響が軽減される。
フレームワークのアップデートは積極的に行い、ライブラリのアップデートは必要になったら行う。
つまり、フレームワークは自分が制御するわけではないので、アップデートは積極的に行わないと進化できなくなる可能性がある。一方ライブラリは必要になったタイミングで更新すればいいという話。
またフレームワークに関するアンチパターンとしてLast 10%という話があった。
Antipattern: Last 10% Trap
— azu (@azu_re) October 8, 2017
- あるフレームワークで要求の80%が実現できることが確認できていた
- ハックをつかって10%+できた
- しかし最後の10%が無理で要求を満たせなかったので、フレームワークを使うのをやめる
泥団子から進化することはできないのでどうやって分解するかという話。
泥団子を進化させることはできない。(本で ball of mud は結構出てくる) 泥団子を再加工するコストが莫大なものとなる。これを変質させる方法の第一歩はモジュール化。 最初に行うべき作業は現在のシステムからモジュールの発見すること。
ここでも境界を見つける話や泥団子からのマイグレーション方法についてなど。 モジュールへ分解していくのだけど、安易に分解するとパフォーマンスが問題になることがあるよとか、分解した結果複数のモジュールが共有してる共有モジュールはどうするの?とか。
どうにかして境界を見つけて分解することができたら、取捨選択のステップへ。ここでも指標となるFitness functionがでてくる。
Next, developers choose and detach the chosen service from the monolith, fixingany calling points. Fitness functions play a critical role here — developersshould build fitness functions to make sure the newly introduced integrationpoints don’t change, and add consumer-driven contracts.
またIncremental changeの話に戻って
サイクルタイムはビジネスメトリクスであるという話。ならなぜ、短い時間で繰り返せるということはコストが小さくなるということ。最小のコストで試すことができる。 このサイクルタイムを短くするにはいろいろ自動化が必要になるという話。
変化のリスクを小さくするのが進化的アーキテクチャの考え方。 その変化において大きなBreaking Changeを減らす/なくしIncremental changeできるようにする。 それによって、新しいものを取り入れる余地を作る。
雑に進化的アーキテクチャとは何かというと
- 予測可能性より進化性
- 進化のリスクを小さくする(痛みを伴うBreaking Changeなしに進化)
- 依存するライブラリとフレームワークの管理とリスクを考えて意思決定をする
- 可逆性を持つ決定を取り入れる
- 腐敗防止層を設ける
- 進化の速度とリリースサイクルには相関がある
- 短い時間で繰り返せるということは、試すコストが小さい
- プロジェクトのサイクルタイムによってアーキテクチャの進化速度が決まる
- 泥団子は進化することができないので、柔軟性のポイントを取り入れる
- 目的に対する成長なのかを計測する(そのため実装の詳細を無視してはいけない)
アーキテクチャは方程式ではなく、進行中のプロセスのスナップショットにすぎないという話。
読み終わってそういえば犠牲的アーキテクチャというものが同じくThoughtWorksのMartin Fowlerさんが言っていたのを思い出した。 進化的アーキテクチャはより緩やか/より前進的な犠牲的アーキテクチャと言えるのかもしれないなーとか思った。
最近聞かなくなった気もするけど犠牲的アーキテクチャの話も少しでてきてた気がする。
— azu (@azu_re) October 8, 2017
進化的アーキテクチャは緩やかな犠牲的アーキテクチャと言えるのかもしれないhttps://t.co/FckZSanZai
おわり
Clean ArchitectureとBuilding Evolutionary Architecturesを読んでの雑なメモ書き。
両方共、アーキテクチャとは境界を見つけることという話や異なるチーム異なるシステムでは異なるアーキテクチャがあるよという話をしてたのが良かった。
あとはアーキテクチャ選び遊びは楽しいけど、目的にあってないアーキテクチャを選ぶアーキテクチャシンドロームにかかってはいけないという話も共通してた気がする。
Don’t build an architecture just because it will be fun meta-work.
どちらの本も読んで何か実践的な何かを学べるタイプのものではないので、その辺を見たい場合は別の本を見たほうが良さそう。
- Delft Students on Software Architecture: DESOSA 2017 · GitBook
- .NETのエンタープライズアプリケーションアーキテクチャ
- Patterns, Principles, and Practices of Domain-Driven Design: Scott Millett, Nick Tune: 0787721845461: Amazon.com: Books
どちらかというと次のものに近い方向だけど、もう少し技術よりなので短い時間で読みやすい。
感想の量からもわかるようにBuilding Evolutionary Architecturesは結構面白かった。
お知らせ欄
JavaScript Primerの書籍版がAmazonで購入できます。
JavaScriptに関する最新情報は週一でJSer.infoを更新しています。
GitHub Sponsorsでの支援を募集しています。