代碼細節重構:請對個人代碼指手劃腳(四)

這是上週在代碼審閱會議上討論到的一段代碼,這段代碼的做用是根據指定記錄數量和頁面大小來計算最大分頁數量的。程序員

目標代碼

 1 /// <summary>
 2 /// 根據指定記錄數量和頁面大小返回分頁頁數。
 3 /// </summary>
 4 /// <param name="totalRecords">記錄總數。</param>
 5 /// <param name="pageSize">頁面大小。</param>
 6 /// <returns>返回分頁頁數。</returns>
 7 public static long ComputePages(int totalRecords, int pageSize)
 8 {
 9     var total = Convert.ToDouble(totalRecords);
10     var size = Convert.ToDouble(pageSize);
11 
12     var temp = total / size;
13 
14     return (long)Math.Ceiling(temp);
15 }

代碼問題

在代碼審閱會議上起初並無留意到這段代碼,但隨着翻閱了多個代碼頁以後便發現「ComputePages」這個方法被屢次從新定義,且功能徹底同樣。應該是開發人員複製粘貼過來的,本來也是想針對複製粘貼來說講這段代碼的,但後來發現了更多的問題:編程

  1. 代碼重用問題。經過在整個解決方案搜索,發現這個方法被原封不動的複製粘貼了36次,總計在37個類當中出現了37次,並且這些類所有都是靜態類。這裏的問題就是對於重複出現的代碼邏輯,並且是業務邏輯簡單且又徹底同樣的代碼,沒能實現代碼重用,這會給後續的代碼維護帶來諸多不便;
  2. 類型安全問題。這段代碼的操做對象都是數字,數字屬於值類型,類型安全問題不會顯得特別突出。但數字自己卻會有一些其餘的隱含問題,好比數據類型轉換、分母不能爲零等;
  3. 分母不能爲零。很顯然,這段代碼裏面包含了除法,而對於除法運算沒有作分母不能爲零的邏輯處理。對於新手程序員來講這是很容易被忽略的問題,但對於有必定經驗的研發人員來說,這一點勢必已經刻骨銘心了;
  4. 代碼性能問題。咱們知道在託管代碼中進行各類類型轉換都會帶來不小的性能損失,而如上代碼便存在着一些可優化的部分;
  5. 業務邏輯問題。認真觀察和分析如上代碼,你會發現該方法的輸入參數在特例條件下會輸出不符合實際指望的結果。好比輸出結果多是小於0的負數;

重構建議

找到了問題所在,那麼就會有必定的解決方案:安全

  • 對於代碼重用,能夠在某個業務邏輯相關的類中集中定義這個方法,而不是分散到不一樣的類中。不過,本文不會具體討論這個問題;
  • 對於類型安全、類型轉換,具體到數字的時候,咱們應該適當的考慮一下經過數學的方法來解決這些問題,而不是死板的套取程序語言規範;
  • 對於分母不能爲零這一類定理性的問題,咱們在編碼過程當中必定要當心在乎!千萬不能抱着僥倖心理;
  • 對於業務邏輯上的問題,咱們在編碼以前必定要認真思考、琢磨,弄清楚要解決的問題及可能產生的後果;

重構結果

爲了使得你們更容易理解,我將代碼重構的一些具體思路和想法以備註的方式貼在代碼裏面了,你們認真觀察,有問題能夠提出。性能優化

 1 /// <summary>
 2 /// 根據指定記錄數量和頁面大小返回分頁頁數。
 3 /// </summary>
 4 /// <param name="totalRecords">記錄總數。</param>
 5 /// <param name="pageSize">頁面大小。</param>
 6 /// <returns>返回分頁頁數。</returns>
 7 /* 
 8     * 一、方法返回值從long修改成int。緣由以下:
 9     *    ·輸入參數皆爲int,且運算關係爲除法,因此輸出結果一定在int範圍以內。不使用unit是由於那會給整個解決方案的其餘部分代碼帶來不少的編碼痛苦;
10     *    ·小小的內存性能改進;
11     */
12 public static int ComputePages(int totalRecords, int pageSize)
13 {
14     /*
15         * 二、對記錄總數的類型安全判斷和業務邏輯處理:
16         *    ·記錄總數確定是大於等於零的數;
17         *    ·記錄總數爲零的時候,頁數確定也是零,此時後續的代碼邏輯沒有意義,能夠直接返回0;
18         */
19     if (totalRecords < 1) return 0;
20     /*
21         * 三、對頁面大小的類型安全判斷和業務邏輯處理:
22         *    ·頁面大小不能爲0,由於分母不能爲0;
23         *    ·頁面大小不能爲負數,由於這與事實不符;
24         *    ·當頁面大小爲1的時候,頁數其實就是記錄總數,直接返回totalRecords,這同時也避免了後續的代碼無心義的執行,減小了性能損耗;
25         */
26     if (pageSize < 1) return totalRecords;
27 
28     /*
29         * 四、對原方法業務邏輯的重構、類型轉換方式的優化及性能優化:
30         *    ·經過任何數字乘以(或除以)浮點數其結果仍然爲浮點數的方式完成自動的、隱式的類型轉換,這不但使得代碼更加簡潔,且優化了性能;
31         *    ·代碼簡單、可讀性強,更加容易理解業務邏輯;
32         */
33     return (int)Math.Ceiling(totalRecords*1.0/pageSize);
34 }

結語

俗話說細節決定成敗。做爲程序員,從代碼的細節咱們就能看得出一我的編程水平的高低和開發經驗的多寡,這也從必定意義上決定了你的成與敗!性能

以前我發表過不少文章,都是從人文角度來引導新手的,今天這篇文章,也正好說明了人文因素對程序員素質的影響!優化

要作事,請首先作好人,對本身的代碼負責就是對本身負責,對本身負責就是對團隊負責,對團隊負責就是對企業利益負責,由於咱們是同一個團隊,擁有一樣的利益!編碼

相關文章
相關標籤/搜索