1. 程式人生 > >軟體開發中的注意事項(常見問題整理)

軟體開發中的注意事項(常見問題整理)

一、函式定義原則

1、一個函式/方法只做一件事情,不能將多個事情放在一個函式中處理(單一職責原則 SRP)

函式/方法的最小粒度是功能,函式在設計/定義的時候,不能將多個功能柔進一個函式裡面,這樣函式會變得得膨脹,增加了函式的耦合性,不便於函式管理維護。

例如,有這麼一個業務邏輯:使用者每天來網站閱讀文章,當閱讀完畢不同的10篇文章之後,就給他增加10個使用者積分。

這個業務邏輯可以拆分為4個功能,也就需要定義為4個函式/方法來實現。

1)、使用者閱讀文章增加閱讀計數(按照文章);

123456789101112 /** * 使用者閱讀文章增加閱讀計數(按照文章)。 * * @param integer $uid       使用者ID * @param integer $articleId 文章ID * * @return void */publicfunctionaddUserReadingArticleCount($uid,$articleId){// ...}

2)、統計指定使用者當日閱讀的不同文章數量;

1234567891011 /** * 統計指定使用者當日閱讀的不同文章數量。 * * @param integer $uid 使用者ID * * @return integer */publicfunctiongetTodayReadingCount($uid){// ...}

3)、給指定使用者增加積分;

123456789101112 /** * 給指定使用者增加積分。 * * @param integer $uid   使用者ID * @param integer $score 使用者積分 * * @return void */publicfunctionaddScoreForUser($uid,$score){// ...}

4)、寫入使用者積分日誌;

12345678910111213 /** * 寫入使用者積分日誌。 * * @param integer $uid   使用者ID * @param integer $score 使用者積分 * @param string  $brief 日誌描述 * * @return void */publicfunctionaddScoreLog($uid,$score,$brief){// ...}

這四個功能函式也可以再封裝到一個函式統一進行管理呼叫,這個函式用來封裝處理當前的業務需求(內部單獨呼叫4個函式來實現),但是卻不能將4個功能都定義到一個函式中。

12345678910111213141516171819 /** * 該方法用來處理一個特定的業務需求。 * * @param integer $uid       使用者ID * @param integer $articleId 文章ID * * @return void */publicfunctioncheckAndAddScoreForUser($uid,$articleId){$this->addUserReadingArticleCount($uid,$articleId);$readingCount=$this->getTodayReadingCount($uid);if($readingCount>=10){$score=10;$this->addScoreForUser($uid,$score);$this->addScoreLog($uid,$score,'當日文章閱讀量達到10,增加積分10');}// ...}

這樣拆分之後的好處是:

1)、程式結構清晰,易於閱讀;

2)、函式耦合性低,易於維護;

3)、函式可重用性高,減少程式碼冗餘;

試想一下,假如又有新的需求:使用者每個月在網站閱讀完畢不同的100篇文章之後,就給他增加100個使用者積分

假如處理之前的需求時沒有對業務邏輯進行功能拆分,僅用一個函式來實現,面對現在這個新需求你將會怎麼做呢?

2、在設計函式/方法時,應當儘可能考慮到定義的通用性,而不是僅僅為了解決當前業務需求本身

通用性設計的目的,是為了提高程式碼的可重用性,減少程式碼冗餘,提高程式碼編寫的質量。

拿上面的兩個需求舉例:

1)、統計使用者閱讀數量的函式,需求是要求統計當日的,因此我們設計的時候只提供了當日的統計數量。後面的需求又要求統計了每個月的數量,於是我們不得不再定義一個統計指定月份的統計數量的函式,然而這兩個統計函式內部的統計邏輯相似度很高,這樣就造成了程式碼的冗餘(大多數的冗餘程式碼就是這麼產生的)。於是我們回過來想一想,當時設計統計函式的時候為什麼不這樣設計呢:

