程式設計師,請優先提高代碼的可讀性

導語:

現在,當有人提及“優化”一詞時,他們通常是指“優化執行時間”,除非他們明確表明要優化GPU的內存消耗,網絡流量等等。

一 瞭解優化對象

當我開始編程時,所擁有的處理器執行速度很慢,內存空間也非常有限 —— 有時僅以KB衡量。因此,必須合理考慮內存的使用和優化。

在大學裡,我們知道了優化的兩個極端情況:

  • 你可以犧牲空間來換取執行速度的提升,
  • 或者通過執行重複操作來換取內存消耗的優化。


如今,沒有人會太在意內存的使用(除了demoseners,嵌入式系統工程師,部分手遊開發者),不僅是對於RAM空間,硬盤空間也是。 試想一下僅安裝看門狗就耗費硬盤近25Gb 空間。 此外,我在谷歌瀏覽器選項卡中寫這篇文章時,佔用了130Mb的RAM空間。

實際上需要優化的對象有很多:

  • 隨著智能手機市場的增長,電量損耗的優化備受關注;
  • 優化可讀性可以讓代碼易於閱讀和調試,從而縮短開發週期,降低開發成本;
  • 還有很多優化類型,此處不再贅述……


優化可讀性——讓代碼更容易閱讀、跟蹤和理解。

你應該明白,你在優化時難以兼顧各個方面。 例如,當致力於性能優化時,你很可能讓應用程序內存消耗增加,同時代碼可讀性也變差。

二 為何優化可讀性

開發者大量工作時間並不是在編寫代碼,而是閱讀代碼,調試代碼,查閱他人提交的開發文檔,學習新的庫等。

當閱讀代碼時,開發者實際上是充當代碼解釋器的角色(雖比不上計算機)—— 在他們的頭腦中執行代碼,並試圖記住當前執行狀態。 這就是程序員在閱讀代碼過程中被打攪脾氣暴躁的原因。

時間== 金錢

你應該意識到一件很最重要的事,是你和你的同事浪費了大量時間。 即使是一個努力工作的開發者,在做下面的事時仍然浪費了大量時間:

  • 實現一些現在不需要,以後也可能永遠用不到的功能。
  • 做一些沒有實際價值的改進。 例如,花費一週時間優化一個函數的執行時間,而該函數在1小時內僅被調用10ms的時間。
  • 編寫的代碼難以調試,卻還要試圖從中找出錯誤。
  • 編寫的代碼他人難以理解。 注意,“他人”也可能是短短一週後的你。


上述情況是假設遇到問題的開發者經驗豐富並且熟知高效算法和簡潔代碼如何書寫,否則要列出的情況要更多。

三 優化可讀性

唐納德·克努特說過一句名言。 我敢打賭你聽過很多次。

“在編程中,過早優化是萬惡之源。 ” —— D.Knuth,1974

我遇到很多知道這句話的人,但真正理解這句話的卻很少。 最常見的錯誤理解像這樣:

  • —為何這麼簡單的任務,代碼卻如此複雜?
  • —我優化了X和Y,因為在將來……
  • —難道你沒聽說過早的優化是萬惡之源嗎?
  • —當然,但這並不是過早優化,我能肯定這樣做程序執行效率會更高。


我想這是由於對過早優化這個詞沒有明確界定的原因。 這就是這些人一點也不認為他們那麼做屬於過早優化的原因。 那麼,我們該如何界定這個詞呢?

過早優化——在工作系統中分析和運行測試前的任何優化嘗試。

除可讀性之外任何修改都屬於過早優化。 所以,與其說一個人不應該做什麼,不如說應該做什麼。 那麼,這句引言可以這樣理解:

優先提高可讀性。

四 什麼阻礙了開發者閱讀代碼

好吧,我們一致認為,我們應該讓代碼更易於閱讀,這樣可以節約時間和金錢,對吧?但這究竟意味著什麼?

有跡象表明,下面兩個基本方面極大地降低了開發者閱讀代碼的速度:

  1. 代碼晦澀難懂,
  2. 代碼難以跟蹤。


五 代碼艱澀難懂

遺憾的是,人們並不能像軟件解釋器那樣,可以不必理會將兩個數相加並調用一個函數這部分代碼的功能(機械式的編譯)。

為了查找代碼異常的原因,程序員必須理解源程序中編寫的代碼實現了何種功能,編寫的初衷是為了實現何種功能。

六 什麼讓代碼晦澀難懂?

下面情況是對於經驗豐富的開發者而言,這些開發者熟悉代碼開發使用的語言和程序中使用的算法(即他們有足夠的知識來理解這段代碼)。

  1. 代碼不良。 單個字母的奇怪變量和1000行代碼的冗長函數。
  2. 代碼的格式不正確或不一致。
  3. 代碼中包含冗餘代碼。
  4. 代碼中包含未備註的低層次優化。
  5. 代碼過於高明。


我將跳過前兩條,因為無論如何你不應該閱讀不良代碼。 如果你所在的公司有人編寫了不良代碼,你應該糾正它們或者將其廢棄。 當然,你必須為你的整個代碼庫執行嚴格的編程規範。

3. 代碼中包含冗餘代碼

亦或所謂的行數優化。 嵌套函數調用和條件運算符的長行代碼難以剖析。 當然,你可能會說這種觀點是片面的。 但這些人覺得源程序代碼越短越好,不必考慮可讀性。

4. 未備註地層次優化

