設計掛了嗎?(設計已死? Is Design Dead?)譯文

轉載請附帶連接,註明出處 http://www.cnblogs.com/Zetazzz/archive/2011/01/06/1926990.html

 

譯註:重新翻譯這篇文章是因爲目前搜索引擎的結果中沒有一個理想的普通話譯本,故盡我所能,將這一方面補完。裏面爲了讓語義平實,並且儘量符合原文詼諧的感覺,也有一些北京或者不知道是哪裏的方言(即興而爲),但是大體上是普通話,希望這些小小的即興發揮不會影響到大家的閱讀。

原文:http://martinfowler.com/articles/designDead.html

 

         對於很多初步接觸極限編程(Extreme Programming, XP)的同學來說,XP似乎宣告了程序設計的死亡。不僅限於很多設計行爲被嘲笑爲“冗餘的前期設計”(Big Up Front Design),而且連像UML,靈活的框架(Framework),甚至連模式(patterns)這些設計技巧都被輕視乃至被完全忽視。實際上,XP中包括很多的設計,只是不同於以往軟件開發流程中的做法。XP通過允許進化的實踐技巧使演進式設計(evolutionary design)成爲一種可行的設計策略。它還爲設計人員(Designers)提供了新的挑戰與技巧,令他們去學習如何使設計簡單,如何利用重構保持設計的整潔,如何在一個演進的形式下使用模式。

 

——————很帥的分割線——————

 

        作者:Martin Fowler

 

        2004年5月發表

 

        這篇文章是我爲XP2000大會上的基調性發言所準備的,這文章的原始版本已經作爲大會的一部分發表。

 

——————很帥的分割線——————

 

         XP對很多軟件開發方面的所謂常識(common assumptions)都提出了挑戰。其中爭議最大的就是它拒絕在前期設計階段投入主要的精力,並且更傾向於一種演進式的方針。對於XP的批評者來說,這分明就是退回了“編了改”(code and fix)時代——經常諷刺爲堆爛代碼。對於XP的粉絲來說,這就成爲了拒絕一切設計技巧(像UML),原則,還有模式的宣言:前期設計個毛啊,如果你跟着你的編碼感覺走,一個好的設計就出來啦。

 

         我發現我正處在這些爭論的中心。我職業生涯中的大部分時光都在與圖形設計語言(像統一建模語言 UML,我是它的先行者)和模式打交道。而且我確實還寫過UML和模式的書。那麼,我投向的XP革命的懷抱意味着我放棄了我所寫的那些題材麼?意味着我已經從我的頭腦中洗去了之前的那些“反革命(counter-revolutionary )”論調麼?

 

         嗯……我不是個喜歡賣關子的人,給大家一個簡短的答案:No。長的呢,請聽我慢慢講來。

 

