大多的程式人都不愛他人遺留下來的程式碼(有些人甚至是用「痛恨」等更激烈的字眼),尤其是當這些程式碼的原作者已經離職而且無法聯絡上。這樣的程式碼,有人將它們稱為「Legacy Code」,中文則譯為「既有程式碼」。

這類的程式碼的特性,並不是在於它存活了很長一段時間,而是在於已經沒有人能夠理解甚至進一步修改。從這邊可以觀察出來,Legacy Code造成的困擾,正是在這兩個面向上──一個是理解,另一個則是修改。

既有程式碼可能代表著組織長久的經驗及智慧
Legacy Code固然會造成困擾,但是它偏偏又存在。大多數的軟體開發組織,都難免面臨開發成員來來去去的情況,只要有人離開,這人所負責的程式碼,便搖身一變成為Legacy Code。

尚在維護的系統毋需多言,只要還在線上運行一天,就不能因為有人離職而把它廢掉。而共用程式碼,對於開發組織的價值同樣很大,因為它代表組織長久以來的許多經驗及智慧的結晶。這些程式碼,通常代表著可重複使用的程式碼,使用它們可以大幅提升生產力。而這生產力的來源,不單只是因為它減少了撰寫程式的時間,同時這些程式碼經過反覆地運用,早已久經測試、百鍊成鋼。

這些程式碼累積了許多的經驗,長期以來的考驗及修改,有能力應付各種可能的情況。

砍掉重練未必是最好的選擇
Legacy Code無法拋棄,然而也讓人退避三舍,因為之所以會被稱為「Legacy」,是因為已經沒有人熟悉、能夠很有把握地修改。但只要我們還無法捨棄、作廢,終究必須試著和它和平相處,甚至進一步善用它的力量。

面對Legacy Code的第一個難題,就是了解並熟悉這些既有的程式碼。程式人都不愛了解別人所寫下的程式碼,寧願重寫。這是因為重寫新的程式碼,能夠有機會運用新的技術,另一方面,心中又會有那種「昨日種種譬如昨日死」的痛快感覺。

把一切打掉全新做起,就像毀壞一切的大革命,將建立起全新的國度,而在新的國度裡,一切都是那麼美好。不過,事實上,大多數人寫的程式碼一旦過了「保存期限」,終是落到慢慢「腐敗」的局面,新的世界並未來到,而程式人只是選擇再一次「砍掉重練」。

借助極限編程的作法,避免程式碼成為Legacy Code
對Legacy Code的了解與熟悉,是處理Legacy Code的基本功課,一點都不了解,就別說要做什麼處理了。

從技術的角度來處理這個議題,可以從兩個方向努力:加強閱讀程式碼的技巧及提升所寫程式碼的可讀性。

那麼,從管理上又要如何協助面對Legacy Code呢?簡單來說,就是從管理上盡量避免程式碼變成Legacy Code,也就是避免程式碼變得「沒有人能夠理解甚至修改」。

著名的極限編程(eXtreme Programming,XP)對此便多有著墨。或許你的組織並不是採用極限編程或者是其他輕量級的開發方法,但這精神也值得多加借鏡。

XP的12項實務中,系統隱喻(System Metaphor)、程式共享(Collective Ownership)、搭檔編程(Pair Programming)、以及編程標準(Coding Standards)等,都能避免程式碼漸漸成為Legacy Code。

關鍵在於,首先,它建立起組織裡共同而且持續性的符號及撰寫風格,使得每個程式人寫出來的程式碼幾無分別,其次,避免特定程式碼總是由特定人所維護。

這兩個關鍵是有關聯的,倘若不能做到所有程式人都使用相同的符號(主要是命名方式)以及撰寫風格,那麼同一份程式碼,便很難交由其他人維護或改寫。兩人搭檔編程的作用,不僅在於讓一人專職監看,同時也有利於內含在程式碼中的資訊及知識在組織中流動。

搭檔編程不見得廣為眾人所接受,但是它的基本精神值得參考。組織除了可以透過分散程式碼的撰寫及維護責任之外,也可以透過其他的方式,讓程式碼中的資訊及知識,有效地在組織之中流動。

大家都知道,由於時間的限制,工作的交接通常僅具形式,缺乏實質作用。因此,程式碼的撰寫及維護責任,倘若能平均的分散在組織中,而且資訊及知識也能有效流動,這便是一個長期持續作用的事情,即便有人員異動,程式碼也不容易成為Legacy Code,因為沒有任何人是任何程式碼的唯一主人。

Legacy和Non-Legacy Code區分的關鍵在測試
以上是針對避免Legacy Code產生而提出的應對方向。但即使是自己所寫下的程式碼,曾經深知所有細節,也有可能因為時間的過去,而對這些細節不復記憶,這些程式碼也有可能成為Legacy Code。倘若已經存在Legacy Code時,要如何與它和平相處呢?這顯然是一門大學問。

Michael Feathers曾經對Legacy Code下了另一個定義,他認為Legacy和Non-Legacy Code區分的關鍵,在於測試。

我想,如果害怕看不懂一組數量龐大的程式碼,是淺層恐懼的話,那麼Michael Feathers便捕捉到人們對於Legacy Code的深層恐懼──害怕修改數量龐大的程式碼。

的確,具備閱讀程式碼技巧的程式人,不難快速理解一組程式碼的基本運行架構,即使規模龐大。但是,我想絕大多數的程式人,都害怕修改規模龐大的程式碼,因為你深深明白,你知道如何修改來達成目的,但是,你也知道這修改真正難的地方,不在於了解並且修改程式碼,而是難在你不知道是否會引出許多意料之外的副作用。

Legacy Code只要能正常運作的話,本身並不會造成傷害,傷害都是企圖修改時產生的。所以,Michael Feathers明白地指出關鍵在於測試。有足夠的測試資本包括為了測試而寫的程式碼和測試案例,在了解大致運作方式之後,便有信心修改,因為測試會協助你找出因修改而發生錯誤的所在。

安心修改的前提──程式能有效測試
關於這個主題,Michael Feathers有本相當著名的書籍值得推薦──《Working Effectively with Legacy Code》。在這本書中,你會看到一套完整的理論及方法。簡單來說,測試是處理Legacy Code時的重要工具,必須倚靠它做為修改的信心後盾,以檢視修改作用是否造成不預期的副作用。

除了測試之外,這本書中所建議的技巧,可以協助我們找出Legacy Code中需要被截斷的相依性。為什麼相依性需要被截斷?因為相依性是修改發生時,衝擊所會傳遞的路徑。

依據他的建議,我們必須要適當地截斷一些相依性,使得我們能夠針對我們所做的修改進行測試。因為很明顯地,倘若沒有截斷一些相依性,縮小改變影響的範圍,那麼修改所影響的層面,便有可能隨著相依性擴散出去,這麼一來,測試的難度以及需要覆蓋的範圍便高上許多。

從測試來談Legacy Code是很有趣、也很實用的觀點。的確,處理Legacy Code的難處在於修改,想要安心地修改就要能有效地測試。透過截斷相依性的技巧,來輔助測試進行,更能確保我們對Legacy Code的修改更具信心。

專欄作者

熱門新聞

Advertisement