DI в DDD проектах

Обсуждаем, как правильно строить приложения
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

DI в DDD проектах

Сообщение glagola »

Всем привет, хотел бы затронуть тему Di контейнеров для проектов реализованных по DDD.

Дело в том что, в моем текущем проекте (я думаю, что такая проблема во всех проектах) все сервисы/валидаторы/репозитории и т.д. инжектятся друг в друга и все они не обладают состоянием (или если и обладают, то являются singleton'ами).

Вопрос:
  • Как часто в вашей практике встречалась необходимость инжектить класс, который нельзя было бы назвать signleton'ом? (нужно уточнить, что вопрос относится к средам, которые умирают после обработки каждого запроса)
  • Может стоит "инвертировать" логику работы \Yii::$container, чтобы по-умолчанию все сервисы были signleton'ами?
P.S. Все эти вопросы возникли, из-за того что сейчас у меня много разных доменных сервисов, которых с каждым днем все больше и больше, и постоянно боюсь забыть их задекларировать как signleton'ы. Я понимаю, что это скорее элемент оптимизации и можно было бы сделать это когда проект будет более менее готов, но не легче было бы сделать это из коробки?
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

Если в сервисе есть какое-либо вспомогательное состояние (подключение к БД или кеш в приватном поле), то сразу объявляю синглтоном, чтобы не открывалось нескольких подключений. Потом объявляю синглтонами репозитории, так как они могут дёргаться несколько раз на странице (в контроллере и в виджетах). Ну и напоследок объявляю гидраторы и прочие вещи, которые могут быть нужны нескольким репозиториям.

А так да, большинство контейнеров всё делают синглтонами по умолчанию. Контейнер Yii от них отличается, так как "родился" из философии использования Yii::createObject(...) для создания абсолютно всех объектов, а не только сервисов.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.18, 14:44P.S. Все эти вопросы возникли, из-за того что сейчас у меня много разных доменных сервисов, которых с каждым днем все больше и больше, и постоянно боюсь забыть их задекларировать как signleton'ы. Я понимаю, что это скорее элемент оптимизации и можно было бы сделать это когда проект будет более менее готов, но не легче было бы сделать это из коробки?
создай внутримодульный реестр сервисов, который регистрируется в yii оберткой, которая автоматически делает синглтон. Что-то типа сервис провайдеров https://github.com/container-interop/service-provider
Аватара пользователя
samdark
Администратор
Сообщения: 9489
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: DI в DDD проектах

Сообщение samdark »

Как часто в вашей практике встречалась необходимость инжектить класс, который нельзя было бы назвать signleton'ом? (нужно уточнить, что вопрос относится к средам, которые умирают после обработки каждого запроса)
Довольно часто, но не через контейнер.
Может стоит "инвертировать" логику работы \Yii::$container, чтобы по-умолчанию все сервисы были signleton'ами?
Возможно. Но в 2.0 сделать нельзя — обратная совместимость. Закиньте в issue tracker.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.18, 16:50создай внутримодульный реестр сервисов, который регистрируется в yii оберткой, которая автоматически делает синглтон. Что-то типа сервис провайдеров https://github.com/container-interop/service-provider
Предложенный подход "облегчит" страдания, но не вылечит болезнь. Основная проблема - "не забыть", а не "лень писать".
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.18, 23:44
zelenin писал(а): 2017.04.18, 16:50создай внутримодульный реестр сервисов, который регистрируется в yii оберткой, которая автоматически делает синглтон. Что-то типа сервис провайдеров https://github.com/container-interop/service-provider
Предложенный подход "облегчит" страдания, но не вылечит болезнь. Основная проблема - "не забыть", а не "лень писать".
ну так именно "не забыть" оно и решает. есть реестр и есть обертка, написанная один раз.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

samdark писал(а): 2017.04.18, 20:07 Возможно. Но в 2.0 сделать нельзя — обратная совместимость. Закиньте в issue tracker.
https://github.com/yiisoft/yii2/issues/14006 В английском не силен, но надеюсь что суть удалось передать :D
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.18, 23:46 ну так именно "не забыть" оно и решает. есть реестр и есть обертка, написанная один раз.
Реестр кто будет заполнять? или вы предлагаете написать скрипт, который будет искать классы без состояния и добавлять их в реестр автоматически?
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.18, 23:59
zelenin писал(а): 2017.04.18, 23:46 ну так именно "не забыть" оно и решает. есть реестр и есть обертка, написанная один раз.
Реестр кто будет заполнять? или вы предлагаете написать скрипт, который будет искать классы без состояния и добавлять их в реестр автоматически?
проблема же не забыть сделать синглтоном? или я не правильно вас понял?
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.19, 00:01 проблема же не забыть сделать синглтоном? или я не правильно вас понял?
Проблема - классов без состояния и классов, подподающих под роль синглтона, много и они постоянно меняются. Я постоянно забываю пометить их как

Код: Выделить всё

\Yii::$container->setSingleton(...)
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.19, 00:05
zelenin писал(а): 2017.04.19, 00:01 проблема же не забыть сделать синглтоном? или я не правильно вас понял?
Проблема - классов без состояния и классов, подподающих под роль синглтона, много и они постоянно меняются. Я постоянно забываю пометить их как

Код: Выделить всё

\Yii::$container->setSingleton(...)
ну так вы пробрасываете же их в контейнер как-то? пробрасывайте на основе сервис-провайдера модуля, в котором будут конфигурационные массивы или фабрики, взависимости от того, как вы регите эти зависимости.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.19, 00:12 ну так вы пробрасываете же их в контейнер как-то?
Нет, это зависимости, которые резолвятся в процессе конструирования объекта контейнером (на github'e тоже возникло недопонимание), например:

Код: Выделить всё

class Foo {
    public function __construct()
    {
        // Foo will be created twice
        echo "Foo", PHP_EOL;
    }
    
}

class Bar {
    public function __construct(Foo $foo)
    {
    
    }
}

class Hoo {
    public function __construct(Foo $foo, Bar $bar)
    {
    
    }
}

// To solve this issue I have to declare Foo as singleton
// \Yii::$container->setSingleton(Foo::class);

\Yii::$container->get(Hoo::class);
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

то есть когда вы вызываете \Yii::$container->get(Hoo::class);, он автоматически резолвится БЕЗ ДОБАВЛЕНИЯ HOO в контейнер? В таком случае логично, что это не синглтон.

то есть если вы явно прописали резолв класса в контейнер, то это должен быть синглтон. Если происходит резолв класса, которого нет в контейнере, то это не должен быть синглтон.
И если проблема в том, что вы резолв зависимостей не хотите прописывать в контейнер, то вообще вся эта ситуация странная именно в контексте di и связанного с ним контрактного программирования (мы прописывем HooInterface, а не Hoo, соответственно разрезолвить это без явного указания не можем).
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.19, 13:35 то есть когда вы вызываете \Yii::$container->get(Hoo::class);, он автоматически резолвится БЕЗ ДОБАВЛЕНИЯ HOO в контейнер? В таком случае логично, что это не синглтон.

то есть если вы явно прописали резолв класса в контейнер, то это должен быть синглтон. Если происходит резолв класса, которого нет в контейнере, то это не должен быть синглтон.
И если проблема в том, что вы резолв зависимостей не хотите прописывать в контейнер, то вообще вся эта ситуация странная именно в контексте di и связанного с ним контрактного программирования (мы прописывем HooInterface, а не Hoo, соответственно разрезолвить это без явного указания не можем).
Нет)) меня напрягает, что Foo (а не Hoo) нужно прописывать как singleton, в противном случае Foo будет создан 2 раза.
Последний раз редактировалось glagola 2017.04.19, 13:57, всего редактировалось 1 раз.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.19, 13:54
zelenin писал(а): 2017.04.19, 13:35 то есть когда вы вызываете \Yii::$container->get(Hoo::class);, он автоматически резолвится БЕЗ ДОБАВЛЕНИЯ HOO в контейнер? В таком случае логично, что это не синглтон.

