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