開發高質量的軟件要付出什麼樣的代價?

在軟件開發項目中,常見的爭論之一是花費時間來提高軟件質量,還是集中精力發佈更有價值的功能。通常來說,交付功能的壓力佔據了主導地位,許多開發人員因此抱怨他們沒有時間在架構和代碼質量方面進行研究與處理。

貝特里奇頭條定律是一句俗語:“任何以問號結尾的頭條,都能夠用‘不’來回答。” 那些瞭解我的人不會懷疑我渴望顛覆這條定律的心。但本文將會走得更遠,因爲它顛覆了問題的本身。這個問題假設了質量和成本之間存在一個共同的權衡。在本文中,我將爲讀者們解釋,這種權衡並不適用於軟件開發——高質量的軟件實際上生產成本更低。

譯註:貝特里奇頭條定律(英語:Betteridge’s law of headlines ),該定律以英國科技記者伊恩・貝特里奇(Ian Betteridge)命名,儘管有關該定律之理論的出現早於貝特里奇活躍的年份。與類似的 “定律”(比如墨菲定律)一樣,這是一個幽默的格言,而不是字面意義上的事實。

雖然我的大部分文章是針對專業軟件開發人員而寫的,但在本文中,我不會假設讀者具有任何相關軟件開發機制的知識背景。我希望這篇文章對任何涉及軟件工作的人們而言都有價值,特別是那些作爲軟件開發團隊的客戶的受衆,比如商業領袖。


我們習慣於在質量和成本之間進行權衡

正如我在本段標題提到的那樣,我們都習慣了在質量和成本之間進行權衡。當我更換智能手機時,我可以選擇一個更昂貴的型號,處理器更快、屏幕更好、內存更多。或者我可以爲了花更少的錢而放棄其中一些品質。然而,這並非絕對規則,因爲我有時候會趁打折促銷活動之類的機會用更少的錢買到優質商品。更多的時候,我們對質量有不同的價值觀:有些人並沒有真正注意到某種手機屏幕是否比其他手機屏幕更好。但在大多數情況下,這一假設是正確的:好貨不便宜,便宜沒好貨。


軟件質量意味着很多事情

如果讓我來談論軟件質量,請讓我首先解釋什麼是軟件質量。這就是第一個複雜問題:有很多東西可以算作軟件質量。比如,我可以考慮用戶界面:是否能夠輕鬆引導我完成需要完成任務,讓我變得更有效率,並驅散挫折感嗎?我還可以考慮它的可靠性:它是否包含導致錯誤和引起挫折感的缺陷呢?另一方面就是它的架構了:源代碼是否分爲清晰的模塊,以便程序員能夠輕鬆地找到並理解他們在本週需要處理代碼的那一部分?

當然,上面提到的這三個關於軟件質量的例子,並不是一個詳盡的列表,但它們足以說明一個重要的觀點。如果我是軟件的客戶或用戶的話,我不會去了解他們稱之爲質量的東西。用戶自己就可以判斷用戶界面是否良好。用戶和客戶自會注意到缺陷,特別是當它們造成數據被損壞或者使系統暫時無法運行時。但是客戶和用戶卻無法理解軟件的架構。

因此,我將軟件質量屬性劃分爲外部(如用戶界面和缺陷)和內部(架構)。區別在於,用戶和客戶可以看到是什麼使軟件產品具有較高的外部質量,但卻無法區分內部質量是較高還是較低。


對客戶來說,內部質量看似無關緊要

既然內部質量並不是客戶或用戶所能看到的,這有什麼關係嗎?讓我們想象一下,Rebecca 和我各自編寫了一個應用程序,用來跟蹤和預測航班延誤。我們的兩個應用程序都有相同的基本功能,都有同樣優雅的用戶界面,並且幾乎沒有任何缺陷。唯一的區別是,Rebecca 寫的內部源代碼組織得整齊有序,而我的源代碼則寫得一團亂麻。另外,還有一個區別是,我編寫的應用程序售價是 6 美元,而她編寫的是 10 美元售價。

