作者 | Alex Meyer

譯者 | 彎月

出品 | CSDN(ID:CSDNnews)

背景介紹

企業軟件的速度非常慢、耗費內存巨大,而且使用起來很痛苦,人們常常對此感到十分困惑。我也曾就職於一傢大型企業軟件公司,所以我希望通過本文來探討一下這個問題。其實,這個問題在軟件行業中普遍存在。

什麼是臃腫的軟件?

臃腫的軟件指的是使用的資源大大超出瞭完成工作所需,比如CPU、內存、I/O以及磁盤空間等。此外,擁有過多功能的軟件也可以稱為臃腫,因為這些軟件的使用和學習難度都很高,耗費的資源也很多。

為什麼軟件臃腫是一個問題?

臃腫的軟件會嚴重影響計算機的使用體驗,不僅會導致你的日常工作速度下降,而且還會耗盡筆記本電腦的電池,甚至迫使你不得不購買更強大的計算機。超高的CPU使用率會直接導致能耗增加,因為通常計算機的處理器可以在空閑時進入睡眠狀態,從而節省能耗。如果某個算法非常低效,運行所需的時間加倍,那麼相應的能耗也會加倍。計算機中的其他硬件也是如此。此外,一旦計算機的硬件無法滿足軟件的資源需求,就會變成電子垃圾。

造成軟件臃腫的原因

1. 組織原因

自行構建比分享更容易

企業軟件的開發通常需要不同職能團隊之間的合作。雖然一個團隊的開發人員通常都會在同一個地點辦公,或者至少在同一個市區內,但不同的團隊可能位於不同的大陸。因此,團隊之間的溝通比團隊內部更難。開發軟件的組織形式大多為自上而下,每個團隊都有一個經理來控制團隊的工作。所有這些特征都阻礙瞭軟件重用以及代碼共享。在許多情況下,團隊內部開發僅供自己使用的功能會更加容易。如果將這類工作委托給另一個團隊,那麼就會帶來大量的溝通/計劃開銷,並導致你的開發計劃依賴於該團隊。所以,通常人們都寧願自己動手。但是這樣一來,代碼庫的增長就會超出必要的范圍,在大多數情況下,資源需求也是如此(因為編寫的代碼更多,由此引發的錯誤也更多)。

2. 業務發展的原因

迎合市場需求

對於大多數產品而言,隻有快速發佈才能獲取市場份額或被視為創新者。通常市場的需求重於其他任何因素,甚至是功能或質量。但這可能導致軟件效率低下,因為開發人員和架構師會各種捷徑,例如將現有系統粘合在一起、使用簡單的算法、在內存中表示數據時采用蹩腳的形式,以及放棄優化瓶頸等。

舉一個例子,如今的許多應用程序都是多平臺的:它們必須在 macOS 和 Windows 等桌面操作系統上運行,還需要構建iOS/iPadOS 和 Android 上的應用,以及在網絡上運行。隻有大公司才有能力為每個平臺配備一個專門的團隊。因此,流行的替代方案是選用可支持同一個代碼庫在多個平臺上運行的框架,例如Electron(VS Code采用瞭該框架)或 Progressive Web Apps(Pinterest 和推特采用瞭該框架)。這些框架是重量級的,需要完整的瀏覽器和 JavaScript 引擎才能運行,框架本身就會占用大量資源。

收購

隨著企業被收購,軟件也需要被集成和融合。通常,集成不會重構代碼或修改內部數據與算法,因此從資源消耗的角度來看,“新”產品就是各個部分之和。除瞭重構的成本和上市時間的壓力之外,個別軟件的用戶也可能會受到重構的負面影響。但是對於一個粘合在一起的系統,由於數據格式轉換、數據的復制或重新處理以及更高的延遲等原因,每個人都會面臨資源消耗過高等問題的困擾。

維護合同

通常,總會有一些客戶依賴於本該刪除的功能。這種依賴通常會通過合同表達出來,因此大多數公司都禁止對這樣的功能進行修改。

多元化的客戶群

有些產品需要服務大量客戶,或者是因為每個功能都有一小部分用戶,這就導致軟件在其生命周期內積累許多功能。這不僅會導致軟件對磁盤空間需求的增加,而且還會導致軟件的開發和使用成本上升。隨著代碼庫的規模變得越來越大,錯誤會到處蔓延,並導致修復的難度加大。逐漸地,開發人員越來越不願意進行重構,因為成本與收益不成比例,或者成本太高以至於管理層不會分配這些時間。此外,各個功能也需要更通用的數據結構和抽象,從而導致資源消耗進一步增加。

合作夥伴集成

兩個公司之間的軟件相互集成是一件好事,雙方不僅可以獲得更多功能,而且還可以獲得更多用戶。不幸的是,這種集成也會導致更多的代碼、更多的抽象、數據轉換等,並最終導致軟件進一步膨脹。從技術角度來看,這與上面提到的收購幾乎是一樣的。

