{iThome 書評—7} 重構—改善既有程式的設計中譯版

重構:改善既有程式的設計
— Refactoring : improving the design of existing code 重構:改善既有程式的設計 — Refactoring : improving the design of existing code
———————————–
作者/Martin Fowler/等著
譯者/侯捷, 熊節/譯
出版社/碁峰 出版
ISBN/9867594061

內容簡介
當物件技術成為老生常談之後 — 尤其在 Java 編程語言之中,新的問題也在軟體開發社群中浮現了出來。缺乏經驗的開發人員完成了大量粗劣設計,獲得的程式不但缺乏效率,也難以維護和擴展。漸漸地,軟體系統專家發現,與這些沿襲下來的、品質不佳的程式共處,是多麼艱難。物件專家運用許多(而且日漸更多)技術來改善既有程式的結構完善性與性能,已有數年之久。但是這些被稱為「重構」(refactoring)的實踐技術,一直(只)流傳在專家領域內,因為沒有人願意將全部這些知識錄寫為所有開發人員可讀的形式。這種情況如今終於結束。在《Refactoring: Improving the Design of Existing Code》書中,知名的物件技術者 Martin Fowler 闖入新的領域,褪去那些名家實踐手法的神秘面紗,並展示軟體從業人員領悟這種新過程的重大意義。

只要受過適度訓練,一位技巧嫻熟的系統程式員可以在拿到一個糟糕的設計之後,把它翻新為設計良好、穩健強固的程式碼。本書之中,Martin Fowler 告訴你重構機會通常可以在哪裡找到,以及如何將一個糟糕的設計重新修訂為一個良好的設計。每個重構步驟都十分簡 — 簡單到了似乎不值得去做的程度。重構涉及將欄位(field)從一個 class 搬移到另一個class,或將某些程式碼拉出來獨立為另一個函式(method),或甚至將某些程式碼上下移動於繼承體系(hierarchy)之中。這些個別步驟雖然可能十分基本,積累下來的影響卻能夠徹底改善設計。重構已經被證明可以阻止軟體的腐朽與衰敗。

除了討論各式各樣的重構技術,作者還提供了一份詳細名錄(catalog),其中有超過 70個已被證明效果的重構手法,以饒富幫助的重點,教導你實施的時機,實施時的逐步指令。並各自攜帶一個例子,顯示重構的運轉。這些富有良好解說價值的實例都以 Java 寫就,其中的觀念適用於任何物件導向編程語言。

Martin Fowler 是一位獨立諮詢顧問,他運用物件技術解決企業問題已經超過 10 年。他的顧問領域包括健康管理、金融貿易,以及法人財務。他的客戶包括 Chrysler, Citibank,UK National Health Service, Andersen Consulting, Netscape Communications。此外Fowler 也是objects、UML、patterns 技術的一位合格講師。他是《Analysis Patterns》和《UML Distilled》的作者。

Kent Beck 是一位知名的程式員、測試員、重構員、作家、五弦琴專家。

John Brant 和 Don Roberts 是《Refactoring Browser for Smalltalk》的作者,此書可從http://st-www.cs.uiuc.edu/~brant/RefactoringBrowser 獲得。他們兩人也是諮詢顧問,研究重構的實踐與理論有六年之久。

William Opdyke 在伊利諾大學所做的 object-oriented frameworks(物件導向框架)博士研究,導出了重構領域的第一份重要出版品。他目前是 Lucent Technologies/Bell Laboratories 的一名卓越技術人員。

譯者 侯捷,致力計算機技術教育超過 10 年 — 以著作、翻譯、評論、專欄、授課等多重形式。對於各種層級、各種定位、各種技術領域之 Framework Libraries 有濃烈興趣和鑽研。

譯者 熊節,普通程式員,喜編程,樂此而不疲。酷愛讀書,好求新知。記性好忘性大,故凡有所得必記諸文字,有小得,無大成。胸有點墨,心無大志,惟願寧靜淡泊而已。夜闌人靜,一杯清水,幾本閑書,神交於各方名士,獻曝於天下同好,吾願足矣。

前言

本書我覺得可以說是軟體界兩大奇書之一 (另一本就是“Design Patterns”)。設計模式講究的是在程式碼之前 (常所說的系統分析與設計活動)的事先設計,而重構講究的則是程式寫碼後對結構的重整。