既然客戶從來沒見過這個應用程序的源代碼,而且也不影響應用程序的運行,那爲什麼還會有人爲 Rebecca 的軟件額外支付 4 美元呢?更籠統地講,這應該意味着不值得爲更高的內部質量支付更多的錢,不是嗎?

換句話說,用成本來換取外部質量是有意義的,但用成本換取內部質量是沒有意義的。用戶可以判斷他們是否願意花更多的錢來得到更好的用戶界面,因爲他們可以評估用戶界面是否足夠好,是否值得支付額外的費用。但是用戶並不能看到軟件的內部模塊結構,更遑論判斷它是不是更好。那爲什麼要爲沒有效果的東西支付更多的費用呢?既然如此,那爲什麼軟件開發人員應該將更多的時間和精力用來提高他們工作的內部質量呢?


內部質量使增強軟件變得更容易

那麼爲什麼軟件開發人員會把內部質量當成一個問題呢?程序員大部分時間都花在代碼的修改上。即使在一個新系統中,幾乎所有的編程都是在現有代碼基礎上完成的。當我想給軟件增加一個新功能時,我的第一個任務就是弄清楚這個功能如何適應現有應用程序的流程。然後,我需要改變這個流程,以讓我添加的功能能夠適應。我經常需要用到應用程序中已存在的數據,因此我需要了解這些數據代表什麼,它如何與周圍的數據關聯,以及我可能需要爲我的新功能添加哪些數據。

所有這些都是關於我對現有代碼的理解。但是,軟件很難讓人理解。邏輯可能會變得很複雜,數據可能很難理解,六個月前用來指代事物的名字可能對 Tony 有意義,但對我來說,就像他離開公司的理由一樣神祕。所有這些都是開發人員稱之爲“Cruft”的形式:當前代碼和理想情況下代碼之間的區別。

譯註:Cruft 指的是程序源代碼中隨時間累積而變得無用的過時垃圾程序代碼(美國傳統英語字典解釋爲隨時間而增加的有害物質或無用訊息)。隨着軟件的發展,以及經歷了修改 Bug 和重構的若干週期之後,軟件的部分代碼已不再使用,但這些代碼仍然保留在源碼中,這種代碼稱爲 Cruft。Cruft 可能是一兩行無用的代碼,也可能是整個源文件模塊。

內部質量的一個主要特點之一是,讓我更容易理解應用程序的工作方式,這樣我就能看到如何添加內容。如果軟件被很好地劃分爲不同模塊的話,我就無需閱讀所有 50 萬行代碼,就可以在幾個模塊中快速找到我要找的那幾百行代碼。如果我們把精力放在清晰的命名上,那麼我就可以快速理解代碼各個部分的用途,而不必糾結於細節。如果數據合理地遵循底層業務的語言和結構,我就可以很容易地理解它如何與客戶服務代表那裏得到的請求相關聯。Cruft 增加了我理解如何改變的時間,還增加了我犯錯誤的可能性。如果我發現了自己的錯誤,那麼我就會浪費更多的時間,因爲我還必須瞭解這一錯誤是什麼,以及如何糾正這個錯誤。如果我沒有發現這些錯誤,那麼我們就遇到產品缺陷,然後將會有更多的時間花在未來的修復上。

image

技術債務是 Cruft 的一個常見的比喻。添加功能的額外成本就跟支付利息一樣。清理 Cruft 就像償還本金一樣。雖然這一比喻很有用,但它確實鼓勵許多人相信,與實際情況相比,Cruft 更容易測量和控制。

我的改變也會影響到未來。我可能找到了一個快速加入這個功能的方法,但這與程序的模塊化結構背道而馳,如此一來這就增加了 Cruft。如果我選擇這條路的話,那麼我今天就可以讓它加快速度,但在未來的幾周或幾個月裏,我會讓其他所有必須處理這段代碼的人都放慢速度。一旦團隊中的其他成員做出相同的決定,一個易於修改的應用程序就會快速累積到每個微小的更改都要花費數週時間的地步。


客戶確實關心新功能的快速發展

