Notes
Простой рецепт отвязки от фреймворка
Если вы хотите создавать приложения, которые будут удобны в обслуживании на долгосрочной основе, вам необходимо отделить их от вашего фреймворка, ORM, HTTP-клиента и т. д., потому что ваше приложение переживет их всех.
Три простых правила
Чтобы достичь отвязки от фреймворка, вам всего лишь нужно следовать этим простым правилам:
- Все сервисы должны получать все свои зависимости и конфигурационные значения, внедренные в качестве аргументов конструктора. Когда зависимость использует ввод-вывод, вы должны ввести для нее абстракцию.
- Другие типы объектов не должны нести сервисные обязанности.
- Контекстную информацию всегда следует передавать в качестве аргументов метода.
Правило 1
Следование правилу 1 гарантирует, что вы никогда не будете получать сервис ad hoc, например, используя Container::get(UserRepository::class). Это необходимо для отвязки от фреймворка, поскольку глобальное статическое средство, которое возвращает вам сервис, по определению является специфическим для фреймворка. То же самое относится к получению конфигурационных значений (например, Config::get('email.default_sender')).
Иногда зависимость использует ввод-вывод, то есть общается с базой данных, файловой системой и т. д. В этом случае вы должны ввести абстракцию для зависимости. Если вы зависите от конкретного класса, этот класс будет работать только с конкретной библиотекой или фреймворком, с которым вы работаете сейчас, поэтому, чтобы остаться независимым, вы должны использовать свою собственную абстракцию, сочетаемую с реализацией, которая использует вашу текущую библиотеку/фреймворк.
Правило 2
Помимо сервисов, будет несколько других типов объектов, таких как сущности, объекты-значения, доменные события и объекты передачи данных, ни один из которых не должен нести сервисные обязанности. Ни один из них не должен нести сервисные обязанности, потому что это означает, что они либо вызывают сервисы через какое-то глобальное статическое средство, либо им нужна специальная настройка, специфическая для фреймворка/ORM, что означает, что они не могут использоваться изолированно и не переживут крупное обновление фреймворка или переход на другой. Примером объекта, который не следует правилу 2, является модель active record, которая может выглядеть как сущность, но способна сохранять себя, что на самом деле является сервисной обязанностью.
Правило 3
Контекстная информация обычно выводится из текущего веб-запроса или пользовательской сессии, например, ID пользователя, который в данный момент вошел в систему. Вместо того чтобы извлекать эти данные каждый раз, когда они вам нужны (например, Auth::getUser()->getId()), вы должны передавать их от метода к методу как обычный аргумент.
В совокупности правила 1, 2 и 3 обеспечивают, что для каждого метода абсолютно ясно, что он делает, какие данные ему нужны и от каких сервисных зависимостей он зависит для своей работы. Более того, ни одна из зависимостей или аргументов методов не будет специфична для фреймворка или библиотеки, что означает, что ваш код приложения будет эффективно отделен от фреймворка.
Заключение
Если спросить меня, эти правила действительно очень просты и не требуют много дополнительной работы по сравнению с тесной связью всего с текущим набором установленных пакетов в вашем проекте. Так почему бы не следовать им, если вы знаете, что ваш проект должен соответствовать актуальным стандартам и через 3 года?
P.S. Следование этим правилам дает вам гораздо больше, чем просто отвязку от фреймворка: все становится тестируемым в изоляции, тесты полностью детерминированы и, следовательно, очень стабильны, и их выполнение занимает очень мало времени.
https://matthiasnoback.nl/2020/09/simple-recipe-for-framework-decoupling/
Leave a reply