Code Complete II《軟體建構之道 2》#5 讀書心得與整理

第五章 軟體建構中的設計
Design in Construction



5.1 設計中的挑戰
Design Challenges

核心話題「設計是什麼?」

設計是個棘手的問題
Design is a Wicked Problem

設計是沒有固定設計的流程
Design is a Sloppy Process

設計就是確定取捨和調整優先順序
Design is About Trade-Offs and Priorities

設計環繞限制
Design Involves Restrictions

設計是不確定的
Design Is Non-deteministic

設計是啟發學習的過程
Design is a Heuristic Process

設計是演化產生的
Design is Emergent





5.2 關鍵的設計概念
Key Design Concepts

核心話題「設計+軟體 又是什麼?」

軟體的首要技術使命:管理複雜性
Software’s Primary Technical Imperative: Managing Complexity

(源自《人月神話-Brooks》的《沒有銀彈》)

我的見解:
管理複雜性,可以看做「管理」+「複雜性」
「複雜性」是軟體的本質性,這是無法改變也沒有一個殺手級工具可以解決問題。
所以目前可以做的就是做好「管理」這件事。

附屬性問題和本質性問題 What?
Accidental and Essential Difficulties

管理複雜性的重要 Why?
Importance of Managing Complexity

如何對付複雜性 How?
How to Attack Complexity

理想的設計特性
Desirable Characteristics of a Design

也就是要邁向的方向(這樣做很好,但是不見得非得要這樣做不可。)

設計的層次
Levels of Design

(模組化設計的解析,看設計書《萬物》)
軟體系統的的五個層次:
  1. 軟體系統
  2. 子系統或封裝
  3. 類別
  4. 常式
  5. 常式內部
限制子系統間的通訊(呼叫、包含、繼承),簡單易懂、易維護

在這個章節,最常見的一句話就是「這樣做,是好的,但是怎麼做,沒有對錯」在設計的角度來看,一直都是這樣沒錯!軟體是想法的產物,所以「概念整體性」完全支配了整個設計,第五章強調的是Brooks說過的概念整體性,在第六章繼承了這樣的想法,將它應用在建立類別上,而第六章討論時會遇到一些「哲學上的問題」在本書也有詳盡的討論。

5.3 設計積木:啓發學習法
Design Building Blocks: Heuristics

核心話題「什麼是『設計的過程』」

找尋真實世界中的物件    Who?
Find Real-World Objects

用程式語言訴說著什麼樣的角色?

制訂一致的抽象(概念)
Form Consistent Abstractions

這些被描述的程式行為,有沒有歸納過?
共同的抽象特徵建立成Base Class
介面本身為概念表達核心,不代表函數內部的細節。

我的見解:
使用類別將專注於介面本身,函數內部是類別設計師的創意
(Design is not how it looksDesign is not just what it looks like and feels like. Design is how it works)
(使用類別的使用者-軟體工程師...管它怎麼做的,好用就對了)

封裝執行細節
Encapsulate Implementation Details
(6.2節)

當繼承能簡化設計就用繼承
Inherit When Inheritance Simplifies the Design
(6.3節)
善用虛擬函數+動態連結的強大力量,除此之外,還是看看6.3節

隱藏秘密(資訊隱藏)
Hide Secrets (Information Hiding)

秘密和隱私權(class的作用)
Secrets and the Right to Privacy

  1. 某個可能變更的區域
  2. 某種檔案格式
  3. 資料型別的執行方式
  4. 某個需要隔離的區域
資訊隱藏的例子
An Example of Information Hiding


第一版 
int main()
{
    int id;
    id = ++g_maxId; //告訴別人,我是怎麼做的,容易找到破解方法或預測方式
    return 0;
}
第二版
int NewId(){  return ++g_maxId; }


int main()
{
    int id;        //告訴別人,可以對ID做四則運算。
    id = NewId();

    return 0;
}
第三版
typedef IdType int;

IdType NewId()
{
  return ++g_maxId;
}

int main()
{
    IdType id;
    id = NewId();

    return 0;
}
需要被隱藏的兩種秘密
Two Categories of Secrets

資訊要被隱藏起來「秘密」主要分為兩類:
  1. 隱藏複雜性
  2. 隱藏變更資料來源

資訊隱藏的障礙Barriers to Information Hiding

資訊過度分散
循環相依性
類別資料誤認為全域資料
  • 全域資料帶來難題(用在哪個函數?用了嗎?誰用過?)
  • 類別資料降低風險 
可察覺的效能減損
「架構層次」、「程式碼層次」的效能減損,做好資訊隱藏就可以避免掉這兩點。
時間過早擔心:「物件具現化」和「常式呼叫」等有隔外的層次,間接存取物件將導致執行階段的效能惡化。(想太多了,想要在維護程式痛苦?還是執行執式痛苦?)

資訊隱藏的價值    Why?
Value of Information Hiding

  1. 看見多少細節,就要考慮多少細節
  2. 有可能用到的Code較多
我的見解:
盡可能的減少看見的細節,保持程式順利執行。←花時間
減少辨別Code是否有用到的思緒。←花時間
減少花時間在不必要的地方,以達到管理複雜度的目標


確定在哪些領域可能改變
Identify Areas Likely to Change

Design Pattern的精神

預測不同程度的變化
Anticipating Different Degrees of Change
步驟:
  1. 分離  包成類別
  2. 隔離  設計介面