12345678910111213 /** * 統計指定使用者指定時間段閱讀的不同文章數量。 * * @param integer $uid       使用者ID * @param integer $startTime 統計開始時間戳 * @param integer $endTime   統計結束時間戳 * * @return integer */publicfunctiongetReadingCount($uid,$startTime,$endTime){// ...}

這樣的設計既滿足了當前業務的需求,也提高了設計的擴充套件性和可重用性,即使後續有不同時間段的統計需求,我也不用再新增加任何統計函式,減少了程式碼冗餘。

2)、目前的需求是要求增加積分,但是有沒有考慮過既然有增加就會有減少的情況,假如遇到減少積分的情況怎麼辦?例如,積分兌換獎品的需求,這個時候我們需要對使用者積分進行減少,按照之前的設計,我們是不是必需再增加一個函式,用於減少使用者積分?那我們為何一開始不這麼開設計呢:

123456789101112 /** * 調整使用者積分。 * * @param integer $uid   使用者ID * @param integer $score 使用者積分(正數為增加,負數為減少) * * @return void */publicfunctionadjustScoreForUser($uid,$score){// ...} 

同樣場景的還有列表分頁函式等等。

二、函式註釋原則

函式註釋必需闡述清楚函式功能(不嫌長而嫌闡述不清),並且不能出現有歧義或者功能與描述不符的情況。

函式的註釋是為了讓開發者在最短的時間內弄清楚這個函式的作用,如果註釋沒有合理填寫,那麼開發者(特別是不同模組的開發者或者後續的功能維護者)會進入到該函式內部進行檢視,並梳理函式內部的業務邏輯甚至會需要結合相關業務需求進行分析才能看明白這個函式是幹什麼用的,這樣的工作效率勢必會影響到整合專案的協作開發及維護效率。

三、快取使用原則

如果不是物理長期儲存的,必需設定過期時間;如果是可以物理儲存的,考慮為何不寫到資料庫中(如:MySQL)。

常用快取伺服器如Redis和Memcache,如果設定快取的資料不過期,那麼久而久之裡面的資料將會越來越多,很容易產生垃圾資料長期佔用記憶體且不易清理。因此,在日常的開發中,對於快取的操作,都儘量設定過期時間,以便在人為忽略或者操作失誤的時候,有快取伺服器這一層可以保證快取資料能自動得到及時清理。

四、團隊分工協作

1、模組維護採用模組責任制。當開發中需要操作某個自己不熟悉的模組時,不能直接修改,而應該找到對應的模組負責人提供相應的介面(並且該介面的定義應當考慮通用性)。

為什麼需要這樣做:

1)、開發過程中獨立開發,互不影響,並且版本管理中也不易產生分支衝突;

2)、開發過程中對於不熟悉的模組進行操作,由於對該模組的業務、功能、資料庫等上下文環境不熟悉,需要花費更多的時間去理解,且容易產生問題;

此外,模組維護採用AB兩人責任制,一人負責,一人後備。

2、關於git的模組維護問題。比如在一次迭代開發中有若干任務(分支例如:A、B、C),任務之間有部分耦合,多個任務需要其他模組的責任人員提供API支援,為了避免程式碼衝突及設計冗餘,怎麼做?

1)、首先,在使用git進行版本管理的時候,不同的分支應當保持獨立性,這樣互不影響,以便在分支部署的時候也可以單獨部署。因此,需要考慮到耦合的任務是否需要保證獨立性?

2)、如果是,那麼任務的開發者需要找到對應耦合模組的負責人,由他來協調好耦合部分的方法定義,並且由他來新建獨立的分支(例如:D)定義這些需要的API,然後開發者再合併API分支(D)到開發任務分支(A、B、C)中,繼續開發;

3)、如果否,那麼任務的開發者也需要找到對應耦合模組的負責人,共同協商耦合部分的方法定義,由其中一個任務的分支(例如:C)負責定義所需的全部API,其他任務的分支分別合併該任務分支即可