敏捷開發與層展論


敏捷開發與層展論

1、什么是層展論(emergence)

諾貝爾物理學獎獲得者卡丹諾夫說得非常清楚:“已經有足夠的經驗表明,不同的聚集層次自然地成為不同科學家群落的研究對象。據此,一組科學家研究誇克(一族亞核粒子),另一組,原子核;另一組,原子;另一組,分子生物學;另一組,遺傳學。在這一序列中,后面的部分是由前面層次的對象所構成。可以認為基本性依次序而遞減。但是在每一層次中總有新的而且激動人心的有效普遍原則,卻並不能由更加‘基礎’的科學自然而然地推導出來。從這一系列中最不基礎的層次開始,我們可以一一列出這些科學中的具有代表性和重要性的結論,諸如孟德爾遺傳律,雙螺旋,量子力學,原子核裂變。誰最根本?誰最基本?誰推導了誰?從這些例子可以看出將科學知識區分等級是十分愚蠢的。寧可說在每一層次的普遍原則中都會呈現宏偉的概念。”

“層展論”是主張各個層次之間“脫耦”與“耦合”相統一的理論。在這個層展論圖景中,由能量級所開拓的層級結構實質上成為一切高級運動形態的舞台。粒子之間在各個能級上的相互作用為各個層級中的各種運動形式提供了基礎性能量來源。而這些能量表現在各種組織結構中,各種運動形式之中。20世紀后半葉蓬勃興起的耗散結構理論、協同學、超循環理論等各種自組織理論,自然地以這個層級圖景為背景,探索了新的運動形態與物質結構如何在這個背景上生成。而在這些自組織過程中,粒子給在各個不同層級所提供的相互作用能量成為創造性能量,它們不斷在各個層級上產生出新的性質,產生出其他層級上不具有的新的相互作用新形態。於是,同一相互作用在不同時空尺度上進行的“層級結構”,在自組織過程中被生成為“層展結構”,無限豐富的新的運動形態、新的結構及其新的性質不斷被創造出來。

呈展論(emergence)又譯作層展論,也叫整體論(Whoism),是描述自然界的一種觀點。其基本思想是客觀世界是分層次的,每一個層次都有自己的基本規律,這種規律是無法用更基本層次的規律來解釋的。呈展論承認客觀現象,並以此為依據找出這個層次上的基本規律,並理解這種現象是如何呈展的。由此可以看出呈展論推導出的理論主要是唯象的。呈展論認為層次間有脫耦,一個整體可能由許多部分組成,但有些性質只有許多部分體在一起時才能體現,而單個部分體根本不具有這種性質。

 

2、為何談層展論

當前在敏捷實踐的幾個層面上,我們忽視了上述的層展理論,而是更傾向於還原論(所謂還原論(reductionism)認為世界上的大量規律都可以由基本規律描述,最終可以由一個“萬有理論”來描述世界上的所有現象)。

1) 需求分析

在進行Product Backlog的分解之中,很多人存在一個誤區:即認為我們需要不斷分解,直到分解到我們一些的不可分割單元為止,認為這樣分割后,最小粒度的就是最明確的。就像我們拿到一輛汽車,把汽車中的每個零件都拆開,然后再獨立加工。這種拆分方法,是符合一個基本原則的:復雜度通過拆分得到降低,從而利於我們在實現時把控。因此拆分這個動作是符合基本規律的。但是不是拆得越細越好就值得探討。這只是一方面。更為重要的一方面是,我們在拆分的同時,卻嚴重忽略了如何把這些零件組合起來。當開發團隊在實現用戶故事時,如果僅僅拿Product Backlog中的用戶故事來做估算和計划,是遠遠不夠的。因為如果缺乏故事之間的串聯,就沒法說清楚故事是如何協作運轉以滿足用戶價值的。換句話說,即使你單個用戶故事滿足了INVEST原則,也不能保證整個功能的完整性和整體價值。而且,系統的分解只是整個需求分析中的一個步驟,在功能間的協作沒有弄清楚之前,任何的估算和計划,都是不靠譜的。仔細想想,我們在整個開發過程中,花在聯調和最后集成測試上的時間是不是多的嚇人,而且這個時間似乎難以控制,往往都是迫於進度壓力就先決定交出去進行系統測試了。

