Зачем использовать внешний интерфейс?

Обсуждаем, как правильно строить приложения
Ответить
sda
Сообщения: 331
Зарегистрирован: 2013.12.19, 09:29

Зачем использовать внешний интерфейс?

Сообщение sda » 2017.09.12, 19:22

Здесь человек пишет, что
Проблема в том как бы мы не хотели не использовать Yii::$app, мы не можем это сделать. (без костылей) У половины стандартных компонентах нет интерфейсов что бы прокинуть в класс.
Почему человек считает, что завязать код на внешний (чужой) интерфейс это лучше, чем использовать Yii::$app ? Какую проблему это решит? Код в обоих случаях будет зависеть от фреймворка. Никакой разницы.
Можно создать свой интерфейс, но это костыль, и мы на него наткнемся если завтра нам нужно взять сторонний кеш.
Почему человек считает, что внешний интерфейс фреймворка ему чем-то поможет если завтра ему нужно будет взять сторонний кеш? Сторонний кеш точно также будет нарушать внешний интерфейс фреймворка, как и его собственный. Никакой разницы.
Можно создать свой интерфейс, но это костыль
Я всегда думал, что это называется адаптер, а оказывается костыль. Всегда думал, что вместо привязки к внешним интерфейсам нужно использовать адаптер, так как
Плюсы:
инкапсуляция реализации внешних классов (компонентов, библиотек), система становится независимой от интерфейса внешних классов; (с) Википедия
Я бы проигнорировал это, если бы ему не отвечал samdark в стиле "да, интерфейс нужен". Зачем пользователю фреймворка внешний интерфейс? Этим интерфейсом мы только привяжем наш Application layer к фреймворку/компоненту/библиотеке. Окей, теперь мы можем не использовать Yii:::$app. Ура. Но проблема фреймворкозависимости решена? Нет.

Где я не прав?

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Зачем использовать внешний интерфейс?

Сообщение zelenin » 2017.09.12, 20:13

sda писал(а):
2017.09.12, 19:22
Почему человек считает, что завязать код на внешний (чужой) интерфейс это лучше, чем использовать Yii::$app ? Какую проблему это решит? Код в обоих случаях будет зависеть от фреймворка. Никакой разницы.
во втором случае он будет зависеть от реализации интерфейса, которая может быть реализована без участия yii.
sda писал(а):
2017.09.12, 19:22
Почему человек считает, что внешний интерфейс фреймворка ему чем-то поможет если завтра ему нужно будет взять сторонний кеш? Сторонний кеш точно также будет нарушать внешний интерфейс фреймворка, как и его собственный. Никакой разницы.
он имеет в виду, что yii2-3rdparty-cache будет реализовывать интерфейс yii, а его не будет.
sda писал(а):
2017.09.12, 19:22
Я всегда думал, что это называется адаптер, а оказывается костыль.
он имел в виду костыль, потмоу что правильнее создать интерфейс.

sda писал(а):
2017.09.12, 19:22
Всегда думал, что вместо привязки к внешним интерфейсам нужно использовать адаптер, так как
Плюсы:
инкапсуляция реализации внешних классов (компонентов, библиотек), система становится независимой от интерфейса внешних классов; (с) Википедия
Я бы проигнорировал это, если бы ему не отвечал samdark в стиле "да, интерфейс нужен". Зачем пользователю фреймворка внешний интерфейс? Этим интерфейсом мы только привяжем наш Application layer к фреймворку/компоненту/библиотеке. Окей, теперь мы можем не использовать Yii:::$app. Ура. Но проблема фреймворкозависимости решена? Нет.

Где я не прав?
он не решает проблему фреймворкозависимости. он решает проблему реализациезависимости.

sda
Сообщения: 331
Зарегистрирован: 2013.12.19, 09:29

Re: Зачем использовать внешний интерфейс?

Сообщение sda » 2017.09.12, 20:29

zelenin, свой интерфейс решает проблему как фреймворкозависимости, так и реализациезависимости. Зачем использовать внешний интерфейс?

Аватара пользователя
ElisDN
Сообщения: 5002
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Зачем использовать внешний интерфейс?

Сообщение ElisDN » 2017.09.12, 20:54

sda писал(а):
2017.09.12, 19:22
Проблема в том как бы мы не хотели не использовать Yii::$app, мы не можем это сделать. (без костылей) У половины стандартных компонентов нет интерфейсов что бы прокинуть в класс.
Почему человек считает, что завязать код на внешний (чужой) интерфейс это лучше, чем использовать Yii::$app ? Какую проблему это решит? Код в обоих случаях будет зависеть от фреймворка. Никакой разницы.
Здесь не написано про "внешний (чужой)". Здесь хотя бы про какой-нибудь свой.

Например, у мейлера интерфейс есть. К нему можно легко привязать компонент из ServiceLocator:

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

$container->setSingleton(\yii\mail\MailerInterface::class, function () {
    return Yii::$app->mailer;
})
чтобы принимать в свои сервисы:

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

