干掉你程序中的僵尸代碼
隨著萬圣節(jié)越來越流行,我感覺有必要跟大家討論一下一個在軟件開發(fā)中非常普遍的問題:僵尸代碼。幾乎所有我接觸過的代碼庫里都四散著很多小段的,甚至大片大片的被注釋掉的代碼。這就是僵尸代碼。
//目前禁用這項功能。Jimmy在寫這段代碼時肯定是喝醉了。 //你可能以為這里發(fā)生了恐怖的代碼兇手案…不,不,我只是把它們注釋掉了…
為什么稱它們?yōu)榻┦a?你知道,僵尸不并不是真的死的。就像恐怕電影里告訴我們的,盡管僵尸看起來是死人,但它們?nèi)杂心芰λ奶幊鰶]襲擊我們。相同的道理,僵尸代碼也是處于不生不死之間…它們在伺機搞砸我們的工作。注釋掉的代碼還活著,它們就存在我們的代碼庫中。程序員在維護和重構(gòu)代碼時會和它們遭遇,通常是滾動屏幕時和它們擦肩而過,或是在進行關(guān)鍵詞搜索時和它們撞個滿懷。但這些代碼也確實是死的,因為它們在軟件產(chǎn)品中并不執(zhí)行。因此,這些僵尸就應(yīng)該被燒掉,立刻。
僵尸代碼不死之軀
我認為,有兩個原因?qū)е铝私┦a的肆虐:懶和害怕風(fēng)險。懶程序員對代碼有收藏癖。他們?nèi)狈Υ_信的勇氣和清楚的認識去刪除無用的代碼,于是他們就把它們隱藏在注釋里,期望有朝一日它們能復(fù)活來再次禍害人。代碼需要經(jīng)常的、有計劃的刪除,因為優(yōu)秀的程序員都知道:代碼就是債務(wù)。越少越好。當然,被注釋掉的代碼仍然是代碼。
爛程序員也許會爭辯說,他們注釋掉這些代碼是為了“萬一”以后有人會需要它們。事實上,這好心反而是害了大家。這實際上說的是害怕風(fēng)險,缺乏對版本控制系統(tǒng)作用的信任。有版本控制系統(tǒng)在,刪除的代碼永遠不會真正的死掉。它們被埋到棺材里但卻活著。所以,注釋代碼的方法沒有多大實際效用。
對于程序來說,注釋掉的代碼跟刪掉的代碼一樣,不起任何作用。讓代碼半死不活,以僵尸的形態(tài)存在,造成技術(shù)債務(wù),最終會讓你的團隊受害。要果斷,刪掉它們。
僵尸代碼降低信噪比
當寫程序時,我們一定要努力使代碼里有效信息的比率越高越好。這有助于人們理解程序,更快的閱讀代碼,防止我們因為誤解而寫出有問題的代碼。僵尸代碼直接的對抗代碼的可理解性。它拖延我們閱讀和維護代碼的速度,因為它使我們在屏幕上看到更少的有效代碼。它們就是視覺噪音,干擾人們的正常閱讀。處于某些原因,有些程序員會接受這種妥協(xié)的做法,可是在現(xiàn)實中,誰會接受這種亂糟糟的畫面。想象一下,如果紐約時報看起來像這個樣子:
如何閱讀這斷斷續(xù)續(xù)的文字?噪音的增加就是對可理解性的損害。對這些被注釋掉的部分,盡管它們毫不相干,甚至?xí)`導(dǎo),但你卻無法對它們視而不見。有人會說,這不是最終發(fā)布的產(chǎn)品,這些代碼存在于開發(fā)過程中,拿它們跟發(fā)布的產(chǎn)品做對比,這就像拿蘋果比桔子。但是請記住,被寫出的每行代碼平均都要被閱讀10次。沒錯,你的代碼的閱讀人數(shù)沒有紐約時報多,但是,你擁有的是一個最重要的忠實的閱讀群體。就是我們。 Knuth對此關(guān)切進行了精辟的總結(jié):
“編程是一種一個人告訴另一個人他想讓計算機做什么的藝術(shù)。” Donald Knuth |
而僵尸代碼讓你講話講不清楚。一個程序員需要去閱讀被注釋掉的代碼嗎?
僵尸代碼造成歧義妨礙調(diào)試
注釋掉的代碼會帶來歧義,人們會懷疑這些代碼是否該注釋掉。試想一下,你是一個來維護程序的程序員,突然看到了一片注釋掉的代碼,而程序就在這附近出了問題。這個程序員的任務(wù)會變得更棘手。他需要閱讀和理解這些注釋掉的代碼,了解注釋它們帶來的影響。是因為測試而注釋這些代碼但忘了恢復(fù)嗎?也許注釋這些代碼的人可以提供幫助,但他是誰?調(diào)查行動開始。多余的歧義會消耗你的時間,增加你的思考負擔(dān)——本來可以是一次輕松的調(diào)試過程。
僵尸代碼影響關(guān)鍵詞搜索
在大型程序庫中,grep/find命令將會是你鎖定某些特定的代碼片段的雷達。然而,如果程序庫里到處散布著僵尸代碼,很有可能你捕捉到的目標都是被注釋掉的。這是干擾。浪費時間。
僵尸代碼影響代碼重構(gòu)
反省(重構(gòu))能修復(fù)我們的靈魂。我們應(yīng)該以小孩scout的做事原則為榮,永遠把代碼收拾得比你想象的要整潔。然而,當一個類或方法包含有大量的僵尸代碼時,事情就不好處理了。如果重構(gòu)這段程序,我是否還要參考注釋掉的代碼?它們近期將會被重新使用嗎?它會影響我的新版的實現(xiàn)嗎?這些問題對于維護的程序員來說本該不需要回答的。
此外,集成重構(gòu)工具根本不會考慮這些注釋掉的代碼。因此,當方法,變量,類被重命名或修飾符改變時,這些注釋掉的代碼就不會同步做修改。當你再想把注釋掉的代碼復(fù)活時,它們很可能根本不能編譯。
有例外嗎?
沒有。很明確。有人會說“我現(xiàn)在注釋它們是因為我過會兒就要恢復(fù)它們。”OK,假設(shè)你是個家庭婦男,你走到起居室,看到:
想想你內(nèi)心的對話。這是個漂亮的房子,但這個東西又丑且怪異。我想開燈,但怎么會有膠帶?如果我撕掉膠帶去開燈,會發(fā)生什么事情?你很可能最終決定找貼膠帶的人。“哦,我想打開吊扇,但它啟動時來回搖擺,掉了下來,我想修理它….”當然,這是應(yīng)該的。而在你沒修好它之前,膠帶一直貼在開關(guān)上。我們當然不該讓這些只修了一半的東西存在屋內(nèi)。同樣,我們也不接受這樣的代碼。
說的更明白些,任何被注釋掉的代碼都是僵尸代碼,都應(yīng)該被刪掉。不管有多少。不管是在發(fā)布的產(chǎn)品中還是在開發(fā)環(huán)境中。僵尸代碼有時會在生死之間搖擺。如果代碼被注釋掉,這很有可能有東西沒有完成。經(jīng)常是配置需要來回切換或邏輯分支左右搖擺。注釋代碼可能會做實驗性的來回切換,刪除這些代碼,建一個記事貼,記錄下需要做的事情。在記事貼中記下哪次提交版本時刪除了這些代碼?;蛘撸陆ㄒ粋€版本分支專門做這事,合并時刪除它們。這樣,維護工作就不會受到干擾。
心里的核對表
如果你打算要注釋一段代碼,請先問問自己:
- 如果有可能的話,什么時候會取消注釋?
- 是否能刪掉它,如果日后有需要,從版本控制系統(tǒng)里找回?
- 對這些未完成的、有可能會回滾的代碼,能否用版本分支來處理?
- 這種需要來回切換注釋的功能可否通過配置實現(xiàn)?
- 重構(gòu)時也需要重構(gòu)這些注釋掉的代碼嗎?
讓我們開啟***次年度萬圣節(jié)僵尸代碼大清剿。
本文英文原文鏈接:Kill the Zombies in Your Code