Какой шаблон дизайна можно использовать для спагетти с переключением функций?

Компания, в которой я работаю, ушла из глубины мира с помощью функциональных ключей-переключателей конфигурации, которые включают / выключают определенное поведение в зависимости от определенных условий. Мартин Фаулер на самом деле называет их "переключателями бизнеса" ( http://martinfowler.com/bliki/FeatureToggle.html).

У нас много клиентов, использующих один и тот же сервис, но каждый хочет немного различного поведения. Хуже того, многие хотят, чтобы определенные подгруппы их пользователей видели другое поведение. Таким образом, мы используем бизнес переключатели. Переключатели стали спагетти-шаром логики if/else с иногда неожиданными взаимодействиями.

Существуют ли какие-либо шаблоны проектирования, полезные для управления такой ситуацией?

Ура!

2 ответа

  • Переключатели должны быть переключателями во время выполнения, а не во время компиляции. Причина в том, что коммутаторы должны работать без повторного развертывания.
  • Есть две возможности реализовать условную логику во время выполнения:
    1. if-then-else (или же switch-case для многоуровневых переключателей)
    2. Полиморфия, которая требует объектно-ориентированного языка программирования.

Я лично предпочитаю использовать равнину if-then-else конструкции, украшенные комментарием поговорка TODO: Remove when feature has been tested. если применимо.

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


Тем не менее, что касается вашего спагетти, я бы порекомендовал рефакторинг.

  • Ни одна функция не должна иметь глубину вложенности больше двух. Если есть, разделите на несколько функций со значимыми именами.
  • Устранить двойные отрицания.
  • Законы де Моргана особенно полезны для реорганизации условной логики.

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

Я чувствую, что легче ответить на вопрос, используя небольшой пример:

Пример проблемы: у вас есть компонент, выполняющий некоторые вычисления из некоторого ввода. В зависимости от клиентов могут меняться следующие вещи:

  • Источник / формат входных данных
  • Предварительная обработка входных данных
  • Три различных способа [A..C] для вычисления некоторого результата в зависимости от варианта использования клиента.
  • Выходной формат результатов вычислений.

Так что рабочий процесс может выглядеть примерно так:

Preprocess -> Compute с использованием [A..C] -> Format output -> Done.

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

  1. Классифицируйте для каждого шага обработки вид Поведения. В примере для этапа предварительной обработки это может быть что-то вроде IInputShaper, отвечающее за преобразование входных данных определенного типа во внутренний формат и некоторую предварительную обработку. Возможно, это можно было бы снова разделить: IInputFitter, IPreprocess. Для других шагов в рабочем процессе, сделайте соответственно. Это оставляет вам контракты для ряда типов поведения (что также полезно для понимания вашей проблемной области. Теперь вы можете легко увидеть, откуда на самом деле берутся степени свободы, сколько различных типов поведения имеет система, и вы можете сохранить Чистая реализация ядра. Также вы можете протестировать базовую кодовую базу, вы можете задокументировать требования для каждого контракта поведения и протестировать реализации поведения в виде модульного тестирования, а не "in vivo" - загроможденного в базовой кодовой базе.
  2. Реализуйте каждое поведение в соответствии с контрактами, определенными на шаге 1. Принимайте некоторый повторяющийся код в реализациях поведения, вместо того, чтобы перепроектировать и пытаться выявить сходства между этими поведениями. Будь проще. И есть тесты для каждого из них.

Результат: коллекция реализаций поведения с 0 опциями конфигурации и базовым кодом с 0 опциями конфигурации. Последний шаг - выбрать реализации поведения для проекта заказчика, возможно, написать новую реализацию, если есть что-то особенное.

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

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

Другие вопросы по тегам