求求你,別再問我爲何要 if-else 走天下了!

掘金的小夥伴們,你們好,我是二哥呀!java

在某乎上看到一個接近萬讚的高贊回答,一開始看的時候我嘴角是上揚的,還會笑出豬聲,隨後情緒就急轉直下,莫名心酸!題目是這樣的:程序員

先來看一下匿名做者的回答,沒看過的同窗記得以淚洗面哈。編程

www.zhihu.com/question/30…設計模式

我曾經接手過一份代碼,遇到過一個有 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 的源碼就給出了方案。

我是二哥呀,下期見,記得點贊喲~~~~

相關文章
相關標籤/搜索