Pull to refresh
0
4.4
Send message

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

  • приводите в пример частный случай, когда легковесные конструкторы мало снижают время построения полного дерева зависимостей, как это отменяет что строится полное дерево зависимстей, никак. Вместо этого вы идёте путём отрицания самой постановки задачи - "Как не промочить ноги? Не ходите по лужам". Это гениальный совет.

  • ServiceProvider выступает как фабрика, инкапсулируя логику создания экземпляров сервисов с учетом их lifetime (Transient, Scoped, Singleton) и зависимостей. Это соответствует определению Factory Method из GoF: "Определите интерфейс для создания объекта, но позвольте подклассам решать, какой класс инстанцировать". Больше я это обсуждать не буду.

  • Я не просил объяснять термины, я просил объяснить как вы эти термины используете в контексте использования Lazy<T>. Как они связаны, где техдолг и т.д.? Не уходите от ответа, не подменяйте тему обсуждения.

  • Ну и последнее - как же не перейти на личности, когда не смог ответить ни на один вопрос? :)

В начале статьи вы привели список проблем, которые решаете. Я же предложил способ исправить корень проблем, а не бороться с последствиями.

Сами придумали, что одна из многих проблем теперь стала корнем всех проблем? Или кто-то подсказал? Mark Seemann так считает?

Чтобы управлять созданием зависимости для получения экземпляра по требованию или нескольких экземпляров лучше использовать фабрики или их простую форму - Func<T>.

DI контейнер это не фабрика? А что? Про Func<T> дал пример почему их неудобно использовать.

Использование Lazy<T> у вас это костыль, которым вы добавляете технический долг. Вы получите проблемы с управлением временем жизни и утилизацией.

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

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

Ваши рассуждения к описаной проблеме имеют слабое отношение.
Lazy не даёт строится дереву зависимостей на всю глубину, будет построен только 1-й уровень. Насколько у вас "легковесные" конструкторы - тут никакой роли не играет.

Из моей практики - если какие-то зависимости нужны "не всегда", то компонент "многовато на себя берёт" и лучше его разбить на более атомарные куски

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

Ок, имеем:

  1. Lazy - это инфраструктурный способ разрешения зависимости, а не бизнес-логика. Его глобальная регистрация делает контейнер более предсказуемым и ортогональным, чем набор частных избыточных регистраций для каждого типа, за которыми ещё нужно дополнительно следить.

  2. Ортогональность - возможность использовать Lazy независимо от регистрации других типов.

У меня получилось:

Lazy - это инфраструктурный способ разрешения зависимости, а не бизнес-логика. Его глобальная регистрация делает контейнер более предсказуемым и даёт возможность использовать Lazy независимо от регистрации других типов, чем набор частных избыточных регистраций для каждого типа, за которыми ещё нужно дополнительно следить.

Потом я долго думал.... Видимо вы хотели сказать, что:

Lazy - это инфраструктурный способ разрешения зависимости, а не бизнес-логика.

С учётом lifetime тут может быть влияние и на бизнес логику.

Если зарегистрировать в контейнере Lazy<>, то не нужно регистриовать Lazy для каждого типа T и это лучше так как меньше кода и следить за каждой регистрацией Lazy для T не нужно.

С этим я не спорил, это же очевидно, но непонятно, какие преимущества кроме "меньше кода" это даёт. Свои возражения о "скрытой регистрации Lazy для каждого типа T" я уже написал ранее. Мы с вами в этом вопросе никуда не продвинулись.

Если я неправильно понял, поправьте.

Идём далее...

Имеем:

  1. Разница между подходами не в прозрачности, а в точке ответственности.
    Точечные регистрации размазывают знание о Lazy по регистрации сервисов,
    open generic концентрирует его в одном месте, ровно как это сделано для ILogger или IOptions.

  2. Точка ответственности - единое место, где описано поведение контейнера. Либо знание о Lazy размазано по регистрациям, либо оно централизовано и не влияет на читаемость бизнес-регистраций.

У меня получилось:

Разница между подходами не в прозрачности, а в едином месте, где описано поведение контейнера. Либо знание о Lazy размазано по регистрациям, либо оно централизовано и не влияет на читаемость бизнес-регистраций.

Плохо понимаю, так как в моём примере все регистрации типов в контейнере для модуля делаются в одном специальном классе `ModuleBootstrapper`, предельно концентрированно в одном месте, в других местах регистрации не делаются. Это и есть пример централизации регистраций без их сокрытия - все регистрации прописаны явно в ModuleBootstrapper, вы же концентрацию одобряете или нет, я запутался.

Точечные регистрации размазывают знание о Lazy по регистрации сервисов, open generic концентрирует его в одном месте, ровно как это сделано для ILogger или IOptions.

