Categories
程式開發

架構設計原則之我見(一):反思KISS原則


寫在前面

在架構設計的領域,人們總結出了很多原則。這些原則的用語大都很簡略,容易傳播。但是提出這些原則的人往往不會特意告訴你,什麼場景下應該用這樣的原則,什麼場景下不該使用。

用心的人也會發現,在實踐中應用這些原則時,好像並不是那麼回事,有時反而會帶來相反的效果。於是,這些原則便淪為心靈雞湯,或事後總結時作附會之用。

本文針對這一問題,對部分設計原則展開討論。期望這些討論可以拋磚引玉,引發讀者自己的獨立思考,形成讀者自己的判斷,不再迷信設計原則。而且,不但對本文中所論及的這些原則要如此,對於其他的原則也應當如此。讀者對於本文的內容也應保持同樣的態度,以形成自己的獨立判斷為目的,不要簡單的全盤接受、全盤認同,那就失去本文的初衷了。

本文將首先從 KISS 原則出發分析,KISS(Keep It Simple, Stupid)原則翻譯成中文,意思是“保持簡單、愚蠢”。這是一句沒有主語的話,猜想主語是指設計師,並且這個“It”所指的應該是設計師所設計的目標系統。這條原則大意是告誡設計師們,在設計系統時要保持目標系統的“Simple and Stupid”。

針對這個原則詳細分析,可以發現它有以下幾個問題。

沒有明確“Simple and Stupid”的判斷原則

怎樣才能算是“Simple and Stupid”?這是很讓人迷惑的地方。人們在認知一句無主語的話時,會下意識地把這句話的主語映射為自己。所以,一般人看到這個原則,下意識給出的都是自己所認知的“Simple and Stupid”含義,當然,這未必是該原則作者所表達的“Simple and Stupid”含義。

要分析這一點,首先需要明確參與目標系統建設的相關角色。

任何一個請設計師設計並建造的為用戶服務系統,最少都會涉及到四方人員:系統擁有者、設計師、實施人員、目標用戶。而這四方的形成,是由社會分工導致的:

系統擁有者是最終為整個系統買單的人,也是最終獲得系統運營收益的人;用戶是系統的服務對象;其他兩方都是從系統擁有者身上拆分出來的角色,因為系統擁有者不具備設計師的能力,而設計師又不具備按時實施完成的能力。因此,這四方人員在看到這個原則時,對於什麼是“Simple and Stupid”都會有各自的看法。

在目標用戶的角度,能讓業務運作方便,能夠節省時間的系統才是 “Simple and Stupid”。因此,用戶會要求實施人員做出讓他們使用起來“Simple and Stupid”的產品。而在現實生活中,由於分工已經很細,當目標用戶的需求傳達到實施人員時,已經過許多不同角色的加工,已經嚴重失真;同時實施人員實現需求也需要較長的時間,因此,系統實現完成後交付給用戶使用時,產生了巨大的時間差。對需求的誤解會形成施工的反复,而反饋時間差導致了對需求的處理不及時,往往導致錯過業務的最佳時間窗口。因此,用戶總對實施人員的輸出不滿意,而實施人員則覺得是用戶的需求不對,兩方總是存在衝突。很明顯,用戶的“Simple and Stupid”很難得到滿足。

在目標系統擁有者的角度,花費最少、產出最高的系統才是“Simple and Stupid”。因此,他關注的是如何能夠簡單地通過這個系統獲利,換一句話說, 就是如何能夠簡單地給他的用戶帶來便利,節省目標用戶的時間。所以,目標系統擁有者的角度,就是在用戶的角度之上,多加了一個成本的考慮:為了做​​到讓用戶使用起來簡單,他需要花的成本是多少?未來的收益又會是是多少?這是他關心的。相對來說,目標用戶並不會關心系統建造的成本,用戶關心的只是他們在使用系統時所花的成本。

在設計師的角度,他潛意識里當然也會認為方便自己工作的設計才是 “Simple and Stupid”。因此,他會拿出他自己最熟悉的那一套設計,這個思路所帶來的後果就是所謂的“金鎚子”(Golden Hammer)。

在實施人員的角度,他潛意識裡也會希望方便自己的工作,儘早地完成被分派的任務,這是他所希望的“Simple and Stupid”。因此,實施人員會希望設計師給出的設計方案能方便他們落地實現,因為設計師自身的“Simple and Stupid” 觀點會對實施人員的工作難度產生巨大的影響。比如體操教練讓一個體操隊員來做一個後空翻,這是“Simple and Stupid”。但是讓一個沒經過體操訓練的普通人做一個後空翻,這絕對不“Simple and Stupid”,可能會摔斷脖子出人命的。

