現狀
首先,我們看看在大多數Java IDE中Java程式碼的風格習慣。
下面是一個例子:
public class Example { public static void main(String[] args) { int answer = 2 + 4 * 6; for (int i = 0; i < 5; i++) { doSomething(); } System.out.println("The answer is " + answer); } private static void doSomething() { // something } }
請注意,這是Java程式設計者中和其它類似C語言的語言中最常見的一種風格
在括號內部兩邊沒有留空格。只有當括號前面有關鍵字for或while等時,空格才會出現在它們之間,但在方法名和其之後的括號間沒有空格。然而,在左大括號前總會有空格(這個左大括號一般會出現在一行的最後)。數學操作符總有空格包圍。而分號前不會有空格。
如果你經常閱讀程式碼,也許認為這是很自然的安排,但如果你不是一個程式設計師,可能會認為這些規則太隨意,有很多不統一、特例、有待討論的地方。
請給你的程式碼留下多一些空間
在我當前的開發專案中,公司裡有兩個主要的開發團隊,一個是Load Test Products(LTP)團隊,另一個是Functional Test Products(FTP)團隊。兩個團隊裡遵守了一些編碼風格習慣,其中對空格的使用都是特別慷慨,就像下面這個程式碼片段的例子:
public class Example { public static void main( String[] args ) { int answer = 2 + 4 * 6; for( int i = 0; i < 5; i++ ) { doSomething(); } System.out.println( "The answer is " + answer ); } private static void doSomething() { // something } }
這種風格看起來程式碼的密度更小,而且更有統一性(例如,在左括號前都沒有空格,在所有的括號、花括號、中括號的左右內邊都有空格)!我並不是說這樣比之前的風格更好或更差….只是這樣更容易區別單詞。代價就是一個螢幕裡只能顯示更少的程式碼。
雖然每種編碼風格都有各自的優勢和缺點,但讓我吃驚的是,FTP開發團隊最終決定轉向使用之前提到的最常見的那種編碼風格。他們認為這種轉變是值得 的,他們甚至還進行過討論,所以,我相信他們認為這種轉變是重要的。他們判斷的依據並不是這種比那種好…我認為這主要著眼於什麼人習慣這種風格,因為我們 的大部分產品都是開源的,這是重要原因,更容易讓社群內的程式設計師捐贈程式碼。
在我的團隊裡,LTP團隊,我們仍然堅持我們的風格,不打算做任何改變。至少對於我來說,這是一種基於技術考慮的決定:如果另一種編碼風格沒有體現出任何的優勢(我們的這個專案對開源捐贈的需求很少),為什麼要轉向另一種風格?
規則需要統一
我一直在給開源專案捐贈程式碼,比如Ceylon程式語言,讓我非常吃驚的是,他們完全沒有遵守任何的編碼風格。你可以用任何你喜歡的風格來寫程式碼。
也許某些被一些公司裡大量的編碼規範驚嚇住的程式設計師會喜歡這樣,但我相信,如果沒一套編碼規範,你的專案的程式碼很可能在格式上出現混亂。每個程式碼捐贈者都會在提交的程式碼裡帶入他特有的程式碼風格,這不奇怪,結果就是所有的程式碼各式各樣,你從下面幾行程式碼裡就能看到多種不同的風格:
while (exists cell = iter) { if (exists elem = cell.element, elem==element) { last = cell; } iter = cell.rest; } } if (exists cell=last){ cell.element=replacement; return true; }
assert (0<=index<length);
我主要想提出的問題是:編碼風格究竟是不是一種重要的開發制度?它對程式設計師開發軟體的效率有多大影響?
我相信這個問題牽連到另外一個相似的問題:程式碼的格式影響程式碼的可讀性嗎?
程式碼格式影響程式碼的可讀性
我認為,這個問題非常容易回答!當然會影響。用眼睛逐行掃描一下下面兩段程式碼(從Ceylon專案中選出的),你會很容易感覺到哪個更易讀。 – CeylonCreate)?
function validModuleNameChar(Character c)=>c.letter||c.digit||c in ['_','.' ]; if (!trimmedName.empty, validModuleNameFirstChar(trimmedName.first else 'X'), trimmedName.every(validModuleNameChar), !(trimmedName.split('.'.equals,true,false)).containsAny(ceylonKeywords.chain {""})) { return trimmedName; }
function validModuleNameChar( Character c ) => c.letter || c.digit || c in ['_', '.' ]; if ( ! trimmedName.empty, validModuleNameFirstChar ( trimmedName.first else 'X' ), trimmedName.every ( validModuleNameChar ), ! ( trimmedName.split ( '.'.equals, true, false ) ).containsAny ( ceylonKeywords.chain { "" } ) ) { return trimmedName; }它們的區別也許很小,但如果你整天花大量的時間讀大量的程式碼,這區別就大了。
從普通文字寫作中學到的經驗
說起程式碼的可讀性,我們也許應該看看人們更普通的閱讀文字的能力,這種能力已經發展了幾千年,所以,應該會總結出來更好的方案!?
在“普通”的英文中,你可以看出約定俗成的對於空格的用法,而你卻看不到作家們討論他們是否應該在括號周邊使用空格的問題!
那麼,如果程式碼像“普通”英文那樣編寫,會是什麼樣子?
回到我們上面簡單的例子:
function validModuleNameChar( Character c ) => c.letter || c.digit || c in ['_', '.' ]; if ( ! trimmedName.empty, validModuleNameFirstChar ( trimmedName.first else 'X' ), trimmedName.every ( validModuleNameChar ), ! ( trimmedName.split ( '.'.equals, true, false ) ).containsAny ( ceylonKeywords.chain { "" } ) ) { return trimmedName; }
程式碼裡大部分的東西都本普通英文句子一樣。你使用括號將某些字詞“分組”。你在單詞和符號之間使用空格——這裡我們發現了一個跟普通編碼習慣不一樣的地方:我們在呼叫方法時,方法名和之後的括號間沒有空格,物件點操作符後面不留空白。
我可以理解為什麼在這些地方沒有空格,因為程式碼裡這些括弧或點號表示了一種“擁有”關係,或關聯關係。但真的有必要擠壓這一點空間來表示這種關係嗎?當我們看上面的這個例子程式碼時不是感覺很清晰嗎?
另外一個在普通英文裡不存在的東西是巢狀表達…所以,我們有普通英文寫作裡不會出現的情況。但這不是大問題,只需要在記住一個通用規則:在符號兩邊加空格。
你是不是感覺上面的程式碼有些奇怪?我不得不承認,看起來稍微有些不舒服,當我相信這只是我還不習慣。
雖然還不習慣,但我確定這些程式碼讀起來更容易理解。
我可以明確的說,如果所有的程式碼都遵守這樣的習慣,那我們程式設計師閱讀程式碼的過程將會輕鬆的多。
結束語
我希望沒有程式設計師會認為遵守一個預先定義的編碼規範會讓程式設計變得困難!
首先,所有的IDE都能配置成自動對程式碼進行格式規範調整,你寫程式碼時可以寫的很亂,但最後別忘了使用IDE裡的快捷鍵整理一下程式碼,然後再提交程式碼。同樣,我估計沒有哪個作家會認為我們的寫文字的格式太嚴,限制了他的創作。
幸運的是,我發現當前所有的編碼風格、規範裡對空格的使用習慣都沒有大問題。但多使用一些空格肯定會讓程式碼更清晰易讀。
你覺得呢?
[英文原文:Give your code some space! ]
本文轉載自:外刊IT評論