[CleanCode] -15. JUnitを参照


モジュールコードを再記述して文字列比較エラーを識別する(ComparisonCompactor)

凱旋殿


public String compact(String message) {
    if (expected == null || actual == null || areStringsEqual()) {
        return Assert.format(message, expected, actual);
    }

    findCommonPrefix();
    findCommonSuffix();
    String expected = compactString(this.expected);
    String actual = compactString(this.actual);
    return Assert.format(message, expected, actual);
}

改善後


趙建文カプセル化
  • public String compact(String message) {
        if (shouldNotCompact()) {
            return Assert.format(message, expected, actual);
        }
    
        findCommonPrefix();
        findCommonSuffix();
        String expected = compactString(this.expected);
        String actual = compactString(this.actual);
        return Assert.format(message, expected, actual);
    }
    
    private boolean shouldNotCompact() {
        return expected == null || actual == null || areStringsEqual();
    }
    関数もいいです(他で使わない場合は)が、領域変数として減算してもいいと思います.
  • 明確変数名
  • public String compact(String message) {
        if (shouldNotCompact()) {
            return Assert.format(message, expected, actual);
        }
    
        findCommonPrefix();
        findCommonSuffix();
        String compactExpected = compactString(this.expected);
        String compactActual = compactString(this.actual);
        return Assert.format(message, expected, actual);
    }
    
    private boolean shouldNotCompact() {
        return expected == null || actual == null || areStringsEqual();
    }
    否定文
  • より肯定文
  • public String compact(String message) {
        if (canBeCompacted()) {
            findCommonPrefix();
            findCommonSuffix();
            String compactExpected = compactString(expected);
            String compactActual = compactString(actual);
            return Assert.format(message, compactExpected, compactActual);
        } else {
            return Assert.format(message, expected, actual);
        }       
    }
    
    private boolean canBeCompacted() {
        return expected != null && actual != null && !areStringsEqual();
    }

  • 1つの関数に1つのロールがあります
    compactという名前の関数とは異なり、エラーチェックという追加のステップも含まれています.
    関数は、圧縮文字列だけでなくフォーマットされた文字列も返します.
  • ...
    
    private String compactExpected;
    private String compactActual;
    
    ...
    
    public String formatCompactedComparison(String message) {
        if (canBeCompacted()) {
            compactExpectedAndActual();
            return Assert.format(message, compactExpected, compactActual);
        } else {
            return Assert.format(message, expected, actual);
        }       
    }
    
    private compactExpectedAndActual() {
        findCommonPrefix();
        findCommonSuffix();
        compactExpected = compactString(expected);
        compactActual = compactString(actual);
    }

  • 一貫性を持たなければならない
    1、2行目はXを返します
    3,4行目はOを返す
    したがって、以下に示すように、すべてのコンテンツを返す方法に変更します.
  • private compactExpectedAndActual() {
        prefixIndex = findCommonPrefix();
        suffixIndex = findCommonSuffix();
        String compactExpected = compactString(expected);
        String compactActual = compactString(actual);
    }
    
    private int findCommonPrefix() {
        int prefixIndex = 0;
        int end = Math.min(expected.length(), actual.length());
        for (; prefixIndex < end; prefixIndex++) {
            if (expected.charAt(prefixIndex) != actual.charAt(prefixIndex)) {
                break;
            }
        }
        return prefixIndex;
    }
    
    private int findCommonSuffix() {
        int expectedSuffix = expected.length() - 1;
        int actualSuffix = actual.length() - 1;
        for (; actualSuffix >= prefixIndex && expectedSuffix >= prefix; actualSuffix--, expectedSuffix--) {
            if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix)) {
                break;
            }
        }
        return expected.length() - expectedSuffix;
    }

  • じょきょけつごう
    findCommonSuffixをよく見ると、prefixIndexの「時間結合」を先に計算する必要があることがわかります.
    関数を誤った順序に設定すると、徹夜デバッグによる苦労がはっきりと見えます.
    従って、以下のように改善することができる.
  • private compactExpectedAndActual() {
        findCommonPrefixAndSuffix();
        String compactExpected = compactString(expected);
        String compactActual = compactString(actual);
    }
    
    private void findCommonPrefixAndSuffix() {
        findCommonPrefix();
        int expectedSuffix = expected.length() - 1;
        int actualSuffix = actual.length() - 1;
        for (; actualSuffix >= prefixIndex && expectedSuffix >= prefix; actualSuffix--, expectedSuffix--) {
            if (expected.charAt(expectedSuffix) != actual.charAt(actualSuffix)) {
                break;
            }
        }
        suffixIndex = expected.length() - expectedSuffix;
    }
    
    private void findCommonPrefix() {
        int prefixIndex = 0;
        int end = Math.min(expected.length(), actual.length());
        for (; prefixIndex < end; prefixIndex++) {
            if (expected.charAt(prefixIndex) != actual.charAt(prefixIndex)) {
                break;
            }
        }
    }

  • 手探り
    ただ上のコードのfindCommonPrefixAndSuffixは少し汚れています.
    そのため、以下のようにさらに整理することができます.
  • private void findCommonPrefixAndSuffix() {
        findCommonPrefix();
        int suffixLength = 1;
        for (; suffixOverlapsPrefix(suffixLength); suffixLength++) {
            if (charFromEnd(expected, suffixLength) != charFromEnd(actual, suffixLength)) {
                break;
            }
        }
        suffixIndex = suffixLength;
    }
    
    private char charFromEnd(String s, int i) {
        return s.charAt(s.length() - i);
    }
    
    private boolean suffixOverlapsPrefix(int suffixLength) {
        return actual.length() = suffixLength < prefixLength || expected.length() - suffixLength < prefixLength;
    }

    n/a.結論


    モジュールは初めてより少しきれいになりました.もともときれいではないというわけではない.
    著者たちは優れたモジュールを作った.しかし、世界には改善する必要のないモジュールはありません.
    私たち一人一人がコードを初めてよりきれいにする責任があります.