:::

軟體構築美學──棕地應用程式開發指導原則讀後感想

6月 17, 2011 , 0 Comments Edit Copy Download

image

Kyle Baley、Donald Belcham 著;蔡煥麟、張簡才祿 譯

  • 出版商:悅知
  • 出版日期:2010-10-20
  • 台幣定價:$650
  • 語言:繁體中文
  • 頁數:528
  • ISBN:9866348784
  • EAN:9789866348785
  • 網路書店連結:天瓏網路書店博客來書籍館

某天我在逛天瓏書局時意外翻到這本書,書中提及了許多我以前就很在意的議題,包括程式開發的環境配置、如何將物件導向設計模式應用到開發中。更重要的是,該書要改善的「棕地應用程式」正是適用我多次開發的真實情境。讀完之後,我發現這本書給我了比預期還要多的啟發,所以我想藉此機會寫一下這本書的讀後感想,也作為整理自己所學的一個記錄。


標題與內容

這本書內文翻譯得很好,但就是「軟體構築美學」這個標題下的太差,很難一眼就搞懂作者到底要講什麼,而且也很容易跟其他書籍混淆。

原文的標題是「Brownfield Application Development in .NET」,直譯就是「棕地應用程式──以.NET語言開發」,但就市場銷售來說,這個讓人無法直覺理解的標題也不太妥當。

先不論標題如何,該書就是環繞在「棕地應用程式」的改善上。作者是以.NET程式語言開發,時常使用Visual Studio IDE來講解,主要是開發安裝在桌面端的應用程式。但是作者是以概念性、原則性的方式說明各種作法的含意,因此很容易讓人將作者的開發技巧轉換到其他的程式語言上。

該書分成兩大部分,Part I說明開發環境,而Part II才是開始寫程式碼。以下我稍微摘要各章的內容,並加入我自己的感想,讓大家對該書有一些基本的認識。


認識棕地應用程式

建築領域所說的棕地(brownfield),指的是一塊年久失修的荒蕪建地,如果將這塊地好好整理一番,則仍可能恢復其利用價值。對軟體開發人員來說,棕地應用程式(brownfield application)指的是一個既有的軟體專案,此專案可能因為用了一些不好的開發方式、結構、或設計而產生許多問題,但若經過仔細的整理和重構(refactoring),還是有機會起死回生。

以上引用自該書的第一章的第一段。簡單來說,接手別人寫好的程式碼繼續改進,通常就是一個棕地應用程式。作者更進一步地說明棕地應用程式的三個基本元素:

  1. 既有程式碼:棕地應用程式中會有大量的、已經寫好的程式碼。但是可能因為有些問題,而現在有一群專屬的團隊在積極地想改善它。
  2. 差勁實務作法所造成的汙染:程式中到處都是看起來不太正常的技術債(technical debt)需要改善,大多都是前人一再拖延而沒有寫好的地方。
  3. 仍有改善或重複使用的潛力:儘管有些問題,但棕地應用程式仍有改善的價值。反之,如果該應用程式已經沒有救了,那麼它會被歸類到「老舊系統」。

我翻到這邊的時候就深深地被這本書吸引住。我認為現在進行開發工作很少是重新開始(該書稱之為綠地應用程式),而是幾乎都是接手別人的程式碼,再來開發自己想要的功能,例如我以開放原始碼系統DSpace為基礎進行開發就是如此。嚴格說來,這並不符合上述的棕地應用程式定義,因為DSpace寫作架構良好,並沒有明顯的污染問題,至多只是應用功能無法達到專案的需求,因此仍需要開發。

大多數時候,公司的工程師要接手其他工程師開發的系統,實驗室的學弟要接手學長的論文系統,而這些以少數人力開發出來的程式,都是屬於典型的棕地應用程式。我們遇到棕地應用程式仍然是比重新開發還來得多,不可忽視棕地應用程式的問題。


Part I 開發環境

Part I 開發環境包括以下五章:

  • 第02章:棕地專案的版本控制
  • 第03章:持續整合
  • 第04章:自動化測試
  • 第05章:軟體度量與程式碼分析
  • 第06章:瑕疵管理

對我來說很意外的是,在我過去的認知中,講到開發環境,要嘛就是指非常針對特定程式語言的IDE、要嘛就是專案開發的方法論,但是該書講的卻是更實在的開發環境──能夠建立信心的開發環境。

程式開發的環境

該書先探討許多棕地專案都會使用的版本控制系統VCS,指出傳統簽出、簽入式VCS與具備合併、分支、標籤功能的VCS應該如何使用。