最初,代碼的可讀性很好,工作也很穩定,但有些人決定在某些方面對其進行優化。 經過認真剖析,這可能是一個很好的優化,但此時的代碼看上去像是數組、位運算和幻數的結合體。 沒有人知道代碼在做什麼,甚至代碼應該做什麼,因為完成優化的人沒有提交任何說明。

也許你聽說過優秀的代碼不需要說明文檔。 但是經過優化的代碼(特別是優化效果很理想的情況)必須要有說明文檔。

在你的代碼庫中,可能大部分的優化只是像這樣的未備註行:

程序員,請優先提高代碼的可讀性


5. 代碼過於高明

作為軟件開發者,我們掌握越來越多的學術技巧並將其運用到實際代碼開發中。 畢竟,我們是計算機科學家,而不只是碼農!

有些語言甚至鼓勵開發者使用前沿技術,使代碼更具表現力和學術性。 當你用代碼建立了一個非常健壯的系統,特別當你用數學方法證明了一個高深定理,而99.997%受過教育的人對這種方法都不理解,你就會有這種成就感。

即使代碼被良好地封裝成模塊/類/函數並且這些模塊包含完全可讀的命令式代碼,但其他人想要讀懂這段代碼,他們必須掌握整個代碼的框架以及所有使用的相關技術和模式。

再一次強調,記住“其他人”可能就是一週後的你。

極可能這是我在工作中僅認識兩個使用Scala語言人的原因。就我個人而言,非常喜歡Scala語言。 對我來說,它就是一個學術操場,我可以在那裡建造玻璃城堡。 一旦你越瞭解它,它的越多特性也就能為你所用,你也就越明白它本質上只是一門編程語言(請不要在這裡引用我!)。

雖不如Perl語言,但即使最漂亮的代碼庫也需要修改和更新。 現在,你需要尋找一個能夠理解這些優美代碼的人……

簡潔高明的代碼難以閱讀似乎是有爭議的。

“軟件調試要比編寫代碼困難一倍,如果你發揮了最大才智編寫代碼,那麼你的智商便不足以調試這個代碼。 ” —— Brian Kernighan

七 代碼難以跟蹤

閱讀代碼時,通常需要頻繁的從一個函數或類跳轉到另一個函數或類。 掌握你使用的集成開發環境(IDE),可以節約很多閱讀時間。 通過使用集成開發環境(例如Visual Studio)的“跳轉至聲明”,“查找使用”,“導航至”,“檢查”等特性,你可以將整個代碼看作是一幅連通圖。

在Notepad中編寫代碼是不錯的選擇,但是如果你想有效的閱讀代碼,必須掌握一個集成開發環境。

那麼,究竟什麼是連通圖呢?

連通圖是在拓撲空間中連接的圖,即圖中任意兩點之間都有一條通路。(來源)


程序員,請優先提高代碼的可讀性


換句話來說,在“連通”代碼中,你可以方便的從一個方法中跟蹤到另一個方法中,並在你頭腦中建立這段代碼的功能框架。

如果代碼中某一部分鏈接被破壞(在這種情況下,集成開發環境不能幫助你實現函數間的跳轉),通常你必須花一些時間自己查找鏈接。代碼中被破壞的鏈部分越多,越難以跟蹤,代碼也就越難以閱讀。

那麼,為什麼代碼圖會被斷開?原因是多方面的,下面將列出一些常見情況:

  1. 使用字符串引用方法和屬性


一些框架就喜歡這樣做,他們將”回調”作為字符串傳遞並在需要時使用反射。 此時你需要使用CMD+F查找。

最可惡的是動態語言中的動態字符串…… 對這個問題,向JavaScript或AS3致敬!

2. 代碼被分割成互不相連的部分

例如,你的代碼一半使用C#編寫,另一半是在可視化節點編輯器生成。 在這兩者之間跳轉非常不易。

依賴注入框架和其他XML配置工具也是。雖然沒有明確說明,但編寫XML配置文件也屬於編程。 這就是所謂的的聲明式編程(更不用說那些構建基於XML命令式語言的瘋狂的人)。

3. 巨大的圖節點

20個鏈接跳轉到這個包含1000行代碼的函數?。。哎喲。 你不需要包含這種節點的圖。

4. 一切都過於抽象

通過跳轉至聲明,你可到達一個接口或者一個抽象類,必須弄清楚有哪些實現。 依賴注入,抽象工廠和其他所有反對依賴的方法使得這一切變得更糟。 代碼圖中節點間的聯繫過於抽象。

這樣說來,我討厭依賴注入(DI)和擴展標識語言(XML)。但DI是一個很棒的工具,它可以讓你避免書寫麵條式代碼並讓程序的架構更加模塊化,更具可測試性。但像其他好的事物一樣,過度依賴必然產生負面效果。

我曾在審查一個應用程序時感到完全氣餒,因為我意識到自己弄不明白程序從何處開始。。。例如它的入口點在哪。 這一切都是在程序開始時從XML配置工具自動生成。但我確實討厭XML配置工具。

所以,到這裡你應該已經學會:

  • 掌握你的集成開發環境,
  • 儘可能保持代碼圖連通,
  • 首先編寫簡單代碼,
  • 編寫不必要的代碼,就是在浪費金錢。

強迫自己編寫簡單的代碼,避免在早期階段優化確實有一定難度,這需要花費時間。

擴展閱讀

提高代碼閱讀能力的7種方法

十個提高編碼技能的訣竅,你掌握了幾個?

程序員去阿里面試,沒想到過程如此壯烈


分享到:


相關文章: