2017年2月20日 星期一

the DevOps journey (1) - 敏捷開發不相信時程預測?

這一篇,我們來討論敏捷開發中怎麼看待時程預估,以及迭代開發的重要性…

到底專案時程能不能預測?

這是一個常常困擾初踏入敏捷開發領域的新手的問題。

你一定聽到過有人說(甚至,其實上一篇推薦的Martin Fowler的文章中也提到過),敏捷開發不太相信可以進行準確的時程預測,我特別用『預測』這個字,而非預估。中文很有意思,這兩個字很接近,但有那麼一點點的不同。

前面提到過,既然真實世界裡面的需求根本不可能固定,開發人員的素質(每個人每天的產出)也不太可能統一,那我們幾乎已經宣告無法掌握軟體開發專案中,最重要的兩個變因,那這樣怎麼可能精準的預測出開發時程呢?

Martin Fowler在早期的文章中,幾乎是直接告訴你,預測是不可能的。

但這件事情非常弔詭,大概所有開發人員都明白,在需求不確定的狀況下,要精準的預測專案時程、計算出人天數,是幾近不可能的事情。但好笑有趣的地方就在於,幾乎所有的軟體專案的業務或PM,都會要求你在專案起始前,在一切模糊的前提下,估出人天數以便於報價

壓在合約裡面的驗收日期和報價耶!? 難到不需要更詳細的資訊以便於精細計算嗎?

這是繼上一篇提到的軟體開發迷思之後,另一個超級經典、行之有年、卻嚴重違反常識/常理的軟體開發迷思。同樣的問題又來了,難道從來沒有人覺得哪裡怪怪的嗎? 我相信有,但你會碰到各種壓力,告訴你整個業界都是這樣幹的,你區區一個程式設計師想改變這個慣例? 不可能。

因此,開發人員只能習慣性的在時程預估裡面保留一些buffer,業務/PM報價時再加一些Buffer,然後客戶的採購砍一些作為折扣,done,成交。後面就看彼此的運氣了…

不能預估,怎麼辦?

這篇文章一開始的那張圖很貼切,它描繪出了理想狀況與真實世界之間的差異,上一篇說過,兩個軟體專案的需求不可能完全一樣,因為完全一樣你就根本不需要新的專案,買個套裝軟體或直接copy一份即可。因此,我們知道每一個軟體專案都是新的開始,既然是新的開始,沒做過的事情要預估時間,這本來就是一種賭博

這也是軟體開發和工程專案差異很大的地方,傳統的工程專案施工較容易預估人天,因為施工方法固定,需求固定,常常只是在可以控制變因的狀況下,重新做一次而已,但軟體開發不是,每一個專案都是一場新的冒險。

我常開玩笑的跟業務說,你真要我這樣報價,乾脆就隨便猜一個數字,你讓我在模糊的狀況下進行時程和成本的預測,估出來的金額,跟你用猜的其實也差不了多少。需求越模糊,我猜(給出)的範圍就越大(例如,150萬~300萬之間,這是我的預估,你在中間隨便選一個數字報價吧)。另外,越有經驗的開發人員,因為考慮的越多,估出來的時程就可能越保守(這某種程度上解釋了,為何同一個需求,新手估出來的金額往往比較低)。

不過,在台灣軟體專案的報價現在已經變成一種藝術,而非可以討論的科學方法,如果可以,我們當然希望能夠採用time-materials的報價,但往往甲方很難接受,如何解決? 在這邊我們先跳過這個議題,(如果有興趣可以私下問我),我們回過頭來談談,如果開發時程不能預估,那專案管理該怎麼進行? 答案就在迭代…

用迭代開發解決問題

敏捷開發中的迭代行為,簡單的說就是把一整個開發循環,切成一個一個迭代(iteration),如果採用Scrum(迭代開發法的一種),那每一個迭代(Scrum稱為Sprint)都需要產出一個潛在可交付產品增量(Potentially Shippable Product Increment ),這個字很有趣,注意『潛在可交付產品增量』並非半成品,也不一定就是一個大產品的一小部分功能,更不是一個功能的某一部分(例如先做該功能的UI、或是先完成該功能的後端API)。