規劃式(Planed design)和演進式設計(Evolutionary design)

 

         我將在這裏描述兩種軟件開發中的設計流程。估計其中比較常見的就是演進式設計(Evolutionary design)。首先,演進式設計意味着系統的設計隨着系統的實施而進行。設計就是開發過程的一部分,並且程序變了,設計也隨之改變。

 

         一般的使用中,演進式設計意味着一場災難。設計以一堆即興的決定(ad hoc decisions)而組成,每一個決定都使我們的程序越來越難以應對變化。你或許會從多個方面來說這根本就是沒有設計,不過一般來說它確實是由一個貧乏的設計導致的。就像Kent說的那樣,設計是用來幫助你在很長的一段時間裏更容易應對軟件的各種修改。而一個貧乏的設計帶給我們的是,你難以有效的應對各種變化。隨着時間的推移,設計越來越難以滿足要求。這不單導致了軟件更加難於應對變化,還使得Bug更容易產生,更難以被找到和安全的解決。這就是“編了改”(Code and fix)噩夢:蟲蟲(Bug)們的生長導致了隨着項目的推進,修改它們的成本將會呈指數級增長。

 

         規劃式設計(Planed design)則相反,它包含從其他各種工程角度得來的一些主張。如果你想造個狗屋,你只需要找點木材然後心裏有個大概印象就可以了。那麼如果你想蓋個摩天大樓的話,你肯定不能用同樣的方法,否則你還沒蓋到一半的時候它就塌了。所以你開始畫工程圖,在就像我老婆位於波士頓市中心的單位那樣的工程辦事處中把它搞定。隨着她完成設計,她就解決了所有的問題,一些用數學分析的方法,更多的使用建築法則。建築法則是一堆以往建築方面的有效經驗積累出來的規則(有些是基於數學的)。當設計搞定了之後,她所在的工程公司可以將設計交付至令一家公司去搞實施。

 

         規劃式設計也遵循同樣的方式。設計人員事先考慮那些重大問題。因爲他們不做軟件的實施,所以他們不寫代碼,他們只做設計。所以他們可以用設計工具,比如UML,幫助他們擺脫編碼細節而更多的關注抽象層面。當搞定了設計,他們可以把它交付給另一個獨立的小組(甚至另一家公司)去實施。因爲設計人員們從很高的層面去思考,所以可以避免一系列局部決定導致的混亂局面。程序員可以遵從設計指引的大方向去實現一個良好實施的系統。

 

         從70年代開始,規劃式設計方針已經普遍運用,而且很多人都接觸過。比起通常以“編了改”形式進行的演進式設計,它體現了很多方面的優勢。但是其中存在着一些錯誤。首先就是你不可能對開發階段即將遇到的所有問題進行預判,從而不可避免的在開發的時候就會發現一些對設計產生的質疑。那麼如果設計人員搞定了設計之後就去了別的項目組,怎麼辦?開發人員開始遷就設計進行編碼,混亂如此產生。即使設計人員沒有閃人,仍然需要時間去理清設計問題,改變設計圖,然後再修改編碼。時間的壓力和一些不按規矩辦事圖省事的同學還是會導致混亂的產生。

 

         此外設計人員和編碼人員兩者常常有些“文化”問題。設計人員之所以成爲設計人員是因爲他們技能優秀而且經驗豐富,但是他們花了那麼多時間去搞設計從而就沒有時間再搞編碼了。軟件開發業使用的技術和工具高速變化,如果你不再編碼那麼你失去的不僅僅是這些技術最新的變更,還有實際從事編碼人員對你的尊重。

 

         在建築領域,也有實施者和設計者之間的這種矛盾,但是在軟件業,這種矛盾體現的更爲激烈。因爲,建築業和軟件業有一個關鍵的區別。建築業中,設計人員和實施人員的技能領域界限很明確。但是軟件業中則不是。在高度設計的環境中工作的開發人員需要很優秀的技能,優秀到足以質疑設計人員的設計,特別是設計人員一天不如一天知道開發平臺的具體細節的情況下。

 

         即便我們說這些都可以被解決。我們或許可以搞定設計與開發之間的情緒問題,我們或許可以找一堆各方面都很優秀的設計人員,並且組建一個嚴格遵守流程的團隊在改變代碼的同時改變設計圖。問題仍然存在:需求變更。需求變更是我在軟件項目中遇到的第一大頭疼問題。

 

         解決需求變更的其中的一個方法是在設計中加入靈活性,從而當需求變更時你可以很快的改好。Ok,這是在你的設計預期中發生了需求變更的情況。設計的確可以應對一定範圍的變化,但是也只能覆蓋可以預判的變化範圍,然而對於不可預判的變化則難以覆蓋(甚至會起反效果)。那麼你必須非常充分的理解需求去預判所有的可變因素,個人認爲這真的非常難。

        

         那麼我們來說就算其中有些需求問題可以歸咎於沒充分理解需求,所以有些人專注於需求分析過程,希望通過獲取理解的更充分的需求來避免以後對於設計的衝擊。但是即使這樣也不一定是解決問題的方法。很多未預期的需求變更來自於業務本身的變化。所以根本沒法避免,無論你多麼注意你的需求分析流程。

 

         那麼規劃式設計似乎是不可能的。它的確面臨着巨大的挑戰。但是我不傾向於說規劃式設計次於通常以編了改方式進行的演進式設計。比起編了改,我確實更支持規劃式設計。我只是發現了規劃式設計所面臨的問題,並且在尋求一個新的方向。

 

XP使撫平曲線可行的措施 

 

         XP因爲諸多原因受爭議,但是這些爭議中的其中之一便是XP是提倡演進式設計而不是規劃式設計。如我們所知,演進式設計因爲其諸多的即興設計決定(ad hoc design decisions)與伴隨而生的混亂局面,從而難以被採納。

 

         這個爭議的核心問題與軟件變化曲線相關。變化曲線表現爲:隨着項目的進行,爲單一變化所付出的代價承指數增長。這個曲線通常簡短的用一句話代表“系統分析時花一塊錢可以做出的改變,在投入實施後則需要1000倍的代價”。這句話印證了很多項目僅有一些即興的流程而缺乏設計環節導致的問題,但是這種指數式增長的趨勢卻函待我們解決。這種承指數趨勢增長的曲線意味着演進式設計不可行。同時也表達了規劃式設計一定要小心的進行,因爲任何錯誤都有可能導致同樣的指數上升曲線降臨在規劃式設計的身上。

 

         XP的基礎假設是它可以將變化曲線撫平以支持演進式設計的開展。XP使撫平曲線成爲可能,同時也利用了這條平整的曲線。這是XP實踐做法的耦合中的一部分:特別是你如果不採取撫平曲線的措施便無法對平整的曲線加以利用。這也是XP所產生爭議的來源。很多人不懂得XP如何將曲線撫平便批評XP利用變化曲線的做法。通常這種非難來自批評者自身的經歷,他們沒有采取撫平曲線的做法便開始利用變化曲線。結果他們被搞得焦頭爛額,此後再看到XP,他們就跟看見火一樣。

 

         使撫平曲線可行的措施包含很多部分。其中核心的包括:測試措施,持續集成。離開測試所帶來的安全性,那麼XP的其他措施幾乎無法實現。持續集成使團隊保持同步,所以你可以進行更改而且不用擔心與其他成員整合所導致的問題。這兩種措施結合對於變化曲線所帶來的影響是巨大的。在ThoughtWorks工作的這段時間再一次給予我這方面的印證。你需要實現所有的這類措施以完全終結你對XP的質疑。

 

         重構也有同樣的效果。嚴格按照XP建議的那樣重構他們代碼的人會發現他們比那些鬆散隨意的所謂重構代碼的人在效果上有重大的區別。這正是當Kent告訴我如何確實的重構時我所經歷到的。最後,這個巨大的變化驅使我寫了關於它的整整一本書。

 

         Jim Highsmith,在他出色的XP概要中,用了一系列參照物進行類比。其中之一是規劃式設計,另一個是重構。傳統的項目實施方針中規劃式設計起主導作用是因爲我們假設我們不能在稍後改變我們的主意。然而當變化的成本降低後,我們可以將更多的設計當做重構推後再做。我們沒有完全拋棄規劃式設計,但是我們找到了兩種設計方針的平衡。對於我來說,當我應用重構之前,我就好像只用了一隻手來做設計。

 

         這些使撫平曲線可行的措施包括持續集成,測試,重構提供了使演進式設計可行的新環境。那麼還有一件事我們沒有搞清楚,那就是平衡點在哪裏。我確信,儘管外觀如此,但是XP絕不僅是測試,編碼,然後重構。在開發前我們仍然爲設計留有空間。一些發生在整體編碼以前,更多的時候發生在某個迭代週期即將爲某個特定任務開始編碼之前。但是前期設計與重構之間是有一個新的平衡點的。

 

