耦合與系統設計

耦合與系統設計


Strong or loose, we live in dread,

Of the coupling monster under the bed.

Yet without it, your system would flake,

Coupling is a pillar you can’t forsake.


耦合是一切罪惡的根源?


:「這邊的 code 一團亂,有複雜的相依關係。」


:「程式碼到底是誰寫的?」


git blame 下去,發現是半年前的自己…


一個完全沒有耦合的系統


所有元件都彼此獨立、可替換


寫起來很舒服

想怎麼改就怎麼改


但這是好設計嗎?

能滿足商業需求嗎?


什麼是耦合?


詞源

Coupling 源自拉丁文 copulare

co:一起

apere:連結、固定

意為「將事物連結在一起」。


在生物學,copulare 則為「交配」的意思。

1
2
3
 ∧ _ ∧ ∧_∧
(,,´∀`,,)w< )ー♡
/ ∩ づ C \

服務間存在耦合 = 服務間存在連結


手錶內有無數的齒輪與彈簧相互連結


引擎、車輪、剎車和其他零件耦合在一起成汽車


不同的耦合設計,帶來不同的結果及維護成本


我們根據什麼因素決定耦合的強與弱呢?


耦合程度


耦合程度越大,它們需要同時修改的頻率就越高


什麼原因導致這些元件需要一起改變?

  • 共享的生命週期
  • 共享的知識

共享的生命週期


A. 單體式應用程式

1
2
3
4
5
6
7
8
9
10
┌─────────────────────────────┐
│ Monolithic App │
│ │
│ ┌────────┐ ┌──────────┐ │
│ │ 付款 │───│ 授權 │ │
│ └────────┘ └──────────┘ │
│ │
│ 同一個部署單位 │
│ 同時啟動、同時關閉 │
└─────────────────────────────┘

B. 獨立的模組

1
2
3
4
5
6
7
8
9
10
┌──────────────┐      ┌──────────────┐
│ 付款服務 │ │ 身份驗證服務 │
│ │ │ │
│ ┌────────┐ │ │ ┌──────────┐ │
│ │ 付款 │ │ ───> │ │ 授權 │ │
│ └────────┘ │ API │ └──────────┘ │
│ │ │ │
│ 獨立部署 │ │ 獨立部署 │
│ 獨立生命週期 │ │ 獨立生命週期 │
└──────────────┘ └──────────────┘

共享的知識


元件為了能夠協同合作,必須共享知識


共享知識可以用幾種不同的方式存在:

  • 知曉模組的介面
  • 知悉對方的需求
  • 獲知對方的實作細節

在耦合元件的邊界,共享越多的知識,

你會遭遇的連鎖變動就越多。


A. 直接依賴具體實作

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──────────────┐
│ UserService │
└──────┬───────┘
│ 依賴

┌─────────────────────┐
│ <<MySQLRepository>> │
├─────────────────────┤
│ BeginTransaction() │
│ ExecuteSQL() │
│ Commit() │
│ Rollback() │
└─────────────────────┘

B. 依賴介面,但暴露實作細節

1
2
3
4
5
6
7
8
9
10
11
12
13
┌──────────────┐
│ UserService │
└──────┬───────┘
│ 依賴

┌─────────────────────┐
│ <<IRepository>> │
├─────────────────────┤
│ BeginTransaction() │
│ ExecuteSQL() │
│ Commit() │
│ Rollback() │
└─────────────────────┘

C. 依賴抽象介面

1
2
3
4
5
6
7
8
9
10
11
┌──────────────┐
│ UserService │
└──────┬───────┘
│ 依賴

┌─────────────────────┐
│ <<IRepository>> │
├─────────────────────┤
│ Save() │
│ Query() │
└─────────────────────┘

知識的流動方向


1
2
3
4
5
6
7
8
┌───────┐              ┌───────┐
│ Sales │ │ CRM │
└───┬───┘ └───┬───┘
│ │
│ <---------------- │ 知識流動 (Knowledge Flow)
│ │
│ ════════════════> │ 依賴方向 (Dependency)
│ │

Upstream and Downstream Component


Upstream Component(上游元件)

  • 介面會公開知識,描述其功能及如何整合
  • 知識的提供者

Downstream Component(下游元件)

  • 使用上游元件的功能
  • 知識的接收者

1
2
3
4
5
6
7
8
┌───────┐              ┌───────┐
│ Sales │ │ CRM │
└───┬───┘ └───┬───┘
│ │
│ <---------------- │ 知識流動 (Knowledge Flow)
│ │
│ ════════════════> │ 依賴方向 (Dependency)
│ │

系統

《系統思考》:系統為一組相互連結的元素,其組織方式能夠達成某種目的。


系統的三個核心要素

  • 元件 (component)
  • 連結關係 (interconnection)
  • 目的 (purpose)

軟體階層

  • 類別本身也能視為系統,其元件包含方法和變數
  • 方法本身也是系統,由個別的程式描述來共同實現方法的目的

系統中的耦合


系統核心三元素

  • 目的需要元件連結關係
  • 元件連結關係實現目的
  • 元件允許連結關係
  • 連結關係指揮元件

系統的改變

在任何系統中,你不可能只改變其中一個元素,但不影響到另外兩個。

這帶出了系統設計的重要概念: 邊界 (boundaries)


系統設計的本質

便是關於邊界的取捨。

(裡外有什麼、有哪些會跨過邊界或來回移動)


耦合

人們經常假設軟體設計要徹底去耦合,使元件完全獨立,但實際上並非如此。

若兩個元件要協作,它們就得共享知識


軟體工程師的工作

我們必須留意元件的連結關係,即元件間分享了哪些知識
什麼方式分享的,這些知識分享又會如何影響系統。


References


ʕ •ᴥ•ʔ: Thank you

Share