среда, 24 мая 2017 г.

Пустая строка - признак дурно пахнущего кода

Может звучать как шутка, но это не так. Пустая строка, используемая в качестве разделителя инструкций в объектном методе, является дурным запахом. Почему? Короче говоря, потому что метод не должен содержать «частей». Метод всегда должен делать одно, а его функциональная декомпозиция должна выполняться языковыми конструкциями (например, новыми методами), а не пустыми строками.

Посмотрите на этот Java-класс (он пахнет, не так ли?):

final class TextFile {
  private final File file;
  TextFile(File src) {
    this.file = src;
  }
  public int grep(Pattern regex) throws IOException {
    Collection<String> lines = new LinkedList<>();
    try (BufferedReader reader =
      new BufferedReader(new FileReader(this.file))) {
      while (true) {
        String line = reader.readLine();
        if (line == null) {
          break;
        }
        lines.add(line);
      }
    }

    int total = 0;
    for (String line : lines) {
      if (regex.matcher(line).matches()) {
        ++total;
      }
    }
    return total;
  }
}

Этот метод сначала загружает содержимое файла. Во-вторых, подсчитывает, сколько строк соответствует регулярному выражению. Итак, почему метод grep пахнет? Потому что он делает две вещи, а не одну...

Если мы сделаем правило, чтобы избежать пустых строк в телах методов, этот метод необходимо будет реорганизовать, чтобы сохранить «разделение проблем», введенное этой пустой строкой:

final class TextFile {
  private final File file;
  TextFile(File src) {
    this.file = src;
  }
  public int grep(Pattern regex) throws IOException {
    return this.count(this.lines(), regex);
  }
  private int count(Iterable<String> lines, Pattern regex) {
    int total = 0;
    for (String line : lines) {
      if (regex.matcher(line).matches()) {
        ++total;
      }
    }
    return total;
  }
  private Iterable<String> lines() throws IOException {
    Collection<String> lines = new LinkedList<>();
    try (BufferedReader reader =
      new BufferedReader(new FileReader(this.file))) {
      while (true) {
        String line = reader.readLine();
        if (line == null) {
          break;
        }
        lines.add(line);
      }
      return lines;
    }
  }
}

Я считаю, что очевидно, что этот новый класс имеет методы, которые являются намного более сплоченными и удобочитаемыми. Теперь каждый метод делает ровно одну вещь, и легко понять, что это такое.

Эта идея об избегании пустых строк применима и к другим языкам, а не только к Java / C ++ / Ruby и т. Д. Например, этот CSS-код определенно выпрашивает рефакторинг:

.container {
  width: 80%;
  margin-left: auto;
  margin-right: auto;

  font-size: 2em;
  font-weight: bold;
}

Пустая строка здесь говорит нам (кричит, на самом деле), что этот класс .container слишком сложен и должен быть разложен на два класса:

.wide {
  width: 80%;
  margin-left: auto;
  margin-right: auto;
}
.important {
  font-size: 2em;
  font-weight: bold;
}

К сожалению, использование пустых строк для разделения блоков кода - очень распространенная привычка. Более того, очень часто я вижу пустые блоки из двух или даже трех строк, которые все играют эту злую роль разделителя проблем.

Разумеется, правильно разработанный класс должен иметь только несколько общедоступных методов, а правильно разработанный метод должен содержать до десяти инструкций. Пустые строки внутри методов побуждают нас нарушать это ужасное правило и превращать их в многостраничные стихи.

Конечно, проще всего просто нажать ввод несколько раз и продолжить код прямо в том же методе, вместо того, чтобы сначала подумать и реорганизовать. Эта ленивость в конечном итоге приведет к тому, что код вряд ли сможет обслуживаться вообще.

Чтобы это не происходило в ваших проектах, полностью прекратите использовать пустые строки внутри методов. В идеале запретите их в автоматическом построении. В qulice.com, инструменте статического анализа, который мы используем во всех проектах Java, мы создали специальную проверку Checkstyle, которая запрещает пустые строки в каждом методе.

Комментариев нет:

Отправить комментарий