簡單性的價值 

 

         兩條XP最偉大的口號就是“做可能有效的最簡單的東西”和“你不會需要他”(簡稱YAGNI)。兩條都宣告着XP的簡單設計實踐原則。

 

         YAGNI通常被解釋爲:你不應該在今天爲一個只會明天才會需要的功能添加任何代碼。表面來看它很簡單。問題就來源於那堆架構,可重用組件,靈活的設計。這些東西很難建立。你用了額外的前期代價去建立它們,並且寄希望於在後期收回前期的成本。這種在前期構建靈活性的做法被看做有效的軟件設計的關鍵。

 

         儘管如此,XP建議你不要爲第一個需要這個功能的情況建立一個靈活性的組件,而是讓這些結構在必要的時候自己成長。如果我今天需要建立一個Money類,它只需要處理加法操作而不是乘法操作,那麼我就只添加加法操作進入這個類。儘管我確定我在下一個迭代週期需要乘法,也明白它多容易實現,並且覺得它能很快的被加上,我還是會把它放在下一個迭代週期中。

 

         這其中的一個原因是經濟考慮。如果我必須考慮下一個迭代週期纔會用到的功能,那麼意味着我不能全力完成這個週期的功能。發佈計劃表明這個功能需要在這個週期完成,那麼在這期間去做未來才應該完成的事情就是違背開發人員與客戶達成的共識。這可能對這個週期的任務準時交付造成風險。就算這個迭代週期不存在風險,那也是客戶來決定什麼樣額外的工作應該被完成——仍然也不一定包含乘法功能。

 

         這種經濟負面影響是伴隨我們預判錯誤而來的。儘管我們很確定這個功能是怎麼運作的,但是我們還是有可能搞錯。特別是當我們還沒有搞懂詳細的需求的時候。提早完成錯誤的工作比起提早完成正確的工作來說是一種更大的浪費。同時,極限編程專家(XPerts)通常認爲我們搞錯的時候比對的時候多。(我同意這個觀點)

 

         採用簡單設計的第二個原因是複雜的設計比簡單的設計難以理解。所以說添加複雜因素使任何對於系統的修改變得困難起來。這增加了我們往系統中添加複雜設計的時點與我們真正需要他們的時點之間的成本。

 

         如今這些建議給很多人以一種胡說八道的印象,而他們這麼想是對的,想象一下還沒有XP措施並且軟件變化成本曲線上揚的傳統開發方式吧。無論如何,當規劃式設計和演進式設計之間的平衡被打破時,YAGNI成爲了最好的實踐措施(沒有之一)。

 

         綜上所述,你不需要去爲一個以後纔會需要的功能花費精力。就算它的成本是零,你仍然不需要添加它,因爲儘管他的添加成本是零,但是它增加了我們修改的成本。不管怎麼說,當你使用XP或者其他一些可以降低變化成本的措施時,你應該靈活的按此約束自己。

 

