ETH官方钱包

創(chuàng)作內(nèi)容

5 GP

命名的迷人魔力-2

作者:藍貓│2013-10-13 00:34:22│巴幣:10│人氣:338
前言
我們在學校寫作業(yè)習慣上把我們要用的變數(shù)用單一字母來命名,比方說a或b.c.i,這種命名履見不鮮,但是筆者要強調(diào)的是,大型程式,這樣阿貓阿狗的命名是極糟的示範,它本身並未包含任何程式意圖。

但這並不是我們的錯,而是因為我們從小到大從未聽過一個有說服力的說法來說服我們遵循這個好原則。

筆者在上一章提到,維持程式的整齊非常重要,而這其中最重要的一小步,同時也是我們維持整齊的一大步,那就是好的命名。

這關係到我們構築程式碼的品質(zhì),材料的質(zhì)感跟品質(zhì)不好(也就是命名),就算結構再好,都不可能構築一個好的程式碼。

介紹
好的命名確實有難度,而且必需高度認真看待命名這件事,才能得到成效,而這一切的作為將花掉我們不少時間,但是替換命名的代價遠比我們事後的檢修代價來得小,因為良好的命名可以徹底表達程式的意圖跟概念。

你可能會直截了當?shù)姆瘩g這一點,並且義正嚴辭的說:我們可以用註解來代替程式碼表達不清處的部份,但我必需說,如果一個程式碼本身需要靠註解才能完整表達本身的意圖,那它就是不合格的程式碼。

例如筆者前陣子寫的多項式加法就可以拿來當實例,筆者只截取前面幾段供參考,剩下的段落由讀者自行感受:

      i1 = 0;
      i2 = 0;
      i3 = 0;
      while( (i1 < p1) || (i2 < p2) )
        {
           while( (A[1][i1] == B[1][i2]) && ((i1 < p1) || (i2 < p2)) )
            {
               C[0][i3] = A[0][i1] + B[0][i2];
               C[1][i3] = A[1][i1];
               i3++;
               i2++;
               i1++;
            }
           while( (A[1][i1] > B[1][i2]) && ((i1 < p1) || (i2 < p2)) )
            {
               C[0][i3] = B[0][i2];
               C[1][i3] = B[1][i2];
               i3++;
               i2++;
            }
           while( (A[1][i1] < B[1][i2]) && ((i1 < p1) || (i2 < p2)) )
            {
               C[0][i3] = A[0][i1];
               C[1][i3] = A[1][i1];
               i3++;
               i1++;
            }
         }

這段程式碼讓我不清楚它的本身意圖,它的邏輯安排還算有秩序,演算法也很簡易,但是它的程式碼隱晦度讓我們被迫去理解以下4件事:

1. A, B, C 陣列存放的資料內(nèi)容代表的是什麼東西?
2. A, B, C 行標號數(shù)字代表什麼?比如:i1,i2,i3
3. A, B, C 列標號中的 0 跟 1 有什麼意義?
4. p1,p2代表什麼?

我們常常會認為,程式碼本身就是很難理解的,並且毫無道理地相信一件不完全正確的事:程式碼無法正確而完整的解釋它們所應當讓人理解的概念,你可能會說,既然程式碼無法確實解釋我們要的想法,那就想辦法多加一些註解吧。

錯了,我們大多數(shù)的人都看小了程式碼的表達功力,程式碼某種程度上就應該負責大部份的表達工作,事實上註解極少但是擁有良好命名的程式碼遠比註解很多命名很糟的程式碼來的優(yōu)。

如果你發(fā)現(xiàn)你的程式碼需要大量的註解輔助你對程式的理解,那你就要相當程度的去質(zhì)疑你是否有發(fā)揮程式本身應該具有的表達力,請牢記在心:註解無法彌補失職的程式碼,而這一切失職往往出於程式設計師的不用心,與其想著如何寫註解,不如多花幾秒去想,如何讓你手上的程式碼更好理解。

