Pull to refresh
12
0
Владимир Калинкин @cylon-v

Пользователь

Send message
Согласен, об этом ответил чуть выше. В целом проблема тут не в том, что вы используете монады и не в том, как они реализованы, а в том, как это непривлекательно выглядит на C#. Не хочу никого задеть этим, просто непредвзятый взгляд со стороны.
Хорошо, что это не бизнес-логика.
Чтение же подобного «бизнесового» кода не вызывает никакого удовольствия.

Посмотрите, сколько мусора натащил сишарп

Возможно сказывается мой длительный разрыв с C#, но мне кажется, что с конструкциями типа
public extension IdMonad of Id : Monad<Id>
{
    static IdMonad<A> Pure<A>(A a) => new Id<A>(a); // просто создаем обертку
    static IdMonad<B> Bind<A, B>(IdMonad<A> ta, Func<A, IdMonad<B>> mapInner)  =>
        mapInner(ta.Value);
}

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

В целом согласен, поэтому и являюсь приверженцем Persistence Ignorance. Только, как мне кажется, после детального моделирования решение уже всё-таки пора принять. Здесь я не противоречу дяде Бобу.

Главное в плане непринятых решений до абсурда не доводить. Наш брат не особо любит говорящие бестолковые головы, которые всячески стараются снять с себя любую ответственность :).
Большое спасибо за развёрнутый и обстоятельный комментарий!
1. Я намеренно не углублялся в паттерны и старался избегать упоминания терминов и известных личностей, дабы не разжечь нездоровую дискуссию о том, что чем является, а чем не является, особенно рассуждая на стыке разных языков и сред. Это я имел в виду в заключении. Изначально Action и назывался Command (в терминах CQRS). Но после «унификации» с репозиториями он был переименован. Что касается выгоды репозиториев как возможности замены RDBMS, я ни разу этого не делал на практике, поскольку это был бы сильный просчёт на этапе проектирования ошибиться с RDBMS и, простите, глупость. Даже если пришлось бы, то в чём принципиальная разница с апгрейдом Action вместо репозиториев?

2.
Кстати, не обязательно в конструктор, можно и через сеттеры

это «взлом» понятия инверсии зависимостей (для чего мы используем injection). Это было бы не трудно реализовать, но принципиально нет. Вот мой пост о том, как я разрабатывал Hypo, где я указал причины.

3. Да, пардон, DI — везде Dependency Injection.
В целом идея такова, что каждый здесь может увидеть свои интерпретации, кто-то «функции», кто-то «команды». Dandy — это всего лишь роутер, пусть и лихой :), он не налагает особых ограничений на использование. Хотите Domain Events, репозитории, пожалуйста, Actions будут лишь обёртками. А уж использовать его или нет, решать разработчику.
С чем дискутирую я: автор в статье заявил, что «Но контроллер вообще не должен быть классом» — с чем я согласен. Но затем последовал пример с контроллером-классом. Что меня удивило.

Попытаюсь перефразировать, если этот момент настолько принципиален. Controller не должен быть классом, если это всего лишь набор малосвязанных методов. Да, можно было бы его сделать модулем с тем же набором методов. Но, поскольку это ничего не даёт с практической точки зрения кроме демагогии, я предложил замену понятию Controller — Action (не путайте). По задумке автора Action должен быть классом ввиду необходимости корректного использования DI (в комментарии выше есть обоснование, зачем это нужно). Это с точки зрения ООП.
Теперь с точки зрения «ФП». Я не знаю на каком языке вы пишете в стиле ФП, но вот, надеюсь, что для вас не является секретом, что функции в JavaScript это тоже объекты? О том, что каждая функция является «объектом», надеюсь, не нужно рассказывать? И не вызовут удивления вещи типа:

new Function(<functionArgs...>, functionBody)
Function.prototype.constructor
Function.prototype.call

?
Ничего не напоминает? :)
Почему тогда в примере не сделать контроллер модулем?

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

//let repository, mail_service, request_params;
// ...
const context = {repository, mail_service, request_params};
// ...
function listInvoices({repository}) {
  repository.getAll();
}


Но это приводит к дополнительной рутине — по пути до этого вызова нужно собрать необходимый контекст руками. Dandy решает эту проблему использованием Dependency Injection с IoC, который может работать с временными объектами: в конструкторе будет всё, что вам нужно.

Зачем ему стейт?

Так или иначе всё имеет состояние. Функция в JS также имеет своё внутреннее состояние, как предложенный Action.

Information

Rating
Does not participate
Location
Санкт-Петербург, Санкт-Петербург и область, Россия
Registered
Activity