最近準(zhǔn)備推動(dòng)團(tuán)隊(duì)產(chǎn)品進(jìn)行代碼重構(gòu),過程中遇到一些問題與困難,由此也回想起早年經(jīng)歷過的一些重構(gòu),其中有些并非我主導(dǎo),在此簡單記錄,主要談其中印象深刻的體會(huì),不展開。
第一次重構(gòu)
我剛參加工作不久,進(jìn)入了一個(gè)剛剛重組成立的項(xiàng)目組,我們接手時(shí)前面的人都已經(jīng)離職了,一個(gè)不剩,就是這么任性,當(dāng)時(shí)的代碼是用 C++ 寫的,而且比較混亂,難以維護(hù),當(dāng)時(shí)的老大決定用 C# 將項(xiàng)目重寫, 于是帶領(lǐng)我們進(jìn)行了我職業(yè)生涯的第一次重構(gòu)。重構(gòu)的目的主要是希望優(yōu)化設(shè)計(jì),減小維護(hù)成本。印象深刻的是在重構(gòu)之前,老大讓我跟他一起畫了一個(gè)看起來巨牛逼的重構(gòu)設(shè)計(jì)圖,其中引入了各種不明覺厲的設(shè)計(jì)模式,今天回想起來只能用過度設(shè)計(jì)來形容了,實(shí)際上最后非但沒有減小維護(hù)成本,反而因?yàn)橐肓艘恍?fù)雜的設(shè)計(jì)模式,導(dǎo)致代碼層次深性能差,難以理解。隨著最初主導(dǎo)設(shè)計(jì)人員的離職,框架開始崩壞,后續(xù)越來越難以維護(hù),到最后不得不面臨再次被重構(gòu)。
第二次重構(gòu)
這次的重構(gòu)由公司里一位非常優(yōu)秀的工程師來主導(dǎo),也正是他直接指出之前過度設(shè)計(jì)的問題,提出了一套更加簡單清晰的設(shè)計(jì)方案,設(shè)計(jì)本身是業(yè)內(nèi)經(jīng)典架構(gòu),并沒有太大問題,最后也是順利完成,但重構(gòu)后的代碼并沒有堅(jiān)持太久,又開始逐漸腐化,根本原因還是在于各種程序員的代碼水平參差不齊,項(xiàng)目里太多低質(zhì)量的代碼,又沒有code review 來保障質(zhì)量。我的感受是光靠架構(gòu)設(shè)計(jì)本身,并不能解決所有問題,代碼腐化是發(fā)生在產(chǎn)品演進(jìn)迭代過程中的,好的架構(gòu)不是銀彈,只關(guān)注宏觀結(jié)構(gòu)不注重細(xì)節(jié)質(zhì)量必然也是不行的。
第三次重構(gòu)
這次我們面臨了新的復(fù)雜業(yè)務(wù)的需要,同時(shí)也引入了一位新的、比較純粹的架構(gòu)師,意思是基本只負(fù)責(zé)架構(gòu)設(shè)計(jì)與架構(gòu)實(shí)現(xiàn),在實(shí)際重構(gòu)過程中,還是發(fā)現(xiàn)了一些問題:架構(gòu)師有自己的架構(gòu)理想,希望將自己多年的架構(gòu)經(jīng)驗(yàn)付諸到具體的業(yè)務(wù)里,驗(yàn)證自己的想法,因此這次又產(chǎn)生了過度設(shè)計(jì)的老問題,而且比之前還要嚴(yán)重,每當(dāng)問及他這里為何要如此復(fù)雜設(shè)計(jì)?理由都是將來這里可能會(huì)怎樣變化云云,咋一看挺有道理,而實(shí)際上很多擔(dān)心過的變化直到我與他都離開也從未發(fā)生過;除卻過度設(shè)計(jì),他當(dāng)時(shí)的一些設(shè)計(jì)觀點(diǎn)現(xiàn)在看來也有些陳舊過時(shí),應(yīng)該跟他之前的從業(yè)經(jīng)歷有關(guān),每個(gè)人都可能受自身背景的局限,唯有不斷學(xué)習(xí)與了解各種業(yè)內(nèi)新知識(shí),與大家多交流,才能突破自身技術(shù)視野的狹窄。
第四次重構(gòu)
這次是我自己主導(dǎo),主要是針對(duì)新業(yè)務(wù)的擴(kuò)展需要,對(duì)現(xiàn)有代碼進(jìn)行調(diào)整,其實(shí)并沒有大的架構(gòu)調(diào)整,除了對(duì)代碼的整體結(jié)構(gòu)整理,都是一些局部代碼的調(diào)整,以滿足業(yè)務(wù)的擴(kuò)展需要,同時(shí)對(duì)以前的一些痛點(diǎn)針對(duì)性調(diào)整,完成后確實(shí)也達(dá)到了部分目標(biāo),但仍然遺留了很多問題沒有解決。這次的主要收獲是,重構(gòu)前要有明確的要解決的目標(biāo),針對(duì)目標(biāo)設(shè)計(jì)方案,不要為了重構(gòu)而重構(gòu),追求完美心態(tài)的重構(gòu)。當(dāng)然也有一些教訓(xùn),重新認(rèn)識(shí)到自己能力有限,看了很多這方面的書,還是沒能做好,低估了其中的困難,也沒能從整體上進(jìn)行規(guī)劃,代碼已經(jīng)過于龐大,也是畏懼大改,深怕陷進(jìn)去,一些陳舊的不好的代碼模版仍然被保留,甚至還引入了一些新的坑。
在迭代中重構(gòu)
以上是我職業(yè)生涯經(jīng)歷過的一些印象深刻的大規(guī)模重構(gòu),越到后面,越發(fā)明白等到技術(shù)債務(wù)欠到一定程度,需要進(jìn)行完全推翻重來的重構(gòu),是一件多么困難的事情,除非有足夠的資源與支持,否則風(fēng)險(xiǎn)極高,也未必能做好,因此個(gè)人的建議是重構(gòu)必須隨時(shí)進(jìn)行,在每個(gè)迭代中進(jìn)行,在很多重構(gòu)相關(guān)的書里都提到過這點(diǎn),但真正能做到的人不多,每次我們要開發(fā)新功能,一旦涉及到代碼里的技術(shù)債務(wù),就盡量設(shè)法一并處理掉,這樣你不僅做完了新功能,同時(shí)也還清了一個(gè)技術(shù)債務(wù),是我認(rèn)為比較理想的重構(gòu)方式,當(dāng)然這需要我們?cè)陂_發(fā)時(shí)為此預(yù)留足夠的時(shí)間,最終能否可行,取決于團(tuán)隊(duì)以怎樣的態(tài)度看待技術(shù)債務(wù),在技術(shù)改進(jìn)與業(yè)務(wù)推進(jìn)之間做出權(quán)衡。