持續整合則是一臺時常進行自動化編譯與測試的伺服器。它負責告訴專案成員現在在VCS中的程式碼是否可用。而持續整合用在不需要編譯的直譯式程式語言上的時候,我認為可以用自動化測試來取代編譯,這也是Ruby on Rails教我的想法。

自動化測試則是基於敏捷開發的概念,藉由單元測試與整合測試來為應用程式抓出臭蟲並改善。

以上三章提到的都是非常重要的議題,而比起單純的專案管理方法論,這些技巧更是能夠確實地提昇專案開發的穩定度,帶給工程師、專案經理、老闆與客戶們信心。讓程式開發就像是坐著一輛穩定的跑車,能夠讓駕駛安心地開往目的地的感覺。

開發以外的環境

更進一步的,作者導入軟體度量與程式碼分析的概念,講述我們常常聽到的「程式碼涵蓋範圍」、「循環複雜度」、「類別耦合度」等指標要如何用於專案開發。

然後作者在瑕疵管理中敘述如何面對瑕疵,以及「達到零瑕疵」原則對於提昇專案組織文化的價值所在,這讓我對於瑕疵報告系統又有了全新的認知。

作者不僅僅只是對程式開發的環境提出指導,也更關注在進行開發的工程師、專案經理遇到程式碼以外的實務問題。我並沒有太多與他人合作開發的經驗,但仍不難想像實際開發時專案成員對於瑕疵所帶來的恐懼以及會如何應對。

正視開發環境中會遇到的問題,並逐步著手改善。這是我認為該書相當有價值的原因之一。而且光是Part I 開發環境,就佔了這本書的一半。


Part II 程式碼

經過半本書漫長兩百多頁的開發環境,Part II總算要關注應用程式真正要處理的程式碼了。在Part II開發環境中包括以下六章:

  1. 第07章:在專案中導入好的物件導向實務
  2. 第08章:應用程式的重新分層
  3. 第09章:鬆散一些:降低程式碼的依賴性
  4. 第10章:重整使用者介面
  5. 第11章:重構資料存取
  6. 第12章:管理系統外部的依賴

在剩餘的兩百多頁中談論如此多的議題,該書並沒有辦法相當地深入探討,但是他卻比專門探討程式開發(例如設計模式)的書籍更加地實用──由於廣泛地討論各種議題,因此適合作為程式開發的入門、回顧、反省,並且更能將這些開發技巧應用在實務上會遇到的各種問題。

可測試的物件導向設計

一開始,作者像是老生常談一樣地帶我們複習了物件導向,而且是「適合實務的物件導向用法」──是的,因為太多人還是用程序導向在寫物件導向的程式。封裝、繼承、抽象化、多型等物件導向基本概念,你學過,我學過,龍五也學過,不過很多學校課程也只會教到這邊而已。

實務上到底應該怎麼用物件導向呢?作者給我們幾個好的程式應該有的能力指標:

  1. 可維護性:一切好的程式應該有的基礎出發點。
  2. 可讀性:讓程式碼容易讓人閱讀。接手棕地應用程式的工程師,閱讀程式碼的時間通常比動手寫的時間還要多。
  3. 可測試性(Designing for testability):程式能夠進行個別的、自動化的測試。
  4. 擴充性:讓程式碼在需要加入新行為時很容易修改。
  5. 可逆性(reversibility):任何設計決策都能輕易回復。
  6. 調適性(adaptability):確保變動發生時不用大幅度重寫。

就如許多程設教科書會講的一樣,這些能力指標也是相當抽象的概念。作者介紹了各種好的程式的開發原則與作法,其中最實在的概念,大概就是「可測試性」了。儘管Part II廣泛地討論各種程式碼設計原則,但大多都會回到「想辦法讓程式可以被自動化測試」的概念上,我也覺得這是一個相當實際的指標。

以實務問題來應用設計模式

第8章討論應用程式的分層、第9章教讀者如何降低程式碼的依賴性,作者從實務中會遇到的問題著手,引進各種設計模式來解決這些問題。

許多以「設計模式」為主題的程設書籍,例如Head First的深入淺出設計模式,大多是為講解「設計模式」而講解,儘管深入淺出設計模式真的寫得很好,但看完之後還是會覺得不知道何時該應用於哪種實務問題上。

