Структура приложения и пространств имён при DDD
Как лучше организовать структуру моего приложения используя DDD и Laravel 4 или 5?
Я обычно разделяю большие приложения на 4-5 пространств имён, которые привязаны к глобальному app пространству имён. Например, я хочу создать приложение ToDo List, так что базовое пространство имён будет ToDo.
Затем у меня есть 3 пространства имён внутри этого:
В дополнение к этому, у меня есть по крайней мере одно пространство имён для взаимодействия с внешним миром. Для типичного веб-приложения это Http, для REST API это Api, для команд artisan это Cli. Итоговая структура приложения может быть примерно такой:
app/
----ToDo/
--------App/
------------Providers/
----------------ToDoServiceProvider.php
----------------ConfigServiceProvider.php
------------Validators/
----------------LaravelValidator.php
------------ValueObject.php
------------BaseModel.php
--------Domain/
------------List/
----------------EloquentList.php
----------------ListRepository.php
----------------ListService.php
----------------ListValidator.php
----------------Priority.php
------------Task/
----------------EloquentTask.php
----------------TaskRepository.php
----------------TaskService.php
----------------TaskValidator.php
--------Http/
------------Lists/
----------------ListController.php
----------------ListPresenter.php
----------------ListViewComposer.php
------------Tasks/
----------------TaskController.php
--------Infrastructure/
------------Lists/
----------------ListRepositoryCacheDecorator.php
----------------EloquentListRepository.php
------------EloquentTaskRepository.php
Это то что я рассматриваю как основную точку взаимодействия между моей бизнес-логикой, логикой инфраструктуры, взаимодействием с внешним миром (web, REST API, CLI), и Laravel. Это то место где я настраиваю все мои зависимости и храню классы которые расширяются потом кодом в домене, и не содержат никакой логики домена в себе. Основное правило здесь — большинство классов будут абстрактными.
[1] Например, у меня может быть Validator, который зависит от массива правильных Task Categories, которые определены в конфигурационном файле. Конструктор принимает массив категорий и я использую сервис-провайдер для для связи:
//ToDo/App/Providers/ConfigServiceProvider.php
public function register()
{
$categories = $this->app['config']->get('todo.categories');
$this->app->bind('ToDo\Domain\Tasks\TaskValidator.php', function($app)
{
$categories = $this->app['config']->get('todo.categories');
$factory = $this->app->make('Illuminate\Validation\Factory');
return new TaskValidator($factory, $categories);
}
[2] Здесь возможно расхождение во мнениях, но я верю что моя логика домена не должна заботиться о том в какой директории файл, до тех пор пока она не получит доступ к этому файлу. Поэтому сервис для определения расположения файлов это слой инфраструктуры или приложения.
Тут просто, это место где живёт вся моя бизнес-лоигка. Сущности, Объекты-значения, Валидаторы, Спецификации, вся фукнциональность которая доставляет результат клиенту находится здесь. В идеале мои сущности должны быть POPO(Plain Old PHP Objects) и не зависеть от Eloquent, но пока это сложно заставить работать хорошо, я имею склонность использовать Eloquent для моих сущностей — это единственное место где я сильно нарушаю принцип разделения ответственности SRP. Но пространство имён ToDo\Domain\List будет содержать следующее:
Все эти вещи должны меняться только тогда когда мне скажет клиент. Любые технические изменения должны уходить в абстрактные классы из которых расширяются классы домена или должны идти в реализации интерфейсов в пространстве имён домена.
Это место где находится вся логика которая связывает моё приложение с внешним миром(например браузером). Всё что отвечает за HTTP запросы должно жить здесь. Это может включать в себя следующее:
Это только один «порт» моего приложения. Если у меня есть Artisan Commands или REST API, то для них будет своё пространство имён с соответствующими классами.
Всё что относится к базовому состоянию находится здесь. Самая очевидная вещь которая должна быть здесь это реализации репозиториев. Например:
Другие вещи которые могут быть здесь: класс ListDatabaseMapper, если используется паттерн Data Mapper вместо Eloquent.