__construct(MailerInterface $mailer)
и всё работает по рефлексии.

А вот для базы, сессии или логгера это уже не сработает:

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

__construct(\yii\db\Connection $db, \yii\web\Session $session, \yii\log\Logger $logger)
так как эти конструкции зациклятся:

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

$container->setSingleton(\yii\db\Connection::class, function () {
    return Yii::$app->db; // через Yii::createObject вызывает Yii::$container->get('yii\db\Connection', ['dsn' => '...'])
});
$container->setSingleton(\yii\web\Session::class, function () {
    return Yii::$app->session; // аналогично вызывает Yii::createObject(['class' => 'yii\web\Session']
});
Поэтому приходится вместо имён классов костылять с псевдонимами:

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

$container->setSingleton('db', function () {
    return Yii::$app->db;
});
$container->setSingleton('logger', function () {
    return Yii::getLogger();
});
и теперь в каждый сервис прокидывать всё вручную по псевдонимам:

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

$container->setSingleton(\app\my\FirstService::class, [], [
    Instance::of('db'),
    Instance::of('session'),
]);
$container->setSingleton(\app\my\SecondService::class, [], [
    Instance::of('logger'),
]);
Либо сразу после установки приложения переносить все компоненты из 'components' в секцию 'container.singletons'.
sda писал(а):
2017.09.12, 19:22
Почему человек считает, что внешний интерфейс фреймворка ему чем-то поможет если завтра ему нужно будет взять сторонний кеш? Сторонний кеш точно также будет нарушать внешний интерфейс фреймворка, как и его собственный. Никакой разницы.
Можно взять PSR-6 или PSR-16 для кеша. И никаких проблем совместимости со сторонними кешами не будет.
sda писал(а):
2017.09.12, 19:22
Я бы проигнорировал это, если бы ему не отвечал samdark в стиле "да, интерфейс нужен". Зачем пользователю фреймворка внешний интерфейс? Этим интерфейсом мы только привяжем наш Application layer к фреймворку/компоненту/библиотеке. Окей, теперь мы можем не использовать Yii:::$app. Ура.
С внутренним интерфейсом будет хотя бы удобно не использовать Yii::$app. Без костылей с прокидыванием встроенных компонентов вроде db, session, user и logger в контейнер.
Последний раз редактировалось ElisDN 2017.09.22, 10:14, всего редактировалось 1 раз.

zelenin
Сообщения: 10596
Зарегистрирован: 2013.04.20, 11:30

Re: Зачем использовать внешний интерфейс?

Сообщение zelenin » 2017.09.12, 21:21

sda писал(а):
2017.09.12, 20:29
zelenin, свой интерфейс решает проблему как фреймворкозависимости, так и реализациезависимости. Зачем использовать внешний интерфейс?
выше написал - автор не решает проблему фреймворкозависимости.

Аватара пользователя
ElisDN
Сообщения: 5002
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Зачем использовать внешний интерфейс?

Сообщение ElisDN » 2017.09.12, 21:55

sda писал(а):
2017.09.12, 20:29
Зачем использовать внешний интерфейс?
Интерфейсы нужны не только для фреймворконезависимости, но и для декорирования:

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

$container->setSingleton(\yii\base\UrlManager::class, function () use ($app) {
    return new LanguageUrlManager(new UrlManager(), $app->params['languages']);
})
, адаптирования, проксирования и прочих проявлений полиморфизма для гибкой кастомизации фреймворка.

sda
Сообщения: 331
Зарегистрирован: 2013.12.19, 09:29

Re: Зачем использовать внешний интерфейс?

Сообщение sda » 2017.09.12, 22:32

ElisDN ваши сервисы зависят от интерфейсов внешних компонентов/библиотек ? Что делать если надо заменить текущую библиотеку на библиотеку с другим интерфейсом ? Придется исправлять код сервисов или писать адаптер на чужой интерфейс. Зачем это делать если можно написать адаптер сразу и под свой интерфейс какой нужен в вашем приложении ?
Интерфейсы нужны не только для фреймворконезависимости, но и для ... адаптирования
Верно. Напишите свой интерфейс + реализующий его адаптер и используйте внутри адаптера хоть yii-шный кеш хоть какой другой. Зачем вам надо чтобы в самом yii сделали интерфейс ? Вы у каждой библиотеки будете просить интерфейс ? :mrgreen:
Можно взять PSR-6 для простого кеша или PSR-16 для продвинутого. И никаких проблем совместимости со сторонними кешами не будет.
Кеш пример. PHP не мир. PSR не стандарт.

Аватара пользователя
ElisDN
Сообщения: 5002
Зарегистрирован: 2012.10.07, 10:24
Контактная информация:

Re: Зачем использовать внешний интерфейс?

Сообщение ElisDN » 2017.09.13, 01:42

