2011年12月30日 星期五

Clean Code - Meaningful Names

最近看了一本大家推薦的書
Clean Code: A Handbook of Agile Software Craftsmanship

看書名就知道這是一本教你怎麼寫出乾淨又簡潔的code
書中提的一些概念和方法我覺得蠻有用的,很推薦大家去看這本書
以下是我整理的一些筆記


  • Use Intention-Revealing Names
  • 選一個好的變數名稱雖然會花時間,但是未來絕對可以幫你省下更多時間
  • 一個好的命名要能傳達以下資訊
  • Why it exists?
  • What it does?
  • How it is used? 
  • 需要額外的註解,不是好的命名
  •  int d; // elapsed time in days
  • 好的命名,清楚的表達變數的用途
  • int elapsedTimeInDays; 
    int daysSinceCreation; 
    int daysSinceModification; 
    int fileAgeInDays; 
    
  • 不好的命名方式,很難看懂這段code在做什麽
  • public List<int[]> getThem() { 
      List<int[]> list1 = new ArrayList<int[]>(); 
      for (int[] x : theList) 
        if (x[0] == 4) 
          list1.add(x); 
      return list1; 
    }
    
  • 同樣一段code經過重新命名後可以看出這是一段踩地雷遊戲程式
  • public List<int[]> getFlaggedCells() { 
      List<int[]> flaggedCells = new ArrayList<int[]>();
      for (int[] cell : gameBoard) 
        if (cell[STATUS_VALUE] == FLAGGED) 
          flaggedCells.add(cell); 
      return flaggedCells; 
    } 
    
  • 更好的作法,用一個Cell的class來取代array of ints
  • public List<int[]> getFlaggedCells() { 
      List<int[]> flaggedCells = new ArrayList<int[]>();
       for (Cell cell : gameBoard) 
         if (cell.isFlagged()) 
           flaggedCells.add(cell); 
       return flaggedCells; 
    } 
    
  • Avoid Disinformation
  • 不要使用一些特殊縮寫的名字
  • ex: hp, aix , sco  (這些縮寫在Unix有特殊意義)
  • 不要使用accountList ,除非他真的是一個List 
  • 就算真的是List也不要把Type encoding到命名裡 
  • accountGroup, bunchOfAccounts, 或是只用accounts都會比accountList來的好
  • 命名不要太過相似
    • XYZMyTodayBrunchBreadXYZMyTodayBreakfastBread 很難被區別
  • 不要使用小寫L和小寫O來做命名,因為很難跟1和0做區別
  • int a = l; 
    if ( O == l ) 
      a = O1; 
    else 
      l = 01; 
    



  • Make Meaningful Distinctions

    • 命名要有意義上的區別
    • 使用Number-series naming(a1, a2, .. aN)不是一種好的命名方式
      • public static void copyChars(char a1[], char a2[]) { 
           for (int i = 0; i < a1.length; i++) { 
             a2[i] = a1[i]; 
           } 
        } 
        
      • 應該命名成source和destination
    • 不要使用類似的單字來命名
      • ex: Product, ProductInfo, ProductData,你無法分辨這三者有什麽不同
    • 不要加上多餘的字
      • ex: NameString, CustomerObject,難道Name會是一個floating pointer嗎?
    • function名稱也要避免使用多餘的字,誰能告訴我以下三個function有什麽差別?
    • getActiveAccount(); 
      getActiveAccounts(); 
      getActiveAccountInfo(); 
      



  • Use Pronounceable Names

    • 使用可以發音的單字來命名,方便Programmer之間溝通
      • genymdhms(generation date, year, month, day, hour, minute, and second)應改成 generationTimestamp



  • Use Searchable Names

    • 使用好被搜尋的名字
    • MAX_CLASSES_PER_STUDENT會比數字7要來的好被找到(簡單說就是不要用magic number)
    • single-letter命名只能被使用在short methods中的local variable


  • Avoid Encodings

    • 不要使用匈牙利命名法
      • 早期因為Compiler不會幫忙檢查type才需要匈牙利命名法,現在的Compiler都很強大
      • 使用匈牙利命名法未來如果要更動型別會很麻煩
        PhoneNumber phoneString; 
        // name not changed when type changed!
        
    • Member Prefixes
      • 不需要prefix member variable with m_
      • 直接用this pointer來區分會比較好,而且在大多數的編輯器中this會有highlight
      • public class Part { 
          private String m_dsc; // The textual description 
          void setName(String name) { 
            m_dsc = name; 
          } 
        } 
        
        public class Part { 
          String description; 
          void setDescription(String description) { 
            this.description = description; 
          } 
        } 
        


  • Avoid Mental Mapping

    • 不要使用單一小寫字母來做命名,因為會需要人腦去做Mapping
    • 如果在很小並且不會和其他名稱衝突的scope,比如說迴圈,使用i, j, k還可以被接受。因為大家都習慣了,容易聯想
    • 如果是使用單一字母a, b, c的話就很糟糕
    • 清楚命名才是王道(clarity is king)


  • Class Names

    • 使用名詞來命名Class和Object,不要使用動詞
    • ex: Customer, WikiPage, Account, AddressParser
    • 避免使用Manager, Processor, Data, Info


  • Method Names

    • 使用動詞來命名,ex: postPayment, deletePage, save
    • Accessors, mutators和predicates要以 get, set和is開頭
      • string name = employee.getName();
        customer.setName("Mike");
        if (paycheck.isPosted())...
        
    • overload constructor的時候,可以使用Factory method pattern來清楚敘述參數
    • Complex fulcrumPoint = Complex.FromRealNumber(23.0);會比Complex fulcrumPoint = new Complex(23.0);來得好


  • Don't be Cute

    • 不要使用俚語或是隱喻的命名方式,因為別人有可能會看不懂
      • (X)HolyHandGrenade => (O)DeleteItems
      • (X)whack() => (O)kill()
      • (X)eatMyShorts() => (O)abort()


  • Pick One Word per Concept

    • 使用一樣的單字來表達同樣一件事情
    • 沒有人分的出來fetch, retrieve, get有什麽差別,使用其中一個為你的method命名就好
    • DeviceManager和ProtocolController,看到這兩個單字你會疑惑Manager和Controller有什麽差別。因此不是一個好的命名
    • 維持code的一致性是很重要的


  • Don't Pun

    • 不要使用同一個單字去表達兩個不同的概念
    • 如果已經有一個叫做add的method用來把兩數相加,就要避免再用add命名"把single parameter加到一個collection的method"。改用insert和append


  • Use Solution Domain Names

    • 命名盡量使用Computer Science領域的專有名詞,因為讀你code的人都是programmer
    • 好的例子
      • AccountVisitor => VISITOR pattern
      • JobQueue => 每個programmer都知道這是什麽


  • Use Problem Domain Names

    • 如果沒有Solution Domain Names可以使用,那就使用和你所解問題有關的字彙。至少可以讓看你code的人去問相關領域的專家


  • Add Meaningful Context

    • firstName, lastName, street, houseNumber, city, state, zipcode這些變數放在一起很明顯可以組成一個address。但是如果你只看到state,你會不知道這代表什麽意思
    • 使用prefix讓他們組合成一個概念,addrFirstName, addrLastName, addrState......


  • Don't Add Gratuitous Context

    • 不要加上多餘的prefix
    • 如果一個application叫做"Gas Satation Deluxe",不需要把所有的class都加上GSD這個prefix
      • 會很難使用IDE做搜尋(所有Class開頭都是GSD)
      • Class名稱會變的很冗長


  • Final Words

    • 不要害怕重新命名,現在有很多好用的tool可以幫助你

    2011年12月27日 星期二

    使用BitBucket來管理你的程式碼



    BitBucket是一個網路服務,他提供了使用者免費的版本控制系統來管理程式碼。
    並且提供issue tracking和wiki的功能。

    其實這類型的網站挺多的,以Git來說最有名的就是Github。不過Github有個缺點是沒辦法免費開私人的Repository,所有的專案都必須公開,不然就是要花錢購買。

    最近,BitBucket 開始支援Git。BitBucket最大的優點就是沒有限制私人Repository的個數。唯一的限制是使用者不能超過5個人
    (5 users free plan and you can have unlimited public and private repositories.)
    官網對user的定義為Someone with read or write access to one of your private repositories
    簡單來說,如果整個專案少於五人參與開發的話,這個限制對你來說完全沒影響
    於是我決定把一些私人的專案搬到BitBucket上試用看看,註冊的方法很簡單

    連結到首頁https://bitbucket.org/,點選Sign up for free

    輸入帳號密碼和信箱(信箱會收到驗證信)

    輸入基本資料

    成功建立帳號後,可以點選create a repository來建立新的repository
    或是點選Import an existing repository來Import其他地方建立的專案,比如說從Github, Google Code, SourceForge......


    輸入專案名稱和使用語言,當然別忘了設定Repository type為Git

    接下來就可以開始上傳程式碼了,這邊不詳細講解Git的指令,只示範如何上傳到BitBucket
    首先先輸入git clone把剛才建立的repository複製一份下來,這邊假設專案名稱為bbs_parser
    swaywang則是你的BitBucket帳號
    sway:~$ git clone https://swaywang@bitbucket.org/swaywang/bbs_parser.git
    
    建立一個上傳測試用的Python程式
    sway:~$ echo "print 'Hello World'" > hello.py
    
    把hello.py加入到Server上
    sway:~$ git add hello.py
    
    commit,並且夾帶訊息
    sway:~$ git commit -m "Print Hello World"
    
    最後push到Server上
    sway:~$ git push -u origin master
    
    
    
    
    


    最後在個人首頁就可以發現程式已經被傳上去了
    之後要再建立repository只需要點個人首頁中的create a repository連結即可

    最後推廣大家一起來使用Git,Git的優點可以參考下列這個網站
    http://git-scm.com/about

    2011年12月26日 星期一

    人月神話:軟體專案管理之道


    這本書應該不用多介紹了,軟體工程的聖經

    人月神話雖然出版30多年了,但是書中所寫得大部分準則到現今仍然適用,甚至有許多主管或是老闆都還是會犯書中所寫到的一些問題。書中最重要的觀念之一就是人月(man-month),到現在還是很多人會認為軟體開發進度落後時候就是要多加一些人手進來。作者在30年前就告訴大家這個主張是完全錯誤的。因為人力和工時根本無法互換。

    記得這本書最早是我高中時候看得,那時候大部分的章節都沒辦法真正體會。研究所時我又看了一次,這次因為有實際開發過一些大型Project,所以比較能搞懂書中的一些章節。接下來我想等工作5年後再來看一次,相信又會體會更多的東西。

    這本書絕對是每個軟體工程師必讀的一本書,如果你還是學生的話可能很多內容沒辦法體會。不過等你經驗夠多之後再看,絕對能學到很多東西。

    Head First Programming(深入淺出程式設計)



    我一直很喜歡Head First系列的書籍,HF的特色就是用許多圖片和有趣且實際的範例來教導讀者。因此看到這本HF Programming就決定借回家看。這本書就如同書名所寫得,是專門寫給完全沒寫過程式的人看。不過花了幾個小時看完之後,我覺得這本書根本不適合初學者看

    先講本書的優點。書中以Python來教導基本的程式概念,我覺得這是很好的主意。Python簡單的語法會比C來的更適合初學者學習。本書1~6章主要以教導程式流程和基本資料結構為主,這部份我覺得寫得還OK,舉得例子(web parser, twitter貼文程式)也很貼近實際上的應用。

    不過從第7章到結束竟然都在講解GUI,我邊看邊想一個完全沒寫過程式的人看到這邊真的能瞭解怎麼撰寫GUI嗎?何況後面講解GUI的速度又非常的快,新手一定很難消化。我反而覺得應該藉由一些簡單的Project再度複習一些前面的基本觀念,這樣才是一本適合初學者的書。

    因此這本書我覺得比較適合有一點點程式基礎的人來看,而不是給完全沒有程式基礎的人看。完全沒程式基礎的人還是比較適合去看詳細一點的入門書,並搭配大量的練習。這本書只花了大約200頁(而且因為圖片的關係,大概3頁等於傳統書籍的一頁)在介紹基本的語法,對初學者來說是完全不夠的。

    題外話,如果是想學Python的人那更是完全不需要看這本書。因為這本書不是一本Python的教學書,沒有很深入的介紹Python,建議去看Python專門的書會比較好。

    2011年12月13日 星期二

    [Vim]清除搜尋完後的Highlight

    在使用Vim搜尋功能的時候,會把找到的關鍵字自動Highlight起來
    這些反白一直到你離開Vim再進來都還會存在
    我剛開始用Vim時候也不知道怎麼把反白清掉
    於是就用很笨的方法,去搜尋一個不會存在的字串
    比如說:
    /asdfghj
    
    最近總算查到消除搜尋Highlight指令

    只要輸入:
    :noh
    
    就可以消除Highlight

    如果要完全關掉搜尋自動Highlight功能
    可以在~/.vimrc中加入以下指令
    set nohlsearch