保持鬆散的耦合
Keep Coupling Loose


耦合的準則
Coupling Criteria

  • 規模
  • 可視性
  • 彈性
//耦合的彈性準則
    LookupVacationBenefit ( Employee  _E );
        //otherClass   就不可以丟進去當參數了。

    LookupVacationBenefit ( date _D, level _L );
        Employee.GetDate();
        Employee.GetLevel();
        otherClass.GetDate();
        otherClass.GetLevel();  //兩個類別都可以丟進去執行了。
耦合的種類
Kinds of Coupling

  • 簡單參數藕合:參數是基本型別
  • 簡單物件藕合:類別裡面宣告物
  • 物件參數藕合:物件3當作參數,從物件2傳給物件1(須要先知的藕合)
  • 語意的藕合:(沒有邏輯,complier看不出來的藕合)(詳見內文繁中版p.104)

尋找常用的設計模式
Look for Common Design Patterns

設計模式有一個潛在的陷阱,就是強迫程式碼使用模式。
不要使用「硬要用」的態度,使用設計模式。

其他啟發學習法
Other Heuristics

  • 追求高內聚力
    Aim for Strong Cohesion
  • 建置層次結構
    Build Hierarchies
  • 嚴格描述類別契約
    Formalize Class Contracts
  • 責任劃分
    Assign Responsibilities
  • 為測試而設計
    Design for Test
  • 避免失誤
    Avoid Failure
  • 有意識地選擇綁定時間
    Choose Binding Time Consciously
  • 集中控制
    Make Central Points of Control
  • 考慮使用暴力法
    Consider Using Brute Force
  • 繪製圖表
    Draw a Diagram
  • 保持你的設計模組化
    Keep Your Design Modula
繫結時間:將特定的值繫結至某變數的時間。

使用啟發學習法的方針
Summary of Design Heuristics

設計啟發法最有效的方針之一:不要執著於單一的方法上。

我的見解:
也許,在工業設計上,就是指「設計方法」這件事吧?!沒有一個方法吃遍天下,但是遇見什麼問題,使用什麼方法似乎是好用的方法,卻不是唯一能用的方法。

使用啟發學習法的原則
Guidelines for Using Heuristics

  1. 了解問題
  2. 設計一個計劃
  3. 執行計畫
  4. 檢查


5.4 設計的實踐
Design Practices

之前講「設計特性」的啓發學習法
現在講「設計實踐」的啓發學習法

重覆(疊迭)
 iterator

iterator : 承前經驗地重覆。

分而治之
Divide and Conquer

沒有人的頭腦能裝下一個複程式的全部細節
《如何解題》-Polya,在解決數學問題中的建議

  1. 理解問題
  2. 設計計畫
  3. 執行計畫
  4. 回顧你的方法

「由上而下」和「由下而上」的設計方法
Top-Down and Bottom-Up Design Approaches

Top-Down & Botton-Up
可以同時存在,而且是人類本能似的運作。
Top-Down : 找零件。
Botton-Up : 組積木。

實驗原型
Experimental Prototyping

寫出用於問答特定設計問題、量最少且能隨時捨棄的程式碼。
(這時就可以不用考慮維護的問題,God Object的問題、架構的問題,而程式也不應該大到這種程度。除非是架構的Prototype)

協同設計
Collaborative Design

找伙伴交流
  • 聊天(隨便找人問想法)
  • 討論(認真找人問想法)
  • Code review(進行雙人設計)
  • 客觀角色(讓不懂的人略懂)
  • 依第21章的結構安排一次正式視察
  • 自己當自己的伙伴(自己忘掉再來看)
  • 社群

什麼樣的設計才算足夠?
How Much Design is Enough?

最大的設計錯誤,源自於「誤以為自己已做得很足夠」
沒有什麼設計上的困難,是因為做了太多的設計。

80% 寫程式
20% 寫文件

記錄你的設計工作
Capturing Your Design Work

(各種寫文件的方法!來寫網誌吧!)

5.5 對流行的方法評論

「應用設計方法時,你的方法愈教條化,能解決的現實問題就越少」- Plaugerd
「設計所有的細節」和「完全不設計」的這兩種
看法極端的人所提倡的這兩種方法,,是唯一兩個永遠是錯的方法!

更多資源
Additional Resources

軟體設計的一般問題
Software Design, General

軟體設計理論
Software Design Theory

設計模式
Design Patterns

廣義的設計
Design in General

標準
Standards


我的見解:
也許現代工業可以給我們一些方向。
「Less is more」 - Ludwig Mies van der Rohe
「Form follows function」 - Horatio Greenough
「Good design is...」十誡 - Dieter Rams
  1. 好的設計是創新的 (Good design is innovative)
  2. 好的設計是實用的 (Good design makes a product useful)
  3. 好的設計是唯美的 (Good design is aesthetic)
  4. 好的設計讓產品說話 (Good design helps a product to be understood)
  5. 好的設計是謙虛的 (Good design is unobtrusive)
  6. 好的設計是誠實的 (Good design is honest)
  7. 好的設計堅固耐用 (Good design is durable)
  8. 好的設計是細緻的 (Good design is thorough to the last detail)
  9. 好的設計是環保的 (Good design is concerned with the environment)
  10. 好的設計是極簡的 (Good design is as little design as possible)

沒有留言:

張貼留言

(什麼是留言欄訊息?)