Здравствуйте, vmpire, Вы писали:
V>·>Дублирование ортогонально контейнеру. Можно и написать wiring код без дублирования, а можно надублировать конфигурацию контейра. Что кстати, мне нередко доводилось наблюдать — почти одинаковые конфигурации для тестов/прода; в итоге тесты работают, а прод падает, внезапно.
V>Вы точно не путаете проблему DI контейнера как такового с проблемой его инициализации из XML или JSON? XML/JSON это практически однозначно зло, кроме, может быть, очень редких специфичных случаев.
Однозначное зло — это словарь, рефлексия, строковые константы и т.п.
V>Если нужны одинаковые конфигурации для тестов и прода, то кто мешает слелать эту конфигурацию в одном куске кода и переиспользовать?
В этом случае придётся бороться с фреймворком как вменяемо разделять конфигурации.
V>·>Никаких осязаемых преимуществ конкретно контейнер не даёт.
V>В тех случаях, когда не даёт, можно ведь им не пользоваться. Я же сразу написал, что это нишевый инструмент.
Так мой поинт, что никогда не даёт.
V>·>Ну можно так выразиться, хотя неясно почему "контейнер", нет ничего контейнерного (словаря-то нет!). Это и есть хорошо, что статический. Динамика это в php и javascript, зачем это тащить в компилируемые ЯП — неясно.
V>Словарь — это всего лишь один из возможных механизмов реализации. Если контейнер не будет библиотекой для использования в произвольных проектах, а делается для одного раза, то словарь будет только лишним.
А какие другие возможные механизмы? Нужна коллекция объектов, граф типов зависимостей и т.п. Это и есть контейнер.
V>·>Подавляющее большинство связывания будет через Constructor Injection. Т.е. ты тупо не сможешь создать объект в коде не имея нужных ему зависимостей.
V>Пример:
V>IDatabase myDatabase = null;
А причём тут wiring/контейнер?! За такой говнокод
в любой части проекта надо сильно по голове бить. И переписать хотя бы вот так (или какой там синтаксис switch expression?):
ILogger myLogger = new MyCoolLogger();
IDatabase myDatabase = switch (configuredDatabase) {
case "mysql" => new MySqlDatabase(myLogger);
case "yoursql" => new YourSqlDatabase(myLogger);
_ => throw new UnsupportedArgument("Unknown " + configuredDatabase);
}
И ещё сделать хотя бы enum для configuredDatabase. Строковые константы — тоже надо избегать, хотя вот как раз в DI-контейнерах без них часто никак, т.к. имена инстансов надо как-то использовать.
V>По сути, точно такая же ошибка, как если бы забыли зарегистрировать объект в DI контейнере.
Такая ошибка может быть в любом коде. Wiring тут не при чём.
V>·>Ты видимо связывание через Property Injection? Тоже хак, который надо избегать.
V>Боже упаси, конечно, нет. Я про вот это
= null часто можно просто не писать, так что это мелкая проблема обычно.
V>·>Что этот код явный и работает явно. И отлаживается как обычный код, и тестами покрывается, и стектрейсы явные и т.п.
V>Код явный — это, конечно, хорошо. Но с таким аргументом лучше вообще библиотеками не пользоваться, а то мало ли что там внутри. Впрочем, я лично знал человека, который писал свою реализацию списка на C# толко потому, что в своей реализации он понимает, как она работает.
V>При отладке и содержимое контейнера прекрасно видно. А в логах — не всё ли равно какой там будет класс, свой или библиотечный?
V>С трейсами то же самое.
V>Так что на мой взгляд оно эквивалентно.
Так тут не надо никакой код по сути писать. Суть того, что делает контейнер, это оборачивает обычные конструкции ЯП new/if/switch в библиотечные классы.
Зачем тебе нужнен фреймворк, чтобы написать фабрику? Фабрика это просто _один_ метод, иногда даже просто лямбда.