所以,對於技術水平不同的實施者,他會的或者他能夠熟練掌握的技術才是 “Simple and Stupid”。如果一個高水平設計師沒有考慮到實施團隊的水平,給出他所認為的“Simple and Stupid”方案並勉強推進落地的話,要么實現不了,或者勉強實施出來,最後也會問題不斷,甚至引發重大事故。因此,設計師要設計 一個系統的話,必須要結合實施團隊的技術水平,做出適合他們的架構設計。如此,對實施團隊而言才是“Simple and Stupid”。

從上述的分析來看,“Simple and Stupid”是因人而異的,不同的角色有不同的訴求,並不一致,而且這些訴求都存在於各個參與方的潛意識裡,很難識別。於是就會形成這樣的結果:實施人員的工作常會受限於設計師的設計,因為設計師要考慮自身工作的“Simple and Stupid”;同時,實施人員在工作時會和用戶直接打交道,而目標用戶則會有業務方的“Simple and Stupid”觀點,會對實施人員的工作產生衝擊。因此,實施人員被夾在用戶和設計師的不同“Simple and Stupid”觀點之間而痛苦不堪,甚至長期加班都於事無補。難怪實施人員會對業務恐懼,而對設計師則是又愛又恨:遇到適合他們的設計是“愛”,遇到不合適的設計則“恨”。

可見,讓各方都得到“Simple and Stupid”是不可能的,那麼哪一個才是設計師想要得到的“Simple and Stupid”呢?

首先,設計師這個角色是從系統擁有者身上拆分出來的,需要考慮系統擁有者的“Simple and Stupid”。

其次,系統是給用戶用的,需要考慮目標用戶的“Simple and Stupid”。

再次,系統擁有者的“Simple and Stupid”已經包含了用戶的“Simple and Stupid”,所以,系統擁有者的“Simple and Stupid”才是真正所需要的“Simple and Stupid”,況且他是系統的出資人,理當得到這個利益。而為實現這個利益,先需要考慮用戶的“Simple and Stupid”,整個系統才會有收益,才有做的價值;然後才能考慮實現目標系統所需成本的“Simple and Stupid”。也就是說:設計師和實施人員所認為的“Simple and Stupid”,都不是真正的“Simple and Stupid”。

“Simple”與“Easy”

人們在說“Simple”的時候,往往潛意識裡說的是“Easy”,即“容易”。如果把“Simple and Stupid”這句話的主語補全的話,那麼“Simple”實際上指的是用戶使用起來“Simple”,而人們潛意識裡的“Simple”,指的是自身工作的“Easy” 。其實, “Simple”並不等同於“Easy”,要把系統做到“Simple”,往往是最難的,一點都不 “Easy”。同樣,實施人員負責構建系統,也是設計師所設計系統的目標用戶,要讓他們也“Simple”,對設計師的要求更高。

當然,如果系統的目標用戶是實施人員或設計師自身時,這種情況屬於用戶、實施者以及設計者三者合體,這是最好的情況。合體之後,減少了分工對設計的影響,需求也不容易失真,系統反而好設計,比如 Git 的設計師本身也是 Git 的用戶。如果一個企業系統的設計者自身也是企業系統的用戶,這也能提升系統的設計質量,只不過企業系統的用戶往往不懂設計。如果大家都意識到這個問題,未來應當會有所改善。

複雜度在不同分工間會互相影響

系統擁有者、設計師、實施者和目標用戶,他們之間的複雜度總是有一個整體平衡的關係:如果要把某一方的工作變簡單,其他角色的工作則往往會變得更加困難。

比如一個設計師設計出來一個他自認為“Simple and Stupid”的系統,但最終卻往往會提升目標用戶的使用難度,或者會提升施工人員的實施難度,或者會提升目標系統擁有者的成本、或降低其收益。許多設計師在給企業設計系統的時候,為了其所堅持的“Simple and Stupid”理念,不斷地和業務團隊發生衝突, 其實只不過是為了方便自己,用自己更熟悉的設計方案而已。然而這麼做很容易降低其用戶的使用體驗,並且這麼繼續衝突下去,設計師自身的體驗也最終會變得一點也不“Simple and Stupid”。