這種方式的需求分析,還會導致另外一個看起來不起眼的小東西:幫助文檔。幫助文檔往往都是交付的最后階段才完成。拋開文檔質量不說,看看內容,其實和還原論很相似。我們寫幫助文檔,往往都是一個菜單一個菜單寫,一個功能一個功能寫,看上去每個功能都介紹了,但用戶拿到文檔和產品,還是不知道如何使用才能解決自己的問題。這是個思維方式問題,即我們認為只要把功能解釋清楚就行了,怎么用來解決問題不是我們的職責。在我參與的某個產品開發中,我們改變了這種做法。采用場景描述方式來做幫助,把數據如何准備、如何TroubleShootting、如何解決問題,采用場景方式描述清楚。這個文檔也是我入司到現在為止,我覺得是最好(沒有之一)的一篇幫助文檔。這其中,也暗含了層展論的思想:即在細粒度的功能層和高粒度的場景層上,其實都有其重要價值,而且二者應該是相互支撐的。

2) 代碼

以前寫代碼,在需求弄清楚之后,編碼的思維方式往往是這樣:先設想一下總體的架構,把功能分成幾個層次去實現,然后拿一條具體需求,去驅動出整體架構代碼。整個過程可能采用TDD,也可能不用,主要看自己在編碼過程中是否有把握。比如如果能夠在腦海中把所有實現都裝下,這樣就會比較有把握。總體下來覺得整個思路還是可以的,也能夠比較清楚。

但其中的問題是,由於在不同層次之間頻繁切換,容易使得分層不那么明顯,而且思維往往會越來越混亂,缺乏一個層次上的整體思考。不像是層展方法論中提到的,先考慮一層,再考慮一層,先在同一層次上思考,然后切到下一層次思考,直到最后的實現層次。這兩種思維方式還是有較大的區別。

在和其他同事結對編程的時候,還發現有一種編碼過程,可能是大部分程序員都會采用的。比如我在函數A中需要用到函數B,它不是這樣寫:

Def A(a,b,c):

    …..

    B(b,c)

既先在A中把對B的調用寫完,再去寫B的實現。而是先寫B的實現:

Def B(b,c):

    ….

這兩種方式表面上看起來差別不大,但思維方式上卻有明顯區別:

即B的接口是站在實現者角度看,還是站在使用者角度看的問題。前者往往會導致更多的變更,因為脫離開使用者,就難以根據需要確定輸入、輸出和異常。后者則相對更加穩定。

此外,如果采用另外一種編碼方式,即把功能分解為一個個細小的具備用戶價值的原子操作,然后通過定義一系列的原子組合規則,這樣就可以采用近似數學推導的方式來構建軟件。這種方式是極其靈活的,也是和層展論思維如出一轍:“無限豐富的新的運動形態、新的結構及其新的性質不斷被創造出來”。

3) 測試

測試也是分層的。從側重於功能的驗收測試,到側重於接口的集成測試,到側重於實現的單元測試,每一層關注的焦點是有區別的。可以這樣說,僅僅依靠高覆蓋率的單元測試,並不能保證驗收測試一定能一次性通過。因為除了單元之外,還有單元之間的關系。可以詳見筆者編寫的《開發者測試》一文。

而如果我們更進一步思考,是不是可以對一些基本測試進行提煉,形成一套測試語言,從而在語言層面進行高層測試用例的編寫。這樣組合出來的測試體系,將更具備靈活性。從這個意義上來講,層展論與測試的分層論基本原理是一樣的。

3、層展論如何實施

1)  需求分析中如何應用