相反地,該書作者以設計模式來解決棕地應用程式會遇到的問題,這讓我對設計模式有了更具體的印象。作者不是很深入地探討設計模式,不同程式語言也會有不同的實作方式,不過這是一個很好的入門、索引。畢竟我們想要學的程設技巧,都是為了解決實務上會遇到的問題,而不是為了使用設計模式才想要去學設計模式。

儘管設計模式的作法沒有深入的探討,但是作者仍有具體的程式碼舉例。作者在降低程式碼的依賴性一章以電影評論的拼字檢查功能來舉例,帶著讀者一步一步將程式拆解,以依賴反轉原則(dependency inversion principle)設計介面(interface)、以依賴注入(dependency injection)降低耦合度,將一個隨處可見的棕地應用程式改成更為良好的程式。

不得不說令我汗顏的是,儘管我以為我自己已經對設計模式、正確的物件導向有所了解,但是在看該章一開始介紹的棕地應用程式時,我真的覺得自己也只會寫出那樣的程式碼,而且不知道其中的問題所在。當作者一一剖析之後,我才有如夢初醒的感覺,同時也深深地反省著自己的功力不足。

使用者介面、資料存取與系統外部依賴的重構

許多程設的教科書只會講到上面的原則性理論,而本書還深入使用者介面、資料存取的設計、以及使用系統外部依賴的議題。

這邊談到的使用者介面並不是介面設計,而是在討論很多工程師都會把商業邏輯(business logic)跟介面寫在一起的問題。這在開發AJAX應用的時候更是讓人苦惱不已,某些邏輯判斷到底要寫在JavaScript,還是寫在後端程式中呢?作者帶我們認識了MVP(Model-View-Presenter)與MVC(Model-View-Controller)設計模式,而在會保留使用者狀態的應用程式中,適合使用MVP,例如桌面端應用程式;傳統的網頁程式則是普遍採用MVC。依此推論,我想以保留使用者狀態為賣點的AJAX應用,應該也可以用MVP的方式來設計也說不定。

在第11章資料存取主要討論DAL(Data Access Layer,也就是MVC中的Model),作者斥責預存程序(store procedure,在資料庫中寫的邏輯判斷程式),建議商業邏輯應該集中,並且大力讚賞ORM(Object-relational mapping)。說真的,我在用過Active Record這種ORM的設計之後,也認為作者的建議實在是中肯到不行。

外部系統依賴的問題中,作者建議以Proxy、Adapter、Facade等設計模式來設計「反腐敗層」(anti-corruption layer)。而如果將目光縮小到專案內部,內部依賴也是可以利用作者介紹的各種設計模式,將內部元件區隔、模組化,以降低內部依賴的程度。

以上三個議題都比前面的原則性指導更貼近實務操作,作者將各種會遇到的問題一一剖析、探討,讓程設從實務需要的技巧更深入到程式的品質。隨著實例看作者是如何改善、為何要如此修改的敘述,讓人獲益良多。


持續改善

該書的最後一章並不談程式,而是回歸到了整體開發環境中的基礎點:要如何持續改善。

該書談論了各種程設的技巧與作法,儘管有其價值所在,但每個看過的人應該都會先在心中打退堂鼓,抱著:「我真的做得到嗎?」「這種作法真的能持續下去嗎?」的疑惑。至少我就是這樣覺得。

在最後一章中,作者點出這個困惑。作者並不是要實務上立刻大轉彎,馬上加入版本控制、持續整合、自動化測試等機制,而是建議讀者緩慢、持續漸進地改善。

我們需要清楚的知道目標,並計劃如何達成目標,而不是「我們想要讓事情變得更好,所以就加入單元測試」,而是要不斷的推動這個專案,讓最後的結果可以盡量貼近我們當初的期望。

然後最後這一章舉了相當多案例,帶讀者回顧整本書的內容要如何應用在實務上。即使是像作者如此老練的高手,還是不斷在專案中碰得一鼻子灰。但是堅持品質、持續改善,儘管專案成果可能很難讓客戶理解這之中的好處,但是團隊的成員素質卻會因此逐步提昇、變得更有自信。

看完持續改善一章之後,我就決定在把這本書還回圖書館之後,自己再去買一本擺入書櫃中。當我要開始開發專案時,或是專案碰到困惑時,我想這本書都可以給我一些實務上的建議。更重要的是,我希望藉由該書在書櫃上的身影,讓我不會忘記對於持續改善的堅持。


優良的翻譯

最近讀了一些歐萊禮的程式書籍,說實在的,歐萊禮的翻譯通常都會讓人覺得奇怪。有些是翻譯的不錯,不過像是這種比較實務性質、又牽扯到各式各樣議題的書本,我通常會有需要腦內自動校正翻譯的覺悟。