我們要先瞭解一件事,軟體設計不可能如建築業一般,只在藍圖上畫好設計圖就能建構出穩固的高樓大廈。軟體開發是要經過不斷地分析、設計、寫碼、測試與修正… 。漸增與反覆,才有可能建構出高品質與強固的系統。事先的設計能保障程式碼相當程度的品質,但不可能完美無瑕,事實上,即使如本書作者 Martin Fowler,也仍須透過程式碼的驗證回饋,再回頭來修整軟體的結構。可以說,運用在紙上藍圖的設計模式與在程式碼的重構本都是設計中的一環,“Top-down (SA/SDPG)”與“Bottom-up (PGSD/SA)”兩者本就不應該在軟體工程是被分開為兩種方法論,而是互補,缺一不可,才有可能建構出軟體設計開發的正回饋環路。

所以重構的對象為程式碼,目的在於對程式碼背後所隱含的結構作重整,提昇對軟體系統的彈性與穩定,同時也相對能讓程式人員容易維護與讓寫碼更有效率。因為設計不可能一開始就是正確,它會隨著設計者的經驗成長而進化;程式碼被閱讀和修改的次數遠多於它被編寫的次數。保持程式碼易讀、易修改的關鍵,就是重構。

本書的作者為 Martin Fowler,不過其實考究起來,“重構 (Refactoring)”一詞是由 Kent-beck在 Smalltalk 專案中率先所提出的概念,並用在實務的顧問輔導。Fowler 是集眾多有經驗的軟體開發先驅們之大成,而把他們所經常用在程式碼重整的技巧整理編寫成重構名錄 (catalog of refactoring),模仿如設計模式一般,對每一個重構給予命名與應用時機等,讓程式人員之間方便利用這些詞彙作為溝通,而成為日常開發實務上的習慣。

瞭解為何重構、為誰重構、何時重構

閱讀全文 »

活用 .NET DataSet 設計觀—實做篇(含程式碼)

Use Case 範例—下採購

Use Case 範例—下採購
圖1、Use Case 範例—下採購

UC 實現(Realizeaiton)—下採購循序圖

圖2、範例–下採購循序圖
(點擊圖片鏈接看原圖)圖2、範例–下採購循序圖

※ 延伸參考:
o 活用 .NET DataSet 設計觀—01
o 活用 .NET DataSet 設計觀—02

