在紛繁複雜的概念滿天飛舞的軟體程式設計領域,希望能分享自己整理的一些觀點,幫助大家穿透迷霧,看清問題以及解決方案的本質。
人類認知能力上限
有一個說法:人的短時記憶廣度平均數為7,即大多數人一次最多隻能記憶7個獨立的塊(Magic number 7)。
有另外一個說法:當需要根據短時記憶進行資訊加工時,一個成年人能處理的塊的個數是4左右(Working memory)。
這些說法不一定完全正確,但我們可以肯定的是,人類處理資訊、加工資訊的能力是有上限的。
軟體系統的複雜性
然而要完成一個有實際意義的軟體業務系統,絕對不是處理4個變數或者7個變數就能完成的,完整的業務其所需處理的資料要大幾個量級。
由此軟體系統的複雜性與人類認知能力存在上限形成了一個矛盾。當複雜度超過人類可控制的範圍時,我們就可以認為其失控了。
我們要怎麼避免軟體系統失控?或者說如何正確可控地完成一個軟體系統呢?大家可以先思考10秒。
既然矛盾是兩個方面的事情,那解決矛盾也可以從兩個方面入手:
-
一個是分而治之,將問題分解成人類可控的範圍大小
-
一個是從軟體複雜度方面出發,控制總體複雜度
分而治之
要進行分治的話,有也兩個問題要解決
-
按什麼邏輯分組
-
每個問題的規模大小
對於第一個問題的答案就是我們經常聽到的
高內聚,低耦合
上述指導原則,能讓緊密耦合的邏輯、資料歸集到一起,能更少牽制(介面、協議)地進行內部演進。
而存在的 介面、協議 能讓我們可以以更高維度的抽象來組織我們的邏輯。
就像我們組裝電腦時,只要主機板與CPU、硬碟、顯示卡等等的介面協議確定了,那麼主機板就可以不管各類元件的具體品牌,型號地組織不同部件的工作,而各個元件都可以在介面的控制下各自獨立改進。
對於第二個問題,則是:
子問題規模應為單個人認知極限規模的70%左右
如上圖,問題可以分解成不同的層級。上圖把問題及解決方案分解成了3層,核心問題、子問題、孫問題。
之所以有層級的存在,是因為子問題的解若數量太多的話,一個人也是無法整合處理的,因此要處理的子問題解數量必須在一個人的可控範圍內。但數量控制了,子問題的規模可能很大,並非一個人能求得,因此需要繼續劃分孫問題。
從上一段的文字我們也可以得出一個結論,子問題並非越小越好,而是儘可能的大,如此才能減少問題的層級,也減少了整合子問題而產生的消耗(也就是說微服務不是越小越好),而問題規模為個人處理極限的70%則是為了應對後續變化,需要預留一定的buffer。
總體複雜度控制
總體複雜度存在一個極限最小值,其由問題域的本質複雜度決定。
然而我們的解決方案會在本質複雜度的基礎上,有意無意地引入其他很多額外的複雜度:
-
由於人類認知極限而進行子問題分解、整合而產生的複雜度
-
由於未透徹理解問題本質而引入的額外複雜度,如錯誤的設計而形成畸形的、繞了遠路的解決方案
-
由於錯誤判斷問題的演化方向而引入了額外的複雜度,這個可以理解為過度設計
-
由於一些問題域外的其他需求引入的額外複雜度,如為了監控、排查問題等等而引入的複雜度
-
由於程式碼腐化導致的複雜度,如複製程式碼塊,補丁式程式碼等等
-
由於效能問題引入的複雜度
-
......
可以說,引入複雜度的原因有千萬種。而我們能做的,只有一件事情——每次引入複雜度時都認真思考其是否必要,是否利大於弊。
然而我們不能指望於每個人都有能力以及覺悟去審視這個問題,因此自上而下的設計以及監督是必須的,否則程式碼的整體複雜度就會不斷提升,與熱力學第二定律有點類似
孤立系統的熵(混亂程度)永不自動減少,熵在可逆過程中不變,在不可逆過程中增加。
一個良好設計的系統,在後續沒有經過上層設計以及監督(外部系統做功)的軟體系統的混亂程度會不斷增加,直到系統的混亂程度變得與編碼的程式設計師思維混亂程度一致(當然或許編碼程式設計師的思維並不混亂,對程式碼也有自己的要求,這樣系統或許會不再腐化,甚至進化,但我們沒辦法做到每個程式設計師都有這樣的水平)。
小結
本文的內容只是寫好程式碼的序章,但由於規模引起的問題最終解決方向都會落到上面提到的 分而治之 以及 總體複雜度控制 上,這個是根源。
分而治之及總量控制不僅僅能在軟體領域上應用,我們可以從 公司人事組織架構、天體系統研究等等方面都可以看到應用。
後續文章我會嘗試在上面兩個方向上繼續細化,將 封裝、抽象、多型、分層、DDD 等等思想 以及 面嚮物件語言、微服務、中臺等等外功 關聯起來。
若本文能給你帶來幫助,請點選右下角在看,若本文存在謬誤,請幫忙批評斧正,謝謝!
作者簡介
多年金融行業經驗,現為某Top2網際網路銀行高階搬磚工,曾在兩家TOP3股份制商業銀行及一家互金創業公司工作(架構、核心業務主程),EasyTransaction作者,歡迎關注個人公眾號,在這裡我會分享日常工作、生活中對於架構、編碼和業務的思考