抽象還是不抽象的問題
今天評審了一個IP設計方案,有個地方定義了一個完整性校驗演算法,這個演算法有兩個控制變數,可以組合出12種校驗效果,這12種校驗效果作用在不同大小的控制塊上(控制塊的大小當前有5種情況:512, 1024, 2048, 4096, 8192),會出現稍微的差別。做這個IP模塊設計的人呢,希望分每種不同的情形來進行設計,如果其中有些情形用不上,他就打算直接忽略了。做軟體驅動的人呢,顯然很不喜歡這樣的形式,因為這會產生非常多的重複代碼。但使用這個代碼的人呢,更大程度上支持前者,因為這個立即解決他的問題,而且設計時抱的包袱很少。使用這個代碼的人的領導呢,更大程度上支持後者,因為這樣他的代碼也很難維護……
誰對?
這種情況無處不在,我做過一個嵌入式網管產品,支持二三十種企業路由器和交換機,每種路由器和交換機的形式基本上是差不多的,都是基於SNMP確定設備類型,然後匹配它的mib資料庫,提取它的界面素材,繪製界面,然後把功能索引到不同的MIB表管理程序中去處理。接到這個任務後,組裡就激烈地分成了兩派:一派要設計一種語言,用來「定義」一個設備的特徵,然後,用一個通用的演算法來繪製不同的交換機和功能。一派要各自為政,除了在確定設備類型的時候使用一個公共的界面,其他就各自根據自己的客戶調查和認識,做成啥樣是啥樣,最後拼在一起。
誰對?
又比如拉分支的問題,一線的,對著客戶的人,最喜歡拉分支。你對著A客戶,要求都定了,最重要是不要出問題,出哪個問題就具體修復那個問題。然後你告訴我B客戶要修改Code Base?B客戶關我鳥事?反過來,家裡負責開發和測試的團隊就特喜歡版本歸一,One Track這類的概念:尼瑪每次修改一個特性,要合主版本,A客戶分支,B客戶分支,C客戶分支,D客戶分支……然後每個都要測試,你做給我看看?
誰對?
還有我們編碼中無處不在的,你需要一個鏈表,你是直接在你的數據結構中放next指針呢?還是建立一個list數據結構,抽象這個邏輯呢?你把幾個radio button合在一起使用,是直接放幾個button,然後加一個控制對象呢?還是實現一個radio button group來「自動」完成這個邏輯呢?
這些情況,大部分都是在現有信息下無解的。這個時候,不往前走是錯誤的,亂往前走也是錯誤的。這種情況,你就發現,你習慣的那些「因為……所以……」的理由是完全無力的。這個時候能夠採取的策略就是「道法自然」了:有目標,但守弱,整個過程是放鬆的,先奔著直線去,自己不添加這個力之外的其他的力,然後讓現實去衝擊你(的策略),從而形成一條合理的路徑。
一旦從這個角度考慮這個問題,你就發現你的決策模型不再是因為-所以了。而是不斷在過程中比較所有力量哪個對結果的作用力更大,不斷進行觀察,調整,和平衡。而且這種判斷僅在當時有效,過後就失效了。你不能因為項目開始的時候沒有抽象一個模塊,項目結束的時候抽象這個模塊了,你就認為當時「決策失誤」。所以,對外行來說,架構師最討厭給你講理由,講理由本身就是成本,在這種快速決策中,不斷消耗「講理由」的成本,這個事情就不用幹了。
理解這一點,對於進行工程實施非常重要,比如前面這個鏈表的問題,我從來不糾結到底要不要抽象的,我的策略是(我只是說大部分情形,前面說了,具體情況要靠「感受」,有細節在左右),我先不抽象,直到我寫到有兩個地方都要用到類似的情形了,我才開始把兩者扭合在一起。
如果是個大團隊怎麼辦呢?我的策略是開源(不是對外開源,而是所有開發者間開源),代碼Review。你們互相看到代碼了,你們要一起來抽象,那是你們的事,我只保證架構中給你這個機會(比如我們有這個平台本身的common.lib),你們的東西可以放到一起。架構的抽象策略是靠系統自然生長,不靠人為的期望(比如「實現抽象」)來控制系統。
而「強控制」放在哪裡呢?「強控制」放在強權上。你要賣給某個大型企業,對方有企業安全規範,這明顯是強權,那我基於這個強權需求來設計功能,增加模塊,這個模塊一旦出現,由於其他人要和它介面,自然就形成約束了。架構師通過創建關聯來控制系統,而不是通過定義每個子系統的行為來控制系統。高明的構架設計是什麼都不做(請正確理解這句話的意思),越想表現構架設計做得多麼好,這個架構設計就越失敗。
求道的團隊,每個人都不成為系統的「代理」,這個系統的「代理」就是這個系統本身。架構好,是這個軟體架構好,不是「這個架構師做得好」,代碼好,是這個代碼本身好,不是「這個工程師寫得好」。這就叫自然之道。架構師用設計師的思維去考慮問題,就是錯誤的開始。
推薦閱讀:
※氣和深度學習1:綜述
※抽離設計邏輯
※雞肋——汽車行業AUTOSAR的使用現狀和利弊分析--利篇
※PCIE匯流排的地址問題
※自然,守弱和Plan B