軟件開發的原因

高級語言

各個項目在選擇編程語言和框架時,主要的考慮因素如下:

掌握編程語言和框架的工程師數量;

編程語言和框架的發展速度;

與其他系統集成的難度;

編寫擴展的難度。

對於許多類型的軟件來說,制定決策時很少會考慮代碼的運行時效率。根據上述標準,得分較高的語言包括:

JavaScript/Web技術棧:作為唯一的客戶端代碼具備可移植性的編程語言,JavaScript的人氣非常高,甚至還在服務器開發中占有一席之地。盡管JavaScript是一種解釋型語言,但對於JIT的研究成果和廣泛深入的優化使其速度完全可以滿足需求。隻不過,JavaScript對內存的要求依然很高。

Python:這是一種優秀的編程語言,可以快速幫助你完成工作,但它的速度很慢,而且內存需求相對也很大。

相比之下,Rust或C++等語言通常可以生成非常高效的軟件,但開發速度明顯較慢,而且能夠編寫出高質量軟件的工程師也較少。

當然語言隻是一個因素,任何語言都可能會編寫出臃腫的軟件。

復雜性和抽象

Donald Knuth有一句名言:“過早的優化是萬惡之源。”

我更喜歡將復雜性視為萬惡之源,過早的優化會引入更多的復雜性。此外,復雜性還涉及其他問題:

軟件必須遵守的所有技術標準(網絡瀏覽器就是一個很好的例子);

可用功能的數量;

過度設計的軟件具備很高的靈活性,能夠支持將來的增強功能。

復雜性往往會導致軟件膨脹,但有時也未必。例如,為瞭將特殊情況下的運行速度提高一個數量級,我們常常會添加第二種算法,這固然會增加復雜性和磁盤占用量,但可以降低CPU消耗和內存的使用,而且還可能會減少軟件的膨脹。

沒有時間編寫更好的代碼

在許多公司中,功能開發的優先級高於優化、重構或刪除遺留代碼。在許多情況下,從業務的角度來看,這種決策很合理,因為客戶隻關心功能,並不會關心硬件。然而,隨著許多工作負載轉移到雲端,這種情況發生瞭變化,因為提供數據庫解決方案的雲提供商承擔瞭運營成本,他們比較有興趣降低軟件的臃腫程度。

日志記錄

企業軟件尤其重視支持的難度。很多企業軟件在客戶專有的服務器上運行,你隻能通過日志文件分析錯誤。因此,此類軟件往往擁有大量記錄日志的代碼,激活這些代碼就可以深入瞭解系統。有些軟件的膨脹隻會影響二進制文件的大小,不會影響內存消耗和運行時性能。

錯誤處理

企業軟件必須更加健壯。想象一個持續運行數月且不能崩潰或泄漏內存的數據庫服務器:它必須能夠正確處理各種內存不足的情況或故障。由於需要處理所有極端的情況,因此這類軟件具備很高的彈性,但代碼量很大,必然會非常臃腫。與日志記錄類似,良好的代碼可以減少對運行時和內存消耗的影響。

可訪問性與法律要求

企業軟件必須滿足各種法律要求,其中最重要的就是可訪問性。企業軟件必須具備這個功能,但這需要很多代碼支持,並且通常會消耗更多的資源。開源項目通常不會處理這些需求。

解決方法

不喜歡使用臃腫的軟件?幸運的是,我們總能找到其他的替代軟件。

不喜歡開發臃腫的軟件?軟件行業的許多領域也有此類困擾:

雲服務後端:雲服務商的利潤與服務占用的資源量直接掛鉤,因此雲服務商非常希望降低資源消耗。由於世界各地的許多人都在使用某些服務,因此即使是很小的優化也可以大大增加利潤。此外,對於雲環境來說,工作負載的分析相對很容易,因此我們可以直接選擇最有價值的優化。

移動設備:對於這些設備來說,電池的壽命至關重要,因此我們應該盡量減少CPU的使用。

嵌入式系統:這些系統很小,硬件都不夠強大;或者這些系統的制造規模非常大,因此構建優化的軟件,並降低硬件消耗,才能增加利潤。

總結

說到底,軟件膨脹的原因還是由業務需求引發的。如果軟件開發免費且不需要任何時間,那麼每個人都會發佈最佳軟件。然而,現實情況遠非如此,因此各個公司必須做出取舍。實際上,做出正確的權衡非常困難,短期內看似正確的權衡從長遠來看可能是有害的。例如,雖然快速發佈臃腫的軟件可以幫助公司搶占市場份額,但隨著客戶開始使用該產品,就會引發許多質量問題。但是,延遲發佈產品又不利於推廣。因此,大多數公司會優先考慮提前發佈軟件,或者發佈新功能,而不是修復臃腫的問題。開源項目不受此類約束,常常可以提供很好的替代方案。

*本文由CSDN翻譯,未經授權,禁止轉載。