這地球兒上啥纔是簡單的呢? 

 

         那麼我們希望我們的代碼儘可能的簡單。這好像是不用爭辯的,畢竟有誰希望把事情搞得很複雜呢?但是我們需要一個問題的解答:什麼纔是簡單?

 

         在XPE中,Kent給出了關於一個簡單系統的四個標準。排序如下(重要在前):

 

      n  運行過所有測試

      n  表達所有意圖(Reveals all the intention)

      n  無任何重複(No duplication)

      n  最少的類和方法

 

         運行過所有的測試是一個挺簡單的標準。無任何重複這條也挺直觀的,儘管很多程序員需要一些指導才能做到。表達所有意圖這條最討巧,它到底意味着什麼?

 

         這條最基本的價值體現在代碼的聲明上。XP傾注了很大的價值放在代碼的可讀性上。在XP中“耍小聰明的代碼”(clever code)是一種被衆人鄙視的做法。但是一個人意圖清晰的代碼往往對於另一個人來說就可能是耍小聰明的代碼。

 

         Josh Kerievsky 在他XP2000的報告中給出了一個很好的例子。他提到了估計是最廣爲人知的XP代碼——JUnit。JUnit使用了裝飾模式(decorators)以爲測試用例添加可選功能,比如併發同步還有批處理代碼。通過將這些代碼以裝飾模式封裝,可以保證本來的測試代碼比不這麼做更加簡潔。

 

         但是你必須問問自己,最終代碼是不是足夠簡單。對於我來說是的,但是我很熟悉裝飾模式。但對於很多人來說理解它很困難。同樣的,JUnit還使用了插入式方法(pluggable method),我注意到對於很多人來說一開始接觸就除了迷茫就是迷茫。那麼我們可不可以下這樣的結論,JUnit的設計對於有經驗的設計人員來說是簡單的,但對於沒什麼經驗的人來說是複雜的。

 

         對於終結重複來說,XP的“一次,就一次”(Once and Only Once)和實效性程序員(Pragmatic Programmer)的DRY(Don't Repeat Yourself)都是很好很強大的建議。遵循這些可以讓你受益很長時間。但是這些不是全部,並且如何簡化我們的代碼仍然是很難追尋的。

 

         最近我接觸了一個很可能是過度設計(over-designed)的系統。它被我們重構後,很多靈活性方面的功能都被移除了。其中,我注意到一個程序員說:“重構一個過度設計的系統比重構沒有設計的系統容易多了。”所以說設計簡單點固然好,但是複雜一點也不至於死人嘛。

 

         我聽過這方面最好的建議來自Bob大叔(Robert Martin)。他建議不必太過在意設計是不是達到了最簡。反正最終你可以,或者可能,或者說有意願去重構它。所以說,我們可以下這樣的結論,重構的意識遠遠重要於知道什麼是最簡單的事情。

 

重構是否與YAGNI衝突 

 

         這個主題來自於最近的XP郵件列表,有必要再次提及以便我們認清設計在XP中的角色。

 

         這個問題基本上來說是這樣的,重構需要些時間,但是不增加任何功能。然而YAGNI表示我們應該爲當下而做設計,而不是爲了以後做設計。它們是有衝突的嗎?

 

         YAGNI認爲你不必爲當前階段不需要的複雜性埋單,這是實現簡單設計的其中一個措施。重構需要被用來保持設計的簡單性,所以你有必要在你認識到有更簡單的方法時重構。

 

         簡單設計既利用了被XP的撫平的變化曲線,同時又可以反過來起到進一步撫平的作用。只要你使用了測試,持續集成,還有重構,你就可以高效的應用簡單設計措施。但是你在應用簡單設計的同時必須保證變化曲線的平整。除非你預判正確,否則任何非必要的複雜性都會在各方面增加你係統變化的難度。人類其實是不擅長預測的,所以我們還是應該專注於簡單性。儘管我們不會在第一時間做到最簡,但是我們需要通過重構來最終接近並達到這一目的。

 

模式與XP

 

         JUnit的列子不可避免的讓我談到了模式。模式與XP之間的關係很有意思,而且也是一個很普遍的問題。Joshua Kerievsky曾論證過模式在XP中未受到足夠的重視,並且他的論證很充分,我就不重複了。但是需要注意的是很多人認爲模式是與XP衝突的。

 

         這個論題的中心在於模式常常被過度使用。世界上傳說級的程序員太多了,剛剛讀“四人幫”(GOF,Gang of four)的時候,他們曾經在32行代碼中用了16種模式。我記得一天晚上,享受着啤酒,和Kent一起翻看一篇叫做“不是模式:23個簡單技巧”時,我們琢磨,那些東西與其用策略來實現還不如用一堆if。這個玩笑說明,模式常常被過度使用,但是模式始終不是壞東西。關鍵是你怎麼用它們。

 

         其中的一個說法是:簡單設計原則的影響會引導你使用模式。很多重構行爲印證了這點,即便你對模式沒概念,只要你遵循簡單設計原則你會不知不覺的使用模式。即便真的是這樣的,但是這真的是最好的方法麼?當然還是你心理大概有個方向並且通過一本書來幫助你解決問題比你去發明一個什麼做法要好些。我確實仍然在我想到一個模式的時候就去看看四人幫(GOF)。對於我來說一個有效率的設計關注的是我們必須知道一個模式的價值所在以及是否值得一用。同樣的像Joshua建議的那樣,我們需要漸漸熟悉如何讓模式融入設計。XP只是對於模式的應用與他人不同,但絕對沒有否認它們的價值。

 

         但是當讀取一些郵件的時候,我有一種相同的感覺,那就是很多人認爲XP不鼓勵用模式,儘管諷刺的是這些建議者中有很多人也是使用模式的引領者。是因爲他們已經超脫了模式了嗎,或者因爲模式已經太深入他們的思維方式致使他們意識不到它了?我不知道其他人的答案,但是我覺得模式仍然是至關重要的。XP或許是一種開發過程,但是模式是設計知識的脊樑,是無關你使用的開發過程的寶貴知識。只是不同的開發過程會按照不同的方法使用模式。XP既強調在你需要模式之前不要使用它,也同時強調通過一個簡單的實現進化你使用模式的方法。但是模式仍然是需要獲得的關鍵知識。

 

         我對於極限人(XPers)使用模式的忠告是:

 

      n  爲學習模式投入一些時間。

      n  關注在開發過程中的什麼時候該使用模式。(別太早)

      n  在一開始關注如何以最簡的形式實現模式,然後再加入複雜性。

      n  如果你使用了一個模式,然後你又發現它不值得使用,毫不猶豫的把它搞掉。

 

         我認爲XP應該多強調一些對於模式的學習。我不確定如何把它加入到XP的措施中,但是我確信Kent會想到好辦法的。

 

培育架構 

 

         聽到軟件架構(software architecture)我們想到什麼?對於我來說,架構表達了一個意思,那就是系統的核心元素,最難去改變的那部分。一個基礎,系統剩餘的部分必須構建於其上。

 

         當你使用演進式設計的時候,架構扮演了一個什麼角色?XP的批評者們又要說,XP忽視架構,XP只是趕緊去編碼然後相信重構可以解決一切設計問題。有趣的是他們對了,這很可能是個弱點。當然,一些巨猛的XP專家——Kent Beck, Ron Jeffries,還有Bob Martin正在越來越多的把精力放在避免前期架構設計上(up front architectural design)。別把數據庫牽扯進來直到你真正需要它。先用文件存然後在未來的一個迭代週期中重構成數據庫。

 

         相對來說我被認爲是一個膽小的極限人,對於這個看法我表示不同意。我認爲一個扁平化的前期架構是有必要的。就像那些初期決定的如何劃分應用層次,如何與數據庫打交道(如果你需要),爲了與Web服務器交互制定什麼樣的方針。

 

         最主要的是我認爲很多這類領域屬於我們這幾年一直在學習的模式。隨着你對模式知識的增長,你應該有一個合理的關於如何使用模式的初步想法。我的觀點與反對任何前期設計的人們的關鍵區別是我的這些架構設計不希望爲項目添加任何頑疾,而他們的觀點則是團隊儘管知道一些早期決定有可能帶來一些錯誤,他們還是應該有勇氣去面對它們。有個人告訴我一個故事,一個項目,快部署了,決定不用EJB了,希望把EJB從系統中移除。這是一個不小的重構,他們在晚些時候做到了。項目中維護的平整變化曲線不僅使這個重構成爲可能,並且讓它顯得相當值得一做。

 

         如果這個事情用另一種方法做會怎樣?如果你決定不用EJB,晚些時候再添加它好不好?你應不應該不用EJB直到你發現缺了它不行?這是一個包含很多因素的問題。的確不用複雜的組件增加了簡易度並提高了效率。不管怎麼說,總之除掉點什麼東西總比添加他們要容易。

 

         所以我的建議是:開始的時候看看架構大概是個什麼樣。如果你看到大量的數據被N個用戶訪問,那麼第一天開始就用數據庫吧。如果你看到了複雜的業務邏輯,那麼用領域模型吧。當懷疑是不是在簡單性方面有錯誤的時候,就遵從YAGNI大神的旨意吧。同時準備在你一見到某部分架構沒發揮作用的時候立即簡化你的架構。

 

UML與XP

 

         我與XP打交道後遇到的所有問題中對我和UML的聯繫改進最大的問題是:UML和XP是不兼容的麼?

 

         這些不兼容包括幾點,XP的確在很大程度上不重視圖形表示。儘管官方說法是“如果它們有用就用”,但這裏有個潛臺詞就是“真正的極限人不用圖形”。而且像Kent那樣的人對於圖什麼的不太感興趣就更加爲這點提供了有力論據,我的確沒見過Kent自願站出來畫個設計圖。

 

         我想這個問題有兩個原因。一個是一部分人覺得圖有用而一部分覺得沒用。危險的是那些認爲有用總想那些認爲沒用的去畫,而反之亦然。其實畫圖的人和不畫圖的人們應該彼此接受。

 

         另一個問題是設計圖容易讓人聯想到一個複雜的過程,那種花了巨多時間而且還毫無幫助,甚至還會帶來災難的複雜過程。所以比起XP專家們說的“只在必須的時候用(,廢物)”這種話,我覺得我們更應該靈活的使用圖並且避免任何副作用。

 

         以下是我對於使用圖的一些建議:

 

         首先時刻想着你爲什麼畫圖。畫圖最重要的價值在於溝通。一個有效的溝通在於選擇表達重要的事而忽略最不重要的。這種選擇就是使用UML的關鍵。不要把所有的類都畫出來——只畫重要的。每個類不要畫出所有的屬性和方法——只畫重要的。不要爲每一個用例和場景畫時序圖——只……你懂的。代碼是最好的傳達意圖的途徑,代碼也是保持代碼同步最容易的途徑。完全通過圖來傳達意思是理解意圖的大敵。

 

         一般來說圖是在開始編碼之前開展設計用的。你常常有一種印象就是做這樣的事是違背XP的,但其實不是這樣的。很多人說當你遇到一個棘手的任務時,還是有必要在開始的時候大家一起很快的搞個設計。那麼,當你這樣搞的時候注意:

 

      n  保持簡短。

      n  別嘗試表達所有的信息(只關心最重要的)

      n  不要把設計結果當做最終設計,而只是一個草稿。

 

         最後一點值得擴展。只要你搞前期設計,你不可避免的會發現某一方面的設計是錯誤的,並且只有在編碼的時候纔會發現。這不是問題,發現了就修改你的設計吧。麻煩往往來自於人們覺得自己搞定了設計,然後他們就不將代碼中的反饋應用回設計中去了。

 

         改變設計不一定意味着改變設計圖。畫個圖幫助你理解意圖,之後就把這圖扔了是非常有道理的。畫了有用的圖,那就很值得了。他們沒必要留着當老古董,好的UML圖不是古董。

 

         很多極限人使用CRC cards(譯註:Class,Responsable,Collaboration Cards 一種圖形化設計方式)。這不與UML衝突。我常常CRC與UML混起來用。使用任何對於你手中工作有價值的技術吧。

 

         UML的另一個用處是可持續維護的文檔,它的通常形態是保存在一個設計工具中的模型。人們這樣做出於希望可以爲系統維護一個文檔來幫助人們工作,其實在實踐中這完全幫不上忙。

 

      n  使這些圖隨時更新很花時間,一方面人們漸漸將更新工作放在一邊

      n  令一方面這些圖一般要麼藏在某個設計工具中,要麼就藏在一捆厚厚的文件中,所以根本就沒人看。

 

         基於這些已經發現的問題,我對於持續維護文檔的建議是:

 

      n  只在你可以輕鬆的保持圖更新的情況下使用圖。

      n  把圖放在任何人都一眼可以看到的地方。我喜歡把它們貼牆上,並鼓勵人們用筆在牆上的圖上做些簡單的修改。

      n  時刻注意人們是不是還在用它,如果沒有,扔掉。

 

         UML最後一個方面的用途是作爲工作移交文檔,就像一組給另一個組移交工作時那樣的文檔。XP的觀點是寫這樣的文檔跟前述的差不多,它的業務價值由客戶來決定。我們可以再一次這樣說,UML在這裏是有用的,有選擇性的畫圖可以幫助人們溝通。時刻記住代碼纔是包含詳細信息的地方,圖只是體現概要與重要問題的載體。

 

隱喻論On Metaphor,譯註:Metahpor 即System Metahpor,極限編程在設計期的一種手法,存有諸多爭議)

 

         好吧,我估計也得在公共場合說說這事——我始終還是沒搞清楚“隱喻”這玩意是怎麼回事。我看到它挺管用,並且在C3項目中發揮了很好的作用,但是這並不代表我知道怎麼去建立它,更不用說解釋怎麼去建立它了。

 

         XP的隱喻措施是建立在 Ward Cunninghams 的命名系統方案上的,也就是說你列出一系列廣爲人知的名稱當做描述業務領域的詞彙庫。這樣一個命名系統可以爲你命名系統中的類和方法提供幫助。

 

         我也曾經通過領域概念模型建立過一套命名系統,那是我和一堆領域專家們用UML或者類似的東西建立的。你需要很小心的去做這件事,你必須把概念的集合儘量縮小,並避免任何技術問題摻和進來。但是如果你建立了這樣一個系統,那麼你會發現你可以用這些領域專家可以明白的領域詞彙幫助他們與開發人員的溝通。領域模型並不完全匹配類設計,但是足以作爲整個領域的一些公共詞彙。

 

         現在我沒有看到任何不能使用系統隱喻來建立這套詞彙系統的理由,C3就用系統隱喻把薪資體系用一個流水線來表達過。然而我也沒看到基於領域模型的命名系統是什麼壞主意。我也不希望放棄一個對我來說很管用的獲取命名系統的方法。

 

         人們常常批評XP至少得做點大體的設計,極限人常常答覆:“Metaphor就是啊。”。但是我始終沒有看到Metaphor被解釋的有說服力過。這的確是XP需要跨越的一道坎,極限人們仍需努力。

 

