Оглавление:
- С чего начать?
- Итак, как мы можем улучшить наши контроллеры?
- Убрать логику из контроллеров
- Создайте отдельный контроллер для каждой конечной точки
- Избегайте наследования
- Обработка ошибок и последовательность операций
- Вывод
Веб-контроллеры - важная часть программного обеспечения. В десктопных приложениях они координируют со службами приложений, получают, анализируют и хранят данные, выполняют бизнес-логику и двунаправленно взаимодействуют с представлением. Однако когда дело доходит до веб-приложений, они являются точкой входа, то есть играют иную роль, чем в десктопных приложениях. В этом посте мы рассмотрим, как иное написание контроллеров сделает наш код более гибким, читаемым и легким.
С чего начать?
Чтобы лучше понять, как контроллер работает по-другому в веб-приложениях, мы рассмотрим хорошо известную модель MVC:
Давайте рассмотрим более подробно. В типичном приложении запроса / ответа ответом, скорее всего, будет представление (иногда контроллеры отвечают только кодом состояния, поскольку они являются действиями, например DELETE для API). Когда представление визуализируется, запрос завершается, взаимодействия больше нет, а для любого другого взаимодействия требуется запуск нового цикла запроса / ответа.
Иными словами, в приложении запрос / ответ у нас есть что-то вроде этого:
Как мы видим, между представлением и контроллером нет двунаправленного обмена: если контроллер снабжает представление всем, что ему нужно, представление никогда не должно получать информацию из других источников. Кроме того, мы можем легко переименовать модель в домен, чтобы отделить ее от любого уровня базы данных, который может использоваться. Переименовывая его в домен, мы разрешаем более широкое использование, например отправку запросов третьим лицам или действия с несколькими организациями.
Итак, как мы можем улучшить наши контроллеры?
По сути, у контроллеров есть две обязанности в веб-приложениях: анализ HTTP-запроса и возврат HTTP-ответа. Это поможет нам успешно разместить наш код. Следующие советы помогут улучшить структуру нашего кода:
Убрать логику из контроллеров
Перенос логики проверки в объекты значений и бизнес-логики в сервисы позволяет нам повторно использовать код в другом месте. Представьте, что в какой-то момент мы решаем обработать какую-то конкретную информацию, поступающую из другого входного уровня, например, из очереди. Во-первых, мы можем повторно использовать все это без необходимости рефакторинга, а во-вторых, мы можем предложить альтернативы для HTTP и реализовать асинхронные и отказоустойчивые процессы, как только введенные данные будут сохранены для последующей обработки.
В этом примере мы видим, что мы предоставляем уровень обслуживания с готовым к использованию объектом, вся информация уже действительна, сразу после инициализации этих объектов.
Создайте отдельный контроллер для каждой конечной точки
Если контроллер обрабатывает GET, он не должен обрабатывать POST, если он получает список, он не должен загружать определенный ресурс. Тем не менее, у нас может быть некоторая дополнительная обработка данных запроса / ответа, например, преобразование json в объекты, объектов в json или ошибка домена в исключения HTTP, но если у контроллера слишком много конечных точек, он станет слишком большим и его будет трудно поддерживать.
Избегайте наследования
Я не говорю, что мы никогда не должны расширять классы, но нам следует избегать расширения контроллера другим контроллером, который, в свою очередь, расширяет другой контроллер и используется половиной приложения. Всякий раз, когда нам нужно что-то изменить в конструкторе базового класса, у нас будет получатся кошмар, исправляющий все эти дочерние классы. Кроме того, у контроллера, вероятно, будет больше обязанностей, чем просто обработка HTTP-запроса / ответа для этого конкретного процесса.
Представьте себе ситуацию, когда нам нужно загрузить пользователя из Redis вместо сеанса PHP, в этом случае мы должны внести клиента Redis во все классы, расширяющие UserController, потому что наше приложение будет иметь набор контроллеров в зависимости от того, какой пользователь вошел в систему. Нам пришлось бы их всех изменить.
Вместо этого, мы создадим классы обслуживания для обработки конкретной логики, подобной этой, то есть сможем внедрить эти службы в наши контроллеры, как в примере ниже:
В этом примере мы извлекли пользовательскую загрузку и контроль доступа к различным службам, поэтому мы можем легко внедрить клиента Redis в UserLoader, и это единственное место, которое нам нужно изменить. Также легко будет протестировать и все остальные места. Такая логика будет работать точно так же.
Обработка ошибок и последовательность операций
Мы должны завершить запрос как можно быстрее. Например, во время цикла запроса есть много разных мест, где мы можем заранее распознать, что запрос не будет успешным. Как только мы это обнаружим, мы сможем сразу же завершить процесс, нет необходимости выполнять больше работы, чем необходимо.
Поток процесса должен начинаться с: 1. Запроса, 2. Подтверждения, 3. Выполнения, и заканчиваться 4. Ответом. Контроллер проверит данные, а уровень сервиса проверит ресурс и выполнит всю бизнес-логику, например, проверив, существует ли уже пользователь, и решит зарегистрировать или вернуть ошибку.
Вывод
Иногда сложно что-то изменить в монолитах, но удаление логики из контроллеров помогает нашему основному домену быть более устойчивым и обеспечивает последовательное применение бизнес-правил во всей кодовой базе. Масштабирование и разделение приложений приведут нас к архитектуре, управляемой событиями, а это означает, что мы будем еще больше повторно использовать бизнес-логику из запросов, отличных от HTTP.
К тому же, такой способ разделения логики не принуждает нас сначала все реорганизовывать, мы можем просто реализовать его по ходу дела и постоянно улучшать дизайн.
Дата: 15.10.2020
|
|
Авторам статті важлива Ваша думка. Будемо раді його обговорити з Вами:
comments powered by Disqus