Showing posts with label design. Show all posts
Showing posts with label design. Show all posts

Tuesday, September 25, 2007

The Art of Design

為甚麼好的設計會來自於差的設計呢? ScottWhy Good Design Comes from Bad Design 提到攻讀 CMU Computer Science 博士時選了門介面設計課,第一堂課上他發現一位年輕人素描著隨身聽的各種變異版本,而且圖紙上已經堆積了三、四十種不同考量的版本了。 Scott 於是湊過去問這個小伙子「幹嘛費勁畫那麼多草稿?」,小伙子發楞了好一會才笑著回說:

I don't know what a good idea looks like until I've seen the bad ones.
經過時日洗煉, Scott 後來也體會到當初認為多餘的作法,其背後的精神,他提到:
Each new idea I sketched out was more informed than the last. Each bad idea illustrated some important aspect of the problem that I hadn't thought about before. Out of every five or six ideas, I'd have one or two that might be feasible.
I learned the right way to present ideas–you have to show the other candidates in order to help support the good ones.
When the design student showed me his sketches, he was showing me that he was a designer. All creative, talented people recognize the value of process, and have no concerns about revealing to others that it takes many bad ideas to obtain good ones.
這讓我想到 C++ 的老爸 Bjarne Stroustrup 也曾經提到:
At the start of an ambitious development project, we do not know the best way to structure the system. Often, we don't even know precisely what the system should do because particulars will become clear only through the effort of building, testing, and using the system. How - short of building the complete system - do we get the information necessary to understand what design decisions are significant and to estimate their ramifications?
-- ref. The C++ Programmming Language, p710
這段 William 翻譯如下:
偉大的軟體開發專案開始之初,我們並不知道什麼才是最好的系統組織方式,甚至連應該做出什麼樣的系統都不知道;因為唯有透過打造、測試、使用系統的過程,一切才會明朗。如果尚未打造系統,該如何才能獲得必備資訊以事先瞭解有哪些重要的設計決定?
-- ref. 中譯本, p930
至此,應該不難體會:無論是要創造一個好的設計或成就一項偉大的專案,非常重要的就是要畫出許多「草稿」、進行多項測試及「實驗」。
知道要「作實驗」是個好啟發,卻不夠充分,因為我知道只有能很容易進行實驗的情況下,來談多作實驗才顯得實際。實驗容易進行,人們才有耐性多嚐試,一次又一次、反覆、輕快地測試各個主意,如此,設計才有機會趨於完善。這也是為甚麼大家開發軟體時會找個合用的 framework 來執行 Unit Testing
人們進行設計時,常常將一個大系統拆成一塊一塊,然後一次一小塊,個別考量。每一小塊都琢磨得差不多了,再把它們組一組,最後「啪」一聲,整個系統就完成了 :)
唉,事情要是都那麼順利那就好了。實際上我們會遇到許多困難,例如:怎麼把一團模糊的設計概念拆卸成小塊?每一小塊要如何進行設計,將來才兜得起來?每個小塊怎麼兜成一個整體才會穩固?為了無礙進行實驗、兜出想要的設計,還得想法子讓每個小塊都易於抽換。
一個個小塊,就是我們慣稱的一個個模組,而模組設計的目標就是讓每個模組要
  • 夠獨立,不會互相干擾。
  • 夠彈性,滿足抽換的需求。
例如設計自走車時,我們不將輪子的輪軸跟馬達的傳動軸直接連起來,而是在兩者中間放個聯軸器(a shaft coupling)的裝置,如此抽換馬達或輪子時都可以省許多功夫。
又例如設計電子元件時,要求有高輸入阻抗(Zin),及低輸出阻抗(Zout);前級元件的輸出阻抗(Zout)要遠低於後級元件的輸入阻抗(Zin),兩者最好相差十倍以上(以達成最大電壓傳輸),如此我們可以致力於前後級個別的設計,不用憂心它們訊號彼此干擾。
也許剛好自己較熟這塊,總覺得軟體的模組設計花招更多,以 OO 領域來說,相關準則有:
  • Open-Closed Principle
    • Software entities should be open for extension, but closed for modification
    • Principle of Encapsulation of Variation
  • Liskov Substitution Principle
  • Dependence Inversion Principle
    • Abstractions should not depend upon details. Details should depend upon abstractions.
    • Program to an interface, not an implementation
  • Composit/Aggregate Reuse Principle
  • Law of Demeter -- Least Knowledge Principle
    • Only talk to your immediate friends. Don't talk to strangers
  • Interface Segregation Principle
