設計已死?
對於許多與極限編程有過短暫接觸的人來說,XP 似乎呼籲軟體設計的死亡。不僅許多設計活動被嘲笑為「龐大前期設計」,而且 UML、靈活架構,甚至模式等設計技術都被淡化或直接忽略。事實上,XP 涉及大量的設計,但其方式不同於既定的軟體流程。XP 以允許演化成為可行設計策略的實務,復興了演化設計的概念。它也為設計師提供了新的挑戰和技能,因為設計師需要學習如何進行簡單設計、如何使用重構來保持設計的簡潔,以及如何以演化方式使用模式。
2004 年 5 月
(本文為我於 XP 2000 會議的基調演講而撰寫,其原始形式已作為會議記錄的一部分發布。)
極限編程 (XP) 挑戰了許多關於軟體開發的常見假設。其中最具爭議性的假設之一是拒絕在前期設計中投入大量精力,而採用更具演化性的方法。對其批評者來說,這是回到「編碼並修復」的開發方式,通常被嘲笑為駭客行為。對其支持者來說,這通常被視為拒絕設計技術(例如 UML)、原則和模式。不要擔心設計,如果你聆聽你的程式碼,一個好的設計就會出現。
我發現自己處於這場爭論的中心。我職業生涯的大部分時間都涉及圖形設計語言,例如統一建模語言 (UML) 及其前身,以及模式。事實上,我寫過有關 UML 和模式的書籍。我擁抱 XP 是否意味著我收回我對這些主題所寫的所有內容,清除我腦海中所有這些反革命概念?
好吧,我不會指望讓你們懸在戲劇性緊張的魚鉤上。簡短的答案是否定的。長篇的答案就是本文的其餘部分。
計畫與演化設計
在本文中,我將說明軟體開發中設計的兩種風格。也許最常見的是演化設計。演化設計基本上意味著系統的設計會隨著系統的實作而成長。設計是程式設計流程的一部分,隨著程式演化,設計也會改變。
在常見的用法中,演化設計是一場災難。設計最終會變成一堆臨時戰術決策的集合,每個決策都會讓程式碼更難以變更。在許多方面,你可能會認為這不是設計,它通常會導致不良的設計。正如肯特所言,設計的存在是為了讓你能夠在長期內輕鬆地持續變更軟體。隨著設計惡化,你有效變更的能力也會下降。你會遇到軟體熵的狀態,隨著時間的推移,設計會越來越糟。這不僅會讓軟體更難以變更,還會讓錯誤更容易滋生,更難以找到並安全地消滅。這是「編碼和修復」的惡夢,隨著專案的進行,錯誤的修復成本會呈指數倍增長。
計畫設計是對此的反制措施,並包含源自其他工程領域的概念。如果你想建造一個狗屋,你可以隨意找一些木材,然後弄出一個粗略的形狀。但是,如果你想建造一棟摩天大樓,你就不能這樣做——它甚至在你完成一半之前就會倒塌。因此,你會從工程製圖開始,就像我妻子在波士頓市中心工作的辦公室所做的那樣。當她在進行設計時,她會找出所有問題,部分透過數學分析,但主要是透過使用建築規範。建築規範是關於你如何根據經驗(和一些基礎數學)來設計結構的規則。一旦設計完成,她的工程公司就可以將設計移交給另一家建造它的公司。
軟體中的計畫設計應以相同方式進行。設計人員會事先思考重大問題。他們不需要撰寫程式碼,因為他們並非建立軟體,而是設計軟體。因此,他們可以使用 UML 等設計技術,避免程式設計的一些細節,並讓設計人員在更抽象的層級工作。完成設計後,他們可以將設計移交給另一個小組(甚至另一家公司)來建置。由於設計人員思考的規模較大,因此可以避免導致軟體熵的一系列戰術決策。程式設計人員可以遵循設計的方向,並在遵循設計的情況下,擁有建置良好的系統
現在,計畫設計方法自 70 年代以來一直存在,而且許多人已經使用過它。它在許多方面都比程式碼和修正演化設計更好。但它有一些缺點。第一個缺點是,在程式設計時,不可能思考所有需要處理的問題。因此,在程式設計時,您一定會發現質疑設計的事物。然而,如果設計人員已經完成,轉移到另一個專案,會發生什麼事?程式設計人員開始編寫設計周圍的程式碼,並設定熵。即使設計人員沒有離開,也要花時間整理設計問題、變更繪圖,然後修改程式碼。通常有更快的修正方法和時間壓力。因此,(再次)產生熵。
此外,通常存在文化問題。設計人員由於技能和經驗而成為設計人員,但他們忙於設計工作,因此沒有太多時間編寫程式碼。然而,軟體開發的工具和材料會快速變更。當您不再編寫程式碼時,不僅會錯失此技術變動所發生的變更,也會失去編寫程式碼的人的尊重。
這種建構者與設計人員之間的緊張關係也會發生在建構中,但在軟體中更為強烈。之所以強烈,是因為有一個關鍵差異。在建構中,設計人員與建構人員之間的技能分工較為明確,但在軟體中,情況並非如此。在高設計環境中工作的任何程式設計人員都需要非常熟練。熟練到足以質疑設計人員的設計,特別是當設計人員對開發平台的日常現實了解較少時。
現在,這些問題可以得到解決。也許我們可以處理人為的緊張關係。也許我們可以讓設計人員具備足夠的技能來處理大多數問題,並具備足夠嚴謹的流程來變更繪圖。還有一個問題:變更需求。變更需求是我遇到的軟體專案中造成頭痛的首要重大問題。
處理變更需求的一種方法是將彈性納入設計中,以便在需求變更時可以輕鬆變更。然而,這需要洞察預期的變更類型。可以規劃設計來處理變動性區域,但儘管這有助於預見需求變更,但對於無法預見的變更卻無濟於事(甚至可能造成傷害)。因此,您必須充分了解需求,才能區分變動性區域,而我的觀察是這非常困難。
現在,其中一些需求問題是源於對需求了解不夠清楚。因此,許多人專注於需求工程流程,以期獲得更好的需求,希望這將避免以後需要變更設計。但即使這個方向也可能無法治癒。許多無法預見的需求變更都是由於業務變更造成的。儘管您的需求工程流程再小心,也無法防止這些變更。
因此,所有這些都讓計畫設計聽起來不可能。它們當然是巨大的挑戰。但我並不想聲稱計畫設計比演化設計更糟,因為演化設計最常以「編碼和修正」的方式實作。我確實比較喜歡計畫設計,而不是「編碼和修正」。然而,我意識到計畫設計的問題,並且正在尋求新的方向。
XP 的促成實務
XP 因許多原因而引起爭議,但 XP 中的一個關鍵警訊是它提倡演化設計,而不是計畫設計。眾所周知,演化設計不可能因為臨時設計決策和軟體熵而奏效。
了解這個論點的核心是軟體變更曲線。變更曲線表示,隨著專案執行,變更的成本將呈指數級增加。變更曲線通常用階段來表示,「在分析中進行的變更,在生產中修復的成本將增加數千美元」。這很諷刺,因為大多數專案仍在臨時流程中工作,而臨時流程沒有分析階段,但指數化仍然存在。指數變更曲線表示演化設計不可能奏效。它也傳達了為什麼必須仔細進行計畫設計,因為計畫設計中的任何錯誤都面臨相同的指數化。
XP 背後的基本假設是,有可能將變更曲線拉平到足以讓演化設計奏效。這種拉平是由 XP 啟用和利用的。這是 XP 實務結合的一部分:特別是您無法在不執行那些促成拉平的動作下執行那些利用拉平曲線的 XP 部分。這是 XP 引起爭議的常見原因。許多人批評利用,卻不了解促成。批評通常源於批評者自己的經驗,他們沒有執行允許利用實務奏效的促成實務。結果,他們被燒傷了,當他們看到 XP 時,他們會想起那場火災。
促成實務有很多部分。核心是測試和持續整合的實務。沒有測試提供的安全性,其他 XP 將是不可能的。持續整合對於讓團隊保持同步是必要的,這樣您就可以進行變更,而不必擔心與其他人整合。這些實務結合起來可以對變更曲線產生重大影響。我在 Thoughtworks 再次想起了這一點。引入測試和持續整合對開發工作有顯著的改善。肯定足以對 XP 聲稱需要所有實務才能獲得重大改善提出嚴肅的質疑。
重構具有類似的效果。以 XP 建議的有紀律方式重構其程式碼的人發現,與進行較鬆散、較臨時性的重組相比,他們的效能有顯著的差異。在我接受 Kent 教導如何正確重構後,那肯定是我所經歷的。畢竟,只有如此強烈的改變才會促使我寫一本關於它的書。
Jim Highsmith 在他出色的 XP 總結 中,使用了天平的類比。一個托盤是計畫設計,另一個是重構。在較傳統的方法中,計畫設計佔主導地位,因為假設你無法在稍後改變主意。隨著變更成本降低,你可以稍後在重構中進行更多設計。計畫設計並不會完全消失,但現在有兩種設計方法可以平衡使用。對我來說,感覺在重構之前,我都是單手進行所有設計。
這些持續整合、測試和重構的啟用實務,提供了一個使演化設計可行的全新環境。然而,有一件事我們尚未弄清楚,那就是平衡點在哪裡。我確信,儘管有外界的印象,XP 不僅僅是測試、程式碼和重構。在編碼之前有設計的空間。其中一些是在編碼之前,大部分發生在為特定任務編碼之前的反覆運算中。但在前期設計和重構之間存在新的平衡。
簡潔的價值
XP 中最偉大的兩個口號是「執行可能有效的最簡單事情」和「你不需要它」(稱為 YAGNI)。兩者都是 XP 簡單設計實務的表現。
YAGNI 通常被描述的方式,它表示你今天不應該新增任何程式碼,而這些程式碼只會被明天需要的功能使用。從表面上看,這聽起來很簡單。問題出在框架、可重複使用的元件和彈性設計等事物上。這些東西很複雜,難以建構。你會支付額外的前期成本來建構它們,並期望稍後能收回該成本。這種預先建構彈性的想法被視為有效軟體設計的關鍵部分。
然而,XP 的建議是,對於第一個需要此功能的案例,您不應建立彈性元件和架構。讓這些結構在需要時自行發展。如果我今天想要一個處理加法但不處理乘法的 Money 類別,那麼我只會在 Money 類別中建立加法。即使我確定在下一個迭代中需要乘法,並且了解如何輕鬆地執行它,並且認為這樣做會非常快速,我仍會將它留到下一個迭代中。
這樣做的原因之一是經濟考量。如果我必須執行任何只用於明天需要的功能的工作,這表示我損失了需要為此次迭代執行的功能的精力。發布計畫說明了現在需要處理什麼,在未來處理其他事情與開發人員與客戶的協議相違背。存在此次迭代的故事可能無法完成的風險。即使此次迭代的故事沒有風險,客戶也必須決定應該執行哪些額外工作,而且可能仍然不涉及乘法。
這種經濟上的反誘因會因我們可能無法正確執行的機率而加劇。無論我們對此功能如何運作有多麼確定,我們仍然可能出錯,特別是因為我們尚未有詳細的需求。提早處理錯誤的解決方案比提早處理正確的解決方案更浪費。而且,XPerts 通常認為我們出錯的機率遠高於做對的機率(我同意這種看法)。
簡單設計的第二個原因是,複雜的設計比簡單的設計更難理解。因此,系統的任何修改都會因增加的複雜性而變得更困難。這會在更複雜的設計新增和需要之間的期間增加成本。
現在,許多人認為這項建議很荒謬,他們這樣想是對的。如果想像 XP 的啟用實務並未到位的一般開發世界,那這樣想是對的。然而,當計畫設計和演化設計之間的平衡改變時,YAGNI 就會變成良好的實務(而且只有在這種情況下才會)。
因此,總結一下。您不想花費精力新增直到未來迭代才需要的全新功能。即使成本為零,您仍然不想新增,因為它會增加修改成本,即使新增成本為零。然而,只有在您使用 XP 或類似技術降低變更成本時,您才能明智地這樣做。
簡潔到底是什麼意思
因此,我們希望我們的程式碼盡可能簡單。這聽起來似乎不太難爭論,畢竟誰想要複雜呢?但這當然會引發「什麼是簡單?」的問題。
在 XPE 中,Kent 給出了簡單系統的四個準則。依序(最重要的優先):
- 執行所有測試
- 沒有重複
- 揭示所有意圖
- 最少的類別或方法數量
執行所有測試是一個相當簡單的標準。沒有重複也很直接,儘管許多開發人員需要指導才能達成此目標。棘手的部分與揭示意圖有關。這到底是什麼意思?
此處的基本價值是程式碼的清晰度。XP 非常重視易於閱讀的程式碼。在 XP 中,「聰明的程式碼」是一個濫用的術語。但有些人揭示意圖的程式碼是別人的聰明才智。
在 Josh Kerievsky 的 XP 2000 論文中,他指出了這方面的良好範例。他檢視了可能是所有 XP 程式碼中最公開的程式碼 - JUnit。JUnit 使用裝飾器為測試案例新增選用功能,例如並行同步和批次設定程式碼。透過將此程式碼分隔到裝飾器中,它允許一般程式碼比原本更清晰。
但您必須自問產生的程式碼是否真的簡單。對我來說是,但我熟悉裝飾器模式。但對於許多不熟悉的人來說,這很複雜。同樣地,JUnit 使用可插入的方法,我注意到大多數人最初發現任何方法都不清楚。因此,我們可以得出結論,JUnit 的設計對於有經驗的設計人員來說更簡單,但對於經驗較少的人來說更複雜嗎?
我認為,透過 XP 的「一次且僅一次」和 實用程式設計師 的 DRY(不要重複自己)消除重複的重點,是那些顯而易見且非常有力的良好建議之一。單單遵循這一點就可以讓您走很長一段路。但這不是全部,而且簡單仍然是一件複雜的事情。
最近我參與了一項可能設計過度的任務。它經過重構,並移除了一些彈性。但正如其中一位開發人員所說,「重構過度設計比重構沒有設計容易。」最好比您需要的簡單一點,但稍微複雜一點並非災難。
我聽過關於這一切的最佳建議來自 Uncle Bob(Robert Martin)。他的建議是不要過於糾結於最簡單的設計是什麼。畢竟,您可以在稍後重構它,而且應該這樣做。最後,願意重構比立即知道最簡單的事情重要得多。
重構是否違反 YAGNI?
這個主題最近在 XP 郵件列表中出現,當我們檢視設計在 XP 中的角色時,值得提出。
基本上,問題始於重構需要時間但不會新增功能的觀點。由於 YAGNI 的重點在於您應該針對現在而非未來進行設計,這是否是一種違規行為?
YAGNI 的重點在於,不要增加當前故事不需要的複雜性。這是簡約設計實務的一部分。重構是為了讓設計盡可能簡潔,因此,只要你發現可以讓事情更簡單,就應該重構。
簡約設計既利用了 XP 實務,也是一種促成實務。只有在有測試、持續整合和重構的情況下,你才能有效地實踐簡約設計。但同時,保持設計簡潔對於讓變更曲線保持平坦至關重要。任何不必要的複雜性都會讓系統更難以朝所有方向變更,除了你預期會使用所加入的複雜彈性。然而,人們並不擅長預期,因此最好追求簡潔。然而,人們不會在第一次就得到最簡單的東西,因此你需要重構才能更接近目標。
模式與 XP
JUnit 範例不可避免地讓我提出模式。模式和 XP 之間的關係很有趣,而且這是一個常見的問題。Joshua Kerievsky 認為,模式在 XP 中被低估了,而且他雄辯地提出了論點,所以我不想重複。但值得注意的是,對許多人來說,模式似乎與 XP 衝突。
這個論點的精髓在於,模式經常被過度使用。這個世界上充滿了傳奇程式設計師,他們剛讀完 GOF,就在 32 行程式碼中加入了十六個模式。我記得某個晚上,在喝了一杯非常棒的單一麥芽威士忌後,和 Kent 一起瀏覽了一篇名為「不是設計模式:23 個小技巧」的論文。我們想到的是,例如使用 if 陳述式而不是策略。這個笑話是有道理的,模式經常被過度使用,但这並不代表它們是個壞主意。問題在於你如何使用它們。
一種理論認為,簡單設計的力量會引導你進入模式。許多重構明確執行此動作,但即使不遵循簡單設計的規則,你也能想出模式,即使你還不認識它們。這可能是真的,但這真的是最好的方法嗎?如果你大致知道自己的方向,並有一本書可以幫助你解決問題,而不是必須自己發明所有東西,那肯定會更好。每當我感覺到模式出現時,我仍然會去拿 GOF。對我來說,有效的設計論證我們需要知道模式的代價是值得付出的 - 那是它自己的技能。同樣地,正如 Joshua 所建議的,我們需要更熟悉如何逐步緩和進入模式。在這方面,XP 處理我們使用模式的方式與某些人使用模式的方式不同,但肯定不會消除它們的價值。
但閱讀一些郵件清單,我明確感受到許多人認為 XP 阻礙模式,儘管具有諷刺意味的是,大多數 XP 的支持者也是模式運動的領導者。這是因為他們已經超越了模式,還是因為模式已經根深蒂固在他們的思維中,以至於他們不再意識到它?我不知道其他人的答案,但對我來說,模式仍然至關重要。XP 可能是一種開發流程,但模式是設計知識的支柱,無論你的流程是什麼,這些知識都是有價值的。不同的流程可能會以不同的方式使用模式。XP 強調在需要之前不要使用模式,並通過簡單的實作逐步演化進入模式。但模式仍然是需要獲取的重要知識。
我對使用模式的 XPer 的建議是
- 花時間學習模式
- 專注於何時套用模式(不要太早)
- 專注於如何先以最簡單的形式實作模式,然後再增加複雜性。
- 如果你放入了模式,然後後來意識到它沒有發揮作用 - 不要害怕再次將它移除。
我認為 XP 應該更強調學習模式。我不確定我如何將它融入 XP 的實務中,但我相信 Kent 可以想出一個方法。
架構的成長
我們所謂的軟體架構是什麼意思?對我來說,架構一詞傳達了系統核心元素的概念,這些元素難以改變。一個其餘部分必須建立在其上的基礎。
當你使用演化設計時,架構扮演什麼角色?XP 的批評者再次聲明 XP 忽略架構,XP 的路線是快速進入程式碼,並相信重構將解決所有設計問題。有趣的是,他們是對的,這很可能是缺點。最激進的 XP 人士 - Kent Beck、Ron Jeffries 和 Bob Martin - 肯定會投入越來越多的精力來避免任何前期架構設計。在真正知道需要之前,不要放入資料庫。先使用檔案,然後在後續反覆運算中重構資料庫。
我以膽小的 XP 人士聞名,因此我必須表示不同意。我認為廣泛的起點架構有其角色。例如,在早期說明如何分層應用程式、如何與資料庫互動(如果你需要的話)、採用什麼方法來處理網路伺服器。
基本上,我認為這些領域中的許多領域都是我們多年來學到的模式。隨著你對模式的了解越來越深入,你應該對如何使用它們有一個合理的初步了解。然而,關鍵的區別在於,這些早期的架構決策並非預期會一成不變,或者團隊知道他們可能會在早期決策中犯錯,並且應該有勇氣去修正它們。其他人講述了一個專案的故事,該專案在接近部署時決定不再需要 EJB,並將其從系統中移除。這是一個相當大的重構,它是在後期完成的,但啟用實務不僅讓它成為可能,而且值得去做。
如果反過來會如何?如果你決定不使用 EJB,稍後再新增它會更困難嗎?因此,你是否應該在沒有 EJB 的情況下嘗試過並發現它有缺陷之前,從不開始使用 EJB?這是一個涉及許多因素的問題。當然,在沒有複雜元件的情況下工作會增加簡潔性,並讓事情進行得更快。然而,有時移除這種東西比放入它更容易。
因此,我的建議是從評估可能的架構開始。如果你看到大量具有多個使用者的資料,請從第一天開始使用資料庫。如果你看到複雜的商業邏輯,請放入網域模型。然而,為了尊重 YAGNI 的神,在有疑問時,請朝著簡潔的方向走。此外,一旦你看到架構的一部分沒有新增任何東西,請準備簡化你的架構。
UML 與 XP
在所有關於我參與 XP 的問題中,最大的問題之一圍繞著我與 UML 的關聯。這兩者不是不相容嗎?
有許多不相容之處。當然,XP 在很大程度上淡化了圖表。儘管官方立場是「如果它們有用,就使用它們」,但有一個強烈的潛台詞是「真正的 XPers 不會使用圖表」。這一點因像 Kent 這樣的人對圖表一點也不熟悉而得到加強,事實上我從未見過 Kent 自願使用任何固定符號繪製軟體圖表
我認為這個問題來自兩個不同的原因。一個原因是有些人發現軟體圖表有幫助,而有些人則沒有。危險在於那些認為不使用圖表的人應該使用圖表,反之亦然。相反,我們應該接受有些人會使用圖表,而有些人則不會。
另一個問題是軟體圖表往往與重量級流程相關聯。此類流程花費大量時間繪製無用的圖表,實際上可能會造成危害。因此,我認為應該建議人們如何正確使用圖表並避免陷阱,而不是 XPerts 通常提出的「只有在必要時(膽小鬼)」訊息。
以下是關於如何正確使用圖表的建議。
首先,請記住您繪製圖表的目的是什麼。主要價值是溝通。有效的溝通意味著選擇重要的事情並忽略不重要的事情。這種選擇性是使用 UML 的關鍵。不要繪製每個類別 - 只繪製重要的類別。對於每個類別,不要顯示每個屬性和操作 - 只顯示重要的屬性和操作。不要為所有用例和場景繪製順序圖 - 只有...您明白了。圖表常見用途的常見問題是人們試圖讓它們全面。程式碼是全面資訊的最佳來源,因為程式碼是最容易與程式碼保持同步的。對於圖表來說,全面性是可理解性的敵人。
圖表的一個常見用途是在開始編碼之前探索設計。您經常會覺得 XP 中此類活動是非法的,但事實並非如此。許多人表示,當您有棘手的任務時,值得聚在一起先進行快速設計會議。但是,當您執行此類會議時
- 讓它們簡短
- 不要試圖解決所有細節(只解決重要的細節)
- 將產生的設計視為草圖,而不是最終設計
最後一點值得擴充。當您進行一些前期設計時,您不可避免地會發現設計的某些方面是錯誤的,而您只有在編碼時才會發現這一點。只要您隨後更改設計,這就不是問題。麻煩在於人們認為設計已經完成,然後不接受他們通過編碼獲得的知識並將其重新應用於設計中。
變更設計並不一定表示要變更圖表。畫出有助於了解設計的圖表,然後丟棄這些圖表,這是完全合理的。畫出這些圖表有助於了解設計,這就足以讓這些圖表有價值。這些圖表不一定要成為永久性的產出。最好的 UML 圖表並非產出。
許多 XP 使用者使用 CRC 卡。這與 UML 並不衝突。我經常混合使用 CRC 和 UML,使用最適合手邊工作的技術。
UML 圖表的另一個用途是持續的文件記錄。在一般形式中,這是一個存在於案例工具中的模型。這個想法是,保留這個文件記錄有助於人員處理系統。在實務上,它通常完全沒有幫助。
- 保持圖表最新需要太長的時間,因此它們與程式碼不同步
- 它們隱藏在 CASE 工具或厚重的活頁夾中,因此沒有人會查看它們
因此,持續的文件記錄的建議來自於這些觀察到的問題
- 只使用您可以在不感到明顯痛苦的情況下保持最新的圖表
- 將圖表放在所有人都可以輕鬆看到的地方。我喜歡將它們貼在牆上。鼓勵人員使用筆編輯牆上的副本,以進行簡單的變更。
- 注意人員是否正在使用它們,如果不是,請將它們丟棄。
使用 UML 的最後一個面向是交接情況中的文件記錄,例如當一個小組交接給另一個小組時。在這裡,XP 重點是製作文件記錄是一個使用者故事,就像任何其他故事一樣,因此其商業價值由客戶決定。在這裡,UML 再次有用,前提是圖表是選擇性的,以利於溝通。請記住,程式碼是詳細資訊的儲存庫,圖表的作用是總結和重點說明重要問題。
關於隱喻
好吧,我可能也公開說一下 - 我仍然沒有掌握這個比喻。我看到它在 C3 專案中運作,而且運作良好,但這並不表示我知道如何執行它,更不用說如何說明如何執行它了。
XP 比喻的實務建立在 Ward Cunningham 的名稱系統方法上。重點是您想出一個眾所周知的名稱集合,作為討論領域的詞彙。這個名稱系統會影響您在系統中命名類別和方法的方式
我透過建立領域的概念模型來建立一個名稱系統。我與領域專家一起使用 UML 或其前身來執行這個動作。我發現執行這個動作時必須小心。您需要維持最少數量的簡單符號,並且必須防止任何技術問題滲入模型中。但是,如果您執行這個動作,我發現您可以使用它來建立領域專家可以理解並用於與開發人員溝通的領域詞彙。這個模型與類別設計並不完全相符,但足以提供整個領域的共同詞彙。
現在我沒有看到任何理由說明這個詞彙不能是一個比喻,例如將薪資轉換為工廠組裝線的 C3 比喻。但我也不認為將您的名稱系統建立在網域詞彙上是一個壞主意。我也不傾向放棄一種對我來說在取得名稱系統時很管用的技術。
人們經常批評 XP,因為您至少需要一些系統的概要設計。XP 人士經常以「那是比喻」來回答。但我仍然認為我沒有看到比喻以令人信服的方式被解釋。這是 XP 中一個真正的差距,而且是 XP 人士需要解決的。
長大後你想成為一名架構師嗎?
在過去十年的大部分時間裡,「軟體架構師」這個術語變得流行。這是一個對我個人來說很難使用的術語。我的妻子是一位結構工程師。工程師和建築師之間的關係……很有趣。我最喜歡的是「建築師擅長三件事:燈泡、灌木叢、鳥類」。這個概念是建築師想出所有這些漂亮的圖紙,但必須確保它們實際上可以站立的卻是工程師。因此,我避免使用軟體架構師這個術語,畢竟如果我自己的妻子都不能以專業的尊重對待我,我還有什麼機會能得到其他人的尊重呢?
在軟體中,架構師這個術語有很多意思。(在軟體中,任何術語都有很多意思。)然而,它通常傳達某種莊重感,例如「我不仅仅是一個程式設計師——我是一個架構師」。這可能會轉化為「我現在是一個架構師——我太重要了,無法進行任何程式設計」。那麼問題就變成了當您想要實施技術領導時,是否應該將自己與世俗的程式設計工作分開。
這個問題產生了大量的負面情緒。我看到人們對他們不再擔任架構師角色的想法感到非常憤怒。「在 XP 中沒有經驗豐富的架構師的位置」是我經常聽到的抱怨。
就像在設計的角色中,我不認為 XP 不重視經驗或好的設計技巧。事實上,許多 XP 的支持者,例如 Kent Beck、Bob Martin,當然還有 Ward Cunningham,都是我從他們身上學到很多關於設計是什麼的人。然而,這確實表示他們的角色與許多人視為技術領導的角色不同。
舉例來說,我將引用 Thoughtworks 的一位技術領導人:Dave Rice。Dave 經歷過幾個生命週期,並在一個五十人專案中擔任非官方的技術領導。他作為領導的角色表示花很多時間與所有程式設計師相處。當他們需要協助時,他會與程式設計師合作,他會四處查看誰需要協助。一個重要的跡象是他坐的地方。作為一位長期 ThoughtWorker,他幾乎可以擁有任何他喜歡的辦公室。他曾經與發行經理 Cara 共用一間辦公室一段時間。然而,在過去幾個月,他搬到程式設計師工作的開放式隔間(使用 XP 偏好的開放式「作戰室」風格)。這對他來說很重要,因為這樣他可以看到正在發生什麼事,並且可以在任何需要的地方提供協助。
那些認識 XP 的人會了解,我正在描述教練的明確 XP 角色。事實上,XP 進行的幾個文字遊戲之一是,它稱領先的技術人物為「教練」。意思很明顯:在 XP 中,技術領導力是透過教導程式設計師並協助他們做出決策來展現的。這需要良好的溝通技巧以及良好的技術技巧。XP 2000 的 Jack Bolles 評論說,現在已經沒有孤獨大師的空間了。合作和教學是成功的關鍵。
在一次會議晚宴中,Dave 和我與一位直言不諱的 XP 反對者交談。當我們討論我們所做的事情時,我們的方法中的相似性相當明顯。我們都喜歡適應性、反覆開發。測試很重要。因此,我們對他反對的激烈程度感到困惑。接著他發表了一項聲明,內容類似於「我最不想要的是我的程式設計師重構並修改設計」。現在一切都清楚了。Dave 在事後對我說:「如果他不信任他的程式設計師,為什麼要雇用他們?」,進一步闡述了概念上的鴻溝。在 XP 中,經驗豐富的開發人員可以做最重要的工作是將他擁有的技能傳授給較資淺的開發人員。你擁有的不是做出所有重要決策的架構師,而是教導開發人員做出重要決策的教練。正如 Ward Cunningham 所指出的,透過這種方式,他擴大了自己的技能,並且比任何孤獨英雄對專案的貢獻更多。
可逆性
在 XP 2002,Enrico Zaninotto 發表了一場引人入勝的演講,討論了敏捷方法與精實製造之間的關聯。他的觀點是,這兩種方法的主要面向之一是,它們透過降低流程中的不可逆性來應對複雜性。
在此觀點中,複雜性的主要來源之一是決策的不可逆性。如果您能輕易地改變您的決策,這表示正確決策的重要性較低,這讓您的生活變得更簡單。演化設計的後果是設計師需要思考如何避免其決策的不可逆性。與其現在就嘗試做出正確的決策,不如尋找方法將決策延後到以後(屆時您將擁有更多資訊),或以一種方式做出決策,讓您在以後能夠毫不費力地逆轉它。
這種支持可逆性的決心是敏捷方法非常重視原始碼控制系統,以及將所有內容放入此類系統的原因之一。雖然這無法保證可逆性,特別是對於長期的決策,但它確實提供了讓團隊充滿信心的基礎,即使它很少被使用。
設計可逆性也意味著一個讓錯誤快速顯示的流程。迭代開發的價值之一是快速迭代讓客戶能夠在系統成長時看到它,如果在需求中發生錯誤,可以在修復成本變得過於昂貴之前發現並修復它。這種快速發現對於設計也很重要。這表示您必須設定事項,以便快速測試潛在問題區域,以查看會出現什麼問題。這也表示值得進行實驗,以查看未來的變更可能有多困難,即使您現在並未實際進行真正的變更,實際上是在系統分支上進行一次拋棄式原型。多個團隊報告嘗試在原型模式的早期嘗試未來的變更,以查看它有多困難。
設計的意願
雖然我在本文中集中介紹了許多技術實務,但有一件事很容易被忽略,那就是人為因素。
為了發揮作用,演化設計需要一種驅動它收斂的力量。這種力量只能來自人,團隊中必須有人決心確保設計品質保持在高水準。
這並非必須來自每個人(儘管這樣很好),通常團隊中只有一或兩個人承擔保持設計完整的責任。這通常屬於「架構師」一詞下的任務之一。
此責任表示持續關注程式碼庫,觀察是否有任何區域變得雜亂,然後在問題失控前迅速採取行動進行修正。設計的維護者不一定要是修正者,但他們必須確保有人進行修正。
缺乏設計意願似乎是演化設計失敗的主要原因。即使人們熟悉我在本文中討論的事物,若沒有意願,設計將無法進行。
難以重構的事物
我們能使用重構來處理所有設計決策嗎?或者有些問題如此普遍,以致於難以在後續加入?目前,XP 正統觀點認為所有事情在需要時都很容易加入,因此 YAGNI 永遠適用。我想知道是否有例外。一個有爭議的後續加入範例是國際化。這是否是一件後續加入很麻煩的事,以致於你應該馬上開始進行?
我很容易想像有些事情會落入此類別。然而,現實是我們仍有極少資料。如果你必須在後續加入某些事物,例如國際化,你會非常清楚這樣做的努力。你較不了解實際上每週投入並在實際需要前維護所需的努力。此外,你較不了解你很可能弄錯,因此無論如何都需要進行一些重構。
YAGNI 的部分論證是,許多這些潛在需求最終並不需要,或至少不是你預期的方式。透過不執行這些需求,你可以省下大量努力。雖然需要努力將簡單的解決方案重構成你實際需要的內容,但此重構可能比建置所有有疑問的功能來得輕鬆。
在此過程中,另一個需要考慮的問題是,你是否真的知道如何執行。如果你已經進行過多次國際化,那麼你就會知道需要使用的模式。因此,你更有可能做對。如果你處於這種情況,那麼在問題上是新手時,添加預期結構可能更好。因此,我的建議是,如果你知道如何執行,那麼你就可以判斷現在執行和以後執行的成本。但是,如果你以前沒有做過,不僅無法很好地評估成本,而且也不太可能做得很好。在這種情況下,你應該稍後添加。如果你在那時添加它,並發現它很痛苦,那麼你可能會比早早添加它時更好。你的團隊更有經驗,你更了解範疇,而且你更了解需求。通常,在這種情況下,你會回顧一下,看看在有 20/20 的後見之明時,它會有多麼容易。它可能比你想像的更難以在早期添加它。
這也與故事排序的問題有關。在 規劃 XP 中,Kent 和我公開表示我們意見分歧。Kent 贊成讓業務價值成為推動故事排序的唯一因素。Ron Jeffries 在最初不同意後,現在同意了。我仍然不確定。我相信這是業務價值和技術風險之間的平衡。這將促使我至少在早期提供一些國際化以降低這種風險。但是,這僅在第一個版本需要國際化時才成立。盡快發布版本至關重要。如果第一個版本不需要任何額外的複雜性,那麼在第一個版本之後執行這些複雜性是值得的。已發布的執行碼的力量是巨大的。它可以集中客戶注意力、提高信譽,並且是學習的巨大來源。盡你所能讓那個日期更接近。即使在第一個版本之後添加某些內容需要更多精力,也最好早點發布。
對於任何新技術,其倡導者不確定其邊界條件是很自然的。大多數 XPer 被告知,對於某個問題,演化設計是不可能的,但後來發現它確實是可能的。征服「不可能」的情況會讓人們相信所有此類情況都可以克服。當然,你不能做出這樣的概括,但直到 XP 社群遇到邊界並失敗,我們永遠無法確定這些邊界在哪裡,而且嘗試突破其他人可能看到的潛在邊界是正確的。
(最近一篇由 Jim Shore 撰寫的 文章 討論了一些情況,包括國際化,在這些情況下,潛在的邊界最終並非障礙。)
設計正在發生嗎?
演化設計的困難之一在於,很難判斷設計是否實際發生。將設計與程式設計混為一談的危險在於,程式設計可以在沒有設計的情況下發生 - 這是演化設計分歧並失敗的情況。
如果你在開發團隊中,那麼你可以透過程式碼庫的品質來感知設計是否正在發生。如果程式碼庫變得越來越複雜且難以處理,就表示沒有足夠的設計完成。但遺憾的是,這是一個主觀的觀點。我們沒有可靠的指標可以讓我們對設計品質有一個客觀的看法。
如果這種缺乏可見性對技術人員來說很困難,那麼對團隊中的非技術成員來說就更令人擔憂了。如果你是一位經理或客戶,你如何判斷軟體是否設計良好?這對你來說很重要,因為設計不良的軟體在未來修改時會更昂貴。對於這個問題沒有簡單的答案,但這裡有一些提示。
- 傾聽技術人員的意見。如果他們抱怨難以進行變更,那麼請認真對待這些抱怨,並給他們時間來修復問題。
- 注意有多少程式碼被丟棄。執行健康重構的專案會穩定地刪除不良程式碼。如果沒有任何程式碼被刪除,那麼幾乎可以肯定地表示沒有足夠的重構正在進行 - 這將導致設計退化。然而,與任何指標一樣,這可能會被濫用,儘管主觀,但優秀技術人員的意見勝過任何指標。
所以設計已死?
絕非如此,但設計的本質已經改變。XP 設計尋找以下技能
- 持續希望讓程式碼盡可能清晰且簡單
- 重構技能,以便在需要時可以自信地進行改進。
- 對模式有良好的了解:不僅是解決方案,還包括何時使用它們以及如何演化成它們。
- 在設計時考慮未來的變更,了解現在做出的決策未來必須改變。
- 知道如何使用程式碼、圖表,最重要的是:對話,將設計傳達給需要了解它的人。
這是一系列令人敬畏的技能,但成為一名優秀的設計師一直很困難。XP 並沒有讓它變得更容易,至少對我來說不是這樣。但我認為 XP 確實給了我們一種思考有效設計的新方式,因為它再次讓演化設計成為一個可行的策略。而且我是演化的忠實擁護者 - 否則誰知道我可能會是什麼?
致謝
在過去的幾年中,我從許多優秀的人那裡收集並竊取了很多好點子。其中大部分都遺失在我記憶的黑暗中。但我確實記得從 Joshua Kerievsky 那裡竊取了好點子。我也記得 Fred George 和 Ron Jeffries 的許多有益評論。我也不能忘記 Ward 和 Kent 不斷提出多少好點子。
我總是感謝那些提出問題並發現錯字的人。我一直很懶惰,沒有保留一份名單來表示感謝,但他們確實包括 Craig Jones、Nigel Thorne、Sven Gorts、Hilary Nelson、Terry Camerlengo。
進一步閱讀
有關探討我對軟體設計方法的文章,請參閱我網站的軟體設計指南頁面。其中包含觸及演化設計重要面向的文章,例如資料庫的演化設計和服務合約介面。
有關演化設計技術的更多詳細資料,請參閱 Neal Ford 的developerWorks 系列和視訊工作坊。
重大修訂
2004 年 5 月:新增「設計意願」、「可逆性」和「設計是否正在發生」等章節
2001 年 2 月:更新文章,新增有關架構成長、架構師的角色,以及難以透過重構新增的內容等章節。
2000 年 7 月:提交原始文章至 XP 2000,並張貼至 martinfowler.com