Хелперы

ivanov77

Новичок
Приветствую.
Есть обычный хэлпер, просто как набор статических методов. Ну например как такие в yii2 и уже что касается не инфраструктуры, а функционала самого приложения, типа:
Код:
class CommonHelper
{
    //////////////////////////////
    ////////// Urls
    //////////////////////////////
    public static function getUrlToPageById($pid, $params = [], $scheme = false)
    {
        if ($arr = Yii::$app->urlManager->getPageInfoByPid($pid)) {
            $params = array_merge($params, ['lang' => $arr['lang'], 'cross' => 'front']);
            return self::urlTo('/' . $arr['source'], $params, $scheme);
        }
        return null;
    }
    //...

    //////////////////////////////
    ////////// Files
    //////////////////////////////
    public static function getImageInfoFromMiniPath($miniPath, $imageTypes)
    {
        $res = [];
        $miniPath = str_replace('../', '', $miniPath);
        $miniPath = ltrim($miniPath, '/');
        $parts = explode('/', $miniPath);
        if (count($parts) < 2) {
            return null;
        }
        $name = array_pop($parts);
        $res['filename'] = $name;
        $x2 = explode('.', $name);
        $res['fileext'] = array_pop($x2);
        // Pattern will be like this: '/.+\.((jpg)|(jpeg)|(png)|(bmp)|(gif))$/'
        $pattern = '/.+\.((' . implode(')|(', $imageTypes) . '))$/';
        if (!preg_match($pattern, $name)) {
            return null;
        }
        $res['miniformat'] = array_pop($parts);
        $parts[] = $name;
        $res['imagepath'] = implode('/', $parts);
        return $res;
    }

    //////////////////////////////
    ////////// Tokens
    //////////////////////////////

    //...
}
Насколько я понял спецы по ООП очень сильно недолюбливают такие хэлперы по причине:
- жесткой завязанности на нем (В yii вон им пришлось по 2 класса делать, чтобы подменить через костыли в случае чего)
- по мере роста кол-ва методов эти хэлперы надо дробить, и когда не совсем точно понятно куда новый метод добавлять, добавляют наугад, а потом естественно не могут найти.

Какой в этом плане кошерный подход?, для вот этих всех служебных, вспомогательных вещей, что никак не уместилось в объекты предметной области, вещи которые могут понадобиться много где, и в UI и в Сервисах приложения(use case-ах).

Так пойдет?:
- Назвать такие классы Сервисами
- Создавать такие классы без состояния, с набором нестатических методов, сгруппированных по смыслу.
- Вопросы расширения функционала этих классов решать посредством https://refactoring.guru/ru/introduce-local-extension . Это заодно согласуется и с OCP.
- инжектить их через DI уже там где нужны.
- Не создавать интерфейсы для каждого из них, а инжектить как класс. Завязки жесткой не будет. Всегда можно будет подменить на наследника или сдекорированный, фреймворки такое позволяют.
 

jonjonson

Охренеть
Статичный метод не использующий статичный параметров - это простая функция.
 

fixxxer

К.О.
Партнер клуба
что никак не уместилось в объекты предметной области, вещи которые могут понадобиться много где, и в UI и в Сервисах приложения(use case-ах).
Не существует таких вещей, которые нужны одновременно и в Domain, и в UI.

Если такое есть, значит вся архитектура приложения никуда не годится и четкое разделение на слои вообще отсутствует.

Впрочем, для yii, в котором инфраструктура перемешана с доменом, это типичная ситуация :)
 

fixxxer

К.О.
Партнер клуба
Ну тогда для тех вещей которые нужны одновременно много где на одном слое.
Хелперы - это просто функции, объединенные статиками в класс. Если бы в php была возможность делать autoload для функций, не было бы ни одной причины делать хелперы.

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

Ответа на вопрос "как мне сделать архтектуру всего", разумеется, не существует.

Могу разве что посоветовать прочитать про Hexagonal Architecture, оно же Ports-and-Adapters.
 

ivanov77

Новичок
Могу разве что посоветовать прочитать про Hexagonal Architecture, оно же Ports-and-Adapters.
Читал.
Но мне больше понравилась Clean Architecture дяди Боба. Там главное чтобы зависимости указывали внутрь.
Т.е. если сервис существует на уровне домена, то к нему могу обращаться и с его же уровня и с внешних, например UI, т.е. как выше я и говорил
 

fixxxer

К.О.
Партнер клуба
Да, только domain service - это такой специальный случай, когда логика принадлежит домену, но при этом ее нельзя отнести к какой-то одной конкретной сущности.

А вовсе не место, куда можно пихать все, что попало.

Вот то, что ты привел в самом первом примере - это что попало. Такие методы не имеют права на существование.
 

Adelf

Administrator
Команда форума
Да, только domain service - это такой специальный случай, когда логика принадлежит домену, но при этом ее нельзя отнести к какой-то одной конкретной сущности.
Кстати, а можешь привести пример такого?
 

Вурдалак

Продвинутый новичок
Кстати, а можешь привести пример такого?
На моей практике, это сервисы, которые нужны для read-запросов.
Может ли @Adelf просматривать профиль @admin, если последний его скрыл?
В принципе, описанный кейс может быть решен generic domain'ом (ну, всякие готовые ACL), но ничего не мешает оформить это в явном виде в вашем проекте в виде domain services.
Обычно они оформлены в виде stateless-сервисов, когда на вход подаются нужные value objects, описывающие строго те данные, которые нужны для данного контекста.

Если же нужна какая-то логика при изменении, то она идет в сущности и тут domain services нафиг не нужны.

Но если для UI мне нужна похожая логика, я ее могу просто продублировать. Это будет лишь проекцией бизнес-логики на UI. Этой красивой фразой можно заткнуть рот тем, что что-то там говорит про DRY, не понимая что это.
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Мне как раз интересно было для write варианта. Поскольку я не могу придумать хороший пример сам...
 

Вурдалак

Продвинутый новичок
Мне как раз интересно было для write варианта. Поскольку я не могу придумать хороший пример сам...
А для чего? Если для какой-то презентации, то так и скажи, что хороших примеров не обнаружено.
Domain services для меня — это сигнал, что скорее всего что-то не так.
Обычно, какая-то логика извне для write-model находится вне её bounded context.
Если у тебя появится пример domain service для write — приведи, а я постараюсь сказать в чём ты не прав :)
 

Adelf

Administrator
Команда форума
У меня то как раз нет. По моему, всегда можно сделать правильный агрегат. Но фиксер о чем-то таком говорит :) вот мне и интересно стало.
 
Сверху