精讀《可維護性思考》

黃子毅發表於2021-10-11
PS: 所有沒給原文連結的精讀都是原創,本篇也是原創。

前端精讀之前寫了 23 篇設計模式總結文,再加上 6 種設計原則,開閉、單一職責、依賴倒置、介面分離、迪米特法則、里氏替換原則,基本上對程式碼的可維護性有了全面深刻的理解。

但你我在工作中都會不斷遇到爛程式碼,快要無法維護的大型專案,想一想,僅憑設計模式就能解決這些問題嗎?為什麼不斷膨脹的大型專案總是變得越來越難以維護,而複雜度更高的真實世界,但沒有人覺得快要崩塌了呢?

設計模式考慮的是程式碼之間的關係,設計原則考慮的是模組以及專案間的關係,那是否存在更上層的思考,解決大型專案越來越難維護的問題?

精讀

先考慮一下,為什麼真實世界沒有可維護性問題?

真實世界為什麼沒有可維護問題

這個問題看起來有點傻,因為從來沒有人會發出這樣的抱怨 “我們的產品、科技、概念太多了,多到我覺得無法在這個世界活下去了”。但是在程式碼世界,程式設計師經常會抱怨,專案的概念太多、設計過於複雜,以至於他無法繼續再維護下去了,是時候尋找下一份工作了。

一種顯而易見的解釋是,生活中,我們都是小角色,活在自己的天空下並不需要觸及那麼多概念,而程式設計師在專案中基本扮演了上帝的角色,必須為每一個細節操心。

但這並不完全解釋得通。我們以為自己接觸的東西不多,但實際上日常生活的知識太多了,就拿家電來說,每個人都會同時接觸幾十種家電,大到空調冰箱洗衣機,小到手機牙刷充電器,即便這些產品被大量標準化,但每個產品用起來都有大量細節的區別,但沒有一個人覺得學習使用一個新剃鬚刀是一種負擔,也並不覺得一款設計得不好的牙刷,會對整個牙刷行業造成怎樣負面的衝擊。

這背後的原因是:拷貝。正因為我們用的每一件東西都是拷貝,所以即使用壞了也不會對其它相同物品產生任何影響。但程式碼世界則不同,因為程式碼呼叫關係的存在,複用的越優雅,破壞力也就越大。一棟大樓斷了幾塊鋼筋尚可支撐,但換在程式碼世界,只要斷了一塊鋼筋,就意味著這棟大樓所有鋼筋都斷了。這就是程式設計師最痛恨的問題之一,就是為什麼改了一處看似人畜無害的程式碼,卻導致一場故障。

從這個角度來說,程式碼世界是無法吸取真實世界經驗的。而且程式碼世界的這種副作用,在商業上是有巨大正向價值的,即軟體的邊際成本幾乎為零,這是實體產品做不到的,因此軟體需要付出可維護性代價,似乎是這種極低邊際成本的代價。

雖然通過借鑑真實世界的經驗,使自己維護成本變成零時不可能的,但真實世界對軟體世界確實有可借鑑之處,下面我們就來探討幾個有意思的點。

真實世界不斷遮蔽複雜度

不知道你會不會有過這樣的思考:面試官總是問原理,就是擔心我只會用框架,而缺乏基礎。但基礎是什麼呢?懂得 js,java 算是基礎嗎?也可以說不算,因為這些語言背後的編譯原理好像才是基礎,編譯原理背後還有作業系統,作業系統執行在硬體上,而硬體的原理呢?從 CPU 設計到背後的矽是如何製作的,等等,這樣下去,似乎永遠也無法掌握原理。

但當我們從軟體推導到硬體時,可以很自然的發現,沒有人覺得掌握矽膠的製作過程是一件必須的事,我們可以一直使用矽膠製作的產品,但卻可以不用瞭解矽膠製作的原理。

真實世界總是不斷遮蔽複雜度,作為消費者時,我們面對的商品總是經過精心包裝,簡單易用的,只有我們工作時,才需要對某個專業領域的原理有所瞭解。

這個道理可以遷移到程式碼世界,即對於一個龐大而複雜的專案,不能指望每位開發者都瞭解全部原理後才能工作,我們需要在大多數時候把開發者當作消費者來看待,提供精美而穩定的介面。要做到這一點,需要一個類似下圖的架構設計:


從圖中可以看出,即便是業務層程式碼,我也不需要關心過於底層的實現,底層的程式碼就像腳下被壓實了的土地,只需要在上面走就行了。

然而最讓人崩潰的是下面的設計:


為了解決一個問題,需要面對無窮無盡的上下文,這就是維護成本高的最主要原因。

為什麼覺得維護成本高

作為開發者,已經習慣了評價程式碼維護成本高還是低,今天我們換個視角,想一想為什麼你會覺得維護成本高?

對維護成本的感受不完全是客觀的,我畫了一個四象限圖:


左邊是和人相關部分,包括你對程式碼的理解能力,以及對專案的熟悉度。