反之,要得到一個讓用戶用起來“Simple and Stupid”的系統,或讓目標系統擁有者覺得“Simple and Stupid”的系統,則會讓設計師的工作變得更加複雜、更困難。要做到這一點,需要設計師突破自身的認知,先站在用戶的業務角度去考慮,這是非常難的;還要站在老闆的角度,要時刻計算著成本,這更難了。許多人都會吐槽,還不如自己來當老闆。

如前所述,用戶業務訪問的“Simple and Stupid”才是目標,所以要先完成用戶業務訪問的“Simple and Stupid”,然後考慮到系統擁有者的成本,同時去考慮實施者的“Simple and Stupid”,做到低成本可持續迭代,最後才能考慮設計師自身的“Simple and Stupid”,這才是一個設計師所應考慮的“Simple and Stupid”順序。往往用戶的訪問方便了,實施者的工作也會相對變得簡單,成本也會更低,因為用戶的需求清晰了,會避免走很多的彎路。

可見,設計師的工作沒法變簡單,其自身工作的“Simple and Stupid”只能放在最後才可以考慮。人們總想成為設計師,但為什麼只有極少人才能夠做到, 可見其工作的困難程度可見一斑。

所以,每個設計師在思考這個原則的時候,都必須先要明確:設計的目的是要先滿足誰的“Simple and Stupid”?是自己還是用戶?

設計師不能夠為了“Simple and Stupid”而去設計

然而哪怕設計師意識到不能只考慮讓自己的工作變簡單,也知道需要滿足用戶的業務場景,可如果設計師以“Simple and Stupid”的態度去理解業務場景,也是不可能因此而真正理解業務的。因為在外行看來,用戶在其業務領域內的活動永遠是複雜的,絕不簡單。設計師會因為追求“Simple and Stupid”而簡化業務需求,導致很難理解用戶的分工,誤解業務的需求。

只有當設計師承認自己是業務的外行,放下自己的任何業務觀點,放棄自己所謂的設計原則,放下自己的先入為主,從最簡單的業務入手,然後逐漸變成業務領域的內行時,他才能真正從業務視角來觀察業務。在這個前提下,他才能對業務生命週期以及用戶訪問生命週期進行分析,才能根據業務分工的不同、或者根據業務流量壓力的不同,進行合理的樹狀拆分。通過這種方式所形 成的設計,一定是符合業務運行規則的;所形成的不同系統,各自的邊界一定是清晰的,一定是內聚的,也因此一定是“Simple and Stupid”。

也就是說,只有設計師放低自己的身段,從業務上去分析、拆分,才能夠得到一個內聚的結構,這個結構也才因此而被稱為“Simple and Stupid”。所 以,這個“Simple and Stupid”的效果只不過是系統設計符合用戶業務內聚的一個副產品,是內聚的一個外在表現,並非設計的目標。可見,“Simple and Stupid” 並不是因為追求“Simple and Stupid”而帶來的,反而是追求業務“內聚”的一個結果,不能作為設計時目標。

所以,在設計時,設計師一定要站在目標用戶的角度,體驗並理解用戶的業務,然後再依照目標用戶的實際需求進行設計,並形成內聚的系統,那麼最終結果一定會是“Simple and Stupid”的。也就是說,“內聚”原則才是設計時的最高目標。

所以,一旦僅僅以“Simple and Stupid”原則作為設計的最高目標,會很容易失去業務的目標,忽視業務人員的訴求,失去業務的“內聚”,從而導致業務問題複雜化,反而使業務的運轉變得更加困難。這麼下去,也會使設計師、施工 人員和用戶三者之間產生衝突,矛盾激化,因為設計師的工作變簡單了,用戶和施工人員的工作一定會變得更複雜。

“Simple and Stupid”原則的作用

雖然這個原則不能作為設計目標,倒是可以作為審查設計的一個手段。比如在審查一個系統的時候,一旦所設計的系統對於目標用戶訪問的拆分不夠清晰,且不是樹狀結構的時候,那麼這個系統往往會表現出來耦合的問題,牽一發動全身,對用戶或施工人員都不夠“Simple and Stupid”。因此,這個原則可以作為架構審查時的一個檢查點,用來判斷一個設計是否合理,反饋給設計人 員,幫助設計人員發現不合理的設計,進而改進設計。

