Есть два потребителя вашего кода: другие люди и компиляторы. Люди — привередливая кучка. Нам трудно держать в голове больше, чем четыре вещи одновременно, мы используем свой личный опыт, чтобы влиять на наши решения, мы ищем упрощения в своем мышлении, используя эвристики, которым мы научились (к лучшему или к худшему), и мы делаем тонны ошибок. Компиляторы тоже привередливы; они очень не прощают нам, людям, когда мы нарушаем синтаксис.

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

Писать для людей тяжело. Очень трудно. Действительно тяжело.

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

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

«В компьютерных науках есть только две сложные вещи: аннулирование кеша и присвоение имен вещам».

— Фил Карлтон

Действительно трудно назвать вещи

Вне разработки программного обеспечения люди изо всех сил пытаются назвать вещи. Это такая сложная задача, что есть много способов назвать ваш бизнес, блог или произвольное вещь. Именование вещей представляет собой уникальную проблему для разработчиков программного обеспечения. Мы постоянно создаем новые пакеты, классы, поля, методы, параметры и переменные. В определенный день мы можем назвать 100 новых вещей, и каждое имя имеет значение.

Одна из причин, почему я думаю, что так сложно придумать хорошие названия для вещей, заключается в том, что обычно нет очевидной аналогии между реальной концепцией и абстракциями, которые мы реализуем. Если аналогия существует, ее может быть трудно понять или иметь незначительную связь с абстракцией. Когда аналогия существует, есть общие термины, которые мы можем использовать при именовании существительных и глаголов в нашей системе. Если вы создаете веб-сайт для интернет-магазина, названия многих ваших существительных и глаголов будут взяты из тех, которые используются при описании обычных розничных магазинов. Почему вы называете объект, содержащий вещи, которые вы хотите купить, чем-то другим, кроме тележки или корзины? Это только запутает читателей вашего кода.

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

Называть вещи, как чемпион!

При попытке сформировать подходящее имя есть несколько рекомендаций, которые могут направить вас в правильном направлении.

Будьте понятны

Назначение вашего класса или функции должно быть очевидно из названия. Вашему пользователю не нужно читать документацию, чтобы получить хорошее представление о том, что делает ваш класс и как его следует использовать. Тем не менее, вы можете зайти слишком далеко в другом направлении; создание неудобных длинных имен.

Рассмотрим некоторый код из реализации базы данных. Вы работаете над сохранением данных на диск и сталкиваетесь со следующим кодом:

private void init() {
  for (File file: files) {
    if (!file.check()) {
      initialize(file);
    }
  }
}

Что проверяет check()? А как насчет файла, который инициализирует initialize()? Я мог бы догадаться, но подозреваю, что моя уверенность в своих предположениях будет достаточно низкой, чтобы я в конечном итоге посмотрел документацию. Сравните этот опыт со следующим кодом:

private void generateMissingTables() {
  for (TableFile table: tables) {
    if (!table.exists()) {
      initializeEmptyTable(table);
    }
  }
}

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

Быть последовательным

Используйте одни и те же имена для одних и тех же «вещей» и не используйте их для других «вещей».

При выборе имени для представления абстракции часто существует множество вариантов. Часто не имеет значения, какое имя выбрано, при условии, что после выбора оно последовательно используется для представления этой абстракции. Например, рассмотрим интерфейс к удаленной системе хранения. Существует множество глаголов, которые можно использовать для представления извлечения элемента из системы хранения, например fetch(), get() или retrieve(). . Если вы выбрали fetch(), вы должны использовать этот глагол всякий раз, когда извлекаете элемент из удаленного storage().

interface RemoteStorage<K, V> {
  Optional<V> fetch(K key);
  Conditional<V> fetchIfNewerThan(K key, Timestamp instant);
  Conditional<V> fetchIfDifferentThan(K key, V value);
}

Использование нескольких глаголов для одного и того же действия увеличит площадь поверхности вашего API, что потребует от ваших пользователей дополнительных знаний для использования вашего пакета.

Если для абстракции выбрано имя, вам следует избегать использования этого имени для других абстракций. Встречая классы или методы с одинаковыми именами, пользователи обычно предполагают, что у них одинаковое поведение. Повторное использование одного и того же имени для разных абстракций не является концом света, но может добавить путаницы. Например, рассмотрим диспетчер кластера для распределенного приложения. Если термин Узел был выбран для обозначения физического хоста, на котором работают приложения, было бы неразумно повторно использовать Узел для обозначения экземпляр приложения. Вместо этого выберите другой термин (например, Экземпляр).

Будьте осторожны, используя синонимы для немного отличающегося поведения. Например, если у вас есть методы remove() и delete() с разным поведением, ваши пользователи будут сбиты с толку и могут непреднамеренно выбрать неправильный метод.

/**
 * Remove the first instance of {@code value} from this collection.
 *
 * @param value The value to remove.
 * @return {@code true} if the collection was modified.
 */
boolean remove(V value);
 
/**
 * Remove the all instances of {@code value} from this collection.
 *
 * @param value The value to remove.
 * @return {@code true} if the collection was modified.
 */
boolean delete(V value);

Вместо этого используйте имя, полученное из исходного термина, с соответствующим цветом для устранения неоднозначности.

/**
 * Remove the first instance of {@code value} from this collection.
 *
 * @param value The value to remove.
 * @return {@code true} if the collection was modified.
 */
boolean remove(V value);
 
/**
 * Remove the all instances of {@code value} from this collection.
 *
 * @param value The value to remove.
 * @return {@code true} if the collection was modified.
 */
boolean removeAll(V value);

Найдите аналогию

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

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

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

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

Доверяйте предупреждающим знакам

Если вам сложно придумать краткое имя для вашего класса или функции, подумайте о рефакторинге. Ваша реализация может делать слишком много или слишком мало.

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

if (engine.currentTemperature() > MAXIMUM_SAFE_ENGINE_TEMPERATURE) {
  dashboard.illuminateIndicator(CHECK_ENGINE);
}