我的if else程式碼純淨無暇,一個字也不能簡化
機器之心報道,參與:劉曉坤、王淑婷、李澤南。
「我曾接手過一個程式碼,裡面是幾十個 if else 模組……」對於程式設計師們來說,遇到這樣的事情應該是苦不堪言的——很多人認為這種寫法非常難看、分支眾多、容易出 bug。最近,網友們在容器管理平臺 Kubernetes 的 GitHub 上發現了這樣一段程式碼,其中的 1700 行 if else 語句卻讓人歎為觀止。
為了防止「頭鐵」群眾真的去重構它,在這段程式碼的開頭,有這樣一段註釋:
不要嘗試簡化此程式碼。
請看著它起飛。
這個控制器是故意以非常詳細的方式編寫的。你會注意到:
1. 每個『if』語句都有一個匹配的『else』(除了客戶端 API 呼叫的簡單錯誤檢查)
2. 在這裡我們要明確地解釋一下
我們把這種程式碼叫做『太空梭風格』。太空梭風格是為了確保每個分支和條件都得到考慮——就像在 NASA 編寫太空梭的航天器應用程式程式碼一樣。
最初,這個控制器的工作被分成了三個控制器來做。該控制器是為簡化 PV 子系統付出巨大努力的結果。在這種努力中,很明顯我們需要確保在程式碼中處理和計算每個條件,即使它導致了無操作程式碼分支。
因此,控制器程式碼可能看起來過於冗長,有太多註釋和「分叉」。但是,這裡記錄了大量的業務知識和內容,以確保未來的維護者能夠正確地推理繫結行為的複雜性。因此,對此檔案的更改應保持太空梭風格。
該檔案的 GitHub 地址:
作為流行的開源系統,Kubernetes 常被用於自動容器化應用程式的部署和管理。其開發者稱,Kubernetes 擁有 15 年承擔 Google 生產工作負載的經驗。對於人工智慧領域的開發者來說,Kubernetes 可以幫助我們部署深度學習模型(參見:如何使用 Kubernetes 輕鬆部署深度學習模型)。
太空梭的風格
聽說它是美國航天局 NASA 的程式碼風格?在 Hackernews 上,眾多網友們在通讀全文程式碼後給出了一致好評。
@Klathmon 表示:
我愛死這個了!這簡直就是軟體開發裡的「爵士樂」。它打破了所有的固有「規則」,但目的明確,比按照「規則」來的結果要好得多。
乍一看,你會覺得這個檔案太大了,裡面充斥著許多分支和巢狀 if 語句,還有很多「無意義的註釋」,僅描述周圍一行或幾行程式碼是做什麼的。註釋裡還有很多 logic,與實際程式碼相比,這些 logic 很快就會過時或者出錯。
但同時,這樣做使得維護和管理程式碼變得簡單多了,因為你不用把 logic 拆分成幾十甚至上百個檔案。它包含了大量對這個檔案需要進行的固有複雜工作,而它的註釋做得又好又多,做任何改變都可以輕易讓註釋一起更新。
@munchbunny 說:
不能更同意了。我日常要處理的程式碼不是這個級別,但也有低級別的特點,同樣也比典型的後端程式碼更接近 metal,被許多的前端和後端程式碼呼叫。如果有「甚至更後端程式碼」的東西,這就是個不錯的例子。如果你忽略了一個細微的差別,一群憤怒的開發人員會在部署程式碼時衝到你辦公桌前,而如果你沒有快速修復它,就會出現一群憤怒的顧客。
對於任務關鍵型程式碼內部迴圈中的程式碼來說,主要的時間成本並不是寫程式碼或者理解程式碼,而是根據所服務場景的細微差別進行優化,檢查更改程式碼帶來的直接影響,然後檢查更改的二階和三階影響。
當你的程式碼非常細化,以至於你做的每個改變都有三階影響時,帶有精心註釋的程式碼會更容易維護。因為假如你拼湊了十個不同的檔案,需要花費精力弄清正確的路徑,就更有可能忽略其中的細微差別。
關於註釋
很多網友對於帶大量註釋的程式碼表示很有用、不反感,並且那些不帶註釋的程式碼會帶來很大的麻煩。
@EB66 說:
我完全同意。對於那些不可避免很複雜的程式碼,我也喜歡這種風格。
我非常喜歡簡潔且語句/命名是表達性的程式碼,但有時候註釋是必要的,以便清楚地闡明邏輯或使用案例。表達性程式碼能直接傳達的含義有限。精心設計的註釋可以大大地減少其他開發人員在不熟悉的程式碼基礎上所耗費的時間。
關鍵是要更新註釋。沒有比不準確的註釋更噁心的事了。檢查程式碼時一定要檢查修改過的程式碼行的註釋。
@ascar 說:
解釋使用案例或目的的過時註釋還是比沒有註釋強。它能給你提供背景資訊,比如程式碼的演變及其目的。
只讀註釋可能比讀沒有註釋的程式碼更糟糕,所以一些開發人員反感過時的註釋,因此就有了一般化(過於簡略)的註釋。
註釋是關於程式碼的附加資訊,沒有事實來源,所以,要同時閱讀程式碼和註釋。
@nickharr 說:
我有 25 年以上用多種語言編寫、檢視、註釋和檢查程式碼的經驗,所以我會說這的確是一個好東西——不管程式設計的「風格」(或者廣義上來說的語言)如何。
好的程式碼註釋可以對生產力產生巨大的影響——無論是對個人、團隊還是企業來說都是如此。它有助於儲存知識(當前和之前的團隊/個人之間容易丟失的資訊)。
我個人花了太多時間對那些沒有註釋的程式碼進行逆向工程。有時候,經驗豐富的程式設計師或開發人員會走捷徑:壓縮程式和函式,這些程式和函式是基於他們明確瞭解的語言和/或領域,但沒有對它們進行註解……
在基本層面上,註釋應該告知、教育、概述和幫助他人理解我們寫程式碼時創造的有時很複雜的路徑和函式。
有些人認為好的程式碼不需要註釋,某種程度上這是對的,但這一點並不適用於每個程式碼庫。有些程式碼很複雜、笨拙,就像義大利麵,有時甚至難以理解。
我一直努力教經驗較少的開發人員以帶點幽默(可能的話)的方式作出高效的好註釋——讓我們能夠快速理解程式碼,欣賞前人所做的努力,並笑對複雜的挑戰。
我個人並不真正關心程式碼和註釋的比率。有時,程式碼註釋可能比程式碼本身更有價值。而有時,它們只是幫助你完成工作;只要快速、高效、沒毛病,就是不錯的程式碼。
檔案大小
@Klathmon 說:
我從事前端網頁應用開發,其中最複雜的問題在於如何實現程式碼庫的快速迭代,大部分情況下都不是實際的業務問題。但儘管「deep functionality and small interfaces」聽起來很不錯,大多數情況下,匯出的僅有少量函式的大型檔案是不容易維護的。將所有程式碼放到同一個檔案中,需要你在做出任何修改之前確保透徹地理解它們。
@taneq 說:
他們是有目的地這樣做的,為了確保開發人員在修改之前能理解整個檔案,因為其功能非常關鍵,很容易被混淆。此外,將一個邏輯嚴密的檔案分割成小型檔案(而不是改寫成更小的邏輯模組)只會導致不必要的檔案管理問題。
新手的膜拜
@jml7c5 說:
作為一個初學程式設計師,我非常震驚這竟然不是程式設計的標準慣例。一般的原始檔應該提供語境、主題背景、解釋概念的參考資料/部落格/書籍指南、關於程式碼如何匹配程式整體的資訊,以及(最重要的)檔案中體現的思考過程(即為什麼選擇這種做法而不是其它,面臨的挑戰,權衡等等)。
我還是想不通,每一位程式設計師都需要從零開始學習使用一個程式碼庫。除非肯花費數小時來做測試,想改善一個 non-trivial 的程式是不可能的。致開源開發者:如果你想要讓人們對專案做出貢獻,這些型別的註釋是很基本的,更不要說它們能幫助節省非常多的時間。
@qlk1123 說:
「作為一個初學程式設計師,我非常震驚這竟然不是程式設計的標準慣例。」我同意這一點,如果這能成為社群標準,當然會有很多人受益。但是,你不認為一個好的社群文化可以讓人們為此保持良好的習慣嗎?
我的日常工作是 Linux 核心開發人員。我發現原始碼僅僅是「What」部分,註釋中應該宣告「How/Why」部分。並且如果這些還不能使我搞明白原始碼,我會直接電郵作者問更深層次的「Why」部分。大多數情況下資訊都是足夠的。
模仿需謹慎
Kubernetes 之外,最近另一個因為程式碼而被熱議的程式可能就是在 Steam 上火起來的獨立國產遊戲《太吾繪卷》了。據好奇的程式設計師介紹,其早期版本中內含數千個 if 語句。由於遊戲主創是中文系出身,隨後又投身建築行業,半路出家寫遊戲程式碼——最後居然玩起來沒有什麼大問題,程式碼的「糟糕」樣式成為了一個梗,為遊戲的流行起到了助推作用。
這些著名的案例雖然可以執行,但沒有強大的邏輯(運氣)是玩不轉的。科班出身的程式設計師們一般就不要模仿了。
參考內容: news.ycombinator.com/item?id=187…