Комментарии в коде и «Приницип неразрывности»


TL;DR

Каждый раз когда вы отделяете фрагмент кода пустой строчкой — пишите однострочный комментарий в котором в двух словах объясните что собираетесь получить.
А каждый раз когда вы пишите однострочный комментарий — выделяйте в метод и комментарий превращайте в его название.
Результат: в вашем коде нет пустых строчек и комментариев

Не пишите комментариев!

Вот очень хорошая, краткая статья о том как правильно писать комментарии. По сути это просто конспект из книжки Дядюшки Боба «Чистый Код».
Читать обязательно. Даже если ты Архитектор с пятнадцатилетним опытом. Чисто для проверки себя и систематизации.

Главная фишка в том, что когда вы избегаете написания комментариев то ваш код сразу становится действительно в разы лучше. Т.е. обдуманно не писать комментарии это условие для написания хорошего кода, а не следствие.
Это очень эффективный метод, правда. Обязательно попробуйте.

Принцип неразрывности кода

Есть ещё один простой принцип который помогает мне писать более ясный код: у вас не должно быть однострочных комментариев и тем более просто пустых строчек в коде. Сейчас поймёте. Есть такой код (из реального проекта):

    private List<CompanyCommand> convertToCompanyCommandList(
            List<CompanyEntity> entities) {

        List<CompanyCommand> companies = new ArrayList<CompanyCommand>();

        for (CompanyEntity entity : entities) {
            companies.add(new CompanyCommand(entity));
        }

        return companies;
    }

Внутри этого метода есть целых три пустые строчки. Зачем они? Для того чтобы логически отделить этапы кода.
Первая пустая строчка на самом деле нужна для того чтобы визуально отделить размазанный на несколько строчек заголовок метода. А почему он размазан на несколько строк? Да потому что есть некий культ карго насчёт ограничения на длину строчек.
Когда то были перфокарты и они имели ограничение на 80 символов в строке. И например в Фортране это ограничение было заложено на уровне языка.
И от туда пошла традиция переносить на другую строчку слишком блинные команды.
Но время шло и сейчас я вам пишу с ноутбука на котором 80 символов занимают примерно 15% ширины экрана. Пятнадцать! Не более.
Естественно не я один это заметил, поэтому в IntelliJ по умолчанию Code Style стоит уже 120 символов. Это конечно прогресс, теперь я могу занять 23% экрана.
Но подождите, зачем вообще сейчас переносить строчки? Для облегчения понимания кода?

В коде это обычное явление когда у тебя есть классы с огромными именами и это обычная ситуация когда делается простая операция (например просто вызов метода и передача пару параметров) и которые выходят за 250 символов.
Ну ничего страшного в этом нет, они остаются простыми для понимания. Проверенно.
А вот если там уже какое сложное выражение а не простой вызов метода или присваивание, тогда вам нужно выделять переменную (Extract Variable refactoring).
Итак, у нас получился такой код:

    private List<CompanyCommand> convertToCompanyCommandList(List<CompanyEntity> entities) {
        List<CompanyCommand> companies = new ArrayList<CompanyCommand>();

        for (CompanyEntity entity : entities) {
            companies.add(new CompanyCommand(entity));
        }

        return companies;
    }

У нас осталась пустая строчка которая отделяет объявление переменной списка от цикла в котором она начиняется элементами.
Давайте напишем комментарий чтобы строчка не пустовала:

    private List<CompanyCommand> convertToCompanyCommandList(List<CompanyEntity> entities) {
        List<CompanyCommand> companies = new ArrayList<CompanyCommand>();
        // add all entaties as company commands
        for (CompanyEntity entity : entities) {
            companies.add(new CompanyCommand(entity));
        }

        return companies;
    }

Отлично. О! Так давайте просто этот код выделим в отдельный метод а этот комментарий станет его названием?

    private List<CompanyCommand> convertToCompanyCommandList(List<CompanyEntity> entities) {
        List<CompanyCommand> companies = new ArrayList<CompanyCommand>();
        addAllEntatiesAsCompanyCommands(entities, companies);

        return companies;
    }

    private void addAllEntatiesAsCompanyCommands(List<CompanyEntity> entities, List<CompanyCommand> commands) {
        for (CompanyEntity entity : entities) {
            companies.add(new CompanyCommand(entity));
        }
    }

Ну и теперь строчка перед return вообще бессмысленна:

    private List<CompanyCommand> convertToCompanyCommandList(List<CompanyEntity> entities) {
        List<CompanyCommand> companies = new ArrayList<CompanyCommand>();
        addAllEntatiesAsCompanyCommands(entities, companies);
        return companies;
    }

Итак, код сократился с десяти строчек до пяти, т.е. в два раза. Это при том, что этот пример просто первый попавшийся мне и не совсем удачный.
На практике у меня было что я сокращал количество строк коде в десяток раз.
Количество строчек кода это не абсолютная метрика — на самом деле у нас даже стало больше строчек потому что мы создали отдельный метод.
Но есть другая метрика кода: вертикальная плотность (Vertical Density). О ней Дядюшка Боб тоже написал в своей книге.
Большую часть времени мы всё таки смотрим код и если мы сразу видим всё на экране то это всё таки проще понять.

Вывод

Пустые строки в кода которые разрывают фрагменты кода это даже не запах, а явный дефект.
Метод неразрывности кода пустыми строчками активно заставляет вас применять самый эффективный рефакторинг выделение метода (extract method refactoring).
Он увеличивает вертикальную плотность кода и улучшает самочувствие программиста 🙂

UPD

Another article in English An Empty Line is a Code Smell

Реклама

5 comments

  1. Аноним

    Обрезать код по 80 символов необходимо хотя бы для того, чтобы его можно было прочитать на странице, подобной этой (без горизонтального скроллинга кусочков).

    • stokito

      Всё верно, и в тоже время код пишется прежде всего для того чтобы быть показаным в IDE а не на блогах или листингах в книгах. А в этой не предназначеной для программистов теме код вообще ужасно смотрится.
      И даже для публикации в блоге код лучше не обрезать.
      Смотрите сами: тут у нас по сути скрылась часть сигнатуры метода. Причём в ней особо ничего важного нет, можно даже туда и не смотреть — всё и так понятно.
      А если перенести на новую строчку то глаза начинают спотыкатся и тогда включается подсознательный компилятор и глаза откатыватся назад чтобы понять «что это за строчка и откуда она взялась? так смотрим назад, ага да это кусок сигнатуры с предыдущей строчки!».

      Так что даже если нужно сделать лишнее движение горизонтального скрола всё равно усваиватся код будет быстрей

  2. Уведомление: Несколько замечаний про код стайл | Серёжа Пономарёв aka stokito
  3. Anastasiia Smirnova

    Все верно написано, но пример довольно неудачный.
    Вы сделали только хуже. У этого метода и так довольно низкий уровень абстракции, он уже оперирует с коллекциями, так что вполне нормально в этом месте проитерировать и добавить элементы в нее.
    С 8ой джавой вот такое бы вообще не имело смысла.
    entities.stream().map(e-> new Command(e)).collect(toList()); — красота

  4. Уведомление: Несколько замечаний про код стайл | stokito on software

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s