或許你常聽到寫出易懂程式碼的重要性。開發者對於如何撰寫淺顯易懂的程式碼都很有想法,尤其越資深的開發者,意見越多。不過,你真的曾經停下敲鍵盤的手,想過如何真的撰寫易懂的程式碼嗎?
標準答案是
你或許會同意,不論使用的程式語言為何,下列項目有助於程式碼的易讀性:
除此之外還有很多關於程式碼易讀性的標準答案與普遍公認的做法,我對這些沒什麼反對意見。
不過我倒是希望你對可讀性有更深入的瞭解。
詞彙和讀者經驗
我可以在看到一份程式碼的兩秒鐘裡,告訴你它寫得好不好以及容易理解與否。同時,我可以拿我寫得最好、有高度易讀性的程式碼範例,給一位新手程式設計者看,讓他們看不出,與他們看過的其他程式碼之間有何不同。
而對他們而言,與他們看過的其他程式碼相較,他們看不出兩者有何不同。
儘管我的程式碼中變數名稱具備高度描述性,僅有少量參數且名稱簡短的方法,一次只做一件事,程式碼清楚地依照功能加以組織分段。但是這些新手們一點也不覺得這樣做,比起他們未經任何結構思考的程式,有任何易於閱讀的地方。
事實上,我經常聽到有關的抱怨,抱怨我的程式碼方法太多,難以閱讀,變數名稱太長,容易讓人混淆。
這一切基本上都源自於老手與新手閱讀程式碼方式的不同
有經驗的開發者閱讀程式碼時,不會留意程式語言本身的詞彙,而是專注在程式碼表達的概念上,是程式碼的目的,而非如何步驟過程。
新手與經驗較少的開發者完全不一樣。當經驗較少的開發者閱讀程式碼時,會試著去了解程式碼的結構。新手則是把大部份重心放在語言的詞彙,而非語言試著要傳達的東西。
對他們而言,像 NumberOfCoins 這樣的長變數名稱毫無描述性,該變數的人格化表示加上過長的名稱,只會誤導他們,以為該變數除了表示一個整數之外,還包含了別的東西。他們寧願看到像 X 或 Number 這樣的變數名,因為光記住整數代表什麼就夠他們受的了。
有經驗的開發者完全不管整數或字串什麼的。他們希望瞭解的是,變數在方法或系統的邏輯語境下,所代表的意義,而非變數形態或變數如何運作。
例子:學習閱讀
想想看閱讀是如何學會的。
當孩童學習閱讀時,一開始會學習字母的發音。當小孩子第一次閱讀書本時,他們會唸出每個字。他們不會關心文法或文字要傳達的意思,他們只是將焦點放在文字本身的結構。
想像如果這篇部落格是寫給閱讀初學者看,然後受限於像童書一樣的詞彙與句子結構,那時你還會覺得這文章好讀嗎?可能不會。
同樣的情況也發生在有經驗的音樂家身上。他們能輕易閱讀樂譜,相較之下,新手則更偏好符號譜。比起那種描述該按哪個鋼琴鍵或彈哪條吉他弦的音樂說明,有經驗的音樂家覺得樂譜更容易閱讀與理解。
可讀性的限制
就像你只能用初學閱讀書籍的詞彙與結構,來表達思想時受到的限制一樣,你也會以同樣方式,受到程式語言的限制。
這最好用一個例子說明,讓我們看底下的組合語言:
.model small .stack 100h .data msg db 'Hello world!$' .code start: mov ah, 09h ; Display the message lea dx, msg int 21h mov ax, 4C00h ; Terminate the executable int 21h end start
以上的組合語言程式碼會在 DOS 下在螢幕上印出 "Hello World"。x86 組合語言的詞彙與文法受到相當多限制,很難輕易表示複雜又可讀的程式碼。不論你是多麼棒的程式設計者,x86 組語的可讀性仍有其上限。
我們看 C# 的例子。
public class Hello1 { public static void Main() { System.Console.WriteLine("Hello, World!"); } }
關鍵在於 C# 擁有更為豐富的詞彙和更複雜的語法,足以提供用更為簡潔和易讀的方式,表達更複雜的想法。
想知道 Ruby 為何一下子這麼流行?以下是 Ruby 版的 Hello World:
puts "Hello, world"
就這麼簡單。
我並不是 Ruby 的超級愛用者,不過如果你知道 Ruby 語言的豐富詞彙和語法結構,你會發現,你可以用該語言清晰地表達你的想法。
不過我發現這樣的比較並不公平。而且 Hello World 也不是程式語言詞彙或語法的好示範。
我想說的是,你可用的詞彙越豐富,想法就可以表現得越簡潔,於是更有易讀性。不過前提是你已經掌握了這些詞彙與語法。
那麼,結論是什麼?
好了,你或許在想,這聽起挺有趣,雖然我不確定是不是完全同意,但我有點瞭解你的意思,但這又怎麼樣呢?
好問題。
從了解詞彙與經驗如何影響可讀性,我們可以得到不少好處。
首先,我們可以針對觀眾撰寫程式。
我們必須思考誰會讀我們的程式,他們的詞彙與經驗層級為何。在 C# 中,經常受到爭論的是條件運算符的使用。
我們應該把程式寫成:
var nextAction = dogIsHungry ? Actions.Feed : Actions.Walk;
或是:
var nextAction = Actions.None if(dogIsHungry) { nextAction = Actions.Feed } else { nextAction = Actions.Walk; }
一直以來我都站在支持第二種寫法的陣營這邊,不過現在我發現,我常常寫的是第一種。如果你問我哪種比較好,我的答案是看情況。理由是,假如你的觀眾不知道條件運算符,這種寫法可能會讓他們感到迷惑。不過如果你的觀眾熟悉條件運算符,那麼使用 if 語句的冗長版本就顯得浪費空間。
從這項觀察中還可以發現到,擁有豐富詞彙的程式語言,並且良好掌握該詞彙與語法的價值。英語正是一個有著相當龐大詞彙與誇張語法數量的豐富語言。不少人說如果能簡化詞彙跟語法,會讓英語更加簡單易用。
然而,如果真的將英語縮減,將複雜的語法簡化為更為簡單的結構,的確會讓英語更易學習,但英語傳達資訊的功能也將大大減弱。換言之,為了節省掌握該語言的時間,代價是喪失語言的表達力。
語言大統一?
對於程式語言,我們很難採取和上述同樣方式的思維。因為我們通常不希望在單一程式語言和框架上,比照口語和書寫語言,投入那麼多的心力。然而,程式語言的詞彙越豐富,語法越複雜,也就越具有表達性,對那麼掌握其詞彙與語法的人來說,可讀性也就更高。
不過別擔心,我並非在提倡發展出一個大家都應該學的超複雜程式語言。至少還不是現在。
這種事有賴於人類整體知識水準的提升。
目前我們要重視的,是擁有簡單詞彙、易於理解與學習的程式語言,即使這些語言的表達力比不上較複雜的語言。
最後當大部份的人都知道如何寫程式時,我相信屆時會需要一個語言,對電腦和人類而言,同具有英語和世上其他語言的表達性。
你的想法呢?我們應該有更複雜、更難以掌握的程式語言,以便享有更高的表達能力,還是應該用比較簡單的程式語言,寫出比較複雜又冗長的程式碼?