Каким образом размазывают? Все регистрации прописаны явно, если регистрация не прописана тут ModuleBootstrapper, значит её нет - предельно простое правило.
Напротив, open generic Lazy<> скрывают регистрацию Lazy для каждого типа T. Это ли не размазывание логики регистрации типов?

Идём далее...

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

Поведение контейнера зависит только от реализации его методов, неважно как он был зарегистрирован. А вот логика работы связки Lazy + T может зависеть от lifetime, я это сразу указал в статье. Отсюда мой посыл - важно обеспечить гибкость против унификации.
Дублирование кода отсутствует в ModuleBootstrapper, там столько же строк кода сколько классов T.

Я как мог контр-аргументировал, но мне думается, что всё упирается во вкусы и предпочтения.

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

На реальных проектах предложенный подход не создавал никаких проблем.

Ссылка на некий реальный проект неумесна, так как не добавляет деталей ни к одному из подходов.

Более того, Microsoft в своей официальной документации дают ссылки на другие IoC-контейнеры, прямо сообщая, что если вам нужны поддержка Func, прокси и прочие плюшки, выбирайте. Нет замечаний по поводу "скрытой логики" или какой-то магии.

Снова ссылка на авторитет документации Microsoft, который не добавляет деталей ни к одному из обсуждаемых способов.

И при чём тут "авторитет Microsoft"? Озвученные примеры регистрации открытых типов используются не просто широко, а максимально широко.

Действительно, причём тут авторитет, когда ОХ КАК ШИРОКО, АЖ МАКСИМАЛЬНО ШИРОКО это используется. Ссылка на "это очень широко используется" (или "все так делают") - это логическая ошибка argumentum ad populum, популярность не доказывает правильность или эффективность подхода.

А возможность регистраций открытых generic типов поддерживаются из коробки.

Поддерживается, не спорю, но это не означает, что теперь это стало единственно правильным подходом.

Не очень понимаю, почему использование этой фичи вдруг объявлена злом и разочаровывают.

Аргументацию я привел - скрытая регистрация типов это плохо, это маскирует зависимости, делая код менее читаемым и отлаживаемым, DI-контейнер становится "чёрным ящиком" - без явных registrations сложно понять граф зависимостей.

Резюмирую - мой единственный аргумент, остался для меня не менее значимым, чем до начала дискуссии.

Вы меня не обидели, я правда не понимаю, что вы иммели ввиду в терминах "ортогональный контейнер" и "точка ответственности".

Из за этого у меня нет чёткой картины, вашей аргументации, непонятно на что вы опираетесь, кроме схожих примеров с ILogger<> и ссылки на авторитет документации Microsoft.

Дело не во вкусах, а в Хабре и здешней публике (отдельные индивиидумы).
Я бы мог попытатся разобратся в вашей аргументации, начал бы с вопроса, что такое "ортогональный контейнер" или хотя бы "точка ответственности".

Lazy<T> - это инфраструктурный способ разрешения зависимости, а не бизнес-логика. Его глобальная регистрация делает контейнер более предсказуемым и ортогональным...
Разница между подходами не в прозрачности, а в точке ответственности.

Но мне тут минусов понаставят, особо пробдвинутые и задвинутые неведомо в какие науки мыслители и борцы за чистоту Хабра. Так что оставим ненужные споры, я себе уже всё доказал.

Не готов погружатся в тему критики open generic, но критика присутствует.

Что вижу я в предложенном подходе - самое главное, скрытая логика регистрации.


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

Хакерские штучки типа - добавить в проект общее поведение для всех типов, меня не впечатляют, а наоборот разочаровывают.

Как это используется?

Значит ServiceProvider резолвит зависимость из контейнера прежде чем вставить в Lazy :)

Щас статью поправлю :)

Спасибо за тестирование.

Это собеседование?

Я думаю, зависит от того как реализовано свойство IsValueCreated и каким образом ServiceProvider инжектит оборачиваемый объект в Lazy. Угадал?

Какой приз мне полагается?

Очень интересная статья.

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

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

Что касается использования ИИ - тут только локальные или доверенные провайдеры, так как получив достаточно вопросов, ИИ может понять чем вы там занимаетесь.

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

Всего вам доброго.

Чтобы утвержать, что на раскопках нет людей потому что их нет - нужно поднять документацию по строительству, к которой вас не подпустят, и убедится, что по документации не идёт работа в 3 смены с применением дорогой арендованной техники :)

Академик - настоящий патриот.

Кстати, а что он для науки сделал, завещал мыть руки перед едой?

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

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

Тут мы бессильны, как говорится это вне нашего круга влияния, это в нашем круге забот.

1
23 ...

Information

Rating
890-th
Registered
Activity