你長大後想當個架構師(Architect)嗎? 

 

         最近的十年間,“軟件架構師”(software architect)一詞變得流行起來。對於個人來說這是一個很難使用的術語。我老婆是一個建築工程師(structural engineer)。工程師與建築師(architect)之間的關係有點……有趣。我比較喜歡的就是“建築師擅長3個B:燈泡(bulbs),灌木叢(bushes),鳥(birds)”。意思是:建築師畫出這堆好看的圖片,但是必須去確保它們能夠站住腳的是工程師。結果就是我儘量避免使用軟件架構師這樣的名詞,畢竟連我老婆都不能給予我的職業以尊重的話,我又怎麼才能混得下去呢。

 

         在軟件業,架構師(architect)意味着很多。(在軟件業很多名詞都意味着很多。)一般來說,它代表一種權威,就像有人說“我不僅是個小程序員——我是個架構師”。這個或許可以翻譯成“我是個架構師了——我如此重要就不應該再做編碼了”。問題就轉變成了,當你想鍛鍊自己的技術領導力的時候是否應該把你自己從普通編碼中抽離出來。

 

         這個問題產生了非常大的情緒。我看到很多人對於他們不再能成爲架構師這個角色感到非常憤怒。“在XP中竟然沒有企業級架構師這樣一個位置。”,這就是我常常聽到的哀號。

 

         就設計這個角色本身來說,我也不認爲XP不重視有經驗或者好的設計技能。確實有很多XP的支持者——Kent Beck,Bob Martin,當然還有Ward Cunningham——我從他們身上學了好多關於設計的知識。儘管他們爲人熟知的技術領導者角色的確發生了變化。

 

         舉例來說,我來介紹我們ThoughtWorks的技術領導者之一:Dave Rice。Dave已經經歷了N多軟件生命週期並且非官方的在技術層面上罩着一個50人左右的項目。他領導者的角色意味着他花了好多時間和全部的同志們在一起。他會在同志們需要幫助的時候和他們工作在一起,並且四處尋找誰需要幫助,他坐的地方就是我們的旗幟。作爲ThoughtWork的長期合作者,他可以坐在任何辦公室中,只要他喜歡。他曾經和Cara(我的發佈經理)合用一間。結果在過去的幾個月裏他又搬了出來,和我們的程序員們一起在開放辦公區工作(或者XP喜歡用的“作戰室”)。這對他很重要,因爲這樣他可以看到事態的進展,並且隨時可以在必要的時候做點什麼。

 

         熟悉XP的人們會發現我正在描述XP中的一種角色:教練(Coach)。的確,XP做的文字遊戲之一管技術領導者叫教練。意思很清楚:XP的技術領導力應該體現在培訓程序員並且幫助程序員做決定上。這是一個需要良好的溝通能力同時也需要良好的技術能力的角色。Jack Bolles在XP 2000大會上表示:“獨孤求敗”以後將越來越難有立足之地。合作與培訓是成功的關鍵。

 

         在一個會議晚宴上,Dave和我與一個XP反對者有一個談話。隨着我們討論我們以往都做過什麼,我們發現我們在方針上有很多共同點。我們都喜歡適配,迭代開發。都認爲測試是很重要的。我們開始猜測他爲什麼會這麼強烈的反對XP。他說了類似這樣的一段話“我最不希望程序員們重構並且瞎搞我的設計”。一切都清楚了,就像Dave之後跟我說的那樣“如果他不信任他的程序員,那當初爲什麼還僱傭他們?”。XP中有經驗的程序員能做的最重要的就是:把儘可能多的技能傳授給新手程序員。我們採用教練培訓程序員們如何做重要的決定,而不是找個架構師獨自決定所有重要的事。就像Ward Cunningham指出的那樣,通過釋放分發他的技能,帶給項目組的比“獨孤求敗”更多。

 

