掘金的小夥伴們,你們好,我是二哥呀!java
在某乎上看到一個接近萬讚的高贊回答,一開始看的時候我嘴角是上揚的,還會笑出豬聲,隨後情緒就急轉直下,莫名心酸!題目是這樣的:程序員
先來看一下匿名做者的回答,沒看過的同窗記得以淚洗面哈。編程
我曾經接手過一份代碼,遇到過一個有 30 多個 if-else 嵌套 if-else 的模塊。數組
內心罵罵咧咧,「誰他喵寫的這玩意!」而後翻了一遍代碼的 history。markdown
大體狀況是這樣的:第一個程序員寫下這段代碼時,只有 2 個 if-else;後來需求逐漸增長,先是 1 個、2 個,而後量變引發質變,因而邏輯分支快速擴張。oop
到這時候已經沒有人願意去重構 switch 或者設計模式了,畢竟複雜度擺在那裏,萬一崩了還得背鍋。學習
大概三四個程序員接手這段代碼後,就編程我如今這種局面了。測試
第一個程序員絕對沒有料到那麼簡單的邏輯在以後會變得這麼複雜,甚至在增長第一個第二個 if-else 時,也只是很隨意的加上。優化
因此我以爲,這鍋絕對是甲方的,讓他孃的隨便改需求。這麼一想內心就好受多了,編程嘛,最重要的是看得開!
因而我又追加了兩條 if-else,而後測試、提交,下班。
看完了做者的回答,二哥強忍着無名的悲傷來講兩句。
十多年的編程生涯裏,的確有過無數次的衝動,想要把原有的代碼重構,想要調優,最後大多數都無疾而終,尤爲是隨着年齡的增加,反而愈來愈膽小怕事,有些真的是不敢亂動,只能忍痛讓原有的代碼更爛一些。
畢竟背鍋是大事,嘿嘿。
有時候,不能把代碼當作是藝術品,要可以適度忍受不完美,程序能跑起來,bug 數量可控,有啥問題能夠解決也是很重要的。
若是重構了,出了問題,本身背鍋是註定的,可能還會連累了測試小姐姐。
記得在外企的第二年,因爲組裏面有個新人的代碼寫得實在是太爛,我就忍不住前先後後優化了一遍,畢竟做爲 Team Leader,要對新人負責,要爲團隊負責,結果你們猜怎麼樣?
我被領導臭罵了一頓!
緣由很簡單,我特麼引入了一個 Bug,Code Review 的時候尚未檢查出來,測試也沒有測試到,結果到了正式環境,剛巧碰到領導在日方出差,領導要給領導的領導展現成果,結果程序出了 bug,而後領導被狠狠地臭罵了一頓。
領導被批了,那天然一通越洋電話打過來,把我直接罵哭!
當時還年輕,那叫一個委屈啊。但能怎麼辦,本身的鍋不背讓誰背?
後來回洛陽後,團隊規模變小,本身重構的慾望又涌上心頭,畢竟此次沒人能管得了我,看到誰寫的代碼爛,就直接一頓操做猛如虎,重構到本身心滿意足爲止。
即使是引入了新的 Bug 也不要緊,畢竟老闆也不懂,好忽悠,嘿嘿。
老闆雖然不懂代碼,但懂得寫代碼哪能沒有 Bug——通過個人不懈努力,成功給老闆灌輸了這個思想,要想不出 Bug,就增長測試團隊的人手,領導可不肯意多發一份工資。
成功洗腦老闆後,我真的有一段時間是飄到了極點,狠起來連本身的代碼都重構,一遍又一遍,手頭最常常看的兩本書,一本《代碼的整潔之道》,一本《重構·改善既有代碼的設計》。
從簡單的變量命名、方法命名,到縮減方法的行數,能拆分就拆分,儘可能保證每一個方法的行數不超過一個小拇指那麼長。爲了適配設計模式,我當時還買了一本《設計模式之禪》,真的是殫精竭慮。
如今想一想那段日子真瘋狂,有時候爲了修本身重構後帶來的新 Bug,真的是熬了很多夜。
但有一說一,那段日子的進步也是肉眼可見的。
不過,話又說回來,對穩定性要求比較高的項目,若是能力沒到那份上,仍是儘可能少重構,搞很差版本更新的日誌裏就會寫下一條:XXX 程序員被祭天了!
最好是等到領導忍不住下了死命令,限爾等多少天以內,務必把這座屎山給搬走!到了那時候,再大展拳腳也不遲。
若是真的是安耐不住,一肚子的重構、調優想法沒法獲得施展,我給你們推薦一個好辦法,就是本身搞一個練手項目,能夠是本身開發的,也能夠是 GitHub 上成熟的項目,好比說我一直推薦的 vhr、mall、miaosha 等等,把源碼 fork 下而後拉下來,在本地跑一跑,嘗試去讀一讀源碼,以爲哪裏須要重構了,就動手實踐一遍,即使是出錯了,也誰都影響不到,對吧?
有些同窗若是以爲本身比較厲害的話,能夠去拿那些頂級的第三方類庫作實驗,重構完必定要記得測試,而且在提交 PR 的時候附帶上本身的測試報告,若是項目的做者認爲你重構的有水平,沒準你一躍就成爲了項目的維護者,簡歷上也是加分項。
但對於公司的那堆屎山,動刀子的時候儘可能猥瑣點,省得把本身埋了。
再說回知乎上關於 if-else 和 switch 這個題目。朋友 @yes 在回答裏提到過 Dubbo 源碼中的 ChannelEventRunnable 類的 run()
方法,我用 Sourcegraph 插件看了一下 GitHub 上 Dubbo 的源碼,還真的是挺有學習價值的。
public void run() {
if (state == ChannelState.RECEIVED) {
try {
handler.received(channel, message);
} catch (Exception e) { }
} else {
switch (state) {
case CONNECTED:
try {
handler.connected(channel);
} catch (Exception e) {}
break;
case DISCONNECTED:
try {
handler.disconnected(channel);
} catch (Exception e) {}
break;
case SENT:
try {
handler.sent(channel, message);
} catch (Exception e) { }
break;
case CAUGHT:
try {
handler.caught(channel, exception);
} catch (Exception e) { }
break;
default:
}
}
}
複製代碼
看到沒,這段代碼裏先用 if 作了判斷,而後纔在 else 中使用 switch 作了分支判斷。爲何不所有使用 switch 呢?
官方還特地給了個說明。
我把其中關鍵的一點摘錄出來,你們看一下就明白了。
現代 CPU 都支持分支預測(branch prediction)和指令流水線(instruction pipeline),這兩個結合能夠極大提升 CPU 效率。對於像簡單的 if 跳轉,CPU 是能夠比較好地作分支預測的。可是對於 switch 跳轉,CPU 則沒有太多的辦法。switch 本質上是根據索引,從地址數組裏取地址再跳轉的。
因此說,不是全部狀況下,把 if-else 重構成 switch 就是最好的選擇,仍是要因地制宜。又學到了新的知識,哈哈。
多說一句哈,若是真的想重構代碼,建議學一學設計模式,持續霸榜 GitHubTrending。設計模式是軟件設計中常見問題的典型解決方案,它們就像能根據需求進行調整的預製藍圖, 可用於解決代碼中反覆出現的設計問題,若是不懂設計模式的話,遇到這些問題就只能抓瞎了。
最後,但願你們在重構 if-else 的時候想想,除了 switch,還有沒有其餘更好的選擇,也許 Dubbo 的源碼就給出了方案。
我是二哥呀,下期見,記得點贊喲~~~~