Pull to refresh

Comments 12

UFO just landed and posted this here
Ага, я о вас тоже в статье написал, в пункте про боевые примеры) Вам самим, кстати, нравится эта система, или, если бы можно было все отмотать назад и переделать, вы бы от нее ушли и сделали, например, на хуках?
UFO just landed and posted this here

Понятно, я думал, что тут как в реддите, username checks out)


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

Очень знакомо и проблемы у нас те же. Действительно, нужно очень аккуратно привносить изменения и следить за побочными эффектами, зато можно это сделать куда угодно. Бывают даже кейсы, когда модуль изменяет сам себя несколько раз в зависимости от состава включенных\выключенных модуле, вот тут вообще мозг взрывается.


Правда, проблема с вызовом парента у нас довольно успешно решается конвенцией "всегда вызывай парент".

Статья, содержащая в себе фразы типа "нативное наследование", изначально настраивает на недоверие.


  • Вмешиваться в иерархию типов кажется очень сомнительной идеей. Более того, определение кто кого расширяет противоречит идее использования интерфейсов. как самих по себе так и в составе SOLID.
  • Не являюсь большим знатоком ворпресса, но коль уж система имеет вполне определенное назначение, что упрекать её в ограниченном наборе хуков, наверное, неуместно.
  • минусы использования DI надуманные. Его (DI) в хороших реализация работа заканчивается на этапе компиляции зависимостей. А также под DI стилем имеется в виду что? Конфиги? или код? Если конфиги, то тут объяснение простое — явное указание зависимостей — это хорошая практика. Да, часто разработчики испытывают соблазн использовать магию в виде автовайринга но мы же знаем, что явное лучше неявного. Если код, то как правило нет никакого стиля, это просто обычные конструкторы, сеттеры или публичные методы с определенными сигнатурами. Это обычные пользовательские типы и DI тут просто как потребитель а не "требователь" архитектуры.

Это навскидку.

Статья, содержащая в себе фразы типа "нативное наследование", изначально настраивает на недоверие

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


Вмешиваться в иерархию типов кажется очень сомнительной идеей. Более того, определение кто кого расширяет противоречит идее использования интерфейсов. как самих по себе так и в составе SOLID.

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


Не являюсь большим знатоком ворпресса, но коль уж система имеет вполне определенное назначение, что упрекать её в ограниченном наборе хуков, наверное, неуместно.

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


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


А также под DI стилем имеется в виду что? Конфиги? или код? Если конфиги, то тут объяснение простое — явное указание зависимостей — это хорошая практика.

Конфиги\код — неважно, имеется ввиду использование единого Composition Root и предоставления зависимостей через конструктор или, на худой конец, сеттеры во всех классах системы.


Проблемы начинаются тогда, когда вам необходимо добавить новую зависимость в конструктор класса через модуль или же заменить реализацию сервиса. Особенно, когда одновременно несколько модулей стремятся подменить сервис своей реализацией. Популярные DI-контейнеры данную проблему абсолютно никак не решают, как и упомянул в статье. Так или иначе придется изобретать свою систему, у пресловутой Magento 2, например, также производится компиляция промежуточного класса с учетом всех модулей, которая доступна через DI и заменяет оригинальный сервис.


P.S. В статье идет речь о системах с динамическим набором модулей — плагинов, т.е. исполнение кода и функциональность системы очень сильно зависит от текущей конфигурации. Речь не о конкретном приложении, а о платформе, отсюда и вытекают все проблемы и приходится выдумывать, как скрещивать независимые куски кода правильно.

Да, система далеко не идеальная. Зато с помощью дискуссии мы вместе сможем придумать что-то более хорошее. Вы могли бы поделится примером "как лучше делать"?

UFO just landed and posted this here

С тестами действительно есть проблема, но она скорее вытекает из-за того, что мы в коде X-Cart не получаем зависимости чисто. Если скрестить этот подход с получением зависимостей строго через сеттеры (через конструктор нельзя, т.к. модули могут потребовать лишние зависимости, а в PHP не получится красиво сделать несколько конструкторов) — можно писать обыкновенные тесты.


Проблему с наличием разных наборов модулей мы решаем разными сборками и параметром --group в PHPUnit. Безусловно, покрыть все комбинации не получается, так что работаем с наиболее популярными.

Интересный способ. В Magento 2 используется генерация промежуточного кода для плагинов и использования нагенеренного вместо оригинала в собственном IoC-контейнере. Но если использовать оригинал напрямую (через new), а не через DI, то будет задействован оригинальный код. Мне кажется, что это достаточно удачный компромисс. Я во главу угла ставлю удобство отладки, особенно, когда имеешь дело с незнакомым кодом (а незнакомым становится даже собственный код, спустя какое-то время). Поэтому мне бы хотелось как можно меньше иметь подобного нагенеренного кода в приложении. Но так как подобный подход (плагины в Magento 2 или описанные Forwarding decorators) дает очень хорошую гибкость при независимой модульной разработке сложных систем, то, похоже, что так или иначе он будет использоваться.


Существующие в Magento 2 плагины позволяют оборачивать (before/after/around) любой публичный метод любого класса, создаваемого в IoC-контейнере, и выстраивать конвейеры из подобных «оберток» на основании зависимостей между модулями, в которых эти «обертки» объявлены. При удалении модуля соответствующая обертка выбывает из конвейера, при добавлении модуля — встраивается в соотв. место конвейра. Мне кажется это более удачный подход, чем выстраивание цепочек наследования (особенно, если зависимости между модулями не линейные, а древовидные), т.к. «обертки» полностью независимы друг от друга с точки зрения наследования. Если бы я обдумывал архитектуру приложения, я бы шел по этому пути (оборачивание отдельных методов и использование через DI, а не forwarding decorators).


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

да, по сути в magento 2 это обычные middleware, подход мне нравится, хоть и довольно тяжелый в дебаге, например многими любимый guzzle использует такой подход без кодогенерации
Sign up to leave a comment.

Articles