剑网3指尖江湖职业推荐 www.1468054.com 在軟件開發項目中,常見的爭論之一是花費時間來提高軟件質量,還是集中精力發布更有價值的功能。通常來說,交付功能的壓力占據了主導地位,許多開發人員因此抱怨他們沒有時間在架構和代碼質量方面進行研究與處理。

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

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

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


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

正如我在本段標題提到的那樣,我們都習慣了在質量和成本之間進行權衡。當我更換智能手機時,我可以選擇一個更昂貴的型號,處理器更快、屏幕更好、內存更多?;蛘呶銥梢暈嘶ǜ俚那牌渲幸恍┢分?。然而,這并非絕對規則,因為我有時候會趁打折促銷活動之類的機會用更少的錢買到優質商品。更多的時候,我們對質量有不同的價值觀:有些人并沒有真正注意到某種手機屏幕是否比其他手機屏幕更好。但在大多數情況下,這一假設是正確的:好貨不便宜,便宜沒好貨。


軟件質量意味著很多事情

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

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

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


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

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

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

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


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

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

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

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

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

圖0:開發高質量的軟件要付出什么樣的代價?

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

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


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

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

圖1:開發高質量的軟件要付出什么樣的代價?


可視化內部質量的影響

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

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

圖2:開發高質量的軟件要付出什么樣的代價?

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

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

圖3:開發高質量的軟件要付出什么樣的代價?

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

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

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


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

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

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

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

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

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

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

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


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

綜上所述:

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

遺憾的是,軟件開發人員通常并不能很好地解釋這種情況。我曾無數次與開發團隊交談過,他們說,“他們(管理層)不會讓我們編寫出高質量的代碼,因為這需要花費太多的時間?!笨⑷嗽蓖ǔP枰ü實鋇淖ㄒ敵岳粗っ鞫災柿康墓刈⑹嗆俠淼?。但是,這種道德主義的觀點暗示這種質量是以犧牲他們的觀點為代價的——注定他們的觀點會失敗。令人討厭的是,由此產生的粗制濫造的代碼不僅讓開發人員的日子更難過,也給客戶帶來了金錢上的損失。在考慮內部質量時,我強調我們只應該講它作為一個經濟論點來看待。較高的內部質量降低了未來功能的開發成本,這意味著花時間編寫優秀的代碼實際上就是降低了成本。

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

余下全文(1/3)

本文最初發表在www.infoq.cn,文章內容屬作者個人觀點,不代表本站立場。

分享這篇文章:

請關注我們:

發表評論

電子郵件地址不會被公開。 必填項已用*標注