close

每個人在寫文章時都有自己的風格,這會依據自己的文學造詣和思考邏輯而有不同。想想看,以前在聯考或是在作文課時,明明就是大家的題目都一樣,可是卻有人寫的好有人寫的差。而且是不可能會有相同的文章出現。但是照樣造句的話呢?那就會有可能出現一樣的造句,因為大家是在同一個規範之下寫簡短的句子(可能是抄參考書的)。

把相同的情形拿到寫程式這件事來看。在一個團隊中每個人的程度都不同,就算不會因為程度的關係,但是寫出來的程式碼卻會因為自己的習慣而大不相同。如果把相同的工作交待給兩個人同時去執行,姑且不論寫好寫壞,也不論完成的時間點與效果。這兩個人所設計出來的資料結構,類別的命名,再者介面與註解等等,都不會一樣。

這樣看來,相同的工作都會有不同的程式碼出現,那不相同的就更不可能會有機會一樣了(除非是用copy的)。
這麼說,一個專案的程式碼就像一本散文集。
其實散文集也沒有什麼不好,就當做看一篇一篇的短篇故事吧。

但是!
散文裡有參雜火星文或是古文就不好了吧!

有人或許會問
為什麼要擔心風格問題?
如果程式能夠Run的話,誰在乎裡面是什麼?
讓程式碼看起來漂亮不是很花時間嗎?
這些規則是不是太武斷?

事實證明,會有這種想法的人不適合當Programmer。(因為一定會被公幹到死)
寫的好的程式碼比較易於閱讀與了解,而且幾乎是錯誤比較少,並且比漫不經心又未修飾過的程式碼來的小又快。
想想看,在一個看似功能正常的程式,展開來的程式碼卻是一坨屎。
雜亂無章,演算法邏輯有問題,多做了重複的事情等等。
如果你看到了這樣的程式碼,心中一定會有一團無名火從"懶趴"那裏衝上來,甚至會嚴重的影響到你工作的情緒與進度。

許多Game Programmer都會埋怨美術或是企劃資料沒有用好。
批評美術為什麼要在很遠的地方放一個幾千面幾萬面的物件,批評企劃設計不好或是資料沒填正確。但是卻忽略了自己程式碼的品質與風格帶給團隊的殺傷力。
這遠遠比美術與企劃資料有錯來的難查,因為美術和企劃的資料都是把問題清楚的攤開來讓大家檢驗,惟獨程式碼是沒辦法被大家檢驗的,也只有Programer可以來審視,但監守自盜總是不好的吧,如果沒有把好的習慣養成,實在是很難說服別人自己的程式碼是沒有問題的。

命名
命名通常可區分為變數的命名與函式的命名,想像一下就跟你寫句子要有主詞與動詞一樣,主詞就是變數,動詞就是函式。以下是命名時的習慣與比較好的建議。
1.  全域變數在字首加上g_,成員變數在字首加上m_,靜態成員變數在字首加上ms_,區域變數也可加上l_或是不加,變數的型態是指標時加上p,例如g_pScene, ms_pSingleton, m_pNode, pAI。class和struct在字首加上C或S,或是由團隊共同指定字首(通常會利用專案或是公司的縮寫)。
變數的型態是int時加上i, unsigned int 加上ui, float 加上f, double 加上 d, char加上c, char * 加上pc。加上這些最主要是能夠快速辨識變數的型別,以免還要回到宣告的地方才能知道型別定義。如果是自己宣告的struct或是class通常不會加上型別識別,而是直接宣告描述性意思與strcut或class的名稱,例如有一個class叫做Node, 宣告一個m_SceneNode。
2. 全域變數(global)和成員變數(member)使用描述性名稱,區域變數(local)使用簡短的名稱。
3. const的變數使用大寫,例如:const float PI = 3.1415962f;。define的巨集或是常數也用大寫。
4. 維持一致性,給相關的事物取相關的名字,這些名字要能顯示之間的關係並指出彼此的差異。例如:
class CUserQueue 
{
public:
    int m_iNoOfItemInQ, m_iFrontofThequeue, m_iQueueCapacity;
};
[queue]這個字分別以Q, Quene, queue三種形式出現。然而變數只能經由UserQueue來存取,所以成員根本不需要提及[Queue]。而且一次出現三種形式反而更讓人混淆其意義。以下版本會比較好一點。
class CUserQueue
{
public:
    int m_iItems, m_iFront, m_iCapacity;
};
5. 函式使用主動名稱。函式名稱應該以主動動詞為基礎,後面可以加上名詞。例如float GetTime();。但是會傳回bool的函式名稱,就應該以可以從函式名字上看出傳回值所代表的意義。例如:bool CheckOctal(int iNumber);,並沒有指明哪個值代表true哪個值代表false。而bool IsOctal(int iNumber);,就清楚多了,因為引數是八進位就回傳true,否則就回傳false。
6. 名稱要精確。名稱不指示標籤,還會傳達資訊給讀者。一個誤導的名字會引發奇怪的臭蟲。例如:
bool InTable(Object * pObj)
{
    int j = this.getIndex(pObj);
    return (j == m_iTableCount);
}
如果發現物件的話,getIndex會回傳一個0到m_iTableCount-1的索引值,如果沒有則回傳m_iTableCount。因此InTable回傳的值和這個名稱所代表的意思正好相反。這樣會讓其他使用的人產生困擾,甚至要花一些時間來除錯,最後才發現產品外觀與內容不符。

arrow
arrow
    全站熱搜

    SnakeEater 發表在 痞客邦 留言(4) 人氣()