Чистая архитектура: как уменьшить сложность при написании бизнес-правил приложения?

Предположим, у нас есть следующий сценарий "Создать пользователя":

  1. Пользователи могут зарегистрироваться в приложении, используя Facebook, Google+ или LinkedIn;
  2. Бэкэнд должен получить некоторую базовую информацию профиля для регистрации пользователя (электронная почта, firstName и lastName);
  3. Пользователи регистрируются с помощью "идентификатора клиента" (просто добавляя сложность бизнес-правилу);
  4. Когда процесс регистрации завершен, данные должны быть отправлены в тему уведомлений.

Я могу представить запрос на создание пользователя со следующей структурой:

{
  "clientId": "someClientId",
  "authProvider": "FACEBOOK | GOOGLE | LINKEDIN",
  "accessToken": "someAccessToken"
}

Итак, подумав о процессе регистрации / проверки, мы бы получили:

  1. Проверьте, действителен ли запрос на создание пользователя;
  2. Проверьте, действительно ли clientId;
  3. Попробуйте получить информацию о профиле из социальной сети API;
  4. Проверьте, заполнена ли вся необходимая информация профиля;
  5. Проверьте, существует ли пользователь в базе данных;
  6. Зарегистрировать пользователя;
  7. Отправьте данные в тему уведомлений;
  8. Передайте данные докладчику.

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

CreateUserUseCase(
    ApplicationClientGateway applicationClientGateway, 
    SocialNetworkGateway socialNetworkGateway,
    UserGateway userGateway,
    NotificationGateway notificationGateway,
    Presenter presenter
)

и метод execute:

execute(CreateUserRequest request)

    // validates the payload
    // something like
    if (request == null)
      presenter.setError(someError);

    // validates the clientId
    applicationClientGateway.findById(request.getClientId())    

    // retrieves the profile information
    // how to inject dinamically the implementation for
    // Facebook, Google or LinkeIn based on a request parameter?
    profile = socialNetworkGateway.findByAccessToken(request.getAccessToken());

    // checks if the user exists
    userGateway.findByEmailAndAuthProvider(profile.getEmail(), request.getAuthProvider());

    //register the user
    userGateway.insert(user);

    //sends the notification
    notificationGateway.send(user);

    // sets the result
    presenter.setResult(user);

Теперь у нас есть конструктор с множеством аргументов (запах кода?) И как минимум 5 шагов проверки в методе execute.

Это выглядит как нарушение SRP, поэтому, как мы можем разложить этот код, чтобы уменьшить сложность в интеракторе?

2 ответа

Решение

Прежде всего, давайте разберем это в несколько небольших шагов:

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

2) Как и в других ответах, похоже, что ваш сценарий использования имеет много ответственности прямо сейчас. Я предлагаю вам разбить это более чем в одном случае. Что-то вроде:

... Your first gateway (API)
..... ValidateClientId.execute();
..... profile = RetrieveProfile.execute();
..... InsertUser.execute(...)

3.1) В отношении ввода правильного компонента на основе правильной социальной сети вы можете обрабатывать эту логику ВНУТРИ шлюза, а не до его вызова. Помните, что один шлюз МОЖЕТ вызвать другой шлюз (они находятся на одном уровне). Итак, я предлагаю вам использовать что-то вроде.

В usercase -> socialNetworkGateway.findByAccessToken(...) Внутри шлюза вы можете переключаться и вызывать что-то вроде FacebookGateway, GoogleGateway и т. Д.

SRP не говорит, что у вас должны быть маленькие методы или только несколько параметров конструктора. SRP говорит, что "должна быть только одна причина для изменения кода".

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

С этой точки зрения вы не нарушаете SRP.

Согласно рисунку дяди Бобса о "потоке управления" ( https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html), также совершенно правильно передать докладчика.

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

Более подробную информацию о "Что такое вариант использования в чистой архитектуре" вы можете найти в моей серии блогов: http://www.plainionist.net/Implementing-Clean-Architecture-UseCases/

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