一些不幸的軟體工程師剛開始工作時,會納悶:為何公司的程式碼如此難維護?為何臭蟲總是總是層出不窮?在新創或是幾乎從無到有打造軟體的團隊,恐怕不會遇到這些問題,這些創始成員能夠掌握自己的程式碼,而專案的規模也不大。然而產業發展至今已有數十年,有十多年歷史的公司也不在少數,這意味著,絕大多數的人還是得維護別人的程式碼、基於別人的程式碼完成自己的業務;令人惋惜的是,一旦工作幾年後多數人便再也不納悶。
我們經常聽到這樣的話:
- 「當時做這個功能很趕」
- 「能正常執行的程式碼,千萬別去動他」
- 「我也很想改,但我們沒有時間」
程式的本質
討論重構之前,也許我們得先從重新審視程式的本質。程式的本質總歸來說就是三個字:I P O,並不是initial public offering而是input、process、output。程式的輸入可能是一組變數也可能是使用者的輸入或是某份文件,process則是程式中的計算、控制流程,output則是最後計算的結果或對狀態造成的改變。總歸來說,任何程式都離不開IPO,就算沒有input也是一種input,沒有output也是一種output。IPO這個簡單的觀念,對理解重構與重構的必要性來說至關重要。
為何需要重構
「能正常執行的程式碼,千萬別去動他」這句話被許多人奉為圭臬,首先我並不反對這句話,但我與許多人的前提不同。
你多常見到「能正常執行的程式碼」?正常執行,是基於團隊對目前的認知,然而認知是會改變的。有可能只是還沒有發現錯誤,也有可能明天需求就改變了。就算今天能正常執行,明天也未必。也許你會聽到這樣的說法:「基於開閉原則,我們不應對模組進行修改,而是進行擴充」這句話也是對的,但並不構成不去重構(修改)的理由。如果你的程式碼已經達到能滿足 SOLID 原則的程度,那多數不需要重構甚至方便進行測試以及重構,這種狀況下也就不會對重構排斥。
如果需要修改,又不想動既有的程式碼,會怎麼做呢?我見過最可怕的做法是,複製了一個長達幾百行的函式,給他一個相似卻又讓人容易混淆的新名稱,並且在複製出來的程式碼中進行修改。又或者,在程式碼中新增了六七個參數,並且在流程中區分是否走舊流程。無論是哪種方法,這種自認堅守「能正常執行的程式碼,千萬別去動他」思想的作法,都傷害了原始碼品質。
複製相同性質的程式碼並修改,只會使得維護成本倍增。舉個例子:測試團隊發現目前的某個支付流程已有錯誤,開發團隊也進行修正,然而負責修正這個錯誤的工程師僅修復了其中一個,其餘被複製的程式碼並沒有被修正。這時,測試團隊必須再一次驗證一個相似的錯誤,而開發者也必須再一次修正一個相似的錯誤;狀況有可能變得更複雜,如果這個錯誤是由兩個不同的開發者來修正呢?他們的修改方式會一模一樣嗎?很難。反過來說,如果將兩段不同卻又相似的流程塞在一個數百行的函數中,會使得狀況更好嗎?通常不會。負責維護這段程式碼的人必須花更多時間來理解。
這還只是需要重構的其中一個例子,其他的還包含由高耦合性造成的複合性錯誤、難以擴展或進行單元測試的架構、效能不彰的計算等等……
排斥、需要重構背後真正的意義
「我很想重構,但公司政策不支持」
「我當時只想著快點把功能做好,程式寫醜一點但能跑不好嗎?」
那些不重視程式碼品質的公司,通常會在某個時間點,感受到某種說不上來的壓迫感。像是那些排水漸漸不順的水管,你不知道裏頭到底有多少油垢或造成堵塞的義務,只期望在你任內的時候水管不要完全堵塞。面對完全堵塞的水管,可能會用一些粗暴的手段、甚至不惜傷害水管,而有些人會完全放棄。對應到軟體公司來說,通常是:
- 透過提高工作時數、人員數量來提高人月
- 人員流動率或離職率提高
- 工程師表示:目前的架構很難動
- 臭蟲越來越多、測試期間越來越長
然而就管理或個人的角度而言,重構不受歡迎往往有個更實際的理由:「重構沒有直接的績效」 重構大多不會直接帶給客戶任何直接或立即的效益,除非重構兼具了效能的提升。管理者不希望公司因為重構而原地踏步,工程師不希望重構浪費自己的時間影響自己的績效。
但在這裡我想問一個乍看無關的問題:
「你覺得從零開始開發軟體比較快,還是基於過去開發的成果比較快?」
肯定是後者對吧。但是如果你無法妥善利用既有的程式碼呢?甚至,你萌生了「把這個砍掉重練吧」這樣的想法,那是否說明了一個道理:你無法掌握的程式碼並不是資產,更有可能是債務。危言聳聽地說,我們為了還債,往往得投入更多的人力與時間。
我的專長之一是效能最佳化,我做的事情並沒有多困難,我並不會研發一個新的湊雜函數或使用複雜的資料結構來進行加速,大多狀況下那些都是80:20的20那一側;那些緩慢的程式碼都具有一個共通的特色,他們的粒度不夠、流程複雜,那才是80所在。而經過重構,這些程式碼比原本更有彈性也更好擴充,理由無他,因為我掌握了這些程式碼也讓別人更易於掌握這些程式碼。我相信沒有任何一個軟體公司的老闆會希望自己公司的步調越來越慢、成本越來越高,我也相信沒有任何一個工程師會希望自己每天要面對牽一髮動全身、寸步難行的程式碼。
在未來的文章中,我會逐步說明一些重構的技巧與觀念。大部分是我自己發現並在工作中應用後在書中得到驗證的,希望無論是對群體或對個人都能產生助益。