可逆性

 

         XP 2002大會上Enrico Zaninotto發表了一個吸引人的講話,討論了敏捷方法與精益生產間的捆綁。他的觀點是這兩個方針的關鍵方面是它們都通過減少過程中的不可逆性來踢走複雜性。

 

         在這個觀點中闡述道:決定的不可逆性是複雜度的主要來源。如果你可以容易的改變你所做的決定,那麼它們是否正確就不那麼重要了——這可以讓你的生活更簡單些。演進式設計的結果就是設計者需要思考他們怎麼去避免他們決定中不可逆的部分。比起立即做出正確的決定,寧可找個方法等等再做決定(當你已經獲得了更多的信息時)或者做那種以後逆轉起來沒多大難度的決定。

 

         這種支持可逆性的決定使敏捷方法在源代碼控制系統上放置了很多關注,並且把所有的東西全放到這樣一個系統上去。儘管這並不保證可逆性,特別是那種長期決定,但它的確提供了一個基礎,爲團隊帶來了信心,儘管它很少被使用。

 

         爲可逆性做設計也意味着一個讓錯誤更早體現出來的流程。迭代開發的價值之一就在於快速的迭代可以允許客戶看到系統的成長,並且如果在需求分析時期出現錯誤,也可以在修改的成本高到不可能修改之前發現並修改它。這種快速發現的做法對於設計也很重要。這意味着你需要先搭起個架子來,這樣潛在的問題區域會在一次次的測試中暴露出問題。它還意味着做一個試驗來看未來的修改有多難也是值得的——儘快的在分支系統上搞一個用完即扔的原型。一些團隊已經有嘗試在原型上做變更來預測變更的難度的報告。

 

