為什麼「耦合」概念該要摒棄

以前,我寫代碼時,我考慮模塊(本文中的模塊就是指單個源文件)的單向依賴關係,考慮介面的正交性和緊湊性。

我覺得我在做低耦合的好設計。

然而,我發現其他程序員寫的代碼依賴關係混亂,介面臃腫,但他們仍然覺得自己寫的代碼耦合很低,設計很好。

我這才發現,我理解的耦合和他們理解的不一樣。

他們理解的低耦合就是把代碼提出來,讓代碼不要「亂」。

然而,對於什麼是「耦合」、什麼是「亂」,他們並不知道有什麼客觀標準可以度量。

所以,現在我相信「耦合」是個有歧義的壞詞,「低耦合」是個程序員經常誤用的理論。

我建議,設計架構、考察模塊之間關係時,不要用「耦合」、「亂」這些無法度量的詞語,而應該改用以下三個可以度量的指標:依賴、正交性、緊湊性。

依賴和耦合的最大區別在於,當我們說「A和B耦合」時,在字面含義中,A和B二者平等。

然而,正確的模塊關係根本不應該平等,而應該是單向依賴才對。

所以我們應該說「A依賴B」,這樣含義要清楚得多。

A依賴B意味著,A模塊可以調用B模塊暴露的API,但B模塊絕不允許調用A模塊的API。

單向依賴是紅線,好的設計一定不會違反這條紅線。

注意:根據實質重於形式原則,本文中的「依賴」指人腦中的依賴而不是編譯器的依賴。

只要程序員編寫模塊A時,需要知道模塊B的存在,需要知道模塊B提供哪些功能,A對B依賴就存在。

甚至就算通過所謂的命名查找之類的「解耦」手段,讓模塊A不需要import B或者include 「B.h」,人腦中的依賴仍舊一點都沒有變化。

唯一的作用是會騙過後文會提到的代碼打分工具,讓工具誤以為兩個模塊間沒有依賴。

很多程序員覺得「耦合」是壞事,愛寫兜圈子的代碼來消除所謂的「耦合」。

但是我們改用「依賴」術語後,我們就發現單向依賴不是壞事,根本不必費心消除,

因為,真正的重點是,依賴關係中,被依賴方暴露的介面能不能足夠「正交」和「緊湊」。

正交性是指一個模塊提供的API中,多個方法之間是否有重複的功能。

如果有重複功能,正交性就差。

通常,正交性高的模塊更穩定,不會因為上層業務變化而被迫修改代碼。

好的API內部的多個方法之間不應該有任何重複功能,只實現正交的機制。

如果感覺拆得太細使用不便,應該在底層API之外包裝出一層Helper、Utility組成的膠水層。

膠水層調用底層原語API來實現常用模式供上層使用。

對於膠水層中的模塊,對正交性的要求可以稍低一些。

注意上層代碼既可以直接調用正交的底層API,又可以調用膠水層的常用模式。

緊湊性是指一個模塊提供的API中,公有方法總數必須很少,每個方法的參數也必須很少。

《Unix編程藝術》上說一個模塊不要超過7個方法,不然就很難理解。

但我實踐中發現,我一般編寫的模塊,公有方法通常不超過3個。

總之,單向依賴、正交性、緊湊性這三個指標都很務實,有客觀方法可以度量。

我覺得也許可以代替「低耦合」這種「公說公有理婆說婆有理」的務虛理論。

比如前兩天我們ThoughtWorks的諮詢師郵件列表中就有人分享一些工具,用上述標準自動檢查代碼質量。

那麼將來你和別的程序員約架,你要噴對方代碼寫得爛,你就有了依據,因為你可以直接用工具給代碼打分。

另外,將來如果有同事或者網友在討論編程時,用了「耦合」、「解耦」、「亂」之類的混亂術語,你可以把這篇文章發給他看,然後鄙視他。


推薦閱讀:

什麼是軟體架構
什麼是「守」
含德之厚
讀《代碼不朽:編寫可維護軟體的10大要則》C# 版
Logging,Metrics 和 Tracing

TAG:软件架构 | 设计模式 | API | 编程范式 | 接口设计 |