前一回談到了程式的「可測試性」。想要增加可測試性,可以透過所謂的 SOCK 模型來著手,即 Simplicity (單純性)、Observability(可觀察性)、Control(控制)、 Knowledge of the expected result(對預期結果的知識)。其中,強化單純性的手段之一,就是模組化。

模組化這個主題,在程式設計領域裡,好像很老哏,幾乎每個剛開始學習程式設計的新手,都會被教導程式要模組化的觀念,學習程序式程式設計語言的人會說:「把程式拆解成一個個副程式,就是模組化」,而學習物件導向程式語言的人可能會說:「把程式變成一個個類別,就是模組化」。有的人甚至會說:「好的模組,應該要高聚合(high Cohesion)、低耦合(low coupling)」。

有趣的是,在從事開發工作時,卻常常看到不甚模組化的設計。即使是一個如此基礎的議題,都不見得很普遍地達成。這或許是因為大家都知道模組化是好的,但是很少人著墨在究竟如何做到模組化。模組化也絕非只單靠畫分副程式或類別的這種手段,就唾手可得的。究竟要依循什麼系統性的原則或方法,來做出模組化的設計呢?

模組化的基本概念

所謂的模組化,其實是一種分而治之(divide and conquer)的基本想法,也就是說,人們期待將一個大問題拆解成若干個小問題之後,透過逐一解決這些小問題,來解決整個大問題。而這種解決問題的方法,可以再套用遞迴的方式,透過解決更小的問題,來解決每一個小問題。將問題分解至不能再分解的程度之後,就將該問題實際解決。接著,再將解決的每個小問題的答案,透過合成的程序,組合成大問題的答案,因而解決掉大問題。

理想上,分而治之、遞迴解決問題的想法很好,但是實務上,每個大模組由許多小的模組所構成,小模組又由多個更小的模組所構成,不斷地拆解下去,會使得系統中的模組數量大幅增加,而一旦數量增加到一定程度之後,可以想見的是,額外的負擔和成本就會隨之升高。

為什麼初學程式設計的人都被教導應該要模組化?這是因為,模組化的確可以帶來許多的好處。例如,模組化可以帶來可重複使用性,因為,每個獨立的模組都有機會靈活運用到不同的專案中。模組化也可以帶來可擴充性和相容性。模組化的好處很多,正如前一回中所談到的主題,即使對測試來說,模組化也能提高可測試性。對於時常變動的需求環境,模組化也能降低需求改變或擴充所造成的影響及衝擊。

建構模組時所考量的三大原則

如何建構一個模組呢?

有幾個原則,首先是模組的抽象化。怎麼做抽象化取決於設計方法,對於程序式的設計方法而言,是依循功能即程序的抽象化來進行的,也就是從抽象的角度畫分出所需的種種功能。在設計時,即使還不確定如何實作,也能先決定功能的抽象表述方式。而對物件導向式的設計方法而言,則是依循著物件的觀點來進行抽象化。

其次是資訊隱藏,也就是不讓模組外界碰觸不需碰觸的資訊、不讓它們知道不需知道的事情。

最後則是獨立性,模組本身需要做為一個獨立的單元,本身就能夠執行特定的工作,而且具備簡單的介面和外界溝通,不和其他模組有太多複雜的關聯。從建構模組的原則看來,就能理解為何高聚合力、低耦合力的模組是好的模組了。

設計時,需讓模組具備的特質

我們可以用不同的方法來設計模組,但一般來說,模組化設計方法須滿足幾個特質,包括了:(1)可分解性(Decomposability)(2)可合成性(Composability)(3)可理解性(Understandability)(4)連續性(Continuity)(5)保護性(Protection)。

可分解性是指可以將一個大問題拆解成小問題,並且透過各個小問題的解法來解決大問題,而且在分解之後,可以將這些小問題指派給不同的人獨立去解決,而且這個分解的過程是可以遞迴進行的。我們所謂「由上而下(top-down)」即為如此,從高階的抽象化觀點出發,逐漸具體化到可以實作的程度。

而可合成性指的則是,允許設計者將多個模組依自己的意念,組合在一塊。具可合成性的模組提供了重複使用能力,這使得模組可以應用在當初開發模組時的情境以外的其他情境,而且具備相同介面、機能的模組間,還可以互相的抽換。當我們透過組裝模組來建構軟體時,即為「由下而上(bottom-up)」的方式。

「由上而下」及「由下而上」的這兩種方式,我們時常交錯著運用在我們的設計工作中。由上而下的過程,是從高階的需求拆解出所需的模組,而由下而上則是組合模組完成高階的需求。

可理解性指的是,要能降低理解模組運用情境所需的知識。當一個模組所涉及的其他模組愈少時,那麼它的可理解性就愈高,因為,只需要了解這個模組的特性及行為,就可以了,毋需一個牽連一個,使得運用單一模組時,還得同時了解眾多其餘的模組特性及行為。

連續性指的則是當規格有了小幅度的更動時,受到影響的模組的個數要愈少愈好。

從上述的可理解性和連續性,就能明白:好的模組只做一件事,而不會一堆事攬在身上。因為這麼一來,很有可能會得到不好的可理解性及連續性。

最後,保護性指的是,在某個模組內所發生的執行期錯誤,其影響到的模組應該愈少愈好,最好只影響到其本身。

獲得模組化特性的設計訣竅

那麼,設計上要怎麼做才能得到模組化的特性呢?有五個原則可以參考,首先是「語言模組化單位」,模組需對應至程式語言中的模組單位,例如 Java 中的 class。透過語言支持的對應,我們可以運用語言機制來分解及合成。

第二個原則是「最少介面」,模組間的溝通應該盡可能降低。你可以想像,當模組間的溝通介面愈少時,它們之間的相依性也就愈低,無論是對可理解性或連續性都有幫助。

第三個原則是「最小介面」,也就是模組間若是一定要有溝通,那麼,它們之間溝通的資訊應該要愈少愈好。你可以想像,如果你類別裡的變數都宣告為 public,那麼形同其他模組都可以任意存取這個類別的資訊,那麼也很容易製造出相依關係。

第四個原則是「明確的介面」,如果兩個模組一定要溝通,那麼它們的相依關係應該要很明顯,如果模組間的相依關係很隱晦,那麼當其中一個模組發生變動時,便會很難評估會影響到那些模組。

最後一個原則是「資訊隱藏」,除了必要公開的資訊之外,一律隱藏在模組之內。很明顯地,這項原則有助於提升可理解性及連續性。

就觀念而言,其實大家都明白要盡可能的模組化,可是,模組化應該具備那些特質,以及要怎麼做才能得到模組化,卻不是人人皆知。在本文中,介紹了模組化的五個特質,以及想要得到模組化軟體時應依循的五個原則,希望有助於在實際的開發工作中現實此一目標。

作者簡介


Advertisement

更多 iThome相關內容