Categories
程式開發

區分敏捷開發中未解決的問題:過早出現的和可預見的


本文要點:

  • 敏捷的力量在於應對未解決的問題,但同樣的力量也會導致技術債務和減少產品價值。
  • 根據本質的不同,未解決的問題應該分為兩種:過早出現的、可預見的。
  • 過早出現的問題和可預見的問題,二者之間的區別在於強調重要性還是可能性。
  • 重要的小改變,可以讓敏捷開發走得更遠。
  • 背後的原則,可以彌合團隊心理層面的距離,調和架構師與開發人員的差異。

如今的敏捷出了什麼問題?

敏捷開發讓人感覺良好,開發人員很喜歡它,但有時候它會出問題。這一點,我們都能感受到,並對其展開爭論。

很多敏捷項目隨時間推移變得不再成功。比如出現拖延,技術債務不斷累積,進度放慢,士氣低落。開發人員已經很努力了,但每個衝刺交付的價值卻在不斷減少。

突然,容易乾的活都解決了,剩下的待辦任務列表(backlog)中滿是龐大、必要、而且對於利益干係人沒什麼價值的條目。團隊與利益干係人開始衝突,項目拖拖拉拉,甚至有可能功虧一簣。

有人說,更嚴格遵守敏捷的核心原則可以避免此類情況。的確如此。但要想做到敏捷和自我管理,每個人必須可以激勵自己,並且嚴格遵守規則。規則越嚴格,團隊越大,紀律感就越容易削弱。

(關於恢復核心價值觀,可深入閱讀免費電子書《理解敏捷價值觀和原則》。 )

還有什麼其他辦法?

應對潛在原因

沒有解決的問題屬於待辦任務列表。理論上,產品負責人要處理待辦任務列表中的所有條目,去除無關緊要的,將最重要的排定優先級,放入衝刺中,直至清空待辦任務列表,項目完成。

但在實際情況中並非如此。待辦任務列表會一直增長。它收集的工作會與技術債務和無法輕鬆處理的“燙手山藥”一起,進入等待狀態。

開發人員認為:待辦任務列表相當於洩洪道,讓他們有事情可做。敏捷指出:對於你還不了解的東西,或是目前不需要的工作,先放在待辦任務列表裡,然後暫時置之腦後。有必要時,它會再次出現。很多時候,這麼做沒問題。敏捷的力量就在與此。

但是到了未解決的問題再次出現時,燙手山藥已經變得太燙了,難以處理,技術債務已經變得過於昂貴而無法支付、解決。可用的資源已經根本不足以支持這些工作。

只要在敏捷的做法中加入一些關鍵的理念,做出一些重要的小改變,就能避免類似問題。

其根源是系統層面的弱點:敏捷方法認為,所有未解決的問題,都是過早出現的問題。沒有這麼簡單,有些問題是可預見的。

過早出現的/可預見的

有兩種未解決的問題,它們有本質上的不同。

過早出現的問題

過早出現的問題是當下不需要擔心的、未解決的問題。現在去管它們就是浪費時間。可以確定:時機合適,它們自會再度出現。

根據預測,過早出現的問題有四種:

  • 變得無關緊要:比如一個腳本運行起來很慢,但很少運行,幾乎無人注意。它是沒有解決,但不值得任何人的時間。
  • 保持不變:比如改變窗口大小就會持續閃動的 UI 界面,確實不好看,但不會阻礙關鍵流程,而且不管什麼時候解決它,整體的工作量沒有變化。
  • 變得容易:比如復雜的配置 UI 界面。等到後來,你會更深入了解項目,而且更好地理解數據模型。你有更多可重用的 UI 組件,是因為其它原因加進來的。難度就會隨項目發展降低,再穩定在某個最低程度上。當你讓它在待辦任務列表中慢慢變成熟時,這就是你所期望的結果。
  • 消失不見:比如某個複雜的功能特性需求,再過六個月,都無法確定用戶是否還需要。不需任何工作就能解決此類問題。

區分敏捷開發中未解決的問題:過早出現的和可預見的 1

當環境發生變化,或是過早出現的問題發生變化時,它就會再次出現。將某個問題視為過早出現,有點賭博的意味。對於很多問題來說,先放在一邊是正確選擇。

可預見的問題

可預見的問題是會隨時間推移變得更難處理的問題。技術債務和燙手山藥就屬於它們。敏捷會產生很多此類問題。

越早處理此類問題越好。如果你總是無視它們,總有一天,可預見的問題會變得超過“可行性邊界”(feasibility limit),過於龐大而無法解決。

