opensource

開發人員要實現一個軟件功能,可能只花了幾個小時,但是完成之後,測試、debug、漏洞修補、向另一個工程師解釋,要麼做客服回答問題、解釋工作原理……。維護單一功能的投入時間要遠遠超過最初開發的幾個小時,人手成本從來難以預計。

固有的複雜度

軟件開發的複雜程度帶來很大的隱形成本,有時候,複雜度在問題領域只是固有的,通過調整價格來平衡供求是一個複雜和痛苦的問題。因此,擴大軟件功能和維護品質的時候,這是固有的複雜度,我們需要根據產品做出調整以取得成功。

撇除固有的複雜度,開發人員仍然受自己產生的複雜度所困擾,例如:

用新程式語言寫代碼,對新語言的瞭解不足,而維護時便花額外的時間; 又或者從網絡看到新興熱門技術,躍躍欲試而增加了額外的基礎架構,但嘗試後便發現失敗了; 開發時引入了一個很少人使用的功能,但是修復和debug報告就花掉了極不對稱的時間。

額外的複雜度造成了很多隱形成本,開發前期我們所做的決定不只決定了當前的開發速度,還埋下了後期維護的時間和人力資源的消耗。複雜度以很多不同的方式滲入到團隊裡,大部分是直接滲入到代碼、系統和產品複雜度裡,亦有間接地滲入到企業裡。我們逐個看看這幾種不同類型複雜度的隱形成本。

代碼複雜度

代碼複雜度不是隨著代碼行數增加而線性增長,絕大部份情況是複式增長。在複雜的代碼庫裡,每行代碼可能與其它很多行代碼交互和影響。我們對於複式增長難以控制,這就是為什麼團隊容易低估大型軟件專案所需要的時間,這也是重寫項目有時候會大幅延期的主要原因。

當代碼過於複雜的時候,它將變得難以擴展、難以釐清其中緣由、難以修復bug、難追蹤錯誤來源的依賴和資料流程向。工程師或許會積極地避免代碼庫最複雜的部分,即使可以做某種修改、最有邏輯的地方也要選擇繞彎來解決。他們或許避免把那些地方都組合起來,即使這項工作有著很大的影響。

系統複雜度

工程師喜歡擺弄新玩具,要麼因為好奇,因為新技術可能為解決他們的緊迫問題。當Pinterest在2011年剛開始擴容網站以應對快速增長時,他們只有3個工程師的後端小組卻使用了6種不同的存儲技術(MySQL、Cassandra、Membase、Memcache、Redis和MongoDB),實驗每項新技術的諾言都是解決現有系統的某些限制。但是,每種新解決方案都以其自身特定方式失敗了,為了管理和維護而投入了更多時間和努力。最終,團隊明白了,增加更多機器而不是更多技術,更能簡化擴充,因此他們消除了Cassandra和MongoDB之類的系統,強化了架構的已有元件。

把基礎架構切分為太多系統,會帶來很多隱形成本。注意力被分散到了多個系統。對於每個系統來說,更難以整合資源以開發可複用的資源庫,更難以為日常工作招聘新人,更難以理解具體的失敗模式和每個系統的性能特點。每個系統的抽象最終變得更弱,因為沒有可投入的太多時間。當工具和抽象太複雜、或太多的時候,讓團隊去理解和探索將變得困難。

產品複雜度

產品複雜度可以導致一個不明確的目標,無節制的野心會令產品缺乏清晰定位。開發人員或投資者總希望不只是在一個核心領域優秀,而要在很多地方都出色表現。這種欲望使其不能向使用者明確地解釋產品的意圖,產品複雜度引發了更多的代碼和系統複雜度,團隊增加更多代碼、更多基礎架構以支持新功能。當產品要增加一個新功能或修改現有功能,將需要放大很多的努力來理解和適應舊的功能。

過於複雜的產品意味著有更多的代碼分支,更多要考慮的問題、更多的需要團隊解決的bug。工程師和數據分析師需要分析更多的變數、做更多的一次性的報表,而不是集中於核心用戶行為的理解上。工程師需要投入更多時間來提供功能空間和提高效率。每個人最終在更多的項目中進行切換。投入在維護所有這些功能上的時間,並不是重新投入代碼、償還技術債務、加固抽象的時間。

<待續>

 


 開發人員守則:避免無謂的隱形成本(上)

 https://www.facebook.com/hkitblog