Каждый инженер должен в свободное время почитать техническую литературу. Когда вы читаете, вы узнаете много нового. Вы читаете о чьем-то опыте, передовой практике и неудачах. Обладая этой полезной информацией, вы можете увидеть новые возможности, можете сделать свой код лучше и стабильнее, можете создавать новые функции лучше и быстрее.
В этой статье я хочу поделиться некоторыми хорошими практиками, которые я прочитал в технической литературе.
Напишите понятный код и подумайте об ответственности
Не забывайте, что Ruby - это умный язык. И постарайтесь написать читаемый код. Многие разработчики при написании кода забывают о принципе ответственности. Много раз я видел дополнительные условия, в которых их быть не должно. Это приводит к негативным последствиям в вашем коде. Очень сложно поддерживать этот код и создавать в нем новые функции. Иногда, если вам нужно реализовать новую функцию, лучший способ - удалить весь код и переписать его с нуля.
Первый пример. Ежедневно информационная система анализирует список подписчиков. Список подписчиков представляет собой csv-файл со следующими столбцами:
- ‘number’ - номер строки индекса.
- «Email» - адрес электронной почты пользователя.
- ‘first_name’ - имя пользователя.
- ‘last_name’ - фамилия пользователя.
- ‘действие’ - действие пользователя. Он может содержать истину или ложь. Истина означает, что пользователь хочет подписаться. Значение false означает, что пользователь хочет отказаться от подписки.
- ‘subscription_ids’ - список идентификаторов подписок.
Нравится:
number|email|first_name|last_name|action|subscription_ids 1|some_email.ru|James|Smith|true|1,3 2|some_email2.ru|Barbara|O'connor|true|1,2,3,5 3|some_email3.ru|||false|3,6
Ниже приведен пример плохого кода. В нем много условий, и его трудно читать.
Давайте сделаем код более читабельным. Нам нужно добавить какой-нибудь метод в класс User и создать класс SubscriberRow. Это лучше.
Второй пример. Мы пишем программное обеспечение (приложение rails) для ресторанной компании. Компания ежедневно изготавливает и продает пиццу. Нам нужно написать модуль для отображения еженедельной статистики. Компании необходимо знать данные на каждый день текущей недели:
- день недели
- количество проданной пиццы
- сумма заказов
- ТОП-3 покупателей (пользователи, у которых наибольшее количество заказов)
- ТОП-3 проданных пиццы
Для этой задачи мы можем создать контроллер с одним общедоступным методом и любым частным методом вроде этого:
Мы завершаем нашу задачу, но код плохой. Если нам понадобится добавить в этот контроллер какие-то большие функции, у нас возникнут проблемы. Или, если нам нужно продублировать функционал для другой части системы (другой контроллер, api) или отправить данные по электронной почте, у нас возникнут проблемы.
Что нам делать? Нам нужно определить ответственность и использовать DRY. Необходимо создать несколько классов для агрегирования данных и сбора ежедневных данных за неделю.
Смотрится лучше. В StatisticsController у нас есть только одна строка, которую мы можем легко скопировать в другую часть системы.
Не бойтесь использовать .fetch для хеширования
Иногда нам нужно работать со сложным вложенным хешем. Когда мы пытаемся получить доступ к значению глубоко, код может быть таким:
var = nil if(some_hash.present? and some_hash[:key_1].present? and some_hash[:key_1][:key_2].present?) var = some_hash[:key_1][:key_2] end
Для доступа к значению существует долгое условие. Трудно читать. Мы можем переписать его с помощью метода .fetch (). Этот метод хеширования принимает два аргумента: ключ и заполнитель. Если у хэша нет ключа, метод вернет заполнитель.
var = nil if some_hash.present? var = some_hash.fetch(:key_1, {}).fetch(:key_2, nil) end
Fetch имеет одну особенность: если существует хеш-ключ и он возвращает nil или false, метод вернет nil или ложь. Но если вы используете activesupport, вы можете переписать код в стиле rails.
var = some_hash.try(:fetch, :key_1, {}).try(:fetch, :key_2, nil)
Проверить переданные аргументы
В Ruby нет статической типизации. Это означает, что любые переданные аргументы и возвращаемые значения могут быть экземпляром любого класса. Это может внести путаницу в код.
Взгляните на пример. Мы создали класс GeoCoordinate для создания географических позиций на интерактивной карте.
class GeoCoordinate def initialize(latitude, longitude) @latitude = latitude @longitude = longitude end # and more code end
Когда вы смотрите на код, вы видите, что метод инициализации принимает два аргумента: «широта» и «долгота». Но вы не видите, в каком экземпляре должны быть широта и долгота. Должна быть широта экземпляром числа или экземпляром строки? Разные разработчики могут писать разный код.
GeoCoordinate.new(55.45, 37.37) GeoCoordinate.new('55.45', '37.37') GeoCoordinate.new(['55.45'], ['37.37']) GeoCoordinate.new(magicCoordinate.new) GeoCoordinate.new(Latitude.new('55.45'), Longitude.new('37.37')) GeoCoordinate.new(latitude: '55.45', longitude: '37.37’)
Вдобавок есть много других классов в разных частях системы.
В этом случае мы можем написать функцию с таким же именем для проверки переданных аргументов. Функция дает нам уверенность в том, что переданные аргументы действительны. Если аргументы недопустимы, это вызовет ошибку TypeError.
Проверка возвращаемых значений
В языках программирования со статической типизацией, если какой-либо метод / функция возвращает массив, он будет возвращать массив каждый раз. Если какой-то другой метод возвращает строку, он будет возвращать строку каждый раз. В языках программирования с нестатической типизацией каждый метод / функция может каждый раз возвращать разные экземпляры. Это может создать проблемы в нашем коде.
Например, принимает класс GeoCoordinate. Он имеет метод three_nearest_coordinates, который должен возвращать максимум три экземпляра класса GeoCoordinate . Но в текущей реализации он может возвращать array, экземпляр, false или nil. Это очень сложно отладить.
Нам нужно переписать three_nearest_coordinates. Он должен каждый раз возвращать массив.
Длинный хеш в переданных атрибутах недопустим
Любой метод / функция может принимать хеш в переданных атрибутах с 2–3 ключами. Звучит неплохо. Через некоторое время система становится больше, имеет больше функций, а в хеш-коде 8–10 ключей вместо 2–3. Это может создать проблемы. Разработчик может сделать орфографическую ошибку в ключах (неправильное написание трудно отладить), или выбор правильного параметра занимает много раз. Взгляните на пример.
Лучше всего переписать метод / функцию, вместо хеша нужно использовать любой экземпляр. Это действительно упрощает чтение и отладку кода.
Это все. Надеюсь, эти советы и практика будут вам очень полезны.