Обновить
4
0
anotherpit@anotherpit

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

Отправить сообщение
Привет. Нет, детей нет.
Пётр. Тот самый тип удалёнщика-который-путешествует. Мы с женой перешли на удалёнку и последние пять лет меняем города и страны раз в несколько месяцев. Успели объехать часть Европы и Азии. Был тимлидом, а сейчас вернулся в разработчики в Skyeng.

Могу рассказать:

  • О чём не забыть, когда ищешь квартиру на время, и как организовать такой поиск
  • Как переключаться от «-2 к Москве» до «+4 к Москве» каждые 3-4 месяца
  • Мадрид, Севилья, Барселона, София, Варна, Подгорица, Рига, Москва, Питер, Сочи, Муйне, Хошимин, Чиангмай, Самуи для удалёнщика
  • Управление командой на удалёнке: как (и нужно ли) контролировать, как строить синки, face-to-face и другие ежедневные рутины


Обычно отвечаю: с 12 до 18 МСК
Идеально, конечно, когда такого конфликта вообще не возникает, и есть возможность не подводить ни себя, ни окружающих. Win-win. Тогда ни жертвовать, ни психовать не приходится.

Но если всё-таки конфликт есть, и приходится выбирать, то… приходится выбирать. И, получается, прав ads83 — это личный выбор. Возможно, непростой. Возможно, не всегда очевидно, что он вообще существует. Но, похоже, что всё же действительно существует.

Просто очень часто мы делаем этот выбор на автомате по выученному паттерну: сначала помочь ближнему, потом самому себе; сначала рабочие обязанности, потому — личное. Но вообще-то это хоть и проторенная дорожка, но не единственная.

Place the oxygen mask on yourself first…

С одной стороны, как бы да. А с другой, выходит, что вы подводите себя, чтобы не подводить всех вокруг себя, не так ли?
было бы странно выделять http в промисы, потом все равно придется конвертить, для вышеописанных целей например.


Этот аргумент работает в обе стороны. Конвертить придётся только при использовании в одном контексте с Observable. При использовании в контексте с другими промисами — не придётся. Реализация HTTP-запросов не знает и не должна знать, в каком контексте её будут использовать. Она должна экспоузить наружу корректный контракт, точно описывающий её семантику. А семантика такова, что это одноразовое отменяемое асинхронное действие.
Отмену можно реализовать без проблем с помощью своей обертки над xhr или используя AbortController


Когда вы разработчик приложения, можно. Но когда вы разработчик Ангуляра, уже сложнее. Вы встаёте перед необходимостью ввести ещё один интерфейс (CancellablePromise a.k.a. OneTimeObservable), который толком не совместим ни с Promise, ни с Observable.

Конечно, многие операторы умеют работать и с промисами тоже, но удобнее когда все однородно.


У единообразия есть ценность, согласен. Но в случае с RxJS, к сожалению, получается всё однородно монструозно, а не однородно изящно, как хотелось бы. Впрочем, тут уже начинается вкусовщина, и предполагаю, что после этой фразы вы меня тоже занесёте в число тех, кто «пока не умеет работать с RxJS».
Тоже топил за это долгое время, пока не понял вот какой момент.

Принципиальное отличие Promise от Observable, из-за которого Promise действительно должны использоваться для HTTP-запросов, — одноразовость Promise.

Но принципиальное отличие Observable от Promise, из-за которого Observable в реальности используются для HTTP-запросов, — отменяемость Observable.

Поэтому у создателей Angular были не руки кривые, а выбор хреновый: Promise без возможности отмены или Observable без возможности явно объявить одноразовость.
Да, это безусловно попахивает процедурщиной. Данные — в DTO (она же тупая сущность), операции над ними — в этом недосервисе (только что обсуждали этот подход с коллегами, родилось название «агент», чтобы отличать от полноценных сервисов). И всё это не из идеологических соображений, а сугубо ради преодоления ограничений реализации DI в Symfony. Фактически это попытка натянуть rich model на Symfony DI.
Переименование в DTO действительно уменьшит путаницу, а вот переименование обсуждаемых сервисов в сущности, скорее, наоборот. Но терминологию стоит подрихтовать, я согласен.
Ну, злобность service locator лично у меня никаких сомнений не вызывает :—)
Только та, что касается доменной сущности (вызов внутренних методов и внутренних свойств)


Мне вот этот момент кажется очень хрупким. Сегодня метод касается только доменной сущности и лежит в ней, завтра требование к методу усложняется, появляется зависимость, и мы бежим вытаскивать метод из сущности в сервис (или надстраивать в сервисе ещё один метод поверх имеющегося в модели). Какой-то постоянный рефакторинг ввиду меняющихся требований.