未避免開空頭支票,我必需誠實對讀者兌現(xiàn),就拿上面的例子來說好了,我們看到這段程式碼,直覺會認定不好理解,所以最普通的作法是,我們將我們的意圖用註解闡明,以便我們?nèi)蔗崂斫膺@一段可以回答上述4個大哉問:

      i1 = 0;  /* 代表多相式 A 第i1相 */
      i2 = 0; /* 代表多相式 B 第i2 */
      i3 = 0;  /* 代表多相式 C 第i3 */
      while( (i1 < p1) || (i2 < p2) )  /* p1, p2分別為 A 多項式和 B 多項式的陣列長度 */
        {
           while( (A[1][i1] == B[1][i2]) && ((i1 < p1) || (i2 < p2)) )  
            /* A[1][i1] 代表 A 多相式的第 i1 項的次方數(shù) */
            /* B[1][i2] 代表 B 多相式的第 i2 項的次方數(shù) */
            {
               C[0][i3] = A[0][i1] + B[0][i2];  /* A[0][i1] 代表 A 多相式的第 i1 項的係數(shù),B[0][i2] 代表 B 多相式的第 i2 項的係數(shù),C[0][i3] 代表 B 多相式的第 i3 項的係數(shù) */
               C[1][i3] = A[1][i1];   /* C[1][i3] 代表 C 多相式的第 i3 項的次方數(shù) */
               i3++;
               i2++;
               i1++;
            }
           while( (A[1][i1] > B[1][i2]) && ((i1 < p1) || (i2 < p2)) )
            {
               C[0][i3] = B[0][i2];
               C[1][i3] = B[1][i2];
               i3++;
               i2++;
            }
           while( (A[1][i1] < B[1][i2]) && ((i1 < p1) || (i2 < p2)) )
            {
               C[0][i3] = A[0][i1];
               C[1][i3] = A[1][i1];
               i3++;
               i1++;
            }
         }


各位在這裡應該察覺到註解變得非常凌亂,而且光是理解註解的難度可能就比程式碼還來的複雜,更不用說註解還有空間限制,它並不能包辦你每一個空間的程式碼,但是不適當?shù)拿赡苌言谀阏麄€程式碼的範圍,而這個範圍是註解很難管轄到的。

再來是時間限制,誰知道我程式碼會不會將概念跟內(nèi)容通通變更?到時後註解若是沒同步更新,我們又更難確知程式碼本身的意圖了。

請記住:只有程式碼能忠實的告訴你程式本身的作用,它是唯一即時且本質(zhì)上是準確的資訊。

我們再將上面的範例改一改,這次我們直接改命名,將多項式 A,B,C 依序變更名稱為 firstPoly, secondPoly, resultPoly,我們也依序?qū)?/font> i1,i2,i3 改為caseFirst, caseSecond, caseResult ,甚至我們可以將列標號 0 1 包裝成 coefpow

你們很可能會有一些抱怨,這個命名真的太長了,但是命名的原則是,寧可取用表達力足夠的命名,也不要簡潔卻不明確的命名,而且最好我的命名是可以發(fā)音的,以免與專案成員討論的時後無法順利進行程式內(nèi)容的討論,這是便於我日後維護工作。

我們來Demo一下命名更改以後的成果吧......
首先看前3行
      i1 = 0;  /* 代表多相式 A 第i1相 */
      i2 = 0; /* 代表多相式 B 第i2 */
      i3 = 0;  /* 代表多相式 C 第i3 */

這邊我們發(fā)現(xiàn)一件很妙的事,修改命名以後我的註解自然也被新的命名給詮釋掉了,所以我們用程式碼來取代這些不需要的註解......

      caseFirst = 0;
      caseSecond = 0;
      caseResult = 0;  

接下去我們將直接了當野蠻的幹下去,當然只截取部份的更改,剩下的留給讀者思考......
     coef = 0;
     pow = 1;
      .
      .
      .
     resultPoly[ coef ][ caseResult ] = firstPoly[ coef ][ caseFirst ] + secondPoly[ coef ][ caseSecond ];  
     resultPoly[ pow ][ caseResult ] = firstPoly[ pow ][ caseFirst ];
     caseResult++;
     caseSecond++;
     caseFirst++;

在這裡大家應該很清楚了吧,一個好的命名閱讀起來,程式碼就會像是一段文字陳述式,就像是在看報章雜誌,你甚至能夠光靠直覺就去判定,這個演算法的長相,而這一切都可歸於一個結論:好的函數(shù)名稱和變數(shù)名稱就是註解的載體。

記住喔,我是說光靠直覺喔,當然這一部份筆者未盡到完善的地方便是while敘述後面的條件式,在這裡我應該用一個簡易的名稱把條件式整個包裝起來,只是這部份我留給讀者去思考。

命名的大方向
1.必需能被搜尋
單一字母變數(shù)的缺陷在這裡將會展露無遺,我們可能會搜尋到很多結果,但是結果都不盡然是我們想要的,增加後續(xù)維護的功夫。

2.函數(shù)的命名用動詞或動詞片語
比方說我有一個函數(shù)要把球踢出去,我會這樣命名......
kickBall(......)
{
......
}
即便再怎麼直覺,命名都是用英文的方式去陳述,但老實說英文程度不好的人看起來可能還是有障礙,基本上這樣命名對老外本身就非常容易讀懂,這是為什麼我們會比別人更傾向依靠註解的原因,但我還是必需鼓勵你試著少用。

3.類別與變數(shù)的命名用名詞或名詞片語
記住,類別的命名對向是一個實體或物件,所以你必需應著你的實體或物件的特性去命名,或者應著你的類別職責去命名。

