Сэнди Метц и объектно-ориентированное проектирование в Ruby

в 9:04, , рубрики: ruby, Блог компании Издательский дом «Питер», книги, ооп, Программирование, Профессиональная литература

Здравствуйте, уважаемые читатели.

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

Сэнди Метц и объектно-ориентированное проектирование в Ruby - 1

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

Поговорите с рубистами – и большинство из них крайне положительно отзовутся о книге «Практическое объектно-ориентированное программирование в Ruby». Программированием я занимаюсь достаточно давно, но начинал с процедурных языков, поэтому стоило мне столкнуться с объектами и классами, как я сразу предпочитал ретироваться. Пройдя курс во Flatiron School, я неплохо усвоил основы ООП, но по-прежнему хотел получше разобраться в нюансах. Вот я и решил взять томик Сэнди и как следует его покурить. Одолев всего около четверти книжки, все вполне уяснил.

Очень круто, когда бывалый разработчик вроде Сэнди таким красивым языком делится своим опытом, накопленным более чем за 30 лет профессиональной карьеры. Кроме того, очень здорово видеть, как она последовательно демонстрирует несколько этапов рефакторинга (а не просто хороший код), начиная с заправского антипаттерна. Итак, довольно предисловий; сейчас расскажу о самых интересных деталях, которые уже узнал из первых глав книги:

Классы и методы должны работать по принципу единственной ответственности и выполнять минимальную возможную задачу

Многие слышали об этом раньше, но стоит еще раз подчеркнуть: одно из основных преимуществ правильного объектно-ориентированного кода в том, что он напоминает конструктор из взаимозаменяемых компонентов, с которыми в будущем станут работать другие программисты. Если реализовать ООП-код хорошо, то это как правило означает, что возможности получится дорабатывать, добавлять и удалять без каскадирования по всей базе кода, которое может превратиться в сущий ночной кошмар. Принцип DRY («не повторяться») красиво вплетается в такую парадигму, поскольку именно при сушке кода приходится разбивать программу на мелкие уникальные компоненты.

Бывает очень сложно определить, как разделить код на классы и зоны ответственности, но Сэнди подсказывает пару хороших правил:

  1. Попытаться описать цель класса в одном утверждении, без И или ИЛИ. Если не получается — попробуйте переделать класс.
  2. Что касается поведений, реализуемых в вашем классе, попробуйте позадавать вопросы различным его методам и проверьте, насколько осмысленно они звучат. Например, «Appointment (встреча — прим. пер.), во сколько ты состоишься?» — нормально. А вот «Встреча, какова твоя площадь в сантиметрах?» — уже подозрительно, вероятно, лучше перенести ее в другой класс.

Избегайте зависимостей

Эта тема слишком объемна, чтобы рассмотреть ее в рамках данной статьи, причем в книге Сэнди данная тема является одной из основных. Но, полагаю, следующая метафора вполне передает ее суть:

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

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

Class Person
  attr_accessor :name, :height, :hair_color

  def initialize(args)
    @name = args[:name]
    @height = args[:height]
    @hair_color = args[:hair_color]
  end
end
Person.new(name: “Travis”,  hair_color: “brown”, height: 6.25)

При использовании хеша получаем сразу несколько преимуществ, в частности:

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

Уважайте Закон деметры (LoD)

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

Допустим, имеется класс Order, в нем есть метод place_order, а в этом методе делается вызов customer.cart.items.update_stock. Тем самым мы, вероятно, нарушим закон Деметры, поскольку обращаемся к пользовательскому объекту, чтобы получить объект корзины заказа, чтобы получить объекты элементов, чтобы реализовать метод update_stock и тем самым изменить количественные атрибуты у каждого элемента. Ух, выговорил! Иногда такая практика сравнивается с избеганием железнодорожных катастроф, так как длинный метод напоминает цепочку вагонов. Согласитесь, такая ассоциация запоминается гораздо лучше, чем имя древнегреческой богини урожая.

Доступ к переменным экземпляров через методы

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

Активно классифицировать методы как публичные и приватные

То, как вы классифицируете методы внутри класса, многое говорит о вашем коде и помогает другим программистам понять, как он работает. Обычно в случае с публичным методом подразумеваются следующие моменты:

  1. Другие объекты могут свободно его использовать
  2. Этот метод стабилен и, вероятно, не изменится
  3. Метод сообщает об ответственности и назначении вашего класса
  4. Метод нужно протестировать

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

Итак, это всего лишь некоторые вещи, которые я почерпнул из книги Сэнди. С увлечением читаю дальше. Книга очень увлекательна, поскольку подробно рассматривает философию программирования и ООП в частности. Спасибо за внимание!

Автор: Издательский дом «Питер»

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js