Сущности (entities) и сервисы (services) как основа распределенной логики для MVC шаблона проектирования

При разработке разных по масштабу приложений становится все более интересно применять различные подходы к проектированию веб приложения. В последнее время особо остро встал вопрос о разделении логики в большом проекте, базирующийся на MVC шаблоне проектирования.

Сущности и сервисы


Сущности


Поскольку задачи стали более сложные и комплексные, а данные в БД хранить все невозможно, то было принято решение о создание сущностей статичных данных в проекте. Суть простая — в определенном месте хранятся базовые статичные данные, которыми можно оперировать в PHP коде, а в БД заносятся их англоязычное представление.

В базовом представлении класс Entity.php может иметь следующий вид:

declare(strict_types = 1);

namespace entities;

class Entity {
	protected static $map;
	
	public static function getMap():array {
		return static::$map;
	}
}

Наследники его должны реализовать свойство $map, которое будут получать следующим образом:

E1::getMap();

Причем, большинство статичных данных будут удовлетворять логике получения. Если требуется группировать данные или выделить дополнительные, то это логика реализуется уже в классах наследниках.

Сервисы


Сервисы предназначены для хранения бизнес логики приложения. Помимо этого, сервисы можно использовать как логика отдельная от фреймворка. Сервис — это набор методов, который реализует логику приложения. Условия, которые были определены сервису:


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

По умолчанию сервис не реализует никакую стандартную логику, поскольку является уникальным исполнением части проекта. Поэтому, было принято решение, что базовый класс сервиса не будет создан. Хотя, стоит отметить, что базовые классы лучше создавать, даже если они будут пустыми. Это объясняется тем, что может наступить такой момент, что всем наследникам надо будет иметь одинаковую логику или выполнять какой-то метод. Чтобы не производить во всех классах изменения в области наследования, проще изначально сделать наследование от базового класса, в котором реализовать данную ситуацию куда менее сложнее и дешевле в области временных ресурсов.

В общем представлении поток данных в предлагаемой архитектуре можно представить следующим образом:

Схема обмена информацией архитектуры MVC с сущностями и сервисами

  1. Данные или запрос поступает в контроллер.
  2. Контроллер общается с моделью, сервисом и сущностью в двунаправленном порядке. Тут он получает и отдает какие-то данные.
  3. Сервис отдает данные в контроллер, получает или отдает данные в модель.
  4. Контроллер отдает полученные данные в представление.

Таким образом, получается, что данные и принцип работы приложения распределен между базовыми элементами MVC и новыми.

Заключение


Стоит отметить, что внедрение такого подхода позволило значительно упростить разработку приложений и контролировать поток данных. Большинство данных были вынесены из базы данных, что позволило сократить ее объем и увеличить общую скорость приложения за счет уменьшения количества запросов.
@mepihin
12.08.2020 01:48 UTC
Первоисточник

Комментарии

@Anton_Zh
12.08.2020 11:05 UTC
0
Поскольку задачи стали более сложные и комплексные, а данные в БД хранить все невозможно

CQRS смотрели? Он как раз это лечит, причем масштабирумо.

Про сущности со статикой: как в map данные будут из базы попадать? Как будет обеспечена актуальность? Это in-memory cache?

Про сервисы: по-моему вы переизобрели сервисный слой, разве нет? в sf что то подобное было принято делать еще со второй версии.
@mepihin
13.08.2020 07:23 UTC
0
CQRS не смотрел, ознакомлюсь.

Как в map данные будут из базы попадать?

Суть Entity в хранении статичных данных, которые разработчик вбивает сам в проекте. То есть, вы сами формируете массив данных.

Как будет обеспечена актуальность?

Тут уже придется написать собственный метод актуализации, так как автоматически обновлять это не получится.
@evgeniymx
12.08.2020 21:33 UTC
+1
Что-то если честно какая-то недосказанность наблюдается в данной статье, как будто это черновик. Вся статья просто проходит на вступление о правильном проектировании системы…
@mepihin
13.08.2020 07:23 UTC
0
Возможно вы правы, но это единственное, что я хотел донести. Узнал, попробовал, понравилось, рассказал. Далее буду развивать темы более обширно.
13.08.2020 08:49 UTC
+1
Вы узнали что-то новое для себя, причем ггубоко не копали. Но далеко не факт что новым оно будет и для остального мира. Не надо сразу бежать рассказывать об этом на хабре. Хотя понимаю, сам таким был)
13.08.2020 12:09 UTC
0
Согласен, но в комментариях можно много нового и дельного узнать)
@VolCh
13.08.2020 05:26 UTC
0
В общем представлении поток данных в предлагаемой архитектуре можно представить следующим образом:

Совсем непонятно. И противоречит тексту, например, "сервис не должен самостоятельно обращаться к контроллерам и представлениям", а стрелка между сервисами и контроллерами двунаправленная. Как-то то ли с терминологией проблема, то ли потоки данных не разделены на параметры и результаты вызовов, то ли ещё что.


Примеры более-менее реального кода помогли бы разобраться, возможно, но их нет. Без них непонятно чем Entity отличается от Model

@mepihin
13.08.2020 07:27 UTC
0
Да, в схеме не очень корректно отобразил. Сервис отдает данные, но не обращается к контроллеру с просьбой что-то сделать. Надо было разделить стрелки на запросы и ответы.

Без них непонятно чем Entity отличается от Model


В моем представлении Model отражает таблицу базы данных и оперирует запросами к ней. В случае таблиц справочников, где данные не могут изменяться пользователями системы, в моем представлении, нет смысла создавать такую таблицу. Следовательно, модель не нужна, а сущность реализует статичное хранение данных на стороне сервера приложения.
13.08.2020 08:26 UTC
0

Явно с терминологией что-то не общепринятое. Сущность, обычно, как раз что-то активно изменяющееся при работе системы. Даже обычными пользователями, не админами сайта.

@EgDude
13.08.2020 07:24 UTC
0
Оттого что модель получает данные не из базы, она не перестает быть моделью.
@mepihin
13.08.2020 07:28 UTC
0
Посмотрите мой ответ выше, я выразил свое виденье модели и сущности. Если не расценивать модель как отражение таблицы базы данных, то вы правы.
@makcumka2000
21.08.2020 09:48 UTC
0

Базовые классы — весьма сомнительный подход. По возможности лучше использовать композицию вместо наследования, да это более трудозатратно за счёт инжекта зависимости, зато более универсально и поддерживаемо, и не подвержено side эффектам.
Если нужен какой-то общий признак на уровне классов, то используйте пустой интерфейс.

@mepihin
24.08.2020 08:01 UTC
0
Можете привести сравнительный пример на базе концептуального примера?