楠木軒

細節中有上帝,論精簡代碼

由 亓官天亦 發佈於 經典

在我開始擔任軟件工程師的那一年(2007),Bob 叔叔出版了他的第一本書《代碼整潔之道》的首版。那時,我在一家制造業公司工作。由於那是一家制造公司,所以工作中會接觸很多精益實踐和方法論,於是我決定深入學習瞭解一下相關知識,並獲得了六西格瑪綠帶認證。

大約在我獲得認證的那年,我也讀到了這本書,但那時候它並沒有給我帶來任何啓迪。等到我第四遍讀這本書時,我正在為一些接受我培訓的開發人員準備一組關於整潔代碼的培訓課。就在那時,精益與整潔代碼兩種方法論的一點一滴開始在我的腦中交織融合在一起,我開始領悟了。

首先定義“精益”。從最純粹的意義上講,它是一種旨在組織人類活動,以在消除浪費的同時提供更多價值的方法。

人們採用了許多不同的方式來定義精益方法論,只不過他們選擇的名稱可能不太一樣。所有這些規範都多少會關注精益原則。

為了組織紀律,你首先必須看到要組織和遵循紀律的事物。而且由於我們談論的是代碼,所以當你看到它時,實際上是在閲讀它。稍後我們繼續這個話題。

現在我們來定義“整潔”。回想一下你的童年,媽媽曾經(或仍然如此)説:“你必須打掃完房間才能出去(是的,當年我們真的是出去玩,而如今你是要上網娛樂)和朋友一起玩”。

當你開始打掃房間時,你會意識到要提高效率,第一步是先把所有亂糟糟的東西分門別類(Sort),把電子遊戲放在這一邊,雜誌歸攏到另一處,玩具收納在那裏,等等。然後為每組分好類的東西分配一個位置(Set in order)。現在你就可以更輕鬆地做清理工作了(Shine)。最後你意識到,為了讓房間中的各種東西保持(Sustain)整潔,更簡單的做法是先制定一套日常管理規則(Standardize),這樣你就用不着打掃房間了,可以快點出去和小夥伴們玩耍。

這就是眾所周知的 5 步方法論,它與我們的整潔(精益)代碼模型完全一致。

5 步方法論是:

一種方法,可以讓工作場所整潔有序,井井有條,以幫助減少浪費並提高生產率。

通過標識和存儲所使用的物品,管理區域和物品並保持秩序來組織管理工作場所,以提高效率和有效性。

將它與整潔代碼方法論結合起來是這樣的:

説實話,每個人都可以成為一名程序員。如今有這麼多現成的工具、友好的框架和編程語言,任何人都可以觀看免費視頻並學着編寫一段計算機可以理解的代碼。但真正困難的部分在於:將軟件工程付諸實踐並編寫出人類也可以理解的代碼。

繼續説實話:如果你寫的不是“整潔代碼”(至少不是受人尊敬的代碼),你就不能稱自己為軟件工程師。你能想象一位醫生的辦公室是亂糟糟無法駐足的場景嗎?書躺在地上,桌子上有垃圾,衣服不整潔。你願意和他一起做一次心臟手術嗎?

現在,我們來談一談為什麼整潔代碼如此重要的原因所在:

代碼更具可維護性。

建立可持續發展的業務

它使你看起來更專業。

易於閲讀和理解。

提高生產率。

避免重新設計的惡性循環。

“上帝在細節中”,建築師:路德維希·密斯·凡德羅

如前所述,精益是一種方法論,是一組旨在組織人類活動以在消除浪費的同時提供更多價值的規範。但是,你無法整理和約束看不見的東西,而要真正能"看到"代碼,代碼就必須是可讀的。你無法改進看不見(無法閲讀)的內容。所以我們先來討論整潔(精益)代碼原則的第一個支柱。

可讀性

下面可讀性的完美定義:

清晰。“如果想快速執行,如果想快速完成,如果想讓代碼易於編寫,請讓代碼易於閲讀”——Robert C.Martin

簡單。不要過度設計。

表達的密度。使用最少的資源和交互以獲得最多結果的藝術。

有意義的名稱:

可以揭示意圖的名稱(為什麼存在,其用途以及使用方式)。

使用動詞表示函數名稱,使用名詞表示類和屬性。

變量應表達自身的創建目的。(避免使用 var x,而應使用 var customersIndex)

命名約定:

