Параметры поддерживаемых опций для функций в JavaScript

Мой друг / коллега Сэм Джессо сказал мне, что он ненавидит использование флагов для изменения поведения функций. Это имеет смысл. Функции должны следовать принципу единой ответственности и делать только одно. Это упрощает тестирование и сопровождение кода, поскольку делает функции простыми и лаконичными. Однако погружение практически в любую базу кода покажет, что мы часто делаем исключения и используем флаги.

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

Вместо того, чтобы рассматривать флаги (или параметры) как отдельные параметры, мы можем сгруппировать их в один объект options:

Группировка параметров в один объект имеет ряд преимуществ перед использованием отдельных параметров. Чтобы лучше понять эти преимущества, давайте рассмотрим менее абстрактный пример ...

Пример с форматированием времени

Вот простая функция для получения форматированной строки времени из объекта Date:

Примечание. Да, я написал свою версию leftPad, потому что я не использую простые зависимости для сообщения в блоге. (Также, если вы не съеживаетесь, когда слышите разговор о leftPad, найдите время, чтобы прочитать это.)

Во всяком случае, вернемся к примеру.

Новые требования

У нас есть функция форматирования времени, и она отлично справляется со своей задачей. Но теперь мы хотим иметь возможность переключаться между 12-часовым и 24-часовым временем. И мы также хотим исключить секунды в некоторых случаях.

Нет проблем, мы можем просто добавить к функции несколько дополнительных параметров:

У этого подхода есть несколько проблем:

  • Параметры должны передаваться в определенном порядке. Если мы хотим скрыть секунды, мы все равно должны передать значение для is12Hours, прежде чем мы сможем указать его для showSeconds.
  • Параметры безымянные. Если функция вызывается далеко от определения, может быть неясно, что означают параметры. Мы должны перейти к определению функции, чтобы узнать, что делают различные значения true / false.

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

Рефакторинг с помощью объекта параметров

Простым способом решения этих проблем является рефакторинг функции для использования объекта для флагов / параметров:

Этот подход решает проблемы, которые существуют при передаче флагов в качестве отдельных параметров:

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

Мы не только сделали функцию более читаемой, но и сделали ее удобной для сопровождения, потому что теперь стало проще добавлять множество флагов в нашу formatTime функцию, не добавляя все больше и больше безымянных логических значений, что делает вызовы функций нечитаемыми. Мы могли бы добавить флаги для showMinutes, showMilliseconds или даже возможность указать настраиваемый разделитель для замены двоеточия по умолчанию. Какие бы флаги или параметры мы ни добавили, функция останется относительно читаемой.

Еще кое-что…

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