設計的意願

 

         儘管我在這篇文章中專注於多種技術實踐,但是有一件事是最容易遺忘的,那就是人的因素。

 

         爲了正常的工作,演進式設計需要一種力量來使它整合。這種力量只能來自於人——一個有決心使設計質量保持在高水準的人。

 

         這種意願不必來源於所有人(儘管如果是的話那樣最好),通常在團隊裏僅有一兩人負責整合設計。這就是通常叫“架構師”的那個人手底下的活。

 

         這個職責意味着對代碼持續的監控,看看有沒有什麼地方正在變亂,然後在事態失去控制前儘快採取行動糾正它。設計的保證者不一定是修正問題的人——但是他們必須確保有人去搞定這個問題。

 

         設計意願的缺失看來是演進式設計失敗的主要原因。就算人們無論多麼熟悉我在這文章裏所說的那些事情,如果缺了意願,那麼不會有任何好的設計。

 

難以重構的部分

 

         我們可不可以用重構處理全部的設計決定,或者說,有沒有一個普遍的問題很難被後期添加?這時,XP的正統說法告訴我們,所有的事情都是隻要你需要就容易被添加的,所以YAGNI總是靈光的。我懷疑是否會有例外。一個在是否能後期添加存在爭議的好的例子就是國際化。這是不是一個後期添加會很痛苦,所以應該在一開始就考慮進去的事情呢?

 

         我可以很快想象一定有一些事可以歸入這個分類,可是現實是我們掌握的數據太少了。如果你必須去添加什麼功能,像國際化,在後期你往往非常清楚它所花費的工作量。你不清楚在需要它之前添加它並且維護它日復一日所付出的工作量。你也不清楚你是否搞對了正確的需求,然後還是要重構。

 

         YAGNI認爲很多這種潛在需求最終被發現是不需要的,或者至少不是按你期待的那種形式被需要的。通過不做它們,你會節省很大的工作量。儘管將一些簡單解決方案重構爲你真正需要的那樣需要一些工作量,但是這種重構仍然比構建所有存在問題的功能的工作量要少。

 

         另一個需要我們記住的問題是你是否知道如何做它。如果你做過幾次國際化,那麼你會知道應用何種模式。那樣你八成能把它做對。這樣的話添加預測性的結構或許比你剛接觸這個問題就開始預測更好。所以我的建議是:如果你知道如何做這件事,那麼你就處在一個可以判斷這件事是現在做還是以後做的高度。那麼如果你沒做過這件事,你不僅無法計算它的成本,估計你也無法做好它。這樣你就應該稍後再添加它。如果你已經添加,並且吃了些苦頭,那麼你大概就知道你晚些添加這個功能可能感覺好的多。因爲你的團隊經驗更豐富了,你對領域更熟悉了,你也更熟悉需求了。往往你在這個時候往回看的時候,你會有一個完美的認識。過早的添加它可能比你想象的還要讓你難受。

 

         這就關聯到一個階段排序的問題。在 Planning XP 中,我和Kent公開的指明瞭我們意見的不同。Kent喜歡使業務價值成爲決定階段排序的唯一因素。Ron Jeffries在一開始是反對的,不過現在也同意了。我還是不太確定。我相信在業務價值與技術風險間是有平衡點的。這會驅使我至少將一些國際化工作提前來做來轉移風險,但是也只是第一個版本發佈時需要國際化時才應該這樣做。讓一個版本儘快發佈是至關重要的。如果第一版發佈不需要一些複雜性,那麼在發佈之後再添加它們也是值得的。一個交付後並且可運行的代碼的力量是巨大的。它可以集中客戶的注意力,增加信任,還是一個巨大的信息來源。做任何可能使發佈提前的事。儘管在第一版發佈後再添加一些功能可能更費事,但是還是儘快發佈比較好。

 

         任何新技術都很自然的有其提倡者不確定一些邊緣狀況的情況。很多極限人被告知演進式設計不可能應對一些特定問題,但結果發現其實是可能的。這種對“不可能”的攻克引導了一種類似的情況可以被克服的信心。當然我們也不能永遠如此推斷,但是直到XP社區碰到一個分界並且跨越不了爲止,我們永遠不知道這些分界在哪裏,並且嘗試跨越這些其他人認爲的潛在分界是正確的。

 

         (Jim Shore最近的一篇文章討論了一些情況,包括國際化,並且最終證明了像這樣的潛在邊界不再是一種障礙。)

 