理解能力越強,越不容易覺得維護成本高;對專案越熟悉,哪怕是屎山程式碼,也會覺得重構後可維護性並不會提高,因為自己對專案會變得不熟悉。

右邊是和專案相關部分,包括業務本身的複雜度,以及這背後的技術抽象實現的質量。

業務本身越複雜,維護成本就會越高,因為資訊量不可避免的增大了,我們永遠不能只盯著 Hello World 的 Demo 研究框架;程式碼質量體現了技術對業務的抽象,抽象的好,複雜度曲線就會比較貼合業務真實複雜度,抽象的不好,Hello World Demo 也能夠新人進來喝一壺。

在這四個關鍵詞中,業務複雜度是幾乎無法改變的,對專案熟悉也需要一個過程,所以重點應該放在理解能力與程式碼質量兩部分。

無論是個人理解能力,還是程式碼質量,目標都是幫助我們快速理解專案,也就是說,只要能快速理解技術專案在做什麼,我如何快速融入,就會覺得可維護性高,反之則覺得不好維護。

所以一個簡單的專案,或者一個分層合理,文件清晰的大型專案都會讓人覺得可維護性好。在這一點上,需要向真實世界學習的經驗就是,即便在軟體世界,也並不是瞭解所有原理,所有犄角旮旯的邏輯才表明技高一籌,帶著這種思想工作只會讓大家陷入無盡的內卷和理解焦慮。我們要給大家思想減負,不需要理解的模組、程式碼設計,就不要輕易展示出來,將每個模組開發所需瞭解的最小知識設定好,最大程度減少開發者的理解負擔。

當然要補充一句,這並不意味著侷限開發者的成長和學習空間,其它知識隨時敞開大門,只是理解它們並不是日常開發所必要的,這些知識形成文件可以用完即棄,不用成為長期記憶。說到這,就引出了真實世界第二個有趣的地方,就是說明書。

真實世界的說明書

我回頭想想也挺不可思議的,無論快遞買來任何需要組裝的東西,按照說明書的指引最終都可以組裝好,而且裝好之後就可以把說明書扔了,完全沒有認知負擔。

與其說快遞包裹的說明書太完善了,不如說說明不完善,不好用的商品根本賣不出去。我們早已習慣極度易用的商品,及其詳盡的說明書了,這是商業社會持續發展,長期博弈後的結果,而且會穩定持續下去。試想一下,如果我們參與維護的專案也有精巧的設計,完善的文件,那維護就不是什麼問題,按照文件說的一步步來就行了。

那為什麼大部分情況,我們接手的專案就像一個沒有說明書的樂高呢?這應該是商品與程式碼的本質區別了,即商品質量好不好,是由買家用鈔票投票的,做得好用,說明書完善的商品才能存活下來,但這背後的技術實現是看不到的,也沒有人可以投票,即便技術人員吐槽程式碼無法維護,但如果專案取得了商業上的成功,也只會越做越大,技術債越滾越多。

技術專案的買家是程式設計師,但程式設計師沒有拒籤的辦法,導致無論專案質量如何都要接受,沒有市場機制的作用,就導致了爛程式碼隨處可見。

要解決這個問題,首先要意識到這個問題,即技術專案質量本質上是無人長期、持續關心的,你可能會說,技術 Leader 會關心呀?但這和業務驅動相比實在是太弱了。產品有使用者側鈔票的投票,無論管理者換多少人,還是會從源頭持續提供動力,但專案質量總是要反覆強調,間歇性整治,並且不同的 Leader 關心程度也不同,因為這背後沒有源動力,除非專案質量影響到使用者那頭的現金供給了,但這種情況發生時,說明專案早已爛透了。

正是因為技術質量缺乏源動力,或者說源動力傳導鏈路太長,我們才要人為的不斷加強重視,重視文件、重視使用體驗、重視是否符合設計模式。只有長期主義者才能堅持做程式碼質量治理,因為堅信總有一天,程式碼質量會影響到業務發展。

總結

這次從真實世界借鑑了一些經驗到軟體世界,我們從借鑑真實世界的遮蔽複雜度,談到了為什麼真實世界的說明書這麼好用,但技術專案文件卻總是缺胳膊少腿的問題。

我們總結出的經驗是,設計原則與設計模式固然可以提升可維護性,但歸根結底還是動力的問題,提升程式碼質量本身就是一件缺乏動力去做的事,或者長期被認為是重要不緊急的事,往往很難找出理由現在就去做,但沒有人覺得不應該做。

所以想要提升可維護性,找到為什麼現在,立刻,馬上就要做技術優化的原因,並立即開始優化才是最重要的。

討論地址是:精讀《可維護性思考》· Issue #359 · dt-fe/weekly

如果你想參與討論,請 點選這裡,每週都有新的主題,週末或週一釋出。前端精讀 - 幫你篩選靠譜的內容。

關注 前端精讀微信公眾號

版權宣告:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證

相關文章