寫”給人讀的代碼”—軟件模塊
東方瀞
ylxxwx@gmail.com
為什么大多數代碼都那么難懂?如果簡單歸結於代碼設計太差,這樣的解釋太容易了,也太廉價了,但卻沒有任何幫助。
聽說過這么一個小故事,有人在大街上采訪了很多人,“如果你在一條陌生的大街上感到內急,你最希望看到什么?”結果大多數人都說麥當勞或肯德基。這是為什么?難道滿大街只有麥當勞、肯德基里有衛生間?顯然不是,而是大家都知道麥當勞、肯德基里面肯定有衛生間;而且他們的布局都有固定模式,很容易找到衛生間;另外還知道他們不拒絕外人使用衛生間。而對於其他的商戶,有沒有衛生間?衛生間在什么地方?會不會讓外人使用?這些都是未知的。作為普通人,我們對未知的事物都有着天然的恐懼和焦慮。兩相比較,自然對確定的麥當勞、肯德基就特別期待了。
代碼亦如是。我們對別人寫的代碼有抵觸、恐懼的情緒也是人之常情。這是因為別人的代碼對我們來說可能是一個完全未知的事物,也許是我們不了解這個領域的知識,也許是我們不知道軟件設計的思路,或許兩者都有。如果是這樣,那我們也學習麥當勞、肯德基,將我們所有的代碼都設計成相同的布局,是不是我們讀來就容易很多。前些年,我們小組曾經學習過某個大公司的一個產品代碼,大家都認為比較容易理解,雖然其設計不是很精妙。究其原因,就是這個產品的代碼都有着相同的風格、布局。讀懂一個模塊,其他模塊也就容易了。
那什么樣的代碼風格、布局能更讓人理解呢?顯然是和人類認知事物的規律越靠近就越容易。讓我們來看看我們是怎樣認識一個新系統的。當我們面對一個新系統時,一般我們都從三個層面來了解他。1.他和哪些外界系統有交互;2.他是什么,由哪些部分組成;3.他對外界事件是如何響應的。這就是軟件設計中常用的Interface View,Interaction View(也叫Dynamic View),Static View。那相應的我們把一個模塊的代碼分為三個子部分,Data部分對應Static View,Context部分對應Interaction View以及Interface部分對應Interface View。並且分布在各自的文件夾中。如圖一所示。
Interface View,揭示該系統與其他系統的接口關系。在實現中,還可以使用不同文件來區分提供給不同模塊的接口。如圖二所以,DHCP模塊需要分別提供結構給輸入輸出模塊和硬件驅動模快。在圖一對應文件就相應有Itf4Io和Itf4Hwd文件。
Static View,揭示了組成系統的對象,包括概念對象、實體對象和對象間的關系,以及裝載這些對象的容器。在代碼實現時,應該是一個個的class或container。這部分是整個模塊的抽象。為了抽象出更容易理解的代碼,可以參照以下幾個原則:1)對象及對象關系必須真實反映領域知識;2)盡可能減少對象間的依賴;3)如果要引入對象間的依賴,優先考慮是不是放在Context部分更合理。圖三是為DHCP模塊設計的static View。他完全對應於DHCP協議里的概念。
Interaction View(Context View),揭示系統在輸入事件下的響應。這部分的工作應該是1)對象的創建、刪除和事件通知,2)對容器進行移入,移出和查詢操作。這部分代碼應該專注於外界事件觸發下,對象的增、刪、改以及對象在容器間的移動。他只關注對象的變化和交互,不做具體的事情,而且只是提供一個對象相關發生關聯的上下文。
與一般軟件代碼布局相比,這里將Context View的代碼和Static View的代碼稍加分離。為什么要將Context View的代碼和Static View代碼分離開?人類認識新事物是分兩個階段的,第一個階段是概念獲取和辨識,第二個階段是了解系統對外界事件的響應。
軟件設計也是這樣,我們在軟件設計中分Static View和Interaction View。Static View着重描述軟件是什么; Interaction View着重描述軟件對外界事件的反應。另外,Context View代碼與Static View代碼的分離,為減少個對象間的依賴也提供的方便。例如,在上述DHCP系統中,對DHCP請求事件的響應,可以由一個Request Context處理,在這個Context中,創建一個TranX,並把他加入到WaitList中,而不是由TranX自己加入到WaitList中,這樣TranX就不需要知道WaitList的存在。再如,ResAvaiable Context處理底層資源空閑的事件,這個Context,從WaitList中取出一個TranX,放入InProcessList中,並發送SendRequest事件給該TranX。而不是由WaitList或InProcessList來響應這個事件,TranX,WaitList和InProcessList就相互沒有了依賴。
這樣的代碼功能划分,使得代碼的布局更貼近人類認識事物的規律。也使得代碼和設計可以一一對應,提高了代碼的可閱讀性和可維護性。當然軟件設計與其說是一門技術,不如說更像一門藝術,沒有絕對的正確和錯誤。這里提供一種軟件設計思路的探索,願其有益。也歡迎拍磚。