Давайте приступим к делу? Вот краткий пример нарушения разделения команд и запросов. Предположим, что x — это переменная экземпляра, являющаяся частью класса.

def add_one
  @x += 1
  return @x
end

Команда выполняет действие, в данном случае добавляя единицу к x. Запрос в этом случае просит метод добавления одного вернуть значение x. Большинство людей смотрят на этот метод и «не так уж это важно», но есть проблемы, возникающие из-за того, что мы не разделяем нашу команду и запрос.

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

Также, написав этот метод, мы изменяем состояние x и непреднамеренно вносим побочный эффект в нашу программу. Если кто-то увидит, что этот метод с именем addOne используется где-то еще в программе, он не будет ожидать изменения переменной x.

Исправление здесь состоит в том, чтобы разделить команду и запрос на их собственные методы. Начнем с команды.

def add_one(number)
  number + 1 
end

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

Как насчет нашего запроса?

def x
  @x
end

Простой! Мы хотим вернуть значение x, поэтому мы просто запрашиваем переменную экземпляра x обратно. Это также можно сделать через attr_accessor в ruby.

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

def add_to_x(number)
  @x += number
end

Когда нарушать разделение запросов команд

Итак, мы увидели преимущества CQS, но были ли случаи, когда мы намеренно использовали команды и запросы в одном и том же методе?

Первый пример, который приходит мне в голову, это файл seed.rb в проекте Ruby on Rails. Часто мы создаем десятки и тысячи записей для нашего проекта, запуская rake:db seed. Это может занять некоторое время, и в процессе заполнения было бы неплохо знать, действительно ли создаются записи.

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

В конце концов, мы получаем подтверждение того, что процесс заполнения происходит.

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

Допустим, у нас есть очередь в порядке очереди. Примером очереди «первым пришел – первым обслужен» является сквозной проезд. У вас есть очередь машин, и первая машина заказывает еду, платит и получает еду, и она первая уезжает.

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

Я сделал быстрый пример в IRB, чтобы показать вам, как это будет выглядеть.

irb(main):001:0› cars = [“civic”, “prius”, “tesla”]
=› [“civic”, “prius”, “tesla”]

irb(main):002:0› cars.shift
=› «civic»

irb(main):003:0› cars
=› [“prius”, “tesla”]

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

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

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