在需求分析中,我們不再僅僅關注於功能的分解,而且也更關注於功能的組合。兩者要能夠有機結合。分解的粒度要合適,而且能夠虛擬場景的方式把用戶故事進行串聯。詳見筆者編寫的《虛擬場景與用戶故事在敏捷開發中的應用》一文。

在進行實際估算和計划時,對於用戶故事的組合也要給基本的估算,或者能夠在一個較高層面上進行功能估算。如果現實操作中僅以用戶故事為粒度進行估算,那么對於每個較大功能,能夠給予聯調故事卡,從而保證一定的聯調估算;也可以把聯調估算折算到各個用戶故事的估算之中。

2)  代碼中如何應用

這里借用孫鳴老師寫的《程序設計》學習心得中的一段關於WishFul Thinking的描述:

    “我們應該如何以problem-solving為導向,識別出問題的核心,圍繞核心問題的解決來演化以及延伸出整個解決方案呢?這里用到的思維模式可以稱之為:Wishful Thinking。Wishful thinking可以幫助我們“從問題本身層面而不是從實現層面考慮如何表達問題”,我們可以假定所有需要的輔助的東東,有個神一樣的助手都幫我們做好了,這樣,我們就可以用“聲明性”的方式來描述問題的解決方法,比如:“做這個,做那個。。。”而不是“如何做這個,做那個”。在應用這種方法時,我們將需要解決的關鍵問題用“聲明性的”簡短的話來描述,然后看看我們的手邊、使用的語言中是不是有稱手的工具來幫助我們表述這個問題如果沒有,就需要我們自己去制造”。

這和ArmStrong的說法類似:程序的結構要嚴格保持與問題的結構一致,即從問題到程序的映射比例為1:1。此時我們就說程序與問題是同構(isomorphic)。

Wishful Thinking的具體做法是:

1.    充分理解問題領域,列出概念清單

2.    精煉這些概念,去除冗余,合並一些本質相同的東西,看清問題的本質;

3.    從最簡單的解決方案、數據結構、表示方式着手,直到發現這樣的實現不能適應於問題,再逐步向復雜一些的方案過渡。

4.    在信封背面做最初的評估,對初始解決方案的可行性有個正確的認識,避免無用功;

5.    優化解決方案, 打造效率可行的方案

6.    稱手的工具

7.    分離不同方面(關注點)的代碼,讓解決方案清晰,整潔

在把握概念本質性后,對於領域建模,衡量模型好壞的標注,可以從Simple,Generic和Composeable入手。具體例子可以看布局練習以及正則表達式練習。

最后,看看鄧輝關於Domain Model的說法:

    “建模時最重要的一點就是要弄清楚事情是如何“計算”的,並選擇出最貼切於表達這個計算的數據結構和算法。在建模時,有個常見的誤區就是:直接從問題描述中找出“膚淺”的概念和算法,然后運用一堆設計原則和模式去改進。”

這實際上是對層展論的進一步闡釋:不管分多少層,層與層之間如何組合和聯系,始終都要圍繞問題的本質來表達。

3)  測試中如何應用

在實現層面,需要結合TDD和WishFul Thinking。如果完全采用WishFul Thinking,它需要一層層講解到最底層,才可能使得測試用例通過,這個過程可能會相當長。因此是否先通過最簡單的用例,把整個WishFul Thinking的邏輯層次驅動出來。再逐步補充起除最頂層之外的其他層次?這個需要思考。

此外,是否WishFul Thinking就不需要TDD了呢?還是這樣做之后,我們的思路更加清晰,從而避免了采用大量測試來保證程序正確性的做事方法?

在這次高級設計培訓中,Re的那個問題,是先lit,再star,每次都是TDD+wishful。這樣做反饋周期和節奏感比較強。

最后的思索:不要為測試而測試!測試的目的是什么?如果我對某件事情特別有把握,為什么要浪費時間去測試?

具體測試的例子,可以參見Coffee Maker,里面對如何組織測試的TSL(Test Specification Language)有很多很好的啟發。

   

 

 

 

 


注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com