2012
Dec
25

如何写一个大家都看得懂的程式呢? 最近读了 「The Art of Readable Code 」与「Clean Code A Handbook of Agile Software Craftsmanshi」这本书,将书中提到的,整合我平常写 Code 的习惯,记录下程式的规范。

Easy to Read, 如何让整体的 Code 容易阅读

  • 复杂的 Function, method 请增加注解,但是注意注解不要影响程式的阅读
  • 适当的空白,空行。
  • 不要过度使用文字的缩写,如果不确定缩写是否其他人看得懂,就宁愿用很长的英文单字,也不要用没有人看得懂的缩写。
  • 一个 function 的行数不要太多,大约 「 50 行」上限,并且保持 function 简单容易阅读。
  • 不要用 小写 L , 大小写 O, o 开头的字母
  • 使用 IDE 摺叠功能,将 function 摺起来缩成一行,如 vim 内建就有 folder 的功能。

写注解的时候要小心,透过修改变数 or function 命名来达到容易阅读的方式为最佳,若不是万不得以,不要写注解。

程式排版

程式的排版非常的重要,一个好的排版,读者才能顺畅的看懂程式。

条列式

条列式的排版,比较适合大部分人的阅读方式,举个例好,下面这个程式就是没有经过排版,程式码的变数指定呈现巨齿状,不容易阅读。

Example
  1. $nickname = $person['nickname'];
  2. $age = $erson['age'];
  3. $name = $person['name'];
  4. $address = $person['zipCode'] . $person['address'];

上面那段程式你是否有注意到 第二行的变数 erson 打错字了,接下来我们来帮程式码好好的排版。

Example
  1. $nickname = $person['nickname'];
  2. $age = $erson['age'];
  3. $name = $person['name'];
  4. $address = $person['zipCode'] . $person['address'];

经过排版后,第二行的错字就可以很容易的被发现,因为程式码的可读性变高。

程式码区块

一个 function 的程式码行数大约会在 10 ~ 50 行之间,读懂 50 行程式码也不算是一个简单的事,如果我们将程式码分成多个区块,再对每一个区块写下一行简短的注解,这样读程式码就更容易了,区块注解还有另一个功能,一般人没办法记住每一个区块的程式码逻辑,而注解能提醒读者每个段落的内容,例如下面这个例子。

Example
  1. function request($url, $params, $header)
  2. {
  3. // Handle http request.
  4. if (preg_match(/\?/, $url)) {
  5. $url .= "&";
  6. } else {
  7. $url .= "?";
  8. }
  9. foreach ($params as $key => $val) {
  10. $url .= $key . "=" . $val;
  11. }
  12.  
  13. // Handle Curl
  14. $tuCurl = curl_init();
  15. curl_setopt($tuCurl, CURLOPT_URL, "https://example.com/xx/");
  16. curl_setopt($tuCurl, CURLOPT_PORT , 443);
  17. $tuData = curl_exec($tuCurl);
  18.  
  19. //Handle response
  20. $response = json_decode($tuData, true);
  21. return $response;
  22. }

tmp 暂存的变数

Example
  1. var tmp = "file_";
  2. for (var i = 0; i , 20; i++) {
  3. tmp += i;
  4. }
  5. var file = tmp + ".txt";
  • tmp_file
  • tmp_username

暂存的变数命名

若是真的有些变数无法命名,那就用一般的变数方式来命名。

  • tmp : 不知道如何命名的暂存变数,都用 tmp
  • retval : return value,用途回传值
  • it : iterator , 用在 for each 的每一个 item。

明确的变数命名

  • runLocal --> useLocalDatabase
  • disallowMethod --> disallowCopyAndPaste
  • id = "2" , encodeId = "abefcbad****"
  • size -->sizeMB
  • time --> timeMS (Million Second)
  • length --> lenBytes ,
  • mb_strlen('','', 'UTF8') lenUTF8 ,当使用 UTF8 编码来计算文字长度,一个中文字代表长度 1 ,一个英文字也代表长度 1
  • maxChars : 最大容纳的字元
  • maxBytes : 最大 byte 数
  • maxMultipleBytes : 最多中文数
  • MAX_ITEMS_IN_BOX : 这个 box 的最大值