一定要選擇易於理解的標識符名稱。

一定要先考慮可讀性再考慮簡潔。

一定要使用語義上有意義的名稱,而不要使用特定於編程語言的關鍵字來寫類型名稱。例如,GetLength 就比 GetInt 更好。

X 請不要將縮寫用作標識符名稱的一部分。比如應該使用 GetWindow 而不是 GetWin。

X 請不要使用與廣泛使用的編程語言的關鍵字衝突的標識符。

X 請不要使用任何不被廣泛接受的首字母縮寫詞,就算它們被廣泛接納,也只在必要時才使用它們。

小方法:

一個方法應該是一個只做一件事情的可測試單元。

保持在 10 到 15 行代碼之內。

如果你的方法更大,那麼它可能正在做很多不該它來負責的事情。

“儘早返回”。

接下來,我們繼續討論整潔(精益)代碼原則的第二大支柱。

組織

由於我們在談論的是代碼,因此我們將專注於開發人員的工作,而開發人員會經常使用類。架構師的工作位於更高的層次上,不涉及代碼,而是處理項目或服務(也稱為域,微服務等)等等。因此我們將專注談類。

源文件就像報紙的標題,其名稱應該簡單明瞭,光看名稱就知道是什麼模塊。源文件的頂部應該提供關於高級概念和算法的信息,往下走逐漸展開細節,最後則是底層函數和細節。

3C 原則:

耦合:軟件模塊之間的關聯性。

內聚:模塊內部元素結合在一起的緊密程度。

組合:類應該根據其組合而非繼承來實現多態。例如,一輛車不是一個發動機,而是集成了一個發動機,所以發動機之類的組件通過外部 API 組合起來形成高級抽象。

最後,我們來談整潔(精益)代碼原則的第三大支柱。

紀律

能力 = 紀律 + 技能

擁有良好的態度勝過擁有多年經驗。

良好的態度是有感染力的。它會激勵整個團隊。

“你的態度,而不是你的才能,將決定你的高度。”——Zig Ziglar

紀律是一套標準、規則、試探法、原則和實踐等。下面我來定義一些保持你的代碼整潔的最佳方法:

童子軍規則。離開營地時先打掃乾淨。每次編寫代碼時,我們應該稍微清理一下舊代碼,是否是別人編寫的都沒關係。整理一下就可以做出一點貢獻。只是不要瘋狂清洗一大堆東西,否則你可能會破壞某些內容。

一定要非常簡潔。記住,不要過度設計;不要用牛刀殺雞。

YAGNI(你並不需要它)。不要因為將來可能添加更多功能就寫一個工廠設計模式。等到需要的時候再創建工廠,不要提前行事。

最小意外原則。為每件事物找到一個地方,然後將其放置在其他開發人員更容易找到的地方。儘量不要放在會讓別人感到意外的去處。

“如果沒有測試,那就默認它壞了”。編寫大量測試,尤其是單元測試,否則你會後悔的。

類和函數應該儘量小一些,並遵守單一責任原則(SRP)。函數不應超過 4 行,而類不應超過 100 行代碼。是的你沒看錯。它們也應該只做一件事。

函數應該沒有副作用。副作用(例如修改輸入參數)是有害的。確保你的代碼中沒有副作用。儘可能在函數合約中明確這一點(例如,傳遞原生類型或沒有 setter 的對象)。

避免重複。抽象出常見的事物並將它們放在一個位置,從而避免重複的代碼。

如何避免重複

以後再做等於永遠不會做。你有長長的待辦事項列表,但你內心深知你永遠不會完成它們。一個好辦法是,每次加入新的待辦事項時都寫一條自己正在處理的事項。

4 人代碼審查規則。為了確保你完全遵循所有標準和最佳實踐等,你應該總是要求 4 個人來審查代碼:身邊找兩位開發人員,你的技術主管以及最重要的是你自己。你審查自己代碼的時候應該和審查別人代碼時一樣嚴謹。

代碼分析工具。Resharper、IDE 企業版、SonarQube、SpotBugs 之類的工具可以幫助你遵守最常見和關鍵的代碼準則。

總結

不要學其他那些只看什麼線上免費課程,並從某些公共倉庫複製粘貼的程序員。要有專業工程師的樣子,讓自己編寫最好的代碼,寫出可讀、有條理且遵循所有規範(內部和外部規範)的代碼。