部分原始程式碼(C#.NET)

o 所有原始程式碼可在 「HSDc. 檔案區」 下載,執行環境為 .NET Framework 2.0, SQL Express 2005。
o 版面設計問題,線上瀏覽程式碼,請參考:
http://www.hsdc.com.tw/modules/newbb/viewtopic.php?topic_id=307&forum=2&post_id=2395#forumpost2395

活用 .NET DataSet 設計觀 <2>

比較一下 ADO.NET 與 J2EE 的永續機制

  • ADO.NET 的設計理念是將資料庫“搬移”至應用伺服器的記憶體(DataSet),然後就與資料來源離線,讓應用程式就近方便“撈”資料處理。這是屬於“寬鬆耦合 (loose coupling)”的設計方式。
  • J2EE 眾多永續儲存機制,包括 EJB Entity Bean, Hibernate 等,都是“緊緊地”維繫資料庫與應用伺服器內的資料物件 (Data Object)的一致性,將 O-R mapping 的自動化做到“最善”。這是屬於“緊密耦合 (tight coupling)”的設計方式。
  • 兩者的設計方案並不一樣,但也各有各的優缺點,並不容易評斷好壞。無論如何,企業層級的系統設計,不應受限與受制於現有的系統機制,而是應該活用、善用其優點。

DataSet 在中間層的設計策略

目的:設計 虛擬DB(Virtual DB),位於中間層(middle-tier) ,讓 企業物件(business Object) 與 控制物件(control object) 得以方便撈資料處理。

實現方法:設計 ModelVDB 類別(Class),內含兩個屬性(property),一為 DataModel;另一為 DataUtility。兩者均為 DataSet 類別。

  • DataModel 定義與關連資料庫一樣的 Table Schema(可依業務性質定義相關的 Table 即可)。
  • DataUtility 定義關於 使用者資訊、查詢條件參數、資料庫連線資訊等 Table Schema。

設計約束:

  • 把 ModelVDB 視為是 “Value Object”,所以不提供任何方法供物件存取,企業或控制物件是直接透過屬性的存取來取得 位於 VDB 內表格的資料。
  • VDB 要讀取或寫入資料庫系統,是透過控制物件呼叫 “小弟物件(PO, Persistent Object)” 負責與資料庫的溝通。
  • Form 物件不得直接存取 ModelVDB ,必須透過控制物件,以維護資訊的完整性與封裝(encapsulation)。

圖1、ModelVDB 與其它物件的相依性關係
(點擊圖片鏈接看原圖)圖1、ModelVDB 與其它物件的相依性關係

圖2、範例–查詢訂購資訊 by ModelVDB
(點擊圖片鏈接看原圖)圖2、範例–查詢訂購資訊 by ModelVDB

DataSet 在 UI 層的設計策略

目的:設計 表單專用的虛擬DB(Virtual DB),讓 表單物件直接存取其內表格的資料,再透過 控制物件 轉換格式至 ModelVDB,然後寫回至實體資料庫,反之亦然。

優點:表單擁有專屬的虛擬資料庫,設計的表格可以以表單為單位,來儲存表單內的欄位資訊,而不用與實體資料庫的結構相符。UI 與 結構設計團隊可以個別開發,彼此不用互相遷就,未來只要在控制物件執行格式轉換即可。

實現方法:設計 ViewVDB 類別(Class),內含兩個屬性(property),一為 ViewModel;另一為 ViewUtility。兩者均為 DataSet 類別。

  • ViewModel 定義以表單為單位的表格,行(column)與資料型態以表單欄位為主。
  • ViewUtility 定義關於 使用者資訊、查詢條件參數等 Table Schema。

設計約束:表單要寫入實體資料庫時,將 ViewVDB 當參數傳遞給 控制物件,再由其轉換格式為 ModelVDB,再透過 PO 物件寫入實體資料庫。

圖3、ViewVDB 與其它物件的相依性關係
(點擊圖片鏈接看原圖)圖3、ViewVDB 與其它物件的相依性關係

圖4、ViewVDB 與 ModelVDB 的 Transform 循序圖表達
(點擊圖片鏈接看原圖)圖4、ViewVDB 與 ModelVDB 的 Transform 循序圖表達

活用 .NET DataSet 設計觀 <1>

什麼是 .NET DataSet?

  • ADO.NET(.NET Framework 所提供的資料存取技術解決方案) 中最為主要的元件。
  • 它是一種資料容器(container)物件,是屬於記憶體的快取資料(in-memory cache of data)。
  • 它完全獨立於資料來源(如 資料庫系統),是離線的(disconnected)。
  • 它所讀取的資料來源可以是:
    • Database (SQL Server, Oracle …)
    • Object (如 MQ 物件)
    • Web Service
  • 它內部可以包含多個表格(Table)的關連,並且可以同時從多個資料來源讀取資料至所定義的表格,儲存成為一列列(row)的資料。
  • 它內部的格式是以 XML 所定義的,所以可以序列化(serialized)為 XML 字串,以方便當成參數來傳遞。(例如,透過 Web Service 傳至 EJB Session Bean)。

DataSet 與 RDB 的連結關係

圖1、DataSet 與 RDB 的連結關係
(點擊圖片鏈接看原圖)圖1、DataSet 與 RDB 的連結關係

DataSet 內的 Table Schema

圖2、利用 Visual Studio .NET 2005 Solution Explorer 瀏覽 DataSet
(點擊圖片鏈接看原圖)圖2、利用 Visual Studio .NET 2005 Solution Explorer 瀏覽 DataSet

DataSet 的優勢

  • 中間層(middleware)的物件可以將 DataSet 視為是位於記憶體的資料庫(虛擬 DB),方便就近 “撈” 資料來處理。
  • 可攜性極高,隨時可以序列化為 XML,當成參數傳遞至其它如表單或物件來處理。
  • 當 DataSet 內的資料經過處理而變動後,由於需要與資料庫內的資料保持同步、維護一致性,所以需要再透過 Data Adapter 建立連線,寫回資料庫內。同步的過程,交由 ADO.NET 的交易機制來處理,這是屬於永續性(persistent) O-R (Object-Relation) mapping 的系統設計議題。

類別之間的關係(Relationship) — 一般化—特殊化(Generalization-Specialization) (3) — Basic

說明

從生活面的觀點來觀察時,當發現到兩個以上的類別有其相似之處(但又不盡相同),我們可以把相似之處抽象(abstract)放在更高層次的一般性類別。例如,觀察「貓」與「狗」兩個類別,是否有可能抽象化成為一般性的類別? 兩者的品種完全不同,但其實也存在著某種程度的相似性,事實上,若我們要開發一個 “寵物店管理系統”,那麼,其實很自然,就可以將此兩個類別抽象成為「寵物」這個一般化的類別。相對來說,只要是符合「寵物」一般化類別共同特性的其它類別,包括可愛、能取悅、陪伴主人等特徵與行為,就可以成為「寵物」的特殊化類別。一般化—特殊化關係的 UML 表示法如下圖。

 

範例、一般化—特殊化的 UML 表示法
圖1、範例 一般化—特殊化的 UML 表示法

概念上,所有貓、狗的個體(instances)從定義來看也都是「寵物」的個體,那麼就可以將「貓」、「狗」等視為是「寵物」的子型態(sub-type)。由此可以看出,「貓」是一種特別的「寵物」。其中一個重要的觀念在於,所有與「寵物」有關係的特徵(features),包括關連、屬性(attributes)與操作(operations),對「貓」、「狗」、「烏龜」來說也都是成立的。

從軟體的觀點來看,對一般化關係的具體實作就是 “繼承(inheritance)” : 「貓」是「寵物」的子類別(sub-class),在主流的 OOP 語言,包括 Java 與 .NET 等,子類別會繼承超類別(super-class)的所有特性,而且還可以覆寫(override)任何超類別的方法(method)。

一般程式設計人員最容易誤解物件導向的繼承觀念就在於,以為繼承是被用來 “可重用(re-use)”的:可重用既有的程式碼。其實繼承的最重要原則是在於 “可被替代性(substitutability)”,而這正是物件導向另一個非常重要的思維– “多型(polymorphism)”:讓外界(Client)能以「一視同仁」的角度來看待多個特殊化類別所抽象出的一般化類別!

關於 "多型" ,留待在在進階主題內再行詳述。請記得,多型同時也是解決軟體複雜度的一個重要原則。

閱讀全文 »

利用 IBM RSA 實現 CoR 的塑模與產出程式碼

使用環境

  • IBM RSA(Rational Software Architect 6.0) Trial UML 工具
  • JDK 1.5

新增 UML 空白專案

首先開啟 Rational Software Architect(使用版本為 6.0),並切換 workspaces 至 \workspaces\GoFPatterns。

新增名為 CoRProject 的 UML 專案:

  1. 在工作區中,選擇File > New > Project > Other
  2. 選擇 UML Project 並選擇 Next
  3. 輸入 CoRProject 作為專案名稱,並選擇 Next
  4. 選擇範本為 “空白模型(Blank Model)”,檔名輸入為 CoRModel,然後在預設選項中勾選 在新模型中建立預設圖形,預設圖形選擇 開放式圖形(Freeform Diagram),選擇 Finish 完成。
  5. 圖1、新增 UML 空白專案

    (點擊圖片鏈接看原圖)圖1、新增 UML 空白專案

  6. 在 “模型瀏覽器(Model Explorer)” 視圖中,可以看到一個新增的 UML 空白專案。
  7. 圖2、Model Explorer 所顯示的空白 UML 專案

    (點擊圖片鏈接看原圖)圖2、Model Explorer 所顯示的空白 UML 專案

型樣瀏覽器(Pattern Explorer)

  1. 在 Windows Menu 中,選擇 顯示視圖 > Pattern Explorer (若沒有出現,則從 Other… 中選取。
  2. 在 Pattern Explorer 視圖中,展開 Design Patterns > Behavioral。
  3. 選擇 Chain of Responsibility Pattern。
  4. 要瞭解 Design Pattern 的結構圖與說明,在 Pattern Explore 視圖底部的 總覽 與 簡要說明 選項之間切換瀏覽。
  5. 圖3、Pattern Explorer 中所顯示的 CoR Pattern

    (點擊圖片鏈接看原圖)圖3、Pattern Explorer 中所顯示的 CoR Pattern

    閱讀全文 »

軟體思維顧問

專職軟體輔導與教育訓練的獨立顧問。輔導企業資訊單位如何有效組織系統開發與維護;輔導開發人員達成有效的專業分工。傳授如何把軟體作軟 (Keeping Software Soft)的技能,得以提昇系統的彈性/延展,並進而創造系統的再利用價值。

Personal