1. 程式人生 > >寫程式碼時應該注意的問題

寫程式碼時應該注意的問題

1, 程式碼可維護性相關
 (1), svn 提交不寫註釋
 (2), 命名太隨意
 (3), 程式碼隨意排版
 (4), 多層巢狀結構
 (5), 一個方法包打天下 : 要記住 -- 單一職責原則, 一個方法不應該承載太多,要儘量抽取出來。
 (6), 不統一的風格
 (7), 混亂的 pom 檔案
 (8), 暈頭轉向的配置檔案 -- Spring配置檔案, MyBatis mapper檔案,properties檔案等
2, 程式碼正確性相關
 (1), 資源清理
 (2), 資源使用
 (3), 忽視引數檢查
 (4), 吞掉異常
 (5), 併發環境下錯誤使用資料結構
 (6), 資料庫
3, 除錯診斷相關
 (1), 合理記錄日誌
 (2), 監控記錄
 (3), 給執行緒指定名稱
4, 設計相關
 (1), 不可測試的程式碼


維護性相關 
*混亂的 pom 檔案*
對於一個java maven專案,pom.xml檔案就是這個專案的臉面,臉面當然要整潔漂亮。那麼一個漂亮的pom要符合哪些需求呢?
    1.  儘量短
        a.  保留儘可能少的必須的依賴,把沒有必要的依賴刪除掉
        b.  減少重複。比如我們經常需要引入同一個系列的幾個依賴, 這些依賴的版本一般都一致,那我們應該抽取一個
            properties來表示該version。在使用父子專案時,我們還可以儘量將一些子module裡都重複使用的東西抽取到父pom
裡(推薦引入superpom)。
    2.  排版整齊
    3.  清晰明確
        a.  在父pom裡使用dependencyManagement來管理依賴,並且將一些重要依賴的版本抽取到properties,這樣開啟父
pom對這個系統的依賴就一目瞭然。
        b.  父子專案中幾個子專案使用統一的版本號
        
正確性相關
InputStream stream1 =  null ;
InputStream stream2 =  null ;
try {
 stream1 = initStream1();
 stream2 = initStream2();
 //porcess stream1 and stream2
} finally {
   if (stream1  !=  null ){
      try {
         stream1.close();
     } catch (Exception e){
       //record log
     }
  }
   if (stream2 !=  null ){
     try {
      stream2.close();
    } catch (Exception e){
       //record log
    }
  }
}
// 這樣就可以保證stream1 和stream2 都能正確的關閉。但是上面的程式碼看起來太繁瑣了,而且這樣的程式碼在系統中很常見,所以我們一些工具類庫也已經為這樣的程式碼提供了工具類,比如commons­lang 裡的IOUtils 就提供了IOUtils.closeQuietly() 方法,而guava 裡也為我們提供Closeables 幫助類。在java 7 裡,jdk 甚至為我們提供了try­with­resources statement 這個基礎設施。
*系統中常見的需要清理的資源*
    (1), 磁碟檔案,比如FileInputStream, FileOutStream等(只要帶Stream的都要注意)
    (2), 網路連線, 比如URLConnection, HttpClient, Socket等
    (3), 資料庫連線,最好使用類似Spring之類的框架訪問資料庫,如果自己使用DataSource.getConnection(不推薦)則一定要小心  
資源使用 *
  在我們的系統中經常需要:
    1.  讀取檔案內容
    2.  批量讀取資料庫
    3.  執行緒池
    4.  等等
這些操作有一個共同的特徵是 : 對系統有限資源(記憶體,CPU等)的索取。當我們編寫對有限資源使用的程式碼時,一定要注意資源的使用是否可控。比如對於讀取檔案來講,如果檔案較大我們最好採用流式讀取(檔案大小不是拍腦袋得出來的,是經過定量的計算得出的),流式讀取使得我們可以一邊讀取檔案內容一邊處理,如果將檔案內容全部讀入記憶體當遇到特別大的檔案的時候可能讓記憶體爆掉。流式讀取也不是說說那麼容易,這就要求我們的檔案以及資料格式是便於流式讀取處理的。


而對於批量讀取資料庫的情況,有的同學直接來一個不加limit的SELECT語句,如果這個時候滿足條件的記錄較多,就會從資料庫中載入特別大的資料,這不僅對資料庫產生較大壓力,對應用的記憶體也是一個考驗。所以對於批量從資料庫讀取資料,要求我們也採用一種流式的,每次讀取一些處理一些,然後再去讀取。


有的時候我們為了並行化或非同步處理一些操作時,需要自己建立執行緒池。在Java中就是建立ThreadPoolExecutor類。我們使用這個類時一定要注意這個類的建構函式中幾個引數的確切意義是什麼,大部分對這幾個引數都不明不白,在出問題的時候往往會使問題惡化。而大部分教科書上推薦使用j.u.c中Executors類更是將這種不明不白加重。


其實就一點,我們對系統任何資源的使用都應該是可控的方式,並且能通過定量的方式分析為什麼要使用這些資源。   


忽視引數檢查 *
    引數檢查的程式碼確實很討厭,寫起來囉哩囉嗦,還擾亂了我們程式碼的核心邏輯。於是一些人為了避免這些麻煩,並且信心滿滿的說我這個方法的呼叫源比較可靠不會傳遞非法的引數給我,如果確實如此當然可以,但理想很豐滿,現實很骨感。往往越是我們盲目自信的地方,往往越容易出一些低階的錯誤。所以對一些公開出去的介面,我們一定要注意引數驗證的邏輯。對於一些private介面
    如果經過檢查確實不會有非法引數傳遞進來,可以不做引數驗證。
好在我們有非常多的第三方庫可以使用幫我們降低引數驗證的繁瑣。比如在Spring Controller這個級別我們有Validator,它可以將引數驗證邏輯剝離到另外一個類中處理,讓Controller更純潔。對於內部的一些介面,我們也可以使用Google guava的Preconditions來簡化程式碼。比如: Preconditions.checkNotNull(url);


併發環境下錯誤使用資料結構 *
  設計的時候考慮到即使以後程式碼在併發環境下執行也不會出問題,如果因為其他原因做不到這點也應該在介面上詳細的表明這一點
資料庫 *
  給表設計主鍵 如果未給表指定主鍵,MySQL會從表中選取一個唯一的列作為主鍵,如果無法找到這樣的列,Mysql會給定一個隱藏的列作為主鍵,這會帶來很多問題, 使用非業務欄位作為主鍵 業務欄位可能因為需求的變更而發生變化使用按插入先後順序的欄位作為主鍵(比如自增),並保持主鍵儘量小(比如自增的整型就挺合適) InnoDB 使用 B­Tree 作為資料庫的索引。如果主鍵不是順序的會引起B­Tree不斷分裂,導致效能低下。InnoDB中所有的索引中都會包含主鍵,所以如果主鍵特別大的化會嚴重影響效能。
  按照業務需要設計索引 按照業務的需求斟酌每個索引的意義和價值,索引也是有成本的
  在使用 SELECT 查詢的時候明確指定要查詢的列,禁止使用 SELECT * 將不需要的列也給搜尋出來。
  -------------------------------------------------------------------------
除錯診斷相關
  合理記錄日誌
  監控記錄
  給執行緒指定名稱
  
從現在起,我們都是專業人士,專業的人要做專業的事兒。用什麼來標識我們的專業?不是你的衣著,也不是你擁有多酷的電腦,
而是用你的程式碼質量,你工作的方式來標識。從現在起,認真對待你每一個命名,每一行程式碼,每一個方法,每一個類。