4.全域變數(shù)越特別越好,有的時後會用很長的一串字命名,區(qū)域變數(shù)則視其範圍可以簡潔有力變數(shù)的包含範圍越大,就越容易重複或誤用甚至誤導,所以一旦是全域變數(shù),命名方面必需非常謹慎;至於區(qū)域型的變數(shù),因為使用範圍小,所以原則上以簡單易懂為主,表達概略意圖即可。

按照含括範圍的大小來給定命名,依狀況不同作微調(diào)。

至於特殊情況,像 for 迴圈裡的 i 基本上是慣用語法,主要是用來代表迴圈執(zhí)行次數(shù),除非別有用途,不然這部份的變數(shù)宣告成 i 是可以讓人接受的......

int i;
for( i = 0; i <= 5 i++ )
{
       printf( "\n" );
}

總結
寫程式就像寫作文一樣,程式語言必需表達完整的程式概念,使用註解前,先停下來思考一下,是否可以靠命名來取代註解?再來就是,永遠別滿足於你現(xiàn)在的命名,當你發(fā)現(xiàn)你的命名正在誤導你理解程式的時後,試著狠狠改掉它,給它一個更好的詮釋。
引用網(wǎng)址:http://www.jamesdambrosio.com/TrackBack.php?sn=2205634
All rights reserved. 版權所有,保留一切權利

相關創(chuàng)作

留言共 0 篇留言

我要留言提醒:您尚未登入,請先登入再留言

5喜歡★ertyk122 可決定是否刪除您的留言,請勿發(fā)表違反站規(guī)文字。

前一篇:維持程式碼的整齊-1... 後一篇:高階程式語言理論-抽象化...

追蹤私訊切換新版閱覽

作品資料夾

小說連載 (0)
英雄聯(lián)盟小說(英雄聯(lián)盟系列) (19)
[外傳]昏黃歲月(英雄聯(lián)盟系列) (1)
阿宅與美女代打(英雄聯(lián)盟系列) (0)
[寫實小說]_糾心恥笑園 (0)
[寫實小說]_倒數(shù)末日 (0)
[寫實小說]_憂鬱天堂 (2)
[寫實小說]_網(wǎng)路殺人魔 (0)
[寫實小說]_錢魔 (0)
[神幻小說]_犬族的命運 (61)
[神幻小說]_捨不得你。妄想 (0)
國中生小說 (3)

漫畫連載 (0)
[搞笑四格]_場外舉人 (0)
[少年漫畫]_臺北大地震 (0)
[少年漫畫]_就是愛運動 (0)
[少年漫畫]_餵愛一口香 (0)
[寫實漫畫]_白狼 (0)
[寫實漫畫]_天刑三二三 (0)
[寫實漫畫]_橫血英雄 (0)
[寫實漫畫]_恐龍妹 (0)
[神幻漫畫]_剩水童子 (0)
[神幻漫畫]_永遠的父女 (0)
[神幻漫畫]_勇者我家人 (0)
[其它]_音魂 (1)

劇本創(chuàng)作 (0)
[寫實劇本]_白狼 (1)
[寫實劇本]_天刑三二三 (0)
[神幻劇本]_繪魔 (0)
[神幻劇本]_魔曲 (0)

電腦理論 (6)
程式設計相關理論 (14)
高階程式語言理論 (6)
實作程式 (15)
程序之相關問題 (0)
硬體管理與計算機結構 (3)

創(chuàng)作理論 (3)
文學理論 (3)
文學實作要領 (0)
繪畫理論 (1)

生活日記 (241)
自我提醒 (5)

文創(chuàng)作品 (2)
散文與詩 (25)
故事大綱 (1)
繪圖 (57)
processing文創(chuàng)應用 (0)
勇造創(chuàng)作 (3)

數(shù)學領域相關證明 (0)

英雄聯(lián)盟豪洨文 (3)

辯論大會 (0)

未分類 (22)

Waterfall10絕大部份巴友
魔幻小說《九芒記》第 170 章「最佳臥底」發(fā)佈囉!歡迎瀏覽 ~看更多昨天21:46


face基於日前微軟官方表示 Internet Explorer 不再支援新的網(wǎng)路標準,可能無法使用新的應用程式來呈現(xiàn)網(wǎng)站內(nèi)容,在瀏覽器支援度及網(wǎng)站安全性的雙重考量下,為了讓巴友們有更好的使用體驗,巴哈姆特即將於 2019年9月2日 停止支援 Internet Explorer 瀏覽器的頁面呈現(xiàn)和功能。
屆時建議您使用下述瀏覽器來瀏覽巴哈姆特:
。Google Chrome(推薦)
。Mozilla Firefox
。Microsoft Edge(Windows10以上的作業(yè)系統(tǒng)版本才可使用)

face我們了解您不想看到廣告的心情? 若您願意支持巴哈姆特永續(xù)經(jīng)營,請將 gamer.com.tw 加入廣告阻擋工具的白名單中,謝謝 !【教學】