這裏我們看到了內部質量對用戶和客戶很重要的線索。更好的內部質量使得添加新功能變得更容易,因此開發速度更快,售價也更便宜。Rebecca 和我各自編寫的應用程序現在可能有同樣功能,但在接下來的幾個月裏,Rebeca 由於她編寫的程序內部質量之高,得以能夠做到每週添加新功能;而我卻被卡住了,一直在努力突破瓶頸,就爲了推出一個新功能。我無法與 Rebecca 的開發速度競爭,很快,她的軟件就比我的軟件功能強大得多,然後我所有的客戶都卸載了我的應用程序,轉而購買 Rebecca 的應用程序,即使她提高售價也在所不惜。

image


可視化內部質量的影響

內部質量的基本作用是降低未來變更的成本。但是編寫優秀的軟件需要額外的努力,而這在短期內確實會帶來一些成本。

可視化的一種方法是使用如下圖的僞圖,其中我繪製了軟件的累積功能與生成它的時間(以及成本)的關係。對於大多數軟件來講,曲線看起來如下圖所顯示的那樣。

image

這就是槽糕的內部質量所造成的後果。最初進展很快,但隨着時間的推移,添加新功能變得越來越困難。即使進行很小的更改也需要程序員理解大量的代碼,而這些代碼很難理解。當他們進行更改時,會發生意想不到的破壞,導致測試時間過長以及出現需要修復的缺陷。

而專注於提高內部質量就是爲了減少生產率的下降。事實上,有些產品會產生相反的效果,開發人員可以通過利用先前的工作輕鬆構建新的功能,從而加快開發速度。但這種令人愉悅的情況很罕見,因爲它需要一支技術嫺熟、訓練有素的團隊才能實現這一目標。但我們偶爾也會看到這一情況。

image

這裏的微妙之處在於,有一段時期,內部質量較低的產品比內部質量較高的產品的生產力更高。在此期間,質量和成本之間存在某種權衡。當然,問題是,在兩條曲線發生交叉之前,這段時間有多長?

在這一點上,我們遇到一個問題,爲什麼這是一個僞圖。我們沒有辦法去衡量軟件團隊交付的功能。由於無法衡量產出,因而也就無法衡量生產率,因此無法對內部質量較低造成的後果(這也很難衡量)給出確切的數字。無法對產出進行衡量在專業工作中相當普遍:我們該如何衡量律師或醫生的生產力?

我評估曲線交叉的方法是徵求我所知道的熟練開發人員的意見。然而,答案讓很多人感到驚訝。開發人員發現,質量很差的代碼在幾周內就會出現顯著降低開發速度的現象。所以,在內部質量和成本之間能夠進行權衡的地方並沒有多少。即使是很小的軟件開發工作也會從對良好的軟件實踐的關注中受益,當然,這是從我經驗中所證明的這一點。


即使是最好的團隊也會製造出“Cruft”

許多非開發人員傾向於,認爲只有當開發團隊粗心大意並出錯時纔會發生這種事情。但實際上,即使是最優秀的團隊也會在工作時不可避免地製造出“Cruft”。

我喜歡用一則我和最好的技術團隊領導聊天的故事來說明這一點。他剛剛完成了一個被普遍認爲是非常成功的項目。客戶對教輔的系統感到非常滿意,無論是功能方面,還是構建時間和成本方面。我們的員工對這個項目的工作經驗持肯定態度。技術主管也非常高興,但也承認系統的架構並不是太好。我的反應是“這怎麼可能?你可是我們最好的架構師之一啊!”,他的回答是任何有經驗的軟件架構師都很熟悉的:“我們做出了很好的決策,但直到現在才明白應該如何進行構建”。

許多人,包括軟件行業的一些人,將構建軟件比作建造大教堂或摩天大樓,畢竟,我們爲什麼要用“架構師”來稱呼高級程序員呢?但構建軟件存在於充滿不確定性的世界,而這一世界不爲物理世界所知。軟件的客戶只對產品需要什麼功能有一個粗略的概念,並隨着軟件的構建瞭解更多的信息:特別是早期版本發佈給他們的用戶時。軟件發開的構件:語言、庫和平臺,每隔幾年就會發生重大的變化。在物理世界中,類似的情況是,一旦一半的建築物建成並被佔用,客戶通常會添加新的樓層,並改變樓層平面圖,而混凝土的基本性能每隔一年就會發生變化。

