真坑!整潔代碼,再見??!
那是一個深夜。
我的同事們剛剛提交了過去整整一周所寫的代碼。我們正在開發(fā)一個基于 Canvas 的圖形編輯器,他們負(fù)責(zé)實現(xiàn)各種“形狀”(比如:矩形、橢圓形)的縮放功能,縮放行為由拖拽“形狀”邊緣上的操作柄來實現(xiàn)。
代碼運行正常。
但是代碼有些重復(fù)。每個“形狀”(如:矩形、橢圓形)各自擁有若干操作柄,從不同方向拖拽操作柄都會對“形狀”的位置和尺寸產(chǎn)生相應(yīng)的影響。如果用戶按住“Shift”鍵,我們還需要保持住“形狀”的寬高比不變。這里涉及到一些數(shù)學(xué)計算。
代碼看起來是這樣的:
let?Rectangle?=?{
??resizeTopLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeTopRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeBottomLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeBottomRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
};
let?Oval?=?{
??resizeLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeTop(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeBottom(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
};
let?Header?=?{
??resizeLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},??
}
let?TextBlock?=?{
??resizeTopLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeTopRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeBottomLeft(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
??resizeBottomRight(position,?size,?preserveAspect,?dx,?dy)?{
????//?10?repetitive?lines?of?math
??},
};
這種重復(fù)的數(shù)學(xué)計算邏輯,對我來說,真的難受。
這不是“整潔”的代碼。
多數(shù)的重復(fù)都在于“方向”上的相似,舉個例子,Oval.resizeLeft()和?Header.resizeLeft()?就很類似。這是因為,它們都是在處理拖拽左側(cè)操作柄的問題。
另一個原因在于“形狀”所擁有的方法上的相似,例如,Oval.resizeLeft()?和?Oval?上的其它方法是類似的。這是因為,它們都是在處理“橢圓形”上的問題。更進一步,Rectangle,?Header?以及?TextBlock?都有相似的地方,因為文本框都是“矩形”。
我有個辦法。
我們可以通過對代碼邏輯進行分組,來實現(xiàn)“去除全部重復(fù)”的目的:
let?Directions?=?{
??top(...)?{
????//?5?unique?lines?of?math
??},
??left(...)?{
????//?5?unique?lines?of?math
??},
??bottom(...)?{
????//?5?unique?lines?of?math
??},
??right(...)?{
????//?5?unique?lines?of?math
??},
};
let?Shapes?=?{
??Oval(...)?{
????//?5?unique?lines?of?math
??},
??Rectangle(...)?{
????//?5?unique?lines?of?math
??},
}
然后,像這樣來組合它們:
let?{top,?bottom,?left,?right}?=?Directions;
function?createHandle(directions)?{
??//?20?lines?of?code
}
let?fourCorners?=?[
??createHandle([top,?left]),
??createHandle([top,?right]),
??createHandle([bottom,?left]),
??createHandle([bottom,?right]),
];
let?fourSides?=?[
??createHandle([top]),
??createHandle([left]),
??createHandle([right]),
??createHandle([bottom]),
];
let?twoSides?=?[
??createHandle([left]),
??createHandle([right]),
];
function?createBox(shape,?handles)?{
??//?20?lines?of?code
}
let?Rectangle?=?createBox(Shapes.Rectangle,?fourCorners);
let?Oval?=?createBox(Shapes.Oval,?fourSides);
let?Header?=?createBox(Shapes.Rectangle,?twoSides);
let?TextBox?=?createBox(Shapes.Rectangle,?fourCorners);
代碼量減少到 1 / 2,并且,重復(fù)代碼不復(fù)存在!這真是“整潔”啊。如果我們希望改變具體某個“方向”上的或“形狀”上的行為,只需要修改一處,而非多處。
已經(jīng)很晚了(我很疲憊了),我提交我重構(gòu)后的代碼,然后就躺下了,并對自己“幫助同事整潔代碼”而感到心滿意足。
第二天上午
… 事情并非我想的那樣。
我的上級單獨找到了我,委婉地要求我撤銷昨天的那些修改。我感到很不可思議,舊代碼那么差勁,而我的是多么“整潔”?。?/p>
我那時只好謹(jǐn)遵照守;但是后來,歷經(jīng)數(shù)年,我才明白他們的要求是對的。
那是一個職業(yè)階段
對“整潔代碼”的沉迷、好于“消除重復(fù)代碼”,是我們大多數(shù)開發(fā)者都會經(jīng)歷的階段。當(dāng)我們對自己的代碼沒有信心,自我價值感和專業(yè)榮譽感往往會使我們與一些可測量的東西靠攏,一組嚴(yán)格的 lint 規(guī)則、一套命名規(guī)范、一種文件結(jié)構(gòu)、無重復(fù)性指標(biāo),等等。
你不可能讓“重復(fù)代碼”自動被消除,但是確實可以借助“實踐經(jīng)驗”使它更可行。你往往可以看到,每次修改后的代碼量是變得更多或更少。結(jié)果就是,消除重復(fù)代碼看起來提高了代碼的某些客觀的可測量指標(biāo)。然而,糟糕的是,這擾亂了人們的自我認(rèn)知,他們會對自己說:“我是那種會寫出整潔代碼的人”,而這其實跟其它的自我欺騙行為沒什么兩樣。
一旦學(xué)會了如何“抽象”,我們似乎就會更進一步,每次看到重復(fù)的代碼,我們甚至能夠從“無”中發(fā)現(xiàn)可“抽象”的東西。編碼數(shù)年以后,我們已經(jīng)厲害得隨處都能看到重復(fù)的代碼,我們同時獲得了一項新的超能力:抽象。進而,如果有人告訴我們“抽象是好的”,我們便對此更加篤信。于是我們開始去批判那些不崇尚”整潔代碼”的人。
我現(xiàn)在明白,我的那次“重構(gòu)行為”確實是一場災(zāi)難(譯者:夸張了吧~),從兩個方面來說:
首先,我沒有告訴代碼的作者。我在沒有他們參入的情況下,重寫并提交了代碼。即便,那確是一次對代碼的“改善”(我現(xiàn)在不以為然了),它也十分可怕。一個健康的工程團隊需要不斷地“建立彼此的信任”。不經(jīng)討論而擅自重寫同事的代碼,是對高效協(xié)作能力的徹底否定。 其次,一切都需要權(quán)衡。為了減少重復(fù),我的代碼難于應(yīng)付需求變更,而這并不值得。例如,我們后邊需要為不同“形狀”上的各個操作柄添加特殊的行為邏輯。為了應(yīng)付這些,我的“抽象”無疑使修改困難了數(shù)倍,反觀那原本“骯臟的”代碼,它則能夠輕松處理。
我的意思是你應(yīng)該寫“臟”的代碼嗎?不,我建議你深入思考一下“整潔”與“骯臟”分別意指何物。你有對于批判、正確、美和優(yōu)雅的直覺嗎?你如何能確定地說你的這次工程成果達(dá)到了那些質(zhì)量指標(biāo)?它們?nèi)绾未_切地影響到代碼的產(chǎn)生與維護?
我當(dāng)時確然對于這些問題沒有進行過深入思考;我當(dāng)時考慮的是代碼“看起來”如何,而不是代碼該如何隨著不斷流動的團隊而演進。
寫代碼是一場旅行?;叵胍幌?,你編寫第一行代碼時的情形,到現(xiàn)在你所處的狀態(tài)。我相信,當(dāng)突然發(fā)現(xiàn)“抽取出一個函數(shù)”或“重構(gòu)一個類的定義”是如何使問題由復(fù)雜變得簡單的時候,你必定是開心的。一旦對自己的作品產(chǎn)生了自豪感,你就會熱切地去追求代碼的整潔。對此,你可以保持一段時間。
但是不要止乎此,不要成為一個整潔代碼的狂熱分子。整潔代碼并不是目的,它只是讓我們從所面對系統(tǒng)的異常復(fù)雜性中解脫出來的方法。在你不是很明確一個改動會如何影響到整個代碼庫時,這信念可以作為一種安全防護機制。但是在未知的海洋里,你需要一個指南針。
那就讓整潔代碼指引你吧,然后忘了它。
源自:https://overreacted.io/zh-hans/goodbye-clean-code/
聲明:文章著作權(quán)歸作者所有,如有侵權(quán),請聯(lián)系小編刪除。
關(guān)注數(shù):10億+?文章數(shù):10億+
粉絲量:10億+?點擊量:10億+
?懸賞博主專區(qū)請掃描這里
喜愛數(shù):?1億+?發(fā)帖數(shù):?1億+
回帖數(shù):?1億+?結(jié)貼率:?99.9%
—————END—————
喜歡本文的朋友,歡迎關(guān)注公眾號?程序員哆啦A夢,收看更多精彩內(nèi)容
點個[在看],是對小達(dá)最大的支持!
如果覺得這篇文章還不錯,來個【分享、點贊、在看】三連吧,讓更多的人也看到~