то есть если вы явно прописали резолв класса в контейнер, то это должен быть синглтон. Если происходит резолв класса, которого нет в контейнере, то это не должен быть синглтон.
И если проблема в том, что вы резолв зависимостей не хотите прописывать в контейнер, то вообще вся эта ситуация странная именно в контексте di и связанного с ним контрактного программирования (мы прописывем HooInterface, а не Hoo, соответственно разрезолвить это без явного указания не можем).
Нет)) меня напрягает, что Foo нужно прописывать как singleton, в противном случае Foo будет создан 2 раза.
хорошо. Foo не прописан в контейнере? замените в моем комменте Hoo на Foo - смысле тот же.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.19, 13:35 Если происходит резолв класса, которого нет в контейнере, то это не должен быть синглтон.
Я хочу противоположенного:
Если происходит резолв класса, которого нет в контейнере, то это должен быть синглтон.

Итак, вот о чем я: Если класс не был задекларирован как создаваемый по требованию в контейнере, то считать его синглтоном (как при резолве зависимостей, так и при \Yii::$container->get(...))
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

ок, я против. Это очередной кусок не явно работающей магии. DI это о внедрении зависимостей, а не service locator. Если хочется синглтона, пропиши сервис. Не хочется - не прописывай и получай разные инстансы, что ожидаемо.
glagola
Сообщения: 47
Зарегистрирован: 2017.02.22, 19:43

