代码防腐
代碼腐化似乎注定的
最初:沒有誰是不想好好寫的。都有一個宏偉的規(guī)劃,這次一定
途中:Code Review 如同“堂吉訶德”一般,根本架不住大批量大批量的修改
放棄:躺平了,下次一定
如此循環(huán)往復(fù)。然而腐化了之后,是無法起死回生的。
食品防腐是 low tech 的事情,但是中毒身亡之后起死回生是天頂星技術(shù)
新冠疫苗已經(jīng)被人類掌握,但是逆轉(zhuǎn)免疫風(fēng)暴造成的多臟器衰竭仍然是天頂星技術(shù)
雖然很多人醉心于遺留代碼改造之道。筆者也從事鏟屎業(yè)務(wù)很多年,仍未掌握此項技術(shù)。還是讓代碼一直保持在未腐化的狀態(tài)更簡單一些。
那么代碼如何防腐呢?不靠 Code Review 又靠什么呢?
信息隱藏
如果我們要給 vscode 添加"列出單元測試",以及"執(zhí)行單元測試"的功能,例如實現(xiàn)下圖所示的功能:
是不需要給 vscode 提交 pull request 的,可以通過新建 Git 倉庫以插件的方式給 vscode 擴展功能。
用 Git 倉庫的依賴關(guān)系圖來看
通過這樣的依賴關(guān)系,我們就把插件的實現(xiàn)細(xì)節(jié),也就是其私有的信息(比如 ts server,mocha這些)給隱藏起來了。vscode 不可能反向依賴去知道 mocha-test-explorer 使用了 mocha,同僚插件 typescript-language-feature 也不會對 mocha-test-explorer 的 mocha 產(chǎn)生耦合關(guān)系。這種做法叫信息隱藏。
更通用的說,這是一種 主板 + 插件 的結(jié)構(gòu)。
這種結(jié)構(gòu)和常見的“聚合?API”是不同的
如果我們在插件中持有私有的數(shù)據(jù),插件自己再怎么開接口,也無法把信息主動暴露出去。因為主板不依賴插件,插件之間也不互相依賴。除非主板提供接口,由插件來實現(xiàn)才能暴露信息。什么信息隱藏,什么信息暴露,完全由主板決定。
如果是上圖所示的“聚合 API”風(fēng)格的依賴關(guān)系。服務(wù)自身持有的數(shù)據(jù)就未必是私有的了,很有可能退化成代持的關(guān)系。比如服務(wù)如果把沒有任何額外邏輯的 CRUD 接口都暴露出去了,這個服務(wù)就退化成了 database proxy 了。這樣的信息是否隱藏,完全取決于“每個”服務(wù)對自己接口的設(shè)計。而不能像上圖所示,把所有的裁量權(quán)集中到主板手上。
太理想了吧!這玩意能寫業(yè)務(wù)?
如果我們要實現(xiàn)下面這樣的離散型 UI
要拆成主板和插件兩部分并不難,比如主板可以是這樣的
插件自然是把上面的坑給填上。
如果我們要實現(xiàn)下面這樣的混合型 UI
與離散型 UI 不同。這樣的界面沒有明顯的槽可以開出來。一個區(qū)塊可能是由多種源數(shù)據(jù)綜合計算出來的。這樣的情況,主板可以是這樣的:
然后插件就是不斷地填充這個數(shù)據(jù)結(jié)構(gòu)
除了只讀的界面渲染,還包括響應(yīng)用戶輸入和表單提交的寫操作。比如下面這樣的離散型流程:
顯然這樣的業(yè)務(wù)類型非常適合事件驅(qū)動。我們讓下單完成去觸發(fā) OrderCreated 事件,由其他感興趣的 Git 倉庫去訂閱這個事件。插件和主板是這樣的一種依賴關(guān)系:
但不是所有的流程都是這么簡單的離散型。比如下面這樣的混合型流程:
可以把混合型流程拆分成多個子流程的復(fù)合
如果不想插件與插件之間產(chǎn)生直接的依賴關(guān)系,但是又要進行流程復(fù)合,那只能把一些接口給下沉到主板里。比如這樣的 Git 倉庫依賴關(guān)系
通過以上4個例子,我們可以看到實際的業(yè)務(wù)需求是可以用類似 vscode 的插件架構(gòu)來實現(xiàn)的。這么別扭的寫業(yè)務(wù)是為了啥?
代碼防腐
1971 年 David Parnas 就已經(jīng)寫成了軟件工程的開山名著《On the Criteria to be Used in Decomposing Systems into Modules》。業(yè)內(nèi)的前輩們已經(jīng)意識到了按流程圖來拆分模塊肯定是錯誤的(it is almost always incorrect to begin the decomposition of a system into modules on the basis of a flowchart)。然而50年過去了,我們主流的模塊拆分的思路仍然是“函數(shù)套函數(shù)”,“中臺套中臺”的想法。為什么?
這是國外一個開發(fā)者調(diào)查中受訪者的從業(yè)時間的分布圖
國內(nèi)的開發(fā)者分布會比這個更偏年輕得多。這說明了新人還在不斷地涌入這個行業(yè)。如果指望一個項目上所有的人都能遵守很高的標(biāo)準(zhǔn),能夠獨立對“好”和“壞”的設(shè)計做正確的判斷,這是不現(xiàn)實的。并不是說軟件工程教育不重要,教育仍然是要做的。但是僅僅靠教育來提高軟件工程的質(zhì)量是不現(xiàn)實的。
如上圖所示的“信息隱藏”的做法,其實質(zhì)是為了“代碼防腐”。在這樣的依賴關(guān)系下,插件的 Git 倉庫是不會造成全局的影響的。所有的重大決策權(quán)都收斂到了主板手里,插件無法自己決定接口是什么以及如何與其他插件集成。這樣我們就可以放心地分配新人去寫插件,而不用擔(dān)心插件中的設(shè)計選擇造成大面積的代碼腐化(大不了也就是重寫這個插件)。Code Review 也從螳臂當(dāng)車,變成了只需要重點關(guān)照主板的修改即可。
點擊”閱讀原文“,訪問《業(yè)務(wù)邏輯拆分模式》電子書?https://autonomy.design
總結(jié)
- 上一篇: 一个 bad file descript
- 下一篇: Go 还是需要泛型的