Здравствуйте, Министр Промышленности, Вы писали:
МП>если инициализация будет объемистой, то вынести в инициализирующий статический helper метод и везде использовать его
А если для создания Dependency1 нужно передать param1 и param2 (скажем, строку подключения и таймаут), а для создания Dependency2 — param3 и param4 (например, имя пользователя и путь к S3), т.е. если Dependency1 и Dependency2 нужно дополнительно конфигурировать?
Как твой helper создаст Dependency1 и Dependency2 в этом случае?
Здравствуйте, varenikAA, Вы писали:
AA>>>Понял, а то у ТС вообще неопнятно на что он жалуется. ну это субъективно. так то во всех учебниках учат что надо избегать явного создания объектов. IT>>Они не учат почему этого нужно избегать? Если нет, то ввыкинь такие учебники на помоечку. Впрочем, если да, то тоже выкинь.
AA>Чтобы не зависеть от реализации.
Зачем? Какую проблему это решает?
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Sharov, Вы писали:
S>>>Передали, и? Чем поведение без DI будет отличаться от поведения с DI в данном случае? IT>>Выше в теме об этом говорилось уже несколько раз. S>Я специально сделал акцент на слове поведение, а не на поиск и устранение причины.
Извини, видимо предполагал в твоём вопросе какую-то смысловую нагрузку, относящуюся к теме.
Если нам не помогут, то мы тоже никого не пощадим.
Здравствуйте, Sharov, Вы писали:
S> M>>Просто кейс что при использовании DI в конструктор передали null невозможен в принципе, тут нужен другой пример. S> IT>Пусть передали не null, а поломаный объект. S> Передали, и? Чем поведение без DI будет отличаться от поведения с DI в данном случае?
Я не очень понял твой вопрос, но попробую потелепатить. Различие в том, что в случае с обычным кодом, можно найти откуда конкретно передали просто проанализировав код, find usages. В случае DI-фреймворка ты можешь лишь понять, что пришло из контейнера и всё, и без дебаггера очень сложно разобраться.
Здравствуйте, ·, Вы писали:
·>Здравствуйте, Sharov, Вы писали:
S>> M>>Просто кейс что при использовании DI в конструктор передали null невозможен в принципе, тут нужен другой пример. S>> IT>Пусть передали не null, а поломаный объект. S>> Передали, и? Чем поведение без DI будет отличаться от поведения с DI в данном случае? ·>Я не очень понял твой вопрос, но попробую потелепатить. Различие в том, что в случае с обычным кодом, можно найти откуда конкретно передали просто проанализировав код, find usages. В случае DI-фреймворка ты можешь лишь понять, что пришло из контейнера и всё, и без дебаггера очень сложно разобраться.
Согласен, это я и имел ввиду. Т.е. разница во времени поиска причины, а не в поведении кода, его реакции, на поломанный объект.
За гибкость разработки приходится платить, увы. Серебряной пули нету.
Здравствуйте,
S>>> M>>Просто кейс что при использовании DI в конструктор передали null невозможен в принципе, тут нужен другой пример. S>>> IT>Пусть передали не null, а поломаный объект. S>>> Передали, и? Чем поведение без DI будет отличаться от поведения с DI в данном случае? S>·>Я не очень понял твой вопрос, но попробую потелепатить. Различие в том, что в случае с обычным кодом, можно найти откуда конкретно передали просто проанализировав код, find usages. В случае DI-фреймворка ты можешь лишь понять, что пришло из контейнера и всё, и без дебаггера очень сложно разобраться.
S>Согласен, это я и имел ввиду. Т.е. разница во времени поиска причины, а не в поведении кода, его реакции, на поломанный объект. S>За гибкость разработки приходится платить, увы. Серебряной пули нету.
как сказать
с одной стороны, если мы говорим о поломанных объектах, то при правильном программировании инвариантов их возможное существование будет пресекаться на корню. либо в конструкторе, либо в фабрике/билдере. и это безотносительно DI, а просто как правило хорошего тона и clean code.
с другой стороны, если мы перспективу иметь отсечение невалидных объектов (а инварианты могут быть существенно сложнее, чем просто not-null какого-то аргумента) будем рассматривать в контексте инстанцирования синглтонов в рамках какого-то фреймворка DI, то затраты технически будут равны тем, что возникнут и без DI. и там, и там нужно запустить процесс и увидеть, падает он или нет, а на этапе компилирования даже при поддержке некоторых аннотаций, абсолютно все проблемы подобного типа отловить не удастся.
к чему это я (ответ всем тем, кто отметился в этой подветке): не надо сравнивать DI или не-DI там, где проблемы возникают по другим причинам.
и ещё одно небольшое дополнение:
— анализ стек-трейсов причин, почему контейнер DI во время запуска упал из-за нарушения инвариантов синглтонов, даётся легко, если соответствующие исключения снабжены говорящими уникальными текстами, явно указывающими на суть нарушения.
— пользоваться дебаггером для этого — моветон. нужно учиться логировать и читать логи. в первую очередь из-за того, что, когда проблема прилетает из продуктива, никакой дебаггер не поможет, а логи — да.
Здравствуйте, IT, Вы писали:
IT>Здравствуйте, varenikAA, Вы писали:
AA>>>>Понял, а то у ТС вообще неопнятно на что он жалуется. ну это субъективно. так то во всех учебниках учат что надо избегать явного создания объектов. IT>>>Они не учат почему этого нужно избегать? Если нет, то ввыкинь такие учебники на помоечку. Впрочем, если да, то тоже выкинь.
AA>>Чтобы не зависеть от реализации.
IT>Зачем? Какую проблему это решает?
Например, командная разработка. Интерфейсы согласованы и лежат в общей сборке. Один работает над клиентом, другой над реализацией интерфейса.
МП>>если инициализация будет объемистой, то вынести в инициализирующий статический helper метод и везде использовать его
Б>А если для создания Dependency1 нужно передать param1 и param2 (скажем, строку подключения и таймаут), а для создания Dependency2 — param3 и param4 (например, имя пользователя и путь к S3), т.е. если Dependency1 и Dependency2 нужно дополнительно конфигурировать?
Б>Как твой helper создаст Dependency1 и Dependency2 в этом случае?
все аргументы которые ему нужны он попросит как входящие аргументы
причем эти все аргументы наверняка будут примитивными типами, типа строк и чисел
чтобы его вызвать нужно будет вначале явно задействовать логику по прочтению конфигурации/обращению к базе данных и т.п. для получения значений
по мне так это структура программы здорового человека
она будет явной, поддерживаемой и развиваемой
Властитель слабый и лукавый, Плешивый щёголь, враг труда,
Нечаянно пригретый славой,
Над нами царствовал тогда.... (А.С. Пушкин ? )
S>> M>>Просто кейс что при использовании DI в конструктор передали null невозможен в принципе, тут нужен другой пример. S>> IT>Пусть передали не null, а поломаный объект. S>> Передали, и? Чем поведение без DI будет отличаться от поведения с DI в данном случае? ·>Я не очень понял твой вопрос, но попробую потелепатить. Различие в том, что в случае с обычным кодом, можно найти откуда конкретно передали просто проанализировав код, find usages. В случае DI-фреймворка ты можешь лишь понять, что пришло из контейнера и всё, и без дебаггера очень сложно разобраться.
да и с дебагером зачастую приходится повозиться чтобы разобраться
Властитель слабый и лукавый, Плешивый щёголь, враг труда,
Нечаянно пригретый славой,
Над нами царствовал тогда.... (А.С. Пушкин ? )
AA>>>>>Понял, а то у ТС вообще неопнятно на что он жалуется. ну это субъективно. так то во всех учебниках учат что надо избегать явного создания объектов. IT>>>>Они не учат почему этого нужно избегать? Если нет, то ввыкинь такие учебники на помоечку. Впрочем, если да, то тоже выкинь. AA>>>Чтобы не зависеть от реализации.
IT>>Зачем? Какую проблему это решает?
AA>Например, командная разработка. Интерфейсы согласованы и лежат в общей сборке. Один работает над клиентом, другой над реализацией интерфейса.
ойойой
а как же интересно вели командную разработку году так в 2005, когда DI извращения ещё не придумали?
Властитель слабый и лукавый, Плешивый щёголь, враг труда,
Нечаянно пригретый славой,
Над нами царствовал тогда.... (А.С. Пушкин ? )
Здравствуйте, Министр Промышленности, Вы писали:
МП>ойойой МП>а как же интересно вели командную разработку году так в 2005, когда DI извращения ещё не придумали?
Как бы это лучше сказать? Через одно место вели.
Втоорй профит кстати в том, что клиентский модуль будет работать без перекомпиляции если пришлось пофиксить реализацию.
В случае же с явным созданием зависимого объекта через конструктор придется что? ребилдить весь солюшн.
Ай-йа-яй!
И кстати. нечего не явного не вижу в DI.
services.AddSingleton<IMainService, MainService>(); // Что тут неявного?
services.AddHostedService(prop => prop.GetService<IMainService>() as MainService); // Что тут неявного?
services.AddDbContext<DbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection"))); // Что тут неявного?
Зато точка сборки приложения одна а не размазана по разным сборкам.
МП>>ойойой МП>>а как же интересно вели командную разработку году так в 2005, когда DI извращения ещё не придумали? AA>Как бы это лучше сказать? Через одно место вели.
нет, вели приемлемо
а если лид хоть как-то продумывал вопросы параллельной разработки — так и вообще без проблем
например делали временную реализацию того же интерфеса, все методы которой вначале кидают NotImplementedException
AA>Втоорй профит кстати в том, что клиентский модуль будет работать без перекомпиляции если пришлось пофиксить реализацию.
тут уже разобрали этот фактор в обсуждении
когда это реально нужно — принимается как некоторый аргумент "за", хотя и привносит свои риски и затруднения
AA>В случае же с явным созданием зависимого объекта через конструктор придется что? ребилдить весь солюшн. AA>Ай-йа-яй!
ребилдить весь солюшен — это чистое и довольно хорошее решение
кроме случаев когда ребилд занимает слишком много времени — сутки, несколько часов
в описанном вами случае ребилдить придётся только клиентский модуль с его зависимостями
AA>И кстати. нечего не явного не вижу в DI. AA>
AA> services.AddSingleton<IMainService, MainService>(); // Что тут неявного?
AA> services.AddHostedService(prop => prop.GetService<IMainService>() as MainService); // Что тут неявного?
AA> services.AddDbContext<DbContext>(options =>
AA> options.UseSqlServer(
AA> Configuration.GetConnectionString("DefaultConnection"))); // Что тут неявного?
AA>
AA>Зато точка сборки приложения одна а не размазана по разным сборкам.
ну неет
точка сборки приложения действительно лучше бы была одна, а именно — в .sln файле
попытка придать зависимостям характер аспекта явно натянута
нет такой проблемы чтобы вот так вот пахабить код вместо естественной инициализации
и код это не сокращает
и вынос всех конструирований зависимостей в одно место сходно с плохим примером объединения классов по сборкам,
ну не по алфавитному порядку их названий конечно
по принципу: классы, которые имеют параметризованные конструкторы инициализируем не где это надо, а вот здесь!
а с классами, которые скажем имеют события или подтипы — вы ничего не хотите сделать?
Властитель слабый и лукавый, Плешивый щёголь, враг труда,
Нечаянно пригретый славой,
Над нами царствовал тогда.... (А.С. Пушкин ? )
Здравствуйте, varenikAA, Вы писали:
AA>// Что тут неявного?
Непонятно кто от кого и как зависит.
AA>Зато точка сборки приложения одна а не размазана по разным сборкам.
Просто делай то же самое, но без контейнера. Если я правильно разгадал твой код:
var dbOptions = new DbOptions()
.UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
var dbContext = new DbContext(dbOptions);
var mainService = new MainService(dbContext);
services.AddHostedService(mainService);
Код внезапно стал проще — никаких лямбд, генериков, рефлексии, даункастов. Можно использовать IDE вовсю — find usages, declarations, использовать рефакторинги.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
AA>>// Что тут неявного? ·>Непонятно кто от кого и как зависит.
AA>>Зато точка сборки приложения одна а не размазана по разным сборкам. ·>Просто делай то же самое, но без контейнера. Если я правильно разгадал твой код:
·>
·>var dbOptions = new DbOptions()
·> .UseSqlServer(Configuration.GetConnectionString("DefaultConnection"));
·>var dbContext = new DbContext(dbOptions);
·>var mainService = new MainService(dbContext);
·>services.AddHostedService(mainService);
·>
·>Код внезапно стал проще — никаких лямбд, генериков, рефлексии, даункастов. Можно использовать IDE вовсю — find usages, declarations, использовать рефакторинги.
все разговоры в этой теме от банального непонимания, для чего придумали DI / IoC
ну так вот тебе надо ПРОТЕСТИРОВАТЬ, что схема базы данных, используемая твоим кодом, актуальна, например,
как ты с твоим этим кодом будешь писать код, который это проверяет?
с DI и EF InMemory Provider это будет где-то в три строчки
МП>С моей профессиональной точки зрения DI фреймворки не нужны.
МП>Они затрудняют распутывание кода, МП>понижают гибкость автоматического рефакторинга (в частности ReSharper-ом) МП>и это не перекрывается гибкостью подстановки mock-объектов
МП>но обнаруживаю ярых адептов этого всего. МП>уже и в вакансиях суют такое требование
МП>кто-то может популярно расписать преимущества либо природу явления популярности? МП>(часть плюсов знаю и гипотезы-то я имею, но мнение всё равно такое)
покажи просто, как ты собираешься поддерживать систему, над которой работали и 10 лет назад (и все эти люди уже уволились) и позавчера пара практикантов, а сегодня надо приделать какую-то фичу тебе и ты эту систему увидел в первый раз
Здравствуйте, Министр Промышленности, Вы писали:
МП>>>так а зачем вообще делать dependency injection? AA>>Уменьшить связанность компонентов.
МП>принимается
Нет не принимается: абстрактная фабрика точно так же уменьшает связность и развязывает зависимости. Ключ здесь — использование интерфейсов вместо конкретных классов.
Всё сказанное выше — личное мнение, если не указано обратное.
Здравствуйте, gandjustas, Вы писали:
МП>>но обнаруживаю ярых адептов этого всего. МП>>уже и в вакансиях суют такое требование G>Уже? Доброе утро. Погугли что означает D в SOLID
МП>>С моей профессиональной точки зрения DI фреймворки не нужны. G>Надо было писать "недостаточно профессинальной"
Да, похоже на то Недостаточно профессиональной.
Погугли, чем эти термины отличаются.
Всё сказанное выше — личное мнение, если не указано обратное.
Здравствуйте, takTak, Вы писали:
МП>>кто-то может популярно расписать преимущества либо природу явления популярности? МП>>(часть плюсов знаю и гипотезы-то я имею, но мнение всё равно такое)
T>покажи просто, как ты собираешься поддерживать систему, над которой работали и 10 лет назад (и все эти люди уже уволились) и позавчера пара практикантов, а сегодня надо приделать какую-то фичу тебе и ты эту систему увидел в первый раз
Встречный закономерный вопрос: как в этом случае поможет DI?
И можно пример кода, пожалуйста.