編寫超級可讀代碼的15個最佳實踐
代碼可讀性是一個計算機編程世界的普遍主題。它是我們作為開發(fā)者第一件學(xué)習(xí)的事情。這篇文章將闡述編寫可讀性代碼十五個最重要的最佳實踐。
1. 注釋和文檔
集成開發(fā)環(huán)境IDE在過去的短短幾年里走過了很長的路。它使得注釋代碼比以前更加有用。依照特定標準書寫的注釋允許IDE和其他工具通過不同的方式來使用它們。
考慮如下示例:
我在函數(shù)定義中添加的注釋可以在調(diào)用它的地方看到,即便是在其他文件中。
這里是我另外一個從第三方庫中調(diào)用函數(shù)的例子:
在這些特殊的例子中,使用的注釋(或者文檔)類型基于PHPDoc,IDE是Aptana。
2 . 一致的排版
我假定你已經(jīng)知道了你必須要縮進你的代碼。然而,保持排版樣式一致仍然是一個好主意。
這里有不止一種方式來進行代碼排版。
第一種:
- function foo() {
- if ($maybe) {
- do_it_now();
- again();
- } else {
- abort_mission();
- }
- finalize();
- }
第二種:
- function foo()
- {
- if ($maybe)
- {
- do_it_now();
- again();
- }
- else
- {
- abort_mission();
- }
- finalize();
- }
第三種:
- function foo()
- { if ($maybe)
- { do_it_now();
- again();
- }
- else
- { abort_mission();
- }
- finalize();
- }
我曾經(jīng)使用第二種樣式但是最近換為第一種。但是這僅僅只代表了一種偏愛。這里并沒有每個人必須要遵守的“最好的”樣式。事實上,最佳的樣式,就是一致的樣式。如果你是一個小組的一部分或者你在為一個項目貢獻代碼,你必須依照這個項目之前使用的樣式。
排版的樣式總不是完全和另外一個不同。有時,它們混合了多種不同的規(guī)則。例如,按照PEAR編碼標準,前括弧“{”和控制結(jié)構(gòu)在同一行上,但是在功能定義后放在第二行上。
PEAR樣式:
- function foo()
- { // placed on the next line
- if ($maybe) { // placed on the same line
- do_it_now();
- again();
- } else {
- abort_mission();
- }
- finalize();
- }
同時注意它們使用4個空格而不是Tab來縮進。
這里http://en.wikipedia.org/wiki/Indent_style有一個維基百科的文章,里面有許多不同排版樣式的例子。
3. 避免顯而易見的注釋
為代碼添加注釋是效果顯著的;但是,它可能太過或者只是多余的文本。像如下例子:
- // get the country code
- $country_code = get_country_code($_SERVER['REMOTE_ADDR']);
- // if country code is US
- if ($country_code == 'US') {
- // display the form input for state
- echo form_input_state();
- }
如果注釋內(nèi)容都是顯而易見的,它們并沒有提高工作效率。如果你必須要注釋這些代碼,你可以簡單的把它們合并在一行:
- // display state selection for US users
- $country_code = get_country_code($_SERVER['REMOTE_ADDR']);
- if ($country_code == 'US') {
- echo form_input_state();
- }
4. 代碼分組
確定的任務(wù)多半需要多行代碼。使用一些空白將這些任務(wù)的代碼分隔為幾段是一個好主意。
這是一個簡單的示例:
- // get list of forums
- $forums = array();
- $r = mysql_query("SELECT id, name, description FROM forums");
- while ($d = mysql_fetch_assoc($r)) {
- $forums []= $d;
- }
- // load the templates
- load_template('header');
- load_template('forum_list',$forums);
- load_template('footer');
在每一段之前添加注釋也增強了視覺上的分隔。
5. 命名的一致性
PHP有些時候在遵守命名一致性方面有很大問題:
strops()和str_split()
imagetypes()和image_type_to_extension()
首先,這些命名必須有單詞的分界線。有兩種流行的選擇:
駱駝命名法:除了第一個單詞外,每個單詞的第一個字符大寫。
下劃線命名法: 單詞間采用下劃線,例如mysql_real_escape_string()。
像我之前提到的一樣,采用不同的命名選擇會創(chuàng)建和排版樣式類似的情形。如果一個已有的項目遵照一個確定的習(xí)慣,你必須遵守它。同時,某些語言平臺傾向于使用特定的命名規(guī)則。例如Java里,大多數(shù)代碼使用駱駝命名法;在PHP里大多采用下劃線命名法。
它們也可以混用。一些開發(fā)者喜歡在程序函數(shù)和類名上使用下劃線命名,但是在類方法名上使用駱駝命名。
- class Foo_Bar {
- public function someDummyMethod() {
- }
- }
- function procedural_function_name() {
- }
所以,沒有明顯的“最好的”樣式,只需要保持一致。
#p#
6. DRY原則
DRY即不要重復(fù)你自己。也被稱為DIE:重復(fù)是惡魔。
這個原則規(guī)定:
“在一個系統(tǒng)里每一個知識的片段必須有一個單一、明確、權(quán)威的表現(xiàn)。”
大多數(shù)應(yīng)用程序(或者通常的計算機)的目的是讓重復(fù)的任務(wù)自動化。這個原則在所有的代碼,即使Web程序中也應(yīng)該保持。代碼的相同片段不應(yīng)該多次重復(fù)。
例如,大多數(shù)Web程序由許多頁面組成。這些頁面很可能包含相同的元素。頁頭和頁腳經(jīng)常符合這個條件。復(fù)制和粘貼這些頁頭和頁尾到每一個頁面中不是一個好主意。這是Jeffrey Way解釋如何在CodeIgniter里創(chuàng)建模版的鏈接。
- $this->load->view('includes/header');
- $this->load->view($main_content);
- $this->load->view('includes/footer');
7. 避免過深的嵌套
太多層的嵌套會造成代碼閱讀和跟蹤困難。
- function do_stuff() {
- // ...
- if (is_writable($folder)) {
- if ($fp = fopen($file_path,'w')) {
- if ($stuff = get_some_stuff()) {
- if (fwrite($fp,$stuff)) {
- // ...
- } else {
- return false;
- }
- } else {
- return false;
- }
- } else {
- return false;
- }
- } else {
- return false;
- }
- }
為了可讀性,通常需要修改代碼來減少嵌套的層數(shù)。
- function do_stuff() {
- // ...
- if (!is_writable($folder)) {
- return false;
- }
- if (!$fp = fopen($file_path,'w')) {
- return false;
- }
- if (!$stuff = get_some_stuff()) {
- return false;
- }
- if (fwrite($fp,$stuff)) {
- // ...
- } else {
- return false;
- }
- }
8. 減少行的長度
我們的眼睛對于閱讀高和窄的文本列更感覺舒適。這就是為什么報紙文章看起來像如下樣子的原因:
避免在一行上編寫過長的代碼是一個最佳實踐。
- // bad
- $my_email->set_from('test@email.com')->add_to('programming@gmail.com')->set_subject('Methods Chained')->set_body('Some long message')->send();
- // good
- $my_email
- ->set_from('test@email.com')
- ->add_to('programming@gmail.com')
- ->set_subject('Methods Chained')
- ->set_body('Some long message')
- ->send();
- // bad
- $query = "SELECT id, username, first_name, last_name, status FROM users LEFT JOIN user_posts USING(users.id, user_posts.user_id) WHERE post_id = '123'";
- // good
- $query = "SELECT id, username, first_name, last_name, status
- FROM users
- LEFT JOIN user_posts USING(users.id, user_posts.user_id)
- WHERE post_id = '123'";
同時,如果任何人想要在例如Vim這樣的終端窗口中閱讀代碼,限制每一行的長度在80個字符以內(nèi)是一個好主意。
9. 代碼結(jié)構(gòu)
理論上,你可以將整個應(yīng)用代碼寫在一個文件里。但是對于閱讀和維護來說是一個噩夢。
在我的第一個編程項目中,我知道創(chuàng)建“包含文件”的含義。但是,我并沒有好好進行組織。我創(chuàng)建了一個“inc”文件夾,放置了兩個文件:db.php、functions.php。當(dāng)程序變大時,functions文件也變得越來越大并難以維護。
最好的方法之一是采用框架或者模仿它們的文件夾結(jié)構(gòu)。下面是CodeIgniter的文件結(jié)構(gòu):
10. 統(tǒng)一的臨時變量名
通常,變量名應(yīng)該是描述性的并且包含一個或者更多的單詞。但是,這對臨時變量來說并不是必須的。它們可以短到只有一個單獨字符。
最佳實踐是:對于有同樣職責(zé)臨時變量采用統(tǒng)一的命名。這里有一些我傾向于在代碼里使用的例子:
- // $i for loop counters
- for ($i = 0; $i < 100; $i++) {
- // $j for the nested loop counters
- for ($j = 0; $j < 100; $j++) {
- }
- }
- // $ret for return variables
- function foo() {
- $ret['bar'] = get_bar();
- $ret['stuff'] = get_stuff();
- return $ret;
- }
- // $k and $v in foreach
- foreach ($some_array as $k => $v) {
- }
- // $q, $r and $d for mysql
- $q = "SELECT * FROM table";
- $r = mysql_query($q);
- while ($d = mysql_fetch_assocr($r)) {
- }
- // $fp for file pointers
- $fp = fopen('file.txt','w');
#p#
11. SQL關(guān)鍵詞大寫
數(shù)據(jù)庫交互對于大多數(shù)Web應(yīng)用來說是很大一個組成部分。如果你正在編寫SQL查詢,盡量保持它們可讀。
即使SQL關(guān)鍵詞和函數(shù)名是大小寫無關(guān)的,大寫來將它們從表名和列名中區(qū)分出來是一個通用的實踐。
- SELECT id, username FROM user;
- UPDATE user SET last_login = NOW()
- WHERE id = '123'
- SELECT id, username FROM user u
- LEFT JOIN user_address ua ON(u.id = ua.user_id)
- WHERE ua.state = 'NY'
- GROUP BY u.id
- ORDER BY u.username
- LIMIT 0,20
12. 代碼和數(shù)據(jù)分離
這是另外一個對于所有環(huán)境下的絕大多數(shù)編程語言都適用的原則。在Web開發(fā)中,數(shù)據(jù)通常意味著HTML輸出。
當(dāng)PHP許多年前第一次發(fā)布時,它最開始被看作是一個模版引擎。在巨大的HTML文件里插入一些PHP代碼行是非常普通的。但是,這些年來,事情發(fā)生了改變:網(wǎng)站變得越來越動態(tài)化和功能化。代碼已經(jīng)是Web程序的一個很大的部分,將它們和HTML合并在一起并不是一個好的實踐。
你可以在你的程序中應(yīng)用這個原則,或者你可以使用一個第三方工具(模版引擎、框架或者CMS系統(tǒng))或者依照它們的習(xí)慣。
流行的PHP框架:
CodeIgniter
Zend Framework
Cake PHP
Symfony
流行的模版引擎:
Smarty
Dwoo
Savant
流行的CMS系統(tǒng):
Joomla
Drupal
13. 模版內(nèi)的交替格式
你可以選擇不使用一個奇特的模版引擎,取而代之的是在模版文件里使用純內(nèi)聯(lián)的PHP代碼。這不是必須要違反“數(shù)據(jù)和代碼分離“,只是內(nèi)聯(lián)代碼是直接和輸出相關(guān)的,并且可讀。在這種情況下你可以考慮使用交替格式來控制結(jié)構(gòu)。
這是一個示例:
- <div class="user_controls">
- <?php if ($user = Current_User::user()): ?>
- Hello, <em><?php echo $user->username; ?></em> <br/>
- <?php echo anchor('logout', 'Logout'); ?>
- <?php else: ?>
- <?php echo anchor('login','Login'); ?> |
- <?php echo anchor('signup', 'Register'); ?>
- <?php endif; ?>
- </div>
- <h1>My Message Board</h1>
- <?php foreach($categories as $category): ?>
- <div class="category">
- <h2><?php echo $category->title; ?></h2>
- <?php foreach($category->Forums as $forum): ?>
- <div class="forum">
- <h3>
- <?php echo anchor('forums/'.$forum->id, $forum->title) ?>
- (<?php echo $forum->Threads->count(); ?> threads)
- </h3>
- <div class="description">
- <?php echo $forum->description; ?>
- </div>
- </div>
- <?php endforeach; ?>
- </div>
- <?php endforeach; ?>
這讓你避免了許多大括號。同時代碼看起來和HTML的結(jié)構(gòu)和排版相似。
14. 面向?qū)ο?vs 面向程序
面向?qū)ο缶幊炭梢詭椭銊?chuàng)建結(jié)構(gòu)化代碼。但是這不代表你完全排除程序化編程。事實上創(chuàng)建兩者混合的風(fēng)格是非常棒的。
描述數(shù)據(jù),通常是數(shù)據(jù)庫里的數(shù)據(jù),必須使用對象。
- class User {
- public $username;
- public $first_name;
- public $last_name;
- public $email;
- public function __construct() {
- // ...
- }
- public function create() {
- // ...
- }
- public function save() {
- // ...
- }
- public function delete() {
- // ...
- }
- }
程序化方法常用于可以獨立執(zhí)行的特定任務(wù)。
- function capitalize($string) {
- $ret = strtoupper($string[0]);
- $ret .= strtolower(substr($string,1));
- return $ret;
- }
15. 閱讀開源代碼
開源項目是許多開發(fā)者一起構(gòu)建的。這些項目必須保持高度的代碼可讀性,以便他們可以盡可能高效的協(xié)同工作。
因此,通讀這些項目的源代碼來觀察這些開發(fā)者是如何工作的是非常棒的方法。
最后: 代碼重構(gòu)
當(dāng)你“重構(gòu)“,你在不改變功能的情況下調(diào)整代碼。你可以把它看作是“清理”,為了改進代碼質(zhì)量和可讀性。
這并不包括bug的修復(fù)或者添加新功能。你可以重構(gòu)你之前編寫的代碼,當(dāng)它們在你頭腦你還保持新鮮的時候,以便于你兩個月以后有可能回顧代碼時更加可讀和可重用。就像那句格言所說的一樣:“盡早重構(gòu),經(jīng)常重構(gòu)“。
你可以在重構(gòu)期間應(yīng)用以上任何關(guān)于代碼可讀性的“最佳實踐“。我希望你喜歡這篇文章!
譯文鏈接:http://blog.csdn.net/hfahe/archive/2011/04/05/6303585.aspx
原文鏈接:http://net.tutsplus.com/tutorials/html-css-techniques/top-15-best-practices-for-writing-super-readable-code/
【編輯推薦】