Robert C. Martin「Clean Architecture 達人に學ぶソフトウェアの構造と設計」2017/9/17
https://gyazo.com/a02d73583e818a4e0812fbc940048457
抽象度ではなくて、不安定な code が安定した code に依存する、安定した code が不安定な code に依存しない (依存してゐたら安定でなくなる)、なぜなら software の変更しやすさは software の構造ではなく (裏で實はかういふ事情があって、と言ふべきでない) 變更の scope に比例するべきだから、といふのが clean architecture の全てで、その爲に使へる手法が色々あるね (code のメトリクスも、依存關係逆轉の原則 (DIP) も、use case も、臨機應變に使へる便利な tool) と紹介されてゐる。と私は理解してゐる。そして安定性と抽象度は相關が高い (安定度・抽象度等價の原則 (SAP))。何が安定してゐるかは architect が考へるべき事、それが仕事 software architecture の目的は、求められる system を構築・保守するために必要な人材を最小限に抑へることである。
構造 (architecture) の價値$ \gt振る舞ひの價値
自信過剩
「あとで clean にすればいいよ。先に市場に出さなければ!」
開發者たちはさうやっていつもごまかす。だが、あとで clean にすることはない。市場からの pressure は止まらないからだ。「先に市場に出さなければ」といふことは、後ろに競合他社が大勢ゐるといふことである。競合他社に追ひ拔かれないためには、これからも走り續けるしかない。
その結果、開發者は mode を切り替へることができない。次の機能、また次の機能、またまた次の機能を追加することになり、code を clean にすることまで手が囘らない。そして、崩壞が始まる。生產性が zero に近づいていく。
事實は、短期的にも長期的にも、 崩壞した code を書くはうが clean な code を書くよりも常に遲い。
自信過剩による再設計は、元の project と同じやうに崩壞する。
構造の價値 (重要) > 振る舞ひの價値 (緊急)
完ぺきに動作するが、變更できない program を與へられたとする。要件が變更されると機能しなくなる。修正することもできない。したがって、この program はいづれ役に立たなくなる。
動作しないが、變更が簡單な program を與へられたとする。要件が變更されても修正は可能なので、動かし續けることができる。したがって、この program はこれからも引き續き役に立つ。
software を soft に保つ
stakeholder が機能を變更したいと思へば、その變更は簡單にできるやうになっておくべきだ。變更の難易度は、變更の形狀ではなく、變更の scope に比例しなければいけない。
できるだけ長い期間、できるだけ多く選擇肢を殘す
「system を適切に動作させること」ではない
方針を詳細から守り、詳細の決定を延期。留保する
詳細の例 : DB。Web server。API 形式。framework。切り離し方式
database は詳細
Web は詳細
framework は詳細
DI framework は詳細
標準 library は詳細
方針
entity (最重要 business data + 最重要 business rule)。system が自動化されてゐなくても存在する
單一性 (oneness)・同一性 (sameness)・範疇 (category)
常に valid にする。invalid な entity を生成しない
次點は use case。application 固有の business rule
進化的 architecture
$ \ne順應
動的平衡への進化可能$ \gt靜的平衡への豫測可能
境界線を引く
不要な依存を取り除く
決定を可逆にする
對稱性
可換性
在庫を減らす
實驗
architecture 適應度函數 (architecture fitness function)
architecture の適應度函數は、ある architecture 特性がどの程度滿たされてゐるかを評價する客觀的な指標を與へる。
ある architecture 特性または architecture 特性の組み合はせについて、客觀的な整合性評價を行ふための何らかの仕組み。
architecture 特性 : -ility (〜性)
trade-off
monitoring 驅動開發 (MDD)
監視は繼續的な test
例
循環依存
循環的複雜度 (cyclomatic complexity)
$ M:={\rm Edge}-{\rm Node}+2P={\rm ClosedLoop}+1.
槪ね 10 以下
主系列からの距離
layer 統制
Conformity Monkey、Security Monkey、Janitor Monkey
SQuBOK
software architecture とは、境界線 (boundary) を引く技藝である。
←→結合 (coupling)
software は基盤より長壽命
software は消耗しないが、firmware や hardware は時代遲れになる。その結果、software の變更が必要になる。
software は消耗しないが、管理できていない firmware や hardware の依存關係により、software が內部から破壞される可能性がある。
基盤 : 物理→infrastructure→hardware→firmware→OS→VM→framework
software とは hardware より後に來るもの、hardware とは software より前に來るもの
software は hardware の囘路を書き換へて別の機械として動作させる
hardware 抽象化 layer (HAL ; hardware abstraction layer)
OS 抽象化 layer (OSAL ; operating system abstraction layer)
data は logic より長壽命
Erlang.iconhot code swap
programming paradigm
構造化 programming
構造化 programming は、直接的な制禦の移行に規律を課すものである。
architecture としての關心事 : componet の分離
科學的な、test 可能性
OOP (object 指向 programming)
object 指向 programming は、閒接的な制禦の移行に規律を課すものである。
architecture としての關心事 : 機能
polymorphism (多相性)
依存關係を制禦し逆轉できる
獨立して deploy できる
獨立して開發できる
函數型 programming
函數型 programming は、代入に規律を課すものである。
直接的な data の變更に規律を課す
こんなんが一つの paradigm の訣無いぢゃん…
MLOCaml.iconは證明に有利なのが產まれた理由だから、函數型 paradigm でない RustRust.iconと同じ範疇だよな architecture としての關心事 : data 管理
閒接的な data の變更に規律を課す
RAII (resource acquisition is initialization)
主に外部 resource に關して destructor を呼ぶ RAII
JavaJava.iconの try-with-resources。C# の using。PythonPython.iconの with $ \ne.
C の free
try {} finally {}
評價順序に規律を課す?
論理 programming
これは制禦か?
Future[T]
原則
coding level
coding は製造作業ではなく設計作業。設計書は source code
coding は設計作業だから試行錯誤する
民藝は設計と製造を區別しない
source code は製造過程 (compile) と密結合
architecture は設計の設計
module level (SOLID)
Conway の法則から導かれる當然の歸結。個々の module を變更する理由がたったひとつだけになるやうに、software system の構造がそれを使ふ組織の社會的構造に大きな影響を受けるやうにする。 module を變更する理由はたったひとつだけであるべきである。
module はたったひとりの user や stakeholder に對して責務を負ふべきである。
module はたったひとつの actor に對して責務を負ふべきである。
architecture level では、「architecture の境界」を作るための「變更の軸」
Bertrand Meyer が 80 年代に廣めた原則。software を變更しやすくするために、既存の code の變更よりも新しい code の追加によって、system の振る舞ひを變更できるやうに設計すべきである。
software の構成要素は擴張に對しては開いてゐて、修正に對して閉じてゐなければならない。
抽象に依存する
plugin
Barbara Liskov が提唱した有名な派生型の定義。1988 年に誕生。要するに、交換可能な parts を使って software を構築するなら、個々の parts が交換可能となるやうな契約に従はなければいけないといふこと。
software を設計する際には、使ってゐないものへの依存を囘避すべきだといふ原則。
制禦の反轉 (IoC。inversion of control)
上位 level の方針の實裝 code は、下位 level の詳細の實裝 code に依存すべきではなく、逆に詳細側が方針に依存すべきであるといふ原則。
例 : interface
coding level では
變化しやすい具象 class を參照しない。
變化しやすい具象 class を繼承しない。
具象函數を override しない。
變化しやすい具象を名指しで參照しない。
architecture level では、依存性の rule
component level
component : deploy の單位。動的 link
https://gyazo.com/d9164220c5112dc6a23dfd736bc4c1cc
再利用の單位と release の單位は等價になる。
ひとつの component を形成する class や module は、まとめて release 可能でなければいけない
同じ理由、同じ timing で變更される class を component にまとめること。變更の理由や timing が異なる class は、別の component に分けること。
component を變更する理由が複數あるべきではない
變更の種類が似てゐる class をひとつの component にまとめる
凝集度 (cohesion)
同じ timing、同じ理由で變更するものはひとまとめにすること。變更の timing や理由が異なるものは別々に分けること。
componet の user に對して、實際には使はないものへの依存を強要してはいけない。
不要なものには依存しないこと。
componet の依存 graph 循環依存があってはいけない。
component の依存關係を管理する
component 圖
code:components の依存關係.mmd
flowchart TB
View --> Presenter
Presenter --> Interactor
Authorizer --> Interactor
Controller --> Interactor
Database --> Interactor
Interactor --> Entity
安定度の高い方向に依存すること。
不安定さ (instability)$ I=\frac{C^e}{C^a + C^e}
I = 0 は最も安定してゐる component
I = 1 は最も不安定な component
fan in$ C^a: 依存入力數。component 內の class に依存している外部の component の數。求心性結合 (afferent coupling)
fan out$ C^e: 依存出力數。component 內にある、外部の component に依存している class の數。遠心性結合 (efferent coupling)
下位 level の component が上位 level の component に依存する
sorce code の依存性は data flow から切り離し、level と結び附けるべきである。
「level」の嚴密な定義は「入力と出力からの距離」である。方針が system の入力と出力から離れてゐれば、それだけ level は高くなる。入力と出力を管理する方針は、system のなかで最下位 level の方針になる。
component の抽象度は、その安定度と同程度でなければいけない。
抽象度$ A=\frac{m^a}{m^c+m^a}
$ m^c: component 內の class の總數。
$ m^a: component 內の抽象 class と interface の總數。
https://gyazo.com/06e8586df14c0696f4cd569d8da91c80
主系列からの距離 (distance) $ D = |A+I-1|\in\lbrack0,1\rbrack
閾値 (soft limit) を定める。例へば$ D\le 0.1
苦痛 zone になり易いもの : DB schema。java.lang.String 等の具象 utility
architecture level
部分的な境界を引いておく
分離するが同じ component に置く
strategy。片方だけの境界
facade
connascence
system の全體的な正しさを維持するため、ある component の變更が別の component の變更を必要とする場合、2 つの component は connascent (接續) されてゐる。
https://gyazo.com/7b1edd822a517ccb5da27346c146d163
結合度 (coupling)
clean architecture
その architecture は何と叫んでゐるか?
例
hexagonal architecture
port と adapter
DCI archirecture
DCI (data - context - interaction)
data + role
data
何であるか
role
何をするか。algorithm に對應する
OORAM
Scala.iconの trait
code:scala
class Data { }
object Context {
trait Role1 { }
trait Role2 { }
object Interaction {
def doSomething(data1: Role1, data2: Role2) { }
}
}
data1 = new Data with Context.Role1
data2 = new Data with Context.Role2
Context.Interaction.doSomething(data1, data2)
code:scala
class Data { }
object Context {
trait Role1 { }
implicit def dataToRole1(data: Data): Role1 = { }
trait Role2 { }
implicit def dataToRole2(data: Data): Role2 = { }
object Interaction {
def doSomething(data1: Role1, data2: Role2) { }
}
}
data1 = new Data
data2 = new Data
Context.Interaction.doSomething(data1, data2)
context
data に、scenario (use case) の中の role を振り付ける。data を cast に仕立てる
interaction
role の振られた data を、user の想定する algorithm (business rule) に從って動作させる
BCE (boundary - control - entity)
C4 model
system context - container - component - code
level 每の圖
1. context diagrams
2. container diagrams
3. component diagrams
4. code diagrams
要素
persons
software systems
containers
components
relationships
clean architecture
抽象性の降順。下は上に依存する
企業の business rule : entity
application の business rule : use case
interface adapter : controller | presenter | gateway
framework と driver : device | Web | UI | 外部 interface | DB (ORM)
layered architecture
pipeline architecture
microkernel architecture
plugin
service-based architecture
event 驅動 architecture
space-based architecture
MnesiaErlang.icon
DatomicClojure.icon
orchestration 驅動 service 指向 architecture
關心事の分離
framework 非依存
test 可能
humble object
例 : presenter に對する view。test しづらい view を控へ目 (humble) に保つ
UI 非依存
database 非依存
外部 agent 非依存
我々が學んだのは、architecture の境界は service と service の中閒に位置するわけではないといふことだ。architecture の境界は、service を橫斷することで、component に分割してゐるのである。
architecture 量子
高度な機能的凝集性と同期的な connascence を持つ、獨立して deploy 可能な artifact。
test
test は architecture の最も外側に在る
脆弱な test の問題 (fragile tests problem)
GUI 等の、變化しやすいものに依存しない
test 用 API
application の構造から test の構造を切り離 す
このやうな進化の分離が必要なのは、時閒が經つにつれて、test は具體的かつ個別化する傾向があるからだ。それとは對照的に、production code は抽象的かつ一般化する傾向がある。構造的結合が強いと、かうした進化の分離が妨げられる。