OOP

Это мини-серия статей по написанию поддерживаемого объектно-ориентированного кода без лишней нервотрепки.

Предыдущие части: Часть 1, Часть 2.

Аргументы, аргументы, аргументы

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

“Каждый из нас может запутаться, сбиться с толку и изменить свое состояние потока в процессе чтения кода. Поэтому и приходится проверять все дважды» — Дядя Боб Мартин.

  • Аргументы осложняют тестирование функции. Крайне трудно писать тестовые примеры для корректной работы всех возможных сочетаний аргументов.

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

Структура

Чем лучше функция, тем меньше в ней аргументов. В идеале — их нет.

ниладическая (нулевая)> монадическая> диадическая> триадическая> полиадическая

Тот же принцип распространяется на конструкторы.

Не забывайте о рефакторинге

  • Объекты аргумента. Если в функциях вы передаете три и более аргументов, то сядьте и подумайте. Если три и более переменные так тесно связаны, что даже передаются вместе в функцию, то почему бы не превратить их в объект? Перегрузка. Перегрузка функции делается для того, чтобы, например, клиент мог вызвать нужную версию функции, указав необходимые параметры.
  • Шаблон «Строитель»: Иногда перегрузка функции приводит к неожиданному эффекту, более известному как анти-паттерн «Телескопический конструктор». Во избежание этого, Джошуа Блок во втором издании «Java. Эффективное программирование» предлагает использовать шаблон «Строитель» для работы с конструкторами, требующими большого количества параметров.
  • Изменяемое состояние: *Не рекомендуется*
    Пожалуй, самым известным и презираемым подходом в разработке ПО с использованием состояния для сокращения параметров в методах является создание глобальных переменных экземпляров. Это решение далеко не идеально, но в ряде случаев работает на ура. Пользуйтесь им с осторожностью, особенно в приложениях с высокой многопоточностью.

«Все глобальные данные виновны, пока не доказано обратное». — Мартин Фоулер

Смерть от логических значений

Чаще всего при передачеbooleanв функцию вы объявляете, что написали функцию, которая выполняет два действия: одно для trueи одно для false. Лучше напишите две функции — по одной на каждый сценарий.

Логическое значение, висящее в списке аргументов, может стать главным источником бед и ошибок. Каким будет истинное значение? А чего можно ждать от ложного? Если это не очевидно из названия функции и аргумента, то каждый раз придется копаться в деталях реализации функции и проверять, что именно передается в true. С передачей двух логических значений дела обстоят еще хуже. Функция, принимающая два логических значения, выполняет целых четыре действия!

Попробуйте отгадать логические значения, их порядок и поведение:

Вынос мозга, не так ли? Избегайте неопределенности и лишних проверок. Переходите на шаблон «Строитель»:

Нулевая защита Null

Передавать null в функцию или писать функцию, ожидающую значения null, — также плохо, как передавать логические значения. По сути, даже хуже. Ведь вы даже не уверены в том, что в ней прописано всего лишь два возможных состояния.

Разумеется, есть некое поведение для всех не пустых значений и одно — для сценария с null. В данном случае, лучше сразу создавать две функции, одна из которых будет принимать не пустой аргумент, а другая — не сможет принять его вовсе. Не пользуйтесь null как псевдологическим значением.

Послушайте Гендальфа. Пустые аргументы не пройдут.

Давайте начистоту: безопасное программирование — отстой. Это же сущий кошмар засорять код проверками на null и ошибки. Мы не хотим думать о том, что наши коллеги могли позволитьnullнезаметно прокрасться в наши функции. Мы также не хотим доверять модульным тестам, не разрешающим передаватьnull.

Такая схема не работает с публичными API, поскольку мы не знаем, кто и что собирается передавать. Если ваш язык поддерживает аннотацию @NotNull или схожую концепцию, то воспользуйтесь им для публичных функций.

Перевод статьи Arun SasidharanObject Oriented Tricks: #3 Death By Arguments