停止事件 , stop , pause, kill

  • stop, start : 停止某一个行为,并可以使用 start 重新启动一个全新的事件。
  • pause, resume : 暂停某个行为,但是可以重新恢复,继续先前的进度。
  • kill : 强迫结束,不管是否会造成任何问题。

常用的缩写单字

除了一些常用的,大家都懂的缩写单字之外,尽量不要使用其他的缩写单字,使用过多的缩写单字,会造成程式阅读的困难,再加上每个人英文程度不同,很容易造成误解。

  • str : string
  • len : length
  • eval : evaluation
  • doc : document
  • db : database
  • util : utility
  • ms : million second
  • us : 微秒
  • addr : address
  • 来源 src ,目的地 dest

不好的范例

  • backendManager => BEManager , BEManager 很难看得懂
  • googleTranslator => GT
  • color: clr

不要使用反向意思, un , dis, anti

  • 例如我曾经碰过有人命名 unFold = true ,代表打开这个节点 , unFold = false 代表关闭节点 ,那 if (empty($unFold)) 到底是开还是关呢?
  • use_encode , disable_encode

is, has, can, should , use

  • isAdmin = true ,代表 User 是 Admin
  • hasOrder = false ,代表这个 User 有订单,不好的写法是使用 notEmpty 这种反意。
  • useMysql = true

Front-End 相关

  • nodeName: 代表 div, span, body 等等。
  • elm: element 的缩写 ,代表 html 中某一个 node 的物件。

与他人合作

如果你是单兵作战部队,那你想怎么写 code 都不会有人理你,但是当你在一个团队中时,你写的程式,未来将会有很多人帮你维护,修改,解 Bug ,所以写 Code 的时候,必须想到接手的人是否能够快速的理解你写程式。

变数的名称要能发音,请使用念得出来的英文字母来当变数,当我们必须使用缩写或是自创文字,这时尽量组成一个容易发音的单字,这样与其他工程师讨论时会比较容易,或是对新人教学时也会方便很多。

重要变数的数值必须要可以被搜寻到 ,例如我定义订单的 status = 5 时,代表这是一笔成功的订单,并且我要更新订单资讯 , 我可以先定义一个常数变数 STATUS_OPEN = 5 , 这样当我想查询 status = 5 ,程式会执行那几行 Code 时,这时我可以搜寻 STATUS_OPEN 这个字母,而不是搜寻 「5」这个数字 (你如果搜寻 5 的话,会搜寻到相当多的垃圾)。

Example
  1. var STATUS_CLOSE = 4;
  2. var STATUS_OPEN = 5;
  3. if (status == STATUS_SUCCESS) {
  4. updateOrder();
  5. }

其他相关

  • begin , end => first, last , end 代表最后一个,但是没办法说明是否包含最后一个,
一行不要太长,可以断行就断行
  1. if (aaaaaaaa == "bbbbbbbbb" &&
  2. ccccccc == "adddddddd"
  3. ) {
  4. }
  • 物件分类,类似的功能的 function 放在一起。
Example
  1. class xx
  2. {
  3. //fetch data
  4. function fetchJS(){}
  5. function fetchCSS(){}
  6. //save
  7. function saveJS(){}
  8. function saveCSS(){}
  9. //convert encoding
  10. function convertToUTF8(){}
  11. function convertToBig5(){}
  12. }

Function 的开头与结尾括号

不管那一种语言, function 都会有一个开头与结尾大括号 "{}" ,建议括号都能自已独立一行,例如下面这个范例,好处是,当我们使用 IDE 将 function 做折叠功能时,function 名称与参数最好不要被折叠,这样程式码可读性比较高。

Example
  1. // 折叠前
  2. void fetchUser(int userId, bool isAdmin)
  3. {
  4. ret = db.query("xxx");
  5.  
  6. }
  7.  
  8. // 好读的折叠结果
  9. void fetchUser(int userId, bool isAdmin)
  10. +-- 4 lines: {--------------------------------------------------------------------------------------------------------------
  11.  
  12. // 括号不断行的话,程式码会折叠成一行
  13. +-- 4 lines: void fetchUser(int userId, bool isAdmin) {------------------

回應 (Leave a comment)