Разделить проект Symfony 2?
У нас есть довольно большое веб-приложение Symfony 2, которое имеет множество различных конечных точек и функций:
- API для данных из нашего старого продукта
- веб-компоненты для использования в нашем устаревшем продукте
- API для нашей новой iOS POS
- API для портала лояльности конечных пользователей
- веб-интерфейс для портала лояльности конечных пользователей
- веб-интерфейс для (отдельного) счета конечного пользователя
- большая админка с настройкой для всего вышеперечисленного
Уровень базы данных (в Doctrine) тесно связан. Транзакции из POS и нашего унаследованного продукта используются на порталах лояльности конечных пользователей, а счета-фактуры основаны на одних и тех же транзакциях. Очевидно, что есть также много сущностей, которые предназначены исключительно для определенных частей приложения.
Изначально мы выбрали единый подход "приложение + пакет" для простоты программирования, который хорошо послужил нам при разработке всей платформы. К сожалению, основными недостатками являются:
- очень низкая производительность (хотя такие вещи, как дальнейшее кэширование, минимизация ресурсов и т. д., могут помочь, мы считаем, что наличие такого раздутого пакета, который должен уметь обрабатывать все, а также включать сторонние библиотеки, используемые только в определенных частях приложения, замедляется все вниз.)
- мы используем непрерывную интеграцию и генерируем новые сборки, а выполнение всех функциональных тестов занимает более 20 минут... и у нас еще много классов, в которых отсутствуют (правильные) тесты.
- когда мы меняем часть приложения, другая часть легко ломается. Хотя в этом помогает все больше и больше разъединяющих и функциональных тестов, это все еще далеко от идеала.
Я провел некоторые исследования, чтобы разделить проект Symfony на несколько проектов (каждый со своим GitHub) и использовать SOA для их соединения. Мой личный опыт, связанный с SOA, заключается в том, что это затрудняет полное тестирование и добавляет много накладных расходов при переходе со стандартных форм Symfony 2 (что мне очень нравится).
Я также думал о другом решении, создавая общий пакет с общими сущностями и репозиториями. Это значительно упростит тестирование кода и совместное использование общих служб (менеджеров), хотя я также слышал аргументацию против крупных менеджеров. Большим недостатком этого является то, что мы не можем просто использовать doctrine: schema: update затем, потому что совместное использование базы данных и обновление базы данных в проекте с более низкой версией общего пакета удалит поля.. что приведет к потере данных. Также при таком подходе я не смог найти никаких примеров или вариантов использования... что заставляет меня задуматься, не будет ли у него еще много минусов.
Итак, мой вопрос: каковы общие подходы и решения для разделения такого большого проекта? И еще: есть ли причины, по которым, возможно, его вообще не следует разделять?
2 ответа
Хотя я отвечаю на ваш вопрос, довольно сложно найти волшебное решение для ваших проблем. Это не попытка решить все ваши проблемы и не навязать вам их следование. Это не единственно возможное решение, на самом деле это может даже не решить ваши проблемы. Тем не менее, давайте начнем.
Я бы разделил проект на 4 слоя:
- Уровень представления: приложения рабочего стола, веб-интерфейсы (независимо от того, является ли это php, C#, если он использует Symphony или любые другие компоненты инфраструктуры и третьих библиотек), мобильные приложения - все, что конечные пользователи могут видеть и взаимодействовать (также известный как GUI). Эти ребята только общаются с Приложением / Сервисом, чтобы запросить что-то, например, список доступных продуктов, где-то обновить данные, отправить электронное письмо для клиентов. Ключевым моментом здесь является то, что они действительно не знают, как и где уровень приложений / сервиса будет выполнять запрошенные действия.
- Уровень приложений / сервисов: я бы рассматривал это как контроллеры, которые могут получать запросы как от уровня презентаций, так и от внешних веб-сервисов. Они выглядят как API-интерфейсы и решают, должны ли они получать доступ к данным или манипулировать ими через репозиторий, или отправлять электронные письма, используя какую-либо службу SMPT. Они просто устанавливают связь между GUI или внешними веб-сервисами, которые могут использовать ваши API и уровни Domain/Infra. Тем не менее, они на самом деле не знают, какую службу SMPT они используют, или где и как будут храниться данные (в MySql через Doctrine, в Sql Server через Entity Framework, в базе данных NoSql, в txt-файлах). Слои приложений обычно имеют свои собственные Модели (также известные как ViewModels), которые доступны миру и возвращаются запрашивающей стороне (GUI или внешнему веб-сервису), представляя часть моделей домена. Такое сопоставление (преобразование классов домена в классы приложения) можно выполнить с помощью таких шаблонов, как Facade и Adapters (также называемые антикоррупционным уровнем), и существует множество пакетов для решения этой проблемы (для C# существует Automapper, для PHP может быть существует что-то тоже). Зачем вам это нужно? Чтобы не показывать весь свой домен миру. Предположим, у вас есть конечные пользователи Invoice и Loyalty, но вы хотите относиться к ним как к одному уникальному классу домена "Пользователь" с соответствующими им свойствами. Вы можете создать классы LoyaltyUser и InvoiceUser в своем приложении, каждый из которых содержит только необходимые свойства для этой цели, а затем использовать эту технику сопоставления, чтобы сопоставить класс пользователя домена каждому из них. Следовательно, прикладной уровень обычно содержит правила аутентификации и авторизации, поэтому только конечный пользователь Loyalty будет иметь разрешение на доступ к действиям контроллера, которые будут работать с моделью LoyaltyUser. Внутри одного действия в контроллере вы не должны выбирать разные пути / пути в зависимости от запрашивающей стороны (для мобильных устройств, сделайте это, для веб-сайта, сделайте это). Вместо этого у вас могут быть разные действия для каждого из них, и на уровне презентации будет известно, что они хотят запросить.
- Уровень домена: это ваше ядро, содержащее всю бизнес-логику. Это то, что обеспечивает ценность для вашего бизнеса. Контейнерные модели / классы доменного уровня, представляющие реальные сущности из вашего мира, интерфейсы для сервисов и репозитории. Домен должен быть максимально чистым и естественным. Они не могут знать, что приложение запрашивает что-то, и как тип инфра используется. Они просто делают бизнес-логику. Слой домена не знает, используете ли вы Doctrine или Laravel в качестве ORM, а также, является ли приложение php-сайтом, созданным с помощью Symphony, или Android Native App.
- Инфра уровень: здесь вы реализуете такие вещи, как база данных, SMPT-сервис, ведение журнала и другие вещи, которые могут понадобиться вашему приложению. Доктрина будет жить здесь. Следовательно, вы должны создать классы репозитория, реализующие интерфейсы репозитория вашего домена. Реализация репозитория использует Doctrine для работы. Эти реализации предоставляются прикладному уровню (обычно через внедрение зависимостей). Это означает, что прикладной уровень не должен знать, является ли Doctrine или Laravel, поэтому приложение использует репозиторий (поэтому логика для доступа к базе данных инкапсулирована).
Ваш веб-интерфейс будет находиться в презентации. Если фреймворк, который вы используете в своей сети, должен использовать MVC и, следовательно, иметь контроллеры, эти контроллеры должны отправляться на прикладной уровень (я знаю, это звучит избыточно). Ваши API будут находиться на уровне приложений.
Это очень разделено: если вам нужно перейти с Doctrine на Laravel, вам не нужно менять ни домен, ни приложения. Если вам нужно перейти с Symphony на что-либо другое или даже изменить свой веб-сайт с PHP на ASP или Java, ваш домен не нужно менять.
Добавление большего количества слоев, сопоставление объектов, использование DI не должны замедлять запросы, учитывая цену и емкость оборудования в настоящее время, разница во времени практически незаметна. Вы должны приложить усилия, пытаясь улучшить свой домен, который приносит ценность для бизнеса. Разделение слоев улучшает разделение, повышает вероятность изменения части приложения, нарушая другие части, повышает гибкость масштабирования приложения и упрощает тестирование.
Рейн, каково было решение, которое ты наконец-то нашел? Вы на самом деле разделили свой проект?
В этой области действительно не хватает информации, я только что нашел одну разумную статью https://ig.nore.me/presentations/2015/04/splitting-a-symfony-project-into-separate-tiers/