Перевод Naming 101: Programmer’s Guide on How to Name Things.

Присвоение имён — одна из главных трудностей в разработке. Невозможно подсчитать, сколько времени мы тратим на обдумывание имён и на попытки разобраться в коде с плохими именами. И не важно, объекты это, методы, классы или что-то другое. Считается доказанным фактом, что мы тратим больше времени на чтение кода, а не на его написание, поэтому хорошие правила присвоения имён в будущем облегчат вам жизнь.

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

Ниже объясним важность хороших правил присвоения имён и поделимся полезными советами.

Уровень абстракции


Методам и переменным нужно присваивать имена в соответствии с их назначением. Прежде чем выбирать имя, поймите, за что отвечает этот кусок кода.

Давайте разберём ситуацию, когда метод возвращает строковое значение расстояния между Варшавой и Парижем:

class DistancePresenter
  def to_s
    'The distance between Warsaw and Paris is 1591 km'
  end
end

Код простой, и вроде бы работает правильно. А если немного поменять требования? Скажем, нужно отображать расстояние в километрах и милях. Для этого введём переменную класса взамен ключевого слова km в методе to_s.

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

Так за что отвечает наша новая переменная? Она предоставляет объекту слова km или mi. Так что назвать переменную можно kilometers_or_miles, но такое наименование будет на том же уровне абстракции, что и сами значения переменной. Если нам нужна возможность использовать другие единицы измерения (к примеру, дни), то имя kilometers_or_miles будет неверным. Нужно что-то более общее. Раз километры и мили — это единицы измерения, то можем назвать переменную unit. Получается на один уровень абстракции выше (более общее название), чем назначение переменной. Новая реализация класса:

class DistancePresenter
  def initialize(unit)
    @unit = unit
  end
  
  def to_s
    "The distance between Warsaw and Paris is 1591 #{unit}"
  end
  
  private
  attr_reader :unit
end

Расстояние между Варшавой и Парижем 1591 км, но в милях получается 988. Нужно реализовать метод, возвращающий правильное значение. Правило такое же, как и в случае с переменной unit. Давайте сначала подумаем о решаемой задаче. Новый метод должен возвращать значения 1591 или 988. Не важно, как метод будет это делать. Можно было бы назвать его distance_warsaw_paris, но получится тот же уровень абстракции, что и у переменной. То есть имя метода будет предполагать возвращаемые значения. Слишком подробно.

В будущем города могут поменяться, к примеру, на Нью-Йорк и Лондон. Тогда имя distance_warsaw_paris устареет, а менять его по всему коду будет трудозатратно. Лучше назвать просто distance. Именно то, что нужно: на один уровень абстракции выше тела метода.

Теперь наши методы выглядят так:

class DistancePresenter
  def initialize(unit)
    @unit = unit
  end
  
  def to_s
    "The distance between Warsaw and Paris is #{distance} #{unit}"
  end
  
  private
  attr_reader :unit
  
  def distance
    if unit == 'km'
      1591
    else
      998
    end
  end
end

Уровень абстракции и имена классов


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

Дочерние классы нужно именовать таким же образом. Если у нас есть класс Car, можно добавить специфическую версию, например, CarPickup для машин Car с большей грузоподъёмностью.

То есть правило, согласно которому именовать нужно на один уровень абстракции выше содержимого, применимо к методам и переменным, но не классам.

Принцип единственной обязанности


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

Например, единственная обязанность бутылки — быть контейнером для жидкостей. Не нужно наделять бутылку возможностью двигаться или делать что-то другое, для чего она не предназначена (в приложении). Как бы вы назвали контейнер для жидкостей, который может двигаться? Не так это легко, и бутылка — довольно простой пример. Вместо того, чтобы плодить ходячие (а затем, возможно, танцующие, бегающие и говорящие) бутылки, лучше придерживаться принципа единственной обязанности. Создайте один класс для контейнера под жидкости, назовите Bottle, а потом создайте класс для перемещения бутылки — BottleCarrier.

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

Разбивайте всё на более мелкие части


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

Задумайтесь, разве не лучше давать имена модулям и объектам, когда вы знаете их назначение? Допустим, нужно описать машину. Трудно в одном классе перечислить каждую функциональность, но если разделить на много маленьких частей, то получим классы Wheel, Tire, steeringWheel и другие, отражающие всевозможные компоненты машины. Этим маленьким компонентам легче подбирать имена, а их назначение легко определить. Так что если вам трудно даются имена компонентов, вероятно, у архитектуры какие-то недостатки.

Итог


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

  • Поднимайтесь на один уровень абстракции выше тела элемента (за исключением имён классов).
  • Имя класса должно описывать его обязанность.
  • Уважайте принцип единственной обязанности (одно из SOLID-правил).
  • Разбивайте задачу на более мелкие подзадачи.

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

* * *

На эту статью вдохновила книга “99 Bottles of OOP”, написанная Сэнди Метц и Катриной Оуэн. Хорошая книга. Из неё можно узнать много полезного, в том числе о хороших методиках рефакторинга кода.

Комментарии (5)


  1. Almet
    05.12.2017 14:30

    Что-то ничего полезного, к сожалению. По моему мнению, чем больше кодишь, тем больше набираешься опыта, соответственно и мышление уже складывается, и название методов/переменных носит частный характер, т.к. четких правил по названию (не считая внутреннюю разработку в команде)


    1. KasperGreen
      06.12.2017 05:12

      Nix Solitions постит по новой методике Porojnyak [/irony]


      В целом советы годные, но скудные.
      Тем кто этим пользуется — и так понятно,
      а тем кто свой код не читает — не нужно.


  1. rustler2000
    06.12.2017 14:12

    Про вред -er в именах объектов и то больше 101


    1. KasperGreen
      06.12.2017 14:24

      Так. Назвать класс, имя… назвать класс… как его назвать?… Точно!

      class Naher {}
      


      А если серьёзно чем так вредны имена на -er? Можно ссылку почитать?