НЕНАВИЖУ, когда мой код выглядит как чудовищное количество условий.

If this, do that; 
else if this + 5, do this; 
else if this - 5, do this*5; 
else don't do anything.

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

На Rails Conf 2014 Сэнди Мец выступил с отличным докладом Все мелочи, в котором говорится об этом.

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

Вот несколько моих приемов уменьшения сложности:

Вернуться с вершины

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

def pretty_time(time)
   if time
     time.strftime("%B %e, %Y")
   else
     nil.to_s
   end
end

Конечно, это не так уж плохо, но может выглядеть еще лучше, если вы сделаете это,

def pretty_time(time)
 return nil.to_s unless time
 time.strftime("%B %e, %Y")
end

Вы можете попрощаться с вашими заявлениями о повешении else!

Отличные трубы

Символ трубы, || является фаворитом разработчиков Ruby. Вы можете быстро присвоить значения по умолчанию, когда переменная равна нулю.

> nil || 6
=> 6

Но со струнами он не слишком дружит.

> "" || "six"
=> ""

Когда вы используете это с методом присутствия, происходит волшебство!

> "".presence || "six"
=> "six"

Попробуйте, попробуйте еще раз

Если бы я получал доллар каждый раз, когда сталкивался с ошибкой nil: NilClass, я был бы миллионером! Это сделало меня параноиком, чтобы повсюду использовать «если объект присутствует?».

if user.present?
  return user.name
end

Фу! Есть способ лучше, просто продолжайте попытки.

user.try(:name)

Простой! Теперь, когда вашего пользователя не существует, он незаметно завершится ошибкой и вернет ноль.

Это работает и с методами (спасибо Стиву Робинсону за указание на это).

Если у вас есть метод под названием fullname, попробуйте это,

user.try(:fullname)

Отправка отправлена ​​

У меня есть ужасная привычка организовывать второстепенных рабочих, как если бы они были логическими классами. Я имею в виду, что если у меня есть несколько задач, которые нужно обработать для пользователя в фоновом режиме, я помещаю их все в один воркер (если он не слишком большой). Этим легче управлять, и у меня не возникает проблем с рабочими, когда другие сотрудничают.

Поскольку у меня есть разные задачи, которые нужно обрабатывать для каждого вызова рабочего, я передаю «идентификатор». Что-то, что сообщает рабочему классу, какую функцию выполнять.

class UserWorker
  include Sidekiq::Worker
  
  def perform(action, options={})
    if action == :welcome
      user.welcome_email(options)
    elsif action == :process
      user.process_profile_picture(options)
    elsif ....
    elsif ....
    end
  end
end

УЖАСНО!

К счастью, есть более чистый способ сделать это. Вот где пригодится мощное метапрограммирование Ruby. Используйте send ().

Что такое отправка?

send( ) is an instance method of the Object class. The first argument to send( ) is the message that you're sending to the object - that is, the name of a method. You can use a string or a symbol, but symbols are preferred. Any remaining arguments are simply passed on to the method.

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

class UserWorker
  include Sidekiq::Worker
  
  def perform(action, options={})
    send(action, options)
  end
  def welcome(options)
    user.welcome_email(options)
  end
  def process(options)
    user.process_profile_picture(options)
  end
end

Намного чище, и его намного легче расширить.

Переопределить

К этому конкретному совету нужно отнестись с недоверием. Это не для всех, и при неосторожном использовании может серьезно повредить вашей логике.

Что замечательно в Ruby, как жалобе на ООП, - это простота расширения базовых классов, таких как String, TrueClass и Integer. При осторожном использовании можно творить чудеса.

Я ненавижу выполнять условие if для логических значений, это просто неправильно. Что-то вроде этого,

"You are an admin" if user.admin

Мне пришлось бы создать специальную функцию в классе User, чтобы справиться с такой простой задачей, как печать сообщения, если атрибут истинен. Вот хитрый трюк,

class TrueClass
  def message(m)
    return m
  end
end

Это переопределяет TrueClass, поэтому вы можете делать что-то столь же простое, как это,

user.admin.message("You are an admin")

Так просто! Теперь не забудьте обойти и FalseClass, чтобы не столкнуться с ошибками, связанными с отсутствием какого-либо метода.

class FalseClass
  def message(m)
  end
end

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

Sudo vs Root - это публикация, управляемая и управляемая Skcript.

Если вам понравилось это читать, нажмите «Рекомендовать» ниже. Ты классный.