碼妞:領(lǐng)導(dǎo)讓我重構(gòu)代碼,怎么辦?
什么時(shí)候進(jìn)行重構(gòu)?
任何時(shí)間都可以進(jìn)行重構(gòu),前提是你有足夠的時(shí)間以及精力去做這件事情,大部分公司重構(gòu)代碼是不會計(jì)入KPI的,甚至重構(gòu)的越多,出bug的概率就越大,背鍋的可能就越大。因此,小規(guī)模的重構(gòu)或者自己負(fù)責(zé)功能的重構(gòu),可以穿插在需求中進(jìn)行;大規(guī)模重構(gòu)因?yàn)楹馁M(fèi)時(shí)間較長,出錯(cuò)概率較高,必須要得到上級的支持才能進(jìn)行下去。
大規(guī)模重構(gòu)的需求來源一般都是因?yàn)槟壳凹夹g(shù)架構(gòu)已經(jīng)不能滿足快速的業(yè)務(wù)迭代,可維護(hù)性差,新人上手困難,出現(xiàn)bug幾率增加,當(dāng)代碼已經(jīng)到達(dá)這個(gè)程度的時(shí)候,就需要推進(jìn)進(jìn)行大規(guī)模重構(gòu)了。
重構(gòu)的原則
需要理清楚的是重構(gòu)不是重寫,更不是解決bug,引入新需求。很多新手在進(jìn)行重構(gòu)的時(shí)候,往往會在重構(gòu)過程中去修改之前的固有邏輯,甚至增加一些自己的業(yè)務(wù)理解去“優(yōu)化”現(xiàn)有的代碼,這是大錯(cuò)特錯(cuò)的,因此重構(gòu)的***個(gè)原則是:“忠于原代碼”,特別是在自己無法理解之前業(yè)務(wù)的下,盡量忠于原文,可以減少產(chǎn)生的新的bug,可測性增強(qiáng)。
重構(gòu)的第二個(gè)原則:“逐步實(shí)施”。盡量不要一下子就推翻重建,應(yīng)該從盡量底層去抽取共性,由點(diǎn)及面,分解目標(biāo),逐步實(shí)施;比如你要對當(dāng)前代碼做整體的MVP重估,這個(gè)時(shí)候你可以先把當(dāng)前業(yè)務(wù)理清楚,分析核心業(yè)務(wù),從最簡單的業(yè)務(wù)入手,保留原有的結(jié)構(gòu),逐步兼容,然后慢慢把之前的代碼精簡掉甚至移除。
重構(gòu)的第三個(gè)原則:“簡潔邏輯而非減少代碼”,重構(gòu)最終的目標(biāo)是需要符合軟件工程中單一指責(zé)以及開閉原則的,代碼行數(shù)的多少不是關(guān)鍵,怎么理清楚邏輯,讓后續(xù)維護(hù)方便,入手學(xué)習(xí)成本低才是最關(guān)鍵的。很多人以“從XXX行到XX行”為重構(gòu)的目標(biāo),行數(shù)的減少是衡量指標(biāo)之一,但絕不是最重要的指標(biāo)。比如RxJava的引入,可能會增加代碼量,但是邏輯更清晰了,增加功能更容易了,這就是成功的重構(gòu)。
重構(gòu)的另外一個(gè)原則就是:“合適的才是***的”,很多人重構(gòu)代碼就是炫技,一旦給他重構(gòu)代碼的機(jī)會,就如脫韁野馬,引入大量自己并不熟悉的框架進(jìn)行,覺得這是一個(gè)學(xué)習(xí)的好機(jī)會,一旦出現(xiàn)問題就無法解決。怎么就算合適了,在我看來,合適的架構(gòu)一定是以下幾個(gè)特征:
- 學(xué)習(xí)成本低,新人入手容易,市場上資料多;
- 不過度設(shè)計(jì),但是又容易擴(kuò)展,以后換成新架構(gòu)也方便;
- 不要過度結(jié)耦;
前面兩點(diǎn)比較容易理解,第三點(diǎn)怎么理解呢?寫代碼久了,就會明白一個(gè)定律:“代碼邏輯守恒定律”,就是無論你怎么設(shè)計(jì)架構(gòu),代碼邏輯是不會減少的,一個(gè)地方邏輯減少了,就一定會在另一個(gè)地方邏輯增加。解偶就意味著,你把不屬于這一塊業(yè)務(wù)的邏輯轉(zhuǎn)移到另外一個(gè)地方,過度解構(gòu)要么是劃分了很多個(gè)模塊,要么就是把對應(yīng)的業(yè)務(wù)放在了“看不到”的地方,當(dāng)“看不到”多了以后,就會造成查找問題非常麻煩,比如過多的在Java使用注解或者編譯時(shí)注解。過度解偶其實(shí)就是隱藏了不必要隱藏的邏輯,對調(diào)用者完全透明,問題的追蹤就會在透明層被截?cái)?,從而?dǎo)致問題的產(chǎn)生。
怎么實(shí)施重構(gòu)
參與重構(gòu)人數(shù)不宜過多,兩三人為宜;功能不宜分散,至少每個(gè)人應(yīng)該要重構(gòu)一個(gè)業(yè)務(wù)功能模塊或者功能點(diǎn),這樣可以更好減少溝通成本。
大規(guī)模重構(gòu),應(yīng)該從下至上,先理清晰要達(dá)到的目標(biāo),先從底層邏輯開始重構(gòu),逐步到上層。比如在Android中對之前代碼的重構(gòu),應(yīng)該是先模塊,后組件,然后逐漸到具體業(yè)務(wù),這樣就可以保證整個(gè)過程中重構(gòu)的一致性。
在進(jìn)行重構(gòu)之前,需要對要達(dá)到的重構(gòu)目標(biāo)做一個(gè)評估,是要完全重構(gòu)完,還是只需要對關(guān)鍵業(yè)務(wù)做梳理,亦或是需要整理出一個(gè)模版,然后分布實(shí)施。不同的目標(biāo)對應(yīng)不同的做法以及不同的工作量;在重構(gòu)之前還需要需要對當(dāng)前關(guān)鍵業(yè)務(wù)做梳理,理清楚周邊支撐組件和必須要提前的工作量。
比如,某一次重構(gòu):
- 目標(biāo):完成所有業(yè)務(wù)模塊的MVP重構(gòu)
- 關(guān)鍵業(yè)務(wù):打車、訂單管理、地圖
- 效果
- 模塊抽取(module1/moduel2...)
- 基礎(chǔ)組件
推送/IM
網(wǎng)絡(luò)
支付
...
- 規(guī)范
預(yù)估時(shí)間 30天/1人
圍繞關(guān)鍵業(yè)務(wù)設(shè)計(jì),設(shè)計(jì)好了關(guān)鍵流程,重構(gòu)就成功了一半。在重構(gòu)中,還有一個(gè)比較基礎(chǔ)問題就是:編碼規(guī)范的問題;編碼規(guī)范盡量使用工具去最規(guī)范。類似于sonar/lint等工具做到自動(dòng)識別,自動(dòng)提醒,不要浪費(fèi)太多時(shí)間在上面。