經驗表明,在一定時間內,難度會緩慢增加,當環境發生變化,問題難度就會陡增。

區分敏捷開發中未解決的問題:過早出現的和可預見的 2

可預見的問題有兩種:

  • 直接:問題本身就是造成問題的根本原因。比如執行緩慢的門戶初始化腳本,在不斷增長的數據庫中費力地運行。
  • 間接:根本原因不在於造成問題本身,而是導致其它地方問題惡化。比如侵入式框架(intrusive framework),依賴它的代碼越多,它導致的衝突越多,以後就難以去掉這個框架。

要想判斷一個問題是否可預見,需要一些預測技巧:

  • 對於表面原因和根本原因的感覺
  • 理解為什麼某些模式會以後導致特定問題
  • 考慮各種場景,估算它們的概率
  • 預測哪些環境有可能變化,以及何時變化
  • 在問題達到可行性邊界之前,你還有多少時間

這些技巧一般要靠架構師具備,而且需要跟每天瘋狂寫代碼的工作有點兒距離。

可預見的問題有一個或是多個 可預見的場景。你可以預測到:如果不行動,情形會如何惡化。你可以預測到:當特定條件變化時,它如何跨越可行性邊界。

會隨時間惡化的問題總是可預見的,正是由此得名。

架構師的職責,就是要判斷哪些問題是過早出現的,哪些是可預見的。

敏捷中可預見的問題

敏捷的本質缺點在於:所有未解決的問題都被視為過早出現的問題,不存在可預見的問題。

開發人員相信:當工作不那麼繁忙的時候,他們可以處理待辦任務列表中的工作。同時,可預見的問題確實存在。既然隱藏在待辦任務列表中,工作任務如何改變是不可見的。有些保持不變,有些變得簡單,或者不再重要,或者消失不見。但是有些會變得更糟糕。

在最不恰當的時候,問題的困難程度會突破可行性邊界。這些問題從墳墓中成群用處,變得太大而無法解決,讓所有人都感到恐懼。

資金充足的組織,可以用錢解決此類問題。上更多服務器,找來更多開發者。可行性邊界會再次提高,此後再次發作。沒有太多資金的組織,項目就會失去創新能力,逐漸過時,最終死去。

架構師應該為敏捷團隊做的事

除了日常職責之外,架構師應該時常瀏覽待辦任務列表,並將問題標識為過早出現的和可預見的;同時說明可預見的場景、可能的情境變化風險和可能造成的影響。

架構師應該選擇最迫切的、可預見的待辦任務列表條目,並產出可以解決它們的設計。然後將這些設計扼要轉化為日常工作任務。設計應該足夠成熟,可以切分難點,變為能夠直接動手開工的任務。

設計是有必要的。把一個老問題直接丟回給程序員,又沒有任何計劃,這會造成壓力、阻力和抵抗。問題在待辦任務列表中出現是有原因的,可以預見也是有原因的。

為可預見的問題排定優先級很複雜,涉及到多個層面,包括:價值、工作量、破壞程度、達到可行性邊界的概率和剩餘時間。這些參數很難量化,最好由經驗出發加以評定。

一條根本原則是:最“間接”的可預見的問題應該首先解決,因為它們造成的麻煩最嚴重,而且到處都是,先解決它們可以釋放出資源,以解決優先級稍低的問題。

敏捷角色中的信任

程序員應該相信:那些一旦忽略就會變得惡劣的未解決問題,有架構師可以搞定它們。有必要時,這個架構師可以讓問題再次出現在程序員的日程中,而且提供了相應設計,並且規劃了優先級,所以不會產生壓力。

唯一要注意的是,程序員不能過度依賴這個“服務“,不能把待辦任務列表當成垃圾堆,把所有尚未認真想清楚的問題都丟進去。

補償產品負責人?

處理過早出現的問題和可預見的問題,這是不是意味著架構師在做一個糟糕的產品負責人的工作?並非如此。這種方法將待辦任務列表變得清晰、可行,產品負責人可以利用其中的信息規劃衝刺迭代。

一般來說,產品負責人無法承擔識別這兩種問題的責任,他們缺少相應的深入技術知識,而且存在利益衝突:在壓力時刻,保證客戶和團隊開心,這是頭等大事。產品負責人不應該去刨根問底翻舊賬。

所以,敏捷可以成功

用上述方法,敏捷就能像期望的那樣成功:成為可持續的開發方法,讓開發人員的生活可以承受得了,同時不必積累技術債務和燙手山藥。

必須付出的小代價是要認識到:只有開發人員,沒有人能承擔架構師的角色,這樣的自管理團隊不可持續。