優秀的程式師總是在思索、尋求「一勞永逸」的作法。學習時不妨從具體案例開始;學成應用時,要改而著重背後的精隨,才不會被細節淹沒。這些年下來,我體會到這個精隨就是「因應變化而設計(Design for Change)」。
要明白 Design for Change ,這裡強烈推薦翻翻 Refactoring 裡提出的壞味。個人認為其中又以下列兩個壞味最為深刻:

Wednesday, March 29, 2006

Embedded System Design

許多 embedded system ,如 MP3 player, mobile phone, PDA,都內含 embedded OS;也有很多小型的 embedded system ,如 USB controller, Nand Flash controller,是不必動用到 OS 的。 embedded OS 提供的 services,最基本的是 multitasking ,其他如 memory management, protocol stack, file system... 也很常見。

對一些小型的應用,把 OS 納入,不但多耗用硬體資源,還可能使系統變得複雜許多。

一個好的思考點是,「在甚麼情況下,把 OS 安置到 embedded system 內才變得必要?」。

看了《Embedded System Design》,得到了一些啟發,面對這個議題,我內心也有更明確的答案。

簡單說,當系統會動用到 multitasking(或 multithreading)時,就是該找個 OS 來用的時候。

但 linux kernel 著名的 hacker, Alan Cox 卻說了這樣的話:

Computers are state machines. Threads are for people who can't program state machines.

看來剛剛的確把話講得太過「簡單」了 :p

~~

Embedded System Design》提到許多用來描述 embedded system 的 computation model :

  • sequential program computation model: 由一組用來計算的程式指令及決定指令順序的敘述構成。C 或 assembly 都是設計來作這類描述的。
  • communication process model: 支援多個 process 並行執行。
  • finite-state machine, FSM: 以一組可能的狀態,描述系統的行為,無論何時,系統只能處於一個狀態;狀態的轉移,取決於現在狀態、輸入值;動作或輸出發生在狀態中或狀態轉移時。現今電腦硬體結構,就是 FSM 加上 ALU, memory 及 I/O 。
  • dataflow model: 將系統的行為描述成一組節點與邊,節點代表轉換,邊則代表資料由一節點流到另一節點。每一節點耗用由其輸入邊所得到的資料、執行轉換、並在其輸出邊上產生資料,所有節點可並行執行。
  • object-oriented model: 將軟體切割成一個個物件,每個物件有自己的責任、行為,物件間可以建立關聯、傳訊息、相互委託,或組合成其他物件。

描述系統,可混合使用幾種 model 。實務上可根據系統特性,以最方便的方式描述、設計系統,必要時再譯成開發環境支援的方式描述。

為了方便描述系統, FSM 也有許多擴充:

  • finite-state machine with Data, FSMD: 為 FSM 增加了可指定型別的資料變數,將變數讀取當成特殊的輸入,變數寫入看成特殊的輸出。
  • hierarchical/concurrent finite-state machine, HCFSM: 狀態可以有子狀態,形成階層;任何時刻,多個狀態可以並存。
  • program state machine, PSM: 容許用循序程式碼來定義一狀態的動作。

值得注意的是,系統也有可能是控制系統。控制系統藉由設定一實體系統的輸入,設法使其輸出追蹤所要的參考輸入,一個有名的例子是汽車定速控制器。如果辨別出所遭遇是控制系統,那要用到的技巧是自動控制領域的 open loop 或 close loop control, PID controller 這些東西。

~~

那到底「怎麼判定是否要把 OS 安置到 embedded system 內?」

一個有用的判斷標準是,當描述系統最方便的方式是 concurrent process model ,可以考慮找個有支援 concurrent processes, pre-emptive multitasking 的 RTOS 來用。

當然,在下這個決定前,請再次複習 Alex Cox 那句名言:「Computers are state machines. Threads are for people who can't program state machines.

對 sequential program computation model 而言, 用 C 就可以了; object-oriented model 可以用 C++;finite-state machine 可以很機械地翻譯成 sequential program computation model;data flow model 在許多場合都可以簡單地用 sequential program computation language 來描述。

另一方面,《Embedded C》及《Patterns for Time-Triggered Embedded Systems》都提到, Embedded System 可以是 even-triggered 或 time-triggered 的。作者 Michael J. Pont 強烈推薦使用 time-triggered 的方式,尤其是在重視安全的應用。因為相較於 even-triggered 的作法,time-triggered 具有簡單、可預期的優點。

Michael J. Pont還提到, co-operatively scheduler 除了比普遍使用的 pre-emptive scheduler 更簡單、可預測、安全、可靠外,在記憶體及 CPU 運算方面也更節省。可以列入 concurrent system 的替代方案。

Tags: [] [] [] [] []