很多新手分不出什麼是潛在可交付產品增量,常常跟prototype甚至半成品搞混。然而,潛在可交付產品增量根本就是迭代開發的重點,每一個迭代的最主要目標(甚至接近是唯一目的),就是產出正確的潛在可交付產品增量

潛在可交付產品增量不是半成品、不是雛形、不是部分功能,而是一個可提供客戶價值(Value)的最小成果,搭配MVP的概念更容易理解,我們參考底下這張很經典的圖:

常有人誤會這張圖所要表達的意思。以為MVP(Minimum Viable Product)是說,客戶要一台車,你就先給他一個滑板應付一下…不,不是這個意思。

MVP是最小可行性產品,不管是軟體專案或是軟體產品開發,只要面對需求可能常常改變、無法控制,那採用迭代開發與潛在可交付產品增量(或MVP概念),都是一個非常好的技巧。

上圖中MVP的意思是,客戶本質上要的是一個交通/運輸工具(這是Value),但往往腦袋裡直覺就會想到是一台車,卻又說不清楚是什麼車?

『車』這個需求描述很空泛,是雙門? 四門? 多少馬力? 幾輪? 甚麼顏色? 傳統瀑布式專案中的系統分析(SA),往往企圖在一開始就想把所有的細節談定,並且要求客戶,一旦定下來,你就不能改

然而,現在這種『一旦定下來,你就不能改』的要求,客戶越來越不能接受,因為市場瞬息萬變,不是客戶故意找你麻煩想變,是客戶的客戶(或市場)逼著客戶變。

因此,敏捷開發和MVP鼓勵你不去先談『車』的細節(features),而是先專注在你的目的,我們知道客戶要的是一個交通/運輸工具,OK,我們就在每一個迭代(也許2周、也許4周)中,一邊開發,一邊持續釐清需求,逐漸為客戶打造出符合他心裡期待的『交通/運輸工具』。

因此,第一個版本是滑板,它不很完美,但能帶著客戶從A點到B點,是一個堪用的交通/運輸工具,它有Value(注意,這很重要),雖然確實還有很大的改善空間。不過,由於客戶看到了實體,客戶的腦袋開始更清楚的知道自己要的是甚麼,以及(特別是)不要的是甚麼。我們的開發團隊每一週持續跟客戶溝通,持續調整對需求的認知、持續蒐集更新需求、持續開發、持續改善,每一段時間都產出一個更貼近客戶要求的成果(但別忘記,每一次產出的成果,都要能夠運輸,都要有Value),直到達成客戶心中100%的預期 -- 這才是迭代開發,這才是潛在可交付產品增量。

這才是迭代開發、潛在可交付產品增量,與MVP(最小可行性產品)的意義。

好,你現在可以回頭對照上圖MVP的上半段,傳統的瀑布式開發則會先蒐集好詳細且完整的需求,然後先產生出輪子(不能運輸、沒有Value)、接著產生出底盤(不能運輸、沒有Value),過了很久很久以後(也許半年也許一年),才產生出一台(工程師心裡認為)完美的車子。然而,這時拿給客戶(客戶第一次看到),有很大的機會,客戶會跟你說:『他不能用』,因為他心裡想的車子和你做的不盡然相同,更有可能,他的想法改變了,或是他的客戶的想法改變了…你沒有機會持續修正,沒有機會持續調整,因為你的開發團隊只看規格書,被要求要stick to the plan。

經過幾年的敏捷開發專案,你會發現,需求是不可能在一開始就釐清的,即便一開始就真的讓你釐清(代價很高,多半要花費很多人力),隨著專案的進行,客戶端人員的異動、市場的改變,需求也會一直在變,往往半年後,一開始談的需求現在已經不同了(前面花時間釐清的需求,撰寫的規格書,全浪費了)。現在你知道,強調sitck on the plan的傳統計畫導向式開發,不具備這時代需要的隨時改變、隨時調整的特性。

從這邊,你會開始看到迭代開發,與傳統計畫導向開發,兩者在本質上有著很大很大的差別。

這樣的開發方法怎麼解決時程問題?

