當我們手中已有了不同的架構圖時,下一步該如何進行?也許你已經發現了一些你最初沒有考慮到的代碼模塊,也可能你已經更清楚地理解了模塊之間的交互方式。在深入探討這些交互(即介面)之前,有一件事情值得你花點時間來思考:什麼會改變?
在設計初期,一切都是實驗性的,因此可以預期系統中的任何部分都有可能發生變化。然而,我們的目標是使初步的架構和代碼對系統特性或硬體的變更更具抵抗力。例如,你可能知道產品的某些功能不太可能改變,但具體實現方式可能會有所變化。就像你的產品也許需要一個顯示屏,且傳輸位圖的最佳方式是通過閃存。雖然 SPI 介面的閃存晶片看起來是個不錯的選擇,但具體用哪一款閃存晶片、哪種 LCD、圖像數據或字型數據都可能變動。因此,圖中的每個模塊應該代表其理想的抽象概念,而不是具體的實現。
在設計圖表時,我們要尋找不依賴於具體模塊內容或行為的介面,這就是封裝(Encapsulation)。通過架構圖表,我們可以找出設計中適合這些介面的地方。每個模塊可能都有其自己的介面,有時這些介面可以合併成一個對象。但是是否應該立刻進行合併,還是等待以後再做?
有時提前合併是值得的。當你可以簡化圖表的複雜性,而不過度犧牲未來的靈活性時,就應該考慮這樣做。例如:
舉例來說,如果一個 LCD 顯示模塊僅依賴於平行介面,並且沒有其他子系統需要訪問該介面,那麼這個介面就可以被封裝在 LCD 模塊內部。這樣,你可以隱藏不必要的實現細節,保持架構的簡潔性。
這些圖表不僅幫助你理解系統架構,還能協助你分配工作給團隊成員。例如,哪些部分可以作為獨立的模塊由其他人來實現?而哪些部分應該由你自己負責?
過於傾向於將乏味的部分工作分給他人可能會降低產品質量。相反,你應該思考哪些整體模塊或子樹可以交給他人完成。在描述模塊間的相依關係時,你可能會發現這些依賴比你最初想像的更為複雜,或許一個簡單的旗標(如信號燈)就能幫助你解決誰擁有資源的問題。
通過清晰的介面(interface)來分離不同的代碼區塊,能夠使你的專案進展更加順利。當團隊成員各自負責自己代碼的開發和測試時,整個專案的效率會顯著提升。
在考慮模塊介面時,從底層開始也是一個有效的方法。底層模塊通常是與硬體打交道的驅動程序。在嵌入式系統中,許多驅動程序基於類 Unix 系統的 POSIX API,因為這種模型在很多情況下運作良好,並且可以避免每次需要訪問硬體時都重新設計驅動程序。
Unix 驅動程序的介面設計相對簡單:
這些標準介面可以讓你的設計更具可維護性和可重用性。如果你的驅動可以遵循這些標準接口,那麼對其他開發者來說,看到這些功能時他們就能快速知道該期待什麼。
總之,設計一個靈活、可擴展的嵌入式系統架構,需要你考慮到系統可能的變更,並運用封裝來保護系統免受未來變更的影響。通過合理劃分工作、清晰劃定模塊介面,以及遵循通用的驅動接口設計原則,你可以構建出一個穩定且可維護的系統。