但是這本悅知文化出的書中,譯者蔡煥麟跟張簡才祿翻譯得真的很好,我幾乎找不到看起來很奇怪的地方,閱讀起來毫無阻礙。不僅是程設專案的專有名詞翻譯貼切(時常標註英文原名也是相當的貼心),而且作者幽默的笑點也能讓人看了會心一笑。這讓該書中的眾多案例讀起來像是小說般的有趣。

以下節錄一段讓我印象最深刻的敘述,這是持續整合中的假設案例:

現在,假設我們開發流程已經有自動化建置程序,只要有人簽入程式碼,就會自動執行下列動作:
  1. 取得最新版程式碼
  2. 編譯程式碼
  3. 透過電子郵件通知團隊這次的建置結果
所以當傑克森簽入程式碼的時候,我們的自動化建置程序便會啟動,並且立即在第2個步驟(編譯程式碼)出現錯誤。然後團隊成員會收到電子郵件,知道程式碼出了問題了。我們甚至設定讓電子郵件的內文顯示最後一次簽入的人是誰,在這個例子當中就是傑克森。
現在得用上我們的建置失敗規則了。麥可、小劉、阿輝,以及其他團隊成員都停下了手邊的開發工作,也許去喝杯咖啡什麼的。他們多半會閒晃到傑克森的辦公室隔間開點小玩笑,也許送他一個小東西,例如,一隻象徵失敗的橡皮鴨,暗示他就是最近造成一次建置失敗的人。傑克森看見一群人朝他這邊走來,嗅到了嘲弄的味道,才想起自己之前忘記取出新版的程式碼,於是趕緊做了必要的修補。在第一個人踏入他的隔間之前,他就已經迅速修正完畢,並執行了正確的簽入程序。現在,他可以心安理得地等待命運之神的降臨。

感想

在寫論文的時候,我嘗試自己進行開發一個綠地應用程式專案。儘管在開發之前我讀了一些程設的書,學習設計模式與專案管理,但是開發過程中,我還是得承認自己真的禁不住「走捷徑」的誘惑,在程式碼中留下了一堆技術債,而我只能絕望地看著程式碼向下沈淪。現在,他已經是個標準的棕地應用程式,雖然我不知道未來會不會有人繼續想要改善它就是。

反省當初,儘管我在論文中找來了PHP與JavaScript的IDE,但是並沒有建構起良好的開發環境。Dropbox雖然有版本控制,但跟VCS比起來還是有很大的差距。自動化測試只有Model可以測,我到最近才知道,原來JavaScript跟前端UI也有一套自動化測試的方法。更進一步的,應該要搭配程式碼覆蓋率與持續整合的作法,鞏固程式碼的穩定性。

雖然我希望將我的論文系統以開放原始碼的形式發佈,但他真的很不像是外面人家做的開放原始碼專案。下次起頭時,我還是應該好好看看別人是怎麼做的,以開放原始碼專案的形式好好地開始規劃。

最後,看完這本書之後,我有一種想要再執行一個開發專案的衝動。我想實作這本書中介紹的各種方法,只要我熟悉這些方法,我就能夠帶給團隊其他的工程師,提高大家的程設能力。

題外話,雖然該書是以.NET來撰寫,但書中多次提到Ruby on Rails框架在自動化測試上的好處,而我也很想做做看大家認為能夠快速開發的Ruby on Rails,到底會是多麼快速。

還有好多想要做,還有好多想要學的事情呢。


結語

「軟體構築美學」一書,並不是專案管理的書。專案管理是成功專案的一部分,但是專案管理看再多,程設的等級還是很難進步,開發系統依然像是高空走吊橋,令人驚心膽跳。

現實環境中,很多開發環境都會讓人難以確實地提昇程設技巧。實務上的問題會變成以交際手段來搓過,工程師的能力還是很難提昇。我們這邊的開發團隊,儘管老師給了我們很大的自由,但我覺得在程設開發的能力上還是不夠。在我們這樣有自由、有時間的環境都是如此,在外面中小企業中,沒有經驗的程設顧問、老闆也不見得願意提供資源、而其他工程師也不一定想要配合,這些情況都很容易想像的出來。

即使如此,我還是想要進行更好的程式開發,用有效率、穩定的方式開發出高品質的系統。現在的我,並沒有能力帶領大家。不過,我想還是可以先將「軟體構築美學」作為目標,一步一步地踏實前進,想辦法增進自己的實力吧。