Sunday, January 22, 2006
好方法;壞方法
好方法;壞方法
軟體開發是怎麼一回事?
如果我們想開發一個軟體,到底應該要怎麼做呢?書籍上告訴我們要先去做需求的蒐集,再去分析這些需求,建立軟體的架構,經過高階與細部的設計後,用程式語言去把它實作出來,通過測試之後就可以去部署來使用了。
但是真的每個軟體都這樣子搞的嗎?開發一個小畫家跟開發一套PhotoShop的開發流程在這其中的每個過程中都應該是差異很大的吧。尤其是現在的軟體形形色色,每天在用的作業系統、瀏覽器、MSN、多媒體程式是軟體,你開一個網頁,網頁中的Flash、Javascript是跑在你這個客戶端瀏覽器上的軟體,而你連過去的伺服端也要跑一些伺服器、網站應用程式、資料庫等軟體。不說電腦,你的手機、iPod、電子錶、健保卡裡面都有軟體。這些軟體有大有小,功能也是變化萬千,怎麼樣去開發它們自然也會是不一樣的。
硬體科技進步神速,電腦與行動科技越來越普及化,也因為網路的興起,全球化的現象日益顯著。為了讓這些硬體發揮其最大的效益,軟體的功能需要更多的創新、更強大的功能、能夠帶來更大的商機。在這同時也讓軟體開發的規模越來越大,越來越複雜、也越來越令軟體開發人員頭痛了。
我們有什麼方法能選擇?
軟體開發除了追求其正確性、使用效能、穩定性、安全性之外,還要考慮到軟體開發的速度、重用性、可維護性、整合性、管理性等。
所以我們要進行軟體開發,就必須要有軟體開發的流程。這流程能夠把跟此專案有關的利害關係人(像是專案經理、架構師、設計師、開發人員、管理人員及客戶等等),加上使用相關設備與財物組織起來,以某種形式的組織架構、程序、方法論、技術與管理控制方法,投入於特定領域的軟體生產工作。
說到流程,就會很直覺地想到常常拿出來被人家詬病的瀑布式(waterfall)流程、還有當紅敏捷(agile)陣營的eXtreme Programming(XP)與物件導向大師們所發展出來的Rational Unified Process(RUP)。
瀑布式流程
瀑布式流程並不適用於大多數的軟體開發早已不是新聞,它的存在可能只是為了提供某一個負面名詞來讓人使用。因為軟體界有一句真理名言叫做:「永遠不變的就是一定會變」,現在的世界變化太快了,想當然軟體變化地會更快,畢竟抹平世界的十大推土機裡面每台都是跟資訊科技有關的技術。變化是我們沒有辦法去預測的,所以我們不能用瀑布式這種一去不回的開發流程,而要改用迭代式的開發流程,用短周期進行開發,才能去適應不同的變化。
RUP
RUP是一種流程架構,它主要是用來作為一個與UML相互配合的流程,在這個架構底下你要使用笨重的或是敏捷的流程都可以。它有初始(inception)、詳述(elaboration)、建構(construction)、轉換(transition)四個階段,還有邏輯(logical)、實作(implementation)、程序(process)、配置(deployment)、使用案例(use case)這4+1個觀點。
敏捷開發流程
敏捷型的開發流程有相當多種,其中包括最引人矚目的XP,還有水晶(Crystal)方法系列、適應性軟體開發方法(Adaptive Software Development,ASD)、SCRUM、功用驅動開發方法(Feature Driven Development,FDD)、動態系統開發方法(Dynamic System Development Methods,DSDM)等等。雖然有這麼多種敏捷方法,但它們都共同具有下列的核心價值觀:
- 個人及互動勝於流程與工具
- 可用的軟體勝於詳盡的文件
- 與客戶合作勝於合約談判
- 回應變化勝於墨守計畫
我們可以看出敏捷開發的著重點是擺在適應性與以人為主的理念上的,但我認為要應用敏捷型的開發流程,不僅僅是要知道它與其它流程的異同而已,最基本的原則、樣式、還有它專有的實務都是非常重要,缺一不可。
如何設計?
軟體開發最大的問題就在於一切都是設計過程的一部份,寫程式是一部份,測試與除錯也是,一般大家所說的軟體設計也還是設計的一部份。
現在是物件導向的時代,所以物件導向的基本原則就是軟體設計上的考量要點。有學過物件導向的人都知道,物件導向包含了封裝、繼承、多型、以訊息傳遞等等的要素。但是要如何應用這些要素來將物件導向的特點發揮到淋漓盡致就是要靠這些設計原則【見附錄A:物件導向設計原則】了。
而設計模式(design pattern)也就是運用了這些物件導向設計原則所形成的。但是目前在不同領域的設計模式越來越多,除了四人幫的23個設計模式之外,大型的企業級架構像是J2EE都有自己的一堆設計模式,甚至還有許多反模式(anti-pattern)的出現。
其實運用設計模式也不完全都是優點,引進設計模式到軟體設計中會造成架構的複雜化,反而失去了簡單性的優點,所以說不要強把設計模式加到自己的系統中,最好是讓它們在系統演進的過程中自然顯現出來比較好。
如何極致?
XP是敏捷開發流程中最受到大家所重視的,原因在於推廣XP理念的人物都是當代軟體業舉足輕重的大師級人物,像是Kent Beck、Martin Fowler等等。
XP本身不但提供了一套流程,其主要的價值觀包括了:
- 溝通(communication)
- 回饋(feedback)
- 簡單性(simplicity)
- 勇氣(courage)
搞得好?搞不好?
團隊的大小會影響應該使用的開發流程,每種流程都會有其侷限性,像是XP就明白地表示其適用在十人以下的專案中,如果開發團隊有一百人,完全採用XP是不適合的,必定要去做一些調整。
我認為在應用任何一種開發流程之前,都需要先藉由一些較為小型、容易的專案開始練習,或是先由專家來帶領整個團隊進行開發。沒有經驗的管理者、開發者若只是隨便買本書、看看網站上的說明,沒有經過使用該流程的專業訓練,就照本宣科,感覺上好像真的採用該流程,但是骨子裡可能就不是那麼一回事了。
拿測試驅動式開發方法來說好了,它主要的規定有三:
- 只有在單元測試失敗後,才能寫實際程式。
- 單元測試如果已經寫到讓實際程式不能通過,就不能再寫單元測試。
- 若實際程式已通過單元測試,就不能寫實際程式。
我看過Kent Beck所寫的那本Test-Driven Development By Example,裡面的第一章就是他舉一個實際運用測試驅動式開發方法的範例,雖然說他是遵守了一些看似簡單的規定來進行程式編寫,但老實說一般人如果沒有學習過相關的知識、沒有去習慣此種開發方式,是不太可能會這樣子去寫程式的。
況且許多的實務都是需要相互配合才能算是正確、有效的使用。就像測試驅動開發也必須配合重構的手法才不會讓程式的架構崩潰。是不是每個人都會使用重構呢?要聞出程式碼的壞味道就已經不是很容易了,重構手法林林總總那麼多項,更何況要應用它們來把程式原本不好的架構重構到好的架構。況且重構不太可能手動去進行,一定要搭配一個好的、容易使用的、方便的整合開發環境才有辦法,所以說開發者還必須要熟悉所有他們會使用到的工具。必須要的工具像是單元測試的架構(JUnit)、整合開發環境(Eclipse、JBuilder…)、版本控管軟體(CVS、Subversion)、建構的工具(Ant、Make…)等等,如此高的門檻可能不是一般人能夠輕易跨過的。
所以說XP是非常重視經驗的,另外如果開發人員沒有一種對於軟體開發設計的狂熱,很可能就沒有辦法應用XP,原因在於並非每個人都熱衷於實踐XP的實務。像是有人喜歡搞孤僻、或是喜歡混水摸魚,他就不太可能喜歡搭檔編程。又或是兩個人的程式設計能力相差太大,高手寫的程式另外一個新手看不懂,那麼高手是要跟新手有耐心地講解還是就不理會新手自己寫呢?
UML有幫助嗎?
目前UML已成為軟體設計過程中主要的塑模工具,每個開發流程都會需要使用到它,但這不代表UML是一個很完美的表示方法,軟體系統中的各個元件、行為、還有它們彼此間互動的關係,很難只用幾張圖就表達了一切。現在有一種模型驅動架構(Model-Driven Architecture)的技術,就是想要讓開發者在設計完一些鉅細靡遺的架構圖後,整個系統就差不多出來了。這是一個不錯的理想,不過可行性卻還是讓很多人懷疑。
目前UML的版本已經到了2.0,總計有13種圖。但是基本上沒有什麼人會想要把所有的規格都弄清楚,即使真的有人畫了一張包含了全部細節的圖,也不會有人想要去看。這也是為什麼在所有單純針對UML所寫的書裡面,賣得最好的是Martin Fowler所寫不到兩百頁的UML Distilled,而不是那些厚厚的UML規格書。並不是每個流程都很需要大量的文件,像是XP就不會,所以說如果要使用UML,不一定要使用完整的UML,而是採用需要的部份就好。
結論
沒有什麼方法是絕對好的或是絕對壞的,一切都要針對個別團隊、專案開發的需求去調適。有許多使用XP、RUP這類熱門流程的專案失敗了,但也有使用瀑布式開發而成功的例子。微軟是全世界最大的軟體公司,他們所使用的開發流程是他們自己根據經驗弄出來的MSF(Microsoft Solutions Framework)開發流程,還是需要在一開始根據專案的種類、人員的多寡來進行調適的。
所以我們可以發現這些流程之間都會有一些異同點,沒有任何一種在所有的情形下都是最好的,能讓專案成功的方法就是好方法。
附錄A:物件導向設計原則
應用於類別設計的原則:
- 單一職責原則(Single Responsibility Principle,SRP)
類別變更的原因應僅只有一種。 - 開放封閉原則(Open Closed Principle,OCP)
軟體實體(如類別、模組、函式等等)對於擴充應保持開放性,而對修改應維持封閉性。 - Liskov替代原則(Liskov Substitution Principle,LSP)
子型別必需可替換父型別。 - 相依性反向原則(Dependency Inversion Principle,DIP)
抽象概念不應該相依於細節;而細節應該相依於抽象概念。 - 介面分割原則(Interface Segregation Principle,ISP)
用戶不應被迫相依於他們用不到的函式,介面隸屬於客戶,而非遷就於繼承階層。
應用於套件內聚力的原則:
- 復用改版同等原則(Release Reuse Equivalency Principle,REP)
復用的單元相等於版本的單元。 - 共同封閉原則(Common Closure Principle,CCP)
套件內的所有類別對同類的變更具有相同的封閉性,也就是對套件造成影響的變更會影響套件中的所有類別,然而不會影響其他的套件。 - 共同復用原則(Common Reuse Principle,CRP)
套件內的所有類別總是一起被復用,如果你復用了套件中的某個類別,就等於是復用了所有類別。
應用於套件耦合度的原則:
- 無循環相依原則(Acyclic Dependencies Principle,ADP)
套件的相依關係圖中不存在任何循環路徑。 - 穩定相依原則(Stable Dependencies Principle,SDP)
以穩定取決相依的方向。 - 穩定抽象原則(Stable Abstractions Principle,SAP)
套件應該既抽象又穩定。
附錄B:XP實務
- 整體團隊
XP專案的所有貢獻者,包括開發人員、業務分析師、測試人員等等,都是團隊的成員,一同在開放的空間裡工作,大幅而明顯可見的圖表及其他表示了專案進度的証明,散亂地貼在牆壁上。 - 規劃遊戲
規劃是不斷持續而漸進的工作,以兩週為週期,針對未來兩週內,開發人員預估候選功能的開發成本,而客戶以開發成本與業務價值為考量,從這些需求中挑選出將被實作的功能。 - 客戶測試
除了挑選要實作的功能,客戶也針對每個被挑選出來的功能,定義自動化的驗收來證明這些功能是可運作的。 - 簡單設計
開發團隊維持系統的設計恰恰滿足系統目前所需具備的功能,讓這個設計成果順利通過所有的測試、沒有任何重複、充分表達設計者所展現的所有概念,而且包含的程式碼越少越好。 - 搭檔編程
所有軟體產出皆由兩位程式員共同建構,兩人比肩而坐,共用一部電腦。 - 測試驅動式開發方法
程式員在很短的開發週期中,先加入系統缺失的測試,然後再想辦法讓它能正常運作。 - 設計改良
不要讓系統毀於劣質的程式碼,盡量保持程式碼既簡潔又清晰明確。 - 持續整合
開發團隊隨時對系統做全面性的整合。 - 程式共享
任何的編程搭檔都可在任意時刻著手改善任何的程式碼。 - 編程標準
系統中所有程式碼看起來就像出自同一個優秀的程式員之手。 - 隱喻
團隊勾勒出程式當如何運作的共同願景。 - 持久穩定的步調
團隊是為長久運作的。成員們努力工作,用可持續不斷的步調,以跑馬拉松而非短程衝刺的心態來對待專案,使自己能保存活力。
我的部落格位於 :
http://tw.myblog.yahoo.com/software-management
<< Home