sda писал(а):
2017.09.12, 22:32
ElisDN ваши сервисы зависят от интерфейсов внешних компонентов/библиотек ? Что делать если надо заменить текущую библиотеку на библиотеку с другим интерфейсом ? Придется исправлять код сервисов или писать адаптер на чужой интерфейс. Зачем это делать если можно написать адаптер сразу и под свой интерфейс какой нужен в вашем приложении ?
Сервисы не зависят. А репозитории и эти самые адаптеры в инфраструктуре как раз зависят напрямую от фреймворковских Connection, Logger и внешних библиотек.

Из статьи Вы процитировали:
У половины стандартных компонентов нет интерфейсов что бы прокинуть в класс.
Речь именно о сложностях прокидывания в конструкторы встроенных компонентов фреймворка. Что надо костыльно извратиться, чтобы компоненты из ServiceLocator прокинуть назад в Container. Хотя это лишь эстетическое неудобство, вызванное одновременным присутствием этих двух вещей вместо одного.
sda писал(а):
2017.09.12, 22:32
Верно. Напишите свой интерфейс + реализующий его адаптер и используйте внутри адаптера хоть yii-шный кеш хоть какой другой.
Я написал свой адаптер и получил геморрой с DIC, когда понадобилось прокинуть в него Connection. Проблема решилась переносом всех компонентов в контейнер. Речь опять об этом.
sda писал(а):
2017.09.12, 22:32
Зачем вам надо чтобы в самом yii сделали интерфейс ?
Библиотеку можно легко выкинуть или поменять, сменив адаптер под свой интерфейс. Фреймворк с ней никак не связан и проблем с этим нет. Другое дело - компоненты, встроенные в сам фреймворк.

Мне здесь постоянно говорят, что Yii - гибкий фреймворк, не навязывающий никакую архитектуру, который я могу легко кастомизировать и расширять под свои нужды. Что я просто не умею его "готовить".

И вот я, вдохновившись этим и бросив себе вызов, захотел задекорировать UrlManager гибким и расширяемым путём без наследования:

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

return new LanguageUrlManager(
    new CityUrlManager(
        new CacheUrlManager(
            new UrlManager($app->params['urlManager']),
            $container->get(Cache::class)
        ),
        $container->get(CityRepository::class)
    ),
    $app->params['languages']
)
и выложить каждый декоратор на GitHub. А здесь такой "облом", что UrlManagerInterface нет и вместо чистого implements UrlManagerInterface мне придётся в каждом классе делать extends UrlManager с кучей ненужных мне public-полей... И вдохновение прошло.

И так любое чистое декорирование/проксирование/адаптирование внутренностей для доработки или подмены пролетает с адским свистом костылей. Ну не захотели разработчики упростить кастомизацию для опытных программистов, побоявшись распугать "непонятными интерфейсами" всех новичков, у которых один только IdentityInterface вызывает дикий ужас.
sda писал(а):
2017.09.12, 22:32
Верно. Напишите свой интерфейс + реализующий его адаптер и используйте внутри адаптера хоть yii-шный кеш хоть какой другой. Зачем вам надо чтобы в самом yii сделали интерфейс ? Вы у каждой библиотеки будете просить интерфейс ? :mrgreen:
Свои внешние адаптеры я напишу. Речь про внутреннее хардкорное отсутствие интерфейсов у встроенных компонентов фреймворка.
sda писал(а):
2017.09.12, 22:32
Кеш пример.
Как уже видим, у фреймворка захардкожено куча кода. Без разделения по ответственностям на внутренние сервисы, адаптеры, резолверы и прочее. В итоге подменяется всё либо через наследование, либо целиком файлами с копипастой через $classMap.
sda писал(а):
2017.09.12, 22:32
PHP не мир. PSR не стандарт.
Это только в Yii-мире PHP - не мир, а PSR - не стандарт.

Nex-Otaku
Сообщения: 809
Зарегистрирован: 2016.07.09, 21:07

Re: Зачем использовать внешний интерфейс?

Сообщение Nex-Otaku » 2017.09.17, 13:31

В итоге подменяется всё либо через наследование, либо целиком файлами с копипастой через $classMap.
Жиза. В моих проектах уже появилась папочка "overrides" с подобными костылями, которая причиняет боль моему внутреннему перфекционисту. Надеюсь, в следующих релизах фреймворка ситуация будет улучшаться.

eleven11
Сообщения: 1
Зарегистрирован: 2017.09.22, 06:37

Re: Зачем использовать внешний интерфейс?

Сообщение eleven11 » 2017.09.22, 06:43

ElisDN писал(а):
2017.09.12, 20:54
Можно взять PSR-6 для простого кеша или PSR-16 для продвинутого. И никаких проблем совместимости со сторонними кешами не будет.
Только наоборот, PSR-6 для продвинутого, верно?

Аватара пользователя
samdark
Администратор
Сообщения: 8800
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Зачем использовать внешний интерфейс?

Сообщение samdark » 2017.09.22, 14:28

Nex-Otaku, ждём пулл-реквестов ;)

eleven11, да.

Ответить