沒有規則的規則
有一次和人討論錯誤日誌的輸出的原則。這個問題大體是這樣的:比如你有三個模組A,B,C。A呼叫B,B呼叫C,然後C發現錯誤了(好比分配記憶體不成功什麼的),返回錯誤碼給B,B返回給C。
這個過程中要輸出錯誤日誌,現在的問題是,應該是A輸出呢,還是B輸出呢?還是C輸出?還是都輸出?
對一些開發人員來說,無所謂的,多列印一些,更容易跟蹤而已。但如果你做過產品,你就知道客戶看見你這種冗餘列印有多恨你了。我還遇到過這樣極端的案例:十幾年前的時候,我們剛剛開始做GSM,有一次有些位置更新(所謂位置更新,是手機開機或者移動到另一個GSM的站點,要告訴新的站點“我到你這裡來了”)會隨機找不到使用者號碼,工程師就在位置更新上增加了一條列印,列印相關的上下文資訊。這個版本上線以後,第二天早上,一大批人同時開機,佇列裡同時排隊了很多等待位置更新的訊息,這個列印導致每個處理都變慢了,所以等某個訊息排隊完成以後,這個訊息已經超時了,如此類推,每個訊息都超時……然後那天早上,全省的人開機找不到網路,釀成一次全國級別的責任事故。
這個問題嚴格來說是超時設計的鍋,但當時的責任可是加這行列印的小夥子(當然,處罰的是他的主管)。我舉這個例子,只是想說明,只要你往系統裡面加程式碼,它的影響就是全域性的,不是你開發人員自己的事情。
回到最初的問題,每個模組都輸出,顯然是不合適的,這個問題的評判標準是最終呈現的使用者介面,使用者介面不需要冗餘的輸出。其他效能影響什麼的,你能罩得住,也沒人理你,但你自己還是要弄清楚。
就A、B、C三個模組這個具體情形來說,讓C來報這個錯是個不錯的選擇。因為C才知道真正的錯誤原因,A和B只是以訛傳訛。但讓C去報錯,其實也是有缺點的,首先程式碼量會增加,假如C有好幾處都有記憶體分配,每個都要列印記憶體不足日誌,這就產生程式碼冗餘了。這種情況下,B來列印是更合適的。
那麼正確的日誌輸出原則是什麼呢?原則是:“符合系統設計要求”。對很多人來說,這基本上是告訴他:“沒有原則,具體情況具體分析。”。對不少人,特別是基層管理者來說,就感覺不可接受:“沒有原則,沒有指標,怎麼管理啊?怎麼下要求啊?怎麼考評啊?”——你看,我們又有了一個用“名”來鎖住你自己的“道”的例子了——你到底是要用自己定義的“規則”來證明你“沒錯”呢,還是要做出好的產品呢?(當然,我知道不少基層管理者其實不關心產品好不好,他們更關心自己的考評好不好,關心自己拿好了鞭子沒有。但心小不成大事,求仁得仁,我不是要說服你,我只是討論事情是怎麼做成的)。
這是一個很小的例子,但證明了一件事:不是任何情形都可以抽象的,但不抽象不表示事情就沒有最優解了。沒有簡單的日誌輸出原則,不表示在某個設計中我們不知道如何輸出日誌是最好的。抽象不出3個硬體的共同之處(關鍵在於這個共同之處是否有利於使用),不表示我們不能為這三個硬體各自提供合適的對外介面。沒有一種最優的程式語言,不表示我們不能為每個領域開發新的DSL。“抽象”,是“自然”決定的,是現實本身決定你可以如何“抽象”。不是有了“抽象”, 你就解決問題了。很多人對架構的理解是“抽象”,是“模式”,卻不明白架構師的高明表現在知道“這裡能不能抽象”。
所以,你學做架構的“樣子”,你其實根本就不是在做“架構”這件事。