怎樣避免脆弱的程式碼?

發表於2016-06-29

遺留程式碼最常見的問題就是脆弱性。團隊如要修改脆弱的程式碼庫,必定伴隨著巨大的痛楚。在我們 ThoughtWorks 開發產品的 10 年裡,當我們年復一年地儘量保持龐大程式碼庫的延展性時,學到了一些慘痛的教訓。我想在本文分享我們從最大挑戰中吸取的教訓。宣告:我寫下這些思考,不代表我們已經搞定了所有問題。我們仍然要分擔遺留程式碼的痛苦,和其它團隊一樣,我們每天都努力讓它變得更好一些。

怎樣避免脆弱的程式碼?

更新所有東東,要一直更新下去

你應該一直渴求更新依賴庫和框架。好吧,或許現在已成為共識。但是,10 年前很少有人這樣想。有些團隊明白,升級是需要完成的、正確的工作,我只是懷疑,他們是否真地優先去做了。它一直需要你認真對待,不要拖到最後,變成技術債務。原因如下:

  1. 如果某項任務是痛點,就要經常去做。對於一直升級所存在的最明顯的理由之一,就在於升級會是艱難的。常常存在不可預期的、一系列被破壞的依賴。工作量通常無法知曉。經常做,它就不再是問題。但是,和簡單的避免痛苦相比,還有更重要的原因。
  2. 升級依賴項的另一個驅動力,在於修復安全漏洞。現在和 10 年前開發軟體,有一個最大的不同,我們資源庫、框架和應用程式的漏洞報告彷彿從未間斷過。修復漏洞,差不多總是涉及到升級某些依賴項。為了快速修復漏洞,升級必須容易操作。
  3. 沒有定期升級操作的團隊,通常將其貼上技術債務的標籤。儘管行業比 10 年前更樂意談起技術債務,但是,說服專案經理償還技術債務,仍然算得上非常艱難的對話。如果你的團隊處於「一直升級所有東東的模式」,你就不用為了升級技術債務而展開溝通。

關於單元測試

遺留程式碼的主要痛點在於,做出修改需要花費多長時間。如果你打算讓程式碼長期執行下去,就需要確保未來修改程式碼的程式設計師感到完全地開心。有一種處於優勢的方法:極度快速、徹底的單元測試套件。

增加新功能、包括任何程式碼重構,每個週期大致描述為:編寫失敗的測試;寫程式碼;顯示綠色;搞定。如果你這樣做了,你就能一直執行大量的單元測試,有時候是某一套針對性的測試、有時候是整個套件。如果測試不夠快,開發週期就不會輕鬆。寫程式碼的體驗不應該是:做了一些修改,而執行測試卻需要坐等 10 或 20 分鐘。太差勁了。

確保測試套件快速執行,不只是與你的設計和程式碼有關。誠然,你可以做大量工作來加速測試,比如避免檔案、資料庫、套接字、海量物件圖表生成等。但是還有另外的重要技巧,挑選有助於加速測試的框架和語言。如果你發現自己為了讓測試更快、而修改了框架,那麼,你需要考慮不同的框架。是的,當我正在開發傳統的多頁應用程式時,下次就不可能用 Rails 開發了。

還需要考慮應用程式的大小。當某個程式碼庫處於一定規模時,就需要規劃好切分方案。這也是讓你充分理解某塊程式碼的唯一方法。找到分割專案的切入點,這不同於學術上的工作,你需要投入大量時間折騰程式碼、研究各種地方、再設計、重構。一直讓快速的測試套件迅速地驗證你的工作,將使這份工作輕鬆幾個數量級。

實際上,「幾個數量級」更像是誇張。如果你需要切分龐大的程式碼庫,並忍受著痛苦的、龜速的單元測試套件,嗯,你可能會被困住。我們正在痛苦地得到教訓。因此,盡力確保單元測試要快,並且在開發機器上以單一執行緒執行。

「抽象分支注1」不應該是常態

執行時間長的產品,經歷了很多技術領導。某些型別的技術領導,剛一接手,就抱怨現有產品的不足,並馬上想開發新的產品。這沒錯。時髦的技術不總是糟糕的。對於長時間存在的程式碼庫,它需要新的活力,產生足夠能量,淘汰不能勝任的地方。我想提兩個重要的點。

新接手的技術領導,在和團隊一起工作兩到三個月之前,不要輕易摒棄任何技術。有太多的情景需要理解。新接手的技術領導需要學會站在團隊和程式碼庫的角度考慮。團隊和技術領導需要建立信任和節奏。短暫地停留是為了更好的決定。

利用抽象分支,是替換新技術的經典方法(長期分支的荒謬性之外):

  • 元件 X 前面放置一個抽象。
  • 元件 Y 做為 X 的替換品,被引入。
  • 抽象智慧地路由到 X 或 Y。
  • X 逐步被廢棄掉。
  • X 被移除;或許抽象也被移除了。

有很多次,我都看不到這個過程能夠順利走完,因為移除舊元件最後 20% 的工作太難了。你簡直想象不到,年復一年地用多種方式做這項工作有多麼痛苦。它減緩了所有工作,還讓士氣消沉。抽象分支屬於優秀的模式,他也是我做這種元件替換工作的唯一方式。但是,它需要團隊的完全承諾,即,在既定時間內,淘汰舊元件。

技術債務會殺了你

僅僅因為我們這裡過多地討論了技術債務,並不能為償還技術債務提供任何擔保。有一點是肯定的,任由技術債務積壓下去,只會使其變得無法償還。「先放一放。我們先做其它緊急需求,它被記下來了,我們回頭再搞。」,這話很容易說出口。同時,它可能算得上明智決定。但是,那些所謂的緊急需求永遠沒有結束的那一天。緊急清單隻會越變越長。

狀況會惡化下去。據我經驗看,當技術債務積壓增長過於頻繁時,團隊將趨向於放棄償還,團隊感到失望,開發人員不能達到流動,業務也獲取不到新的價值。關於如何避免不可逾越的技術債務,我做過一些思考。

一個良好的開發團隊,不會一而再、再而三地以技術債務為藉口。當團隊意識到,同種技術債務重複出現時,就必須向前推動,並很快將其融入到日常工作中去。

我的同事 Badri 建議,團隊必須就共同承擔技術債務達成一致。任何人無權讓程式碼庫變得更糟、而讓整個團隊隨後為此買單。

更重要的是,技術領導和產品領導需要彼此信任。雙方都不應該玩「我說了算」的把戲。好的技術領導理解業務的優先順序,好的產品經理看重能夠交付的價值。雙方均需要探討風險、成本和收益。如果你無法交付,你的技術債務就轉變成了業務問題,對每個人都沒有好處。

顯然,為了編寫長期存在的程式碼,一個團隊還有大量工作要做:為閱讀程式碼的人寫程式碼,不要自作聰明,經常想想你未來的同事。我樂於聽到你的想法。

相關文章