代碼腐爛可以避免嗎?
一個(gè)蘋果放在桌子上不理它,它會(huì)慢慢地變壞。代碼也跟蘋果一樣,會(huì)發(fā)生代碼腐爛。壞的代碼就跟壞的蘋果一樣,會(huì)更容易發(fā)生腐爛、腐爛得更快。工作時(shí)間久了,關(guān)注的角度從個(gè)人變成了團(tuán)隊(duì)整體。我就會(huì)想:代碼腐爛是否真的不可避免?有什么辦法能夠避免代碼腐爛呢?
代碼腐爛可以避免嗎?
對(duì)于這個(gè)問題,我想了挺久,后面發(fā)現(xiàn)答案是:代碼腐爛不可避免,只不過是時(shí)間問題。 雖然很沮喪,但是卻認(rèn)清了事物的本質(zhì),走上了一條正確的道路。這比起不愿意接受,然后制定錯(cuò)誤的決定來(lái)得更好。
我給出代碼腐爛不可避免的結(jié)論,其實(shí)是在思考了許多之后才做出的結(jié)論。代碼質(zhì)量高低取決于許多因素,包括但不限于:需求緊急程度、需求變化程度、團(tuán)隊(duì)成員技術(shù)能力、團(tuán)隊(duì)幸福感等等。這些因素都會(huì)從不同方面影響到代碼質(zhì)量,從而造成代碼持續(xù)腐爛。
如果一個(gè)需求特別緊急,這時(shí)候我們不會(huì)考慮使用多么高深的代碼結(jié)構(gòu)去實(shí)現(xiàn),肯定是短平快直接開干。畢竟對(duì)于現(xiàn)在來(lái)說,時(shí)間才是我們真正的敵人。這時(shí)候的代碼質(zhì)量肯定沒有那么高,考慮得也沒有那么全面,這時(shí)候代碼腐爛的進(jìn)度條又快速往前跑了一步。
需求變化程度也會(huì)影響代碼腐爛的程度。如果需求來(lái)來(lái)回回變化特別大,那么我們很難設(shè)計(jì)一個(gè)統(tǒng)一的架構(gòu)去適應(yīng)需求。這時(shí)候就會(huì)出現(xiàn)分叉,分叉變得多了,代碼結(jié)構(gòu)就不好理解了。代碼腐爛就自然而然發(fā)生了。
團(tuán)隊(duì)成員技術(shù)能力也是一個(gè)很重要的點(diǎn)。很多時(shí)候我們希望大家能用更好的代碼結(jié)構(gòu),例如設(shè)計(jì)模式,例如用封裝的思路來(lái)寫代碼。但是團(tuán)隊(duì)成員的能力是有區(qū)別的,有些人對(duì)代碼能力強(qiáng)一點(diǎn),對(duì)代碼有追求,會(huì)做得很好。但是有些人能力就是差一些,很難寫出這么好的代碼。
簡(jiǎn)單地說,希望通過某些流程規(guī)范去完全避免代碼腐爛,那是不可能的。注意,我這里說的是「完全避免」是不可能的。無(wú)論你做得多好,你的系統(tǒng)可能兩三年后就需要做一次重構(gòu),這太正常了。但我們可以通過一些流程規(guī)范,去減緩這種代碼腐爛的發(fā)生。
弄清楚我們的目標(biāo)是完全消滅代碼腐爛,還是減緩代碼腐爛,這非常重要。只有制定了正確的目標(biāo),我們才不會(huì)做出錯(cuò)誤的決策,我們制定具體行動(dòng)的時(shí)候才會(huì)更有信心。
如何減緩代碼腐爛?
減緩代碼腐爛,其實(shí)有好多種辦法。但最常見、收益最高、最好落地的兩個(gè)措施,我認(rèn)為是:技術(shù)方案評(píng)審、CodeReview。
編寫技術(shù)方案,簡(jiǎn)單地說就是在你開發(fā)之前先想好技術(shù)方案。整個(gè)需求是怎么樣的,你想如何去實(shí)現(xiàn)這個(gè)需求?表結(jié)構(gòu)你要怎么調(diào)整?數(shù)據(jù)流從前到后的流動(dòng)是怎樣的?你要做哪一些改動(dòng)?而技術(shù)方案評(píng)審,則是拉上熟悉這塊業(yè)務(wù)的同學(xué),讓他們一起看看你的技術(shù)方案。看看這種實(shí)現(xiàn)方案是否有問題,是否有更好的實(shí)現(xiàn)方式?
通過技術(shù)方案評(píng)審,我們基本上可以避免出現(xiàn)大的需求問題,并且能確保需求改動(dòng)能符合原有的系統(tǒng)設(shè)計(jì)。即使不得已選擇了另外一個(gè)方式,出現(xiàn)了設(shè)計(jì)分叉,那大家也都知道這個(gè)事情的背景,更有利于后續(xù)解決問題。
CodeReview 則是對(duì)于技術(shù)方案的最終核對(duì)。很多時(shí)候技術(shù)方案寫的是 A,但是代碼寫著寫著就變成了 B。CodeReview 的出現(xiàn)就可以避免這個(gè)問題。當(dāng)然 CodeReview 還有很多其他好處,例如:提高代碼質(zhì)量等等。
總結(jié)
代碼腐爛是不可避免的,幾乎所有系統(tǒng)都在發(fā)生不同程度的代碼腐爛,大多數(shù)系統(tǒng)在兩三年后就要做一次重構(gòu)。我們能做的只是減緩代碼腐爛的速度,讓系統(tǒng)能夠撐得更久。而減緩代碼腐爛的方法,技術(shù)方案評(píng)審和 CodeReview 是最基本的、最好用的兩個(gè)方法。
在周志明最新的書籍《鳳凰架構(gòu):構(gòu)建可靠的大型分布式系統(tǒng)》里,他也說到:
架構(gòu)腐化與生物的衰老過程很像,原因都來(lái)自于隨時(shí)間發(fā)生的微妙變化,如果你曾經(jīng)參與過多個(gè)項(xiàng)目或產(chǎn)品的研發(fā),應(yīng)該能對(duì)以下場(chǎng)景有所共鳴:在項(xiàng)目開始的時(shí)候,團(tuán)隊(duì)會(huì)花很多時(shí)間去決策該選擇什么技術(shù)體系、哪種架構(gòu)、怎樣的平臺(tái)框架,甚至具體到開發(fā)、測(cè)試和持續(xù)集成工具。此時(shí)就像小孩子在選擇自己鐘愛的玩具,筆者相信無(wú)論決策的結(jié)果如何,團(tuán)隊(duì)都會(huì)欣然選擇他們所想選擇的,并且堅(jiān)信他們的選擇是正確的。
老人的退出、新人的加入使得團(tuán)隊(duì)總是需要理解舊代碼同時(shí)完成新功能的成員,技術(shù)專家偶爾來(lái)評(píng)審一下或救一救火,充其量只能算臨時(shí)抱佛腳;另一方面是代碼會(huì)逐漸失控,時(shí)間長(zhǎng)了一定會(huì)有某些并不適合放進(jìn)最初設(shè)計(jì)中的需求出現(xiàn),工期緊、任務(wù)重、業(yè)務(wù)復(fù)雜、代碼不熟悉等都會(huì)成為欠下一筆技術(shù)債的妥協(xié)理由,原則底線每一次被細(xì)微地突破,都可能被破窗效應(yīng)撕裂放大成觸目驚心的血痕,最終累積到每個(gè)新人到來(lái)就馬上能嗅出老朽腐臭味道的程度。
架構(gòu)腐化與生物體衰老一樣,是不可避免的。老人退出、信任加入、工期緊、任務(wù)重等等原因,都是不斷欠下的技術(shù)債,我們無(wú)法避免。而對(duì)于代碼腐爛,演進(jìn)式設(shè)計(jì)或許是一個(gè)可解決的方案。簡(jiǎn)單地說:演進(jìn)式設(shè)計(jì)是不追求完美,而是追求滿足一定「保質(zhì)期」內(nèi)的合適,讓合適的架構(gòu)在合理的生命周期中發(fā)揮價(jià)值。
演進(jìn)式設(shè)計(jì)是ThoughtWorks提出的架構(gòu)方法,無(wú)論是代際的演進(jìn)還是漸進(jìn)的演進(jìn),都帶有不少爭(zhēng)議,它不僅是建造的學(xué)問,也是破壞的學(xué)問。Neal Ford在Building EvolutionaryArchitectures:Support Constant Change一書中比較詳細(xì)地闡述了演進(jìn)式架構(gòu)的思想,獲得不少關(guān)注,卻不見得其中所有觀點(diǎn)都能得到廣泛認(rèn)可。如果你是管理者,大概很難接受正是那些正常工作的系統(tǒng)帶來(lái)了研發(fā)效率的下降的觀點(diǎn);如果你是程序員,估計(jì)不一定能接受代碼復(fù)用性越高、可用性越低這樣與之前認(rèn)知相悖的結(jié)論。
當(dāng)我們思考清楚代碼腐爛這件事情之后,或許我們就能更客觀、更平和地接受系統(tǒng)里那些爛代碼。因?yàn)槲覀冎来a腐爛是一個(gè)自然法則,是不可避免的一件事情。我們能做的是盡量減緩腐爛的速度,讓系統(tǒng)在合理的生命周期里發(fā)揮它的價(jià)值。
本文轉(zhuǎn)載自微信公眾號(hào)「陳樹義」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請(qǐng)聯(lián)系陳樹義公眾號(hào)。