コードの香りを認識する


“Smells,” you say, “and that is supposed to be better than vague aesthetics?”
Well, yes. We have looked at lots of code, written for projects that span the gamut
from wildly successful to nearly dead. In doing so, we have learned to look for
certain structures in the code that suggest—sometimes, scream for—the possibility
of refactoring.

  • Kent Beck and Martin Fowler, Refactoring

コードの匂いは、悪いソフトウェアのための、そして、したがって、リファクタリングが期限切れであるという指示について説明するのに用いられる用語です.我々が我々のソフトウェアで認識して、適用するのを学ぶデザインパターンに類似していて、命名して、異なるコード匂いを特定することは、既存のコードベースをトリアージして、リファクタリングの形で修正を適用するのを助けます.
マーティンFowlerによって特定されるコード匂いのカタログは、以下です
  • 異なるインタフェースを持つ代替クラス
  • コメント
  • データクラス
  • データ混乱
  • 分岐変化
  • 重複コード
  • 特徴羨望
  • グローバルデータ
  • インサイダー取引
  • ラージクラス
  • 怠惰な要素
  • 長い関数
  • 長いパラメータリスト
  • ループ
  • メッセージチェーン
  • ミドルマン
  • 変更可能なデータ
  • 不可解な名前
  • 原始的な強迫観念
  • 拒否された遺産
  • 繰り返しスイッチ
  • ショットガン手術
  • 投機的な一般性
  • 仮設

  • 実例:コメント
    コメントを明確にし、コードの目的を説明するために使用するときに便利です.しかし、コメントを書くのも難しいですので、不十分なときに、彼らはノイズの源となる可能性が潜在的にソフトウェアの弱点を暴露した.良いコメントを書くテクニックの上で、コメントがどのようにコードファクターになるかについて見てみましょう.

    関数が何をするかを記述するコメント
    // add expenditure to record
    void processInput(int data) {
        //...
    }
    
    機能の変更:関数の変更とコメントの削除
    void recordExpenditure(int amount) {
        //...
    }
    

    コードのブロックを記述するコメント
    static Command parseInput(String input) throws InvalidInputException {
        String task = Parser.tokenize(input)[0];
        // check if the user input contains recognized keywords
        boolean hasKeyword = Arrays
                .stream(TaskType.values())
                .map(TaskType::getRep)
                .anyMatch(x -> x.equals(task));
        if (!hasKeyword) {
            return false;
        }
        return Parser.interpret(input);
    }
    
    機能の抽出
    private static boolean hasTaskKeyword(String input) {
        String task = Parser.tokenize(input)[0];
        return Arrays
                .stream(TaskType.values())
                .map(TaskType::getRep)
                .anyMatch(x -> x.equals(task));
    }
    
    static Command parseInput(String input) throws InvalidInputException {
        if (!hasTaskKeyword(input)) {
            throw new InvalidInputException(input);
        }
        return Parser.interpret(input);
    }
    

    仮定を記述するコメント
    public ShowCommand(Index index) {
        // note that index must not be null!
        // and index must be larger or equal to zero!
        this.index = index;
    }
    
    行動のコース:防御と使用アサーション
    public ShowCommand(Index index) {
        requireNonNull(index);
        assert index.getZeroBased() >= 0;
        this.index = index;
    }
    

    更なる読書
  • An short essay on code smell by Martin Fowler
  • A catalog of code smells
  • コード匂いについての包括的な議論も本の一部です:Refactoring: Improving the Design of Existing Code