Правило про то, что вся бизнес-логика в сервисах, кажется более простым для понимания, реализации и сопровождения.
У меня в голове похожее решение: слой тупых сущностей с геттерами/сеттерами, поверх них слой локализованных сервисов, предназначенных для работы с одной сущностью, поверх них слой более сложных сервисов (интеракторов, юзкейсов, you name it). Сущности в таком подходе — почти тупые DTO. Первый слой сервисов — это такой типа способ подружить сущности, необходимые им сервисы и DI. Второй слой сервисов — классические интеракторы. Ну, и всё это смазать соглашением (которое никак не выйдет контролировать на уровне средств языка) о том, что с сущностью может работать только её сервис из первого слоя.
1) Полноценная сущность надёжно контролирует свои внутренности на своём уровне. Оркестрацией сущностей занимается внешний сервис-юзкейс. В отличие от имения набора сеттеров в сущности, с которыми другой внешний сервис может её испортить, забыв присвоить какое-нибудь поле.

Ну да, лазеек для поломки сущности как будто бы становится сильно меньше. Но всё ещё остаются, если мы не можем передать нужные зависимости в метод. Если же можем, то, кажется, что API сущности становится полным и при этом единственным местом для работы с сущностью. Годится.

Не синглтоны же в методе дёргать.

Смотря что понимать под синглтонами в данном случае. Внешний код, которому придётся передать эту зависимость в метод, всё равно получит её из DI-контейнера, и она фактически будет точно таким же синглтоном (в том смысле, что это один и тот же инстанс на всё приложение). Если внешний код может получить эту зависимость из какого-то общего контекста (DI-контейнера), то почему мы не хотим, чтобы модель могла сама её получить оттуда же?
1) Я в соседней ветке привёл пример, когда это выглядит не очень. Сущность User хочет генерить пароль для пользователя, и ей для этого нужен сервис, генерящий рандомные строки. Использование этого сервиса — это настолько внутренняя деталь реализации, что обязывать код, вызывающий метод генерации пароля, знать об этой детали и инстанциировать нужную зависимость, чтобы передать её в метод, кажется прям совсем грязным решением. Но, честно говоря, это выглядит не как проблема DI в целом, а как проблема конкретных реализаций этого паттерна (в частности, реализации в Symfony). Хотя, с другой стороны, DDD-ребята вроде как идеологически против зависимостей от сервисов в сущностях. Но тогда я не понимаю, как предлагается красиво решать описанную проблему.

2) Ага, это Dependency Inversion из SOLID. Принимается.
Тут вижу две проблемы:

1) Задача инкапсулирования всей логики всё равно стоит. И если вы (или DDD) предлагаете её решать не на уровне сущности, то где? На уровне сервисов? Тогда как защититься от того, что API сущности позволяет разным сервисам по-разному с ней работать? Это очень напоминает исходную ситуацию, когда в сущности только тупые геттеры и сеттеры, и мы защищаемся от бездумного дёргания этих методов лишь тем, что договариваемся, мол, с этой сущностью можно работать только через такой-то и такой-то сервис. То есть, эта защита на уровне договорённостей, а не языка. Понятно проблему сформулировал? Что нам говорит DDD делать в таких ситуациях?

2) Сущность User хочет инкапсулировать в себе генерацию пароля. Ей для этого нужен сервис, который генерит рандомные строчки. О том, что он ей нужен, знает только сама сущность, это деталь её реализации, и внешний код, который использует этот метод, по-хорошему не должен догадываться о том, что сущность использует этот сервис. DI Symfony не даст нам нормально воткнуть в сущность эту зависимость. Да и DDD говорит, что зависимости в сущностях — это атата. Как быть?
А можете подробнее? Непонятно, что именно имеете в виду и как это решает заявленную проблему.
Принимается. Технически это действительно сработает в большом количестве случаев.

Вижу два неприятных момента:

1) Symfony DI тут никак не поможет — зависимости придётся передавать явно. В частности, если у нас есть стек вызовов таких умных методов, и самому глубокому из этих методов понадобилась какая-то зависимость, её придётся пробрасывать через весь стек, не получится просто взять её из контейнера на нужном уровне.

2) Циклические зависимости. Слой сущностей начинает зависеть от слоя сервисов, который, в свою очередь, зависит от слоя сущностей. Это, как минимум, неаккуратно (и идёт в разрез, например, с чистой архитектурой Фаулера, да и DDD тоже).

Есть идеи, как преодолеть эти две неприятности?

Тогда получается, что Order::deliver() всё ещё инкапсулирует не всю необходимую логику, часть её всё ещё лежит в каком-то стороннем сервисе. И другой сервис всё ещё может вызывать напрямую Order::deliver() в обход первого сервиса. Это чуть лучше чем тупые сеттеры/геттеры, но всё ещё недостаточно хорошо. Принципиальная проблема инкапсуляции всей логики на уровне сущностей не решена.
Окей, вы говорите, что сущности — это не тупые DTO и должны экспоузить наружу не просто геттеры и сеттеры, а методы, реализующие бизнес-логику и бизнес-правила. То есть быть умнее. Как быть с зависимостями? Например, представим, что Order::deliver() в вашем примере должен сходить ещё в какой-то сервис, что-то там проверить перед установкой статуса и/или отправить какое-нибудь уведомление после установки статуса. Как это реализовать, учитывая, что DI Symfony не даст вам воткнуть зависимость в сущность?

Информация

В рейтинге
Не участвует
Зарегистрирован
Активность