整潔代碼之道 5 格式

選用一套管理代碼格式的簡單規則,然後貫徹這些規則
其實現在的 IDE 基本上都有非常標準的代碼格式化規則,我們只需要在編寫代碼的過程中時常格式化代碼即可

5.1 格式的目的

  1. 代碼格式很重要
  2. 代碼格式不可忽略,必須嚴肅對待
  3. 代碼的可讀性會對以後可能產生的修改行爲產生深遠影響

5.2 垂直格式

  1. 每個文件的代碼行數不要過多,儘量保持在 100 行以內,儘量不要超過 200 行
  2. 短文件通常比長文件易於理解

5.2.1 向報紙學習

  1. 名稱應當簡單且一目瞭然
  2. 源文件最頂部應該給出高層次概念和算法
  3. 細節應該往下漸次展開,直至找到源文件最底層的函數和細節

5.2.2 概念間垂直方向上的區隔

  1. 每行展現一個表達式或一個子句,每組代碼展示一條完整的思路
  2. 這些思路之間應該用空白行區隔開
  3. 每個空白行都是一條線索,標識出新的獨立概念

5.2.3 垂直方向上的靠近

  1. 緊密相關的代碼應該互相靠近

5.2.4 垂直距離

  1. 對於那些關係密切,放置於同一源文件中的概念,它們之間的區隔應該成爲對相互易懂程度有多重要的衡量標準
  2. 應該避免迫使讀者在源文件和類中跳來跳去
  3. 變量聲明應該儘可能的靠近其使用位置,僅限於局部變量
  4. 循環中的控制變量應該總是在循環語句中聲明
  5. 實體變量應該在類的頂部聲明,就是指的全局變量
  6. 若某個函數調用了另外一個,就應該把它們放到一起,而且調用者應該儘可能的放在被調用者上面
    • 這一點和我平時的習慣有衝突,我一般喜歡把私有的函數從文件底部開始編寫,公開的函數從文件頂部開始編寫
  7. 概念相關的代碼應該放到一起,相關性越強,彼此之間的距離就該越短

Good Example

  1. 這是 Junit4 的代碼片段,這段代碼遵循了作者上述描述中的所有規則
  2. 我一般習慣把被調用的函數放在下面,同時喜歡把私有函數和共有函數區分開
public class Assert {
  static public void assertTrue(String message, boolean condition) {
    if (!condition) {
      fail(message);
    }
  }

  static public void assertTrue(boolean condition) {
    assertTrue(null, condition);
  }

  static public void assertFalse(String message, boolean condition) {
    assertTrue(message, !condtion);
  }

  static public void assertFalse(boolean condition) {
    assertFalse(null, condtion);
  }
}

5.2.5 垂直順序

  1. 被調用的函數應該放在執行調用的函數下面
  2. 最重要的概念先出來,通過最少細節表述它們,底層細節最後出來

5.3 橫向格式

  1. 代碼長度達到 100 個字符或者 120 個字符是作者認爲已經比較長了
  2. 但作者也說到,現在顯示屏越來越大,分辨率越來越高,所以像 100 - 120 個字符的長度也可以接受,但真的不建議更長

5.3.1 水平方向上的區隔與靠近

  1. 我們使用空格字符將彼此緊密相關的事物連接到一起
  2. 也用空格字符把相關性較弱的事物分隔開
  3. 這些規則現在的 IDE 都會通過格式化代碼做到準確無誤
  4. 我個人比較喜歡單行註釋後面加一個空格在編寫內容,例如 // 這裏是註釋 ,而不是 //這裏是註釋

5.3.2 水平對齊

  1. 老舊的習慣,沒什麼用

5.3.3 縮緊

  1. 遵循 IDE 規則即可
  2. 唯一需要注意的是縮緊的實際空格大小,例如 Java 中的一個 Tab 縮緊表示的是 4 個空格,而其他的例如 JS 就是兩個空格
  3. 我習慣於除了 Java 以外,其他的語言都使用兩個空格作爲一個 Tab 的縮緊

5.3.4 空範圍

  1. 儘量不要使用將 while 或 for 語句的語句體置爲空的寫法

5.4 團隊規則

  1. 一組開發者應當認同一種格式風格,每個成員都應該採用那種風格
  2. 好的軟件系統是由一系列讀起來不錯的代碼文件組成,它們需要擁有一致和順暢的風格
  3. 絕對不要用各種不同的風格來編寫源代碼,這樣會增加其複雜度

5.5 鮑勃大叔的格式規則

  1. 作者認爲下面這段代碼是他寫的可以作爲 最好的編碼便準文檔的範例
  2. 我覺得大部分還比較認可,幾個小細節跟我習慣性的有點出入
public class CodeAnalyzer implements JavaFileAnalysis {
  private int lineCount;
  private int maxLineWidth;
  private int widestLineNumber;
  private LineWidthHistogram lineWidthHistogram;
  private int totalChars;

  public CodeAnalyzer() {
    lineWidthHistogram = new LineWidthHistogram;
  }

  public static List<File> findJavaFiles(File parentDirectory) {
    List<File> files = new ArrayList<File>();
    findJavaFiles(parentDirectory, files);
    return files;
  }

  private static void findJavaFiles(File parentDirectory, List<File> files) {
    for (File file : parentDirectory.listFiles()) {
      if (file.getName().endsWith(.java”)) {
        files.add(file);
      } else if (file.isDirectory()) {
        findJavaFile(file, files);
      }
    }
  }

  public void analyzeFile(File javaFile) throws Exception {
    BufferedReader br = new BufferedReader(new FileReader(javaFile));
    String line;
    while ((line = br.readLine()) != null) {
      measureLine(line);
    }
  }

  private void measureLine(String line) {
    lineCount++;

    int lineSize = line.length();
    totalChars += lineSize;

    lineWidthHistogram.addLine(lineSize, lineCount);
    recordWidestLine(lineSize);
  }

  private void recordWidestLine(int lineSize) {
    if (lineSize > maxLineWidth) {
      maxLineWidth = lineSize;
      widestLineNumber = lineCount;
    }
  }

  public int getLineCount() {
    return lineCount;
  }

  public int getMaxLineWidth() {
    return maxLineWidth;
  }

  public int getWidestLineNumber() {
    return widestLineNumber;
  }

  public LineWidthHistogram getLineWidthHistogram() {
    return lineWidthHistogram;
  }

  public double getMeanLineWidth() {
    return (double) totalChars / lineCount;
  }

  public int getMedianLineWidth() {
    Integer[] sortedWidths = getSortedWidth();
    int cumulativeLineCount = 0;
    
    for (int width : sortedWidths) {
      cumulativeLineCount += lineCountForWidth(width);

      if (cumulativeLineCount > lineCount / 2) {
        return width;
      }
    }

    throw new Error(“Cannot get here”);
  }

  private int lineCountForWidth(int width) {
    return lineWidthHistogram.getLinesForWidth(width).size();
  }

  private Integer[] getSortedWidths() {
    Set<Integer> widths = lineWidthHistogram.getWidths();
    Integer[] sortedWidths = (widths.toArray(new Integer[0]));
    
    Array.sort(sortedWidths);
    
    return sortedWidths;
  }
}
發佈了419 篇原創文章 · 獲贊 50 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章