查閱了一下這個原則的出處,發現其原本是軍工行業對設計飛機的一個要求。 “Simple and Stupid”原則中所說的“Stupid”本義,是形容修理人員對系統組件修理維護時的簡單程度,不需要復雜的工具,直接簡單替換即可。其針對的是系統組件的修理維護人員,即用戶,不是系統的設計者。為達到這一目的,系統設計者必須要做好內聚,不能存在耦合,他的工作因此反而變得更複雜、 更加困難了。感興趣的讀者,可以去研究一下這個原則的歷史背景。

不同系統之間“Simple and Stupid”的互相影響

前面討論的互相影響還僅局限在系統內部。如擴展到更大的範圍,那麼不同系統之間的“Simple and Stupid”也是會互相影響的,一個設計師對其係統的“Simple and Stupid”判斷也會擴散到外部,對其他系統產生影響,類似“蝴蝶效應”。

比如硬盤設計師設計一塊機械硬盤,根本不會去考慮維修的“Simple and Stupid”,因為機械硬盤的維修成本太高,壞了就直接丟棄,不需維修,所以硬盤設計師的工作相對會容易許多。如果要把機械硬盤設計成維修時可以“Simple and Stupid”,硬盤設計師的工作難度會高上好幾個級別,還不一定能夠實現出 來,成本也會飆升。

而在設計一個軟件系統時,則因為機械硬槃無法維修這一前提,也不會在硬盤維修方面考慮“Simple and Stupid”,因此用戶在使用軟件系統時,就時刻需要考慮硬盤中數據的備份,增加了用戶的使用複雜度。可見,硬盤的設計方便了,用戶的使用就複雜了。

為了降低用戶的使用複雜度,軟件系統需要能夠自動應對硬盤失效的情況,因此,這一要求就增加了軟件系統設計人員和實施人員的複雜度。如果要進一步降低實施人員的複雜度,但卻使得軟件設計師的工作複雜度進一步增 加。

通過這個例子也可以發現,相關係統的設計師之間,其工作難易程度也是存在連鎖反應的:某個系統的設計師工作簡單了,其他相關係統的設計師工作則會變複雜。

在目標系統內部拆分樹的範圍內來說,子系統之間互相影響主要可以分為兩個方向:上層節點的設計,會影響子系統的劃分;而子系統的設計,則會影響大系統拆分時的取捨。比如上例中,底層硬盤的設計,直接影響了上層軟件的設計。而目標系統的設計,也會影響到與其相連的外部系統,並最終擴散到系統外的整個世界。

所以,一旦形成設計師、施工人員和用戶三者的分工,他們各自工作的難易程度會有平衡關係,最終會影響到系統擁有者的難度。而設計師是其中最難的工作,不可能達成“Simple and Stupid”。並且在整個系統的設計中,設計師可以對其他某個角色的工作複雜度作出取捨,但絕不能對自己工作的難易程度作出取捨。哪怕需要取捨,也要放在最後一個來考慮。而設計師對自身工作的取捨,往往都是受限於社會整體技術水平的發展,這個取捨最終也會通過其所設計的系統影響到整個世界。

由此也可以看出,“Simple and Stupid”原則無法適用所有的情況。不去了解一個原則的歷史,盲目地直接引用到軟件行業來,很容易造成誤解,因為每個人都可以拿這個原則來為自己的工作辯解。這個原則其實是告訴我們,只有用戶的“Simple and Stupid”才是對的。

“Simple and Stupid”與內聚的關係

也有人說,只要做到內聚、低耦合,不就可以滿足“Simple and Stupid”了?是的,內聚的系統一定是“Simple and Stupid”。因此,如果已經做到內聚,就不再需要用“Simple and Stupid”原則來判斷,“內聚”才是最核心的設計原則。反之, 做到“Simple and Stupid”的系統,則並不一定是內聚的,比如一個足夠簡單但是耦合的系統,也可以是“Simple and Stupid”,可以很容易讓人掌握,可是它並不內聚。所以,“Simple and Stupid”並不能作為“內聚”的判斷標準,也不能作為設 計目標。

而“內聚”才是設計的真正目標,只有“內聚”才是各個行業、各個領域通行 的原則,為什麼呢?因為只有內聚才能夠保證權責對等,才能保障個體在空間 上的連續與完整,不同個體才得以佔有獨立的空間,才能符合現實世界的特質!因此,做設計時,不如直接強調“內聚”原則。

為了論證內聚,人們用了很多理論,但“內聚”這個詞已經足夠好用了,應該擔心的反而是人們對“內聚”這個詞內涵的正確理解,比如下文中的一些原則也有對“內聚”的不同表述,也很容易令人造成誤解。

參考資料

KISS原則維基百科