好,我們終究要回頭面對預估的問題,前面提到過,預測精確的時程幾乎不可能,因為大多數的軟體開發根本就是一場冒險,由於所有的事情都是新的,以前沒做過,就算預估也是猜測。加上,客戶的需求無法固定,專案中可能會遭遇哪些問題你也無法預測,所以,精確的預測哪一天會完成根本不可能。

但這不代表我們無法『預估』。

當你用上面提到的這樣的『MVP』、『潛在可交付產品增量』、以及『迭代』的概念進行軟體開發,你就會發現,雖然無法預測哪一天完成,但每一次交付產出的時候(也許每隔兩周、也許每隔一個月),你和客戶雙方都會更清楚的知道,距離雙方的理想目標還有多遠,雙方認知的差距還有多大,每一個迭代都會靠近最終成果更近一點,都會縮小彼此的認知落差,每一個迭代的預估也都會越來越貼近真正的結案時間。

也就是說,我們不能在專案尚未開始進行前,就預測出專案需要的精準人力或完成時間,但我們可以隨著專案的進行,依照前面的經驗和花費過的時間(P),來推估後面還需要花多少時間(E)…

上面這張圖很貼切,我們在專案開始點(B),因為還沒開始做,想要去預估專案完成所需要花費的人力和時程是非常非常困難的,估不准是理所當然。但,我們透過迭代開發、陸續蒐集需求、持續與客戶確認、持續產出潛在可交付產品增量、持續調整更正需求…經過了一段時間,到了今天(T),這時,過去花費的時間(P)就成為一個依據,透過這個依據,我們可以更合理的推估出,還需要多少時間(E)。

因此,我們得到一個結論:

專案開始前幾乎無法精準預估時程,但隨著專案的進行,我們得到的資訊(需求、已花費時間P)越來越多,我們預估的(E)就會越來越準確,只要我們持續修正這個預估

理解嗎? 我再舉一個例子你應該會更容易掌握。

你一定用過GPS。

以前剛出來的導航系統很笨,你輸入給它你要去的目的地(F),以及開始位置(B),它幫你計算出最佳路徑,然後就叫你依照這個最佳路徑走,不管這個路徑中的路況是否有問題,可能出了車禍導致交通堵塞,也可能前面正在施工根本無法通行….但,以前的導航只會叫你照著這個路徑走(stick to the plan),因為它認為這是計算過後的最佳路徑。

但,最近幾年的導航系統都很聰明,還可以連上網,它在幫你計算出最佳路徑之後,還會隨時觀察交通狀況(例如Google導航會有即時路況),當它發現前面路段似乎有嚴重塞車時,可以立即重新計算出新的路徑,讓你用更短的時間抵達,這就是自適應性,也就是應變能力。而傳統的導航則是計畫驅動式導航,如同過去的瀑布式開發,一旦SA團隊把規格書開好,就拍拍屁股閃人進入下一個專案了,至於開發過程中發生什麼問題?很抱歉,不關我的事(保重,我在另一個案子了)。

以前的軟體開發大多是是計劃導向,我們要求大家遵循計劃,制定計劃的人並不在乎你知不知道目標,也不在乎你要不要隨時依照路況去應變。

之所以過去可以行之多年,是因為早年路況良好、變數不大、不會常常塞車。但,現在時代不同了,現在路況變幻莫測、瞬息萬變,不能夠再依靠以前的計畫導向,而必須強調目標導向,強調自適應性(提升團隊的應變能力)。

這是敏捷開發和計畫驅動開發最大最大的差異,至於時程預估,你會發現,現在Google導航的預計到達時間幾乎都非常準,且你越靠近目的地,算出來的結果就越準。是了,它會參考先前的行車資訊與路況持續修正,和過去舊版的導航只依照目的地剩餘公里數和平均速度來推估,有著很大的不同,沒錯,這是敏捷導航是也。

最後,分享一張最近從FB上看到的圖:

(引用的原始出處為https://www.facebook.com/jaceju/posts/1291860560895634)

如果你覺得這有點怪怪的,為何依舊接受計畫導向的專案管理?

------
這一篇,我們釐清了迭代的重要概念,接著,後面我們會陸續介紹該如何做? 用甚麼工具來做?

------------------------------
本系列文章索引位於 http://studyhost.blogspot.tw/2017/02/the-devops-journey-index.html

沒有留言: