Прошел по ссылке на оригинальную статью. Насколько я понял в "вопросах-ответах" Матиас считает, что этот подход хорош в самых простых объектах, которые и тестировать-то нет неообходимости. Ну что ж, каждое решение имеет свою область применения.
Меня интересовало, что будет инжектиться в класс, завязанный на класс Time, если его конструктор недоступен:
class DependedClass {
public function __construct(Time $time) {
// ...
}
}
Т.е., данный подход предполагает в таких случаях создавать фабрики, которые будут создавать объекты с использованием их собственных статических фабричных методов, и уже эти фабрики инжектить в зависящие от объектов классы (или, как в случае с Symfony, указывать в настройках DI, что для создания экземпляров Time нужно использовать "factory: [TimeFactory, create]"):
class TimeFactory {
public function create() {
$result = Time::fromValues(0, 0);
return $result;
}
}
class DependedClass {
public function __construct(TimeFactory $factory) {
// ...
}
}
Вполне возможно, в этом есть какой-то сакральный смысл, но я бы все-таки конструктор не прятал. Ну или очень сильно ограничил бы применение "именованных конструкторов" — все-таки статика к тестам совсем не friendly. Вообщем, мне эти "именованные конструкторы" как-то не совсем по душе. Но смотрятся красиво, не отрицаю.
Массивна уж очень. Гибкость достигается за счет сложности. Плюс высокий порог вхождения, неочевидность некоторых решений, размазывание функционала между уровнями (например, формирование в PHP-скриптах JS-кода для фронта). Все это и приводит к тому, что решение нельзя назвать "изящным". Гибким, мощным — можно. Изящным — я бы поостерегся. Хотя вторая версия, на мой взгляд, более "прямая" (а может я уже привык думать "Magento style"). Это я как разработчик говорю, а не как конечный пользователь.
Не плохое. "Все есть яд, и все есть лекарство. Зависит от дозы." (с) Парацельс
Просто у angular'а своя ниша, и ее границы достаточно хорошо видны. Инвестировать свое время в разработку прототипа на angular'е, если твое web-приложение строится на чем-то другом — не самое оптимальное решение, IMHO.
Замечательная статья! Как "Матрица" или "Шестое чувство"! Интригует, зовет узнать, как получить все эти увлекательные плюшки и незадорого, а ближе к концу раз — и angular. Ощущение, как доской по голове дали. Зато сразу отрезвление наступило и морок пропал. Да, "серебряной пули" не существует, каждое решение имеет свои границы применимости, angular ничуть не хуже ember/knockout/backbone/smartclient, а твои проекты — это те проекты, в которых прототипирование такой ценой не нужно. Нет, разумеется, есть такие по настоящему крупные проекты, в которых построение прототипа на angular'е дает все эти бонусы и плавно перетекает в production (особенно, если production тоже на angular'е), но вот для твоих задач (разработка модулей для Magento) и бумаги хватит (или Enterprise Architect'а, если нужно красиво). В любом случае, написано здорово, а то, что цена высока — так никто не говорил, что это для всех.
public function __construct(
\Psr\Log\LoggerInterface $logger,
\Zend_Db_Adapter_Pdo_Abstract $dba,
ISomeService $service,
...
) {...}
и ваш пример:
public function __construct(MyServiceInterface $service, LoggerInterface $logger) {
$this->service = $service;
$this->logger = $logger;
} {...}
и, честно сказать, не нахожу особой разницы. С точки зрения темы, освещаемой в статье, ее нет вообще.
Я хотел для примера воткнуть хоть какие-то более-менее правдоподобные зависимости в конструктор, чтобы не писать "ISomeService1", ..., "ISomeService4", а получилось, что я нарушил "принцип единственной ответственности". В результате дискуссия ушла в сторону правомерности использования логирования для трассировки выполнения бизнес-операций.
Спасибо, что осветили свою точку зрения на этот вопрос (про логирование) — мне, по крайне мере, было очень интересно.
Чем интерфейс "логгер-декоратора" отличается от PSR3?
interface LoggerInterface
{
public function emergency($message, array $context = array());
public function alert($message, array $context = array());
public function critical($message, array $context = array());
public function error($message, array $context = array());
public function warning($message, array $context = array());
public function notice($message, array $context = array());
public function info($message, array $context = array());
public function debug($message, array $context = array());
public function log($level, $message, array $context = array());
}
Можете привести для примера 2-3 публичных метода "логгер-декоратора"?
но на сколько я понял из ваших слов, вы пытались выбрать между двумя фреймворками для выбора между двумя пакетами
из моих слов:
У Magento 1 гораздо большее кол-во расширений.
Здесь "расширение" не равно "пакет". В одном случае в конечной системе требуется поддержка helpdesk'а, в другом — мультисклад. Вот у Magento 1 гораздо больше таких вот расширений, чем у второй версии. Никто не знает, будут ли эти расширения портированы на М2 через полгода. Если будут — завернемся на вторую версию, если нет — на первую.
Как же тогда автор предлагает писать бизнес-логику, если заранее не известно будет в вашем фреймворке использоваться DI или не будет
Я создавал у себя в приложении обертку, если фреймворк предоставляет DI — использую его, нет — использую Zend'овский. Ну а классы с бизнес-логикой вообще не интересует, кто и как в них заинжектил нужные зависимости.
Меня, если честно, ваши вопросы ставят в тупик. Эти функции, как и запись в БД, и ротация лог-файлов, и изменение формата вывода сообщений без изменения кода приложения, на уровне конфигурационных файлов давным-давно не являются экзотикой в фреймворках логирования.
В Java этого добра поболее — java.util.logging, log4j, slfj4, в PHP я использовал только log4php и собственно Monolog (PSR3 имплементацию). Я не вижу смысла проектировать логгеры — они уже есть. Остается их только использовать там, где нужно. А в сложных системах, да еще и в случае "гибкой архитектуры", их нужно использовать чуть менее, чем везде (слегка утрирую, но для сервисов, реализующих бизнес-логику — везде).
Если вы же и поддерживаете те приложения, архитектором которых вы являетесь, у вас не может быть другого мнения на этот счет.
Для начала я бы использовал готовый PSR3-фреймворк — Monolog. Затем, убедившись, что он не конфигурируется через внешние файлы, я бы обернул его в monolog-cascade. После чего я имел бы возможность через конфигурационный файл влиять на все логи приложения с возможностью их вывода в "никуда"/файл/базу/syslog/email/… С использованием процессора IntrospectionProcessor (подключаемого через конфиг, когда мне нужно) я имел бы возможность расширять сообщения до такого формата: [YYYY-MM-DD HH:MM:SS] main.DEBUG: MESSAGE_HERE. {"file":"/.../Main_Test.php","line":75,"class":"...\\Main_IntegrationTest","function":"test_main"}
Чего мне уже бы хватило для нахождения в лог-файле (я в основном использую их, но можно и в БД лить) сообщения с конкретной строки конкретного метода конкретного класса (вне зависимости от его уровня логирования).
Если же мне и этого мало, а мне нужно по конкретному сообщению создавать, например, таск support'у в JIRA, то я могу написать свой handler/processor/formatter и подключить его через конфиг-файл без изменения кода сервиса:
public function __construct(
\Psr\Log\LoggerInterface $logger,
...
) {
$this->_logger = $logger;
...
}
public function operation($request) {
$this->_logger->info("Operation is called.");
...
}
Если нужна еще большая гибкость, то да — это решение не подходит, и нужно применять что-то другое. Возможно даже EventDispatcher.
Если предполагается, что в сервисе могут возникнуть различные варианты обработки лог-сообщений (помимо стандартного уровня — debug, info, ...), то нужно маркировать подобные сообщения на этапе девелопмента (см. второй параметр $context в LoggerInterface). После чего на уровне конфигурирования можно перенаправлять ваши сообщения куда хотите.
Если вы сначала написали код, а потом решили, что он должен работать по-другому, то да — код нужно будет менять.
Т.е., данный подход предполагает в таких случаях создавать фабрики, которые будут создавать объекты с использованием их собственных статических фабричных методов, и уже эти фабрики инжектить в зависящие от объектов классы (или, как в случае с Symfony, указывать в настройках DI, что для создания экземпляров Time нужно использовать "factory: [TimeFactory, create]"):
Вполне возможно, в этом есть какой-то сакральный смысл, но я бы все-таки конструктор не прятал. Ну или очень сильно ограничил бы применение "именованных конструкторов" — все-таки статика к тестам совсем не friendly. Вообщем, мне эти "именованные конструкторы" как-то не совсем по душе. Но смотрятся красиво, не отрицаю.
Просто у angular'а своя ниша, и ее границы достаточно хорошо видны. Инвестировать свое время в разработку прототипа на angular'е, если твое web-приложение строится на чем-то другом — не самое оптимальное решение, IMHO.
и ваш пример:
и, честно сказать, не нахожу особой разницы. С точки зрения темы, освещаемой в статье, ее нет вообще.
Я хотел для примера воткнуть хоть какие-то более-менее правдоподобные зависимости в конструктор, чтобы не писать "ISomeService1", ..., "ISomeService4", а получилось, что я нарушил "принцип единственной ответственности". В результате дискуссия ушла в сторону правомерности использования логирования для трассировки выполнения бизнес-операций.
Спасибо, что осветили свою точку зрения на этот вопрос (про логирование) — мне, по крайне мере, было очень интересно.
Можете привести для примера 2-3 публичных метода "логгер-декоратора"?
из моих слов:
Здесь "расширение" не равно "пакет". В одном случае в конечной системе требуется поддержка helpdesk'а, в другом — мультисклад. Вот у Magento 1 гораздо больше таких вот расширений, чем у второй версии. Никто не знает, будут ли эти расширения портированы на М2 через полгода. Если будут — завернемся на вторую версию, если нет — на первую.
к этому.
Я создавал у себя в приложении обертку, если фреймворк предоставляет DI — использую его, нет — использую Zend'овский. Ну а классы с бизнес-логикой вообще не интересует, кто и как в них заинжектил нужные зависимости.
Да.
Меня, если честно, ваши вопросы ставят в тупик. Эти функции, как и запись в БД, и ротация лог-файлов, и изменение формата вывода сообщений без изменения кода приложения, на уровне конфигурационных файлов давным-давно не являются экзотикой в фреймворках логирования.
В Java этого добра поболее — java.util.logging, log4j, slfj4, в PHP я использовал только log4php и собственно Monolog (PSR3 имплементацию). Я не вижу смысла проектировать логгеры — они уже есть. Остается их только использовать там, где нужно. А в сложных системах, да еще и в случае "гибкой архитектуры", их нужно использовать чуть менее, чем везде (слегка утрирую, но для сервисов, реализующих бизнес-логику — везде).
Если вы же и поддерживаете те приложения, архитектором которых вы являетесь, у вас не может быть другого мнения на этот счет.
[YYYY-MM-DD HH:MM:SS] main.DEBUG: MESSAGE_HERE. {"file":"/.../Main_Test.php","line":75,"class":"...\\Main_IntegrationTest","function":"test_main"}Чего мне уже бы хватило для нахождения в лог-файле (я в основном использую их, но можно и в БД лить) сообщения с конкретной строки конкретного метода конкретного класса (вне зависимости от его уровня логирования).
Если же мне и этого мало, а мне нужно по конкретному сообщению создавать, например, таск support'у в JIRA, то я могу написать свой handler/processor/formatter и подключить его через конфиг-файл без изменения кода сервиса:
Если нужна еще большая гибкость, то да — это решение не подходит, и нужно применять что-то другое. Возможно даже EventDispatcher.
Т.е., в более гибком варианте поведения мне нужно будет изменить код слушателя, я правильно понял?
Если вы сначала написали код, а потом решили, что он должен работать по-другому, то да — код нужно будет менять.