程序员为什么热衷于重写软件?
作者:Ben Northrop
譯者:劉雅夢
策劃:蔡芳芳
軟件重寫可能是一項非常危險的工作——存在許多非常真實的成本和風險,甚至可能會讓最善意的努力付諸東流。然而我們確實重寫了!并且經常這么干。雖然明知道會有風險,業務和技術還是一起宣布:“該死的魚雷,我們正在重寫這堆舊代碼,這次我們一定會成功的!”
我想在本文中探討的問題是“為什么”。考慮到所有的成本和風險,為什么我們還經常選擇重寫可運行的遺留系統,而不是局部重構呢?根據心理學、社會學和其他領域的分析,我想揭示一些微妙或不那么微妙的力量,這些力量推動著我們每個人走向全面重寫的道路。
我想澄清一下。我絕對不認為重寫總是錯誤的選擇——重寫有很多好的、合理的理由,我們將會在后面的文章中介紹。
創作的樂趣
開發人員喜歡創作的過程。我們天生就是構建者。盡管我們知道這項工作通常需要我們勇敢地冒險進入他人代碼的黑暗角落,以消除一些潛在的缺陷或調整一些深奧的計算,但這并不是吸引我們編程的原因。這只是一種必然的不幸。如果有機會,我們還是希望構建自己的系統。我們希望以一種對我們有吸引力的方式,以一種對我們有意義的方式,來制定解決方案。雖然冒著感情用事的危險,但編程是我們的藝術。同樣的,畫家寧愿從一片空白的畫布開始作畫,而不愿在另一幅畫像中作畫。
事實上,不僅是程序員喜歡自己創建的東西,所有人都是這樣的。Dan Ariely 在其著作《回報:影響人們動機的隱藏邏輯》(The Hidden Logic That Shapes Our Motivations)一書中,提到了一個有趣的軼事,強調了人類的這種傾向:
早在 20 世紀 40 年代,當大多數女性都在家工作時,一家名為 P. Duff and Sons 的公司就推出了盒裝蛋糕粉。家庭主婦們只需加水,在碗里攪拌面糊,將其倒入蛋糕盤中,烘烤半小時,然后調味,他們即可吃到一份美味的甜點。但令人驚訝的是,這種蛋糕粉賣得并不好。原因與味道無關,與流程的復雜性有關——但這不是我們通常認為的復雜性。
Duff 發現,家庭主婦們覺得這些蛋糕不像是她們自己做的;在賦予人們創造力和有意義的所有權方面,她們付出的努力實在太少了。因此,該公司將雞蛋和奶粉從蛋糕粉中取出。這次,當家庭主婦們添加新鮮的雞蛋、油和純牛奶時,她們會覺得自己參與到了制作過程中,并且對最終產品更加滿意了。
Ariely 接著描述了一些科學研究,這些研究顯示了同樣的效果:事實上,我們天生就喜歡享受創作的樂趣,而且我們可能會過分重視自己創作的成果(與我們實際創建出的東西有多好無關)。
我認為這就直接說明了我們作為開發人員對維護遺留系統的感覺。當然,我們能夠完全按照某種規定的模式在報表中添加一個新列,或者在屏幕上添加一個按鈕,但這并沒有給我們帶來那種對工作的依戀感或意義。我們想要的是打碎我們自己的雞蛋,并加入我們自己的牛奶和油。換句話說,我們的大腦可能會自然而然地傾向于重寫而不是重構。
維護之苦
從創建過程中尋求樂趣的另一面,是可以避免因繁瑣的維護工作而感到沮喪。維護遺留系統總是會帶來許多挫敗感。隨著時間的流逝,軟件趨于衰退。業務需求發生了變化,迫使開發人員將原來的廚房改造成前門廊。關鍵 Deadline 迫使我們偷工減料,并使用 TODO 和復制粘貼的方式交付代碼。隨著時間的流逝,新老開發人員在系統中開發的東西會在系統架構中形成“沉積層”——“你可以從風格上看出來,這段代碼來自 pre-IPO 時期,依賴注入之前”。
在這樣的遺留代碼中工作可能令人沮喪。即使只是要修復最簡單的 bug,也可能需要我們追蹤復雜的執行路徑,因為它們會在不同的軟件貧民窟里進進出出,在那里雜草叢生,而破爛的窗戶尚未修復。將系統的邏輯(或非邏輯!)掌握在我們的腦海中可能是一項艱巨的任務。當我們盡職盡責地接受我們的命運,修復這些缺陷,并添加那些小的改進時,我們一直在思考如何才能以不同的方式來做這件事。我們會想,如果能一把火把這個充滿復雜性和技術債的軟件堡壘燒掉,從頭開始,那該有多好呀。
然而,對于最終用戶,甚至對于企業而言,情況可能就不一樣了。當然,遺留系統看起來可能不那么美觀,或者可能需要比首選系統更多的點擊或延時,但它還是可以工作的。該系統功能正常,相對可靠,并且圍繞它的業務流程雖然不是最佳的,但至少能被很好地理解。但是對于開發人員,尤其是那些不是原始創建者的開發人員來說,這個系統代表的不是舒適,而是挫折和約束。我們在里面工作的時間越長,就越想逃離并重寫它。
利己主義與技術趨勢
除了尋求樂趣或避免挫敗感之外,作為開發人員,我們也很清楚什么工作才對自己的職業生涯有實際好處,這通常都不會是維護遺留系統。 2019 年的 Stack Overflow 開發人員調查顯示,語言的新穎性與開發人員的收入直接相關。薪資排名前五位的語言,平均年齡只有 15 歲,而排名后五位的語言,平均年齡則為 39 歲。
| 語言 | 年齡 | 平均工資 |
|---|---|---|
| Clojure | 13 | $90k |
| F# | 15 | $80k |
| Go | 8 | $78k |
| Scala | 17 | $78k |
| Elixir | 9 | $76k |
按平均工資排名前 5 的語言
| 語言 | 年齡 | 平均工資 |
|---|---|---|
| HTML/CSS | 25 | $55k |
| VBA | 27 | $55k |
| Assembly | 71 | $52k |
| C | 48 | $52k |
| Java | 25 | $52k |
按平均工資排名后 5 的語言
當然,還有很多其他因素也在起作用,但是在所有條件都相同的情況下,很顯然,如果我們不跟上新技術的步伐,那么我們能賺的錢就會更少。對于最近進入就業市場的任何一個開發人員來說,這并不足為奇。招聘人員、簡歷篩選機器人,甚至其他開發人員都在通過我們的經驗尋找最新的熱門詞匯:微服務、Kubernetes、漸進式 Web 應用程序或其他前沿技術。越新越前沿,越好。其邏輯大概是,與僅像仆人一樣從事遺留系統維護工作的人員相比,掌握最新技能的開發人員必然是更有動力也是投入了更多精力的(諷刺的是,從前雇主的角度來看,維護遺留系統可能才是正確的)。
這樣的邏輯確實有一些道理。編程工作確實需要高度的探索和實驗,因此對學習的熱情真的很重要。但是,我認為我們這個行業有一種趨勢,有時更傾向于追逐時髦的新技術而非實際需要的技術。當我們選擇一種語言、工具或框架時,我們當然希望選擇一種最適合這項工作的,但是我們也要考慮這個選擇對我們來說意味著什么。我們是使用諸如 Java 之類的成熟但笨拙的語言的人,還是選擇使用 Go 或 Kotlin 之類的富有“遠見”和“創新性”的人呢?從某種意義上說,我們使用的技術就像我們穿的衣服一樣——它們訴說著我們是誰,我們代表了什么,我們的價值是什么。從某種程度上說,技術和時尚是一樣的。
當然,現在這個類比還遠遠不夠完美,但看看社會學家 Herbert Blumer 對時尚周期的描述,其中確實有一些相似之處:
精英階層試圖通過明顯的標記或標志,比如獨特的著裝,來使自己與眾不同。然而,緊隨其后的階層成員采用這些標志來作為滿足他們為獲得較高地位而努力的一種手段。它們依次被它們下一階層的成員所復制。
通過這種方式,精英階層的顯著標志就會在階層金字塔中逐漸向下過濾。但是,在這個過程中,精英階層失去了這些獨立身份的標志。因此,又會導致設計出新的區別標志,這些標志又被下面的階層所復制,從而重復了這一循環。
簡而言之,無論是服裝、音樂還是編程,時尚都與階級分化相關。精英們不斷創新,大眾趕上來,所以他們可以與精英聯系在一起。然而,一旦他們這樣做了,精英就不再是“精英”了,因此他們必須重新創新。大眾最終又會追隨而來,循環往復,永無止境。
當談到重寫還是重構的問題時,我認為這可能是另一種微妙的力量,它促使作為開發人員的我們朝著全面現代化的選擇邁進。維持現有系統的活力,就像穿十年前的衣服一樣。當然,它們仍然可以讓你保持溫暖和干燥,但它們已經破舊了,可能無法向世人展示你想要展示的形象。對于那些不喜歡緊跟技術潮流的人,我們至少要知道,這確實會對我們的職業生涯產生明顯的影響。所以,要么保持步調一致,要么減少收入。
直覺錯誤與思維捷徑
拋開動機和個人利益不談,還有另一種強大的力量可以迫使我們相信,對于遺留系統而言,重寫是顯而易見的最佳決策,即使事實并非如此。那就是我們自己的直覺。
Daniel Kahneman 在關于決策和認知偏見的著作《思考,快與慢》中解釋到,盡管我們很容易就所有類型的問題形成意見(并對這些意見充滿了信心),但這些問題通常是基于簡單的思維捷徑,而不是可靠的推理。對于利害關系不大的決策來說,這可能沒什么問題,但是對于像重構或重寫整個系統(這可能要花費數百甚至數千小時的精力)這樣的問題,風險巨大。我們需要確認,問題到底能不能得到解決。
我們使用的一個微妙的思維捷徑是替代。當遇到需要深入思考和分析的問題(這是一項艱苦的工作)時,我們通常會把它替換成一個更簡單的問題,這樣我們就可以更快地解答了。例如,想要知道重寫與重構是否值得,我們應該要了解重寫的成本是多少,它能為組織帶來多少價值,何時實現投資回報(ROI)等。但這太難了!因此,我們會用更容易回答的問題來替代這個問題,比如,“現有系統是否有問題?”或者“ UI 是否過時了?”。答案自然是肯定的。這么做的話,雖然看起來好像解決了原始(困難的)問題,但實際并沒有,我們只是將其替換成了更容易解答的問題。
多年來,我一遍又一遍地看到這種辯解。與其停下來試圖回答真正困難的問題(重寫的凈值是否大于重構的凈值),我們經常回過頭來討論更簡單的替代問題。我們會說“我們要重寫,因為遺留系統難以使用”或者“因為沒有人能理解它”。是的,這些答案確實相關,但還不夠。也許沒有人能理解代碼是真的,但是一個人要理解這些代碼需要多少成本呢?這個成本與從頭開始重寫整個系統相比,是更大還是更小呢?bug 和技術債也是如此,成本和回報到底是多少?
當然,現在我們生活在一個瞬息萬變的世界里——我們沒有無限的時間來分析、制定商業案例并發表意見。但是對于一個像重寫或重構這樣至關重要的問題,我們應該試著放慢速度,確保我們至少回答了真正的問題,而不是回答了一個更容易的替代問題。
“拋棄”的文化
推動我們重寫的最后一股力量并非植根于我們自身,而是植根于我們周圍的社會。我們生活在一種“拋棄第一”(throw-away)的文化中。我們的食品和飲料裝在一次性容器里;購買的產品都是用過多的塑料和紙進行包裝的;我們的電器和設備都是為淘汰而設計的,因此它們經常連修都沒法修,即使我們想修也不行。換句話說,我們已經習慣了不加思索地丟掉一些東西——不管它是有了瑕疵、破裂了、故障了,還是只是稍微有點舊或有點磨損,我們都會選擇扔掉它。
因此,我認為這種“拋棄第一”的態度也有可能影響我們對軟件的看法。當一個系統老化時,我們的傾向不是拔出膠帶和 WD40 來延長它的使用壽命,而是將它扔掉,出去買(或重寫一個)新的型號 。實際上,“遺留”(legacy)一詞似乎總能引起開發人員的同情。“真遺憾,你不得不為此工作。”他們會問,“你打算什么時候重寫呢?”
公平地說,軟件開發是一個不斷改進和創新的行業。我們一直在學習更好、更簡潔的做事方式,然后將它們整合到我們的工具、框架和語言中。當他們可以使用 Java 8 的流(stream)和 Lambda 表達式,或更簡潔的函數式語言(如 Kotlin 或 Scala)時,沒有人會再刻意去使用 Java 7。此外,新的平臺和設備不斷發布,而我們現有的系統可能無法移植到這些平臺和設備上。因此,我并不是說,以舊換新一定是個輕率的選擇。
但我確實認為,意識到這種潛在的偏見是有幫助的。當我們過快地放棄一個可能還算可靠的遺留系統(盡管它有些舊或復雜)時,組織可能會付出代價。在接下來的文章中,我將討論遺留系統現代化的三個不同“R”:“修復”(Repair)、“重用”(Reuse)和“再利用”(Recycle)。與其把我們現有的系統看作是需要敬而遠之的東西,我們應該理解并利用好那些目前仍在起作用的組件和元素,并只嘗試重寫那些需要重寫的組件和元素。
原文鏈接:
http://rewriteorrefactor.com/chapter-3-why-we-rewrite-even-when-we-shouldnt.php
總結
以上是生活随笔為你收集整理的程序员为什么热衷于重写软件?的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 孤舟苏笠翁下一句是什么啊?
- 下一篇: 中移动6月净增5G用户1459万户 用户