(深入閱讀:《也許敏捷才是問題》《敏捷宣言:軟件架構師角度的思考》

還有更多東西要考慮

這個過早出現的和可預見的問題分類原則還涉及更多主題。

總而言之,該方法是要具體化一種沒有說出的張力——短期內寫代碼並帶來成效,長期內的可維護性和可演化性,這兩者之間的張力。

(深入閱讀:《構建可演化的架構》一書,特別是第 2、6、8 三章。 )

開發人員的心態

所有架構師都知道:開發人員從完全不一樣的角度對待項目,這會導致很多誤解。使用過早出現的和可預見的原則,有助於彌合差距。

待辦任務列表作為分散注意力的垃圾堆

程序員是手藝人,手上忙著各種事情。他們希望干擾越少越好,從而保持“心流”狀態。程序員善於將乾擾從自己的思維空間中趕出去。

為了讓代碼工作,他們有無數的問題要解決,再加上一大堆問題,只會造成壓力。對於偶然出現的問題,程序員需要待辦任務列表將它們置於一邊。

架構師有時候會認為這是置問題於不顧。但程序員覺得這麼做沒問題。此時缺少的是整體掌控,需要有人可以過濾可預見的問題,在以後的開發週期中再放進來。

這樣的待辦任務列表掌控不應是程序員的職責,他們還有日常開發工作。否則就會導致利益衝突和壓力。此類壓力會觸發絕望,使得大家想從頭重新開發,拉低整個團隊士氣。

不去評判未解決的問題

程序員相信自己的編碼能力,相信自己可以解決遇到的任何問題。這是他們的日常工作。

在程序員看來,架構師的設計讓他們感到被評判,似乎他們的編碼能力不足,然而正是他們在做所有的實際工作。但是架構師的意圖是中性的:有了好設計,程序員的編碼能力可以走得更遠。

在日常對話中引入過早出現的和可預見的問題分類原則,可以讓此類討論免去評判的意味。這與誰工作效率低下、能力不足、誰更好或是更聰明無關。關鍵是要判斷會發生什麼問題,從而加以預防。

當待辦任務列表中加入新條目時,如果程序員可以針對可疑的可預見的問題附加警告標籤,並添加可預見的場景,對大家都有幫助。

將框架作為可預見的問題

程序員會不小心將框架放到代碼庫中。他們遇到某個問題,而且發現很難解決,那就看看還有誰也碰到類似情況。找到一個框架,沒問題,看上去挺好,不錯,繼續寫代碼。

架構師認為,框架是結構性的決策。程序員認為,框架是可以直接用的代碼。如果程序員每次選擇框架的時候,都要暫停衝刺迭代,保證選擇過程深入徹底,那他們什麼都做不了。

對於架構師而言,匆忙決策會減少可選項。常常出現的是,過早選擇框架會在後面讓人失望。一旦用上框架,再想去掉就很麻煩。如果過了很久再說,那就完全不可逆了。

這是可預見的問題。框架選擇應該在衝刺之前完成。提前選擇框架,應視為可預見的問題的解決方案。

減少對英雄的依賴

敏捷希望程序員在面對難題時充滿勇氣:團隊是自治的,可以相信的,知道該做什麼。實際上並非總是如此。一般來說,隨著項目進展,利益干係人的信任會不斷銷蝕,當交付的產品成功時才能恢復。

信任銷蝕得越多,團隊要想說服鬱悶的利益干係人,讓團隊開發“模糊”的任務,則需要的勇氣越多。慢慢地,對於很多人而言,就不再具有這樣的勇氣。他們不願意提出難以解釋的討論主題。逃避會讓可預見的問題向可行性邊界慢慢前行。

和利益干係人討論時,說明某個問題是可預見的,可以去掉勇氣的因素,讓其成為更中性的議題。能做到以下幾點就更容易:

  • 需求明確
  • 不做評判
  • 結果有益
  • 每個人都能理解置之不理的後果

(深入閱讀:《敏捷組織中溝通勇氣的重要性》

開發人員抵觸設計

架構師希望程序員理解、支持自己的設計,並且能和自己辯論,發現其中的潛在問題,同時積極提出想法,加以改進。有價值的設計應該經得起健康的辯論。過早出現的和可預見的問題分類原則能夠讓辯論更有價值。

抵觸複雜性

如果程序員認為某個設計太過複雜,他們就會抵觸,同時相信更簡單的解決方案更好。如果存在更簡單的解決方案,那當然再好不過,趕緊用起來!可惜,複雜方案常常是有必要的,因為簡單方案力有不逮。

程序員可能公開抵觸,抑或消極聽命,拒絕主動貢獻想法。這是有成本的,會帶來更多潛在設計問題、寫代碼時更多返工、將來更多要修復的 bug。

通常,架構師的理由是考慮未來遠景和設計原則。但如果去跟程序員解釋這些整體圖景,那就過於龐大而有些雜亂了。越想講清楚,程序員越是固執己見。

抵觸設計常常伴隨這些情緒:失望、畏懼、感到別人更聰明、或是被奪去自主權。光靠討論很難克服,因為程序員總是用技術論點討論技術和情緒話題。此種討論難以捉摸,而且無人受益。架構師應該一起來預防對設計的抵觸。

抵觸設計中的潛在問題

設計的問題會增加抵觸心理。人會犯錯誤。架構師也不例外。設計越複雜,架構師就越有可能漏掉某些東西,留下設計問題。

程序員認為:遇到潛在問題,就得丟棄剛剛寫好的代碼,還增加了複雜性,錯過截止日期。設計潛在問題常常難以察覺,而且很不容易解決。程序員從經驗出發,擔心越是複雜的設計,越容易遇到潛在設計問題。

為什麼展示整體圖景沒有作用

程序員說:“我看不清大局”,或者“你把這個弄得太漂亮了”,他們是在說:如果他們找不到一個做得這麼複雜的合理的理由,那就不存在合理的理由。

用展示整體圖景來說明你的選擇,這麼做很誘人,但是會有反效果。

程序員認為:雄心勃勃的設計,就好比架構師用大油漆滾筒畫出了西斯廷天頂畫的輪廓,留下無數細節,等著程序員去完成。

區分敏捷開發中未解決的問題:過早出現的和可預見的 3

左:架構師如何看待設計 右:程序員擔心自己要做的事情

展示整體圖景會讓程序員崩潰,因為他們看到有那麼多東西,就會想:“天啊,我怎麼做的了這個。”龐大的設計常常是人腦海中難以容納的,還得擔心存在潛在設計問題。

如果你的龐大設計包括未知因素,那就更糟糕了。存在不了解的東西,在架構師設計過程中很正常。在程序員心中,想到糟糕的客戶需求以及自己要為之寫出的代碼,自然會將未知因素轉換為不確定性、更多要解決的問題、更擔心潛在問題,從而錯誤認為:架構師不知道自己在幹什麼。

如果程序員想了解大局,那就要找到根本原因。最好只跟有經驗的人分享龐大的整體設計,他們不會暈頭轉向。

為什麼抽象的討論沒有意義

架構師認為,使用某些抽像是必要的,由此就不用在各步驟之間想得太多。當然,這是架構師的必要能力。而且很容易就會向程序員解釋這些設計抽象。

程序員認為原則和設計模式就像汽車:它們都能把你帶到目的地,那為什麼要花錢去買最貴的呢?

與程序員討論抽象設計,會將討論帶到品味上,或是爭論誰能產生“最乾淨”的抽象。兩者都不會帶來進展。

為什麼業務原因不起作用

架構師認為:某些技術決定是出於商業原因。比如,能讓商業合作夥伴更輕鬆的技術能力,會讓組織成為市場領導者,而不是偏安一隅。架構師應該參與此類決策討論。

業務原因不能說服程序員。相反,他們會把討論轉向商業人士的不理性頭腦、產生的無理需求,從而否決架構師設計的合理性。

程序員畏懼商業元素。過去與合作夥伴的經驗,常常導致程序員要去收拾爛攤子,由合作夥伴要求無度而且能力不足的 IT 人員留下的爛攤子。程序員認為:商業上的成功,意味著由一意孤行的管理者提出不切實際的要求,導致自己被迫做出讓人後悔的應急方案,而且總被事故推著走。

很多程序員不喜歡商業、銷售和市場,無論是人還是相關主題。三十年的呆伯特漫畫可以告訴你為什麼

那麼,到底該怎麼做才有用?

從整體設計產生可執行的設計方案,避免論及宏大的、深奧的、未知的因素,這是架構師的職責所在。

設計應該從一系列你想解決的、可預見的問題和場景開始。這樣一來,架構師就能說明為什麼簡單方案不行,或是無法堅持足夠長時間,因此不能使用。

最好能寫下多個可預見的場景,讓它們彼此關聯。為什麼?可預見的場景可以將抽象和相關問題轉變為具體例子。如果只有一個場景,程序員可能會傾向於找到某種簡單的權宜之計,只解決這個場景的問題,而不是它代表的整個問題類別,從而低估問題範圍。

有些相關問題很明顯,但是過早出現,那就要歸類為“不在範圍之內”。

列出過早出現的和可預見的問題的設計列表,可以讓程序員知道不要擔心什麼, 應該重點關注什麼。這讓架構師在抵觸到達沸點之前,可以中性地展開設計辯論。

對於程序員來說,由過早出現和可預見驅動的設計更容易理解,更易於尋找潛在設計問題,更便於找到改進方案。這麼做的同時,還不會產生復雜設計帶來的更多壓力、不確定性和過多問題導致的負擔。

這還能為程序員留出更多空間,讓他們可以自己決定,同時保證他們深入了解架構師的意圖,不需要過多詳細需求,還能讓設計切合當前衝刺。

(觀看關於設計抵觸、前期大型設計、衝刺中交付架構的視頻。 )

整而合之

還得聊聊可能性

現在,討論從爭辯一個問題的相關性轉移到了可能性。它有多大機會發生?情境改變的可能性有多少?還需要多久,它會達到可行性邊界?

為了簡化,可預見的問題的可能性可以分為三個級別:

  • 不可避免:必將發生,必須行動
  • 火災風險:難以發生,一旦發生,必須有類似自動噴水設備的措施
  • 流星撞地球的風險:幾乎不可能發生,而且不值得去修個太空盾牌那樣的防範措施

必要的同理心

你必須理解程序員的心態,看到在新的做事邏輯生效之前,為什麼會發生某些事情。突然就將問題標識為“可預見的”,會讓人覺得過於生硬,讓人覺得在評判程序員的腦子、工作素質或編碼能力。開發人員也許會將未解決的問題作為秘密保守,自己承擔相應負擔,就像程序員們一直以來自然而言的做法。你會用一個問題取代另一個問題。

(深入閱讀:《同理心是一種技術能力》。 )

如果程序員覺得說出想法不是問題,討論未解決的問題就不會覺得自己能力不行、懶惰或是不上進。未解決的問題是努力工作和良好意圖的中性後果,搞定麻煩的那些問題正是架構師的職責。這樣敏捷就能起作用了。

(深入閱讀:給架構師的提示,包括“垂直分片”建議,可以幫助大家概要了解可預見的問題,同時不會讓架構師聽上去像個末日預言家。 )

那麼關於留出更多選擇呢?

留出更多選擇,這是架構師的工作:你無法預言,所以你要讓自己有更多選擇。聽上去似乎與過早出現的和可預見的問題分類原則直接衝突。

實際上,留出更多選擇是積極地安排你的未解決問題,這樣你就可以將盡可能多的問題變成過早出現的問題,只剩下盡可能少的可預見的問題。

架構師能做的最有用的事情,就是解決一個可預見的問題,該問題可以將很多其他可預見的問題變為過早出現的問題,讓你有更多選擇。

結論

引入過早出現的問題和可預見的問題之間的區別,是一種全新的思考和討論習慣,它可以:

  • 讓燙手山藥和技術債務變得可以討論,同時不會讓程序員因為壓力而崩潰
  • 讓架構師承擔職責,應對那些因為沒人管就會失控的問題
  • 有助於以中性的方式討論設計,每個人都可以理解
  • 針對更加複雜但有必要的解決方案,讓大家都能更好地了解
  • 預防潛在設計問題和 bug

區分過早出現的和可預見的問題,可以讓敏捷成為本應成為的可持續的開發方法。

作者介紹

Bas Groot 住在阿姆斯特丹,已經創業 19 年。他開發了 web 應用平台和內容管理系統,那時還是 1996 年,類似軟件尚無名稱。接下來的 7 年,他為某金融服務軟件供應商工作,擔任使用同一平台的web 解決方案部門的架構師。在其職業生涯中,Bas 主管並培訓開發人員團隊,作為架構師領導產品開發和軟件設計。他實施落地了眾多客戶項目,包括政府、金融、法律、非盈利、汽車和廣播媒體等多個行業,用到多種敏捷方法。 Bas 主導開發的有:兩種編程語言、一種圖形化底層代碼應用編程環境、一種具備實時集群編碼能力的web 應用框架、一個數據建模框架、一個軟件和內容分發部署框架、一個web 開發代碼庫等等。 Bas 有實際上手開發和使用框架的經驗,同時對於設計軟件和方法論有深厚的抽象能力。

“出現問題時,我要做的第一件事,是看人們遵循什麼規則,以及背後的原因。”

原文鏈接

Categorise Unsolved Problems in Agile Development: Premature & Foreseeable