90%的程式設計師都犯過的程式碼錯誤
最近參加了多次的程式碼review會,在review的過程中,發現有些問題幾乎每次都出現。挑了幾個比較典型的問題講解下。這幾個問題都是初級問題,解決方法都很容易。只要掌握了方法,有意識避免,能讓短時間內迅速提高程式碼質量。真所謂投入小,見效快。
變數命名不清晰,一詞多義
為變數命名時最重要的考慮事項是,該名字要完全、準確地描述出該變數所代表的事務 。容易閱讀,不會與其他事務混淆。
例如:
if(staff_id == 0) { printf("系統歸檔,不是員工歸檔"); }
上面這段程式碼,staff_id是員工號的意思,用staff_id為0表示是系統歸檔。一詞多義,本來應該把系統和人分開,但是混用到了一個變數。如果呼叫方出現個bug忘記把初始化的變數賦值,還會走到意外的邏輯。
解決方法是變數名稱首先要符合變數的實際意義,沒有歧義;對於一個變數名,不用特定值表示特殊邏輯。
有些程式碼會把變數取不到的值賦予其他的意義,感覺是省事了,實際後患無窮。例如使用者名稱不可能為空,就用空值表示這個使用者資料已經被刪除了。而且判定資料是否刪除的程式碼看著也讓人莫名其妙。
總之,變數命名要保證沒有「潛規則」,防止給自己挖坑。
使用魔數
命名不清晰更嚴重的是,沒有命名,直接用魔數。如果連註釋都沒有,就只能靠猜。
使用魔數有兩個不好的地方:
1、不方便修改。
使用常量替換魔數是一種將程式「引數化」的方法,需要修改改動一處就可以了,而不必程式碼中到處修改。
例如在程式碼中預設繫結的埠是80,如果不用一個常量代替,哪天軟體升級預設埠變成443了。要整個程式碼搜尋80這個數字,既耗時,又容易改錯。
2、程式碼不方便閱讀。
只有一個數字,很難了解到具體的意思。
for(int i = 0; i < 13; ++i) { ... }
上面這段程式碼,只看13,誰能猜出來是什麼意思呢,為什麼用13這個數值?可能只有寫程式碼的人和上帝知道,如果天長日久,寫程式碼的人忘記了,就只有上帝知道了。
也有同學會問,有的數字只用到一個地方,也起個常量的名字會不會太麻煩了?
答案是:不麻煩。給魔數起個好名字是應該的,這是對的事,不要因為麻煩就不做。有時為了起個準確的名字,甚至要查下詞典。
有一個常用的判定方式:
一、如果引用魔數的地方不超過3個,直接用數字影響也不大。如果超過了3個,都是表示同一個數值意義,還是乖乖地用有意義的變數名代替。
二、如果魔數本身就是表示一個純粹的數字定義,例如是幾米、幾千克這種,作為引數傳遞。在函式的定義明確表示了形引數所代表的意義。大家看用到的地方和函式定義,就知道數字是表示多少個單位的意思,可以用魔數。但是如果用數字表示種類,例如
const int ieBrowser=1; const int chromeBrowser=2;
表示瀏覽器的種類,如果直接只是看到1或2,是不明白什麼意思的。即使在函式宣告的地方已經說過是瀏覽器種類了,也不要用魔數。
魔數解決的辦法很簡單:用列舉、常量等方式,代替魔數 。
if else 或switch等邏輯判斷語句太長
例如下面的虛擬碼程式碼,條件分支很多,用很長的if else語句或者switch語句才能表達完整的邏輯,要思考下是否能用「表驅動」方式來優化。
const int CN=1; const int US=2; const int UK=3; string language; if(country==CN) { language="中文"; } else if(country==US) { language="english"; } else if(country==UK) { language="english"; } else { language=""; }
條件分支太多太長有幾點不好:
1、程式碼太長,不易閱讀。
如果超過了一個螢幕能表示的長度,要翻頁才能看完程式碼,會大大降低看程式碼的效率。因為程式碼的資訊密度太低了。
2、不易擴充套件,修改程式碼。
就像上面的例子,如果又增加了新的條件判斷,那麼要增加新的if else語句,由於修改了邏輯,要重新測試,也要防止改錯。
可以用「表驅動」的方式替代太長的邏輯分支。
把每個條件要用到的資料放到一個「表」裡。用條件分支的判斷條件來索引到表中的資料。
上面的程式碼可以修改為
const int CN=1; const int US=2; const int UK=3; string languageTable[]={"","中文","English","English"}; //先判斷country變數是否在定義的CN、US、UK範圍內,如果在繼續 language = languageTable[country];
經過修改,程式碼變得很短,一眼就能看出程式碼所表示的邏輯。而且以後更新的只有資料,邏輯部分不用修改。
使用「表驅動」後,邏輯和資料分離。使得新增資料修改簡單,而且一目瞭然。
總結
上面只是簡單的說明了幾種常見的程式碼書寫錯誤。稍加註意,就能夠在短時間內迅速提升程式碼質量。具體的方法可以參考一些程式碼規範,或者重構的書籍,例如「表驅動」會有更詳盡的介紹。
最本質的還是要從意識上有足夠的認識。程式碼是寫給人看的 ,寫程式碼時要有同理心,想到以後讓閱讀程式碼的人儘量能夠不費力讀懂。換位思考,如果你就是review人,或後面接手這個程式碼的人,你會喜歡這段程式碼嗎?