Как вы знаете, с ростом размера кода приложения его становится все сложнее поддерживать.
Давайте рассмотрим подход к тому, как с наименьшими усилиями структурировать код Symfony приложения таким образом, чтобы снизить затраты на внесение в него изменений и упростить повторное использование или замену его частей.
Давайте на примере рассмотрим, по каким принципам разбивать функционал на модули, как его обобщать, как называть.
У нас будет готовое приложение, но при необходимости мы сможем с минимальными усилиями подобрать необходимый компонент. И так, мы берём за основу какое-то базовое понятие, например продукт, и начинаем вокруг него обобщать.
Создайте папку «Продукт».
У продукта может быть категория и другие сущности, мы можем разместить их внутри.
Некоторый функционал можно выделить отдельно, и это будет зависеть от Продукта.
Нам нужно посмотреть, насколько связана эта логика, насколько сложно ее разделить и насколько это необходимо.
Это разделение может быть изменено со временем и подвергнуто рефакторингу.
Так что по мере необходимости можно будет подбирать компоненты.
Отметим некоторые особенности компонента.
Компонент может зависеть от другого компонента, но этот другой компонент не может зависеть от него, и не должно быть циклической зависимости между другими компонентами.
В противном случае это все будет один сплошной компонент, разделенный на модули.
Мы можем повторно использовать компонент или заменить его аналогичным компонентом с минимальными усилиями.
Сделать это можно внутри так, как удобно разработчикам, главное, чтобы было понятно, как этим пользоваться.
Вы можете разделить его на слои.
Можно не делить или делить полностью.
Вы можете выделить слой в отдельный компонент. Не обязательно давать слоям конкретные имена, это могут быть просто разные классы или папки.
Не забывайте, что слои верхнего уровня независимы от слоев нижнего уровня.
Если это произойдет, мы используем инверсию зависимостей или делаем адаптер.
Нижний уровень ближе всего к вводу/выводу — это репозитории, сторонние API, шаблоны Twig. Дальше идут контроллеры и наши сервисы с логикой.
Мы сохраняем простоту, усложняя по мере необходимости.
Или делаем сразу что-то сложное, если знаем, что это может понадобиться.
Про SOLID не забываем, но и используем его при необходимости.
Для удобства вы можете оставить общие папки с Entity, Repository, Controller, как это сделано по умолчанию в Symfony, чтобы не прописывать каждый раз пути к ним в конфиге, либо нужно автоматизировать этот процесс.
Конфиги Yaml, шаблоны, переводы также остаются по умолчанию.
Остальной код, код модуля, можно по традиции разместить в папке Service. Вы можете дублировать имена модулей внутри папок.
В будущем при необходимости будет проще подобрать повторно используемый компонент, комплект. Сущности отображают таблицы; с ними можно работать как с простыми структурами DTO. Не путать с концепцией Entity из многоуровневой шестиугольной архитектуры DDD. Это просто данные, минимум логики.
Таким образом мы не привязываем структуру наших классов с логикой к структуре таблиц базы данных, мы можем использовать DI-контейнер, а при необходимости через интерфейсы или DTO можно будет довольно легко отделить логику от конкретной сущность.
Если код сущности сильно разрастается, вы можете разделить его на особенности PHP или установить соединения «один к одному».
Всю логику пишем в сервисах, называем сервис согласно его назначению.
Например, если логика относится к Product, мы помещаем ее в ProductService. Если сервис будет расти, мы сможем раскрутить, например, ProductStoresService. Соответственно, лучше сразу написать логику и учесть, что она может быть разделена.
И лучше, конечно, сразу его правильно разбить, чтобы в дальнейшем тратить меньше времени на рефакторинг.
Если ProductStoresService находится в папке Product, мы можем сократить имя до StoresService. Или можно переименовать его, например, в InventoryControl (складской учет).
Вы можете выбрать его отдельно.
В общем, вариантов много.
Имя ProductStoresService является универсальным; это говорит нам о том, что алгоритм сервиса обрабатывает складские данные применительно к товару.
Также можно создать StoreService, содержащий логику для одного склада, независимого от товара, если таковой имеется, и так далее.
А если склады взаимодействуют не только с товарами, но и с чем-то еще, например, с пользователями, заведующими складами, то может появиться еще один StoresService, в другой папке — UserStores. И UserStores будет зависеть от пользователя и продукта.
Но если мы не хотим, чтобы UserStore зависел от всего Продукта, нам придется отделить Магазин отдельно от Продукта.
Но тогда Товар начнет зависеть от Магазина, и товар вполне может существовать и без склада.
То есть нам не нужно, чтобы Product зависел от Store. А чтобы его убрать, нужно создать отдельный ProductStore, который их соединяет. А товары без склада для нас не имеют смысла; нам больше нечего хранить на складе, кроме товара.
Поэтому мы можем включить Store внутри ProductStore. Итак, у нас осталось: Product, ProductStores, User, UserStores. UserStore зависит от User и ProductStore, а ProductStore зависит от Product. Теперь UserStores зависит от Product не напрямую, а косвенно через ProductStores. Конечно, на практике UserStore без Product нам вряд ли понадобятся, поэтому ProductStore можно включить в Product. И Пользователь может существовать без Магазина.
А если мы включим UserStore в User, то User потянет за собой Product, что довольно странно.
В результате оставляем: Product, User, UserStore. Репозитории можно оставить пустыми и использовать в наших репозиториях, которые мы создадим в модулях, расположенных в Сервисе.
Эти репозитории представляют собой простые сервисы, использующие репозиторий Doctrine. Репозитории необходимы для абстрагирования от репозитория.
Вы также можете создавать конфиги PHP в виде сервисов для каждого модуля и не использовать YAML. Если код небольшой, его можно написать прямо в контроллере.
Но можно и в отдельном сервисе или в нескольких сервисах.
Мы можем назвать их UseCase, варианты использования.
Они, в свою очередь, вызовут другие службы более высокого уровня.
Класс контроллера Symfony содержит довольно много полезных функций и оберток, поэтому вы можете наследовать от него абстрактный вариант использования или создать свой собственный.
Теги: #php #чистая архитектура #symfony #ddd #зависимость от предметной области #шестиугольная архитектура #анемичная модель
-
.Xlsx На Службе Оператора Базы Данных
19 Oct, 24 -
О Дистанционном Обучении...
19 Oct, 24