鑑於存在這種程度的變化,軟件項目總是創造一些新穎的東西。我們幾乎從未發現自己在處理一個以前已經解決過的、大家都能理解的問題,當我們構建解決方案的過程中,我們對這個問題了解得最多,因此,我常常聽到團隊只有在花了一年左右的時間去構建軟件之後,才能真正理解軟件的架構應該是什麼。即使是最好的團隊,他們的軟件也會出現“Cruft”。

不同之處在,最好的團隊創造出來的“Cruft”,但也消除了足夠多的“Cruft”,這樣,他們就可以繼續快速添加功能。他們花費時間創建自動化測試,以便能夠快速發現問題,並花更少的時間來消除 Bug。他們經常進行重構,這樣他們就可以在 Cruft 積累到足以礙手礙腳之前就清除掉。由於團隊成員是在不同目的上的工作,持續集成可以最大限度地減少 Cruft 的出現。一種常見的比喻是,這就好比清理廚房的檯面和設備。要知道,在你做飯的時候,你不可能不把東西弄髒,對吧。但如果你不趕快把東西清理乾淨的話,那髒東西就會變幹,這樣就很難清理,所有的張東西都會妨礙你烹製下一道菜。

Dora 對精英團隊的研究表明,質量和速度之間的選擇,並非軟件開發中唯一具有至關意義的選擇,但這卻是錯誤的。還有一種強烈的觀點認爲,在快速開發(如系統的頻繁更新)和在生產中不會中斷的可靠系統之間,存在雙模選擇(Bi Modal)。其實這是一個錯誤的選擇,這點在《State of Dev Ops Repot》中嚴謹的科學研究中得到了證實。

幾年來,他們一直使用調差的統計分析來梳理高效軟件團隊的實踐。他們的工作表明,精英軟件團隊每天多次更新產品代碼,在不到一個小時的時間內,即可完成將代碼從開發狀態更改爲生產狀態。當他們這樣做時,他們更改失敗率明顯低於低效團隊,因此他們從錯誤中恢復的速度要快得多。此外,這些精英軟件交付組織與更高的組織績效相關。


高質量的軟件生產成本更低

綜上所述:

  • 忽視內部質量,會導致 Cruft 快速形成。
  • 這種 Cruft 降低了功能開發的速度。
  • 即使是優秀團隊也會製造出Cruft,但通過保持較高的內部質量,就可以使它處於受控狀態。
  • 較高的內部質量使 Cruft 降至最低,使團隊能夠以更少的工作量、時間和成本來添加功能。

遺憾的是,軟件開發人員通常並不能很好地解釋這種情況。我曾無數次與開發團隊交談過,他們說,“他們(管理層)不會讓我們編寫出高質量的代碼,因爲這需要花費太多的時間。”開發人員通常需要通過適當的專業性來證明對質量的關注是合理的。但是,這種道德主義的觀點暗示這種質量是以犧牲他們的觀點爲代價的——註定他們的觀點會失敗。令人討厭的是,由此產生的粗製濫造的代碼不僅讓開發人員的日子更難過,也給客戶帶來了金錢上的損失。在考慮內部質量時,我強調我們只應該講它作爲一個經濟論點來看待。較高的內部質量降低了未來功能的開發成本,這意味着花時間編寫優秀的代碼實際上就是降低了成本。

這就是爲什麼本文開頭提到的問題沒有抓住這一點的原因。較高內部質量的軟件的“成本”實際上是負的。通常,成本和質量之間的權衡,我們在生活中的大多數決策中都已經習慣了這種權衡,但對於軟件的內部質量來說,這種權衡是沒有意義的。(它可以提高外部質量,比如精心設計的用戶體驗。)因爲成本與內部質量之間的關係,是一種不尋常的、違反直覺的關係,因此通常很難理解。但是,如果能夠理解它的話,對於以最高效率開發軟件而言至關重要。


原文鏈接:

https://martinfowler.com/articles/is-quality-worth-cost.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章