必須移除無用代碼
Kevlin Henney指出,需要發現和移除無用代碼。對于編程人員理解程序并采取行動而言,無用代碼的存在是一種障礙,因為無用代碼存在被喚醒的風險,并會導致嚴重的問題。移除無用代碼并非是一個技術問題,而是一種理念上的和文化上的問題。
Kevlin Henney是一位獨立顧問和培訓師。他在 2017年歐洲測試大會 上以“我們做事方式中的錯誤”為題目做了開幕式主題演講,并在演講中展示了無用代碼的喚醒是如何給企業帶來上百萬的損失。InfoQ以問答、總結和文章的形式對大會作全程覆蓋報道。
軟件故障會對個人造成不便也是十分煩人的,還會產生顯著的經濟和社會影響。Henny展示了數個由于細微的軟件故障導致上百萬損失的例子。
Henney指出,故障可能源自無用代碼。無用代碼是存在于系統中的、但并不被認為會再被使用的代碼。意外執行這些代碼會導致系統嚴重故障。因此,他建議必須移除無用代碼,以避免此類問題的發生。
InfoQ就如何解決無用代碼所導致的問題采訪了Kevlin Henney,并請教他如何處理出錯狀態和異常。
InfoQ:您談及被激活的無用代碼將會對企業造成巨大損失,能就此解釋一下嗎?
Kevlin Henney:2012年8月1日紐約股票交易所開盤后,Knight Capital Group最新的高速算法給出的交易路線錯誤下單,所產生的交易充斥了整個市場。系統在錯誤運行大約45分鐘并完成了4億股交易后才被下線。一切塵埃落定后,所造成的凈損失達每分鐘一千萬美元以上。
這個破產界定事件源自于一場完美風暴(即獨立發生時沒有危險性但一并發生時會帶來災難性后果的事件組合)。為使新的NYSE交易系統按預期在8月1日上線,公司在服務器上部署了更新。工程師手工更新了服務器,但他們并不知道其中的一次部署失敗使舊版本保留運行。在新的NYSE交易系統中,他們重用了一個舊標識,但是該停用標識已更改了用途,用于表示另一個意義。雖然該標識在過去的八年中都沒有被使用,舊版本代碼依然依賴于這個舊標識。
這段已有八年時間處于無用狀態的代碼由于標識值的更新而被喚醒了。僵尸災難發生了,只剩下破產一條路。
InfoQ:采取哪些措施本可以避免問題的發生?
Henney:可以說完美風暴中的任何一個貢獻因素都是有問題的,但是這些因素的組合被證明會引發更為嚴重的問題。更改其中任何一個貢獻因素都有可能阻止或至少降低損害:
- 服務器是手工更新的:這是一個迫切需要自動化的任務。
- 失敗的更新并未得到關注:沒有人去審查更新。飛機艙門雖然是手工上鎖的,但飛行安全是通過機組成員間的交叉驗證得以提升。
- 無用代碼并非真的無用,除非確實被移除。他們早在幾年前就應該移除那些多余代碼。
- 有時確實是出于十分現實的考慮而將標識、記錄等改做他用,而非添加新的。但是如果完全可以添加新的而非回收利用,就應該去添加新的。
- 企業在處理違規交易系統中缺失了上報流程。通常很難預期能得到準確的交易失敗情況,但是如果采用高速交易系統意在實現比交易員更快交易的話,很明顯這也會導致金錢更快的損失,因為高速交易系統放大了交易能力。企業應該具有清晰的上報流程,最好是具有一種中止機制(Stop-the-line Culture)。
- 在發生故障的45分鐘里,他們在不了解錯誤原因的情況下將正確的更新進行了回滾。這使得問題更為復雜化,而非解決了問題。一個實時系統不知因何出錯,卻手忙腳亂地處理,只會讓事情變得更糟。不要這樣做。
- 這反映了他們缺少自動化安裝,也缺少讓系統離線的簡單方法。他們應該將“更新”和“緊急停止”都自動化。
InfoQ:對于如何處理無用代碼,你有哪些建議?
Henney:我的建議就是:“找到他們,刪除他們。”
“找到他們”是其中最難的部分。有時無用代碼真是難以觸及,正如靜態分析所給出的。靜態分析的有效性雖然取決于所使用的工具、語言和架構,但它是一個很好的解決問題的好出發點。
內幕交易在股票交易中被認為是非法操作,但是在代碼里使用內幕知識卻是完全可被接受的。開發人員可能對超出需求的代碼實現已經有了很好的認識。利用產品特性知識也是完全合法的,當在需求層撤回或替換特性時,關聯到這些特性的代碼可能也終將退役。
另一條可用線索是代碼穩定性。你的版本控制系統是一個關于變更的知識庫。代碼塊的哪一部分從未變更過?很多原因導致代碼從未變更,例如:代碼已經正確的、代碼是無用的或者只是不敢于去更改的。除非開展調查,否則你也不知道原因。當然由于自動重構,無用代碼可能仍保持被更改的狀態,這些更改也有與其他重構更改相關的簽名,但并非是修復軟件故障或添加特性。
系統的運行時監控并不能明確指出哪一部分代碼是無用的,但可以明確指出哪一部分代碼是活的。這有助于縮小搜索范圍。
簡而言之,就是做假設并進行調查。
刪除無用代碼并非技術問題,而是思維模式和文化上的問題。人們常會感覺代碼如果不做一些事情就沒有效果,因此將代碼遺留下來也是可以的。需要牢記正是出于同一理由,我們應該移除這樣的代碼。即如果代碼不做任何事情,那么移除它。這個原則可以由版本控制系統替你實現。
移除代碼出于很多原因,并非僅是因為存在僵尸災難的可能性。無用代碼使得運行時的資源占用大于所需資源。如果你關心的是性能,那么就要考慮移除無用代碼。此外,對于編程人員理解問題并采取行動而言,無用代碼也是一個障礙。充斥了無用代碼的系統浪費了開發人員的時間,妨害了軟件文化,導致代碼總處于修改和改進狀態。
如果你是因為不確定是否為無用代碼而不想移除這些代碼,這種不確定性其實是說明了你的架構存在的問題以及它與開發人員之間的關系。
InfoQ:你在演講中也談到了關于處理錯誤的代碼的問題。處理錯誤的代碼并非無用代碼,但是其中的問題常被忽視并遺留下來。對非致命錯誤的不正確處理是如何導致災難性失敗的?
Henney:某一部分代碼被使用得越多,越可能是發生過缺陷的地方。處理錯誤的代碼通常是系統中最不常被使用的代碼,很多錯誤場景是非常罕見的。因此雖然存在處理各種錯誤場景的代碼,但是代碼的正確性并未得到驗證。一旦罕見錯誤場景發生,雖然處理錯誤的代碼在設計上是用于解決錯誤而非產生新的錯誤,但是控制流程在導向有問題的執行路徑后整個系統就崩潰了。有時毫不夸張的說,就像1996年首次阿麗亞娜火箭失敗那樣。
InfoQ:對于處理出錯狀態和異常,您能給出哪些建議?
Henney:我的建議是做審核、靜態分析和自動化測試。全面的走查和透徹的討論有助于找出被疏忽的地方并發現新的問題。你可以從工具中得到一些有用反饋,了解在運行時發生的情況。反饋的內容根據編程語言不同而有所差異。
測試是一種確認在安全環境中執行代碼片段的方法,謹記人們在編寫處理錯誤的代碼時總會有些盲點和樂觀傾向,僅僅去測試正常用例(Happy-Day Scenario)。為解決該問題,時常問一下自己:當發生錯誤時,相應的處理代碼在哪里?對錯誤條件的測試在哪里?對處理代碼的測試在哪里?
來自:http://www.infoq.com/cn/news/2017/02/dead-code