有設計嗎?

 

         演進式設計的難題之一是非常難以說清到底設計了沒。設計和編碼混合在一起的風險就是可能沒設計就編碼了——一旦出現這種情況,演進式設計就可能脫軌並失敗。

 

         如果你在開發小組,那麼你可以通過代碼來判斷是不是有設計。如果代碼越來越複雜,越來越難搞,那麼就是設計沒有做足。但杯具的是這個觀點比較主觀。我們沒有一個可靠的標尺來給我們一個客觀的衡量設計好壞的方法。

 

         如果對於技術人員來說這種設計的“透明性”是個難題的話,那對團隊中的非技術人員來說簡直是要叫苦連天了。如果你是一個經理或者客戶,那你怎麼分辨軟件是否有個好的設計?這對你來說很重要,因爲一個缺乏設計的軟件以後修改的成本會很高。的確沒有一個簡單的答案,但是有一些提示。

 

      n  聽聽技術人員說些什麼。如果他們在抱怨修改的複雜,那麼重視這種抱怨並給予他們時間去修改。

      n  時刻注意有多少代碼不再使用了。一個不斷健康重構的項目會不斷的刪除一些不好的代碼。如果沒有代碼被刪除,那麼這就是一個標誌着沒有足夠的重構的信號——會導致設計的腐化。當然,就像任何其他的標尺一樣,這個標尺也可能會被誤用,但是一個好的技術人員會力挺任何標尺,輕視任何主觀因素。

 

那麼設計掛了嗎?

 

         絕對沒有,但是設計的本質改變了。XP的設計尋求的是如下技能:

 

      n  一種持續的慾望去儘可能的保持代碼的乾淨與簡潔。

      n  重構技能,那樣你就可以自信的在你需要的時候來做出改進。

      n  對於模式的良好認知:不光是如何使用它們,還包括理解什麼時候使用它們並且如何使它們融入。

      n  設計的同時留意未來的變化,要知道你現在做的決定有可能不得不在未來做出改變。

      n  瞭解如何與那些必須理解設計的人做溝通,用代碼,圖,還有以上的一切:言語。

 

         這是一堆嚇人的技能選擇,但是成爲一個好的設計者一直是比較難的。XP根本就沒有讓這事簡單些,至少對我來說不是。但是XP的確給予我們一個新的方法去思考高效的設計,因爲它已經讓演進式設計再次成爲了一種貌似可行的策略。而且我是演進的大粉絲——否則誰知道我會成爲什麼呢?

 

聲明

 

         過去的幾年裏,我從很多好兄弟那裏撿到或者“偷”到了好多好主意。而這些都沉默在我記憶的陰暗面裏了。但是我的確記得我從Joshua Kerievsky那裏弄到不少好主意,還有Fred George 和 Ron Jeffries也給我不少好建議,還有,我不能忘記還有多少好主意不斷地Ward 和 Kent 那裏涌出來。

 

         我永遠感謝那些問我問題還有揪出我的錯別字的人。雖然我實在懶得弄個列表出來,但是這的確包括:Craig Jones, Nigel Thorne, Sven Gorts, Hilary Nelson, Terry Camerlengo。

發佈了53 篇原創文章 · 獲贊 8 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章