Re: DI в DDD проектах

Сообщение glagola »

zelenin писал(а): 2017.04.19, 14:19 Если хочется синглтона, пропиши сервис. Не хочется - не прописывай и получай разные инстансы, что ожидаемо.
Так, вот я и задавал этот вопрос выше: как часто вы сталкивались c ситуацией, что injected dependency должна создаваться с 0 каждый раз (учитывая, что среда в которой обрабатывается запрос умирает после обработки запроса)?

Мне кажется, что идея пересоздания зависимостей (без явного определения их как singleton) может быть актуальна для сред, которые НЕ умирают после обработки запроса.

Мне кажется, что именно поэтому предложенный подход вам кажется неочевидной магией.
zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: DI в DDD проектах

Сообщение zelenin »

glagola писал(а): 2017.04.19, 14:32
zelenin писал(а): 2017.04.19, 14:19 Если хочется синглтона, пропиши сервис. Не хочется - не прописывай и получай разные инстансы, что ожидаемо.
Так, вот я и задавал этот вопрос выше: как часто вы сталкивались c ситуацией, что injected dependency должна создаваться с 0 каждый раз (учитывая, что среда в которой обрабатывается запрос умирает после обработки запроса)?
никогда не сталкивался, т.к. у меня все зависимости всегда прописаны в конфигурации DI-контейнера, но если бы я не прописал и зависимость резолвилась "из воздуха", то я бы ожидал, что каждый раз будет новый инстанс.

ElisDn, а вообще сторонние DIC позволяют резолвить зависимости, которые в них явно не прописаны? это как-то противоречит самому названию dependency injection container.
glagola писал(а): 2017.04.19, 14:32 Мне кажется, что идея пересоздания зависимостей (без явного определения их как singleton) может быть актуальна для сред, которые НЕ умирают после обработки запроса.
не вижу связи. Когда мне не нужны разные инстансы, я делаю один и им пользуюсь (сервисы без хранения состояния либо с хранением глобального состояния в рамках реквеста). Когда нужны инстансы с локальным состоянием, я делаю разные инстансы (в рамках локального контекста).
glagola писал(а): 2017.04.19, 14:32Мне кажется, что именно поэтому предложенный подход вам кажется неочевидной магией.
потому что контейнер должен содержать (contain) зависимости (dependency) и резолвить их, а не создавать из воздуха.
Аватара пользователя
ElisDN
Сообщения: 5845
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: DI в DDD проектах

Сообщение ElisDN »

zelenin писал(а): 2017.04.19, 14:46 ElisDn, а вообще сторонние DIC позволяют резолвить зависимости, которые в них явно не прописаны? это как-то противоречит самому названию dependency injection container.
В Yii, PHP-DI и Laravel такой autowiring включен по умолчанию.

В Symfony можно включить опцией autowire у любого сервиса или глобально, и контейнер тоже начнёт рекурсивно парсить конструкторы и создавать всё в лоб через new, если не найдёт определений для нужного класса. Даже добавили новый синтаксис для конфигурирования именно классов без использования псевдонимов для такого автоподхвата.
Последний раз редактировалось ElisDN 2017.04.19, 15:22, всего редактировалось 2 раза.
Ответить