О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.07.16 06:40
Оценка: 74 (6) +4 :))) :))
О "наивном" DI и об архитектурном бессилии


Warning. В результате срача дисксиий, пробелы автора в понимании сути DI были заполнены (см. Update 4 внизу). Претензии высказанные в посте по отношению к DI оказались претензиями к DI фреймворкам.


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

Собственно ситуация имхо довольно типичная — мне то "опыт подказывает", а молодежь старательно "набивает шишки", но при этом, я почему-то сходу не нашел ни одного внятного объяснения от популяризаторов DI того, почему наивное использование DI будет провальным. Поэтому я решил таки сформулировать свой вариант

Посмотрим на типичный пример наивного DI:

public class HomeController : Controller

public HomeController(
IBoringItemDataReader,
IBoringItemDataWriter,
BoringItemChildDataReader,
IBoringItemChildDataWriter,
IAppDataJsonConverter,
...
)

Гиперболизируя можно было бы добавить еще IJsonConverter чтобы механизм конвертирования json можно было изменить и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но на всякий случай стоит "уменьшить зависимости" .

Посмотрим на реализацию IBoringItemDataReader:

public class BoringItemDataReader : IBoringItemDataReader

и с десяток совершенно очевидных хелперных stateless методов типа:

GetBoringItemById
GetBoringItemByNumber
GetBoringItemByDataInterval
...

Ребята... вот эта низкоуровневая "требуха" это что ли "сервис"? Вот эти все "внутренности наружу" это инкапсуляция и архитектура? Как получилось, что попытка "соблюсти" принцип DIP очевидно вызывает нарушение всех остальных принципов SOLID и на это закрывают глаза? Как можно внедрять "зависимость сервиса" в ситуации, когда разработчик не способен создать сам внедряемый сервис? Проблема тут имхо базовая — разработчик не имеет навыков создания объектной декомпозиции и пытается компенсировать это использованием сложных механизмов, смысла которых он не понимает.

Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры". Часть знакомых уверяла, что DI жизненно необходим для тестирования, но тут ситуация становилась совсем абсурдной, т.к. архитектурное решение (использовать DI) вроде как принималось, но никаких тестов при этом не было и в будущем они никогда не появлялись.

Как-то так... имхо главная начальная проблема DI — неспособность разработчиков создавать объектные декомпозиции. Это ведет к созданию абсолютно неправильной, очень низкоуровневой и хрупкой системы зависимостей нарушающей 4 из 5 принципов SOLID. Пример того, как некоторые пытаются лечить гланды через задний проход. Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.

Update:

Обсуждение натолкнуло на мысль, что на самом деле наивный DI нарушает принцип DIP в первую очередь. Т.к. каноничная формулировка DIP гласит:


имхо совершенно очевидно, что наивный сервис слепленный из хелперных методов DAL, ни в коем случае не является "абстракцией". Он предельно конкретный с предельно конкретными entity типами даже если структура этих типов продублирована, а данные копируются с помощью мапперов (эдакий карго-культ "абстрации"). Имхо здесь совершенно четко определяемая проблемы — интерфейсы верхних уровней начинают определять низкоуровневые интерфейсы DAL. Разрозненные хелперные методы не перестанут быть хелперными методами от того, что их вызывают через интерфейс.

Update 2:

Не стоит ждать в этом топике борьбы за рассовую чистоту DI, здесь рассматривается совсем другой аспект. Возможно аспект не очень грамотный (с точки зрения тех кто хорошо разбирается в теме DI и давно его использует), но уж какой есть. Имхо нельзя игнорировать тот факт, что из за базза поднятого вокруг DI фреймворков их пытаются использовать не так и не там полностью игнорируя негативные результаты.

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

Update 3

Мое имхо по итогам обсуждения поста:

Ребята это секта... секта свидетелей DI фреймворков, отпочковавшаяся от секты свидетелей TDD. Вообще имхо DI фреймворки появились из за того, что сектантам TDD было необходимо тестировать приватную логику, а по их канонам unit test этого делать нельзя. Поэтому был применен ряд шельмований, приватную логику перекрестили в сервисы вытащили их наружу. Здесь можно вспомнить COM, который решает аналогичные DI фреймворкам задачи, но в те времена не было движения TDD и поэтому COM не стал религией, а остался инфраструктурным решением.

Ни DI ни TDD ничего не гарантируют разработчику, ни от чего не защищают и ни в чем не помогают. Зато гарантированно служат серьезным источником оверхеда. Как же им удается иногда демонстрировать свою полезность? А все элементарно... например код веб систем, можно разделить на две части — бизнес логика и код взаимодействия с системными сервисами UI, DB и т.д. Взаимодействие с системными сервисами разработчику понятно, отлично проработано и имеет долгую историю. Что провоцирует наивные умы, особенно на первых этапах проекта, запихивать бизнес логику прямо в код который реализует взаимодействие с системными сервисами. Так создаются шедевры спагетти кода. Что делает TDD? Оно постулирует — сначала пишем тесты. Все верно, в юнит тестах нет взаимодействия с системными сервисами поэтому структуру бизнес логики приходится прорабатывать отдельно от всего т.е. приходится строить архитектуру. Вот и весь трюк. Цена такого подхода — значительный оверхед кода (уровень которого зависит от религиозного фанатизма разработчика), потому как бизнес логика гарантированно будет уточнятся и изменяться и тесты придется переписывать, но как мы теперь понимаем, для проработки бизнес логики и построения архитекуры тесты на самом деле лишь полезны, но никак не обязательны.

Update 4 (вероятно крайний)

После сосредоточения на теме обнаружился забавный баг. DI на деле выглядит примерно так:

public SomeClass (MyClass myObject)
{
this.myObject = myObject;
}

и не требует никаких интерфейсов, фреймворков, code-дуделок и code-перделок (думаю практически все, так или иначе используют этот паттерн). А все остальное от лукавого.

Хвала stackoverflow бельгийцы (!) сохранили способность воздерживаться от троллинга и сектантщины.

http://stackoverflow.com/questions/130794/what-is-dependency-injection

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

Т.е. все мои претензии высказанные в посте по отношению к DI стоит считать претензиями к DI фреймворкам. И получается любопытный вывод — если с простым DI ваши проекты, с завидным постоянством превращаются в big ball of mud, то как использование DI фреймворка может это предотвратить?
Отредактировано 11.10.2016 8:22 IQuerist . Предыдущая версия . Еще …
Отредактировано 11.10.2016 8:21 IQuerist . Предыдущая версия .
Отредактировано 11.10.2016 8:15 IQuerist . Предыдущая версия .
Отредактировано 11.10.2016 8:12 IQuerist . Предыдущая версия .
Отредактировано 10.10.2016 12:40 IQuerist . Предыдущая версия .
Отредактировано 27.09.2016 7:09 IQuerist . Предыдущая версия .
Отредактировано 21.09.2016 11:05 IQuerist . Предыдущая версия .
Отредактировано 21.09.2016 11:04 IQuerist . Предыдущая версия .
Отредактировано 02.08.2016 14:20 IQuerist . Предыдущая версия .
Отредактировано 27.07.2016 6:43 IQuerist . Предыдущая версия .
Re[4]: О "наивном" DI и об архитектурном бессилии
От: Lexey Россия  
Дата: 29.07.16 17:44
Оценка: 7 (2) +6
Здравствуйте, Sinix, Вы писали:

S>В самых тяжёлых случаях — moq/ms fakes/NSubstitute etc. Во всех остальных проще и дешевле использовать интеграционные тесты. Те же юнит-тесты, только вся инфраструктура уже заведена и доступна к использованию.


Может у тебя специфика такая. У меня, как правило, ситуация обратная. Юнит-тесты писать проще и дешевле, чем интеграционные. И исполняются они на порядки быстрее. А бывало и так, что хороший интеграционный тест в принципе невозможен. И самое интересное вылезает в процессе пуско-наладки.

S>Оно хоть и немного гемморойней на начальном этапе, но зато в итоге не будет такого, что тесты зелёные, а вот работать — упс.


В идеале хорошо и то и то иметь зеленым.

S>Я ж выше писал Большие проекты с необходимостью поддерживать плагины от сторонних разработчиков. Вот там DI творит чудеса. Самый простой пример — расширения студии. Сравни число расширений для кода, который подрубается через MEF (редактор по сути) и то, для чего нормальное API только в процессе (lang services, debugging api etc).


ИМХО, DI-контейнеры — это все-таки весьма частный случай DI, а не его родная ниша. Простейший DI (в виде передачи функции или объекта в другую) существовал задолго до того, как начали массово лепить контейнеры везде, где только можно (и чаще всего не нужно). Только никто его так не называл.
Re: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 01.09.16 13:37
Оценка: 22 (1) +5
Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.
Лично для себя сделал простой вывод, DI НЕ требуется только для объектов в которых нет логики, т.е. POCO.
Всё остальное — DI. Причин тут несколько и все они достаточно очевидны и разжёваны не мной а в тьме видео описывающих какие именно проблемы решает DI но я ещё раз ох опишу.

1. Когда говорят про использование DI то в 99% случаев DI используют вместе с контейнером. А смысл контейнера не только в предоставлении зависимостей а в управлении временем жизни объекта. Делегирование управления жизни обьекта контейнеру — одна из самых принципиальных вещей.

2. Использование DI позволяет тебе чётко определять все зависимости объекта, зависимости становятся явными и получает их обьект обычно в конструкторе. Иными словами мне НЕ нужно лазить по коду объекта что бы понять а от чего ещё он зависит. Достаточно глянуть в конструктор и всё становится понятным.

3. При тотальном использовании DI во всём проекте во всём проекте используется один и тот же стандартных подход. Такой код читать просто и понятно. А вот обратный случай когда вот тут вот мы сделаем new, а вот там вот вызовем статический метод а вот это вот мы заинжектим потому что оно — это сервис (а что такое сервис никто не знает). Это точно бред.

В целом у автора пока просто мало опыта использование DI и DI для него новая концепция при переходе к которой абсолютно естественно возникает куча вопросов и нормальное отторжение. Так у всех, это нормально.
Народная мудрось
всем все никому ничего(с).
Re[3]: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 29.07.16 15:03
Оценка: 8 (1) +5
Здравствуйте, Lexey, Вы писали:

L>А как ты предлагаешь подсовывать моки/фейки без DI?

В самых тяжёлых случаях — moq/ms fakes/NSubstitute etc. Во всех остальных проще и дешевле использовать интеграционные тесты. Те же юнит-тесты, только вся инфраструктура уже заведена и доступна к использованию.

Оно хоть и немного гемморойней на начальном этапе, но зато в итоге не будет такого, что тесты зелёные, а вот работать — упс.


L>Что такое "родная ниша" DI?


Я ж выше писал Большие проекты с необходимостью поддерживать плагины от сторонних разработчиков. Вот там DI творит чудеса. Самый простой пример — расширения студии. Сравни число расширений для кода, который подрубается через MEF (редактор по сути) и то, для чего нормальное API только в процессе (lang services, debugging api etc).
Re[5]: О "наивном" DI и об архитектурном бессилии
От: fddima  
Дата: 21.09.16 02:19
Оценка: 79 (3) +2
Здравствуйте, Lexey, Вы писали:

L>Может у тебя специфика такая. У меня, как правило, ситуация обратная. Юнит-тесты писать проще и дешевле, чем интеграционные. И исполняются они на порядки быстрее. А бывало и так, что хороший интеграционный тест в принципе невозможен. И самое интересное вылезает в процессе пуско-наладки.

Я извиняюсь, что подымаю старую тему. Но в случае юнит-тестов — ситуация — все тесты зеленые, а оно не работает — вполне себе. А в процессе пуско-наладки оно не работает и как выясняется — работать не могло, по причине, например отсутствия самого важного куска в SQL процедуре.
Интеграционные тесты в каком-то смысле необходимо воспринимать как функциональные, например:
1. Компилятор для определенного входа, должен генерировать определенный код; или выдавать строго определенные ошибки в сторого определенных случаях/позициях.
2. Браузер должен ренедерить pixel-to-pixel картинку для заранее определенных/подготовленных данных.
Это: легко реализуется, ну и именно в том числе такие подходы используются в реальных проектах.
Плюсы очевидны — мы работаем на вполне определенных входных данных, кстати, что важно — они вполне читаемы человеком (повезло).

Безусловно есть совершенно другой класс систем, где входы/выходы и состояние настолько запрятаны, что протестировать так просто... просто не получится. Или входы/выходы едва анализируются человеком.
Ну вот пример на который натыкался лично я: процессинг карт/транзакций на самом деле за 20 лет никогда не считал комиссию по терминалу в соответствии со спецификацией — она должна была быть взята в соответствии с приказом на терминал на дату транзакции. На самом деле считалось по последнему приказу (точнее в соответствии с приказом соответствующий текущей дате). В случае задержки обработки по тем или иным причинам реальный разрыв времени / сбой может произойти. Ситуация как уже понятно весьма и весьма редкая, тем не менее поизошла.
И тут мы имеем, допустим классику: и сервер приложений, и терминальный сервер и SQL сервер и даже где-то в стороне ОДБ.
Так вот, пока мы не наделим всей информацией все подсистемы для моделирования одного такого кейса — смоделировать по сути не получится.
Как только мы начнем наделять *каждую* подсистему необходимыми данными перед проведением теста — тест можно будет выполнить с минимальным количеством проверок / иногда даже не заглядывая во все подсистемы. В данном случае — всё вообще можно было сделать со стороны терминального сервера эмулируя команды и карт и других процессингов, что в итоге может быть проще — а может быть и нет (зависит от тестовой инфраструктуры).
Детали я маленько забыл, давно с этим уже не работаю.
И если бы я это делал изначально — я забил бы болт на все, и максимально обложил бы тестами как раз с этой стороны — потому что в момент переписывания одной из подсистем делал в общем-то тоже самое, только в меньшем объеме, вдобавок вскрыл моменты которые спецификацией не определены, что не могло бы быть незамеченным, если бы такие тесты проводились.
Безусловно это требует усилий, и немалых, однако большинство из них просто технические, но главный — это как раз создание вменяемых сценариев и вменяемое воплощение их в кодируемый вид (для меня прямой кодинг для C# не работал от слова вообще — слишком много шума, DSL получше — но тут тоже дорожка тонкая — захочется отойти в сторону — он будет или слишком сложным или вернемся к C#).

А, ещё был опыт с моками и везде DI. Подход/тесты выходили настолько дебильные и большие, что легче бы сделали интеграционные — вдобавок система *полностью* наблюдаема через одну точку доступа, и фэйковый поставщик данных. Вдобавок прямо перед этим я в своем проекте делал именно так, и подход себя зарекомендовал вполне сносно. Толку явно больше, потому как довольно просто описывается, вместо кода для моков в которых опять таки можно ошибиться, а затем допиливание самого кода что бы оно могло быть протестировано моками. Фе.

Сейчас у меня (не мой личный, скорее неофициально прижившийся) — фокус на фичи, и смотрим на error rate и выборчно результаты (их можно глазами осознать / довольно легко проверить), может быть несколько деплоев в день. Впрочем для кое-каких подсистем, пришлось написать свои интеграционные тесты. Совсем мало юнит. Впрочем для тестов — и кастом/MITM прокси, позволяющая "украсть" ответ запроса и потом бесконечно его тыркать (для перфоманс тестов), да и небольшой in-house фреймворк. Кое-где я писал. Просто, мы, как и многие зависим от third party практически константно — и важно, что оно или работает в обозначенных сценариях — или нет. Юниты тут как бы тоже никчему не прилепишь, да и выполнить практически нормальный workflow проще. Скорее тесты — по необходимости, но не более, или там где я ожидаю изменение поведения в будущем, и хочу быть уверен, что функциональный блок сохранит работоспособность, вплоть до ассерта в рантайме. Ну, а встреченных проблем кстати в third party — хватает, начиная от самого фреймворка, заканчивания каким-нибудь клиентом к rabbit который в асинхронном методе синхронно лочится в BlockingCollection, чем ставит раком абсолютно всю систему, хотя и не должен бы. Кватовая физика прямо — попытки пронаблюдать состояние в дебаггере — приводят к тому, что tasks "отлипают".

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

PS: Кстати сейчас проект практически без DI. Но кое-где напрашивается.

Update: Кстати, есть один немаловажный момент, — если система (программный комплекс) предполагает долгую жизнь, то интеграционные тесты (в случае их хорошего исполнения) позволяют полностью абстрагироваться от конкретной базы кода (понятно, что если это позволяет предмет, и в необходимых количествах), что сыграет наруку в будущем. Таким образом при необходимости миграции с продукта версии 1 к версии 2 (в современном версионировании браузеров — от перехода от версии к 70 к версии 230), где версия >200 по праву считается совершенно отдельным и независимым продуктом (т.е. переписан с "нуля", стал например распределенным, или же использует несовместимое хранилище (т.е. нет возможности апгрейда, есть возможность конверсии, при чем не всегда обратимой)) — интеграционные/функциональные тесты помогут ответить на вопрос клиента: не станет ли всё раком после перехода. А программиты которые работали над версиией 200 — смогут ответить себе на вопрос — будет ли это точно работать именно у этого клиента. Поскольку я лично с этим столкнулся, наверное поэтому считаю, что приоритет для интеграционных и функциональных тестов, по минимум юнит, оставляя им место, где просмотрев код — неясно работает ли он. Это обычно всякие парсеры и/или мудреная/перераспухшая логика, и/или где неясны граничные моменты а пощупать их хочется (и есть возможность). Впрочем перераспухей логики скорее всего как раз юнит и не помогут.
Отредактировано 21.09.2016 2:47 Mystic Artifact . Предыдущая версия .
Re[13]: О "наивном" DI и об архитектурном бессилии
От: ilvi Россия  
Дата: 26.08.16 16:21
Оценка: 2 (1) :))) :)
Здравствуйте, Cyberax, Вы писали:

C>Я внутри Amazon'а работаю в облачных вычислениях.

Полтора-два года назад как раз читал про плеер амазонвский под андроид, были огромные ветки на форумах с разгневаными пользователями и оценка в плеймаркете соответсвенная. Потом довелось подержать в руках один из киндлов, с цветным экраном, на котором этот плеер можно было помучать. Через пять минут я его "сломал" — перестал отображать постеры к описаниям фильмов и еще что-то отвалилось. Потом спросил у дядечки, который руководил одним из проектов по разработке этого плеера, как они тестируют — ответ был, что только юнит тесты и никаких ручных тестов. На тот момент всей этой информации хватило, чтобы сформировать мнение, почему у амазона конкретно этот плеер такой глючный.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re: О "наивном" DI и об архитектурном бессилии
От: Vladek Россия Github
Дата: 29.07.16 00:08
Оценка: 4 (2) +2
Здравствуйте, IQuerist, Вы писали:

IQ>О "наивном" DI и об архитектурном бессилии


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


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

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

IQ>Собственно ситуация имхо довольно типичная — мне то "опыт подказывает", а молодежь старательно "набивает шишки", но при этом, я почему-то сходу не нашел ни одного внятного объяснения от популяризаторов DI того, почему наивное использование DI будет провальным. Поэтому я решил таки сформулировать свой вариант


А как ещё учиться программистам? Только набивать шишки, анализировать свои ошибки, меняться.

IQ>Посмотрим на типичный пример наивного DI:

IQ>Ребята... вот эта низкоуровневая "требуха" это что ли "сервис"? Вот эти все "внутренности наружу" это инкапсуляция и архитектура? Как получилось, что попытка "соблюсти" принцип DIP очевидно вызывает нарушение всех остальных принципов SOLID и на это закрывают глаза? Как можно внедрять "зависимость сервиса" в ситуации, когда разработчик не способен создать сам внедряемый сервис? Проблема тут имхо базовая — разработчик не имеет навыков создания объектной декомпозиции и пытается компенсировать это использованием сложных механизмов, смысла которых он не понимает.

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

IQ>Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры". Часть знакомых уверяла, что DI жизненно необходим для тестирования, но тут ситуация становилась совсем абсурдной, т.к. архитектурное решение (использовать DI) вроде как принималось, но никаких тестов при этом не было и в будущем они никогда не появлялись.


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

Это процесс итеративный, главное не надо думать, что ясная архитектура должна рождаться сразу. Код должен писаться, а потом читаться и правиться. Только после серии правок начнёт вырисоваться внятная схема взаимодействия объектов.

IQ>Как-то так... имхо главная начальная проблема DI — неспособность разработчиков создавать объектные декомпозиции. Это ведет к созданию абсолютно неправильной, очень низкоуровневой и хрупкой системы зависимостей нарушающей 4 из 5 принципов SOLID. Пример того, как некоторые пытаются лечить гланды через задний проход. Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.


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

Почему это названо проблемой конфигурации (внедрения зависимостей)? Конфигурация и архитектура не одно и то же.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IT Россия linq2db.com
Дата: 29.07.16 03:12
Оценка: +4
Здравствуйте, Vladek, Вы писали:

V>Почему это названо проблемой конфигурации (внедрения зависимостей)? Конфигурация и архитектура не одно и то же.


В случае с невменяемым DI получается, что конфигурация заменяет архитектуру.
Если нам не помогут, то мы тоже никого не пощадим.
Re[23]: При чем тут Di?
От: maxkar  
Дата: 21.08.16 11:53
Оценка: 42 (1) +2
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, maxkar, Вы писали:


S>Почему на реальный сценарий пофиг? Так твои советы не подходят. У контекста нет поведения, он по определению иммутабельный (хотим предоставить другой набор сервисов — подменяем контекст) и может предоставлять как захардкоженные зависимости, так и определяемые в рантайме. Иначе начинается разброд: часть передаём через контекст, часть — через DI. Фу-фу-фу


А я разве утверждал, что на бизнес-сценарий пофиг? Бизнес-задача (основная цель) как раз и нужен. Но вот формулировка "нужно создать сервис в зависимости от контекста" бизнес-задачей не является. Необходимость передачи сервиса — это артефакт конкретной реализации и ранее принятых решений. Я предлагаю не фокусироваться на том, как оно сейчас вылилось в коде. Я предлагаю посмотреть на бизнес-задачу. И решить ее так, чтобы на уровне реализации нам вообще не приходилось "создавать сервисы в зависимости от контекста". Да, это потребует пересмотра разделения ответственностей и рефакторингов. Возможно, хорошего DI. В результате задача получается "обеспечить нужное динамическое поведение в зависимости от данных без применения service lookup или передач сервисов". "Динамическое поведение" можно заменить на конкретное поведение из спецификации программы.

Ну а контекст... context.logger.info("Hello, world!") — это поведение контекста или сервис, передаваемый через него? Я вот считаю, что если до сервиса можно добраться через контекст, то его поведение является и поведением контекста (или части контекста). И передача сервисов через контекст как раз добавляет "поведений" контексту. Разброда на практике обычно как раз и нет. Поведения/данных, присущих контексту, очень мало. Это логирование, пользователь/сессия. А все остальное инжектится через DI.


M>>Ну здесь все банально. Вот прямо к данному коду применяется рефакторинг "Tell, Don't ask". И получается яуже упомянутое


S>Ну так это ж зло в чистейшем виде. Вместо явного разделения ответственностей (вся инициализация — в одном методе) у нас получается мешанина из

S>* Собственно реализаций
S>* Обёртки SmartConfirmationService,
S>* Подменяемой фабрики, которая и будет выбирать конкретную реализацию. Чтобы не делать копию SmartConfirmationService для другого метода, скажем, для GetAdvancedConfirmationService

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

В рамках этой модели фабрика как раз не нужна. Для другого метода я передам другую ConfirmationSerivce в конструктор объекта, содержащего метод. Это может быть как по-другому сконфигурированная SmartConfirmationSerivce, так и другая реализация. Т.е. да, у нас именно через DI могут заинжектится различные экземпляры одного типа. И почти ни один "DI Framework" вот именно этого делать не умеет. Фабрика обычно возникает как раз в этом случае — нужно много экземпляров, но фреймворок все объекты идентифицирует только по типам. Там приходится делать одну фабрику, которая будет решать эту (искуственную) проблему. А мне ее решать не нужно, у меня в методах доступны ровно те сервисы, которые им нужны. Без всяких lookup.

S>Вот этот подход "мы не смотрим на реальную проблему, мы можем в паттерны" изначально порочен, т.к. он приводит к дикому переусложнению кода на ровном месте. На этом же примере объясню.


Нет, нет так. Я не занимаюсь активностью в виде "мы тут себе изобрели проблем и теперь героически их решаем". Я предпочитаю сразу выпилить источник проблем и решать бизнес-задачи удобным способом. Если источник проблем DI Framework — тем хуже для него.

S>Помимо нагромождения типов у нас есть ещё один косяк: мы продлеваем время жизни зависимостей — в оригинальном коде Consumer был нужен только для получения конкретной реализации, дальше можно передавать только саму реализацию.

S>У тебя consumer-а приходится протаскивать дальше. Ок, запоминаем consumer через конструктор SmartConfirmationService.

Нет. Не запоминаем. Обычно все сервисы создаются на старте приложения и живут до его завершения. Все остальное (включая Consumer) — параметры. Сервисы по возможности effectively immutable/stateless. У них нет способов "видеть их внутреннее состояние". Совсем типичный сервис как раз immutable, более сложные вещи вроде кэшей — да, там приходится делать аккуратно. Параметры методов обычно тоже immutable. А все изменяемое состояние — только в persistense services (не важно, база там или in memory service).

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

S>Всё? Нифига: у нас баг: consumer мутабельный, если его изменить, то внезапно приходит не тот сервис.

S>Ок, определяем нужный сервис сразу, в конструкторе... и мы оказались в идиотской ситуации: переусложнённый код, который по сути прячет вызов GetConfirmationService внутрь отдельного объекта. Зашибись архитектура.

Вот такого там точно не будет. У сервисов время жизни обычно гораздо больше, чем время жизни параметров (запросов и т.п.). Поэтому через конструкторы к ним только другие сервисы передаются. А вот интерфейсы сервисов и общее разделение ответственностей делаются так, чтобы лишних параметров не нужно было передавать и чтобы лишние параметры транзитом через сервисы не гонять. Замыкания на параметры встечаются иногда для сложных алгоритмов, но они всегда явлюятся деталью реализации компонента и не являются частью публичного API.

Если же это было legacy, оно встанет в очередь на рефакторинг. К immutable и конструкцией сервисов только на старте приложения.

M>>А вот заводить интерфейсы по месту "вставки реализации" — хорошая. Ну да, будет много мелких интерфейсов, будет Interface Segregation.

S>Ну да, вот именно про это я и говорил. Аккуратно продумать API — нет, допиливать "правильный" код обёртками по месту, даже ломая архитектуру — да. Не, эт вопрос вкуса конечно, поэтому даже спорить не буду

А что значит "правильный"? Вот как получилось, что при "аккуратно продуманном API" у компонента появилась обязанность, которую он не может выполнить без костылей, благородно переданных ему в вызове? Может, с распределением обязанностей (ну и изменением API, да) что-то не так и его стоит поменять? Я согласен с тем, что "если из-за архитектуры у нас получается сложный/неинтуитивный/вызывающий вопросы API — в топку такую архитектуру".

Кстати, даже "архитектура" в данном месте может трактоваться по-разному. Если это "правила именования, написания классов и прочие церемонии" — да, особой ценности это не имеет. Для меня архитектура — это в первую очередь высокоуровневое распределение обязанностей между компонентами. Поэтому любые проблемы и неоптимальности на уровне API — это лишь следствие проблем с выбранной архитектурой. Ну и да, ее нужно менять в таком случае, потому что она не соответствует реальным задачам.
Re: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 29.07.16 05:01
Оценка: 5 (2) +1
Здравствуйте, IQuerist, Вы писали:

IQ>Ребята... вот эта низкоуровневая "требуха" это что ли "сервис"? Вот эти все "внутренности наружу" это инкапсуляция и архитектура?


Как мне кажется, этот момент — следствие попытки натянуть "классический" DI на все остальные области. Классический — это который пошёл от тяжёлых продуктов с продвинутым public API и поддержкой плагинов от сторонних разработчиков. Вот там возможность подсунуть нужные сервисы в код минимумом телодвижений — то, что надо.

К сожалению, DI в чистом виде абсолютно непригоден для использования в тяжёлом биз-коде. Там от DI требуется не закинуть сервисы и отдать объект, а способ протащить эти сервисы по длиннющей цепочке вызовов, причём состав зависимостей часто заранее неизвестен и определяется в рантайме. Для дотнета обсуждали вот тут
Автор: LWhisper
Дата: 30.05.16
.


IQ>Часть знакомых уверяла, что DI жизненно необходим для тестирования, но тут ситуация становилась совсем абсурдной, т.к. архитектурное решение (использовать DI) вроде как принималось, но никаких тестов при этом не было и в будущем они никогда не появлялись.

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


IQ>Как-то так... имхо главная начальная проблема DI — неспособность разработчиков создавать объектные декомпозиции.

+1, только я бы немного по-другому сформулировал. Фраза "я добавил возможность" на уровне архитектуры на самом деле означает "теперь нам всем придётся это использовать". Сам по себе DI экономит кучу времени, но только до момента, когда он не вылезает из своей родной ниши. После этого лучше смотреть в сторону других инструментов.


UPD, P.S. Не стоит налегать на SOLID как на аргумент в спорах. Его к сожалению воспринимают как волшебную палочку, хотя на практике подход "потому что SOLID" работает не лучше, чем самолёт из культа карго. Голову никто не отменял
Отредактировано 29.07.2016 5:07 Sinix . Предыдущая версия .
Re[5]: При чем тут Di?
От: 0x7be СССР  
Дата: 11.08.16 07:32
Оценка: +2 :)
Здравствуйте, IQuerist, Вы писали:

IQ>Ну уж ладно наша отрасль имхо построена таки не на людях, а на идеях. А идеи принадлежат сообществам. Так что причина должна быть в каких-то сообществах которые распространяют неполные идеи ))

Ты попробуй заставить идеи написать тебе программу без людей
Или возьми случайных людей с улицы, дай им книжку с правильными идеями и посмотри, что они тебе сделают
Re[3]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 01.09.16 15:08
Оценка: +1 -2
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Tom, Вы писали:


Tom>>Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.

·>Литров не обещаю, но возразить могу: контейнер не нужен. Накой мне жуткий монстр тащить, не надо ему ничего делегировать. Я что не в состоянии сам new вызвать в нужный момент? Просто пишется отдельный инфрасткуртурный код, который будет делать весь этот ваш wiring. А эти контейнеры не только с собой тащат всякий хлам с поддержкой всякой чёрной магии (противоречит твоему пункту 3), но ещё и в особо запущенных случаях — жуткие XML-конфиги.

Конфигов 0, не дай бог никакого XML. Магии 0. Монструозности 0. С производительность всё прелесно. Пользовать DI без контейнера конечно можно но жутко неудобно. Вы отстали от жизни.
Народная мудрось
всем все никому ничего(с).
Re[6]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 01.09.16 15:58
Оценка: +1 :))
Здравствуйте, Tom, Вы писали:

Tom>·>Это ты о чём? О каком-то конкретном контейнере?

Tom>О большинстве современных. Lightinject, DryIoc, Unity, StructureMap итп
Tom>Больше скажу, с вовременных зачастую конфигурация только через код.
Я все не смотрел, посмотрел только первый. А что именно там хорошего, современного?
container.Register<IFoo, Foo>();//я очень надеюсь, что интерфейс IFoo необязателен и регистрировать можно просто Foo.
container.Register<IFoo, AnotherFoo>("AnotherFoo"); // В самом деле? магические строки?!
var instance = container.GetInstance<Bar>();// Service Locator?!! фтопку.

container.RegisterInstance<string>("SomeValue");
var value = container.GetInstance<string>();// в контекст суём тип string?!!

Куча вредных антипаттернов, которые легко размазать по всему проекту, а обычно достаточно одного единственного constructor injection. И вычищать потом это — замучаешься.
И собственно тупой код типа:
var someValue = "SomeValue";
var anotherFoo = new AnotherFoo();
var instance = new Bar(anotherFoo, someValue);

выглядит ничуть не хуже.

Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.

Tom>Пользовать DI без контейнера конечно можно но жутко неудобно.

Зато полная поддержка компилятора и IDE. А неудобно только с непривычки.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[27]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 28.09.16 07:21
Оценка: -3
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>Нда... а вы вообще программированием занимаетесь? "то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует" компилятор по вашему конструирует объекты???

IQ>>·>Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта, и защищает доступ к приватным полям классов, не давая доступ к зависимостям, которых у тебя не предусмотрено. Тем самым в рантайме обеспечивает гарантию.
IQ>>Вероятно вы начинали с javascript...
·>Я начинал с С++, а javascript был в новинку и его обычно отключали в браузере.
·>А к чему это всё?

Это ужосъ ))) "Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта" как такое может говорить C++ программер? А ведь я в последний раз кодил на C++ 14 лет назад.

IQ>>·>Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал.

IQ>>Ну кто-то же должен, раз все остальные стыдливо молчат
·>Критиковать — пожалуйста, но критикуя — предлагай, неконструктивная критика только увеличивает невежество.

Дружища, здесь не запукинский митинг. Вы предлагаете задавать вопрос только когда известен ответ? Но базовый ответ известен всем и всегда — "контрагент идиот не желает признавать очевидного" Вспоминайте об этом каждый раз когда повторяете глупость — "критикуя — предлагай".

IQ>>·>Вместо того чтобы внести ясность, поделиться как же делать правильно, дискредитируешь хорошие техники всякими уничижительными словечками типа Colonoscopy Injection.

IQ>>Поверьте код из за которого написан пост этого стоит. Однако как правильно вы тоже так и не сформулировали
·>Как не сформулировал? Перечитай внимательно топик.
·>Подытожу: "По умолчанию используйте DI+CI везде где возможно, а где невозможно — делайте рефакторинг, чтобы стало возможно".

Таки да, это секта...
Re[23]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 14:43
Оценка: 44 (1) +1
Здравствуйте, Sinix, Вы писали:

S>·>по опыту получилось, что лучше метод с парой "лишних" параметров, которые легко анализировать в IDE и рефакторить, чем какие-то неявные зависимости, которые сложно отследить.

S>Ну так пара — оно только в простых случаях. В сложных там штук 10-15 в сумме набирается (понятно, что они оборачиваются в классы-обёртки типа MyServiceParams, чтоб не протаскивать всё по отдельности).


S>·>В сложных случаях — фабрика:

S>Угу, тем же путём шли. И вот тут у нас начинался ад. Потому что внезапно мы были вынуждены ручками повторять всю пляску с зависимостями, которую обычно за нас выполняет DI. В одном-двух местах — куда не шло, в нескольких десятках — проще протащить сервис для самого DI и не мучаться. В сотнях — надо изобретать удобное API. И тут внезапно оказывается, что по факту у нас по-прежнему service locator, только немного приукрашенный.

S>В общем, DI сам по себе не лечит проблему с кучей зависимостей, это всего лишь инструмент для явной документации этих зависимостей. Иногда это отлично и классно, как в примере с расширениями студии.

Да, зависимости волшебным образом не лечатся. Надо именно что передизайнивать систему для их упрощения. А вот SL и глобальные переменные просто заметают проблему под коврик.

S>А иногда получается, что проще оставить DI как хелпер для автоматического заполнения статически известных зависимостей, а сами зависимости протаскивать через контекст, который по факту тот же самый service locator, вид сбоку. В общем, не всё так однозначно

Но так хотя бы оно хоть как-то локализованно получается. Можно ещё что-то типа такого. Было так:
class A
{
   B b;
   void methodA()
   {
     P prm = calculateParam();
     b.methodB(prm);
   }
}
class B
{
   C c;
   void methodB(P prm)
   {// мы тут prm не используем, но его приходится протаскивать в зависимость C
     c.methodC(prm);
   }
}
class C
{
  void methodC(P prm)
  {
    use(prm);
  }
}

преобразуем так:
class A
{
    B b;
    ParamContext paramContext;
    void methodA()
    {
        P prm = calculateParam();
        paramContext.set(prm);
        b.methodB();
        paramContext.clear();// using/try-finally по вкусу
    }
}
class B
{
// теперь тут вообще тип Param не упоминается.
    C c;
    void methodB()
    {
        c.methodC();
    }
}
class C
{
    ParamContext paramContext;
    void methodC()
    {
        P prm = paramContext.get();
        use(prm);
    }
}

или даже так:
class A
{
    B b;
    C c;
    void methodA()
    {
        P prm = calculateParam();
        c.prm = prm;
        b.methodB();
        c.prm = null;// using/try-finally по вкусу
    }
}
class B
{
// теперь тут вообще тип Param не упоминается.
    C c;
    void methodB()
    {
        c.methodC();
    }
}
class C
{
    Param prm;
    void methodC()
    {
        use(prm);
    }
}

Такой миниатюрный SL по сути, притом локальный. Понятно, что тут начинают вылазить все эти проблемы которые присущи SL и глобальным переменным... но когда этих самых Param слишком много или протаскивать приходится слишком глубоко, то особо выбора нет. Хотя аккуратный wiring code может хотя бы сделать видимым, что ParamContext засовываемый внутрь A тот же что и в C.


S>·>А, ну это да, типичный DI код, плагинность тут так... сбоку. Правда я бы предпочёл Constructor-injection вместо field injection.

S>Ага. Ну эт вопрос вкуса фломастеров уже
Не совсем вкус. Field Injection создаёт лишнее состояние, когда класс уже создан, но ещё не готов к использованию. А ещё можно забыть магическую аннотацию [Import] и обнаружить это довольно поздно. Забытая же Constructor-injection обнаруживается ещё в IDE.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: При чем тут Di?
От: maxkar  
Дата: 16.08.16 20:40
Оценка: 29 (2)
Здравствуйте, Sinix, Вы писали:

S>Зависимости надо динамически разруливать, а не в момент создания сервисов.

Это очень неудачная формулировка. Она сужает взгляд на пространство возможных решений. На самом деле вам нужно полиморфное поведение в зависимости от контекста. Оно может и разруливается многими способами.

Часть вещей (вроде того же логирования и транзакций) является неотъемлемой частью контекста. Поэтому всякие логгеры как раз нормально смотрятся как часть контекста (и не надо их называть service!). Контекст — это ООП-шный объект с некоторым общим поведением. Это не "service registry" в общепринятом смысле. Набор предоставляемых услуг у него фиксирова и известен.

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

S>Т.е. нужно что-то делать с кодом типа

S>
S>var someService = GetConfirmationService(someParams.Consumer);
S>someService.PostConfirmation(....)
S>


Ну здесь все банально. Вот прямо к данному коду применяется рефакторинг "Tell, Don't ask". И получается яуже упомянутое
confirmationService.postConfirmation(someParams.Consumer, ...);


А вот про фабрику в более сложном случае я с коллегой не согласен. Все по той же причине: "Tell, Don't ask". Я использую композицию:
final class SmartConfirmationService implements IConfirmationService {
  final IConfirmationService poorManNotifications;
  final IConfirmationService premiumNotifications;

  public SmartConfirmationService(
      IConfirmationService poorManNotifications, 
      IConfirmationService premiumNotifications) {
    this.poorManNotifications = poorManNotifications;
    this.premiumNotifications = premiumNotifications;
  }

  @Override
  void postConfirmation(Consumer consumer, ...) {
    if (consumer.hasPremiumSubscription)
      premiumNotifications.postConfirmation(consumer,...);
    else
      poorManNotifications.postConfirmation(consumer, ...);
  }
}

// Somewhere in init:
final IConfirmationService smsConfirmationService = new SMSConfirmationService(gateway, ...);
final IConfirmationService mailConfirmationService = new MainConfirmationService(...);
final IConfirmationService confirmationService = new SmartConfirmationService(smsConfirmationService, mailConfirmationSerivce);


Диспетчеризация остается. Но она идет на уровне "сконфигурированных объектов". Их можно конфигурировать с помощью DI (если он, конечно, есть). Никаких lookup, используется композиция поведений. Поведение (контракты) отдельных сервисов становятся более четкими и ограниченными. И возникает задача передать все необходимые параметры в места, где принимается актуальное решение.

Для решения задчи "передачи параметров" нужно смотреть на код, использующий сервис. Потому что именно он определяет, как должен выглядеть интерфейс сервиса. Писать интерфейс сервиса по реализации — стандартная ошибка, приводящая к плохой декомпозиции сервисов. А вот заводить интерфейсы по месту "вставки реализации" — хорошая. Ну да, будет много мелких интерфейсов, будет Interface Segregation. И некоторые сервисы смогут реализовывать много интерфейсов (но не будут, много адаптеров к одному большому сервису лучше. Передача отдельных методов вместо интерфейсов еще лучше).

В исходном коде оно выглядит как-то так:
final class SomethingDoer {
  final IConfirmationService confirmationService;
  void doSomething(...) {
    ...
    confirmationService.postConfirmation(...);
  }
}


Стандартным первым шагом для этого будет "расширение" контекста. Какие правила отправки сообщений вы можете придумать? Логичны ли эти правила для контеста doing someting? Какие данные нужны? Это может приводить к избыточности. Например, для подтверждения заказа передается весь Order а не consumer. Это нормально, потому что допускает изменение реализации без изменения контракта. Ну и не завязано на отдельно взятую реализацию.

Очевидно, что угадать параметры все равно не получится. И со временем вместе с Order могут понадобиться ClientManager и т.п. Пока их мало, можно добавлять в параметры метода в интерфейсе. А потом делается очень хитрый ход. Вместо дальнейшего увеличения количества параметров, они уменьшаются до одного/двух примитивных значений — идентификаторов сущностей. А сервис учится сам ходить в базу хитрыми запросами и доставать ровно то, что ему нужно. Вот такое "переполнение" списка аргументов.

Т.е. вместо доставания параметров "сверху" дерева вызовов и передаче их через все уровни, параметры достаются "снизу". Да, это лишние запросы в базу. Это обычно не проблема, так как другие запросы худеют (тот же consumer.email не нужен 90% кода), всякие оптимизации вроде lazy дают то же количество, а навигационный доступ по entity обычно и больше запросов даст. Плюс естественными становятся и всякие "локальные" настройки вроде confirmation preferences и т.п. Они не торчат из entity. Да, после этого сервисы перестают соответствовать таблицам, ну и что? Код из
void methodA(Entity someEntity) {
  final Params params = getParams(someEntity);
  methodB(params.a, params.c, params.d, someEntity.piece);
}

methodB(int a, int b, int c, EntityPiece d) {
  methodC(a, b, c, d)
}

Превращается в
void methodA(long entityId) {
  methodB(entityId);
}

void methodB(long entityId) {
  methodC(entityId);
}

void methodC(long entityId) {
  UsedParams status = doSomeSqlQuery(entityId);
  if (status > 3)
    doSomethingWithAnotherCoolQuery(enitityId, status);
}


Возможно, вместо переноса загрузки "контекста" вниз, цепочка должна быть разрублена и вызов перенесен вверх. Обычно случается, когда в цепочке a->b->c на уровне b нарушаются абстракции. Он делает что-то, что от него не ожидается. Обычно является свидетельством неоптимальной функциональной декомпозиции. В этом случае косвенный вызов с из b заменяется на прямой вызов из A (там, где есть нужный контекст). Т.е. вместо a->b->c будет {a->b;a->c}. И в конце концов это заканчивается transaction script, что очень даже неплохо. Transaction script читается хорошо.

Опять же, на практике это часто вылиывается в "семейство" transaction script. Т.е. для похожих операциях в разных контекстах есть несколько своих скриптов с коэффициэнтом схожести от 30 до 70%. Даже не смотря на некоторое повторение, это обыно легче читать и поддерживать, чем попытки закодировать и передать информацию о контексте в сервисы.


Это все общие решения. Для выбора нужно смотреть на конкретную решаемую задачу. Я пока не видел ничего, что нельзя нормально разложить на (относительно неглубокие) сервисы. При этом, правда, они ни модели базы данных напрямую не соответствуют, ни модели данных веб-запросов. Зато они соответствуют модели выполняемых операций, что круто! Ну и на практике будет, опять же, комбинация подходов. Вроде TS, вытаскивающего много данных и распихивающего части их по высокоуровневым сервисам. Они распихивают более мелкие часть по следующему уровню. А вот уже этот третий уровень загружает еще гору данных из базы и пилит их между сервисами четвертого уровня.



Я даже знаю, откуда идет беда с фабриками и прочим. Все это потому, что разработчики считают, что нужно обязательно взять "DI Library" или даже "DI Framework". И ни один из них DI-то и не реализует! Они все — вариации на тему Service Locator. Ваш код дальше — хороший пример данного утверждения.

S>·>Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?

S>
S>[Import]
S>internal IClassificationTypeRegistryService ClassificationRegistry;

S>[Import]
S>ITextBufferFactoryService textBufferService;
S>


Это семантически эквиваленто:
internal var ClassificationRegistry = Locator.get(IClassificationTypeRegistryService.class);
var textBufferService = Locator.get(ITextBufferFactoryService.class);


Пока есть ровно одна реализация сервиса, это работает. А вот когда их становится много — нет. Как вот в моем первом примере с CompositeConfirmation. Самое интересное там — передача параметров в сам композит. Всякие хаки вроде указания имени полностью эквивалентны Locator.get(someClass, someName), что гвоздями прибивает композит к одному конкретному месту в программе. А если мне нужно несколько композитов под разные контексты? Ну можно через хитрые пляски там отдельных Locator наплодить. Но это же извращение какое-то — покласть параметры в контекст, чтобы потом их кто-то оттуда достал.

Я конфигурацию собирают в стартовом коде вручную и через constructor injection. Могу создавать произвольные графы сервисов в достаточно естественном виде. И композиции могу создать, и переиспользовать. Ни один сервис не использует "глобальные lookup id". И не использует типы в качестве этих ID (ну, чуть хитрее, для удаления boilerplate я scala implicit parameter использую)
Re[6]: О "наивном" DI и об архитектурном бессилии
От: itslave СССР  
Дата: 30.07.16 19:41
Оценка: 22 (1) +1
Здравствуйте, Sinix, Вы писали:

S>Сорри за подколку. Если серьёзно, то оформление инфраструктурного API в виде интерфейсов и DI — вещи ортогональные. К первому рано или поздно приходят во всех более-менее крупных проектах. Для второго за редкими исключениями нет никаких причин кроме как "прочитал, хочу попробовать". Тесты — это лишь отмазка и не более того. Если ваш код приходится менять именно ради тестов, то это у вас уже следствие вылезло. Первопричина в 100% случаев — бардак в проекте. Его и надо лечить.

Есть целая методология TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла, она популярная, модная, молодежная и все такое. Я к примеру несколько проектов сделал с поголовным DI и тысячами юнит тестов. Тяжеловестности добавляет(процентов 20 времени в среднем на задачу), но в общем и целом — полет нормальный.
Вот чего я не нашел пока — это каких бы то ни было метрик полезности этого хозяйства. Юнит тесты ранаются, все зелененькое. Может когда у кого из девов локально чота ломается и фиксается. В случае рефакторинга эти самые тесты пачками выкидываются и пачками же переписываются. Но вот как понять, насколько оно себя оправдывает — неясно.

S>Так тут тоже путаница с терминологией Давайте не путать интеграционные тесты (всё то же тестирование API, только на уровне крупных блоков, а не отдельных типов) и автотесты/ui-тестирование (aka blackbox testing — используем исключительно публичные интерфейсы продукта, UI — если ничего другого нет). Вы пишете про второе, я — про первое

Я не путаю, автотесты — это подвид интеграционных тестов
Но ок, давай про крупноблочные тесты.
Тут есть 2 засады:
— БД. Она должна быть, в ней должны быть подготовлены корректные данные для каждого теста. Их надо корректно инсертать и чистить. Это все время. При паре тысяче тестов время выполнения может лихко затянуться на полчаса, что очень нехорошо. Кроме того зачастую очень легко устроить race conditions при параллельном запуске тестов — передерутся из-за данных в базе, что в свою очередь может вынудить запускать их последовательно, что опять таки бьет по времени исполнения.
— Конфигурация. Если тестировать большую подсистему, то для прогона типичного сценария надо исполнить танец нанайских мальчиков инициализации системы. Зачастую это больно и тяжело. А если внутри используются переменные типа HttpContext.Current или же DateTime.Now, то вечер перестает быть томным — проинициализировать их корректно больно, неприятно и не всегда возможно.
Отредактировано 30.07.2016 19:43 itslave . Предыдущая версия .
Re[6]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 21.09.16 09:33
Оценка: 9 (2)
Здравствуйте, fddima, Вы писали:

F> Update: Кстати, есть один немаловажный момент, — если система (программный комплекс) предполагает долгую жизнь, то интеграционные тесты (в случае их хорошего исполнения) позволяют полностью абстрагироваться от конкретной базы кода (понятно, что если это позволяет предмет, и в необходимых количествах), что сыграет наруку в будущем.

Интеграционные и юнит-тесты друг-друга не заменяют. Оба вида нужны и важны.
У меня был опыт в образцово-показательном проекте где было то, и то.
Юнит-тестов было несколько десятков тысяч, выполнялись они за 1-3 минуты на машине разработчика, поэтому перед коммитом они прогонялись всегда. Большее число багов отлавливалось именно ЮТ.
Интеграционных было около тысячи. Выполнялись они около 20 минут, обычно разработчики их запускали выборочно, лихорадочно правя если что-то поломалось в CI.
Ещё были функциональные тесты (которые ты называешь интеграционными), абстрагированые от базы кода, т.е. взаимодействуют с системой по тем же каналам, что и реальные клиенты — WebUI, REST, FIX, sockets, etc. Вот их было около восьми тысяч и выполнялись они около 20 минут на кластере из ~150 машин. Выполнить все на машине разработчика — нереально. Поэтому без предварительного багофильтра в виде ЮТ и ИТ они бы вечно были красными и бесполезными. А так падение ФТ в CI было событием, если в течение 5 минут поправить ошибку не можешь, твой коммит ревертят.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: О "наивном" DI и об архитектурном бессилии
От: Слава  
Дата: 28.07.16 22:18
Оценка: +2
Здравствуйте, IQuerist, Вы писали:

IQ>Как-то так... имхо главная начальная проблема DI — неспособность разработчиков создавать объектные декомпозиции. Это ведет к созданию абсолютно неправильной, очень низкоуровневой и хрупкой системы зависимостей нарушающей 4 из 5 принципов SOLID. Пример того, как некоторые пытаются лечить гланды через задний проход. Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.


Напишите на Reddit, только чуть более подробно. Как именно набивают шишки, какая декомпозиция правильная, а какая — нет, с примером. Не обязательно правильным, даже наборот, если будет криво — тем лучше для холивара. Выражение Colonoscopy Injection следует вынести в заголовок статьи, термин у вас получился совершенно убойный. Даже если со статьей не согласятся, термин пойдет в народ и DI будет надежно обгажено, туда ему и дорога.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 07:16
Оценка: :))
Здравствуйте, LaptevVV, Вы писали:

IQ>>Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.

LVV>Перевод гугля совершенно "убойный"...
LVV>Колоноскопия Инъекции
LVV>
LVV>Кстати, давайте уж сразу русское токование...

Шарман... мы с вами интелегентные люди оставим "русское токование" для совещаний и разбора полетов
Re[4]: О "наивном" DI и об архитектурном бессилии
От: Lexey Россия  
Дата: 29.07.16 12:00
Оценка: +2
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Например как альтернатива serivce locator. В более общем виде — dynamic scoping.


Service Locator — это не альтернатива, а вариант реализации DI. Контексты, в общем-то, тоже.
Re[6]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 01.08.16 05:44
Оценка: +1 :)
Здравствуйте, _hum_, Вы писали:

__>Здравствуйте, IQuerist, Вы писали:


IQ>>Здравствуйте, _hum_, Вы писали:


__>>>а какая, на ваш взгляд, тогда правильная методология разработки — сперва не думать про DI, и только по прошествие времени, когда система обретет очертания, уже начинать продумывать, что стоит отделять в качестве целостных самодостаточных зависимостей?


IQ>>Думаю да, инструменты и механизмы надо использовать по мере необходимости, а не потому, что так модно.


__>так это верно для любого случая. почему вы выделили именно DI?


Потому, что про него пост. Вы можете написать пост о любом другом случае.

__>>>кстати, в той же wiki указаны недосатки (наряду с достоинствами), в том числе и те, о которых вы говорите: Dependency_injection_frameworks


IQ>>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.


__>на что все-таки логическое ударение — на "маниакальная страсть к IOC" или на "ранее внедрение DI"?


логическое ударение на непонимание того, какие проблемы инструмент решает.
Re: О "наивном" DI и об архитектурном бессилии
От: Visor2004  
Дата: 09.08.16 21:24
Оценка: +2
Здравствуйте, IQuerist, Вы писали:

IQ>имхо совершенно очевидно, что наивный сервис слепленный из хелперных методов DAL, ни в коем случае не является "абстракцией". Он предельно конкретный с предельно конкретными entity типами даже если структура этих типов продублирована, а данные копируются с помощью мапперов (эдакий карго-культ "абстрации"). Имхо здесь совершенно четко определяемая проблемы — интерфейсы верхних уровней начинают определять низкоуровневые интерфейсы DAL. Разрозненные хелперные методы не перестанут быть хелперными методами от того, что их вызывают через интерфейс.


И каким же образом он эту концепцию нарушает? BoringItemDataReader небось нужна какая-то конфигурация, ConnectionString, например, а то и IDbContext для стабильной работы, который обычно имеет свое время жизни и правила создания/освобождения и доступен как часть подсистемы, которая хранит настройки, т.е. отдельный сервис в вашей терминологии. Так же может легко еще зависеть от 2-3 абстракций, кэша например и т.д. Мне доводилось видеть поделки людей, которые считали, что для реализации инфраструктуры проекта хватит 10 классов хелперов и все будет ништяк, заканчивалось еще хуже, чем переусложенное новичками DI.
Помните!!! ваш говнокод кому-то предстоит разгребать.
Re[9]: При чем тут Di?
От: 0x7be СССР  
Дата: 11.08.16 11:56
Оценка: +1 :)
Здравствуйте, IQuerist, Вы писали:

IQ>Я кстати тоже Какой смысл делать инвестиции в заведомый г...код.

Очень простой. Если ты знаешь, что этот г-код тебе принесет деньги, то почему бы и нет?
Re[15]: О "наивном" DI и об архитектурном бессилии
От: Sinclair Россия https://github.com/evilguest/
Дата: 30.08.16 15:20
Оценка: :))
Здравствуйте, IQuerist, Вы писали:

IQ>У меня был знакомый, тестировщик от рождения, в его руках софт просто горел аццким пламенем "общение" с ним, когда он просто рвал, уже многократно оттестированный UI на части, вызывало бессильную ярость и преклонение перед гениальностью одновременно.

Этот
Автор(ы): Антон Злыгостев aka Sinclair
Дата: 24.06.2004
Этот четверг ничем не отличался от обычных. Часов с 12 я начал испытывать просто нестерпимое желание найти повод поотлынивать. Поэтому когда в аське всплыл вопрос шефа "Не хочешь пособеседовать тестеров?", я долго не думал...
?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[10]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 02.09.16 12:48
Оценка: +2
Здравствуйте, Tom, Вы писали:

Tom>·>SL. В подавляющем числе случаев он не нужен. Проблема — он делает зависимости неявными.

Tom>? Что такое SL?
Service Locator.

Tom>Абсолютно согласен, зло злейшее. В 99% только Constructor Injection. Правда есть пару случаев когда из за "чужёго кривого дизайна" приходится использовать property injection но это исключение.

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

Tom>Да конечно надо как то регистрации отличать друг от друга и ничего проще строк тут нету. Что бы эти строки перестали быть магическими — вынеси их в константу и используй эту константу как при регистарции так и при резолве.

А зачем тебе их по строкам отличать? Зачем их вообще отличать? Есть две ситуации.
Первая cитуация, у тебя действительно два инстанса и ты разные инстансы используешь в разных частях программы с разными целями. Ну например, DbConnection для основной БД и для отдельной БД для аудита, например. В этом случае тебе строки не нужны. В случае ручного связывания у тебя вместо строк это будет именем поля или локальной переменной.
Вторая ситуация, у тебя действительно несколько инстансов и их нужно как-то определять в рантайме в зависимости от каких-то данных. Ну например, найти инстанс какого-нибудь класса по фрагменту URL. В этом случае следует использовать не "ничего проще строк нету", а соответсвующий бизнес-требованиям тип — UrlFragment, enum, етс. Пихать везде строки — плохой стиль.

Tom>·>Сканирование сборок. В подавляющем числе случаев он не нужен. Доставляет столько удовольствия исследовать что куда залетело и почему. Притом это можно исследовать только на запущенной системе в данном (часто prod) окружении.

Tom>Ничего не понимаю что куда залетело. В общем случае фича которая называется auto wire работает прекрасно. Регистрируешь только то что отличается от принятых в контейнере конвенций.
Я о http://www.lightinject.net/#assembly-scanning , а ты о чём?

Tom>·>Циклические зависимости. С DI+CI сделать цикл невозможно. Заставляет аккуратнее подходить к архитектуре приложения, а не всякие lazy/PI, которые тебе циклы создадут на ура.

Tom>Эммм а где антипаттерн? И причём тут контейнеры с DI. Если у тебя циклические зависимости то это проблема не контейнера а проблема твоего дизайна. Но даже в этом случае контейнер может подставить тебе плечо, ты можешь резолвить Lazy<T> и фактически резолв будет сделан в момент использования.
Циклические зависимости делать не надо. Никогда. А если это действительно неизбежно — это должно быть сложно и сразу явно видно. Ты можешь случайно добавить незаметив, а контейнер тебе всё сам свяжет и не пикнет, втихую добавив +100 к техническому долгу. А потом эту вязанку развязывать.

Tom>На стадии проектирования интерфейса и своей реализации интерфейса ты НЕ знаешь будут ли другие реализации которым может потребоваться очистка ресурсов. Это основная идея. В случае исполдьзования контейнера, обычно, на запрос создаётся так называемый child container который разрушается при окончании обработки запроса и который при разрушении вызовет Dispose у обьектов которые были в нём зарезолвлены. Причём он вызовет Dispose естественно вне зависимости от того унаследован интерфейс от IDsiposable или нет. В случае когда у тебя контейнера нет тебе надо либо самому писать такой функционал но это не возможно так как без контейнера нет единственного класса который контролирует время жизни всех обьектов. Либо наследовать интерфейс от IDisposable в тех местах где ты предпологаешь в реализациях может понадобится очистка ресурсов, но это жутко криво ибо во первых ты по сути не должен знать и не знаешь где очистка может понадобится а во вторых сам факт наследования от IDisposable это ад адский.

public class RequestModule и пусть он и управляет временем жизни создаваемых им IDisposable-ы ровно так как надо, а не универсальный всемогутер, который делает какую-то неявную магию.

Tom>>>Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.

Tom>·>Но это всё не надо использовать. Контейнеры можно использовать для каких-то сложных случаев, только в довольно маленьком чётко отделённом контексте, в плагинном менеджере каком-нибудь например. Но пихать везде — антипаттерн.
Tom>Так, то что это вдруг антипатотерн — это придумал ты. Основная масса современных разработчиков с этим не согласна
Я знаю. Сам таким был.
Потом попал в компанию, где история развития была такая: "что попало как попало" -> "монстр Spring Framework" -> "модный Guice" -> "DI, plain Java code". По началу тоже возмущался отстутсвием "современного" контейнера, а потом осенило.

Tom>·>Нет, просто пишешь классы-модули, которые делают wiring тестируемых поддеревьев зависимостей. И тестируешь именно их. Иначе интеграционные тесты тестируют тестовый wiring.

Tom>О чём и речь, без контейнера тебе надо собирать деревья зависимостей руками. Зачем это делать если это умеет делать контейнер.
Дерево зависимостей довольно сложная, но важная вещь. Оно не только является некого рода документом, описывающим высокоуровневую архитектуру, но и сдерживающим фактором говнокодинга. Если у тебя это самое дерево руками получается делать плохо, слишком сложно, непонятно, значит ты делаешь что-то не то, остановись, подумай — сделай проще. А контейнер эту всю сложность прячет под коврик и через какое-то время кроме как автоматически это дерево не строится. Контроль над сложностью потерян, значит без бутылки человек уже не разберётся что куда откуда.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 21.09.16 08:13
Оценка: +1 -1
Здравствуйте, IQuerist, Вы писали:

Проекты с DI, дебажить сложно и в них сложно разбираться.
Понаписывают рантайм подмену интерфесов, но на практике вообще не встречал что бы в рантайме делали подмену одних сервисов на другие. Подмену можно было сделать напрямую в коде без всякого DI.
DI однозначно отлично подойдет для приложений где приложение устанавливается к потребителю локально и потребитель сам пишет для себя плагины, исспользуя указанное апи. (вариант: приложение — это веб сервик к которому пишут плагины сторонние люди, отпадает по секурити.)
Для сервисной архитектуры, по тестам: нафиг моки. Только усложняют жизнь и вводят в заблуждение. Надо тестировать на реальных данных, тестируя реальный код, а не код с костылями и бинтами. Сгенерил бд с тестовыми данными со скриптов. Прогнал по юнит и интеграционным тестам, почитал логи — увидел что апи соответствует спеки и норм.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[2]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 21.09.16 09:04
Оценка: +1 -1
Здравствуйте, #John, Вы писали:

J>Проекты с DI, дебажить сложно и в них сложно разбираться.

J>Понаписывают рантайм подмену интерфесов, но на практике вообще не встречал что бы в рантайме делали подмену одних сервисов на другие. Подмену можно было сделать напрямую
Я не понимаю, где этот источник невежества? Удивительно, что ты не первый это несёшь. Каким образом DI связанно с интерфейсами? Каким образом DI связан с runtime-подменой? Ведь даже если взять wiki, там ничего такого нет.
Вот ты лично об этом откуда узал, что для DI нужны интерфейсы или runtime-подмена?

J> в коде без всякого DI.

Как именно?

J>DI однозначно отлично подойдет для приложений где приложение устанавливается к потребителю локально и потребитель сам пишет для себя плагины, исспользуя указанное апи. (вариант: приложение — это веб сервик к которому пишут плагины сторонние люди, отпадает по секурити.)

Так DI или контейнеры?

J>Для сервисной архитектуры, по тестам: нафиг моки. Только усложняют жизнь и вводят в заблуждение. Надо тестировать на реальных данных, тестируя реальный код, а не код с костылями и бинтами. Сгенерил бд с тестовыми данными со скриптов. Прогнал по юнит и интеграционным тестам,

Такие тесты как правило трудно-подъёмные, медленные и плохо локализуют ошибку. Но такие тесты тоже нужны.
И вообще, юнит-тесты это больше инструмент разработки, а не контроля качества.

J>почитал логи — увидел что апи соответствует спеки и норм.

Что ещё за логи??
У правильного теста два состояния: pass/fail.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 21.09.16 14:31
Оценка: +1 :)
Здравствуйте, #John, Вы писали:

J>·> Каким образом DI связанно с интерфейсами?

J>DI — это же, у нас есть конструктор, который в параметре принимается интерфейс/класс, а после исспользует его методы. А дальше мы пишем код: если класс в конструкторе принимает такой-то класс, то заменика ты нам в такой-то момент времени, это класс на вот этот.
И где ты об этом прочитал? Можно ссылочку?

>>>Каким образом DI связан с runtime-подменой?

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

J>·>Вот ты лично об этом откуда узал, что для DI нужны интерфейсы или runtime-подмена?

J>Вот видел как его в проектах применяли не для подмены в рантайме. Но оно его подменяло как раз в рантайме.
Кто на ком стоял? Можно пример?

J>>> в коде без всякого DI.

J>·>Как именно?
J>Не применять насследование вообще.
Оппа. Теперь ещё и наследование к DI приплели. ОТКУДА ЭТО ВСЁ БЕРЁТСЯ?!

J>только фукнциональщина. Хз. почему но в последнее время замечаю чем меньше в коде ооп,(вместо наследования — вложенные объекты). Тем код становится более гибким и адаптируемый под измечивые требования заказчика.

А ещё у меня сегодня поезд задержали, пришлось с пересадкой ехать. Явно всё из-за DI. Как там бузина в огороде?

J>·>Что ещё за логи??

J>Можно тестировать апи так: скрипт посылает json на /api/user/dropbyme, получает json.
J>И приложение все http request|responce сливает в лог файл. Иногда туда попадают ошибки, связанные с добавлением нового функционала.
Тесты значит кривые. Падать тесты должны, а не то что кто-то случайно заметил неожиданную ошибку в логе. Как вообще в гигабайтных логах можно что-то заметить — непонятно.

J>Или напр. когда мануально тестят тоже можно в логах увидеть где произошла ошибка, разобрать лог, пересоздать бд с данными, запустить скрипт для тестирования метода, послать туда данные из лога и восспроизвести ошибку.

Обычно логи читают когда тест упал и разбираются в причине. Или, иногда, когда пишут новый тест. Зачем читать логи после прогона тестов?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[2]: О "наивном" DI и об архитектурном бессилии
От: Dziman США http://github.com/Dziman
Дата: 27.09.16 17:49
Оценка: +1 -1
Здравствуйте, IQuerist, Вы писали:

IQ>Мое имхо по итогам обсуждения поста:

IQ>Ребята это секта...
Тебя уже два месяца просят раскрыть им глаза и показать как же надо, но гуру так и не снизошол
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[17]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 09:31
Оценка: 22 (1)
Здравствуйте, IQuerist, Вы писали:

IQ>>>Вам не в комментах стоит холиварить, а свой собственный пост запилить об абсолютной святости DI,

IQ>·>Об абсолютной святости ты сам досочинил. Я утверждаю лишь что уж пусть будет гкод с DI, чем гкод без DI.
IQ> Для обоснования своей позиции я написал целый пост. Для обоснования своей вы не написали и одной полной строки. Несимметрично.
Я уже написал достаточно в этой ветке. Ты правда считаешь, что имеет смысл накопипастить новый пост?

IQ>В последнее время, мне как раз попадались реализации big ball of mud исключительно с DI

Так повезло, видимо, найди нормальную работу. Но с чего ты взял что BBoM с global variable или с service locator будет хоть чем-то лучше?

IQ>global variable и service locator и что в них плохого на ранних этапах развития проекта?

Тем что это типичный technical debt. Если, конечно, не писать проекты-однодневки (а с ними всё просто — пиши как хочешь, всё пофиг), то потом от них придётся избавляться, что всегда довольно болезненно: рефакторить DI проще, чем GV или SL.
Кстати, SL и реализовывать сложнее чем DI.

Кстати, вот это:

Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры".

тоже не понимание предмета. Вот как раз SL лучше подходит для плагинной архитектуры, особенно когда связывание происходит runtime.
А как ты реализуешь плагины с DI?

Далее:

Модули верхних уровней не должны зависеть от модулей нижних уровней

только именно так и получится сделать если использовать только DI с Constructor Injection. Ибо ты просто не сможешь создать объекты если уровни смешиваются. DAG, однако. В случае с GV и SL — легко получается месиво зависимостей всего от всего, которое потом фиг распутаешь.

IQ>Вы забыли оператор new забанить, он же главный источник неуправляемых связей.

Что значит забанить? В DI он не банится, а переносится наружу, в wiring-код.

IQ>>>и приложенными enterprise проектами

IQ>·>Ага, ты значит запилил пост с какой-то лажей из пяти строк, а с меня enterprise проекты требуешь.
IQ>Ну вы то пока даже с "лажей" поста не запилили, одно нытье и литании.
Да о чём тут пилить-то? Прочитай ту ссылку на вики с DI Examples, там всё вроде понятно.
Если нужен код, возьми свой и выкини интерфейсы:
public class HomeController : Controller

    public HomeController(
        BoringItemDataReader,
        BoringItemDataWriter,
        BoringItemChildDataReader,
        BoringItemChildDataWriter,
        AppDataJsonConverter,
    ...
)
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[6]: О "наивном" DI и об архитектурном бессилии
От: Lexey Россия  
Дата: 21.09.16 09:42
Оценка: 14 (1)
Здравствуйте, fddima, Вы писали:

F> Я извиняюсь, что подымаю старую тему. Но в случае юнит-тестов — ситуация — все тесты зеленые, а оно не работает — вполне себе. А в процессе пуско-наладки оно не работает и как выясняется — работать не могло, по причине, например отсутствия самого важного куска в SQL процедуре.


Ну, это банальщина. На такую фигню, как процедуры в базе, можно и юнит-тесты написать.
В моем примере все намного веселее: нужно активно взаимодействовать с промышленной установкой, которая делается партнерами в единичном экземпляре под конкретного заказчика. Аналогичный стенд для тестирования сделать просто невозможно, ибо установка стоит дофига, плюс количество ее компонентов и система автоматики меняется от поставки к поставке. Сильно упрощенный программно-аппаратный эмулятор есть, но он покрывает очень ограниченное число вариантов. Вот и получается, что создать среду для полноценных интеграционных тестов просто невозможно.
Re[22]: При чем тут Di?
От: Sinix  
Дата: 17.08.16 06:18
Оценка: 8 (1)
Здравствуйте, maxkar, Вы писали:

M>Это очень неудачная формулировка. ... Часть вещей (вроде того же логирования и транзакций) является неотъемлемой частью контекста. Поэтому всякие логгеры как раз нормально смотрятся как часть контекста (и не надо их называть service!). Контекст — это ООП-шный объект с некоторым общим поведением. Это не "service registry" в общепринятом смысле. Набор предоставляемых услуг у него фиксирова и известен.


Ну так это ещё более неудачная формулировка, по крайней мере для шарпа. Потому что вместо классического "нет реального сценария использования — все теоретические изыскания идут лесом" мы переходим к "пофиг на реальную проблему, зато по канону(tm)". Последнее — эт скорее к яве, там такое очень одобряется.

Почему на реальный сценарий пофиг? Так твои советы не подходят. У контекста нет поведения, он по определению иммутабельный (хотим предоставить другой набор сервисов — подменяем контекст) и может предоставлять как захардкоженные зависимости, так и определяемые в рантайме. Иначе начинается разброд: часть передаём через контекст, часть — через DI. Фу-фу-фу



M>Ну здесь все банально. Вот прямо к данному коду применяется рефакторинг "Tell, Don't ask". И получается яуже упомянутое


Ну так это ж зло в чистейшем виде. Вместо явного разделения ответственностей (вся инициализация — в одном методе) у нас получается мешанина из
* Собственно реализаций
* Обёртки SmartConfirmationService,
* Подменяемой фабрики, которая и будет выбирать конкретную реализацию. Чтобы не делать копию SmartConfirmationService для другого метода, скажем, для GetAdvancedConfirmationService

Вот этот подход "мы не смотрим на реальную проблему, мы можем в паттерны" изначально порочен, т.к. он приводит к дикому переусложнению кода на ровном месте. На этом же примере объясню.

Помимо нагромождения типов у нас есть ещё один косяк: мы продлеваем время жизни зависимостей — в оригинальном коде Consumer был нужен только для получения конкретной реализации, дальше можно передавать только саму реализацию.
У тебя consumer-а приходится протаскивать дальше. Ок, запоминаем consumer через конструктор SmartConfirmationService.
Всё? Нифига: у нас баг: consumer мутабельный, если его изменить, то внезапно приходит не тот сервис.
Ок, определяем нужный сервис сразу, в конструкторе... и мы оказались в идиотской ситуации: переусложнённый код, который по сути прячет вызов GetConfirmationService внутрь отдельного объекта. Зашибись архитектура.

Всё та же проблема мангустов в почтовом ящике
Автор: Sinix
Дата: 01.06.14
, угу.


M>А вот заводить интерфейсы по месту "вставки реализации" — хорошая. Ну да, будет много мелких интерфейсов, будет Interface Segregation.

Ну да, вот именно про это я и говорил. Аккуратно продумать API — нет, допиливать "правильный" код обёртками по месту, даже ломая архитектуру — да. Не, эт вопрос вкуса конечно, поэтому даже спорить не буду

M>А потом делается очень хитрый ход. Вместо дальнейшего увеличения количества параметров, они уменьшаются до одного/двух примитивных значений — идентификаторов сущностей. А сервис учится сам ходить в базу хитрыми запросами и доставать ровно то, что ему нужно. Вот такое "переполнение" списка аргументов.


Вот это не просто зло в чистом виде, а прям ректификат. Без комментариев, сорри.
Re[7]: О "наивном" DI и об архитектурном бессилии
От: fddima  
Дата: 21.09.16 10:45
Оценка: 8 (1)
Здравствуйте, Lexey, Вы писали:

L>Ну, это банальщина. На такую фигню, как процедуры в базе, можно и юнит-тесты написать.

Можно теоретически. На практике под капотом интерпретатор поданных аргументов в зависимости от настроек в БД и фаз лун. А логика размазана для неподготовленного чела по 10/100mb sql сорсов (два проекта с которыми я работал), в реальности конечно если знать где искать, — тысяч 20 строк sql лапши (sp, триггеры, кучи таблиц, я имею ввиду которые учавствуют), в которой можно разобраться — но по факту — задача невыполнима в разумные сроки. Реверс кода быстро показывает, что он делает что-то именно так — проверку например по незадокументированному флагу. Опечатка ли, так задумано и лог VSS — ясности не приносит, спросить не у кого. Можно просто заниматься реверс инжинирингом для написания тестов, но совершенно не прогрессировать в бизнес задаче и в тестах, т.к. что бы сделать тесты — придется понять задачу и... Ну вот и поди реши что писать и на что хватит сил.
Я собственно говорю, что когда коду более 10 лет — он легко обрастает потом и кровью добытыми фичами, и естественно — не всегда об этом известно. Написали юнит — хорошо, но и мешаться они не должны.
Понятно, что это пожалуй единичные случаи. Тем не менее, — для простых процедур никогда не было необходимости в тестах.

L>Вот и получается, что создать среду для полноценных интеграционных тестов просто невозможно.

Да, это интересно. Ну, специфика... что ж поделать. Я и не говорил что "мой" путь единственно верный. Опять же, не поварившись в проекте — не знаешь слабые (и необходимые для тестов) места и/или подход. Ну а покрывать все — по мне — расточительно. Опять же — вопрос в допустимых затратах и доступных (человеческих и временных) ресурсах. Да и вообще были ли тесты или поле непаханое.
Re[18]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 26.09.16 13:09
Оценка: 8 (1)
Здравствуйте, IQuerist, Вы писали:


IQ>Что за ужосы??? Какие камменты? ServiceLocator.GetCurrentUserInfo

Я вот тут хорошее объяснение окнопал на пальцах и с картинками почему этот твой подход говно:
http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
Ну и вывод совпадающий с моим:

The compiler can offer both consumers and producers so much help when Constructor Injection is used, but none of that assistance is available for APIs that rely on Service Locator.


Собственно, прежде чем отвечать на предыдущий пост ознакомься с этой статьёй и пиши возражения по делу, если есть.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 22.09.16 12:46
Оценка: 4 (1)
Здравствуйте, #John, Вы писали:

J>·>И какой тут смысл создавать инстанс UserService? Чем UserService.Save со статическим методом хуже?

J>Вообщем-то можно и статические методы исспользовать.
Зачем тогда классы вообще существуют?..

J>ConnectionParams ему можно передать из Singleton объектов.

Хррр. Имхо, это даже хуже чем IoC-контейнер.

J>·>Т.е. у тебя все зависимости будут синглтонами. Правильно понял? Жуть же. Типичный спагетти-код и радости дебага правильности порядка инициализации синглтонов.

J>Есть такое.
И ещё получается такой некий твой "class Settigs", который зависит от всего и все от него зависят.
Собственно IoC-контейнер позволяет этим хоть как-то рулить. Синглтоны однозначно в топку.

J>·>Почему редко такой код встречается?..

J>А если в классе UserService в методе Save для бизнес логики надо исспользовать разные *Managers,
J>а в методе Delete еще более разные(UserProfileManager, AcitvityManager и т.д.).
J>Передавать в UserService(FabricOfManagers fabric) — фабрику классов со всеми менеджерами?
Нет. Просто передаёшь всех менеджеров в конструкторе.
UserService(UserProfileManager, AcitvityManager, SomethingManager, ...)
Да, конструктор _может_ получиться с тучей аргументов, но зато сразу видно что именно требуется для функционирования данного класса, тебе не нужно читать код каждого отдельного метода чтобы выяснить а что же этот конкретный метод в этой ветке if-условия решил вытянуть из глобального Context.Current. И, более того, это всё проверяется на этапе компиляции, все зависимости обеспечены, плюс IDE помогает с навигацией по коду, find usages, go to declaration и прочим.
Далее, если у тебя таки получается класс у которого очень много зависимостей это сразу явно видно по его конструктору. Это просто значит что данный класс превращается в Универсальный Всемогутор (https://en.wikipedia.org/wiki/God_object) и требуется рефакторинг: пилишь компоненты по зависимостям так, чтобы уменьшить максимальную валентность графа зависимостей.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: О "наивном" DI и об архитектурном бессилии
От: Cyberax Марс  
Дата: 15.08.16 10:37
Оценка: 2 (1)
Здравствуйте, IQuerist, Вы писали:

C>>Тесты значительно СНИЖАЮТ стоимость разработки как раз из-за этого. Программист после небольшого изменения не ждёт конца интеграционных тестов, а сразу запускает локальные юнит-тесты с mock'ами. Конечно, они не идеальны, но находят процентов так 95 рутинных ошибок времени разработки.

IQ>Какие-то вы фантастические вещи рассказываете. Вы в какой области работаете?
Я внутри Amazon'а работаю в облачных вычислениях. Самый эпицентр service-based архитектуры, можно сказать. Языки разработки — Java и производные от неё.
Sapienti sat!
Re[15]: О "наивном" DI и об архитектурном бессилии
От: ilvi Россия  
Дата: 31.08.16 03:42
Оценка: 2 (1)
Здравствуйте, ·, Вы писали:

·>А если по сути...

·>Во-первых, фраза "только юнит тесты и никаких ручных тестов" показывает как минимум непонимание терминологии, а чаще — непонимание темы вообще. Хинт: бывают не ручные UI-тесты, а бывают ручные юнит-тесты.
·>Во-вторых, ты правда считаешь, что из этой информации правда достаточно для именно такого мнения? Ведь существует столько причин ведущих к плохому качеству продукта, но ты сразу делаешь однозначный далеко идущий вывод. Откуда такое предубеждение к тестам?
·>В-третьих, а это точно именно амазоновский продукт был? Купили очередной стартап, и слепили что получилось из того что досталось побыстрому. Что не удивительно для очередного плеера, с облачными вычислениями мало что общего.

3) Именно амазоновский, общался непосредственно с командой его разрабатывающей. Для самого показа видео они использовали сильверлайт, все остальное амозоновская инфраструктура по предоставлению самого видео.
2) У меня нету предубеждения перед тестами, у меня есть предубеждение перед людьми, которые считают, что юнит тесты могут заменить хорошую команду QA. Дополнить могут, но вот заменить — мое мнение нет.
1) Я знаю про автоматизированые тесты, но давать их писать разработчику, это тоже самое что давать тестировать разработчику. Он будет тестировать то что он написал, а это может быть немного не то что требовалось.

Мое мнение, что все типы автоматизорованых тестов это очень хорошо, но не надо при этом сводить команду QA до нуля.
... << RSDN@Home 1.0.0 alpha 5 rev. 0>>
Re[4]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 08:04
Оценка: :)
Здравствуйте, vsb, Вы писали:

vsb>Но ведь юнит-тестирование это стандарт-де факто в современном софтостроении. Писать софт без тестов это как пользоваться винраром для контроля версий.


юнит-тестирование это не стандарт, а всего лишь инструмент. Стандартом он никогда не станет, т.к. к нему не применимы критерии оценки.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 12:54
Оценка: :)
Здравствуйте, _hum_, Вы писали:

__>так все-таки, какая основная мысль вашего поста — что бездумное использование DI — типичная ошибка неумелого архитектора, или, что сам паттерн переоценен?


Думаю общая проблема в другом. DI стимулирует неопытных разработчиков городить непродуманные и хрупкие абстракции на ранних стадиях проекта причем там где их нет и быть не может (т.к. в первую очередь они создают DAL), нарушая принципы SOLID. Эти хрупкие абстракции начнут сильно мешать при построении бизнес логики, когда сил и энтузиазма будет уже не так много. А когда еще и сроки начнут поджимать, то бизнес логика оказывается в самом плачевном состоянии.

И как справедливо написали в камментах:

>>>В случае с невменяемым DI получается, что конфигурация заменяет архитектуру.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Evgeny.Panasyuk Россия  
Дата: 29.07.16 18:01
Оценка: +1
Здравствуйте, Lexey, Вы писали:

L>ИМХО, DI-контейнеры — это все-таки весьма частный случай DI, а не его родная ниша. Простейший DI (в виде передачи функции или объекта в другую) существовал задолго до того, как начали массово лепить контейнеры везде, где только можно (и чаще всего не нужно). Только никто его так не называл.


+1
Видимо "параметр" звучит недостаточно солидно и паттерново
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Vladek Россия Github
Дата: 29.07.16 21:16
Оценка: +1
Здравствуйте, Lexey, Вы писали:

L>ИМХО, DI-контейнеры — это все-таки весьма частный случай DI, а не его родная ниша. Простейший DI (в виде передачи функции или объекта в другую) существовал задолго до того, как начали массово лепить контейнеры везде, где только можно (и чаще всего не нужно). Только никто его так не называл.


Обобщающий термин — инверсия управления.

https://ru.wikipedia.org/wiki/%D0%98%D0%BD%D0%B2%D0%B5%D1%80%D1%81%D0%B8%D1%8F_%D1%83%D0%BF%D1%80%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D1%8F
Re[7]: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 31.07.16 08:32
Оценка: +1
Здравствуйте, itslave, Вы писали:

I>Есть целая методология TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла, она популярная, модная, молодежная и все такое.

Она отлично работает для инфраструктуры, почти для любого масштаба, неплохо работает для мелочёвки и абсолютно не работает даже для средних проектов. Чтоб было понятно, что такое средний проект: представь себе типовой биз-кейз в виде 20-страничного документа 12 шрифтом, в котором 90% текста — не вода, а логика, причём высокоуровневая, без расписывания до отдельных инструкций. Представь объём кода для этого документа и умножь этот код на 5 — получишь самый минимум для тестов. И теперь контрольный в голову — таких кейсов несколько десятков на каждого разработчика. TDD сам по себе в таких условиях не катит.

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

I>Я к примеру несколько проектов сделал с поголовным DI и тысячами юнит тестов.

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

I>Но вот как понять, насколько оно себя оправдывает — неясно.

Так у вас сам код, получается, особой ценности не имеет. В смысле, его можно переписать, не заморачиваясь с совместимостью. Это немножко обесценивает тесты, да.
А вот когда упавший тест показывает, что мы поломали поведение и это поймано на самом раннем этапе, ещё до коммита кода — вот это приятно.



I> — БД. Она должна быть, в ней должны быть подготовлены корректные данные для каждого теста. Их надо корректно инсертать и чистить. Это все время. При паре тысяче тестов время выполнения может лихко затянуться на полчаса, что очень нехорошо.

Ну так это обязательно, особенно если запросы нетривиальные, какие ещё варианты-то?

Отлично работает комбинация CI-сервер + SSD + MS SQL Dev edition. Минуты, но никак не полчаса. Иначе уже есть повод профилировать и убирать узкие места. Ну и тысяча интеграционных тестов — это уже много. По соотношению к простым юнит-тестам их обычно хорошо если 1 к 20.


I> Кроме того зачастую очень легко устроить race conditions при параллельном запуске тестов — передерутся из-за данных в базе, что в свою очередь может вынудить запускать их последовательно, что опять таки бьет по времени исполнения.

Ну да. Исхитриться можно с разбиением по группам, но какая альтернатива-то?


I> — Конфигурация. Если тестировать большую подсистему, то для прогона типичного сценария надо исполнить танец нанайских мальчиков инициализации системы. Зачастую это больно и тяжело.

Не, эт тяжело только на первых порах, затем решается тем или иным способом. Для больших проектов для интеграционных тестов инфраструктуру вообще запускают локальной службой, чтоб не ждать, пока оно заведётся. Это конечно ещё сложнее и требует отдельного этапа при сборке чтоб закинуть туда свежие assemblies, но иногда по-другому никак. Впрочем, сейчас в моде быстрое развёртывание / запуск, внедренцы очень просят. Поэтому потихоньку переползаем со всех костылей на стандартное API, но чтоб оно не тормозило.


I>А если внутри используются переменные типа HttpContext.Current или же DateTime.Now, то вечер перестает быть томным — проинициализировать их корректно больно, неприятно и не всегда возможно.

В бизнес-логике??? Да ну нафиг, расстреливать за такое. Оно ж потом, если потребуется поправить (например, пользователь просит печать форм заранее, за пару дней до фактической даты) — кучу кода придётся просматривать и править.
Re[3]: При чем тут Di?
От: 0x7be СССР  
Дата: 10.08.16 18:51
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

0>>В их руках абсолютно что угодно станет оружием судного дня для проекта.

IQ>Может comrade... я написал про DI, вы можете написать про все остальное — "что угодно"...
Ну, я видел победу модульности над здравым смыслом. Победу паттернов над здравым смыслом (особенно лютовал Visitor).
Победу микросервисов над здравым смыслом. Победу message queue над здравым смыслом. Победу DDD на здравым смыслом.
Ну и прочие триумфы сил добра над силами разума DI тут ничем особенно не выделяется.

IQ>Кстати любопытная ситуация, остальное "что угодно" не больно то потакает сокрытию архитектурных проблем , а вот у DI это получается просто блестяще... Приделай к самой низкопробной дряни интерфейс, заверни в DI контейнер и ты мега архитект!

Ой, да ладно. Они все скрывают одни архитектурные проблемы, создавая другие проблемы на ровном месте
Хотя, конечно, это не "они" (сиречь, паттерны) а люди. Вся проблема в людях и только в них.
Re[9]: При чем тут Di?
От: · Великобритания  
Дата: 11.08.16 16:11
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

IQ>>>Альтернатива простая — г...кодить г...код без DI.

IQ>·>Это как? И чем это лучше?
IQ> это значительно экономит время и силы и г...кодеру и окружающим...
Так покажи этот код без DI. Ты показал "плохой" код, теперь давай "хороший" код в студию.

IQ>·>Ты привёл ситуацию, но я не вижу в ней ничего криминального. Я и пытаюсь добиться конкретики. Что именно плохо и как должно быть чтобы стало хорошо?

IQ>То ли боги тотально берегли вас от случаев убогого использования DI, то ли вы видели его на на картинках в книжках... Если вы не видите в моем примере типичного антипаттерна, я могу вам только позавидовать.
Я пока только вижу код, который назван "плохим". Но код не бывает абстрактно плохим. Он может быть только хуже/лучше некоего другого кода по неким критериям. Вот это я и пытаюсь выудить из тебя: какой код ты считаешь лучше и почему.

IQ> Нету в убогих проектах никаких юнит тестов не доживают они до них

Допустим. И причём тут DI?

Похоже ты обжёгся на молоке, и теперь дуешь на воду.

IQ>>> Тогда пропадает видимость — IoC половина священной коровы.

IQ>·>Ы? Что за бред? Что пропадает? Куда пропадает?
IQ>·>В DI никаких интерфейсов нет. Найди мне их тут: https://en.wikipedia.org/wiki/Dependency_injection#Examples
IQ>Расскажите это тем кто пытается пихать DI всюду где есть оператор new или вызов статической функции
Ага... значит интерфейсы тут не причём как выяснилось. Но в начальном сообщении new и статических функций не было. Может приведёшь более выразительный пример?

Т.е. проблема в том, что люди создают интерфейсы где попало, бормоча "во имя DI!", так что-ли? Ну такое надо лечить только ликбезом по мягким местам...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 11.08.2016 16:12 · . Предыдущая версия .
Re[13]: При чем тут Di?
От: · Великобритания  
Дата: 12.08.16 12:12
Оценка: :)
Здравствуйте, IQuerist, Вы писали:

IQ>·>Блин. Пятый раз прошу! Покажи этот самый любой другой сходный гкод!!!

IQ>Как вы себе это представляете? Вам enterprise проект выложить? И вы в нем будете копаться? Я понимаю, что ваши требования явить конкретный пример это софистский прием, но не понимаю смысла, демонстрируемого вами упорства, в теме где нет холивара
Нет, не приём. Просто не понимаю что в этом невозможного.

IQ>>>При том, что его впихивают в проект обосновывая тем, что проще будет писать юнит тесты, которые, к слову как правило никогда не будут написаны

IQ>·>Ок. Да, пихают, но тесты не пишут. Тесты не пишут — да, это плохо, полностью согласен. А то что пихание само по себе плохо — мне не очевидно, обоснуй.
IQ> т.е. по вашему, принимать решения основываясь на причинах, которые причинами не являются, это серьезный разговор?
Если напишут хоть пару тестов, уже хорошо. Таки объясни — чем пихание плохо?

IQ>>>·>Похоже ты обжёгся на молоке, и теперь дуешь на воду.

IQ>>>Я я пишу не о себе, а о других, которые почему-то массово делают одни и те же ошибки, увы связанные с DI. Потому пост и появился.
IQ>·>Ошибка — не писать тесты, ошибка — создавать интерфейс для каждого класса. Каким образом это связанно с DI?!
IQ>Это вы мне объясните каким волшебным образом решение о неуместном использовании DI попадает в ряд самых глупых и банальных ошибок
Опять двадцать пять. "неуместном использовании DI". Мой тезис — в типичном проекте неуместного использования DI не бывает, вещь хорошая сама по себе по сравнению альтернативами. Даже если не пишут тесты, но если таки решатся — будет проще начать. Даже если создают лишние интерфейсы — фигня какая, нажал кнопочку "refactor->inline" и готово.
Термин вон придумал — Colonoscopy Injection. А что в Constructor Injection плохого-то?

IQ>Проблема не в коде, а в ситуации. Если вы с такой не сталкивались, то вероятно пост не для вас.

Ладно, буду считать, что это некое эзотерическое знание, невыразимое в формате сообщения в форуме, только личный опыт позволяет постичь это.
Но мне не нравится, что говоря о чём попало, обвинения сыпятся в сторону ни в чём не повинного DI.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: При чем тут Di?
От: 0x7be СССР  
Дата: 12.08.16 14:45
Оценка: +1
Здравствуйте, IQuerist, Вы писали:


IQ>Главная опасность второго варианта имхо в том, что имеющий оправдания, не станет ничего менять и исправлять.

Главная опасность в том, что продукт никогда не будет выпущен. Весь пар уйдёт в свисток архитектуру.
Re[9]: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 15.08.16 09:55
Оценка: +1
Здравствуйте, Cyberax, Вы писали:


C>Вот прекрасно всё работает, в условиях ещё более жёстких.

Так мы не про сами тесты, а про "TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла".

Излишний радикализм с отдельными тестами на каждую мелочь на практике поднимает стоимость сопровождения раза в два из-за колоссального объёма кода, который приходится править при изменении бизнес-правил у очередного заказчика (что скорее обыденность, чем что-то исключительное). Комбинация "юнит-тесты где надо, интеграционные тесты для остального + ассерты везде" в этом плане намного дешевле.

C>А если система ещё и сложная, с внешними зависимостями, то вообще вариантов никаких нет. Только TDD с mock'ами поведения внешних сервисов.

Не-не-не, для сложных систем тру-TDD не работает. Получается ИБД в чистом виде. Везде красота и благолепие, тесты зеленеют, одни внедренцы без валерьянки к клиентам не ездят.
Re[11]: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 15.08.16 12:35
Оценка: +1
Здравствуйте, Cyberax, Вы писали:

C>Пофиг. Юнит-тесты писать проще всего. И по наблюдениям, если юнит-тестов мало, то интеграционных тестов нет вообще.

Написать проще всего — это да. Поддерживать — это вряд ли См ниже.

C>Так это говнокод, однако. Если изменение одного заказчика ломает 100500 тестов, то код или тесты написаны плохо. Думайте как переделать.

Нет. Это на требования одного заказчика приходится писать 100500 тестов, если решать проблему в лоб. Я ж говорю

Она отлично работает для инфраструктуры, почти для любого масштаба, неплохо работает для мелочёвки и абсолютно не работает даже для средних проектов. Чтоб было понятно, что такое средний проект: представь себе типовой биз-кейз в виде 20-страничного документа 12 шрифтом, в котором 90% текста — не вода, а логика, причём высокоуровневая...


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

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

Самое эпичное, что попадалось — вычисления с принудительным округлением до то ли 5, то ли 8 знаков после запятой после каждой из операций. Ибо какой-то древний сервис у одного из контрагентов считал именно так и иначе цифры не бились. Реального объяснения так и не добыли, в качестве извинения-байки — цифры подгоняли под ещё более древние бумажные записи, которые велись именно с такой погрешностью.

Ну и про настройку количества байт в мегабайте
Автор: Sinix
Дата: 22.04.15
тоже писал как-то. В общем, это не говнокод. Это реальность такая замечательная


C>Вторые 95% догоняются на этапе интеграционного тестирования.

В общем, об одном и том же говорим, только разными словами. Я ж не утверждаю, что юнит-тесты не нужны Я про то, что ими ограничиваться не надо.
Re[22]: При чем тут Di?
От: · Великобритания  
Дата: 17.08.16 07:37
Оценка: +1
Здравствуйте, maxkar, Вы писали:

M>В других случаях поведение зависит от принятых данных и состояния базы данных. И вот там нужно правильно передавать используемые данные. Не "инжектить сервисы", а получать нужные данные в нужном месте.

Т.е. по сути использовать БД как service registry... Кстати, не во всех проектах есть БД.

M>А вот про фабрику в более сложном случае я с коллегой не согласен. Все по той же причине: "Tell, Don't ask". Я использую композицию:

Более сложный случай это:
SomeSerivce someService = someSerivceFactory.getByConsumer(consumer);
someService.doA(boo);
somethingElse(someService.doB(baa));
someService.doC(mee);
andSoOn(someService, foo);

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

M>Диспетчеризация остается. Но она идет на уровне "сконфигурированных объектов".

Но как возможное решение в каких-то ситуациях — ОК.

M>void methodA(Entity someEntity) {
M>void methodA(long entityId) {

Ну нафиг. Преждевременная пессимизация, усложнение тестирования, плюс превращение типированных параметров в безликое long.

M>Т.е. вместо a->b->c будет {a->b;a->c}

+1

M>Они все — вариации на тему Service Locator. Ваш код дальше — хороший пример данного утверждения.

Вот это точно. Так и чуял что Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры" — полная лажа. Не выйдет плагины делать с помощью DI, нужен именно SL — бочка с зависимостями из которой каждый плагин выуживает то что ему надо.

M>Пока есть ровно одна реализация сервиса, это работает. А вот когда их становится много — нет. Как вот в моем первом примере с CompositeConfirmation.

Просто можно готовить соответсвующий service registry в место втыкания плагинов.

M>И не использует типы в качестве этих ID (ну, чуть хитрее, для удаления boilerplate я scala implicit parameter использую)

Это как?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: О "наивном" DI и об архитектурном бессилии
От: diez_p  
Дата: 17.08.16 12:56
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

IQ>О "наивном" DI и об архитектурном бессилии

да все просто, начитавшись модных книжек о сильвер-булет технологиях, молодеж кидается их применять, не понимая, конечного результата.
Проект дорлжен развиваться эволюционно и возможно оставлять заделы наперед в архитектуре и дизайне.
Ничто не может появиться просто так и только по желанию создателей, все должно быть обосновано и подтверждено практическим использованием. Любая технология имеет ограниченную область применений.
Нет тестов или заменяемых компонент, нафиг этот DI и всю иерархию интерфейсов. И так везде. А то на практике надо две отвертки, а люди покупают набор инструентов kraftool, с количетвом предметов больше 200, в сервисах же его используют, а мы что хуже?
Re[24]: При чем тут Di?
От: · Великобритания  
Дата: 21.08.16 17:36
Оценка: +1
Здравствуйте, maxkar, Вы писали:

M>>>В других случаях поведение зависит от принятых данных и состояния базы данных. И вот там нужно правильно передавать используемые данные. Не "инжектить сервисы", а получать нужные данные в нужном месте.

M>·>Т.е. по сути использовать БД как service registry... Кстати, не во всех проектах есть БД.
M>Не service registry. Там характерного для registry API не возникает ни на каком этапе. Интерфейс формулируется в терминах бизнес-логики, например sendConfirmation(long orderId). БД содержит "данные, на основе которых принимаются решения, описанные бизнес-логикой". Эти данные есть в любом случае, это часть предметной области. Что меняется, так это компонент, ответственный за извлечение нужных для принятия решения данных из базы данных. В случае с entity и прочими большими объектами эта обязанность лежит на пользователе ConfirmationService. И может потребоваться изменить этого пользователя при изменении бизнес-правил. При передаче id вся ответстенность за извлечение необходимых для решения данных переносится на сам ConfirmationService. Это может быть удобнее для пользователя. Но из-за этого реализация сервиса знает чуть больше о структуре хранилища.
По сути ты кладёшь контекстные данные в хранлище в одном месте и извлекаешь их в другом, создаётся неявная плоховыраженная зависимость. Неужели не напоминает service registry?

M>В общем, переход к ID — не автоматическое решение. У него есть и плюсы, и минусы.

Его стоит применять в случае наличия хранилища, при передаче объектов по некоторым внешним к ЯП идентификаторам, для межпроцессного взаимодействия. А так — чем передача по ссылке плоха?

M>·>Более сложный случай это:

M>·>Т.е. возвращённый сервис используется многократно, притом в разных местах — по-разному, и фабрика может выдавать разные экземпляры SomeSerivce, которые могут иметь различные зависимости или даже типы.
M>Ну вот это явно встанет в очередь на рефакторинг. Чтобы не приходилось передавать сервисы в параметрах методов. Рефакторинги будут зависеть от реального кода. В абстрактном виде это обсуждать не реально. Ряд используемых техник я показал. Если у вас где-то есть код в opensource с описанной проблемой — могу ближе к новому году посмотреть и сказать, что бы я делал.
А чем плохо? Зачем на рефакторинг?

M>Да, минусы есть. Это не универсальное решение. Но лишние поля у Entity (вроде "confirmation preferences"), используемые только в 5% случаев работы с entity — тоже не круто. Нужен баланс. По-умолчанию я тоже за entity, кстати.

Можно ещё Entity декомпозировать на части помельче и передавать их, а не Entity целиком.

M>И переход к id только при росте интерфейса.

А что это даёт? То что ты передаёшь ID вовсе не означает, что из базы ты можешь загружать или не загружать "лишние поля". Вообще понятия не имеешь что где используется. Т.е. нарушаешь IoC опять: Вместо того, чтобы использовать что дают — имплементация начинает сама тянуть из базы что захочет.

M>А тестирование обычно не проблема. Если можно тестировать internal methods, то все просто:

M>
M>/* internal */ void methodAImpl(ConfirmationData data) { 
M>

M>Тест находится в том же пакете (поэтому имеет доступ и к методу). В юнит-тестах проверется только methodAImpl. В ряде случаев methodAImpl может еще и static оказаться, что вообще прекрасно.
Фу-фу. "visible for testing" — не люблю. Тестируется не то, что реально используется. Конечно, такой подход иногда упрощает тестирование, но это short-cut, который применяется в исключительных ситуациях, делать из этого типичный код — ну нафиг.
Ты просто создёшь месиво из инфраструктурного wiring кода и собственно самой логики в одном месте.

M>Подобный трюк с разделением на два метода еще очень хорошо позволяет избавляться от страшных вещей вроде ICurrentTimeProvider { long now(); },

Это правильная вещь, почему страшная? Даже в JDK наконец-то допёрли до этого, начиная с Java8 — java.time.Clock вместо System.currentTimeMillis()

M>который вводится для "тестирования поведения, зависящего от времени".

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


M>>>Пока есть ровно одна реализация сервиса, это работает. А вот когда их становится много — нет. Как вот в моем первом примере с CompositeConfirmation.

M>·>Просто можно готовить соответсвующий service registry в место втыкания плагинов.
M>Можно. Но не удобно и вводит личные сущности. Поэтому я предпочитаю выкинуть сторонние библиотеки и сделать все кодом, ровно так, как я люблю.

M>>>И не использует типы в качестве этих ID (ну, чуть хитрее, для удаления boilerplate я scala implicit parameter использую)

M>·>Это как?

M>В scala есть хитрый механизм, когда параметры (метода или конструктора) могут передаваться автоматически исходя из лексического контекста. Очень похоже на типичный DI, реализуемый различными библиотеками, но для параметров. В коде выглядит примерно так:

M>

M>def init() : Unit = {
M>  val config = readConfig()
M>  implicit val mainDb = createDataSource(config.db.main)
M>  val thirdPartyDb = createDataSource(config.db.thirdparty)
 
M>  val idGens = new TableIdGenerators
M>  val someService = new SomeService(config.someService.param)
M>  val anotherService = new AnotherService(
M>    someService, idsGens.idsFor("anotherServiceSeq"))
M>  val thirdPartyService = new ThirdPartyService(config.thirdPartyId)(thirdPartyDb)
M>}
M>

M>В данном примере idGenerator, someService и anotherService будут использовать mainDb, а thirdPartyService будет использовать thirdPartyDb. Недостающие implicit-параметры
Что-то пок не впечатляет. Как смотря на этот код увидеть зависимости? Как обнаружить по коду кто использует значение mainDb? IDE хотя бы как-нибудь подсвечивть умеет?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[14]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 30.08.16 16:11
Оценка: :)
Здравствуйте, ilvi, Вы писали:

C>>Я внутри Amazon'а работаю в облачных вычислениях.

I>Полтора-два года назад как раз читал про плеер амазонвский под андроид, были огромные ветки на форумах с разгневаными пользователями и оценка в плеймаркете соответсвенная. Потом довелось подержать в руках один из киндлов, с цветным экраном, на котором этот плеер можно было помучать. Через пять минут я его "сломал" — перестал отображать постеры к описаниям фильмов и еще что-то отвалилось. Потом спросил у дядечки, который руководил одним из проектов по разработке этого плеера, как они тестируют — ответ был, что только юнит тесты и никаких ручных тестов. На тот момент всей этой информации хватило, чтобы сформировать мнение, почему у амазона конкретно этот плеер такой глючный.
А если по сути...
Во-первых, фраза "только юнит тесты и никаких ручных тестов" показывает как минимум непонимание терминологии, а чаще — непонимание темы вообще. Хинт: бывают не ручные UI-тесты, а бывают ручные юнит-тесты.
Во-вторых, ты правда считаешь, что из этой информации правда достаточно для именно такого мнения? Ведь существует столько причин ведущих к плохому качеству продукта, но ты сразу делаешь однозначный далеко идущий вывод. Откуда такое предубеждение к тестам?
В-третьих, а это точно именно амазоновский продукт был? Купили очередной стартап, и слепили что получилось из того что досталось побыстрому. Что не удивительно для очередного плеера, с облачными вычислениями мало что общего.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 31.08.16 08:34
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, IQuerist, Вы писали:


IQ>>У меня был знакомый, тестировщик от рождения, в его руках софт просто горел аццким пламенем "общение" с ним, когда он просто рвал, уже многократно оттестированный UI на части, вызывало бессильную ярость и преклонение перед гениальностью одновременно.

S>Этот
Автор(ы): Антон Злыгостев aka Sinclair
Дата: 24.06.2004
Этот четверг ничем не отличался от обычных. Часов с 12 я начал испытывать просто нестерпимое желание найти повод поотлынивать. Поэтому когда в аське всплыл вопрос шефа "Не хочешь пособеседовать тестеров?", я долго не думал...
?


Ну все же не на столько брутальный ))) впрочем... один раз он вскрывал алюминевый бочонок пива топором проигнорировав штатный кран, признаться тогда я не придал этому значения.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 01.09.16 13:40
Оценка: +1
IQ>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.
Вы бы с SOLID разобрались и не писали чушь. Расскажите мне как DI у нас портит S или I я уже не говорю про D
Народная мудрось
всем все никому ничего(с).
Re[2]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 01.09.16 14:13
Оценка: +1
Здравствуйте, Tom, Вы писали:

Tom>Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.

Литров не обещаю, но возразить могу: контейнер не нужен. Накой мне жуткий монстр тащить, не надо ему ничего делегировать. Я что не в состоянии сам new вызвать в нужный момент? Просто пишется отдельный инфрасткуртурный код, который будет делать весь этот ваш wiring. А эти контейнеры не только с собой тащат всякий хлам с поддержкой всякой чёрной магии (противоречит твоему пункту 3), но ещё и в особо запущенных случаях — жуткие XML-конфиги.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 01.09.2016 14:14 · . Предыдущая версия .
Re[8]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 09:35
Оценка: -1
Здравствуйте, Tom, Вы писали:

Tom>·>Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.

Tom>Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.

И зачем вы тогда комменты писали? поставили бы минус и вся не долга. У нас не было согласия с ., но у него хотя бы есть позиция. А в ваших каментах пока не видно ничего кроме слепой веры и предрассудков.
Отредактировано 02.09.2016 9:36 IQuerist . Предыдущая версия .
Re[4]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 10:14
Оценка: :)
Здравствуйте, Tom, Вы писали:

IQ>>Звучит эпически, а как быть со stateless объектами в которых одна логика и нет состояния? Для чего им DI, если потенциальное время их жизни — от старта системы до самого ее финиша?


Tom>Звучит не эпически а логично. Statefull или Stateless абсолютно никак не влияет на то надо ли обьект инжектить. Единственное на что это влияет — на время жизни обьекта. Если он Stateless — его смело можно делать singleton-ом. Что касается Statefull то надо разбираться что за стейт и кому он принадлежит. А у вас в голове каша, вы смешали разные понятия — State-а, и DI. На вопрос для чего — уже обьяснял, для того что бы иметь возможность подменять в тестах, для того что бы сделать зависимость явной.


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

Если бы вы прочитали сам пост, то несомненно увидели бы, что я описываю ситуацию, когда тесты в проекте — это несбыточная фантазия.

IQ>>Забавно ))) вот например время жизни db entity определяется оно как правило контекстом внутри одного метода от загрузки из БД до сохранения в БД. Вот например есть ворох статических хелперных методов не имеющих состояния. Вот например есть целые сервисы, зависимость от которых и жизни которых определяется контекстом бизнес операции т.к. сильно зависит от бизнес логики...

Tom>Спросить то чего хотел. И ещё раз уточню, забавно выглядит тут ваша позиция неофита. Могу спорить вы возрастной программист лет после 40-ка которые просто не смог в DI. И уже никогда не сможет.

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

IQ>>Мне кажется или ваша позиция больше связана с вопросами веры, чем с вопросами разработки ПО?

Tom>Вам кажется. Моя позиция связана с принципами и опытом разработки mission critical систем работающих 24/7 и распространяющихся по схеме PaaS. Качество для нас критически важно. Покрытие тестами для нас критически важно.

Спрошу прямо — вы на каком курсе института?

Tom>>>2. Использование DI позволяет тебе чётко определять все зависимости объекта, зависимости становятся явными и получает их обьект обычно в конструкторе. Иными словами мне НЕ нужно лазить по коду объекта что бы понять а от чего ещё он зависит. Достаточно глянуть в конструктор и всё становится понятным.


Tom>>>3. При тотальном использовании DI во всём проекте во всём проекте используется один и тот же стандартных подход. Такой код читать просто и понятно. А вот обратный случай когда вот тут вот мы сделаем new, а вот там вот вызовем статический метод а вот это вот мы заинжектим потому что оно — это сервис (а что такое сервис никто не знает). Это точно бред.


IQ>> У меня полно опыта в области DI. Я отхреначивал DI нафиг уже в трех проектах потому как с ним архитектура типа big ball of mud становиться абсолютно неподдерживаемой.


Tom>С чем вас и поздравляю. Отхреначивайте дальше. И к архитектуре DI не имеет никакого отношения. DI это маленькая частная практика наряду с кучей других практик которые необходимы для того что бы писать качественный код. А то что вы делает называется "макароны"


Если бы вы прочитали пост, то сообразили, что именно про это там и написано И собственно проблема о которой я заявляю в том, что "маленькая частная практика DI" в силу своей формальности, доминирует над всеми другими практиками. Что использование DI не делает архитектуру автоматически хорошей А вот г...код делает на порядок более многословным и сложным.

PS И к архитектуре DI не имеет никакого отношения.

Т.е. по вашему использование механизмов DI никак не влияет на архитектуру системы?
Re[8]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 02.09.16 10:21
Оценка: +1
Здравствуйте, Tom, Вы писали:

Tom>·>Куча вредных антипаттернов, которые легко размазать по всему проекту, а обычно достаточно одного единственного constructor injection. И вычищать потом это — замучаешься.

Tom>Давай по конкретнее. Хоть один анти паттерн покажи мне и опиши в чём состоит проблема.
  1. SL. В подавляющем числе случаев он не нужен. Проблема — он делает зависимости неявными.
  2. методы-инициализаторы и property injection. Проблема — добавляет в объект опасное состояние "создан, но не очень-то ещё создан".
  3. Магические строки. Ничем не лучше магических чисел.
  4. Сканирование сборок. В подавляющем числе случаев он не нужен. Доставляет столько удовольствия исследовать что куда залетело и почему. Притом это можно исследовать только на запущенной системе в данном (часто prod) окружении.
  5. Циклические зависимости. С DI+CI сделать цикл невозможно. Заставляет аккуратнее подходить к архитектуре приложения, а не всякие lazy/PI, которые тебе циклы создадут на ура.
Tom>·>выглядит ничуть не хуже.
Tom>Выглядит хуже. И создаёт конкретные проблемы в вполне конкретных случаях. Я больше скажу, с управлением временем жизни обьектов руками есть большие проблемы даже на теоретическом уровне.
Если это невозможно на теоретическом уровне, то как контейнер это будет разруливать?

Tom>Вот тебе прмиер. Есть обьект IFoo. Ну или IPlugin для наглядности. Есть пара его реализаций, одна из них использует unmanaget ресурсы и требует реализации IDisposable а другая нет. Кроме как калечного решения в виде наследованияч IPlugin от IDisposable для ручного управления зависимостями я не вижу.

Не понял. Давай более конкретный пример. Вот код:
var foo = fooProvider.giveMeFoo();
doSomethingWith(foo);

Если какие-то из IFoo могут быть disposable ты в данном месте обязан предполагать худшее и всегда освобождать foo, т.к. ты не знаешь какой из IFoo провайдер тебе выдаст. Поэтому будь добр оберни:
public void businessLogicMethod()
{
    using(var foo = fooProvider.giveMeFoo())
    {
        doSomethingWith(foo);
    }
}

А значит только наследование.

Если это известно в инфраструктурном коде, так и пиши в wiring модуле:
if(useDatabase)
{
    using(var foo = new DatabaseFoo(connectionString))
    {
        doBusinessLogicWith(foo);
    }
}
else
{
    var foo = new InMemoryFoo();
    doBusinessLogicWith(foo);
}

и спаси IFoo от leaking abstractions.

Tom>·>Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.

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

Tom>·>Зато полная поддержка компилятора и IDE. А неудобно только с непривычки.

Tom>new это огромные трудности при написании тестов. Я про Integration тесты.
Tom>Руками собирать всё дерево зависимостей? Вопрос нахера, если я 2-мя движениями мышки могу в тесте подменить любую зависимость.
Нет, просто пишешь классы-модули, которые делают wiring тестируемых поддеревьев зависимостей. И тестируешь именно их. Иначе интеграционные тесты тестируют тестовый wiring.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 12:58
Оценка: -1
Здравствуйте, Tom, Вы писали:

IQ>>К 37 то годочкам, уж пора бы отучиться говорить за всех...

Tom>Я говорю за пару сотен разработчиков и несколько десятков проектов с которыми я знаком.

Очевидно я говорю за миллионы остальных , чем особо не хвастаю.

Tom>>>Расскажите и научите как ВЫ делаете Правильно.

IQ>>Если бы вы прочитали пост, то поняли бы, что он не том, как делать правильно. А о том, как часто делают неправильно.
Tom>Прочитал. Не понял. Поясните.

Пояснить как делают не правильно Вероятно ваша работа чертовски скучна

IQ>>Абсолютно не интересует. Опыт часто видно по задаваемым вопросам.

Tom>>>И всё это время я учусь ибо в нашей профессии это необходимо что бы оставаться профессионалом.
IQ>>Вот никогда не понимал людей, которые врут наполовину
Tom>Можно по подробнее где я вру

То был намек Намеки не поясняют, их или понимают, или нет.

IQ>>Ну прочитайте уже пост! Я нигде не утверждаю что DI это зло. Наоборот, специально раз пять написал обратное.

Tom>У вас DI какой то очень странный. Какой то избирательный.

так об том и пост! Не у меня, а у наивных архитекторов.

Tom>Вы так и не пояснили критерии как определить что надо DI а что не надо и главное почему не надо и какие проблемы это несёт.


Пост о том, как в DI строят на основе DAL хелперов. Я высказал предположение, что так делать не надо и ряд соображений. Если описанный пример не несет для вас проблем — пост явно не для вас. Написали бы:

"я и пару сотен разработчиков" сделали так в "несколько десятков проектов с которыми я знаком" и все отлично, зря автор париться.
Re[12]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 02.09.16 13:39
Оценка: +1
Здравствуйте, Tom, Вы писали:

Tom>·>Service Locator.

Tom>Так не надо его использовать. Контейнер то тут причём
Ещё как причём. Открываешь первую попавшуюся доку по контейнерам и там этим всё пестрит, как будто так и надо.
И ты вот уже неосознанно используешь "константу как при регистарции так и при резолве". Регистация и резолв это и есть SL. Т.е. ты регистируешь в реестре инстанс по ключу "тип" или "тип+простая_строка", потом его достаёшь:
container.Register<IFoo, Foo>();
var instance = container.GetInstance<IFoo>();

Для DI не нужны никакие регистрации и резолвы.

Tom>Конечно есть некоторые исключения — вершина стека вызовов. Аля новый поток но тут ничего не сделать.

Не нужны никакие исключения.
public static void main(args)
{
  var app = new AppModule();
  app.run(args);
}



Tom>Мне казалось я понятно обьяснил зачем нужны строки.

Ты объяснил для чего ты их используешь, но не объяснил зачем ты используешь именно строки, а не миллион других способов выразить полиморфизм.

Tom>1-е для того что бы сказать контейнеру что он не должен переопределять зависимость а должен зарегистрировать вторую для того жде интерфейса.

Зачем зарегистрировать-то?? С какой целью?

Tom>2-й для того что бы как то можно было зарезолвить зависимость по имени. Таких случаев тьма, случаи когда есть N обьектов реализующих один и тот же интерфейс, как пример ICommand. И никаких проблем строки не создают, обьявите их константами и используйте.

Почему именно по строковому имени? А если у меня long-идентификатор? или тупо bool? Потому что контейнер по-другому не умеет. Да ведь?
Если тебе так надо, то так и напиши: Map<String, IFoo>, или switch-case, или if. Вон сколько есть выразительных средств, а ты вынужден использовать только строки, т.к. даже самый современный контейнер по-другому особо и не умеет.

Tom>>>Ничего не понимаю что куда залетело. В общем случае фича которая называется auto wire работает прекрасно. Регистрируешь только то что отличается от принятых в контейнере конвенций.

Tom>·>Я о http://www.lightinject.net/#assembly-scanning , а ты о чём?
Tom>И я о том же, обычно это называется auto wiring
Нет. Почитай доки что-ли для начала. Если непонятно, могу объяснить.

Tom>·>Циклические зависимости делать не надо. Никогда. А если это действительно неизбежно — это должно быть сложно и сразу явно видно. Ты можешь случайно добавить незаметив, а контейнер тебе всё сам свяжет и не пикнет, втихую добавив +100 к техническому долгу. А потом эту вязанку развязывать.

Tom>Да действительно контейнер в случае циклической зависимости упадёт только во время резолва. У меня такая проблема встречалась один раз и выявлена была в тестах. Ничего серьёзного, решилась за пару часов.
В случае использования lazy и property injection этот самый auto-wiring всё втихую сошьёт.

Tom>·>public class RequestModule и пусть он и управляет временем жизни создаваемых им IDisposable-ы ровно так как надо, а не универсальный всемогутер, который делает какую-то неявную магию.

Tom>Не понял я кто такой RequestModule и как он может определить какой обьект надо диспоузить а какой нет.
RequestModule это контекст создаваемый для реквеста. В нём и будет нужные new внутри using. Он не должен ничего определять, ты сам пишешь код так, чтобы всё что надо диспозилось когда надо.

Tom>·>Я знаю. Сам таким был.

Tom>·>Потом попал в компанию, где история развития была такая: "что попало как попало" -> "монстр Spring Framework" -> "модный Guice" -> "DI, plain Java code". По началу тоже возмущался отстутсвием "современного" контейнера, а потом осенило.
Tom>Я кстате заметил что ты из жабы+spring пришёл по опасениям за конфиг+xml.
Tom>Сейчас контейнеры совсем лругие. Это уже не монстры а достаточно простые, быстрые и логичные девайсы.
Tom>Советую перестать их бояться, хотя бы попробовать не нескольких проектах.
Tom>Многое становиться делать проще и удобнее чем руками.
guice именно такой, там вообще нет xml-конфигов. Но всё равно фтопку.
spring4 тоже теперь умеет xml-free.

Tom>Ничего контейнер не прячем, зависимости у каждого класса явные. Если их много, то эта проблема и так явная и контейнер тут не причём.

Я говорю не о классе, а о крупных модулях/блоках приложения.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 05.09.2016 8:45 · . Предыдущая версия .
Re[22]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 27.09.16 09:27
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

IQ>·>Потому что вызовов этого конкретного метода может быть много по всему коду, а вызововы конструктора обычно постоянны.

IQ>Но это еще хуже! Если реализация IOrderValidator, IOrderCollector и IOrderShipper существует одном экземпляре то нафига выносить их из модуля и засорять область приложения. А если их много, то необходимо явно и локально показывать их зависимость от контекста иначе логика размазывается.
Пусть одна реализация, это дело не меняет. Пишут эту реализацию другие люди, в другой команде, или это какой-нибудь RPC-интерфейс или ещё что — не важно. В вопросе главное как управлять зависимостями, а не конкретные названия классов/интерфейсов.

IQ>>>если можно где-то там, за ширмой неявно затаскивать его через конструктор в DI? Ведь достаточно будет посмотреть конструктор,

IQ>·>Зачем тебе его смотреть? Если у тебя есть ссылка на OrderProcessor — то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует.
IQ>Компилятор гарантирует? Мне казалось DI работает исключительно в динамике.
Если кажется — крестись, или хотя бы учебники читай. Я же уже ссылку давал на вики, читал? Где там динамика?

IQ>И потом, если разные варианты поведения, то мне надо четко указать, какое использовать, если поведение одно — зачем вообще выносить его за границы модуля? Впрочем я знаю ответ... — "для unit тестов". Вот так убогие фреймворки для тестирования порождают архитектурные проблемы.

Это далеко не единственный ответ.

IQ>·>Если у тебя такой ссылки нет, то смотри wiring и найди добавь эту ссылку к себе. Если не получится — значит что-то у тебя не хвататет в зависимостях, протаскивай как надо куда надо, а не надейся на глобальные переменные.

IQ>Но мне не надо ничего протаскивать, мне надо локально указать конкретный вариант.
Какой конкретный вариант? Забудь множественные имплементации, не в них дело. Дело в том, что "конкретный вариант" тоже откуда-то должен взяться, у него можеть быть специфичный lifespan и у него могут быть свои зависимости.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[24]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 28.09.16 13:48
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

IQ>>>Честно нет... я искренне не ожидал, что одинаковые вещи могут по разному называться и по разному оцениваться. Для меня это честно было сюрпризом. Но в мутной теме обязаны быть грязные хаки надо лишь поискать.

IQ>·>Ничего не понял. Тема не мутная, похоже муть у тебя в голове. ServiceLocator и Ambient Context вещи не одинаковые, вообще ничего общего.
IQ>·>Ambient Context это хипстерская обёртка для обеспечения более вменяемого использования глобальных переменных.
IQ>·>А Service Locator это фактически такая мапа [serviceId -> serviceImplementation], называемая Registry. Притом сама мапа может протягиваться как через те же глобальные переменные (и даже с использованием Ambient Context), через DI, тупо через арументы метода или ещё как.

IQ>Читаем талмудъ:

IQ>https://smarly.net/dependency-injection-in-net/di-catalog/di-patterns/ambient-context

IQ>

IQ>Ambient Context сходный по структуре с анти-паттерном Service Locator,

Выражения "Сходный по структуре" и "одинаковые вещи" — не одинаковые вещи, и даже не сходны по структуре. Сходность по структуре не означает, что можно ambient context в коде называть как service locator.
Почему для тебя это сюрприз — я до сих пор не понимаю. Ведь даже в этом талмуде это по-разному оценивается: Service Locator записали в анти-паттерн, а Ambient Context как паттерн.

IQ>Кстати там же про Thread Local Storage и HttpContext

А ещё там написано "Ambient Context должен быть использован только в редчайших случаях". А ты предлагаешь это как дефолтное решение.

У меня был опыт, что даже приведённый в этом талмуде пример с TimeProvider как глобальня переменная (или ambient context, что почти то же самое) дал сбой. У нас в приложении оказалось нужно два вида часов — физические для текущего запуска и логические, определяемые проигрыванием исторических событий из лога и для реализации "машины времени", применяемой для системного тестирования (а как ещё протестировать, например, что некий отчёт создаётся по пятницам?). Поэтому нам пришлось дружно заменять по всему коду статики на DI+CI.

IQ>·>Причём тут бизнес-операция? Это вообще не в тему. Смотрим что ты написал:

IQ>·>"и с десяток совершенно очевидных хелперных stateless методов типа: GetBoringItemById". Вот как такой метод может быть stateless? Как мне доводилось видеть, сигнатура такого метода типично
IQ>·>public BoringItem GetBoringItemById(long id)
IQ>·>или у тебя другие варианты?
IQ>·>Покажи как ты видишь этот метод сделать stateless. Ему как минимум нужен borrowed DbConnection и активный TransactionContext, а ещё, бывает, какой-нибудь security context и audit recorder.
IQ>GetBoringItemById не имеет состояния, состояние "DbConnection и активный TransactionContext" предоставляются ему внешними сервисами.
Они ему не предоставляются, а он их сам находит. Если бы сигнатура была public BoringItem GetBoringItemById(long id, DbConnection db, TransactionContext tx) — вот это stateless.
Иначе у тебя получается, что любая функция на C — stateless, т.к. классов нет, все функции "статические".

IQ>Да в моем случае этот сервис глобальный (как и loggingContext). Ваш пример конечно интересен, хотя на мой взгляд никаких явных TransactionContext, security context и audit recorder и т.д. в DAL быть не должно — не тот уровень абстракции Они все же должны быть в высокоуровневом сервисе и это имхо очевидный маркер того, что в случае GetBoringItemById DI используется неверно.

Это просто самые очевидные и понятные примеры, не придирайся к конкретным названиям. Суть в том, что такие зависимости или что-то подобное может появиться когда-то и "We still get no help if we need to add a new dependency: is it a breaking change or not?".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: О "наивном" DI и об архитектурном бессилии
От: Vladek Россия Github
Дата: 30.09.16 01:32
Оценка: +1
Здравствуйте, IQuerist, Вы писали:

IQ>А вы пост-то вообще читали? Смысл поста — обозначить очевидную проблему. В результате обсуждения, "адепты DI" наличие описанной в посте проблемы признавать отказались. Нет никакой проблемы, пишите как писали и не замарачивайтесь.


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

Процесс занимает 5-10 лет внимательного программирования.
Re: О "наивном" DI и об архитектурном бессилии
От: r.kamenskiy Россия  
Дата: 28.07.16 21:19
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Гиперболизируя можно было бы добавить еще IJsonConverter чтобы механизм конвертирования json можно было изменить и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но на всякий случай стоит "уменьшить зависимости" .


Это еще ничего. Вот когда начинают эти зависимости внедрять через всякие xml конфиги, вот тогда действительно зашкаливает
Re: О "наивном" DI и об архитектурном бессилии
От: vsb Казахстан  
Дата: 28.07.16 22:23
Оценка:
Так что вы предлагаете, учитывая, что тестировать надо? Я пока ничего лучше DI не видел.
Re: О "наивном" DI и об архитектурном бессилии
От: LaptevVV Россия  
Дата: 29.07.16 04:58
Оценка:
IQ>Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.
Перевод гугля совершенно "убойный"...
Колоноскопия Инъекции

Кстати, давайте уж сразу русское токование...
Хочешь быть счастливым — будь им!
Без булдырабыз!!!
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 06:49
Оценка:
Здравствуйте, Слава, Вы писали:

С>Здравствуйте, IQuerist, Вы писали:


IQ>>Как-то так... имхо главная начальная проблема DI — неспособность разработчиков создавать объектные декомпозиции. Это ведет к созданию абсолютно неправильной, очень низкоуровневой и хрупкой системы зависимостей нарушающей 4 из 5 принципов SOLID. Пример того, как некоторые пытаются лечить гланды через задний проход. Кстати неплохое название для антипаттерна — Colonoscopy Injection и для всей братии зомбированных шаблонами "наивных архитекторов" — архитект-проктолог.


С>Напишите на Reddit, только чуть более подробно.


Я честно говоря не очень в курсе, как "продвигать идею" в современном IT сообществе

С>Как именно набивают шишки, какая декомпозиция правильная, а какая — нет, с примером. Не обязательно правильным, даже наборот, если будет криво — тем лучше для холивара.


Шишки набивают очень просто когда неделями бьешься с абстракциями которые сам создал и при этом они очевидно деградируют, что бы ты не делал и при этом еще и вину свалить не на кого

Про "правильную декомпозицию" имхо не пишут статей, про нее пишут докторскую диссертацию

С>Выражение Colonoscopy Injection следует вынести в заголовок статьи, термин у вас получился совершенно убойный.


Ну с общей помощью надеюсь, антипаттерн пойдет в массы. Потому как ситуация с наивным DI просто абсурдная.

С>Даже если со статьей не согласятся, термин пойдет в народ и DI будет надежно обгажено, туда ему и дорога.


я не имел цели "обгадить DI" для "плагинной архитектуры" это прекрасное решение см. COM и OLE. Меня просто в очередной раз взбесило нежелание (типичное?) отдельных программистов немного подумать над тем, что они делают.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 06:50
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Так что вы предлагаете, учитывая, что тестировать надо? Я пока ничего лучше DI не видел.


Я предлагаю не принимать архитектурные решения в рассчете на "сервисы" (тестирование), которые с крайне высокой долей вероятности никогда не будут реализованы.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 07:15
Оценка:
Здравствуйте, Vladek, Вы писали:

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


снижение рисков с помощью нарушения SOLID?

V>Я предполагаю, что внедрение зависимостей используется так: при запуске программы создаётся контейнер, в нём регистрируются сразу все компоненты, контейнер создаёт дерево зависимых компонентов, способное жить самостоятельно, и завершает свою работу (умирает). Компоненты далее работают сами по себе, не подозревая о наличии какого-то там контейнера.


Все красиво и есть прекрасный пример — COM. Но, увы я с уверенностью могу сказать, что в большинстве проектов до выделения компонентов дело просто не доходит... Проекты часто деградируют до крайне высокой стоимости поддержки и их или замораживают или переписывают с нуля. И в этом случае DI (как подход) имхо значительно увеличивает сложность систем на начальном уровне.

IQ>>Собственно ситуация имхо довольно типичная — мне то "опыт подказывает", а молодежь старательно "набивает шишки", но при этом, я почему-то сходу не нашел ни одного внятного объяснения от популяризаторов DI того, почему наивное использование DI будет провальным. Поэтому я решил таки сформулировать свой вариант


V>А как ещё учиться программистам? Только набивать шишки, анализировать свои ошибки, меняться.


В том то и парадокс, что проблемы DI почему-то не анализируют.

IQ>>Посмотрим на типичный пример наивного DI:

IQ>>Ребята... вот эта низкоуровневая "требуха" это что ли "сервис"? Вот эти все "внутренности наружу" это инкапсуляция и архитектура? Как получилось, что попытка "соблюсти" принцип DIP очевидно вызывает нарушение всех остальных принципов SOLID и на это закрывают глаза? Как можно внедрять "зависимость сервиса" в ситуации, когда разработчик не способен создать сам внедряемый сервис? Проблема тут имхо базовая — разработчик не имеет навыков создания объектной декомпозиции и пытается компенсировать это использованием сложных механизмов, смысла которых он не понимает.

V>Разработчик рано или поздно избавится от этих кишок наружу — сначала спрячет их за фасадом, изолирует их, а потом ещё как-нибудь разделит — количество зависимостей между компонентами уменьшится. Но это уже мало имеет отношения к механизму внедрения зависимостей.


Т.е. возможно... в финале... разработчик исправит дефекты вызванные нарушением SOLID, спровоцированные наивным использованием DI. Но здесь имхо возникает онтологический разрыв — если разработчик способен понять, что его "наивный DI" был ошибкой, тогда почему он его в таком ошибочно виде внедрил? Т.е. чтобы перейти от наивного DI к компонентной архитектуре, от разработчика требуется имхо крайне серьезный профессиональный рост, а на это нужны годы.

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


V>Это процесс итеративный, главное не надо думать, что ясная архитектура должна рождаться сразу. Код должен писаться, а потом читаться и правиться. Только после серии правок начнёт вырисоваться внятная схема взаимодействия объектов.


Я это понимаю поэтому даже и не думаю в сторону DI на начальных стадиях проекта, т.к. ничего кроме синтаксического оверхеда это не принесет.

V>Почему это названо проблемой конфигурации (внедрения зависимостей)? Конфигурация и архитектура не одно и то же.


В примере наивного DI который я привел, "внедрение зависимостей" доминирует над всем. И у этого кстати есть забавнейшее следствие — бизнес логика часто "выдавливается" "наивным DI" в клиентские javascript и в хранимые процедуры. Разработчик уже и сам чувствует, что "наивный DI" его ограничивает, но упорно от него не отказывается.
Отредактировано 29.07.2016 7:29 IQuerist . Предыдущая версия . Еще …
Отредактировано 29.07.2016 7:28 IQuerist . Предыдущая версия .
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 07:26
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, IQuerist, Вы писали:


IQ>>Ребята... вот эта низкоуровневая "требуха" это что ли "сервис"? Вот эти все "внутренности наружу" это инкапсуляция и архитектура?


S>Как мне кажется, этот момент — следствие попытки натянуть "классический" DI на все остальные области.


Да, это и есть "наивный DI". В ограниченном инструменте видят решение.

S>К сожалению, DI в чистом виде абсолютно непригоден для использования в тяжёлом биз-коде. Там от DI требуется не закинуть сервисы и отдать объект, а способ протащить эти сервисы по длиннющей цепочке вызовов, причём состав зависимостей часто заранее неизвестен и определяется в рантайме. Для дотнета обсуждали вот тут
Автор: LWhisper
Дата: 30.05.16
.


Да... протащить контекст по длиннющей цепочке бизнес решений. Поэтому хорошая декомпозиция там жизненно важна.

S>UPD, P.S. Не стоит налегать на SOLID как на аргумент в спорах. Его к сожалению воспринимают как волшебную палочку, хотя на практике подход "потому что SOLID" работает не лучше, чем самолёт из культа карго. Голову никто не отменял


Так ведь часто использование DI только этим самым SOLID и объясняют. Мол нам позарез надо уменьшить зависимость иначе не по SOLID, иначе опять получится говнокод.

Хм... неплохой мем — внедрение Colonoscopy Injection не влияет на количество говнокода, оно лишь добавляет посторонние предметы
Отредактировано 29.07.2016 7:33 IQuerist . Предыдущая версия .
Re[3]: О "наивном" DI и об архитектурном бессилии
От: vsb Казахстан  
Дата: 29.07.16 08:00
Оценка:
Здравствуйте, IQuerist, Вы писали:

vsb>>Так что вы предлагаете, учитывая, что тестировать надо? Я пока ничего лучше DI не видел.


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


Но ведь юнит-тестирование это стандарт-де факто в современном софтостроении. Писать софт без тестов это как пользоваться винраром для контроля версий.
Re[2]: О "наивном" DI и об архитектурном бессилии
От: Lexey Россия  
Дата: 29.07.16 09:19
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Вот да-да-да. На практике DI сам по себе никак не помогает и не упрощает процесс тестирования. Сложный код с полудесятком зависимостей одинаково неприятно покрывать тестами, что с DI, что без. Простой вообще не должен требовать DI для тестов


А как ты предлагаешь подсовывать моки/фейки без DI?

S>+1, только я бы немного по-другому сформулировал. Фраза "я добавил возможность" на уровне архитектуры на самом деле означает "теперь нам всем придётся это использовать". Сам по себе DI экономит кучу времени, но только до момента, когда он не вылезает из своей родной ниши. После этого лучше смотреть в сторону других инструментов.


Что такое "родная ниша" DI?

S>UPD, P.S. Не стоит налегать на SOLID как на аргумент в спорах. Его к сожалению воспринимают как волшебную палочку, хотя на практике подход "потому что SOLID" работает не лучше, чем самолёт из культа карго. Голову никто не отменял


+100500. КМК, его скорее стоит воспринимать как базворд, позволяющий попытаться произвести впечатление на оппонентов.
Re: О "наивном" DI и об архитектурном бессилии
От: _hum_ Беларусь  
Дата: 29.07.16 11:18
Оценка:
так все-таки, какая основная мысль вашего поста — что бездумное использование DI — типичная ошибка неумелого архитектора, или, что сам паттерн переоценен?
Re[3]: О "наивном" DI и об архитектурном бессилии
От: Evgeny.Panasyuk Россия  
Дата: 29.07.16 11:32
Оценка:
Здравствуйте, Lexey, Вы писали:

S>>Простой вообще не должен требовать DI для тестов

L>А как ты предлагаешь подсовывать моки/фейки без DI?

Например как альтернатива serivce locator. В более общем виде — dynamic scoping.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Evgeny.Panasyuk Россия  
Дата: 29.07.16 12:09
Оценка:
Здравствуйте, Lexey, Вы писали:

EP>>Например как альтернатива serivce locator. В более общем виде — dynamic scoping.

L>Service Locator — это не альтернатива, а вариант реализации DI.

Зависит от определения, это уже терминологический вопрос. Вот например из wiki:

Dependency injection separates the creation of a client's dependencies from the client's behavior, which allows program designs to be loosely coupled[7] and to follow the dependency inversion and single responsibility principles.[4][8] It directly contrasts with the service locator pattern, which allows clients to know about the system they use to find dependencies.

Хотя с другой стороны, чуть ниже там:

The different injector implementations (factories, service locators, and dependency injection containers) are not that different as far as dependency injection is concerned.

Re[3]: О "наивном" DI и об архитектурном бессилии
От: _hum_ Беларусь  
Дата: 29.07.16 14:08
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Здравствуйте, _hum_, Вы писали:


__>>так все-таки, какая основная мысль вашего поста — что бездумное использование DI — типичная ошибка неумелого архитектора, или, что сам паттерн переоценен?


IQ>Думаю общая проблема в другом. DI стимулирует неопытных разработчиков городить непродуманные и хрупкие абстракции на ранних стадиях проекта причем там где их нет и быть не может (т.к. в первую очередь они создают DAL), нарушая принципы SOLID. Эти хрупкие абстракции начнут сильно мешать при построении бизнес логики, когда сил и энтузиазма будет уже не так много. А когда еще и сроки начнут поджимать, то бизнес логика оказывается в самом плачевном состоянии.


IQ>И как справедливо написали в камментах:


>>>>В случае с невменяемым DI получается, что конфигурация заменяет архитектуру.



а какая, на ваш взгляд, тогда правильная методология разработки — сперва не думать про DI, и только по прошествие времени, когда система обретет очертания, уже начинать продумывать, что стоит отделять в качестве целостных самодостаточных зависимостей?

кстати, в той же wiki указаны недосатки (наряду с достоинствами), в том числе и те, о которых вы говорите: Dependency_injection_frameworks
Re[4]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.07.16 14:40
Оценка:
Здравствуйте, _hum_, Вы писали:

__>а какая, на ваш взгляд, тогда правильная методология разработки — сперва не думать про DI, и только по прошествие времени, когда система обретет очертания, уже начинать продумывать, что стоит отделять в качестве целостных самодостаточных зависимостей?


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

__>кстати, в той же wiki указаны недосатки (наряду с достоинствами), в том числе и те, о которых вы говорите: Dependency_injection_frameworks


Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: _hum_ Беларусь  
Дата: 29.07.16 14:58
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Здравствуйте, _hum_, Вы писали:


__>>а какая, на ваш взгляд, тогда правильная методология разработки — сперва не думать про DI, и только по прошествие времени, когда система обретет очертания, уже начинать продумывать, что стоит отделять в качестве целостных самодостаточных зависимостей?


IQ>Думаю да, инструменты и механизмы надо использовать по мере необходимости, а не потому, что так модно.


так это верно для любого случая. почему вы выделили именно DI?

__>>кстати, в той же wiki указаны недосатки (наряду с достоинствами), в том числе и те, о которых вы говорите: Dependency_injection_frameworks


IQ>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.


на что все-таки логическое ударение — на "маниакальная страсть к IOC" или на "ранее внедрение DI"?
Re[4]: О "наивном" DI и об архитектурном бессилии
От: itslave СССР  
Дата: 30.07.16 11:27
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, Lexey, Вы писали:


L>>А как ты предлагаешь подсовывать моки/фейки без DI?

S>В самых тяжёлых случаях — moq/ms fakes/NSubstitute etc.
Дык вот если не будет DI, то моки из вышеперечисленных либ по простому прокинуть в тестируемый класс не получится.

S>Во всех остальных проще и дешевле использовать интеграционные тесты. Те же юнит-тесты, только вся инфраструктура уже заведена и доступна к использованию.

Не проще и не дешевле. И писать тяжелей среднестатистическому деву(автоматизаторы вообще отдельная профессия), и дебажить(ну там к примеру рандомные тормоза http, которые локально не репродьясятся валят тесты на серваке), и ранаются они гораздо дольше. А если есть много интеграций с третьесторонними сервисами, то все становится

S>Оно хоть и немного гемморойней на начальном этапе, но зато в итоге не будет такого, что тесты зелёные, а вот работать — упс.

Поэтому нужны и те и эти тесты: юнит чтобы локально прогнать и убедиться что "бизнес логику не поломал" и интеграционные чтобы убедиться в работоспособности приложения.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Sinix  
Дата: 30.07.16 14:08
Оценка:
Здравствуйте, itslave, Вы писали:

S>>В самых тяжёлых случаях — moq/ms fakes/NSubstitute etc.

I>Дык вот если не будет DI, то моки из вышеперечисленных либ по простому прокинуть в тестируемый класс не получится.

Тут полтопика путает DI с IoC, так что вы в хорошей компании

Сорри за подколку. Если серьёзно, то оформление инфраструктурного API в виде интерфейсов и DI — вещи ортогональные. К первому рано или поздно приходят во всех более-менее крупных проектах. Для второго за редкими исключениями нет никаких причин кроме как "прочитал, хочу попробовать". Тесты — это лишь отмазка и не более того. Если ваш код приходится менять именно ради тестов, то это у вас уже следствие вылезло. Первопричина в 100% случаев — бардак в проекте. Его и надо лечить.


I>Не проще и не дешевле. И писать тяжелей среднестатистическому деву(автоматизаторы вообще отдельная профессия), и дебажить(ну там к примеру рандомные тормоза http, которые локально не репродьясятся валят тесты на серваке), и ранаются они гораздо дольше. А если есть много интеграций с третьесторонними сервисами, то все становится.


Так тут тоже путаница с терминологией Давайте не путать интеграционные тесты (всё то же тестирование API, только на уровне крупных блоков, а не отдельных типов) и автотесты/ui-тестирование (aka blackbox testing — используем исключительно публичные интерфейсы продукта, UI — если ничего другого нет). Вы пишете про второе, я — про первое
Последнее — это делянка QA и разработчикам там делать особо нечего, только исправлять места, которые плохо поддаются тестированию.
Re: О "наивном" DI и об архитектурном бессилии
От: UberPsychoSvin  
Дата: 01.08.16 08:30
Оценка:
Здравствуйте, IQuerist, Вы писали:

У меня от DI в проекте:
— Градус общей монструозности вырос. И конструкторы здоровые и интерфейсы "лишние".
+/- через интерфейсы можно что угодно легко вкорячить куда угодно. Это и плюс. И минус — могут прорастать неявные зависимости.
+ Удобно синглтоны создавать. Прописал в конфиге .InSingletonScope() и всё.
+ В тестах можно мокать объекты.
+ Можно через моки погонять на живую часть системы. Типа такого.
var kernel = KernelFactory.Build();
kernel.Rebind<IConfigProvider>().To<Mock1>().InSingletonScope();//ребиндим от чего у нас компонент зависит.
kernel.Rebind<IService>().To<Mock2>().InSingletonScope();
var c = kernel.Get<IComponent>();

И играемся с компонентом в тестовом проекте.

Одним словом:
— Монструозненько.
+ Универсальненько.

----------

А что взамен предлагаете. Такие штуки?
static class LoggingFactoryProvider { ILogFactory get; }
static class WebServiceProvider { IWebService get; }
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.08.16 06:46
Оценка:
Здравствуйте, UberPsychoSvin, Вы писали:

UPS>Здравствуйте, IQuerist, Вы писали:


UPS>У меня от DI в проекте:

UPS>- Градус общей монструозности вырос. И конструкторы здоровые и интерфейсы "лишние".

UPS>А что взамен предлагаете. Такие штуки?


Этот топик не против DI в целом, он против "DI ради DI". Вы похоже хоть какими-то возможностями DI пользуетесь, но большинство новичков только плодит "намертво стабильные абстракции" из DAL хелперов и constructor injection. Исходя из проектов, на которых мне пришлось работать это стало архитектурным шаблоном. Ничего кроме монструозности они не получают и по какой-то странной причине отказываются это замечать.
Re: О "наивном" DI и об архитектурном бессилии
От: r.kamenskiy Россия  
Дата: 02.08.16 11:22
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>О "наивном" DI и об архитектурном бессилии


IQ>Никогда я не имел желания холиварить на тему DI...


А тем временем DI уже попал в ASP Core. И не просто попал, а полноценно поддержан всеми уровнями MVC. Даже появилась возможность инжектить прям во View.
т.е. подразумевается, что DI будет использоваться (и используется) почти во всех Asp Core приложениях.

Как дальше жить будете?
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.08.16 14:07
Оценка:
Здравствуйте, r.kamenskiy, Вы писали:

RK>А тем временем DI уже попал в ASP Core. И не просто попал, а полноценно поддержан всеми уровнями MVC. Даже появилась возможность инжектить прям во View.

RK>т.е. подразумевается, что DI будет использоваться (и используется) почти во всех Asp Core приложениях.

RK>Как дальше жить будете?


Надеюсь неплохо Я категорически приветствую DI, я против горе-прогеров которые используют его например для инжектирования DAL хелперов (Colonoscopy Injection).
Отредактировано 12.08.2016 13:56 IQuerist . Предыдущая версия .
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 10.08.16 07:29
Оценка:
Здравствуйте, Visor2004, Вы писали:

V>И каким же образом он эту концепцию нарушает? BoringItemDataReader небось нужна какая-то конфигурация, ConnectionString, например, а то и IDbContext для стабильной работы, который обычно имеет свое время жизни и правила создания/освобождения и доступен как часть подсистемы, которая хранит настройки, т.е. отдельный сервис в вашей терминологии. Так же может легко еще зависеть от 2-3 абстракций, кэша например и т.д. Мне доводилось видеть поделки людей, которые считали, что для реализации инфраструктуры проекта хватит 10 классов хелперов и все будет ништяк, заканчивалось еще хуже, чем переусложенное новичками DI.


Хорошее дополнение. Я собственно написал пост только потому, что те, кто реализует "наивный DI" ничего вами перечисленного не создают и даже не собираются. Они тупо инжектируют аналоги статических классов со статическими хелперными методами.

Проблема которую я описываю в другом... в пропаганде в среде новичков идеи о том, что если к статическим методам статического класса приделать интерфейс и создавать через DI. То это уже нифига не code smell, а "хорошая архитектура".

PS кстати в последствии это порождает наивные REST интерфейсы и переезд критической части бизнес логики в клиентские скрипты. Как я и определил ранее — Colonoscopy Injection (зависимость от очень конкретных сущностей и повсеместное нарушение DI).
Отредактировано 10.08.2016 8:05 IQuerist . Предыдущая версия . Еще …
Отредактировано 10.08.2016 7:34 IQuerist . Предыдущая версия .
Отредактировано 10.08.2016 7:30 IQuerist . Предыдущая версия .
Re: При чем тут Di?
От: 0x7be СССР  
Дата: 10.08.16 09:33
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>О "наивном" DI и об архитектурном бессилии

При чем тут DI?

Проблема в экзальтированных юношах (любого возраста), которые из-за максимализма и неопытности "следуют принципам" вместо того чтобы думать.
В их руках абсолютно что угодно станет оружием судного дня для проекта.
Re[4]: О "наивном" DI и об архитектурном бессилии
От: IB Австрия http://rsdn.ru
Дата: 10.08.16 13:13
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Например как альтернатива serivce locator. В более общем виде — dynamic scoping.

SL — это тот же DI, только хуже. В DI хоть зависимости в контракте видно, в отличии от..
Мы уже победили, просто это еще не так заметно...
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Evgeny.Panasyuk Россия  
Дата: 10.08.16 13:28
Оценка:
Здравствуйте, IB, Вы писали:

EP>>Например как альтернатива serivce locator. В более общем виде — dynamic scoping.

IB>SL — это тот же DI,

Это уже терминологический вопрос. Смотри цитаты ниже по ветке
Автор: Evgeny.Panasyuk
Дата: 29.07.16
— в одном из мест противопоставление, в другом наоборот подтип.

IB>только хуже.


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

IB>В DI хоть зависимости в контракте видно, в отличии от..


Да, это одно из преимуществ, но не делает автоматически "лучше".
Re[2]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 10.08.16 14:48
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, IQuerist, Вы писали:


IQ>>О "наивном" DI и об архитектурном бессилии

0>При чем тут DI?

0>Проблема в экзальтированных юношах (любого возраста), которые из-за максимализма и неопытности "следуют принципам" вместо того чтобы думать.

0>В их руках абсолютно что угодно станет оружием судного дня для проекта.

Может comrade... я написал про DI, вы можете написать про все остальное — "что угодно"...

Кстати любопытная ситуация, остальное "что угодно" не больно то потакает сокрытию архитектурных проблем , а вот у DI это получается просто блестяще... Приделай к самой низкопробной дряни интерфейс, заверни в DI контейнер и ты мега архитект!
Отредактировано 10.08.2016 14:49 IQuerist . Предыдущая версия .
Re[3]: При чем тут Di?
От: · Великобритания  
Дата: 10.08.16 15:13
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Кстати любопытная ситуация, остальное "что угодно" не больно то потакает сокрытию архитектурных проблем , а вот у DI это получается просто блестяще... Приделай к самой низкопробной дряни интерфейс, заверни в DI контейнер и ты мега архитект!

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

Так что... сабж?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 06:29
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>Кстати любопытная ситуация, остальное "что угодно" не больно то потакает сокрытию архитектурных проблем , а вот у DI это получается просто блестяще... Приделай к самой низкопробной дряни интерфейс, заверни в DI контейнер и ты мега архитект!


·>DI сам по себе отличная штука.


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

·>Вот скажем "DI" и "DI IoC-контейнер" это разные вещи. Использовать DI можно (а на прошлой моей работе даже решили что нужно) без контейнера.

·>И интерфейсы тоже к DI отношения не имеют. Можно использовать DI и без интерфейсов.

Можно делать всякое... я описал конкретный кейс который имхо наблюдается повсеместно, но почему-то мало критикуется или критикуется не по делу.
Re[4]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 06:36
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Хотя, конечно, это не "они" (сиречь, паттерны) а люди. Вся проблема в людях и только в них.


Ну уж ладно наша отрасль имхо построена таки не на людях, а на идеях. А идеи принадлежат сообществам. Так что причина должна быть в каких-то сообществах которые распространяют неполные идеи
Re[6]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 08:09
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, IQuerist, Вы писали:


IQ>>Ну уж ладно наша отрасль имхо построена таки не на людях, а на идеях. А идеи принадлежат сообществам. Так что причина должна быть в каких-то сообществах которые распространяют неполные идеи ))

0>Ты попробуй заставить идеи написать тебе программу без людей

Гораздо интереснее то, что напишут люди без идей.

0>Или возьми случайных людей с улицы, дай им книжку с правильными идеями и посмотри, что они тебе сделают


Неверно идеи принадлежат сообществам. Идеи изложенные в книгах это таки опять частное изложение частного видения...
Re[7]: При чем тут Di?
От: 0x7be СССР  
Дата: 11.08.16 09:30
Оценка:
Здравствуйте, IQuerist, Вы писали:

0>>Ты попробуй заставить идеи написать тебе программу без людей

IQ> Гораздо интереснее то, что напишут люди без идей.
Я видел такое. Обычно это как-то работает, но внутри адский ад.
А когда экзальтированные юноши берутся делать "всё по уму", то оно не работает, а внутри адский ад.
Разница только в том, что под каждый элемент этого ада юноши могут сказать много умных слов, почему так сделано.
Между этими двумя вариантами я выбираю первый

0>>Или возьми случайных людей с улицы, дай им книжку с правильными идеями и посмотри, что они тебе сделают

IQ>Неверно идеи принадлежат сообществам. Идеи изложенные в книгах это таки опять частное изложение частного видения...
Что не верно?
Сделай какое-нибудь утверждение, а то спор зашёл в тупик
Re[8]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 09:51
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, IQuerist, Вы писали:


0>>>Ты попробуй заставить идеи написать тебе программу без людей

IQ>> Гораздо интереснее то, что напишут люди без идей.
0>Между этими двумя вариантами я выбираю первый

Я кстати тоже Какой смысл делать инвестиции в заведомый г...код.

0>>>Или возьми случайных людей с улицы, дай им книжку с правильными идеями и посмотри, что они тебе сделают

IQ>>Неверно идеи принадлежат сообществам. Идеи изложенные в книгах это таки опять частное изложение частного видения...
0>Что не верно?
0>Сделай какое-нибудь утверждение, а то спор зашёл в тупик

Да, over-philosophy детектед это наводки из другого хреда
Re[10]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 12:25
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, IQuerist, Вы писали:


IQ>>Я кстати тоже Какой смысл делать инвестиции в заведомый г...код.


0>Очень простой. Если ты знаешь, что этот г-код тебе принесет деньги, то почему бы и нет?


Не... я про то, что не стоит тратить время и силы пытаясь представить г...код в виде что-то пристойного.

Какой смысл делать ЛИШНИЕ инвестиции в заведомый г...код.
Re[5]: При чем тут Di?
От: · Великобритания  
Дата: 11.08.16 13:11
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Вот скажем "DI" и "DI IoC-контейнер" это разные вещи. Использовать DI можно (а на прошлой моей работе даже решили что нужно) без контейнера.

IQ>·>И интерфейсы тоже к DI отношения не имеют. Можно использовать DI и без интерфейсов.
IQ>Можно делать всякое... я описал конкретный кейс который имхо наблюдается повсеместно, но почему-то мало критикуется или критикуется не по делу.
Ты описал кейс, но не предложил альтернативу. Как надо-то по-твоему?

IQ>Гиперболизируя можно было бы добавить еще IJsonConverter чтобы механизм конвертирования json можно было изменить

А ты не подумал, что тот же JsonConverter может иметь ещё пять зависимостей, скажем настройки форматирования json и какие-нибудь там сериализаторы кастомных типов?

IQ>и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но

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

IQ>на всякий случай стоит "уменьшить зависимости"

DI не уменьшает зависимости, а делает их явными.

Единственное что в твоём коде я бы поменял, так это выкинул все эти I* интерфейсы и инжектил бы сами классы. Интерфейс лежащий рядом с единственной имплементацией — не нужен.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[11]: При чем тут Di?
От: 0x7be СССР  
Дата: 11.08.16 13:21
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Не... я про то, что не стоит тратить время и силы пытаясь представить г...код в виде что-то пристойного.

IQ>Какой смысл делать ЛИШНИЕ инвестиции в заведомый г...код.
Теперь понял
Re[6]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 14:02
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>Можно делать всякое... я описал конкретный кейс который имхо наблюдается повсеместно, но почему-то мало критикуется или критикуется не по делу.

·>Ты описал кейс, но не предложил альтернативу. Как надо-то по-твоему?

Альтернатива простая — г...кодить г...код без DI.

IQ>>Гиперболизируя можно было бы добавить еще IJsonConverter чтобы механизм конвертирования json можно было изменить

·>А ты не подумал, что тот же JsonConverter может иметь ещё пять зависимостей, скажем настройки форматирования json и какие-нибудь там сериализаторы кастомных типов?
IQ>>и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но
·>А мы так сделали в нашем проекте, ибо да, у нас "текущее время" оказалось вещью необычной.

Я привел имхо довольно понятную ситуацию, зачем вы мне описываете варианты где использование DI вполне уместно? Я же не говорю, что таких вообще не существует.

IQ>>на всякий случай стоит "уменьшить зависимости"

·>DI не уменьшает зависимости, а делает их явными.

Мы используем DI чтобы уменьшить/снизить зависимости — это не моя формулировка, это первое из обоснований наивного использования DI. Второе — DI позволит нам еще лучше писать юнит тесты.

·>Единственное что в твоём коде я бы поменял, так это выкинул все эти I* интерфейсы и инжектил бы сами классы. Интерфейс лежащий рядом с единственной имплементацией — не нужен.


Тогда пропадает видимость IoC — половина священной коровы.
Отредактировано 11.08.2016 14:26 IQuerist . Предыдущая версия .
Re[7]: При чем тут Di?
От: · Великобритания  
Дата: 11.08.16 14:23
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Можно делать всякое... я описал конкретный кейс который имхо наблюдается повсеместно, но почему-то мало критикуется или критикуется не по делу.

IQ>·>Ты описал кейс, но не предложил альтернативу. Как надо-то по-твоему?
IQ>Альтернатива простая — г...кодить г...код без DI.
Это как? И чем это лучше?

IQ>>>и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но

IQ>·>А мы так сделали в нашем проекте, ибо да, у нас "текущее время" оказалось вещью необычной.
IQ>Я привел имхо довольно понятную ситуацию, зачем вы мне описываете варианты где использование DI вполне уместно? Я же не говорю, что таких вообще не существует.
Ты привёл ситуацию, но я не вижу в ней ничего криминального. Я и пытаюсь добиться конкретики. Что именно плохо и как должно быть чтобы стало хорошо?

IQ>>>на всякий случай стоит "уменьшить зависимости"

IQ>·>DI не уменьшает зависимости, а делает их явными.
IQ>Мы используем DI чтобы уменьшить/снизить зависимости — это не моя формулировка, это первое из обоснований наивного использования DI. Второе — DI позволит нам еще лучше писать юнит тесты.
Это уже следствие. Когда зависимости явные — их можно перелопатить и уменьшить.
ЮТ — да, как следствие тоже упрощаются, т.к. понятие юнита тоже становится явным.

IQ>·>Единственное что в твоём коде я бы поменял, так это выкинул все эти I* интерфейсы и инжектил бы сами классы. Интерфейс лежащий рядом с единственной имплементацией — не нужен.

IQ> Тогда пропадает видимость — IoC половина священной коровы.
Ы? Что за бред? Что пропадает? Куда пропадает?
В DI никаких интерфейсов нет. Найди мне их тут: https://en.wikipedia.org/wiki/Dependency_injection#Examples
Видимо просто люди не понимают что такое DI, но свои проблемы валят именно на него.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 11.08.16 15:23
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>Можно делать всякое... я описал конкретный кейс который имхо наблюдается повсеместно, но почему-то мало критикуется или критикуется не по делу.

IQ>>·>Ты описал кейс, но не предложил альтернативу. Как надо-то по-твоему?
IQ>>Альтернатива простая — г...кодить г...код без DI.
·>Это как? И чем это лучше?

это значительно экономит время и силы и г...кодеру и окружающим...

IQ>>>>и что ни будь вроде IDateTimeProvider, работа с датой и временем вряд ли поменяется, но

IQ>>·>А мы так сделали в нашем проекте, ибо да, у нас "текущее время" оказалось вещью необычной.
IQ>>Я привел имхо довольно понятную ситуацию, зачем вы мне описываете варианты где использование DI вполне уместно? Я же не говорю, что таких вообще не существует.
·>Ты привёл ситуацию, но я не вижу в ней ничего криминального. Я и пытаюсь добиться конкретики. Что именно плохо и как должно быть чтобы стало хорошо?

То ли боги тотально берегли вас от случаев убогого использования DI, то ли вы видели его на на картинках в книжках... Если вы не видите в моем примере типичного антипаттерна, я могу вам только позавидовать.

IQ>>>>на всякий случай стоит "уменьшить зависимости"

IQ>>·>DI не уменьшает зависимости, а делает их явными.
IQ>>Мы используем DI чтобы уменьшить/снизить зависимости — это не моя формулировка, это первое из обоснований наивного использования DI. Второе — DI позволит нам еще лучше писать юнит тесты.
·>Это уже следствие. Когда зависимости явные — их можно перелопатить и уменьшить.
·>ЮТ — да, как следствие тоже упрощаются, т.к. понятие юнита тоже становится явным.

Нету в убогих проектах никаких юнит тестов не доживают они до них

IQ>>·>Единственное что в твоём коде я бы поменял, так это выкинул все эти I* интерфейсы и инжектил бы сами классы. Интерфейс лежащий рядом с единственной имплементацией — не нужен.

IQ>> Тогда пропадает видимость — IoC половина священной коровы.
·>Ы? Что за бред? Что пропадает? Куда пропадает?
·>В DI никаких интерфейсов нет. Найди мне их тут: https://en.wikipedia.org/wiki/Dependency_injection#Examples

Расскажите это тем кто пытается пихать DI всюду где есть оператор new или вызов статической функции
Отредактировано 11.08.2016 15:24 IQuerist . Предыдущая версия .
Re[10]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 12.08.16 06:02
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>·>Ты привёл ситуацию, но я не вижу в ней ничего криминального. Я и пытаюсь добиться конкретики. Что именно плохо и как должно быть чтобы стало хорошо?

IQ>>То ли боги тотально берегли вас от случаев убогого использования DI, то ли вы видели его на на картинках в книжках... Если вы не видите в моем примере типичного антипаттерна, я могу вам только позавидовать.
·>Я пока только вижу код, который назван "плохим". Но код не бывает абстрактно плохим. Он может быть только хуже/лучше некоего другого кода по неким критериям. Вот это я и пытаюсь выудить из тебя: какой код ты считаешь лучше и почему.

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

Любой другой сходный г...код без DI будет лучше по одной простой причине — он будет значительно проще и меньше по объему в 2-3 раза. А значит не будет создавать препятствий рефакторингу

IQ>> Нету в убогих проектах никаких юнит тестов не доживают они до них

·>Допустим. И причём тут DI?

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

·>Похоже ты обжёгся на молоке, и теперь дуешь на воду.


Я я пишу не о себе, а о других, которые почему-то массово делают одни и те же ошибки, увы связанные с DI. Потому пост и появился.

IQ>>>> Тогда пропадает видимость — IoC половина священной коровы.

IQ>>·>Ы? Что за бред? Что пропадает? Куда пропадает?
IQ>>·>В DI никаких интерфейсов нет. Найди мне их тут: https://en.wikipedia.org/wiki/Dependency_injection#Examples
IQ>>Расскажите это тем кто пытается пихать DI всюду где есть оператор new или вызов статической функции
·>Ага... значит интерфейсы тут не причём как выяснилось. Но в начальном сообщении new и статических функций не было. Может приведёшь более выразительный пример?

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

·>Т.е. проблема в том, что люди создают интерфейсы где попало, бормоча "во имя DI!", так что-ли? Ну такое надо лечить только ликбезом по мягким местам...


Так и я о том же. Но я выделил имхо общепринятый антипаттерн, о котором и написал пост. Пост ведь называется не "Какой же б-гомерзкий этот ваш DI, гореть ему в аду", а — "О "наивном" DI и об архитектурном бессилии".
Отредактировано 12.08.2016 8:21 IQuerist . Предыдущая версия . Еще …
Отредактировано 12.08.2016 6:53 IQuerist . Предыдущая версия .
Отредактировано 12.08.2016 6:05 IQuerist . Предыдущая версия .
Re[11]: При чем тут Di?
От: · Великобритания  
Дата: 12.08.16 09:15
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Я пока только вижу код, который назван "плохим". Но код не бывает абстрактно плохим. Он может быть только хуже/лучше некоего другого кода по неким критериям. Вот это я и пытаюсь выудить из тебя: какой код ты считаешь лучше и почему.

IQ> А незачем особенно всматриваться в код, код лишь намек по которому имхо очень просто определить антипаттерн.
IQ>Любой другой сходный г...код без DI будет лучше по одной простой причине — он будет значительно проще и меньше по объему в 2-3 раза. А значит не будет создавать препятствий рефакторингу
Блин. Пятый раз прошу! Покажи этот самый любой другой сходный гкод!!!

IQ>>> Нету в убогих проектах никаких юнит тестов не доживают они до них

IQ>·>Допустим. И причём тут DI?
IQ>При том, что его впихивают в проект обосновывая тем, что проще будет писать юнит тесты, которые, к слову как правило никогда не будут написаны
Ок. Да, пихают, но тесты не пишут. Тесты не пишут — да, это плохо, полностью согласен. А то что пихание само по себе плохо — мне не очевидно, обоснуй.

IQ>·>Похоже ты обжёгся на молоке, и теперь дуешь на воду.

IQ>Я я пишу не о себе, а о других, которые почему-то массово делают одни и те же ошибки, увы связанные с DI. Потому пост и появился.
Ошибка — не писать тесты, ошибка — создавать интерфейс для каждого класса. Каким образом это связанно с DI?!

IQ>>>Расскажите это тем кто пытается пихать DI всюду где есть оператор new или вызов статической функции

IQ>·>Ага... значит интерфейсы тут не причём как выяснилось. Но в начальном сообщении new и статических функций не было. Может приведёшь более выразительный пример?
IQ>Для чего? Кейс мегатипичный, те кто сталкивался думаю сразу все поймут. А кто не сталкивался, увы, опыт придется получать самостоятельно.
Почему придётся? Может я никогда и не столкнусь.

IQ>·>Т.е. проблема в том, что люди создают интерфейсы где попало, бормоча "во имя DI!", так что-ли? Ну такое надо лечить только ликбезом по мягким местам...

IQ> Так и я о том же. Но я выделил имхо общепринятый антипаттерн, о котором и написал пост. Пост ведь называется не "Какой же б-гомерзкий этот ваш DI, гореть ему в аду", а — "О "наивном" DI и об архитектурном бессилии".
Может я что-то не понимаю, но чего-то плохого в приведённом коде я не увидел. Конструктор с пятью параметрами? Мне попадалось с 37, и это было вполне нормально, т.к. код был хоть и массивный, но тривиальный.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 12.08.16 10:14
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>·>Я пока только вижу код, который назван "плохим". Но код не бывает абстрактно плохим. Он может быть только хуже/лучше некоего другого кода по неким критериям. Вот это я и пытаюсь выудить из тебя: какой код ты считаешь лучше и почему.

IQ>> А незачем особенно всматриваться в код, код лишь намек по которому имхо очень просто определить антипаттерн.
IQ>>Любой другой сходный г...код без DI будет лучше по одной простой причине — он будет значительно проще и меньше по объему в 2-3 раза. А значит не будет создавать препятствий рефакторингу
·>Блин. Пятый раз прошу! Покажи этот самый любой другой сходный гкод!!!

Как вы себе это представляете? Вам enterprise проект выложить? И вы в нем будете копаться? Я понимаю, что ваши требования явить конкретный пример это софистский прием, но не понимаю смысла, демонстрируемого вами упорства, в теме где нет холивара

IQ>>>> Нету в убогих проектах никаких юнит тестов не доживают они до них

IQ>>·>Допустим. И причём тут DI?
IQ>>При том, что его впихивают в проект обосновывая тем, что проще будет писать юнит тесты, которые, к слову как правило никогда не будут написаны
·>Ок. Да, пихают, но тесты не пишут. Тесты не пишут — да, это плохо, полностью согласен. А то что пихание само по себе плохо — мне не очевидно, обоснуй.

т.е. по вашему, принимать решения основываясь на причинах, которые причинами не являются, это серьезный разговор?

IQ>>·>Похоже ты обжёгся на молоке, и теперь дуешь на воду.

IQ>>Я я пишу не о себе, а о других, которые почему-то массово делают одни и те же ошибки, увы связанные с DI. Потому пост и появился.
·>Ошибка — не писать тесты, ошибка — создавать интерфейс для каждого класса. Каким образом это связанно с DI?!

Это вы мне объясните каким волшебным образом решение о неуместном использовании DI попадает в ряд самых глупых и банальных ошибок

IQ>>·>Ага... значит интерфейсы тут не причём как выяснилось. Но в начальном сообщении new и статических функций не было. Может приведёшь более выразительный пример?

IQ>>Для чего? Кейс мегатипичный, те кто сталкивался думаю сразу все поймут. А кто не сталкивался, увы, опыт придется получать самостоятельно.
·>Почему придётся? Может я никогда и не столкнусь.

Значит незачем забивать себе голову

IQ>>·>Т.е. проблема в том, что люди создают интерфейсы где попало, бормоча "во имя DI!", так что-ли? Ну такое надо лечить только ликбезом по мягким местам...

IQ>> Так и я о том же. Но я выделил имхо общепринятый антипаттерн, о котором и написал пост. Пост ведь называется не "Какой же б-гомерзкий этот ваш DI, гореть ему в аду", а — "О "наивном" DI и об архитектурном бессилии".
·>Может я что-то не понимаю, но чего-то плохого в приведённом коде я не увидел. Конструктор с пятью параметрами? Мне попадалось с 37, и это было вполне нормально, т.к. код был хоть и массивный, но тривиальный.

Проблема не в коде, а в ситуации. Если вы с такой не сталкивались, то вероятно пост не для вас.
Re[14]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 12.08.16 13:32
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>>>·>Похоже ты обжёгся на молоке, и теперь дуешь на воду.

IQ>>>>Я я пишу не о себе, а о других, которые почему-то массово делают одни и те же ошибки, увы связанные с DI. Потому пост и появился.
IQ>>·>Ошибка — не писать тесты, ошибка — создавать интерфейс для каждого класса. Каким образом это связанно с DI?!
IQ>>Это вы мне объясните каким волшебным образом решение о неуместном использовании DI попадает в ряд самых глупых и банальных ошибок
·>Опять двадцать пять. "неуместном использовании DI". Мой тезис — в типичном проекте неуместного использования DI не бывает

Вооот! Вот с этого и надо было начинать! А то объясни, докажи, покажи код А все это бессмысленно, если оппонент — религиозный фанатик упорствующий в ереси.

Вам не в комментах стоит холиварить, а свой собственный пост запилить об абсолютной святости DI, с обоснованиями и доказательствами и приложенными enterprise проектами
Re[8]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 12.08.16 13:49
Оценка:
Здравствуйте, 0x7be, Вы писали:

0>Здравствуйте, IQuerist, Вы писали:


0>>>Ты попробуй заставить идеи написать тебе программу без людей

IQ>> Гораздо интереснее то, что напишут люди без идей.
0>Я видел такое. Обычно это как-то работает, но внутри адский ад.
0>А когда экзальтированные юноши берутся делать "всё по уму", то оно не работает, а внутри адский ад.
0>Разница только в том, что под каждый элемент этого ада юноши могут сказать много умных слов, почему так сделано.
0>Между этими двумя вариантами я выбираю первый

Главная опасность второго варианта имхо в том, что имеющий оправдания, не станет ничего менять и исправлять.
Re[15]: При чем тут Di?
От: · Великобритания  
Дата: 12.08.16 14:53
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Опять двадцать пять. "неуместном использовании DI". Мой тезис — в типичном проекте неуместного использования DI не бывает

IQ>Вооот! Вот с этого и надо было начинать! А то объясни, докажи, покажи код А все это бессмысленно, если оппонент — религиозный фанатик упорствующий в ереси.
IQ>Вам не в комментах стоит холиварить, а свой собственный пост запилить об абсолютной святости DI,
Об абсолютной святости ты сам досочинил. Я утверждаю лишь что уж пусть будет гкод с DI, чем гкод без DI.

IQ>с обоснованиями и доказательствами

А собсвенно тут писать нечего. Если сделать работу за тебя и перечислить альтернативы DI:
  1. big ball of mud
  2. global variable
  3. service locator
то станет очевидно, что DI не так уж плох как ты его рисуешь.

IQ>и приложенными enterprise проектами

Ага, ты значит запилил пост с какой-то лажей из пяти строк, а с меня enterprise проекты требуешь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[8]: О "наивном" DI и об архитектурном бессилии
От: Cyberax Марс  
Дата: 13.08.16 10:26
Оценка:
Здравствуйте, Sinix, Вы писали:

I>>Есть целая методология TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла, она популярная, модная, молодежная и все такое.

S>Она отлично работает для инфраструктуры, почти для любого масштаба, неплохо работает для мелочёвки и абсолютно не работает даже для средних проектов. Чтоб было понятно, что такое средний проект: представь себе типовой биз-кейз в виде 20-страничного документа 12 шрифтом, в котором 90% текста — не вода, а логика, причём высокоуровневая, без расписывания до отдельных инструкций.
Вот прекрасно всё работает, в условиях ещё более жёстких. Более того, без TDD всё очень плохо, так как про эту логику на 100500 листах 12-шрифтом через смену одного поколения разработчиков (2-3 года) никто знать даже не будет.

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

А если система ещё и сложная, с внешними зависимостями, то вообще вариантов никаких нет. Только TDD с mock'ами поведения внешних сервисов.
Sapienti sat!
Re[9]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 15.08.16 06:12
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Здравствуйте, Sinix, Вы писали:


I>>>Есть целая методология TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла, она популярная, модная, молодежная и все такое.

S>>Она отлично работает для инфраструктуры, почти для любого масштаба, неплохо работает для мелочёвки и абсолютно не работает даже для средних проектов. Чтоб было понятно, что такое средний проект: представь себе типовой биз-кейз в виде 20-страничного документа 12 шрифтом, в котором 90% текста — не вода, а логика, причём высокоуровневая, без расписывания до отдельных инструкций.
C>Вот прекрасно всё работает, в условиях ещё более жёстких. Более того, без TDD всё очень плохо, так как про эту логику на 100500 листах 12-шрифтом через смену одного поколения разработчиков (2-3 года) никто знать даже не будет.

C>В случае TDD останутся тесты, которые хотя бы сломаются при "невинном" рефакторинге.


Или останутся тесты, которые не сломаются при ошибочном рефакторинге, увы... здесь гарантий никаких.
Re[16]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 15.08.16 06:29
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>Вам не в комментах стоит холиварить, а свой собственный пост запилить об абсолютной святости DI,

·>Об абсолютной святости ты сам досочинил. Я утверждаю лишь что уж пусть будет гкод с DI, чем гкод без DI.

Для обоснования своей позиции я написал целый пост. Для обоснования своей вы не написали и одной полной строки. Несимметрично.

IQ>>с обоснованиями и доказательствами

·>А собсвенно тут писать нечего. Если сделать работу за тебя и перечислить альтернативы DI:
·>

    ·>
  1. big ball of mud
    ·>
  2. global variable
    ·>
  3. service locator
    ·>
·>то станет очевидно, что DI не так уж плох как ты его рисуешь.

В последнее время, мне как раз попадались реализации big ball of mud исключительно с DI

global variable и service locator и что в них плохого на ранних этапах развития проекта? Вы забыли оператор new забанить, он же главный источник неуправляемых связей.

IQ>>и приложенными enterprise проектами

·>Ага, ты значит запилил пост с какой-то лажей из пяти строк, а с меня enterprise проекты требуешь.

Ну вы то пока даже с "лажей" поста не запилили, одно нытье и литании.
Re[18]: При чем тут Di?
От: Sinix  
Дата: 15.08.16 09:43
Оценка:
Здравствуйте, ·, Вы писали:

·>Тем что это типичный technical debt. Если, конечно, не писать проекты-однодневки (а с ними всё просто — пиши как хочешь, всё пофиг), то потом от них придётся избавляться, что всегда довольно болезненно: рефакторить DI проще, чем GV или SL.


Ага! Наконец-то мне попался человек, который переделывает SL на DI, а не наоборот. Такой вопрос: а как вы решаете проблему цепочек зависимостей в бизнес-коде?
Ну, когда бизнес-сервис A вызывает B, тот — C и D и у всех есть свои уникальные зависимости?

·>А как ты реализуешь плагины с DI?

Как я понял, IQuerist про предоставление системного API плагинам, а не про встраивание самих плагинов. Для этого DI — самое оно, смотрим на extensions студии.
Re[19]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 10:00
Оценка:
Здравствуйте, Sinix, Вы писали:

S>·>Тем что это типичный technical debt. Если, конечно, не писать проекты-однодневки (а с ними всё просто — пиши как хочешь, всё пофиг), то потом от них придётся избавляться, что всегда довольно болезненно: рефакторить DI проще, чем GV или SL.

S>Ага! Наконец-то мне попался человек, который переделывает SL на DI, а не наоборот. Такой вопрос: а как вы решаете проблему цепочек зависимостей в бизнес-коде?
S>Ну, когда бизнес-сервис A вызывает B, тот — C и D и у всех есть свои уникальные зависимости?
Не совсем понял. Что за проблема-то? Вроде пишешь как слышишь:
class ServiceA
{
    ServiceA(SerivceB b, CommonDependency1 cd1, CommonDependency2 cd2, UniqueDependecyA uA...)
}
class ServiceB
{
    ServiceB(SerivceC c, SerivceD d, CommonDependency1 cd1, CommonDependency2 cd2, UniqueDependecy1 u1...)
}
...

И что приятно — оно тебя будет круто бить по рукам, если вдруг захочется создать циклическую зависимость (захочешь вдруг использовать A из C — будет облом).

S>·>А как ты реализуешь плагины с DI?

S>Как я понял, IQuerist про предоставление системного API плагинам, а не про встраивание самих плагинов. Для этого DI — самое оно, смотрим на extensions студии.
Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: О "наивном" DI и об архитектурном бессилии
От: Cyberax Марс  
Дата: 15.08.16 10:12
Оценка:
Здравствуйте, Sinix, Вы писали:

C>>Вот прекрасно всё работает, в условиях ещё более жёстких.

S>Так мы не про сами тесты, а про "TDD, которая именно юнит тестирование(и как следствие DI) ставит во главу угла".
Пофиг. Юнит-тесты писать проще всего. И по наблюдениям, если юнит-тестов мало, то интеграционных тестов нет вообще.

S>Излишний радикализм с отдельными тестами на каждую мелочь на практике поднимает стоимость сопровождения раза в два из-за колоссального объёма кода, который приходится править при изменении бизнес-правил у очередного заказчика (что скорее обыденность, чем что-то исключительное).

Так это говнокод, однако. Если изменение одного заказчика ломает 100500 тестов, то код или тесты написаны плохо. Думайте как переделать.

C>>А если система ещё и сложная, с внешними зависимостями, то вообще вариантов никаких нет. Только TDD с mock'ами поведения внешних сервисов.

S>Не-не-не, для сложных систем тру-TDD не работает. Получается ИБД в чистом виде. Везде красота и благолепие, тесты зеленеют, одни внедренцы без валерьянки к клиентам не ездят.
Тесты значительно СНИЖАЮТ стоимость разработки как раз из-за этого. Программист после небольшого изменения не ждёт конца интеграционных тестов, а сразу запускает локальные юнит-тесты с mock'ами. Конечно, они не идеальны, но находят процентов так 95 рутинных ошибок времени разработки.

Вторые 95% догоняются на этапе интеграционного тестирования.
Sapienti sat!
Re[18]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 15.08.16 10:18
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>Вам не в комментах стоит холиварить, а свой собственный пост запилить об абсолютной святости DI,

IQ>>·>Об абсолютной святости ты сам досочинил. Я утверждаю лишь что уж пусть будет гкод с DI, чем гкод без DI.
IQ>> Для обоснования своей позиции я написал целый пост. Для обоснования своей вы не написали и одной полной строки. Несимметрично.
·>Я уже написал достаточно в этой ветке. Ты правда считаешь, что имеет смысл накопипастить новый пост?

Вам решать

IQ>>В последнее время, мне как раз попадались реализации big ball of mud исключительно с DI

·>Так повезло, видимо, найди нормальную работу. Но с чего ты взял что BBoM с global variable или с service locator будет хоть чем-то лучше?

Бесполезно кругом одни и те же сектанты DI.

IQ>>global variable и service locator и что в них плохого на ранних этапах развития проекта?

·>Тем что это типичный technical debt.

На ранних этапах имхо "technical debt" и "оптимизация" не те вещи от которых что-то зависит.

>>>Если, конечно, не писать проекты-однодневки (а с ними всё просто — пиши как хочешь, всё пофиг), то потом от них придётся избавляться, что всегда довольно болезненно: рефакторить DI проще, чем GV или SL.


Ну сказочки то не рассказывайте. DI дает очень серьезную синтаксическую нагрузку, плюс как правило неумелый дизайн модели с постоянным копированием и мапингом одних и тех же entity. Из за этого часто вообще не хочется затевать рефакторинг.

·>Кстати, вот это:

·>

Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры".

·>тоже не понимание предмета. Вот как раз SL лучше подходит для плагинной архитектуры, особенно когда связывание происходит runtime.
·>А как ты реализуешь плагины с DI?

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

·>Далее:

·>

Модули верхних уровней не должны зависеть от модулей нижних уровней

·>только именно так и получится сделать если использовать только DI с Constructor Injection. Ибо ты просто не сможешь создать объекты если уровни смешиваются. DAG, однако.

Нда... 98% виденных мною внедряемых сервисов были DAL хелперами. Ну и как же без обязательного для такого случая ILoggerManager. Обращаю в 1001 раз ваше внимание DAL это крайне низкий уровень. И никакие обертки и мапперы не делают его выше.

·>В случае с GV и SL — легко получается месиво зависимостей всего от всего, которое потом фиг распутаешь.


Я собственно и написал, пост из за того, что с использованием DI делает такое месиво куда более "густым"

IQ>>Вы забыли оператор new забанить, он же главный источник неуправляемых связей.

·>Что значит забанить? В DI он не банится, а переносится наружу, в wiring-код.

Забанить значит — тотально (по религиозным причинам)
Re[11]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 15.08.16 10:25
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>>>А если система ещё и сложная, с внешними зависимостями, то вообще вариантов никаких нет. Только TDD с mock'ами поведения внешних сервисов.

S>>Не-не-не, для сложных систем тру-TDD не работает. Получается ИБД в чистом виде. Везде красота и благолепие, тесты зеленеют, одни внедренцы без валерьянки к клиентам не ездят.
C>Тесты значительно СНИЖАЮТ стоимость разработки как раз из-за этого. Программист после небольшого изменения не ждёт конца интеграционных тестов, а сразу запускает локальные юнит-тесты с mock'ами. Конечно, они не идеальны, но находят процентов так 95 рутинных ошибок времени разработки.

Какие-то вы фантастические вещи рассказываете. Вы в какой области работаете?
Re[20]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 15.08.16 10:27
Оценка:
Здравствуйте, ·, Вы писали:

S>>·>А как ты реализуешь плагины с DI?

S>>Как я понял, IQuerist про предоставление системного API плагинам, а не про встраивание самих плагинов. Для этого DI — самое оно, смотрим на extensions студии.
·>Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?

А вот это уже интересно в какой же программерской области находится подлинное царство DI? В какой области вы работаете и на чем?
Re[19]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 10:52
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>В последнее время, мне как раз попадались реализации big ball of mud исключительно с DI

IQ>·>Так повезло, видимо, найди нормальную работу. Но с чего ты взял что BBoM с global variable или с service locator будет хоть чем-то лучше?
IQ>Бесполезно кругом одни и те же сектанты DI.
"Да их тут тысячи!" (c)

IQ>>>global variable и service locator и что в них плохого на ранних этапах развития проекта?

IQ>·>Тем что это типичный technical debt.
IQ> На ранних этапах имхо "technical debt" и "оптимизация" не те вещи от которых что-то зависит.
А гкодерство и пессимизация — от них зависит перспективность проекта.

>>>>Если, конечно, не писать проекты-однодневки (а с ними всё просто — пиши как хочешь, всё пофиг), то потом от них придётся избавляться, что всегда довольно болезненно: рефакторить DI проще, чем GV или SL.

IQ>Ну сказочки то не рассказывайте. DI дает очень серьезную синтаксическую нагрузку,
Какую нагрузку? Появляется только конструктор со списком зависимостей. Всё.
Кстати, это хороший индикатор. Если этот самый конструктор начинает выглядеть монструозно, то это значит что класс начинает становиться универсальным всемогутером, нужен рефакторинг.

IQ>плюс как правило неумелый дизайн модели с постоянным копированием и мапингом одних и тех же entity. Из за этого часто вообще не хочется затевать рефакторинг.

Блин... Ещё какие-то маппинги вылезли. И причём тут DI??

IQ>·>Кстати, вот это:

IQ>·>

Лично для меня DI изначально был всего лишь удобным механизмом построения "плагинной архитектуры".

IQ>·>тоже не понимание предмета. Вот как раз SL лучше подходит для плагинной архитектуры, особенно когда связывание происходит runtime.
IQ>·>А как ты реализуешь плагины с DI?
IQ>Никак мои проекты это тонны быстро устаревающей бизнес логики, которую заказчик хочет получить как правило вчера. Никаких плагинов там не вырисовывается в принципе, код завязан на конкретную бизнес логику никакой реюз не предполагается. Спасает исключительно дисциплина и декомпозиция.
DI к реюзу тоже не относится (или ты опять про интерфейсы?!), а вот дисциплину и декомпозицию он улучшает, засчёт того, что явно требует структурировать зависимости в DAG.

IQ>·>Далее:

IQ>·>

Модули верхних уровней не должны зависеть от модулей нижних уровней

IQ>·>только именно так и получится сделать если использовать только DI с Constructor Injection. Ибо ты просто не сможешь создать объекты если уровни смешиваются. DAG, однако.
IQ>Нда... 98% виденных мною внедряемых сервисов были DAL хелперами. Ну и как же без обязательного для такого случая ILoggerManager. Обращаю в 1001 раз ваше внимание DAL это крайне низкий уровень. И никакие обертки и мапперы не делают его выше.
Уже хорошо. Хуже когда из DAL-хелперов кто-то вдруг начинает обращаться к HttpContext.Current.

IQ>·>В случае с GV и SL — легко получается месиво зависимостей всего от всего, которое потом фиг распутаешь.

IQ> Я собственно и написал, пост из за того, что с использованием DI делает такое месиво куда более "густым"
Каким образом? Оно же тупо не скомпилится.

IQ>>>Вы забыли оператор new забанить, он же главный источник неуправляемых связей.

IQ>·>Что значит забанить? В DI он не банится, а переносится наружу, в wiring-код.
IQ>Забанить значит — тотально (по религиозным причинам)
Ну бань, если хочется. Но причём тут DI???
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 10:56
Оценка:
Здравствуйте, IQuerist, Вы писали:

S>>>Как я понял, IQuerist про предоставление системного API плагинам, а не про встраивание самих плагинов. Для этого DI — самое оно, смотрим на extensions студии.

IQ>·>Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?
IQ>А вот это уже интересно в какой же программерской области находится подлинное царство DI? В какой области вы работаете и на чем?
Я в Java-мире живу, backend всякий, low latency.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[20]: При чем тут Di?
От: Sinix  
Дата: 15.08.16 12:00
Оценка:
Здравствуйте, ·, Вы писали:

·>Не совсем понял. Что за проблема-то? Вроде пишешь как слышишь:

А, это я главный нюанс забыл, миль пардон

Зависимости надо динамически разруливать, а не в момент создания сервисов. Без этого приходится городить отдельные костыли для всего, что связано с контекстом — от локальных транзакций и до кэша с логированием. Т.е. нужно что-то делать с кодом типа
var someService = GetConfirmationService(someParams.Consumer);
someService.PostConfirmation(....)


·>Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?

Плагины студии. Для части API пока используется старый com-интероп, но большая часть переписана с использованием DI. Вторую использовать на порядок удобнее, для получения большинства сервисов достаточно навесить атрибут [Import] на поле с нужной зависимостью.
[Import]
internal IClassificationTypeRegistryService ClassificationRegistry;

[Import]
ITextBufferFactoryService textBufferService;
Re[21]: При чем тут Di?
От: · Великобритания  
Дата: 15.08.16 12:45
Оценка:
Здравствуйте, Sinix, Вы писали:

S>·>Не совсем понял. Что за проблема-то? Вроде пишешь как слышишь:

S>А, это я главный нюанс забыл, миль пардон
S>Зависимости надо динамически разруливать, а не в момент создания сервисов. Без этого приходится городить отдельные костыли для всего, что связано с контекстом — от локальных транзакций и до кэша с логированием. Т.е. нужно что-то делать с кодом типа
S>
S>var someService = GetConfirmationService(someParams.Consumer);
S>someService.PostConfirmation(....)
S>

В простых случаях — протаскиваем через параметры методов:
сonfirmationService.PostConfirmation(someParams.Consumer, ....);

по опыту получилось, что лучше метод с парой "лишних" параметров, которые легко анализировать в IDE и рефакторить, чем какие-то неявные зависимости, которые сложно отследить.
В сложных случаях — фабрика:
var someService = confirmationServiceFactory.getByConsumer(someParams.Consumer);
someService.PostConfirmation(....)


S>·>Я Студию смотрел последний раз больше лет 10 назад... Можно подробнее? Что за extensions?

S>Плагины студии. Для части API пока используется старый com-интероп, но большая часть переписана с использованием DI. Вторую использовать на порядок удобнее, для получения большинства сервисов достаточно навесить атрибут [Import] на поле с нужной зависимостью.
S>
S>[Import]
S>internal IClassificationTypeRegistryService ClassificationRegistry;

S>[Import]
S>ITextBufferFactoryService textBufferService;
S>

А, ну это да, типичный DI код, плагинность тут так... сбоку. Правда я бы предпочёл Constructor-injection вместо field injection.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[22]: При чем тут Di?
От: Sinix  
Дата: 15.08.16 13:18
Оценка:
Здравствуйте, ·, Вы писали:


·>по опыту получилось, что лучше метод с парой "лишних" параметров, которые легко анализировать в IDE и рефакторить, чем какие-то неявные зависимости, которые сложно отследить.

Ну так пара — оно только в простых случаях. В сложных там штук 10-15 в сумме набирается (понятно, что они оборачиваются в классы-обёртки типа MyServiceParams, чтоб не протаскивать всё по отдельности).


·>В сложных случаях — фабрика:

Угу, тем же путём шли. И вот тут у нас начинался ад. Потому что внезапно мы были вынуждены ручками повторять всю пляску с зависимостями, которую обычно за нас выполняет DI. В одном-двух местах — куда не шло, в нескольких десятках — проще протащить сервис для самого DI и не мучаться. В сотнях — надо изобретать удобное API. И тут внезапно оказывается, что по факту у нас по-прежнему service locator, только немного приукрашенный.

В общем, DI сам по себе не лечит проблему с кучей зависимостей, это всего лишь инструмент для явной документации этих зависимостей. Иногда это отлично и классно, как в примере с расширениями студии.

А иногда получается, что проще оставить DI как хелпер для автоматического заполнения статически известных зависимостей, а сами зависимости протаскивать через контекст, который по факту тот же самый service locator, вид сбоку. В общем, не всё так однозначно


·>А, ну это да, типичный DI код, плагинность тут так... сбоку. Правда я бы предпочёл Constructor-injection вместо field injection.

Ага. Ну эт вопрос вкуса фломастеров уже
Re[23]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 17.08.16 06:50
Оценка:
Здравствуйте, Sinix, Вы писали:

Любопытное обсуждение.

S>Почему на реальный сценарий пофиг? Так твои советы не подходят. У контекста нет поведения, он по определению иммутабельный


Подскажите плиз, а что вы здесь под словом "контекст" понимаете?
Re[24]: При чем тут Di?
От: Sinix  
Дата: 17.08.16 07:04
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Подскажите плиз, а что вы здесь под словом "контекст" понимаете?


Класс (классы), которые хранят состояние текущей логической сессии. Текущий пользователь, текущая транзакция, текущий логгер etc. Обсуждалось
Автор: LWhisper
Дата: 30.05.16
недавно.
Re[25]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 17.08.16 07:29
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, IQuerist, Вы писали:


IQ>>Подскажите плиз, а что вы здесь под словом "контекст" понимаете?


S>Класс (классы), которые хранят состояние текущей логической сессии. Текущий пользователь, текущая транзакция, текущий логгер etc. Обсуждалось
Автор: LWhisper
Дата: 30.05.16
недавно.


Спасибо. Понятно. А контекст бизнес операции вы как-то "организовываете"?
Re[26]: При чем тут Di?
От: Sinix  
Дата: 17.08.16 08:03
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Спасибо. Понятно. А контекст бизнес операции вы как-то "организовываете"?


Зависит от проекта. Где-то используется вариант "все бизнес-объекты создаются через DI-сервис, сам DI-сервис инжектится в свойство Manager", DI-сервис по сути явялется контекстом.

Где-то используется неявное протаскивание контекста через AsyncLocal<T>. Красиво, удобно, но нужно быть очень внимательным в инфраструктурном коде, чтобы нечаянно не потерять контекст. В критичном коде я бы такой вариант пока не рискнул бы использовать.

Ну а в CodeJam.Perftests используется вариант с протаскиванием ручками объекта и хранением сервисов в словарике в этом объекте.
Re[27]: При чем тут Di?
От: IQuerist Мухосранск  
Дата: 17.08.16 10:19
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Здравствуйте, IQuerist, Вы писали:


IQ>>Спасибо. Понятно. А контекст бизнес операции вы как-то "организовываете"?


S>Зависит от проекта. Где-то используется вариант "все бизнес-объекты создаются через DI-сервис, сам DI-сервис инжектится в свойство Manager", DI-сервис по сути явялется контекстом.


S>Где-то используется неявное протаскивание контекста через AsyncLocal<T>. Красиво, удобно, но нужно быть очень внимательным в инфраструктурном коде, чтобы нечаянно не потерять контекст. В критичном коде я бы такой вариант пока не рискнул бы использовать.


Я думал я один такой любитель "Local Context" вся ждал, что кто-то придет и ткнет меня в него носом и расскажет, как делать лучше но никто не пришел.
Re[23]: При чем тут Di?
От: maxkar  
Дата: 21.08.16 12:38
Оценка:
Здравствуйте, ·, Вы писали:

M>>В других случаях поведение зависит от принятых данных и состояния базы данных. И вот там нужно правильно передавать используемые данные. Не "инжектить сервисы", а получать нужные данные в нужном месте.

·>Т.е. по сути использовать БД как service registry... Кстати, не во всех проектах есть БД.

Не service registry. Там характерного для registry API не возникает ни на каком этапе. Интерфейс формулируется в терминах бизнес-логики, например sendConfirmation(long orderId). БД содержит "данные, на основе которых принимаются решения, описанные бизнес-логикой". Эти данные есть в любом случае, это часть предметной области. Что меняется, так это компонент, ответственный за извлечение нужных для принятия решения данных из базы данных. В случае с entity и прочими большими объектами эта обязанность лежит на пользователе ConfirmationService. И может потребоваться изменить этого пользователя при изменении бизнес-правил. При передаче id вся ответстенность за извлечение необходимых для решения данных переносится на сам ConfirmationService. Это может быть удобнее для пользователя. Но из-за этого реализация сервиса знает чуть больше о структуре хранилища.

В общем, переход к ID — не автоматическое решение. У него есть и плюсы, и минусы.

·>Более сложный случай это:

·>Т.е. возвращённый сервис используется многократно, притом в разных местах — по-разному, и фабрика может выдавать разные экземпляры SomeSerivce, которые могут иметь различные зависимости или даже типы.

Ну вот это явно встанет в очередь на рефакторинг. Чтобы не приходилось передавать сервисы в параметрах методов. Рефакторинги будут зависеть от реального кода. В абстрактном виде это обсуждать не реально. Ряд используемых техник я показал. Если у вас где-то есть код в opensource с описанной проблемой — могу ближе к новому году посмотреть и сказать, что бы я делал.

·>
M>>void methodA(Entity someEntity) {
M>>void methodA(long entityId) {
·>

·>Ну нафиг. Преждевременная пессимизация, усложнение тестирования, плюс превращение типированных параметров в безликое long.

Да, минусы есть. Это не универсальное решение. Но лишние поля у Entity (вроде "confirmation preferences"), используемые только в 5% случаев работы с entity — тоже не круто. Нужен баланс. По-умолчанию я тоже за entity, кстати. И переход к id только при росте интерфейса.

А тестирование обычно не проблема. Если можно тестировать internal methods, то все просто:
public void methodA(long entityId) {
  ConfirmationData data = queryDbForData(enitityId);
  methodAImpl(data);
}

/* internal */ void methodAImpl(ConfirmationData data) { 
  ...
}


Тест находится в том же пакете (поэтому имеет доступ и к методу). В юнит-тестах проверется только methodAImpl. В ряде случаев methodAImpl может еще и static оказаться, что вообще прекрасно.
Подобный трюк с разделением на два метода еще очень хорошо позволяет избавляться от страшных вещей вроде ICurrentTimeProvider { long now(); }, который вводится для "тестирования поведения, зависящего от времени".

M>>Пока есть ровно одна реализация сервиса, это работает. А вот когда их становится много — нет. Как вот в моем первом примере с CompositeConfirmation.

·>Просто можно готовить соответсвующий service registry в место втыкания плагинов.
Можно. Но не удобно и вводит личные сущности. Поэтому я предпочитаю выкинуть сторонние библиотеки и сделать все кодом, ровно так, как я люблю.

M>>И не использует типы в качестве этих ID (ну, чуть хитрее, для удаления boilerplate я scala implicit parameter использую)

·>Это как?

В scala есть хитрый механизм, когда параметры (метода или конструктора) могут передаваться автоматически исходя из лексического контекста. Очень похоже на типичный DI, реализуемый различными библиотеками, но для параметров. В коде выглядит примерно так:
class TableIdGenerators(implicit ds : DataSource) {
  def idsFor(name : String) : IdGenerator = 
    new TableBasedIdGenerator(ds, name)
}

class SomeService(someParam : String)(implicit ds : DataSource) {
}

class AnotherService(
      someService : SomeService, 
      idGenerator : IdGenerator)(
      implicit ds : DataSource) {
}

class ThirdPartyService(anotherParam : Int)(implicit ds : DataSource) {
}

/* Application construction code. */
def init() : Unit = {
  val config = readConfig()
  implicit val mainDb = createDataSource(config.db.main)
  val thirdPartyDb = createDataSource(config.db.thirdparty)
 
  val idGens = new TableIdGenerators
  val someService = new SomeService(config.someService.param)
  val anotherService = new AnotherService(
    someService, idsGens.idsFor("anotherServiceSeq"))
  val thirdPartyService = new ThirdPartyService(config.thirdPartyId)(thirdPartyDb)
}

В данном примере idGenerator, someService и anotherService будут использовать mainDb, а thirdPartyService будет использовать thirdPartyDb. Недостающие implicit-параметры передаются из лексического контекста, компилятор смотрит только на тип. Если есть два implicit-кандидата, компилятор будет ругаться и нужно передавать их явно. Ну и их можно явно передать всегда (как в инициализации thirdPartyService). Удобно для передачи глобальных вещей вроде соединений с внешними сервисами (базы данных, memcached, redis и тому подобные вещи, существующие в единственном экземпляре). Что передавать явно, а что через имплиситы — решается по мере необходимости. Четких правил нет.
Re[14]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.08.16 09:08
Оценка:
Здравствуйте, ilvi, Вы писали:

I>Здравствуйте, Cyberax, Вы писали:


C>>Я внутри Amazon'а работаю в облачных вычислениях.

I>Полтора-два года назад как раз читал про плеер амазонвский под андроид, были огромные ветки на форумах с разгневаными пользователями и оценка в плеймаркете соответсвенная. Потом довелось подержать в руках один из киндлов, с цветным экраном, на котором этот плеер можно было помучать. Через пять минут я его "сломал" — перестал отображать постеры к описаниям фильмов и еще что-то отвалилось. Потом спросил у дядечки, который руководил одним из проектов по разработке этого плеера, как они тестируют — ответ был, что только юнит тесты и никаких ручных тестов. На тот момент всей этой информации хватило, чтобы сформировать мнение, почему у амазона конкретно этот плеер такой глючный.

У меня был знакомый, тестировщик от рождения, в его руках софт просто горел аццким пламенем "общение" с ним, когда он просто рвал, уже многократно оттестированный UI на части, вызывало бессильную ярость и преклонение перед гениальностью одновременно.
Отредактировано 29.08.2016 14:09 IQuerist . Предыдущая версия . Еще …
Отредактировано 29.08.2016 9:10 IQuerist . Предыдущая версия .
Re[15]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 31.08.16 08:38
Оценка:
Здравствуйте, ·, Вы писали:

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


Предубеждение классическое все разработчики страдают "кретинизмом тестирования" и очень часто пропускают кейсы чуть менее очевидные чем выбивалка для ковров ))) Я сам так делаю и у других наблюдаю повсеместно
Re[16]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 31.08.16 08:41
Оценка:
Здравствуйте, ilvi, Вы писали:

I>2) У меня нету предубеждения перед тестами, у меня есть предубеждение перед людьми, которые считают, что юнит тесты могут заменить хорошую команду QA. Дополнить могут, но вот заменить — мое мнение нет.

Юнит-тесты вообще-то не QA, а инструмент разработки.

I>1) Я знаю про автоматизированые тесты, но давать их писать разработчику, это тоже самое что давать тестировать разработчику. Он будет тестировать то что он написал, а это может быть немного не то что требовалось.

I>Мое мнение, что все типы автоматизорованых тестов это очень хорошо, но не надо при этом сводить команду QA до нуля.
Так согласен, "отсутствие QA" может быть причиной плохого качества. А "только юнит тесты и никаких ручных тестов" — лажа. На моей прошлой работе команда QA писала тесты, ручного тестирования практически не было.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[4]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 01.09.16 15:15
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>>>Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.

Tom>·>Литров не обещаю, но возразить могу: контейнер не нужен. Накой мне жуткий монстр тащить, не надо ему ничего делегировать. Я что не в состоянии сам new вызвать в нужный момент? Просто пишется отдельный инфрасткуртурный код, который будет делать весь этот ваш wiring. А эти контейнеры не только с собой тащат всякий хлам с поддержкой всякой чёрной магии (противоречит твоему пункту 3), но ещё и в особо запущенных случаях — жуткие XML-конфиги.
Tom>Конфигов 0, не дай бог никакого XML. Магии 0. Монструозности 0. С производительность всё прелесно. Пользовать DI без контейнера конечно можно но жутко неудобно. Вы отстали от жизни.
Это ты о чём? О каком-то конкретном контейнере?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 01.09.16 15:28
Оценка:
·>Это ты о чём? О каком-то конкретном контейнере?
О большинстве современных. Lightinject, DryIoc, Unity, StructureMap итп
Больше скажу, с вовременных зачастую конфигурация только через код.
Народная мудрось
всем все никому ничего(с).
Отредактировано 01.09.2016 15:29 Tom . Предыдущая версия .
Re[7]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 01.09.16 20:28
Оценка:
·>Куча вредных антипаттернов, которые легко размазать по всему проекту, а обычно достаточно одного единственного constructor injection. И вычищать потом это — замучаешься.
Давай по конкретнее. Хоть один анти паттерн покажи мне и опиши в чём состоит проблема.

·>И собственно тупой код типа:

·>
·>var someValue = "SomeValue";
·>var anotherFoo = new AnotherFoo();
·>var instance = new Bar(anotherFoo, someValue);
·>

·>выглядит ничуть не хуже.
Выглядит хуже. И создаёт конкретные проблемы в вполне конкретных случаях. Я больше скажу, с управлением временем жизни обьектов руками есть большие проблемы даже на теоретическом уровне. Вот тебе прмиер. Есть обьект IFoo. Ну или IPlugin для наглядности. Есть пара его реализаций, одна из них использует unmanaget ресурсы и требует реализации IDisposable а другая нет. Кроме как калечного решения в виде наследованияч IPlugin от IDisposable для ручного управления зависимостями я не вижу.

·>Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.

Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.

Tom>>Пользовать DI без контейнера конечно можно но жутко неудобно.

·>Зато полная поддержка компилятора и IDE. А неудобно только с непривычки.
new это огромные трудности при написании тестов. Я про Integration тесты.
Руками собирать всё дерево зависимостей? Вопрос нахера, если я 2-мя движениями мышки могу в тесте подменить любую зависимость.
Народная мудрось
всем все никому ничего(с).
Re[6]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 09:07
Оценка:
Здравствуйте, Tom, Вы писали:

IQ>>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.

Tom>Вы бы с SOLID разобрались и не писали чушь. Расскажите мне как DI у нас портит S или I я уже не говорю про D

Вы бы сам пост, таки почитали...
Re[2]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 09:23
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.

Tom>Лично для себя сделал простой вывод, DI НЕ требуется только для объектов в которых нет логики, т.е. POCO.

Звучит эпически, а как быть со stateless объектами в которых одна логика и нет состояния? Для чего им DI, если потенциальное время их жизни — от старта системы до самого ее финиша?

Tom>Всё остальное — DI. Причин тут несколько и все они достаточно очевидны и разжёваны не мной а в тьме видео описывающих какие именно проблемы решает DI но я ещё раз ох опишу.


Tom>1. Когда говорят про использование DI то в 99% случаев DI используют вместе с контейнером. А смысл контейнера не только в предоставлении зависимостей а в управлении временем жизни объекта. Делегирование управления жизни обьекта контейнеру — одна из самых принципиальных вещей.


Забавно ))) вот например есть ворох статических хелперных методов не имеющих состояния. Вот например есть целые сервисы, зависимость от которых и жизни которых определяется контекстом бизнес операции т.к. сильно зависит от бизнес логики...

Мне кажется или ваша позиция больше связана с вопросами веры, чем с вопросами разработки ПО?

Tom>2. Использование DI позволяет тебе чётко определять все зависимости объекта, зависимости становятся явными и получает их обьект обычно в конструкторе. Иными словами мне НЕ нужно лазить по коду объекта что бы понять а от чего ещё он зависит. Достаточно глянуть в конструктор и всё становится понятным.


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

Tom>3. При тотальном использовании DI во всём проекте во всём проекте используется один и тот же стандартных подход. Такой код читать просто и понятно. А вот обратный случай когда вот тут вот мы сделаем new, а вот там вот вызовем статический метод а вот это вот мы заинжектим потому что оно — это сервис (а что такое сервис никто не знает). Это точно бред.


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

Tom>В целом у автора пока просто мало опыта использование DI и DI для него новая концепция при переходе к которой абсолютно естественно возникает куча вопросов и нормальное отторжение. Так у всех, это нормально.


У меня полно опыта в области DI. Я отхреначивал DI нафиг уже в трех проектах потому как с ним архитектура типа big ball of mud становиться абсолютно неподдерживаемой.
Отредактировано 02.09.2016 9:38 IQuerist . Предыдущая версия . Еще …
Отредактировано 02.09.2016 9:31 IQuerist . Предыдущая версия .
Re[3]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 09:24
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Tom, Вы писали:


Tom>>Понимаю сейчас что польются литры говна на меня от тех кто не осилил и не понял смысла DI но попробую ответить.

·>Литров не обещаю, но возразить могу: контейнер не нужен. Накой мне жуткий монстр тащить, не надо ему ничего делегировать. Я что не в состоянии сам new вызвать в нужный момент? Просто пишется отдельный инфрасткуртурный код, который будет делать весь этот ваш wiring. А эти контейнеры не только с собой тащат всякий хлам с поддержкой всякой чёрной магии (противоречит твоему пункту 3), но ещё и в особо запущенных случаях — жуткие XML-конфиги.

<OFFTOP>

— ЕРЕТИК!!!

</OFFTOP>

Re[7]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 09:38
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Здравствуйте, Tom, Вы писали:


IQ>>>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.

Tom>>Вы бы с SOLID разобрались и не писали чушь. Расскажите мне как DI у нас портит S или I я уже не говорю про D

IQ>Вы бы сам пост, таки почитали...

Я сам пост читал, в отличии от вас. Вам зажали конкретный вопрос, что именно и как именно из SOLID нарушает DI. Вы слились...
Народная мудрось
всем все никому ничего(с).
Re[3]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 09:50
Оценка:
IQ>Звучит эпически, а как быть со stateless объектами в которых одна логика и нет состояния? Для чего им DI, если потенциальное время их жизни — от старта системы до самого ее финиша?

Звучит не эпически а логично. Statefull или Stateless абсолютно никак не влияет на то надо ли обьект инжектить. Единственное на что это влияет — на время жизни обьекта. Если он Stateless — его смело можно делать singleton-ом. Что касается Statefull то надо разбираться что за стейт и кому он принадлежит. А у вас в голове каша, вы смешали разные понятия — State-а, и DI. На вопрос для чего — уже обьяснял, для того что бы иметь возможность подменять в тестах, для того что бы сделать зависимость явной.


Tom>>Всё остальное — DI. Причин тут несколько и все они достаточно очевидны и разжёваны не мной а в тьме видео описывающих какие именно проблемы решает DI но я ещё раз ох опишу.


Tom>>1. Когда говорят про использование DI то в 99% случаев DI используют вместе с контейнером. А смысл контейнера не только в предоставлении зависимостей а в управлении временем жизни объекта. Делегирование управления жизни обьекта контейнеру — одна из самых принципиальных вещей.


IQ>Забавно ))) вот например время жизни db entity определяется оно как правило контекстом внутри одного метода от загрузки из БД до сохранения в БД. Вот например есть ворох статических хелперных методов не имеющих состояния. Вот например есть целые сервисы, зависимость от которых и жизни которых определяется контекстом бизнес операции т.к. сильно зависит от бизнес логики...

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

IQ>Мне кажется или ваша позиция больше связана с вопросами веры, чем с вопросами разработки ПО?

Вам кажется. Моя позиция связана с принципами и опытом разработки mission critical систем работающих 24/7 и распространяющихся по схеме PaaS. Качество для нас критически важно. Покрытие тестами для нас критически важно.

Tom>>2. Использование DI позволяет тебе чётко определять все зависимости объекта, зависимости становятся явными и получает их обьект обычно в конструкторе. Иными словами мне НЕ нужно лазить по коду объекта что бы понять а от чего ещё он зависит. Достаточно глянуть в конструктор и всё становится понятным.


IQ> Э... четко определить зависимости исключительно в рамках конкретной реализации DI которые качественно более примитивные, чем могут быть рамки бизнес операции. Собственно, когда DI перестает использоваться новичками исключительно для хелперных методов, проблемы с ним связанные и начинают всплывать.

Мда. Вы научитесь писать стройно и понятно. А то у вас каша не только в голове а и в сообщениях. И когда пишете чётко определяйтесь что именно хотите сказать.

Tom>>3. При тотальном использовании DI во всём проекте во всём проекте используется один и тот же стандартных подход. Такой код читать просто и понятно. А вот обратный случай когда вот тут вот мы сделаем new, а вот там вот вызовем статический метод а вот это вот мы заинжектим потому что оно — это сервис (а что такое сервис никто не знает). Это точно бред.


IQ>А вы не задумывались откуда может взяться понимание, что есть сервис, а что нет на старте проекта? А ведь DI религиозные фанатики начинают использовать в самом начале. Ах да... Tom — "Всё остальное — DI." Т.е. вообще все прямо с самого старта и есть цель для DI... Colonoscopy Injection детектед В общем мой пост как раз про это.


Tom>>В целом у автора пока просто мало опыта использование DI и DI для него новая концепция при переходе к которой абсолютно естественно возникает куча вопросов и нормальное отторжение. Так у всех, это нормально.


IQ> У меня полно опыта в области DI. Я отхреначивал DI нафиг уже в трех проектах потому как с ним архитектура типа big ball of mud становиться абсолютно неподдерживаемой.

С чем вас и поздравляю. Отхреначивайте дальше. И к архитектуре DI не имеет никакого отношения. DI это маленькая частная практика наряду с кучей других практик которые необходимы для того что бы писать качественный код. А то что вы делает называется "макароны"
Народная мудрось
всем все никому ничего(с).
Re[8]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 10:19
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Здравствуйте, IQuerist, Вы писали:


IQ>>Здравствуйте, Tom, Вы писали:


IQ>>>>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.

Tom>>>Вы бы с SOLID разобрались и не писали чушь. Расскажите мне как DI у нас портит S или I я уже не говорю про D

IQ>>Вы бы сам пост, таки почитали...

Tom>Я сам пост читал, в отличии от вас. Вам зажали конкретный вопрос, что именно и как именно из SOLID нарушает DI. Вы слились...

Ну так вы вопросы не зажимайте... и на них таки ответят. Или уже ответили в тексте поста.

>>>Вы слились.


вы нам тут устраиваете сеанс унитазной магии?
Re[5]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 10:24
Оценка:
IQ>Опять эти тесты... несовершенная технология тестирования в ответе за уничтожение мозгов огромного количества разработчиков. Сегодня уже есть технологии позволяющие не ломать архитектуру исходя из потребностей тестирования.
Ну так давайте с тестов и начнём. Расскажите нам про эту чудо технологию (надеюсь не Typemock и не Microsoft Shim?)
А ещё лучше, просветите нас, покажите ваши тесты.

IQ>Если бы вы прочитали сам пост, то несомненно увидели бы, что я описываю ситуацию, когда тесты в проекте — это несбыточная фантазия.

??? Тесты, фантазия???? Без коментариев.

IQ>>>Забавно ))) вот например время жизни db entity определяется оно как правило контекстом внутри одного метода от загрузки из БД до сохранения в БД. Вот например есть ворох статических хелперных методов не имеющих состояния. Вот например есть целые сервисы, зависимость от которых и жизни которых определяется контекстом бизнес операции т.к. сильно зависит от бизнес логики...

Tom>>Спросить то чего хотел. И ещё раз уточню, забавно выглядит тут ваша позиция неофита. Могу спорить вы возрастной программист лет после 40-ка которые просто не смог в DI. И уже никогда не сможет.

IQ>Я в посте все написал — я лично не встречал проектов, где DI был обоснованно использован. Увы мне, увы моей конторе. Мы клепаем бизнес логику, тоннами. Может где-то оно иначе, мой пост не против DI, а против его использования в религиозных целях.


IQ>>>Мне кажется или ваша позиция больше связана с вопросами веры, чем с вопросами разработки ПО?

Tom>>Вам кажется. Моя позиция связана с принципами и опытом разработки mission critical систем работающих 24/7 и распространяющихся по схеме PaaS. Качество для нас критически важно. Покрытие тестами для нас критически важно.

IQ>Спрошу прямо — вы на каком курсе института?

Спросите прямо сколько мне лет. Я не стесняюсь, мне будет 37 зимой.

IQ>Т.е. по вашему использование механизмов DI никак не влияет на архитектуру системы?

DI относится к реализации а не архитектуре. DI слишком низкоуровневая абстракция что бы её относить к архитектуре.
Народная мудрось
всем все никому ничего(с).
Re[9]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 10:26
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Здравствуйте, Tom, Вы писали:


Tom>>Здравствуйте, IQuerist, Вы писали:


IQ>>>Здравствуйте, Tom, Вы писали:


IQ>>>>>Имхо главного не написано — маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID.

Tom>>>>Вы бы с SOLID разобрались и не писали чушь. Расскажите мне как DI у нас портит S или I я уже не говорю про D

IQ>>>Вы бы сам пост, таки почитали...

Tom>>Я сам пост читал, в отличии от вас. Вам зажали конкретный вопрос, что именно и как именно из SOLID нарушает DI. Вы слились...

IQ>Ну так вы вопросы не зажимайте... и на них таки ответят. Или уже ответили в тексте поста.

Вы ответите на вопрос, что вы имели ввиду когда написали "маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID". Поясните мне недогадливому на примерах, какие именно принципы из SOLID и как именно по вашему нарушаются.

>>>>Вы слились.

IQ> вы нам тут устраиваете сеанс унитазной магии?
Мда. Оставлю ьез коментариев.
Народная мудрось
всем все никому ничего(с).
Re[6]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 10:54
Оценка:
Здравствуйте, Tom, Вы писали:

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

Tom>Ну так давайте с тестов и начнём. Расскажите нам про эту чудо технологию (надеюсь не Typemock и не Microsoft Shim?)
Tom>А ещё лучше, просветите нас, покажите ваши тесты.

Это становиться смешно, вы пост читали? Нет никаких тестов проекты с наивным DI до них, как правило не доживают.

IQ>>Если бы вы прочитали сам пост, то несомненно увидели бы, что я описываю ситуацию, когда тесты в проекте — это несбыточная фантазия.

Tom>??? Тесты, фантазия???? Без коментариев.

Если бы вы прочитали пост, то обошлись бы без фантазий там русским по белому написано — использование DI в конкретном проекте часто обосновывают исключительно потребностью создания юнит тестов, которых конкретный проект никогда не дождется.

IQ>>Спрошу прямо — вы на каком курсе института?

Tom>Спросите прямо сколько мне лет. Я не стесняюсь, мне будет 37 зимой.

И на каком вы курсе института в 37 лет зимой?

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

IQ>>Т.е. по вашему использование механизмов DI никак не влияет на архитектуру системы?

Tom>DI относится к реализации а не архитектуре. DI слишком низкоуровневая абстракция что бы её относить к архитектуре.

Справедливо К сожалению я слишком часто наблюдаю ситуацию, когда архитектуру big ball of mud пытаются облагородить используя DI (о том и пост). И возникает закономерный вопрос — свелось бы развитие проекта к big ball of mud без маниакальной потребности внедрения DI на самых ранних стадиях или таки нет...
Re[10]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 11:09
Оценка:
Здравствуйте, Tom, Вы писали:

IQ>>Ну так вы вопросы не зажимайте... и на них таки ответят. Или уже ответили в тексте поста.

Tom>Вы ответите на вопрос, что вы имели ввиду когда написали "маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID". Поясните мне недогадливому на примерах, какие именно принципы из SOLID и как именно по вашему нарушаются.

Была такая идея, но в целом все основные проблемы сводились к тому, что в качестве сервисов используются ну очень низкоуровневые конкретные реализации, как правило это DAL хелперы. В статье это уже показано, так что мне это все показалось избыточным.
Re[7]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 11:16
Оценка:
IQ>>>Опять эти тесты... несовершенная технология тестирования в ответе за уничтожение мозгов огромного количества разработчиков. Сегодня уже есть технологии позволяющие не ломать архитектуру исходя из потребностей тестирования.
Tom>>Ну так давайте с тестов и начнём. Расскажите нам про эту чудо технологию (надеюсь не Typemock и не Microsoft Shim?)
Tom>>А ещё лучше, просветите нас, покажите ваши тесты.

IQ> Это становиться смешно, вы пост читали? Нет никаких тестов проекты с наивным DI до них, как правило не доживают.

У вас не доживают, у всех остальных проблем нету. Покажите мне ВАШИ тесты которые делаете ВЫ в ваших правильных проектах.
Расскажите и научите как ВЫ делаете Правильно.

IQ>>>Если бы вы прочитали сам пост, то несомненно увидели бы, что я описываю ситуацию, когда тесты в проекте — это несбыточная фантазия.

Tom>>??? Тесты, фантазия???? Без коментариев.

IQ>Если бы вы прочитали пост, то обошлись бы без фантазий там русским по белому написано — использование DI в конкретном проекте часто обосновывают исключительно потребностью создания юнит тестов, которых конкретный проект никогда не дождется.


IQ>>>Спрошу прямо — вы на каком курсе института?

Tom>>Спросите прямо сколько мне лет. Я не стесняюсь, мне будет 37 зимой.

IQ>И на каком вы курсе института в 37 лет зимой?

IQ>Вы выдали столько "маркетинговово базза", сколько я слышал только от студентов.
Я начал программировать когда мне не было ещё 10 лет. А работать лет в 20 по специальности если вас интересует мой опыт.
И всё это время я учусь ибо в нашей профессии это необходимо что бы оставаться профессионалом.

IQ>>>Т.е. по вашему использование механизмов DI никак не влияет на архитектуру системы?

IQ>Справедливо К сожалению я слишком часто наблюдаю ситуацию, когда архитектуру big ball of mud пытаются облагородить используя DI (о том и пост). И возникает закономерный вопрос — свелось бы развитие проекта к big ball of mud без маниакальной потребности внедрения DI на самых ранних стадиях или таки нет...
К сожалению у вас такая каша в голове что ни что такое архитектура, ни что такое DI ни что такое контейнеры для чего они нужны и как их правильно использовать, ни что такое State и как его правильно использовать вы не знаете. Но при этом НЕ спрашиваете вопросы а уверенно утверждаете что DI это зло. А на вопросы рассказать как с вашей точки зрения делать правильно вы тихочечно сливаетесь... Ваш "союзник" рядом хоть по делу спрашивает. А у вас всё сопли из носа надуваются.
Народная мудрось
всем все никому ничего(с).
Re[9]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 11:26
Оценка:
·>SL. В подавляющем числе случаев он не нужен. Проблема — он делает зависимости неявными.
? Что такое SL?

·>[методы-инициализаторы и property injection. Проблема — добавляет в объект опасное состояние "создан, но не очень-то ещё создан".

Абсолютно согласен, зло злейшее. В 99% только Constructor Injection. Правда есть пару случаев когда из за "чужёго кривого дизайна" приходится использовать property injection но это исключение.

·>Магические строки. Ничем не лучше магических чисел.

Давай с самого начала, есть ощущение что ты не понимаешь откуда там при регистрации взялись строки. Есть 2 принципиально разных случая. Случай 1 — я хочу что бы в контейнере была зарегистрирована только одна реализация интерфейса X. В этом случае никаких строк ненадо, обычная регистрация. Если я хочу переопределить предыдущую регистрацию, например в тесте то я так же выполняю обычную регистрацию без каких либо имён ака строк. Но что делать если:
a) Я хочу зарегистрировать в контейнере 2 реализации одного и того же интерфейса. Как сказать контейнеру что я хочу не "перезаписать" предыдущую регистрацию а сделать их две. И более того, как эти 2 регистрации идентифицировать, как потом если вдруг надо зарезолвить конкретную регистарцию. Ведь иногда мне могут понадобиться все регистрации интерфейса аля IEnumerable<IFoo> а иногда нужно взять конкретную (таких случаев вагон). Вот для этого и придумали имена. Да конечно надо как то регистрации отличать друг от друга и ничего проще строк тут нету. Что бы эти строки перестали быть магическими — вынеси их в константу и используй эту константу как при регистарции так и при резолве.

·>Сканирование сборок. В подавляющем числе случаев он не нужен. Доставляет столько удовольствия исследовать что куда залетело и почему. Притом это можно исследовать только на запущенной системе в данном (часто prod) окружении.

Ничего не понимаю что куда залетело. В общем случае фича которая называется auto wire работает прекрасно. Регистрируешь только то что отличается от принятых в контейнере конвенций.

·>Циклические зависимости. С DI+CI сделать цикл невозможно. Заставляет аккуратнее подходить к архитектуре приложения, а не всякие lazy/PI, которые тебе циклы создадут на ура.

Эммм а где антипаттерн? И причём тут контейнеры с DI. Если у тебя циклические зависимости то это проблема не контейнера а проблема твоего дизайна. Но даже в этом случае контейнер может подставить тебе плечо, ты можешь резолвить Lazy<T> и фактически резолв будет сделан в момент использования.

Tom>>Вот тебе прмиер. Есть обьект IFoo. Ну или IPlugin для наглядности. Есть пара его реализаций, одна из них использует unmanaget ресурсы и требует реализации IDisposable а другая нет. Кроме как калечного решения в виде наследованияч IPlugin от IDisposable для ручного управления зависимостями я не вижу.


·>Не понял. Давай более конкретный пример. Вот код:

На стадии проектирования интерфейса и своей реализации интерфейса ты НЕ знаешь будут ли другие реализации которым может потребоваться очистка ресурсов. Это основная идея. В случае исполдьзования контейнера, обычно, на запрос создаётся так называемый child container который разрушается при окончании обработки запроса и который при разрушении вызовет Dispose у обьектов которые были в нём зарезолвлены. Причём он вызовет Dispose естественно вне зависимости от того унаследован интерфейс от IDsiposable или нет. В случае когда у тебя контейнера нет тебе надо либо самому писать такой функционал но это не возможно так как без контейнера нет единственного класса который контролирует время жизни всех обьектов. Либо наследовать интерфейс от IDisposable в тех местах где ты предпологаешь в реализациях может понадобится очистка ресурсов, но это жутко криво ибо во первых ты по сути не должен знать и не знаешь где очистка может понадобится а во вторых сам факт наследования от IDisposable это ад адский.


Tom>>·>Единственное для чего эти контейнеры могут быть хороши это всякое Assembly Scanning, но реально проектов, где это необходимо — очень мало.

Tom>>Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.
·>Но это всё не надо использовать. Контейнеры можно использовать для каких-то сложных случаев, только в довольно маленьком чётко отделённом контексте, в плагинном менеджере каком-нибудь например. Но пихать везде — антипаттерн.
Так, то что это вдруг антипатотерн — это придумал ты. Основная масса современных разработчиков с этим не согласна

Tom>>·>Зато полная поддержка компилятора и IDE. А неудобно только с непривычки.

Tom>>new это огромные трудности при написании тестов. Я про Integration тесты.
Tom>>Руками собирать всё дерево зависимостей? Вопрос нахера, если я 2-мя движениями мышки могу в тесте подменить любую зависимость.
·>Нет, просто пишешь классы-модули, которые делают wiring тестируемых поддеревьев зависимостей. И тестируешь именно их. Иначе интеграционные тесты тестируют тестовый wiring.
О чём и речь, без контейнера тебе надо собирать деревья зависимостей руками. Зачем это делать если это умеет делать контейнер.
Народная мудрось
всем все никому ничего(с).
Re[11]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 11:28
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Здравствуйте, Tom, Вы писали:


IQ>>>Ну так вы вопросы не зажимайте... и на них таки ответят. Или уже ответили в тексте поста.

Tom>>Вы ответите на вопрос, что вы имели ввиду когда написали "маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID". Поясните мне недогадливому на примерах, какие именно принципы из SOLID и как именно по вашему нарушаются.

IQ>Была такая идея, но в целом все основные проблемы сводились к тому, что в качестве сервисов используются ну очень низкоуровневые конкретные реализации, как правило это DAL хелперы. В статье это уже показано, так что мне это все показалось избыточным.

Ключевое слово вам показалось.
Тесты когда свои покажешь?
Народная мудрось
всем все никому ничего(с).
Re[12]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 11:39
Оценка:
Здравствуйте, Tom, Вы писали:

Tom>Здравствуйте, IQuerist, Вы писали:


IQ>>Здравствуйте, Tom, Вы писали:


IQ>>>>Ну так вы вопросы не зажимайте... и на них таки ответят. Или уже ответили в тексте поста.

Tom>>>Вы ответите на вопрос, что вы имели ввиду когда написали "маниакальная страсть к IOC навязываемая ранним внедрением DI провоцирует нарушение всех принципов SOLID". Поясните мне недогадливому на примерах, какие именно принципы из SOLID и как именно по вашему нарушаются.

IQ>>Была такая идея, но в целом все основные проблемы сводились к тому, что в качестве сервисов используются ну очень низкоуровневые конкретные реализации, как правило это DAL хелперы. В статье это уже показано, так что мне это все показалось избыточным.

Tom>Ключевое слово вам показалось.

Так и топик мой Вам кажется иначе? Запостите свой.
Re[8]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 11:46
Оценка:
Здравствуйте, Tom, Вы писали:

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

Tom>>>Ну так давайте с тестов и начнём. Расскажите нам про эту чудо технологию (надеюсь не Typemock и не Microsoft Shim?)
Tom>>>А ещё лучше, просветите нас, покажите ваши тесты.

IQ>> Это становиться смешно, вы пост читали? Нет никаких тестов проекты с наивным DI до них, как правило не доживают.

Tom>У вас не доживают, у всех остальных проблем нету.

К 37 то годочкам, уж пора бы отучиться говорить за всех...

Tom>Расскажите и научите как ВЫ делаете Правильно.


Если бы вы прочитали пост, то поняли бы, что он не том, как делать правильно. А о том, как часто делают неправильно.

IQ>>И на каком вы курсе института в 37 лет зимой?

IQ>>Вы выдали столько "маркетинговово базза", сколько я слышал только от студентов.
Tom>Я начал программировать когда мне не было ещё 10 лет. А работать лет в 20 по специальности если вас интересует мой опыт.

Абсолютно не интересует. Опыт часто видно по задаваемым вопросам.

Tom>И всё это время я учусь ибо в нашей профессии это необходимо что бы оставаться профессионалом.


Вот никогда не понимал людей, которые врут наполовину

Tom>К сожалению у вас такая каша в голове что ни что такое архитектура, ни что такое DI ни что такое контейнеры для чего они нужны и как их правильно использовать, ни что такое State и как его правильно использовать вы не знаете. Но при этом НЕ спрашиваете вопросы а уверенно утверждаете что DI это зло.


Ну прочитайте уже пост! Я нигде не утверждаю что DI это зло. Наоборот, специально раз пять написал обратное.
Re[9]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 12:32
Оценка:
IQ>>> Это становиться смешно, вы пост читали? Нет никаких тестов проекты с наивным DI до них, как правило не доживают.
Tom>>У вас не доживают, у всех остальных проблем нету.
IQ>К 37 то годочкам, уж пора бы отучиться говорить за всех...
Я говорю за пару сотен разработчиков и несколько десятков проектов с которыми я знаком.

Tom>>Расскажите и научите как ВЫ делаете Правильно.

IQ>Если бы вы прочитали пост, то поняли бы, что он не том, как делать правильно. А о том, как часто делают неправильно.
Прочитал. Не понял. Поясните.

IQ>>>И на каком вы курсе института в 37 лет зимой?

IQ>>>Вы выдали столько "маркетинговово базза", сколько я слышал только от студентов.
Tom>>Я начал программировать когда мне не было ещё 10 лет. А работать лет в 20 по специальности если вас интересует мой опыт.

IQ>Абсолютно не интересует. Опыт часто видно по задаваемым вопросам.

Tom>>И всё это время я учусь ибо в нашей профессии это необходимо что бы оставаться профессионалом.
IQ>Вот никогда не понимал людей, которые врут наполовину
Можно по подробнее где я вру

IQ>Ну прочитайте уже пост! Я нигде не утверждаю что DI это зло. Наоборот, специально раз пять написал обратное.

У вас DI какой то очень странный. Какой то избирательный. Вы так и не пояснили критерии как определить что надо DI а что не надо и главное почему не надо и какие проблемы это несёт.
Народная мудрось
всем все никому ничего(с).
Re[13]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 12:33
Оценка:
IQ>Так и топик мой Вам кажется иначе? Запостите свой.
Топик ваш в котором вы не отвечаете за слова. Сказали что DI то то нарушает а рссказать нам что и почему именно не можете. Сказал бы что погорячился и проехали бы но нет, упираемся...
Народная мудрось
всем все никому ничего(с).
Re[14]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 12:51
Оценка:
Здравствуйте, Tom, Вы писали:

IQ>>Так и топик мой Вам кажется иначе? Запостите свой.

Tom>Топик ваш в котором вы не отвечаете за слова.

Нда... я с универа такой предьявы не слышал.

Tom>Сказали что DI то то нарушает а рссказать нам что и почему именно не можете. Сказал бы что погорячился и проехали бы но нет, упираемся...


Погорячился? Мне стабильно приходится отхреначивать из проектов "наивный DI", который только мешает.

Читайте пост. Не согласны — пишите свой.
Re[11]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 02.09.16 13:01
Оценка:
Здравствуйте, ·, Вы писали:

Если я ничего не путаю, вам цитируют то ли книгу по DI то ли лекции
Re[11]: О "наивном" DI и об архитектурном бессилии
От: Tom Россия http://www.RSDN.ru
Дата: 02.09.16 13:06
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, Tom, Вы писали:


Tom>>·>SL. В подавляющем числе случаев он не нужен. Проблема — он делает зависимости неявными.

Tom>>? Что такое SL?
·>Service Locator.
Так не надо его использовать. Контейнер то тут причём
Обычно контейнер встраивается бесшовно и вы навсегда забываете о его существовании и явно никогда не вызываете.
Конечно есть некоторые исключения — вершина стека вызовов. Аля новый поток но тут ничего не сделать. Кто то должен инициировать резолв дерева зависимостей но таки да использовать локатор не есть хорошо по очевидному ряду причин описанному в толпе статей.

Tom>>Абсолютно согласен, зло злейшее. В 99% только Constructor Injection. Правда есть пару случаев когда из за "чужёго кривого дизайна" приходится использовать property injection но это исключение.

·>Но вот добрый контейнер легко и непринуждённо позволяет это пихать куда угодно в любых количествах.
То что контейнер позволяет это делать не мешает вам не использовать эти плохие практики. Если вы их используете то контейнер тут не причём, это ваше собственное плохое решение. Однако как я говорил есть редкие случаи когда таки property injection необходим.

Tom>>Да конечно надо как то регистрации отличать друг от друга и ничего проще строк тут нету. Что бы эти строки перестали быть магическими — вынеси их в константу и используй эту константу как при регистарции так и при резолве.

·>А зачем тебе их по строкам отличать? Зачем их вообще отличать? Есть две ситуации.
·>Первая cитуация, у тебя действительно два инстанса и ты разные инстансы используешь в разных частях программы с разными целями. Ну например, DbConnection для основной БД и для отдельной БД для аудита, например. В этом случае тебе строки не нужны. В случае ручного связывания у тебя вместо строк это будет именем поля или локальной переменной.
·>Вторая ситуация, у тебя действительно несколько инстансов и их нужно как-то определять в рантайме в зависимости от каких-то данных. Ну например, найти инстанс какого-нибудь класса по фрагменту URL. В этом случае следует использовать не "ничего проще строк нету", а соответсвующий бизнес-требованиям тип — UrlFragment, enum, етс. Пихать везде строки — плохой стиль.
Мне казалось я понятно обьяснил зачем нужны строки. 1-е для того что бы сказать контейнеру что он не должен переопределять зависимость а должен зарегистрировать вторую для того жде интерфейса. 2-й для того что бы как то можно было зарезолвить зависимость по имени. Таких случаев тьма, случаи когда есть N обьектов реализующих один и тот же интерфейс, как пример ICommand. И никаких проблем строки не создают, обьявите их константами и используйте.

Tom>>·>Сканирование сборок. В подавляющем числе случаев он не нужен. Доставляет столько удовольствия исследовать что куда залетело и почему. Притом это можно исследовать только на запущенной системе в данном (часто prod) окружении.

Tom>>Ничего не понимаю что куда залетело. В общем случае фича которая называется auto wire работает прекрасно. Регистрируешь только то что отличается от принятых в контейнере конвенций.
·>Я о http://www.lightinject.net/#assembly-scanning , а ты о чём?
И я о том же, обычно это называется auto wiring

Tom>>·>Циклические зависимости. С DI+CI сделать цикл невозможно. Заставляет аккуратнее подходить к архитектуре приложения, а не всякие lazy/PI, которые тебе циклы создадут на ура.

Tom>>Эммм а где антипаттерн? И причём тут контейнеры с DI. Если у тебя циклические зависимости то это проблема не контейнера а проблема твоего дизайна. Но даже в этом случае контейнер может подставить тебе плечо, ты можешь резолвить Lazy<T> и фактически резолв будет сделан в момент использования.
·>Циклические зависимости делать не надо. Никогда. А если это действительно неизбежно — это должно быть сложно и сразу явно видно. Ты можешь случайно добавить незаметив, а контейнер тебе всё сам свяжет и не пикнет, втихую добавив +100 к техническому долгу. А потом эту вязанку развязывать.
Да действительно контейнер в случае циклической зависимости упадёт только во время резолва. У меня такая проблема встречалась один раз и выявлена была в тестах. Ничего серьёзного, решилась за пару часов.

Tom>>На стадии проектирования интерфейса и своей реализации интерфейса ты НЕ знаешь будут ли другие реализации которым может потребоваться очистка ресурсов. Это основная идея. В случае исполдьзования контейнера, обычно, на запрос создаётся так называемый child container который разрушается при окончании обработки запроса и который при разрушении вызовет Dispose у обьектов которые были в нём зарезолвлены. Причём он вызовет Dispose естественно вне зависимости от того унаследован интерфейс от IDsiposable или нет. В случае когда у тебя контейнера нет тебе надо либо самому писать такой функционал но это не возможно так как без контейнера нет единственного класса который контролирует время жизни всех обьектов. Либо наследовать интерфейс от IDisposable в тех местах где ты предпологаешь в реализациях может понадобится очистка ресурсов, но это жутко криво ибо во первых ты по сути не должен знать и не знаешь где очистка может понадобится а во вторых сам факт наследования от IDisposable это ад адский.

·>public class RequestModule и пусть он и управляет временем жизни создаваемых им IDisposable-ы ровно так как надо, а не универсальный всемогутер, который делает какую-то неявную магию.
Не понял я кто такой RequestModule и как он может определить какой обьект надо диспоузить а какой нет.

Tom>>>>Контейнеры много чего могут но это бесполезно обьяснять человеку у которого в голове установка что они зло.

Tom>>·>Но это всё не надо использовать. Контейнеры можно использовать для каких-то сложных случаев, только в довольно маленьком чётко отделённом контексте, в плагинном менеджере каком-нибудь например. Но пихать везде — антипаттерн.
Tom>>Так, то что это вдруг антипатотерн — это придумал ты. Основная масса современных разработчиков с этим не согласна
·>Я знаю. Сам таким был.
·>Потом попал в компанию, где история развития была такая: "что попало как попало" -> "монстр Spring Framework" -> "модный Guice" -> "DI, plain Java code". По началу тоже возмущался отстутсвием "современного" контейнера, а потом осенило.
Я кстате заметил что ты из жабы+spring пришёл по опасениям за конфиг+xml.
Сейчас контейнеры совсем лругие. Это уже не монстры а достаточно простые, быстрые и логичные девайсы.
Советую перестать их бояться, хотя бы попробовать не нескольких проектах.
Многое становиться делать проще и удобнее чем руками.

Tom>>·>Нет, просто пишешь классы-модули, которые делают wiring тестируемых поддеревьев зависимостей. И тестируешь именно их. Иначе интеграционные тесты тестируют тестовый wiring.

Tom>>О чём и речь, без контейнера тебе надо собирать деревья зависимостей руками. Зачем это делать если это умеет делать контейнер.
·>Дерево зависимостей довольно сложная, но важная вещь. Оно не только является некого рода документом, описывающим высокоуровневую архитектуру, но и сдерживающим фактором говнокодинга. Если у тебя это самое дерево руками получается делать плохо, слишком сложно, непонятно, значит ты делаешь что-то не то, остановись, подумай — сделай проще. А контейнер эту всю сложность прячет под коврик и через какое-то время кроме как автоматически это дерево не строится. Контроль над сложностью потерян, значит без бутылки человек уже не разберётся что куда откуда.
Ничего контейнер не прячем, зависимости у каждого класса явные. Если их много, то эта проблема и так явная и контейнер тут не причём.
Народная мудрось
всем все никому ничего(с).
Re[12]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 02.09.16 13:10
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Если я ничего не путаю, вам цитируют то ли книгу по DI то ли лекции

Книга или лекции вряд ли, скорее доку какого-то контейнера, о том какой он хороший и полезный, и без него любой проект не проект.
А у тебя каша в голове. Не "по DI", а по IoC, или даже IoC-контейнерам.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[13]: О "наивном" DI и об архитектурном бессилии
От: Artem Korneev США https://www.linkedin.com/in/artemkorneev/
Дата: 05.09.16 04:51
Оценка:
Здравствуйте, Cyberax, Вы писали:

C>Я внутри Amazon'а работаю в облачных вычислениях. Самый эпицентр service-based архитектуры, можно сказать. Языки разработки — Java и производные от неё.


[Немного оффтопика]

AWS? А правда говорят, что это единственное нормальное подразделение во всём Амазоне в плане условий работы?

Мы тут с коллегами, человек 12, год назад дружно работу меняли — получили гринкарты и пошли искать повышений на стороне. Я подумывал в Амазон пойти, но в другое подразделение. Но как-то не сложилось — на собеседование сходил, но оффер не получил. Потом с коллегами говорил, оказалось что я был единственным, кто и в самом деле хотел туда пойти, остальные хотели получить оффер Амазона чтоб потом выторговать себе побольше денег в других конторах. Очень ругали work/life ballance Амазона, говорят что народ там живёт на работе и единственное место с человеческими условиями работы — разработка AWS.
С уважением, Artem Korneev.
Re[3]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 21.09.16 10:18
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, #John, Вы писали:


J>>Проекты с DI, дебажить сложно и в них сложно разбираться.

J>>Понаписывают рантайм подмену интерфесов, но на практике вообще не встречал что бы в рантайме делали подмену одних сервисов на другие. Подмену можно было сделать напрямую
·>Я не понимаю, где этот источник невежества? Удивительно, что ты не первый это несёшь. Каким образом DI связанно с интерфейсами? Каким образом DI связан с runtime-подменой? Ведь даже если взять wiki, там ничего такого нет.
·>Вот ты лично об этом откуда узал, что для DI нужны интерфейсы или runtime-подмена?

Осмелюсь предположить из того г...кода откуда один из DI фреймворков пришлось отхреначивать.

J>> в коде без всякого DI.

·>Как именно?

Иногда достаточно одного if

J>>DI однозначно отлично подойдет для приложений где приложение устанавливается к потребителю локально и потребитель сам пишет для себя плагины, исспользуя указанное апи. (вариант: приложение — это веб сервик к которому пишут плагины сторонние люди, отпадает по секурити.)

·>Так DI или контейнеры?

Вы так эмоционально холиварите в топике "О наивном DI"... Имхо не стоило ждать здесь борьбы за рассовую чистоту DI, здесь рассматривается совсем другой аспект. Возможно аспект неграмотный (с точки зрения тех кто хорошо разбирается в теме DI и давно его использует), но уж какой есть. Имхо нельзя игнорировать тот факт, что из за базза поднятого вокруг DI его пытаются использовать не так и не там игнорируя негативные результаты.

Вот в чем проблема и смысл топика, а вовсе не в том, что люди которым приходится отхреначивать DI из провальных проектов как-то не очень правильно DI понимают.
Отредактировано 21.09.2016 11:02 IQuerist . Предыдущая версия . Еще …
Отредактировано 21.09.2016 11:01 IQuerist . Предыдущая версия .
Отредактировано 21.09.2016 10:19 IQuerist . Предыдущая версия .
Re[7]: О "наивном" DI и об архитектурном бессилии
От: fddima  
Дата: 21.09.16 11:21
Оценка:
Здравствуйте, ·, Вы писали:

Скорость и легкость запуска безусловно важна, и надо прилагать усилия, что бы это сохранялось. Да блин, не всегда проект вообще можно запустить после чекаута/сборки без каких-то шизанутых плясок с конфигом. А другие упорно заставляют запускать студию от админа, хотя этого можно избежать.

Понятно, что девелопер не сможет развернуть гигабайтную базу (терабайтную) без геморов. Но в больших/уникальных проектах один фиг свои правила. Я не верю, что проблему скорости совсем невозможно преодолеть. Да и я очень подозреваю, что абсолютно все тесты не нужны сразу (девелоперу).

А в целом поинт понятен / принимается.

--

Я думаю, что не нужно писать 300 строк инфраструктурного кода который настраивает моки, что бы проверить 200 строк простейшего кода. Ровно как и не нужны они в pass-thru коде коего на самом деле завались в проектах.

Но вообще каждый (проект) сам себе должен выбирать подходящие правила/соглашения. Проблема только как выбрать походящие,.. в смысле пока кто-нить не набросит на вентилятор — опытом никто не делится.
Re[7]: О "наивном" DI и об архитектурном бессилии
От: fddima  
Дата: 21.09.16 11:26
Оценка:
Здравствуйте, ·, Вы писали:

Кстати просто рандомно но в тему: до деплоя кластера эту http://rsdn.org/forum/cpp/6559067.1
Автор: fddima
Дата: 21.09.16
проблему никто не обнаружил. У всех нынче на борту AVX.
Re[3]: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 21.09.16 12:22
Оценка:
Здравствуйте, ·, Вы писали:

·> Каким образом DI связанно с интерфейсами?

DI — это же, у нас есть конструктор, который в параметре принимается интерфейс/класс, а после исспользует его методы. А дальше мы пишем код: если класс в конструкторе принимает такой-то класс, то заменика ты нам в такой-то момент времени, это класс на вот этот.
>>Каким образом DI связан с runtime-подменой?
Да, не обязательно подменять в рантайме, но зачем его подменять в компилируемом коде? когда можно и так передать в параметр конструктора нужный объект.
·>Вот ты лично об этом откуда узал, что для DI нужны интерфейсы или runtime-подмена?
Вот видел как его в проектах применяли не для подмены в рантайме. Но оно его подменяло как раз в рантайме.

J>> в коде без всякого DI.

·>Как именно?
Не применять насследование вообще. только фукнциональщина. Хз. почему но в последнее время замечаю чем меньше в коде ооп,(вместо наследования — вложенные объекты). Тем код становится более гибким и адаптируемый под измечивые требования заказчика.

·>И вообще, юнит-тесты это больше инструмент разработки, а не контроля качества.

Да.

>>У правильного теста два состояния: pass/fail.

Да.
·>Что ещё за логи??
Можно тестировать апи так: скрипт посылает json на /api/user/dropbyme, получает json.
И приложение все http request|responce сливает в лог файл. Иногда туда попадают ошибки, связанные с добавлением нового функционала. Или напр. когда мануально тестят тоже можно в логах увидеть где произошла ошибка, разобрать лог, пересоздать бд с данными, запустить скрипт для тестирования метода, послать туда данные из лога и восспроизвести ошибку.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[5]: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 22.09.16 08:00
Оценка:
Здравствуйте, ·, Вы писали:

J>>·> Каким образом DI связанно с интерфейсами?

·>И где ты об этом прочитал? Можно ссылочку?
https://en.wikipedia.org/wiki/Dependency_injection

Three types of dependency injection
There are at least three ways an object can receive a reference to an external module:
constructor injection: the dependencies are provided through a class constructor.
setter injection: the client exposes a setter method that the injector uses to inject the dependency.
interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.



·>Не знаю что и где ты подменяешь, но с DI это никак не связано.

·>Можно пример?
Вот о одном из проектов(исспользуется autofac):
В Global.asax регистрируется тип который будет создаваться через рефлексию(а значит в рантайме):
AutofacConfig.Instance.Configure(b =>
                {
                    b.RegisterType<UserManager>().As<IUserManager>().InstancePerLifetimeScope();

В контроллере. т.к. UserManager реализует интерфейс IUserManager, в рантайме будет создан его объект.
[HttpPost]
        public ActionResult Save(UserModel user)
        {            
            return HandleAction(() => Context.Current.Scope.Resolve<IUserManager>().Save(user));
        }


И зачем все эти сложности с интерфейсами, рефлексией? почему бы просто не написать: new UserManager().Save(user);
Типа у нас когда-то в далеком будущем появится еще один UserManager2 и что бы не рефакторить код мы подправим
одну строчку в Global.asax ?



·>Обычно логи читают когда тест упал и разбираются в причине. Или, иногда, когда пишут новый тест. Зачем читать логи после прогона тестов?

Да все верно, логи смотреть если тест сломался или у пользователся отображаются неверные данные.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[6]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 22.09.16 09:19
Оценка:
Здравствуйте, #John, Вы писали:


J>>>·> Каким образом DI связанно с интерфейсами?

J>·>И где ты об этом прочитал? Можно ссылочку?
J>https://en.wikipedia.org/wiki/Dependency_injection
J>

J>Three types of dependency injection
J>There are at least three ways an object can receive a reference to an external module:
J>constructor injection: the dependencies are provided through a class constructor.
J>setter injection: the client exposes a setter method that the injector uses to inject the dependency.
J>interface injection: the dependency provides an injector method that will inject the dependency into any client passed to it. Clients must implement an interface that exposes a setter method that accepts the dependency.

Слово interface таки нашел? А ты прочитал что такое Interface Injection, как оно устроено? Каким образом оно связано с IUserManager+UserManager?
И где тут что-либо связанное с рантайм-подменой?

J>·>Не знаю что и где ты подменяешь, но с DI это никак не связано.

J>·>Можно пример?
J>Вот о одном из проектов(исспользуется autofac):
J>В Global.asax регистрируется тип который будет создаваться через рефлексию(а значит в рантайме):
J>                    b.RegisterType<UserManager>().As<IUserManager>().InstancePerLifetimeScope();
...
J>            return HandleAction(() => Context.Current.Scope.Resolve<IUserManager>().Save(user));

Это не DI. Это Singleton + Service Locator, да ещё и использование какого-то очередного IoC-контейнера (что собственно и громко написано на https://autofac.org/).
Слово "Register" сразу должно намекать что используется registry. А тут даже явно противопоставляют DI: "The registry makes the code more difficult to maintain (opposed to using Dependency injection), because it becomes unclear when you would be introducing a breaking change."

Мне интересен источник невежества. Каким образом у тебя в голове этот код ассоциируется именно с DI?

J>И зачем все эти сложности с интерфейсами, рефлексией? почему бы просто не написать: new UserManager().Save(user);

Ок. Давай по шагам. Где именно ты хочешь это написать? И что делать с зависимостями самого UserManager? Например, ему может понадобиться DbConnection и SomeUserConfigParams, а DbConnection тянет за собой ConnectionParams.

J>Типа у нас когда-то в далеком будущем появится еще один UserManager2 и что бы не рефакторить код мы подправим

J>одну строчку в Global.asax ?
Неужели autofac не умеет регистировать классы без интерфейсов? Возьмите другой, наверняка другие умеют. А лучше вообще выкиньте эту бяку.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[7]: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 22.09.16 10:15
Оценка:
Здравствуйте, ·, Вы писали:

·>Мне интересен источник невежества. Каким образом у тебя в голове этот код ассоциируется именно с DI?

Ок, перечитаю.
J>>И зачем все эти сложности с интерфейсами, рефлексией? почему бы просто не написать: new UserManager().Save(user);
·>Ок. Давай по шагам. Где именно ты хочешь это написать? И что делать с зависимостями самого UserManager? Например, ему может понадобиться DbConnection и SomeUserConfigParams, а DbConnection тянет за собой ConnectionParams.
Допустим проект(другой) из двух либ:
1. Там где находятся MVC котроллеры,Global.asax.
        [HttpPost]
        [ActionName("save")]
        public ResponceResult Save(UserModel user){ 
            var s = new UserService();
            return s.Save(user);
        }

2. Вторая либа Domain:
Где находятся *Service *Managers. UserService имеет обслужываеющий код(логирование, ловлю ошибок, создания ResponceResult), простую бизнес логику, и UserService дергает методы UserManage для извлечения данных из бд, выполнения sql процедур.
 
public class UserService {
 public ResponceResult Save(UserModel usermodel){
            try
            {
                if (!usermodel.IsValid())
                {
                        return new ResponceResult { ... };
                }
                using (var someContext = new SomeContext())
                {
                    var userManager =new UsersManager(ibeaconContext);
                    var users = userManager.List();
...

                    return new ResponceResult() {... };
                }
            }
            catch (Exception ex)
            {
                return new ResponceResult { ...};
            }
        }

        #endregion


Как передать SomeUserConfigParams .

Так как либа должна быть независимой от либы которая ее исспользует.
Надо в либе Domain создать класс для разных пользовательских настроек(которые исспользуются в этой либе).
class Settigs{
public SomeUserConfigParams {get;set;}
public SomeOtherThings {get;set;}
}

Создать Singleton с этим объектом в Domain либе.
И теперь при создании new UserService.Save() метода как-то инициализировать Singleton.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[8]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 22.09.16 11:17
Оценка:
Здравствуйте, #John, Вы писали:

J>>>И зачем все эти сложности с интерфейсами, рефлексией? почему бы просто не написать: new UserManager().Save(user);

J>·>Ок. Давай по шагам. Где именно ты хочешь это написать? И что делать с зависимостями самого UserManager? Например, ему может понадобиться DbConnection и SomeUserConfigParams, а DbConnection тянет за собой ConnectionParams.
J>Допустим проект(другой) из двух либ:
Ещё хуже.

J>1. Там где находятся MVC котроллеры,Global.asax.

J>
J>            var s = new UserService();
J>            return s.Save(user);
J>

И какой тут смысл создавать инстанс UserService? Чем UserService.Save со статическим методом хуже?

J>2. Вторая либа Domain:

J>Где находятся *Service *Managers. UserService имеет обслужываеющий код(логирование, ловлю ошибок, создания ResponceResult), простую бизнес логику, и UserService дергает методы UserManage для извлечения данных из бд, выполнения sql процедур.
J>
 
J>                using (var someContext = new SomeContext())
J>                {
J>                    var userManager =new UsersManager(ibeaconContext);

Не понял. Что за ibeaconContext? Где DbConnection и ConnectionParams?

J>Как передать SomeUserConfigParams .

J>Создать Singleton с этим объектом в Domain либе.
J>И теперь при создании new UserService.Save() метода как-то инициализировать Singleton.
Т.е. у тебя все зависимости будут синглтонами. Правильно понял? Жуть же. Типичный спагетти-код и радости дебага правильности порядка инициализации синглтонов.
А теперь посмотрим на DI здорового человека:
public class UserRestController
{
    private const UserService userService;
    public UserRestController(UserService userService) {this.userService = userService;}

        [HttpPost]
        [ActionName("save")]
        public ResponceResult Save(UserModel user){ 
            return userService.Save(user);
        }
}

public class UserService {
 private const DbConnection connection;
 private const UserManager userManager;
 public UserService(DbConnection connection, UserManager userManager) {this.connection = connection; this.userManager = userManager;}

 public ResponceResult Save(UserModel usermodel){
            try
            {
                if (!usermodel.IsValid())
                {
                        return new ResponceResult { ... };
                }
                using (var txn = new TransactionContext(connection))
                {
                    var users = userManager.List();
...
                    /// validate data, save data.
                    txn.commit();        

                    return new ResponceResult() {... };
                }
            }
            catch (Exception ex)
            {
                return new ResponceResult { ...};
            }
        }
}

И отдельно где-нибудь в Global делаем явный wiring:
var someUserConfigParams = readParamsFromConfigFile();
var connectionParams = readConnectionParamsFromAnotherConfigSource();
var dbConnection = new DbConnection(connectionParams);
var userManager = new UserManager(someUserConfigParams);
var userService = new UserService(dbConnection, userManager);
var userRestController = new UserRestController();
var HttpServer server = new HttpServer();
server.addHandler(userRestController);
server.start();

Почему редко такой код встречается?..
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[9]: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 22.09.16 12:21
Оценка:
Здравствуйте, ·, Вы писали:

·>И какой тут смысл создавать инстанс UserService? Чем UserService.Save со статическим методом хуже?

Вообщем-то можно и статические методы исспользовать.

·>Не понял. Что за ibeaconContext? Где DbConnection и ConnectionParams?

Опечатка. ibeaconContext — это someContext. SomeContext — это наследованный от Entities из EF, который наследуется от DbContext.
ConnectionParams ему можно передать из Singleton объектов.

·>Т.е. у тебя все зависимости будут синглтонами. Правильно понял? Жуть же. Типичный спагетти-код и радости дебага правильности порядка инициализации синглтонов.

Есть такое.

·>А теперь посмотрим на DI здорового человека:

·>
·>public class UserService {
·> public UserService(DbConnection connection, UserManager userManager) {this.connection = connection; this.userManager = userManager;}

·>

·>И отдельно где-нибудь в Global делаем явный wiring:
·>
·>var userService = new UserService(dbConnection, userManager);
·>

·>Почему редко такой код встречается?..
А если в классе UserService в методе Save для бизнес логики надо исспользовать разные *Managers,
а в методе Delete еще более разные(UserProfileManager, AcitvityManager и т.д.).
Передавать в UserService(FabricOfManagers fabric) — фабрику классов со всеми менеджерами?
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[11]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 22.09.16 13:22
Оценка:
Здравствуйте, ·, Вы писали:

Полный сарказма ответ:

J>>·>И какой тут смысл создавать инстанс UserService? Чем UserService.Save со статическим методом хуже?

J>>Вообщем-то можно и статические методы исспользовать.
·>Зачем тогда классы вообще существуют?..

Чтобы упрощать структуру кода, там где это может быть полезно... не?

J>>·>Т.е. у тебя все зависимости будут синглтонами. Правильно понял? Жуть же. Типичный спагетти-код и радости дебага правильности порядка инициализации синглтонов.

J>>Есть такое.
·>И ещё получается такой некий твой "class Settigs", который зависит от всего и все от него зависят.
·>Собственно IoC-контейнер позволяет этим хоть как-то рулить. Синглтоны однозначно в топку.

Старая история, IoC-контейнер выполняет роль статического конструктора, но адепты верят, что так они чем-то по особенному рулят.

J>>·>Почему редко такой код встречается?..

J>>А если в классе UserService в методе Save для бизнес логики надо исспользовать разные *Managers,
J>>а в методе Delete еще более разные(UserProfileManager, AcitvityManager и т.д.).
J>>Передавать в UserService(FabricOfManagers fabric) — фабрику классов со всеми менеджерами?
·>Нет. Просто передаёшь всех менеджеров в конструкторе.
·>UserService(UserProfileManager, AcitvityManager, SomethingManager, ...)
·>Да, конструктор _может_ получиться с тучей аргументов, но зато сразу видно что именно требуется для функционирования данного класса, тебе не нужно читать код каждого отдельного метода чтобы выяснить а что же этот конкретный метод в этой ветке if-условия решил вытянуть из глобального Context.Current.

Это иллюзия, код каждого конкретного метода читать все равно придется

·>И, более того, это всё проверяется на этапе компиляции, все зависимости обеспечены, плюс IDE помогает с навигацией по коду, find usages, go to declaration и прочим.


А все остальные способы создания сервисов в коде на этапе компиляции не проверяются, зависимости не обеспечивают, а IDE будет намеренно мешать навигации по коду!

·>Далее, если у тебя таки получается класс у которого очень много зависимостей это сразу явно видно по его конструктору. Это просто значит что данный класс превращается в Универсальный Всемогутор (https://en.wikipedia.org/wiki/God_object) и требуется рефакторинг: пилишь компоненты по зависимостям так, чтобы уменьшить максимальную валентность графа зависимостей.


Какая красота, люди ведь не замечают, что полдня работают с одним файлом кол-во строк которого перевалило за несколько тыс. И что найти метод без средств студии уже просто нереально А так — глянул конструктор и все понятно А то, что всю эту сервисную обвязку при рефакторинге скорее всего придется переносить во новые классы. Ну это фигня не упаримся. Нам работу компилятора выполнять не в тягость!
Отредактировано 22.09.2016 13:24 IQuerist . Предыдущая версия . Еще …
Отредактировано 22.09.2016 13:23 IQuerist . Предыдущая версия .
Re[12]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 22.09.16 14:29
Оценка:
Здравствуйте, IQuerist, Вы писали:

J>>>·>И какой тут смысл создавать инстанс UserService? Чем UserService.Save со статическим методом хуже?

J>>>Вообщем-то можно и статические методы исспользовать.
IQ>·>Зачем тогда классы вообще существуют?..
IQ>Чтобы упрощать структуру кода, там где это может быть полезно... не?
Если в классе все методы статические, то какая именно польза от класса? Можно просто использовать namespace или что-то подобное.

IQ>·>И ещё получается такой некий твой "class Settigs", который зависит от всего и все от него зависят.

IQ>·>Собственно IoC-контейнер позволяет этим хоть как-то рулить. Синглтоны однозначно в топку.
IQ> Старая история, IoC-контейнер выполняет роль статического конструктора, но адепты верят, что так они чем-то по особенному рулят.
Если выбирать между IoC-контейнером и signletones я однозначно выберу первое. Но простой DI лучше обоих.

IQ>·>Нет. Просто передаёшь всех менеджеров в конструкторе.

IQ>·>UserService(UserProfileManager, AcitvityManager, SomethingManager, ...)
IQ>·>Да, конструктор _может_ получиться с тучей аргументов, но зато сразу видно что именно требуется для функционирования данного класса, тебе не нужно читать код каждого отдельного метода чтобы выяснить а что же этот конкретный метод в этой ветке if-условия решил вытянуть из глобального Context.Current.
IQ>Это иллюзия, код каждого конкретного метода читать все равно придется
Для чего?

IQ>·>И, более того, это всё проверяется на этапе компиляции, все зависимости обеспечены, плюс IDE помогает с навигацией по коду, find usages, go to declaration и прочим.

IQ>А все остальные способы создания сервисов в коде на этапе компиляции не проверяются, зависимости не обеспечивают, а IDE будет намеренно мешать навигации по коду!
Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить...
Синглтоны скрывают структуру зависимостей и порядок инициализации.

IQ>·>Далее, если у тебя таки получается класс у которого очень много зависимостей это сразу явно видно по его конструктору. Это просто значит что данный класс превращается в Универсальный Всемогутор (https://en.wikipedia.org/wiki/God_object) и требуется рефакторинг: пилишь компоненты по зависимостям так, чтобы уменьшить максимальную валентность графа зависимостей.

IQ>Какая красота, люди ведь не замечают, что полдня работают с одним файлом кол-во строк которого перевалило за несколько тыс. И что найти метод без средств студии уже просто нереально
В проекте где хотя бы за 5к файлов/классов так и есть.

IQ>А так — глянул конструктор и все понятно А то, что всю эту сервисную обвязку при рефакторинге скорее всего придется переносить во новые классы. Ну это фигня не упаримся.

В этом хотя бы IDE отлично помогает. В отличии от клубка синглтонов.

IQ>Нам работу компилятора выполнять не в тягость!

Какую работу компилятора ты собрался выполнять?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[13]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 22.09.16 15:22
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>Чтобы упрощать структуру кода, там где это может быть полезно... не?

·>Если в классе все методы статические, то какая именно польза от класса? Можно просто использовать namespace или что-то подобное.

Да класс превращается в старый добрый сишный модуль.

IQ>>·>Нет. Просто передаёшь всех менеджеров в конструкторе.

IQ>>·>UserService(UserProfileManager, AcitvityManager, SomethingManager, ...)
IQ>>·>Да, конструктор _может_ получиться с тучей аргументов, но зато сразу видно что именно требуется для функционирования данного класса, тебе не нужно читать код каждого отдельного метода чтобы выяснить а что же этот конкретный метод в этой ветке if-условия решил вытянуть из глобального Context.Current.
IQ>>Это иллюзия, код каждого конкретного метода читать все равно придется
·>Для чего?

Если надо выяснить какие сервисы он использует.

IQ>>·>И, более того, это всё проверяется на этапе компиляции, все зависимости обеспечены, плюс IDE помогает с навигацией по коду, find usages, go to declaration и прочим.

IQ>>А все остальные способы создания сервисов в коде на этапе компиляции не проверяются, зависимости не обеспечивают, а IDE будет намеренно мешать навигации по коду!
·>Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить...

Но это же самые любимые техники "наивного DI".

·>Синглтоны скрывают структуру зависимостей и порядок инициализации.


Это хороший аргумент... но часто порядок инициализации не имеет значения. А если инициализация сложная, то я лично поостерегся бы отдавать ее на откуп малознакомому фреймворку.
Re[14]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 22.09.16 16:20
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Чтобы упрощать структуру кода, там где это может быть полезно... не?

IQ>·>Если в классе все методы статические, то какая именно польза от класса? Можно просто использовать namespace или что-то подобное.
IQ>Да класс превращается в старый добрый сишный модуль.
С глобальными переменными?
Ты так говоришь, как будто это что-то хорошее.

IQ>·>Для чего?

IQ>Если надо выяснить какие сервисы он использует.
В смысле какие сервисы данный метод использует? А ты с какой целью интересуешься?
Если ты пользователь класса, то тебя это не должно заботить, т.к. наличие у тебя объекта означает, что у него можно дёрнуть метод — все зависимости у него будут по определению, т.к. объект сконструирован.
Если ты разработчк класса, то ты можешь использовать только то, что у тебя есть в конструкторе. Никаких неоднозначностей.
Так что давай дальше объясняй что и зачем ты хочешь выяснить.

Вот есть у тебя UserService.getInstance().serveUser(user) — нужен ли тебе для этого вызова HttpContext.Current? Как узнать?
И наоборот. Вот есть у тебя
public void serveUser(User user)
{
// как узнать - есть ли тут у меня доступ к HttpContext?
}


IQ>>>А все остальные способы создания сервисов в коде на этапе компиляции не проверяются, зависимости не обеспечивают, а IDE будет намеренно мешать навигации по коду!

IQ>·>Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить...
IQ>Но это же самые любимые техники "наивного DI".
Это "наивный IoC", DI тут не причём.

IQ>·>Синглтоны скрывают структуру зависимостей и порядок инициализации.

IQ>Это хороший аргумент... но часто порядок инициализации не имеет значения. А если инициализация сложная, то я лично поостерегся бы отдавать ее на откуп малознакомому фреймворку.
Неужели лучше отдать на откуп Undefined Behaviour инициализации статиков?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[15]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 23.09.16 14:29
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>Да класс превращается в старый добрый сишный модуль.

·>С глобальными переменными?
·>Ты так говоришь, как будто это что-то хорошее.

В тех проектах на которых работаю я (прямо скажем не больших) в этом нет ничего плохого. В прессе я встречаю не малое количество рекоммендаций по использованию функционального stateless стиля. И мой опыт показывает, что это не пустые слова... Конечно это создает определенные проблемы с согласованностью, но эти проблемы сущая ерунда, по сравнению с теми к которым приводят например попытки реализации наивной доменной модели (DDD). Об этом тоже может напишу пост

IQ>>·>Для чего?

IQ>>Если надо выяснить какие сервисы он использует.
·>В смысле какие сервисы данный метод использует? А ты с какой целью интересуешься?
·>Если ты пользователь класса, то тебя это не должно заботить, т.к. наличие у тебя объекта означает, что у него можно дёрнуть метод — все зависимости у него будут по определению, т.к. объект сконструирован.
·>Если ты разработчк класса, то ты можешь использовать только то, что у тебя есть в конструкторе. Никаких неоднозначностей.

Книжный какой-то пример... в любой реализации сущности сколь ни будь сложнее сортировки пузырьком есть дофига нюансов. И что самое паршивое — таких сущностей тоже дофига. Вы можете упомнить все нюансы во всех проектах за 3-6 лет? Или можете описать эти нюансы в названиях методов или комментариях к названиям методов? Имхо это просто невозможно.

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

·>Вот есть у тебя UserService.getInstance().serveUser(user) — нужен ли тебе для этого вызова HttpContext.Current? Как узнать?


А сколько у вас реализаций UserService.getInstance().serveUser ? У нас одна на 20+ проектов Ей более 6 лет и второй не будет я вас уверяю.

·>И наоборот. Вот есть у тебя

·>
·>public void serveUser(User user)
·>{
·>// как узнать - есть ли тут у меня доступ к HttpContext?
·>}
·>


Ну что-то пример совсем не бей лежачего в BL вообще не должно быть явного использования HttpContext. Все данные должны быть собраны на уровне получения запроса в web controller. А все системные данные текущего пользователя должны находиться в текущем контексте или это будет HttpContext в случае web или CallContext в случае win. Бизнес логика об этом ничего не должна знать.

IQ>>>>А все остальные способы создания сервисов в коде на этапе компиляции не проверяются, зависимости не обеспечивают, а IDE будет намеренно мешать навигации по коду!

IQ>>·>Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить...
IQ>>Но это же самые любимые техники "наивного DI".
·>Это "наивный IoC", DI тут не причём.

Да я знаю.

IQ>>·>Синглтоны скрывают структуру зависимостей и порядок инициализации.

IQ>>Это хороший аргумент... но часто порядок инициализации не имеет значения. А если инициализация сложная, то я лично поостерегся бы отдавать ее на откуп малознакомому фреймворку.
·>Неужели лучше отдать на откуп Undefined Behaviour инициализации статиков?

В простых stateless случаях я не вижу в этом проблемы. В подходе ряды плюсов — не надо ничего описывать, не надо изучать нюансы сторонних фреймворков, не надо давать пояснений и ждать подвохов.
Re[16]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 23.09.16 15:20
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>С глобальными переменными?

IQ>·>Ты так говоришь, как будто это что-то хорошее.
IQ>В тех проектах на которых работаю я (прямо скажем не больших) в этом нет ничего плохого. В прессе я встречаю не малое количество рекоммендаций по использованию функционального stateless стиля. И мой опыт показывает, что это не пустые слова... Конечно это создает определенные проблемы с согласованностью, но эти проблемы сущая ерунда, по сравнению с теми к которым приводят например попытки реализации наивной доменной модели (DDD). Об этом тоже может напишу пост
Ликбез. Ты глубоко заблуждаешься, что просто использование статических методов означает stateless стиль. Это stateless стиль только в том случае, если нет никакого глобального состояния (да вообще никакого состояния нет, ибо _state_less_), а значит результат такого метода зависит _только_ от его аргументов. Да, stateless стиль — благо, но в этом топике я этого не видел, только ламерские Context.Current.
Кстати, объекты и нестатические методы тоже бывают stateless — иммутабельные классы например.
Короче, stateless и static — совершенно независимые непересекающиеся понятия.

Да и причём тут DI?

IQ>·>Если ты пользователь класса, то тебя это не должно заботить, т.к. наличие у тебя объекта означает, что у него можно дёрнуть метод — все зависимости у него будут по определению, т.к. объект сконструирован.

IQ>·>Если ты разработчк класса, то ты можешь использовать только то, что у тебя есть в конструкторе. Никаких неоднозначностей.
IQ>Книжный какой-то пример... в любой реализации сущности сколь ни будь сложнее сортировки пузырьком есть дофига нюансов. И что самое паршивое — таких сущностей тоже дофига. Вы можете упомнить все нюансы во всех проектах за 3-6 лет? Или можете описать эти нюансы в названиях методов или комментариях к названиям методов? Имхо это просто невозможно.
Я говорю о контроле зависимостей, а не об общей теории всего. Ты задал конкретный вопрос — получил конкретный ответ, но ушел куда-то в абстратные рассуждения, вовращайся скорее к теме, а то скучно становится.

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

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

IQ>·>Вот есть у тебя UserService.getInstance().serveUser(user) — нужен ли тебе для этого вызова HttpContext.Current? Как узнать?

IQ>А сколько у вас реализаций UserService.getInstance().serveUser ? У нас одна на 20+ проектов Ей более 6 лет и второй не будет я вас уверяю.
Да какая разница? Ну пусть одна (но помни, что она ВНЕЗАПНО в течение 6 лет всяко разно меняется разными людьми). Ответь на вопрос.

IQ>·>И наоборот. Вот есть у тебя

IQ>·>
IQ>·>public void serveUser(User user)
IQ>·>{
IQ>·>// как узнать - есть ли тут у меня доступ к HttpContext?
IQ>·>}
IQ>·>


IQ> Ну что-то пример совсем не бей лежачего в BL вообще не должно быть явного использования HttpContext.

Ок. Ну пусть не HttpContext, пусть DbContext или как тут выше по топику "Context.Current.Scope.Resolve<IUserManager>". Это что-то изменит?

IQ>Все данные должны быть собраны на уровне получения запроса в web controller. А все системные данные текущего пользователя должны находиться в текущем контексте или это будет HttpContext в случае web или CallContext в случае win. Бизнес логика об этом ничего не должна знать.

И как это выражается и контролируется на уровне кода?

Ты наверное просто пишешь в коде
public void serveUser(User user)
{
// Мамой клянус!!!
   doSomething(user, Context.Current.Stuff);
}

А дальше плагин к компилятору находит все эти комментарии и проверяет?

IQ>>>Но это же самые любимые техники "наивного DI".

IQ>·>Это "наивный IoC", DI тут не причём.
IQ> Да я знаю.
Ну и зачем опять терминами жонглируешь?

IQ>·>Неужели лучше отдать на откуп Undefined Behaviour инициализации статиков?

IQ>В простых stateless случаях я не вижу в этом проблемы.
Простые случаи ВНЕЗАПНО становятся сложными. Да, в проектах на выброс пиши как хошь — пофиг. Но я предпочитаю не участвовать в проектах на выброс.

IQ>В подходе ряды плюсов — не надо ничего описывать,

Это тупо технический долг.

IQ>не надо изучать нюансы сторонних фреймворков, не надо давать пояснений и ждать подвохов.

Для DI не нужны фреймворки, нужны только мозги.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 26.09.16 09:25
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>·>С глобальными переменными?

IQ>>·>Ты так говоришь, как будто это что-то хорошее.
IQ>>В тех проектах на которых работаю я (прямо скажем не больших) в этом нет ничего плохого. В прессе я встречаю не малое количество рекоммендаций по использованию функционального stateless стиля. И мой опыт показывает, что это не пустые слова... Конечно это создает определенные проблемы с согласованностью, но эти проблемы сущая ерунда, по сравнению с теми к которым приводят например попытки реализации наивной доменной модели (DDD). Об этом тоже может напишу пост
·>Ликбез. Ты глубоко заблуждаешься, что просто использование статических методов означает stateless стиль. Это stateless стиль только в том случае, если нет никакого глобального состояния (да вообще никакого состояния нет, ибо _state_less_), а значит результат такого метода зависит _только_ от его аргументов.

Да конечно. Отсутствие глобального состояния важный факт.

·>Да, stateless стиль — благо, но в этом топике я этого не видел, только ламерские Context.Current.


А вы думаете DI фреймворки как-то по другому работают???

·>Кстати, объекты и нестатические методы тоже бывают stateless — иммутабельные классы например.

·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.

Обратного я и не утверждал

·>Да и причём тут DI?


Ну хватит вам уже извиняться за DI

IQ>>·>Если ты пользователь класса, то тебя это не должно заботить, т.к. наличие у тебя объекта означает, что у него можно дёрнуть метод — все зависимости у него будут по определению, т.к. объект сконструирован.

IQ>>·>Если ты разработчк класса, то ты можешь использовать только то, что у тебя есть в конструкторе. Никаких неоднозначностей.
IQ>>Книжный какой-то пример... в любой реализации сущности сколь ни будь сложнее сортировки пузырьком есть дофига нюансов. И что самое паршивое — таких сущностей тоже дофига. Вы можете упомнить все нюансы во всех проектах за 3-6 лет? Или можете описать эти нюансы в названиях методов или комментариях к названиям методов? Имхо это просто невозможно.
·>Я говорю о контроле зависимостей, а не об общей теории всего. Ты задал конкретный вопрос — получил конкретный ответ, но ушел куда-то в абстратные рассуждения, вовращайся скорее к теме, а то скучно становится.

Я показал, что "собирание зависимостей в конструкторе" имеет такую же иллюзорную ценность как и "улучшение тестируемости" решения.

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

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

Это все рекламный мусор. Модуль не класс, а то что он вдруг станет сколь ни будь более изолированным, собери я все зависимости в конструкторе, вообще ниоткуда не следует. На rsdn полно топиков о трудности создания api годного качества.

·>Попробуй — понравится, примеры кода я публиковал в этом топике.


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

IQ>>·>Вот есть у тебя UserService.getInstance().serveUser(user) — нужен ли тебе для этого вызова HttpContext.Current? Как узнать?

IQ>>А сколько у вас реализаций UserService.getInstance().serveUser ? У нас одна на 20+ проектов Ей более 6 лет и второй не будет я вас уверяю.
·>Да какая разница? Ну пусть одна (но помни, что она ВНЕЗАПНО в течение 6 лет всяко разно меняется разными людьми). Ответь на вопрос.

Но она практически не меняется, т.к. ее контракт сильно ограничен и определен в рамках конкретного проекта. И все расширения тоже локальны для конкретных проектов. Это просто хороший api для очень конкретной ниши.

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

IQ>>·>И наоборот. Вот есть у тебя

IQ>>·>
IQ>>·>public void serveUser(User user)
IQ>>·>{
IQ>>·>// как узнать - есть ли тут у меня доступ к HttpContext?
IQ>>·>}
IQ>>·>


IQ>> Ну что-то пример совсем не бей лежачего в BL вообще не должно быть явного использования HttpContext.

·>Ок. Ну пусть не HttpContext, пусть DbContext или как тут выше по топику "Context.Current.Scope.Resolve<IUserManager>". Это что-то изменит?

HttpContextService, DbContextService, CacheContextService, LoggingContextService — имхо как раз первые признаки наивного DI.

IQ>>Все данные должны быть собраны на уровне получения запроса в web controller. А все системные данные текущего пользователя должны находиться в текущем контексте или это будет HttpContext в случае web или CallContext в случае win. Бизнес логика об этом ничего не должна знать.

·>И как это выражается и контролируется на уровне кода?

А как это вообще может быть проконтролировано? Только само-дисциплина и код-ревью.

·>Ты наверное просто пишешь в коде

·>
·>public void serveUser(User user)
·>{
·>// Мамой клянус!!!
·>   doSomething(user, Context.Current.Stuff);
·>}
·>

·>А дальше плагин к компилятору находит все эти комментарии и проверяет?

Что за ужосы??? Какие камменты? ServiceLocator.GetCurrentUserInfo или можно вручную создать SysUserService и дернуть нужный метод.

IQ>>>>Но это же самые любимые техники "наивного DI".

IQ>>·>Это "наивный IoC", DI тут не причём.
IQ>> Да я знаю.
·>Ну и зачем опять терминами жонглируешь?

Это я что ли вспомнил про "Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить..."?

IQ>>·>Неужели лучше отдать на откуп Undefined Behaviour инициализации статиков?

IQ>>В простых stateless случаях я не вижу в этом проблемы.
·>Простые случаи ВНЕЗАПНО становятся сложными. Да, в проектах на выброс пиши как хошь — пофиг.

Или десятилетия не становятся. И в данном конкретном случае не станут. Впрочем вы натолкнули меня на мысль, поэтому вот имхо неплохой аргумент за DI — фреймворки будут все более абстрагировать логику в модулях и рано или поздно фокусы со static и local context вроде бы должны перестать работать. Но вот что странно, подобный подход был в ранних application server в конце 90х (не знаю как обстоят дела с azure) но вот мы до сих пор пишем веб приложения в которых доступны и http запросы и static и local context.

·>Но я предпочитаю не участвовать в проектах на выброс.


Ох... видать мало бизнес логики вам пришлось запилить на своем веку... иногда на выброс идут целые проекты, потому что юзеры не смогли/не захотели разбираться в софте, который для них создало начальство и саботировали внедрение.

IQ>>В подходе ряды плюсов — не надо ничего описывать,

·>Это тупо технический долг.

Долг за которым никогда не придут — подарок...

IQ>>не надо изучать нюансы сторонних фреймворков, не надо давать пояснений и ждать подвохов.

·>Для DI не нужны фреймворки, нужны только мозги.

А вот это ведь напрямую связано с темой моего поста Вы вообще с чем не согласны та?
Re[18]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 26.09.16 11:43
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Ликбез. Ты глубоко заблуждаешься, что просто использование статических методов означает stateless стиль. Это stateless стиль только в том случае, если нет никакого глобального состояния (да вообще никакого состояния нет, ибо _state_less_), а значит результат такого метода зависит _только_ от его аргументов.

IQ>Да конечно. Отсутствие глобального состояния важный факт.
К чему ты вообще упомянул stateless которого у тебя нет, да и не было никогда?

IQ>·>Да, stateless стиль — благо, но в этом топике я этого не видел, только ламерские Context.Current.

IQ>А вы думаете DI фреймворки как-то по другому работают???
_Могут_ работать по-другому.

IQ>·>Кстати, объекты и нестатические методы тоже бывают stateless — иммутабельные классы например.

IQ>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.
IQ>Обратного я и не утверждал
И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?

IQ>>>Книжный какой-то пример... в любой реализации сущности сколь ни будь сложнее сортировки пузырьком есть дофига нюансов. И что самое паршивое — таких сущностей тоже дофига. Вы можете упомнить все нюансы во всех проектах за 3-6 лет? Или можете описать эти нюансы в названиях методов или комментариях к названиям методов? Имхо это просто невозможно.

IQ>·>Я говорю о контроле зависимостей, а не об общей теории всего. Ты задал конкретный вопрос — получил конкретный ответ, но ушел куда-то в абстратные рассуждения, вовращайся скорее к теме, а то скучно становится.
IQ> Я показал, что "собирание зависимостей в конструкторе" имеет такую же иллюзорную ценность как и "улучшение тестируемости" решения.
А что для тебя имеет неиллюзорную ценность?

IQ>·>Суть в том, что у тебя класс получается более изолированным модулем, который легко понять и проще править независимо, а не просто сборищем малосвязанных методов, которые случайно попали в один файл.

IQ>Это все рекламный мусор. Модуль не класс, а то что он вдруг станет сколь ни будь более изолированным, собери я все зависимости в конструкторе, вообще ниоткуда не следует. На rsdn полно топиков о трудности создания api годного качества.
Как не следует? Если ты будешь использовать только те зависимости, которые есть в конструкторе, то он будет изолирован от всего остального.

IQ>·>Попробуй — понравится, примеры кода я публиковал в этом топике.

IQ>Вы знаете, на текущих проектах, у меня неплохо получается поддерживать модульность и изолированность на хорошем уровне и контролировать внешние зависимости без спец. фреймворков.
Хорошо что без фреймворков, осталось начать использовать DI и тогда будет совсем хорошо.

IQ>>>·>Вот есть у тебя UserService.getInstance().serveUser(user) — нужен ли тебе для этого вызова HttpContext.Current? Как узнать?

IQ>>>А сколько у вас реализаций UserService.getInstance().serveUser ? У нас одна на 20+ проектов Ей более 6 лет и второй не будет я вас уверяю.
IQ>·>Да какая разница? Ну пусть одна (но помни, что она ВНЕЗАПНО в течение 6 лет всяко разно меняется разными людьми). Ответь на вопрос.
IQ>Но она практически не меняется, т.к. ее контракт сильно ограничен и определен в рамках конкретного проекта. И все расширения тоже локальны для конкретных проектов. Это просто хороший api для очень конкретной ниши.
Ответь на конкретный вопрос: "нужен ли тебе для этого вызова HttpContext.Current? Как узнать?".

IQ>Да мне повезло, мне не нужно создавать и поддерживать универсальный user-решатор на все случаи жизни и для всех, всех, всех проектов. Наивные коллеги-разработчики хотели сделать такой, но очевидные последствия необходимости тестирования всех систем (коих три десятка) после любого изменения охладили их неопытный пыл, я считаю это своей заслугой.

Какой универсальный? Не нужен мне универсальный. Ты о чём?

IQ>>> Ну что-то пример совсем не бей лежачего в BL вообще не должно быть явного использования HttpContext.

IQ>·>Ок. Ну пусть не HttpContext, пусть DbContext или как тут выше по топику "Context.Current.Scope.Resolve<IUserManager>". Это что-то изменит?
IQ> HttpContextService, DbContextService, CacheContextService, LoggingContextService — имхо как раз первые признаки наивного DI.
Что за звери и какое это имеет отношение к моему вопросу?

IQ>>>Все данные должны быть собраны на уровне получения запроса в web controller. А все системные данные текущего пользователя должны находиться в текущем контексте или это будет HttpContext в случае web или CallContext в случае win. Бизнес логика об этом ничего не должна знать.

IQ>·>И как это выражается и контролируется на уровне кода?
IQ>А как это вообще может быть проконтролировано? Только само-дисциплина и код-ревью.
Так уже не раз намекнул — компилятором, с помощью DI+CI.

IQ>Что за ужосы??? Какие камменты? ServiceLocator.GetCurrentUserInfo или

А можно увидеть как выглядит класс ServiceLocator?

IQ>можно вручную создать SysUserService и дернуть нужный метод.

Как выглядит конструктор SysUserService? и где он возьмёт HttpRequest, например? Из тумбочки?

IQ>>>>>Но это же самые любимые техники "наивного DI".

IQ>>>·>Это "наивный IoC", DI тут не причём.
IQ>>> Да я знаю.
IQ>·>Ну и зачем опять терминами жонглируешь?
IQ>Это я что ли вспомнил про "Конечно, когда конструктор вызывается через рефлекию — IDE ничем помочь не может. А уж если XML-кофиги вспомнить..."?
Мне интересно как можно вменяемо реализовать SL без рефлексии или хотя бы даункастов.

IQ>>>·>Неужели лучше отдать на откуп Undefined Behaviour инициализации статиков?

IQ>>>В простых stateless случаях я не вижу в этом проблемы.
IQ>·>Простые случаи ВНЕЗАПНО становятся сложными. Да, в проектах на выброс пиши как хошь — пофиг.
IQ> Или десятилетия не становятся. И в данном конкретном случае не станут. Впрочем вы натолкнули меня на мысль, поэтому вот имхо неплохой аргумент за DI — фреймворки будут все более абстрагировать логику в модулях и рано или поздно фокусы со static и local context вроде бы должны перестать работать. Но вот что странно, подобный подход был в ранних application server в конце 90х (не знаю как обстоят дела с azure) но вот мы до сих пор пишем веб приложения в которых доступны и http запросы и static и local context.
Ну да, действительно, сейчас вон системы и на коболе есть, и работать не перестало. Зачем писать хороший, удобный в поддержке код, когда можно тупо говнокодить?

IQ>·>Но я предпочитаю не участвовать в проектах на выброс.

IQ>Ох... видать мало бизнес логики вам пришлось запилить на своем веку... иногда на выброс идут целые проекты, потому что юзеры не смогли/не захотели разбираться в софте, который для них создало начальство и саботировали внедрение.
Да как было, конечно, раньше, потом набрался опыта.

IQ>>>В подходе ряды плюсов — не надо ничего описывать,

IQ>·>Это тупо технический долг.
IQ>Долг за которым никогда не придут — подарок...
Это не подарок, а халява. А халява это сыр в мышеловке, может можно чуток успеть урвать, но когда-нибудь прихлопнет.

IQ>>>не надо изучать нюансы сторонних фреймворков, не надо давать пояснений и ждать подвохов.

IQ>·>Для DI не нужны фреймворки, нужны только мозги.
IQ>А вот это ведь напрямую связано с темой моего поста Вы вообще с чем не согласны та?
С критикой DI и CI и предлагаемыми альтернативами в виде глобальных переменных в надежде на "подарок".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 26.09.16 14:46
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:



IQ>>Что за ужосы??? Какие камменты? ServiceLocator.GetCurrentUserInfo

·>Я вот тут хорошее объяснение окнопал на пальцах и с картинками почему этот твой подход говно:
·>http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
·>Ну и вывод совпадающий с моим:

The compiler can offer both consumers and producers so much help when Constructor Injection is used, but none of that assistance is available for APIs that rely on Service Locator.


·>Собственно, прежде чем отвечать на предыдущий пост ознакомься с этой статьёй и пиши возражения по делу, если есть.


Нда... Как говорит народная мудрость лучше всего бандиты решают те проблемы которые сами и создают В посте Seemann создал инвалидное решение, огреб проблем и доблестно все порешал с помощью constructor injection! Какую же проблему он решил? А оказывается OrderProcessor.Process(Order order) внутри использует IOrderValidator! Но зачем явно передавать его в конкретный метод, если можно где-то там, за ширмой неявно затаскивать его через конструктор в DI? Ведь достаточно будет посмотреть конструктор, и метод инициализации всех сервисов системы и все сразу станет понятно! Не забывайте это делать при вызове каждого метода сервиса и пожалуйста отслеживайте все время изменения, которые вносят ваши коллеги. Кроме валидатора, в OrderProcessor.Process можно затащить много любопытных вещей, а вы, по api об этом даже не узнаете Это очень удобно.
Re[20]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 26.09.16 17:04
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Что за ужосы??? Какие камменты? ServiceLocator.GetCurrentUserInfo

IQ>·>Я вот тут хорошее объяснение окнопал на пальцах и с картинками почему этот твой подход говно:
IQ>·>http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/
IQ>·>Ну и вывод совпадающий с моим:

The compiler can offer both consumers and producers so much help when Constructor Injection is used, but none of that assistance is available for APIs that rely on Service Locator.

IQ>·>Собственно, прежде чем отвечать на предыдущий пост ознакомься с этой статьёй и пиши возражения по делу, если есть.
IQ>Нда... Как говорит народная мудрость лучше всего бандиты решают те проблемы которые сами и создают В посте Seemann создал инвалидное решение, огреб проблем и доблестно все порешал с помощью constructor injection! Какую же проблему он решил? А оказывается OrderProcessor.Process(Order order) внутри использует IOrderValidator!
Не только IOrderValidator, но и IOrderCollector, а потом со временем добавление IOrderShipper.

IQ>Но зачем явно передавать его в конкретный метод,

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

IQ>если можно где-то там, за ширмой неявно затаскивать его через конструктор в DI? Ведь достаточно будет посмотреть конструктор,

Зачем тебе его смотреть? Если у тебя есть ссылка на OrderProcessor — то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует.
Если у тебя такой ссылки нет, то смотри wiring и найди добавь эту ссылку к себе. Если не получится — значит что-то у тебя не хвататет в зависимостях, протаскивай как надо куда надо, а не надейся на глобальные переменные.

IQ>и метод инициализации всех сервисов системы и все сразу станет понятно!

Что такое "метод инициализации всех сервисов системы"?

IQ>Не забывайте это делать при вызове каждого метода сервиса и пожалуйста отслеживайте все время изменения, которые вносят ваши коллеги. Кроме валидатора, в OrderProcessor.Process можно затащить много любопытных вещей, а вы, по api об этом даже не узнаете Это очень удобно.

Да, удобно. А ты предлагаешь всё затаскивать через параметры метода? А в месте вызова этого метода они откуда возьмутся? Из тумбочки?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: О "наивном" DI и об архитектурном бессилии
От: #John Европа https://github.com/ichensky
Дата: 26.09.16 19:11
Оценка:
Здравствуйте, Вы писали:

Подумал, если DI, IoC, Singleton сравнивать с реальной жизнью.
Представим что у нас есть 1000 новостей, которую мы хотим рассказать городу.
* Singleton — вешаем доску с новостями и каждый житель города, сам решает когда ему подойти и прочитать что он хочет.
* DI — мы попомним, чем интересуется каждый из жителей и когда у нас появляются новости, мы бежим в нужную квартиру доложить о новостях.
* IoC — у каждого жителя включен телефон и мы вещаем в тел. новости пачками иногда доставляя их не тем кто их ждет.

Проблема IoC в том что нам сложно/дорого провести нормальную связь к каждому из жителей.
Проблема DI в том что нам надо помнить кому что надо знать и постоянно бегать к жителям домой. (а они гады иногда спят, едят, гуляют где-то в вне квартиры).
Проблема Singleton в том что возле доски может собраться большая толпа людей и они могут приходить в неправильной последовательности как нам хотелось бы.

Но, если взглянуть на жизнь со стороны, то решать проблемы с Singleton проще/дешевле/лучше, чем другими методами:
городские телефоны у нас глючат(бывает такое что слышем в трубке соседей)/IoC/, доставляя неудобства; почтальоны, те кто снимают показания с щетчиков, раздают повестки приходят когда нас нет дома/DI/, теряют на это драгоценно время всего общества. Но, когда мы приходим в налоговую или к врачу, всегда можно взять талончик и узнать приблизительно время, когда можно подойти или записаться на определенно время(хз, может еще не везде так, но упустим политику)/Singleton/, тут у нас страдает(или вообще нет), только отдельно взятый юнит.
Підтримати Україну у боротьбі з країною-терористом.

https://prytulafoundation.org/
https://u24.gov.ua/

Слава Збройним Силам України!!! Героям слава!!!
Re[20]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 26.09.16 21:51
Оценка:
Здравствуйте, #John, Вы писали:

J>Подумал, если DI, IoC, Singleton сравнивать с реальной жизнью.

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

Но если тебе так хочется, вот моя аналогия.

J>Представим что у нас есть 1000 новостей, которую мы хотим рассказать городу.

J>* Singleton — вешаем доску с новостями и каждый житель города, сам решает когда ему подойти и прочитать что он хочет.
Это скорее всего большой открытый базар-толкучка. Ибо доска read only, а синглтоны — ВНЕЗАПНО меняются. Особенно такие как HttpContext.CurrentRequest.

J>* DI — мы попомним, чем интересуется каждый из жителей и когда у нас появляются новости, мы бежим в нужную квартиру доложить о новостях.

Это что-то типа заказа по интернету. Задекларировал "нужны штаны и ведро картошки", тебе их привозят домой с помощью специально организованной службы доставки (wiring code), тебя как клиента не интересует как служба работает. Служба доставки знает что кому нужно и организует логистику чтобы всем всё доставлять.

J>* IoC

Ты наверное имеешь в виду Service Locator.
SL и DI — это паттерны, которые реализуют принцип IoC — когда не ты сам идёшь за тем, что тебе надо, а тебе дают то что тебе надо.

J>SL — у каждого жителя включен телефон и мы вещаем в тел. новости пачками иногда доставляя их не тем кто их ждет.

Что-то вроде специализированных магазинов. Ты знаешь где продаются штаны и туда ходишь.

J>Проблема IoC в том что нам сложно/дорого провести нормальную связь к каждому из жителей.

Проблема — идёшь в магазин, а он закрыт, или товар заканчивается и ты остаёшься без штанов, или там жуткая очередь.

J>Проблема DI в том что нам надо помнить кому что надо знать и постоянно бегать к жителям домой. (а они гады иногда спят, едят, гуляют где-то в вне квартиры).

Проблема — нужна компьютерная грамотность у населения. Зачем жамкать какие-то кнопки у шайтан-машины, когда можно как мой дед выйти вон на ту площать и купить/продать ведро картошки.

J>Проблема Singleton в том что возле доски может собраться большая толпа людей и они могут приходить в неправильной последовательности как нам хотелось бы.

Проблема — пришел за штанами в знакомое место, а там офигенная очередь, или продавец ими больше не торгует, или на обед решил сходить. Ещё надо хорошо помнить и знать куда за чем ходить.

J>Но, если взглянуть на жизнь со стороны, то решать проблемы с Singleton проще/дешевле/лучше, чем другими методами:

J>городские телефоны у нас глючат(бывает такое что слышем в трубке соседей)/IoC/, доставляя неудобства; почтальоны, те кто снимают показания с щетчиков, раздают повестки приходят когда нас нет дома/DI/, теряют на это драгоценно время всего общества. Но, когда мы приходим в налоговую или к врачу, всегда можно взять талончик и узнать приблизительно время, когда можно подойти или записаться на определенно время(хз, может еще не везде так, но упустим политику)/Singleton/, тут у нас страдает(или вообще нет), только отдельно взятый юнит.
signleton подходит для небольших городов. В городах побольше уже образуются несколько базаров, пришел в один — ничего нет, поехал в другой. А где-то очереди, а где-то пусто, а где-то густо. И сложно угадать что когда и какого качества сможешь купить.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 06:13
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>·>Кстати, объекты и нестатические методы тоже бывают stateless — иммутабельные классы например.

IQ>>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.
IQ>>Обратного я и не утверждал
·>И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?

Нда... а у меня оказывается не вульгарный ServiceLocator, а кошерный Ambient Context...
Re[21]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 06:24
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>Нда... Как говорит народная мудрость лучше всего бандиты решают те проблемы которые сами и создают В посте Seemann создал инвалидное решение, огреб проблем и доблестно все порешал с помощью constructor injection! Какую же проблему он решил? А оказывается OrderProcessor.Process(Order order) внутри использует IOrderValidator!

·>Не только IOrderValidator, но и IOrderCollector, а потом со временем добавление IOrderShipper.

IQ>>Но зачем явно передавать его в конкретный метод,

·>Потому что вызовов этого конкретного метода может быть много по всему коду, а вызововы конструктора обычно постоянны.

Но это еще хуже! Если реализация IOrderValidator, IOrderCollector и IOrderShipper существует одном экземпляре то нафига выносить их из модуля и засорять область приложения. А если их много, то необходимо явно и локально показывать их зависимость от контекста иначе логика размазывается.

IQ>>если можно где-то там, за ширмой неявно затаскивать его через конструктор в DI? Ведь достаточно будет посмотреть конструктор,

·>Зачем тебе его смотреть? Если у тебя есть ссылка на OrderProcessor — то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует.

Компилятор гарантирует? Мне казалось DI работает исключительно в динамике. И потом, если разные варианты поведения, то мне надо четко указать, какое использовать, если поведение одно — зачем вообще выносить его за границы модуля? Впрочем я знаю ответ... — "для unit тестов". Вот так убогие фреймворки для тестирования порождают архитектурные проблемы.

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


Но мне не надо ничего протаскивать, мне надо локально указать конкретный вариант.
Отредактировано 27.09.2016 6:25 IQuerist . Предыдущая версия .
Re: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 07:09
Оценка:
Мое имхо по итогам обсуждения поста:

Ребята это секта... секта свидетелей DI фреймворков, отпочковавшаяся от секты свидетелей TDD. Вообще имхо DI фреймворки появились из за того, что сектантам TDD было необходимо тестировать приватную логику, а по их канонам unit test этого делать нельзя. Поэтому был применен ряд шельмований, приватную логику перекрестили в сервисы вытащили их наружу. Здесь можно вспомнить COM, который решает аналогичные DI фреймворкам задачи, но в те времена не было движения TDD и поэтому COM не стал религией, а остался инфраструктурным решением.

Ни DI ни TDD ничего не гарантируют разработчику, ни от чего не защищают и ни в чем не помогают. Зато гарантированно служат серьезным источником оверхеда. Как же им удается иногда демонстрировать свою полезность? А все элементарно... например код веб систем, можно разделить на две части — бизнес логику и код взаимодействия с системными сервисами UI, DB и т.д. Взаимодействие с системными сервисами разработчику понятно, отлично проработано и имеет долгую историю. Что провоцирует наивные умы, особенно на первых этапах проекта, запихиать бизнес логику прямо в код взаимодействия с системными сервисами. Так создаются шедевры спагетти кода. Что делает TDD? Оно ограничивает — сначала пишем тесты. И тут все верно, в юнит тестах нет взаимодействия с системными сервисами поэтому структуру бизнес логики приходится прорабатывать отдельно от всего т.е. приходится строить архитектуру. Вот и весь трюк. Цена такого подхода — серьезный оверхед (уровень которого зависит от религиозного фанатизма разработчика), потому что бизнес логика гарантированно будет уточнятся и изменяться и тесты придется переписывать, но как мы теперь понимаем, для проработки бизнес логики и построения архитекуры тесты на самом деле лишь полезны, но никак не обязательны.
Отредактировано 27.09.2016 7:12 IQuerist . Предыдущая версия .
Re[20]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 27.09.16 09:05
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.

IQ>>>Обратного я и не утверждал
IQ>·>И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?
IQ>Нда... а у меня оказывается не вульгарный ServiceLocator, а кошерный Ambient Context...
Оппа. Класс называется ServiceLocator, но это не Service Locator. Клёво чё, жоб секьюрити себе обеспечиваешь?
Но не важно. Контекст — это состояние. На вопросик-то ответь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[23]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 11:28
Оценка:
Здравствуйте, ·, Вы писали:

·>Пусть одна реализация, это дело не меняет. Пишут эту реализацию другие люди, в другой команде, или это какой-нибудь RPC-интерфейс или ещё что — не важно. В вопросе главное как управлять зависимостями, а не конкретные названия классов/интерфейсов.


DI uber alies, а то что инкапсуляция идет лесом — пофигу?

IQ>>>>если можно где-то там, за ширмой неявно затаскивать его через конструктор в DI? Ведь достаточно будет посмотреть конструктор,

IQ>>·>Зачем тебе его смотреть? Если у тебя есть ссылка на OrderProcessor — то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует.
IQ>>Компилятор гарантирует? Мне казалось DI работает исключительно в динамике.
·>Если кажется — крестись, или хотя бы учебники читай. Я же уже ссылку давал на вики, читал? Где там динамика?

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

IQ>>И потом, если разные варианты поведения, то мне надо четко указать, какое использовать, если поведение одно — зачем вообще выносить его за границы модуля? Впрочем я знаю ответ... — "для unit тестов". Вот так убогие фреймворки для тестирования порождают архитектурные проблемы.

·>Это далеко не единственный ответ.

Имхо единственный, остальное — отмазы.

IQ>>·>Если у тебя такой ссылки нет, то смотри wiring и найди добавь эту ссылку к себе. Если не получится — значит что-то у тебя не хвататет в зависимостях, протаскивай как надо куда надо, а не надейся на глобальные переменные.

IQ>>Но мне не надо ничего протаскивать, мне надо локально указать конкретный вариант.
·>Какой конкретный вариант? Забудь множественные имплементации, не в них дело. Дело в том, что "конкретный вариант" тоже откуда-то должен взяться, у него можеть быть специфичный lifespan и у него могут быть свои зависимости.

А вот это отличный ответ... проясняет почему разговор идет именно о сервисах. Спасибо. Конечно остается вопрос — почему в виденом мною коде где использовался DI ничего из этого не использовалось... Это конечно не к вам претензия, а к "мейнстриму".
Отредактировано 27.09.2016 11:38 IQuerist . Предыдущая версия .
Re[21]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 11:33
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.

IQ>>>>Обратного я и не утверждал
IQ>>·>И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?
IQ>>Нда... а у меня оказывается не вульгарный ServiceLocator, а кошерный Ambient Context...
·>Оппа. Класс называется ServiceLocator, но это не Service Locator. Клёво чё, жоб секьюрити себе обеспечиваешь?

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

·>Но не важно. Контекст — это состояние. На вопросик-то ответь.


Состояние у бизнес-операции. Ее обработка создает все нужные контексты и раздает используемым модулям.
Отредактировано 27.09.2016 11:34 IQuerist . Предыдущая версия .
Re[24]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 27.09.16 12:34
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Пусть одна реализация, это дело не меняет. Пишут эту реализацию другие люди, в другой команде, или это какой-нибудь RPC-интерфейс или ещё что — не важно. В вопросе главное как управлять зависимостями, а не конкретные названия классов/интерфейсов.

IQ>DI uber alies, а то что инкапсуляция идет лесом — пофигу?
alles же.
Как раз с инкапсуляцией всё гораздо лучше, по сравнению с твоими любимыми глобальными переменными.

IQ>>>Компилятор гарантирует? Мне казалось DI работает исключительно в динамике.

IQ>·>Если кажется — крестись, или хотя бы учебники читай. Я же уже ссылку давал на вики, читал? Где там динамика?
IQ>Нда... а вы вообще программированием занимаетесь? "то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует" компилятор по вашему конструирует объекты???
Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта, и защищает доступ к приватным полям классов, не давая доступ к зависимостям, которых у тебя не предусмотрено. Тем самым в рантайме обеспечивает гарантию.

IQ>>>И потом, если разные варианты поведения, то мне надо четко указать, какое использовать, если поведение одно — зачем вообще выносить его за границы модуля? Впрочем я знаю ответ... — "для unit тестов". Вот так убогие фреймворки для тестирования порождают архитектурные проблемы.

IQ>·>Это далеко не единственный ответ.
IQ>Имхо единственный, остальное — отмазы.
Самый главный ответ — альтернативы DI+CI хуже по многим критериям.

IQ>·>Какой конкретный вариант? Забудь множественные имплементации, не в них дело. Дело в том, что "конкретный вариант" тоже откуда-то должен взяться, у него можеть быть специфичный lifespan и у него могут быть свои зависимости.

IQ>А вот это отличный ответ... проясняет почему разговор идет именно о сервисах. Спасибо. Конечно остается вопрос — почему в виденом мною коде где использовался DI ничего из этого не использовалось... Это конечно не к вам претензия, а к "мейнстриму".
Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал. Вместо того чтобы внести ясность, поделиться как же делать правильно, дискредитируешь хорошие техники всякими уничижительными словечками типа Colonoscopy Injection. И так тут сплошное невежество в "мейнстриме", а ты только усугубляешь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 27.09.16 13:05
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>>>Компилятор гарантирует? Мне казалось DI работает исключительно в динамике.

IQ>>·>Если кажется — крестись, или хотя бы учебники читай. Я же уже ссылку давал на вики, читал? Где там динамика?
IQ>>Нда... а вы вообще программированием занимаетесь? "то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует" компилятор по вашему конструирует объекты???
·>Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта, и защищает доступ к приватным полям классов, не давая доступ к зависимостям, которых у тебя не предусмотрено. Тем самым в рантайме обеспечивает гарантию.

Вероятно вы начинали с javascript...

IQ>>·>Это далеко не единственный ответ.

IQ>>Имхо единственный, остальное — отмазы.
·>Самый главный ответ — альтернативы DI+CI хуже по многим критериям.

да никто не обещал что будет хорошо говорили — будет еще лучше

IQ>>·>Какой конкретный вариант? Забудь множественные имплементации, не в них дело. Дело в том, что "конкретный вариант" тоже откуда-то должен взяться, у него можеть быть специфичный lifespan и у него могут быть свои зависимости.

IQ>>А вот это отличный ответ... проясняет почему разговор идет именно о сервисах. Спасибо. Конечно остается вопрос — почему в виденом мною коде где использовался DI ничего из этого не использовалось... Это конечно не к вам претензия, а к "мейнстриму".
·>Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал.

Ну кто-то же должен, раз все остальные стыдливо молчат

·>Вместо того чтобы внести ясность, поделиться как же делать правильно, дискредитируешь хорошие техники всякими уничижительными словечками типа Colonoscopy Injection.


Поверьте код из за которого написан пост этого стоит. Однако как правильно вы тоже так и не сформулировали

·>И так тут сплошное невежество в "мейнстриме", а ты только усугубляешь.


Складывается у меня стойкое ощущение, что это тот "мейнстрим" порожден невежеством... (это я не на вас намекаю)
Re[22]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 27.09.16 13:48
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>>>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.

IQ>>>>>Обратного я и не утверждал
IQ>>>·>И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?
IQ>>>Нда... а у меня оказывается не вульгарный ServiceLocator, а кошерный Ambient Context...
IQ>·>Оппа. Класс называется ServiceLocator, но это не Service Locator. Клёво чё, жоб секьюрити себе обеспечиваешь?
IQ>Честно нет... я искренне не ожидал, что одинаковые вещи могут по разному называться и по разному оцениваться. Для меня это честно было сюрпризом. Но в мутной теме обязаны быть грязные хаки надо лишь поискать.
Ничего не понял. Тема не мутная, похоже муть у тебя в голове. ServiceLocator и Ambient Context вещи не одинаковые, вообще ничего общего.
Ambient Context это хипстерская обёртка для обеспечения более вменяемого использования глобальных переменных.
А Service Locator это фактически такая мапа [serviceId -> serviceImplementation], называемая Registry. Притом сама мапа может протягиваться как через те же глобальные переменные (и даже с использованием Ambient Context), через DI, тупо через арументы метода или ещё как.

IQ>·>Но не важно. Контекст — это состояние. На вопросик-то ответь.

IQ>Состояние у бизнес-операции. Ее обработка создает все нужные контексты и раздает используемым модулям.
Причём тут бизнес-операция? Это вообще не в тему. Смотрим что ты написал:
"и с десяток совершенно очевидных хелперных stateless методов типа: GetBoringItemById". Вот как такой метод может быть stateless? Как мне доводилось видеть, сигнатура такого метода типично
public BoringItem GetBoringItemById(long id)
или у тебя другие варианты?
Покажи как ты видишь этот метод сделать stateless. Ему как минимум нужен borrowed DbConnection и активный TransactionContext, а ещё, бывает, какой-нибудь security context и audit recorder.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 27.09.16 15:34
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Нда... а вы вообще программированием занимаетесь? "то ты смело можешь использовать любые его методы, т.к. объект уже сконструирован, компилятор гарантирует" компилятор по вашему конструирует объекты???

IQ>·>Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта, и защищает доступ к приватным полям классов, не давая доступ к зависимостям, которых у тебя не предусмотрено. Тем самым в рантайме обеспечивает гарантию.
IQ>Вероятно вы начинали с javascript...
Я начинал с С++, а javascript был в новинку и его обычно отключали в браузере.
А к чему это всё?

IQ>·>Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал.

IQ>Ну кто-то же должен, раз все остальные стыдливо молчат
Критиковать — пожалуйста, но критикуя — предлагай, неконструктивная критика только увеличивает невежество.

IQ>·>Вместо того чтобы внести ясность, поделиться как же делать правильно, дискредитируешь хорошие техники всякими уничижительными словечками типа Colonoscopy Injection.

IQ>Поверьте код из за которого написан пост этого стоит. Однако как правильно вы тоже так и не сформулировали
Как не сформулировал? Перечитай внимательно топик.
Подытожу: "По умолчанию используйте DI+CI везде где возможно, а где невозможно — делайте рефакторинг, чтобы стало возможно".
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[23]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 28.09.16 07:07
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>>>·>Короче, stateless и static — совершенно независимые непересекающиеся понятия.

IQ>>>>>>Обратного я и не утверждал
IQ>>>>·>И как твой ServiceLocator.GetCurrentUserInfo согласуется с твоей любовью к stateless?
IQ>>>>Нда... а у меня оказывается не вульгарный ServiceLocator, а кошерный Ambient Context...
IQ>>·>Оппа. Класс называется ServiceLocator, но это не Service Locator. Клёво чё, жоб секьюрити себе обеспечиваешь?
IQ>>Честно нет... я искренне не ожидал, что одинаковые вещи могут по разному называться и по разному оцениваться. Для меня это честно было сюрпризом. Но в мутной теме обязаны быть грязные хаки надо лишь поискать.
·>Ничего не понял. Тема не мутная, похоже муть у тебя в голове. ServiceLocator и Ambient Context вещи не одинаковые, вообще ничего общего.
·>Ambient Context это хипстерская обёртка для обеспечения более вменяемого использования глобальных переменных.
·>А Service Locator это фактически такая мапа [serviceId -> serviceImplementation], называемая Registry. Притом сама мапа может протягиваться как через те же глобальные переменные (и даже с использованием Ambient Context), через DI, тупо через арументы метода или ещё как.

Читаем талмудъ:

https://smarly.net/dependency-injection-in-net/di-catalog/di-patterns/ambient-context

Ambient Context сходный по структуре с анти-паттерном Service Locator, который я опишу в главе 5. Разница состоит в том, что Ambient Context предоставляет экземпляр только одной, строго типизированной зависимости, в то время как Service Locator предположительно должен обеспечить экземпляры для каждой зависимости, которую вы можете запросить. Различия являются тонкими, так что убедитесь, что вы полностью понимаете, когда следует применять Ambient Context, прежде чем сделать это. Если вы сомневаетесь, выберите другой DI паттерн.

Хипстер — Марк Симан


Кстати там же про Thread Local Storage и HttpContext

IQ>>·>Но не важно. Контекст — это состояние. На вопросик-то ответь.

IQ>>Состояние у бизнес-операции. Ее обработка создает все нужные контексты и раздает используемым модулям.
·>Причём тут бизнес-операция? Это вообще не в тему. Смотрим что ты написал:
·>"и с десяток совершенно очевидных хелперных stateless методов типа: GetBoringItemById". Вот как такой метод может быть stateless? Как мне доводилось видеть, сигнатура такого метода типично
·>public BoringItem GetBoringItemById(long id)
·>или у тебя другие варианты?
·>Покажи как ты видишь этот метод сделать stateless. Ему как минимум нужен borrowed DbConnection и активный TransactionContext, а ещё, бывает, какой-нибудь security context и audit recorder.

GetBoringItemById не имеет состояния, состояние "DbConnection и активный TransactionContext" предоставляются ему внешними сервисами. Да в моем случае этот сервис глобальный (как и loggingContext). Ваш пример конечно интересен, хотя на мой взгляд никаких явных TransactionContext, security context и audit recorder и т.д. в DAL быть не должно — не тот уровень абстракции Они все же должны быть в высокоуровневом сервисе и это имхо очевидный маркер того, что в случае GetBoringItemById DI используется неверно.
Re[3]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 28.09.16 07:35
Оценка:
Здравствуйте, Dziman, Вы писали:

D>Здравствуйте, IQuerist, Вы писали:


IQ>>Мое имхо по итогам обсуждения поста:

IQ>>Ребята это секта...
D>Тебя уже два месяца просят раскрыть им глаза и показать как же надо, но гуру так и не снизошол

А вы пост-то вообще читали? Смысл поста — обозначить очевидную проблему. В результате обсуждения, "адепты DI" наличие описанной в посте проблемы признавать отказались. Нет никакой проблемы, пишите как писали и не замарачивайтесь.
Re[28]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 28.09.16 14:01
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Это ужосъ ))) "Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта" как такое может говорить C++ программер? А ведь я в последний раз кодил на C++ 14 лет назад.

Сейчас я Java-програмер. У тебя есть что по существу возразить или так и будешь прикапываться к личности собеседника?

IQ>>>·>Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал.

IQ>>>Ну кто-то же должен, раз все остальные стыдливо молчат
IQ>·>Критиковать — пожалуйста, но критикуя — предлагай, неконструктивная критика только увеличивает невежество.
IQ> Дружища, здесь не запукинский митинг. Вы предлагаете задавать вопрос только когда известен ответ? Но базовый ответ известен всем и всегда — "контрагент идиот не желает признавать очевидного" Вспоминайте об этом каждый раз когда повторяете глупость — "критикуя — предлагай".
Я что-то пропустил, ты разве задавал какие-то вопросы? По-моему просто поворчал, пожаловался на жизнь и участие в говнопроектах.

IQ>·>Как не сформулировал? Перечитай внимательно топик.

IQ>·>Подытожу: "По умолчанию используйте DI+CI везде где возможно, а где невозможно — делайте рефакторинг, чтобы стало возможно".
IQ>Таки да, это секта...
Таки да, упёртый невежда, смотрит в книгу видит фигу. В конце концов, почитай хотя бы приведённый тобой же талмуд:

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

Почти дословно мой вывод.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 28.09.16 16:05
Оценка:
Здравствуйте, #John, Вы писали:

J>·>Почему редко такой код встречается?..

J>А если в классе UserService в методе Save для бизнес логики надо исспользовать разные *Managers,
J>а в методе Delete еще более разные(UserProfileManager, AcitvityManager и т.д.).
J>Передавать в UserService(FabricOfManagers fabric) — фабрику классов со всеми менеджерами?
Оказывается это называется Constructor Over-injection
тут вот разжевано с примерами: https://smarly.net/dependency-injection-in-net/di-catalog/di-refactorings/dealing-with-constructor-over-injection
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[29]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.09.16 06:42
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>Это ужосъ ))) "Компилятор проверяет, что вызов конструктора выполнен с правильными аргументами, обеспечивает невозможность обратиться к методам несконструированного объекта" как такое может говорить C++ программер? А ведь я в последний раз кодил на C++ 14 лет назад.

·>Сейчас я Java-програмер. У тебя есть что по существу возразить или так и будешь прикапываться к личности собеседника?

К личности — не буду, вы вполне симпатичны

IQ>>>>·>Собственно моя претензия в том, что ты лишь на основании своего негативного опыта с говнопроектами в одну кучу всё свалил и раскритиковал.

IQ>>>>Ну кто-то же должен, раз все остальные стыдливо молчат
IQ>>·>Критиковать — пожалуйста, но критикуя — предлагай, неконструктивная критика только увеличивает невежество.
IQ>> Дружища, здесь не запукинский митинг. Вы предлагаете задавать вопрос только когда известен ответ? Но базовый ответ известен всем и всегда — "контрагент идиот не желает признавать очевидного" Вспоминайте об этом каждый раз когда повторяете глупость — "критикуя — предлагай".
·>Я что-то пропустил, ты разве задавал какие-то вопросы? По-моему просто поворчал, пожаловался на жизнь и участие в говнопроектах.

А должен был поднять зеленое знамя с надпись — будем за такое руки отрубать?

IQ>>·>Как не сформулировал? Перечитай внимательно топик.

IQ>>·>Подытожу: "По умолчанию используйте DI+CI везде где возможно, а где невозможно — делайте рефакторинг, чтобы стало возможно".
IQ>>Таки да, это секта...
·>Таки да, упёртый невежда, смотрит в книгу видит фигу. В конце концов, почитай хотя бы приведённый тобой же талмуд:

Вот нету у меня понимания примеров полезности DI. Все предлагают какой-то академический мусор за который в реальном проекте лупят ссаными тряпками. Да я сам похожий мусор когда-то плодил и довольно быстро увидел минусы. Плюсов пока разглядеть не получается, конечно я признаю, что повышение абстрактности кода потенциально полезно, но не понимаю — для чего, хотя я допускаю, что в некоторых проектах (которых я не видел) это может быть очень важно.

Пеар buzz на меня не действует.

·>

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

·>Почти дословно мой вывод.

Ваше право.
Отредактировано 29.09.2016 7:39 IQuerist . Предыдущая версия . Еще …
Отредактировано 29.09.2016 7:37 IQuerist . Предыдущая версия .
Отредактировано 29.09.2016 7:36 IQuerist . Предыдущая версия .
Re[11]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.09.16 07:12
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, #John, Вы писали:


J>>·>Почему редко такой код встречается?..

J>>А если в классе UserService в методе Save для бизнес логики надо исспользовать разные *Managers,
J>>а в методе Delete еще более разные(UserProfileManager, AcitvityManager и т.д.).
J>>Передавать в UserService(FabricOfManagers fabric) — фабрику классов со всеми менеджерами?
·>Оказывается это называется Constructor Over-injection
·>тут вот разжевано с примерами: https://smarly.net/dependency-injection-in-net/di-catalog/di-refactorings/dealing-with-constructor-over-injection

Эх... ну вот опять вроде бы правильные и нужные вещи говорит дядя, но в итоге это выглядит — плодите интерфейсы, интерфейсы над интерфейсами и над ними еще интерфейсы. Может это дело потенциально полезное, но имхо мало кто будет этим заниматься на всех давят сроки, поэтому будут оставаться конструкторы с 20-30 параметрами на все случаи жизни. А когда на подходе дед-лайн новые классы будут создаваться копи-пастом вообще всех зависимостей самого жирного конструктора. И это в лучшем случае, в худшем максимальное количество данных будут передавать например на клиента в javascript чтобы допилить бизнес логику там. Т.к. там можно избежать всей этой возни с зависимостями и интерфейсами.
Да... метод наименьшего сопротивления.

Идеи то вроде бы и правильные, а вот их воплощение имхо абсолютно негодное.

PS и вот еще какая проблема — каждому "сервису" надо дать имя. И если методу еще как-то что-то можно вымучить исходя из его поведения. То с сервисами все обстоит гораздо хуже. Имена дают нелогичные, непонятные и ошибочные, камменты быстро деградируют и чтобы узнать о том, что же таки эта зависимость делает приходится лезть в ее реализацию, а искать ее приходится как правило по интерфейсу.
Отредактировано 29.09.2016 9:27 IQuerist . Предыдущая версия . Еще …
Отредактировано 29.09.2016 7:23 IQuerist . Предыдущая версия .
Отредактировано 29.09.2016 7:22 IQuerist . Предыдущая версия .
Отредактировано 29.09.2016 7:21 IQuerist . Предыдущая версия .
Re[30]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 29.09.16 09:32
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Сейчас я Java-програмер. У тебя есть что по существу возразить или так и будешь прикапываться к личности собеседника?

IQ>К личности — не буду, вы вполне симпатичны
Вместо того, чтобы сказать что не так в моих словах, к чему тогда вопросы о моём знании С++ и js?

IQ>·>Я что-то пропустил, ты разве задавал какие-то вопросы? По-моему просто поворчал, пожаловался на жизнь и участие в говнопроектах.

IQ>А должен был поднять зеленое знамя с надпись — будем за такое руки отрубать?
Это тоже не конструктивно.

IQ>>>Таки да, это секта...

IQ>·>Таки да, упёртый невежда, смотрит в книгу видит фигу. В конце концов, почитай хотя бы приведённый тобой же талмуд:
IQ>Вот нету у меня понимания примеров полезности DI. Все предлагают какой-то академический мусор за который в реальном проекте лупят ссаными тряпками. Да я сам похожий мусор когда-то плодил и довольно быстро увидел минусы. Плюсов пока разглядеть не получается, конечно я признаю, что повышение абстрактности кода потенциально полезно, но не понимаю — для чего, хотя я допускаю, что в некоторых проектах (которых я не видел) это может быть очень важно.
Ага, понимания нет, но используешь что попалось под руку. На каком основании ты именно ambient context выбрал? Почему? Привычнее? Выбираешь сердцем?

IQ>Пеар buzz на меня не действует.

Ты даже чайнико-адаптированную книгу привёл с разжевыванием и примерами что и как делается, почему так делается и чем это грозит. Причём тут баззворды?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[12]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 29.09.16 10:00
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Оказывается это называется Constructor Over-injection

IQ>·>тут вот разжевано с примерами: https://smarly.net/dependency-injection-in-net/di-catalog/di-refactorings/dealing-with-constructor-over-injection

IQ>Эх... ну вот опять вроде бы правильные и нужные вещи говорит дядя, но в итоге это выглядит — плодите интерфейсы, интерфейсы над интерфейсами и над ними еще интерфейсы.

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

IQ>Может это дело потенциально полезное, но имхо мало кто будет этим заниматься на всех давят сроки, поэтому будут оставаться конструкторы с 20-30 параметрами на все случаи жизни.

У меня был опыт с такими конструкторами. Рекорд толи 37 толи 47 параметров было, я не помню. И знаешь — это был вариант лучше остальных мною виденных. Была уверенность — если что-то не так сделаю — код просто не сможет скомпилиться, а не грохнется в проде ВНЕЗАПНО.

IQ>А когда на подходе дед-лайн новые классы будут создаваться копи-пастом вообще всех зависимостей самого жирного конструктора. И это в лучшем случае, в худшем максимальное количество данных будут передавать например на клиента в javascript чтобы допилить бизнес логику там. Т.к. там можно избежать всей этой возни с зависимостями и интерфейсами.

IQ>Да... метод наименьшего сопротивления.
Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается. Это лишь такой явный индикатор того, что вот эта часть приложения плохо продумана, были дед-лайны и всё такое, что туда нужно вложить ещё сколько-то времени.

IQ>Идеи то вроде бы и правильные, а вот их воплощение имхо абсолютно негодное.

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

IQ>PS и вот еще какая проблема — каждому "сервису" надо дать имя. И если методу еще как-то что-то можно вымучить исходя из его поведения. То с сервисами все обстоит гораздо хуже. Имена дают нелогичные, непонятные и ошибочные, камменты быстро деградируют и чтобы узнать о том, что же таки эта зависимость делает приходится лезть в ее реализацию,

Вот уж это совсем не проблема. Рефакторинг rename method/class — занимает около 1 минуты, включая коммит+пуш.

IQ>а искать ее приходится как правило по интерфейсу.

Открой для себя рефакторинг inline interface.

Ты считаешь это проблемой потому что у тебя плохое качество кода и абсолютно любое его изменение — страшно, ты не понимаешь что где может поломаться. Это звоночек.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[31]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.09.16 10:10
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>>>Таки да, это секта...

IQ>>·>Таки да, упёртый невежда, смотрит в книгу видит фигу. В конце концов, почитай хотя бы приведённый тобой же талмуд:
IQ>>Вот нету у меня понимания примеров полезности DI. Все предлагают какой-то академический мусор за который в реальном проекте лупят ссаными тряпками. Да я сам похожий мусор когда-то плодил и довольно быстро увидел минусы. Плюсов пока разглядеть не получается, конечно я признаю, что повышение абстрактности кода потенциально полезно, но не понимаю — для чего, хотя я допускаю, что в некоторых проектах (которых я не видел) это может быть очень важно.
·>Ага, понимания нет, но используешь что попалось под руку. На каком основании ты именно ambient context выбрал? Почему? Привычнее? Выбираешь сердцем?

Я его не выбирал я использую решение 12 летней давности. Просто ambient context более подходит по описанию.

IQ>>Пеар buzz на меня не действует.

·>Ты даже чайнико-адаптированную книгу привёл с разжевыванием и примерами что и как делается, почему так делается и чем это грозит. Причём тут баззворды?

При том, что на мой взгляд, "как надо" эти техники использоваться не будут...
Отредактировано 29.09.2016 10:14 IQuerist . Предыдущая версия .
Re[13]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.09.16 10:26
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>Эх... ну вот опять вроде бы правильные и нужные вещи говорит дядя, но в итоге это выглядит — плодите интерфейсы, интерфейсы над интерфейсами и над ними еще интерфейсы.

·>Надо понимать, что вот это вся интерфейсизация рассказывает о решениях в больших многомодульных проектах, которые пишутся разными командами и т.п.

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

IQ>>Может это дело потенциально полезное, но имхо мало кто будет этим заниматься на всех давят сроки, поэтому будут оставаться конструкторы с 20-30 параметрами на все случаи жизни.

·>У меня был опыт с такими конструкторами. Рекорд толи 37 толи 47 параметров было, я не помню. И знаешь — это был вариант лучше остальных мною виденных. Была уверенность — если что-то не так сделаю — код просто не сможет скомпилиться, а не грохнется в проде ВНЕЗАПНО.

Совсем не понятно откуда такая уверенность.

IQ>>А когда на подходе дед-лайн новые классы будут создаваться копи-пастом вообще всех зависимостей самого жирного конструктора. И это в лучшем случае, в худшем максимальное количество данных будут передавать например на клиента в javascript чтобы допилить бизнес логику там. Т.к. там можно избежать всей этой возни с зависимостями и интерфейсами.

IQ>>Да... метод наименьшего сопротивления.
·>Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается.

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

IQ>>Идеи то вроде бы и правильные, а вот их воплощение имхо абсолютно негодное.

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

Вот эти вынужденные фасады над фасадами над фасадами это "понимаемо" и "легко изменяемо"?

IQ>>PS и вот еще какая проблема — каждому "сервису" надо дать имя. И если методу еще как-то что-то можно вымучить исходя из его поведения. То с сервисами все обстоит гораздо хуже. Имена дают нелогичные, непонятные и ошибочные, камменты быстро деградируют и чтобы узнать о том, что же таки эта зависимость делает приходится лезть в ее реализацию,

·>Вот уж это совсем не проблема. Рефакторинг rename method/class — занимает около 1 минуты, включая коммит+пуш.

Шпасиба друг! А я и не знал, что "Рефакторинг rename method/class" поможет придумать грамотные, понятные и верные названия для сервисов.

IQ>>а искать ее приходится как правило по интерфейсу.

·>Открой для себя рефакторинг inline interface.

·>Ты считаешь это проблемой потому что у тебя плохое качество кода и абсолютно любое его изменение — страшно, ты не понимаешь что где может поломаться. Это звоночек.


Лично у меня, я считаю, приемлемое качество кода, потому что бизнес логика моих систем активно расширяется многие годы без рисков того, что проект деградирует настолько, что единственным верным решением будет — переписать его с нуля. Это обеспечивается всего лишь грамотной декомпозицией.
Re[13]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 29.09.16 12:09
Оценка:
Здравствуйте, ·, Вы писали:

Забавный ответ от uncle Bob

https://youtu.be/Nltqi7ODZTM?t=2025

Я признаться был готов перестать его уважать, но после этого видео зауважал еще больше. Рекомендую смотреть сначала мне очень понравилось.
Re[14]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 29.09.16 13:46
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Эх... ну вот опять вроде бы правильные и нужные вещи говорит дядя, но в итоге это выглядит — плодите интерфейсы, интерфейсы над интерфейсами и над ними еще интерфейсы.

IQ>·>Надо понимать, что вот это вся интерфейсизация рассказывает о решениях в больших многомодульных проектах, которые пишутся разными командами и т.п.
IQ>Не надо рассказывать о "больших многомодульных проектах" в топиках где обсуждают малые проекты плохого качества. Стартуйте свой топик о "больших многомодульных проектах" и мне, там стыдно будет предлагать вам не использовать DI. Но в этом топике разговор о другом.
Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

IQ>·>У меня был опыт с такими конструкторами. Рекорд толи 37 толи 47 параметров было, я не помню. И знаешь — это был вариант лучше остальных мною виденных. Была уверенность — если что-то не так сделаю — код просто не сможет скомпилиться, а не грохнется в проде ВНЕЗАПНО.

IQ>Совсем не понятно откуда такая уверенность.
Из моего опыта, я повидал и Spring разных версий, и Guice, и JBoss Seam, и доморощенный код на всяких синглтонах и прочих контекстах, и чисто java код, где даже большинство стандартных JDK-классов (типа String) не используется, и даже, прости господи, EJB. Так вот самый дубовый и простой в написании и поддержке код это именно DI+CI с явно выделенным composition root. К сожалению, делать просто — сложно, а делать сложно — просто.

IQ>·>Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается.

IQ>Ох... ну раз в книге написано, значит г..нопроектов откуда я отхреначивал наивный DI не было, может они мне приснились...
По-моему опыту так же. Что такое "отхреначивать наивный DI" ты так и не прояснил. Как я понял — ты заменял CI на глобальные переменные. В чём именно было улучшение-то от этого твоего отхреначивания?

IQ>>>Идеи то вроде бы и правильные, а вот их воплощение имхо абсолютно негодное.

IQ>·>Воплощение должно быть таким, чтобы код был всё ещё понимаемым и легко при желании изменяемым. Явные зависимости этому делу хорошо способствуют.
IQ>Вот эти вынужденные фасады над фасадами над фасадами это "понимаемо" и "легко изменяемо"?
Что значит вынужденные? Если они вынуждены, то дело не в CI, а с твоими любимыми глобальными переменными получится амбиентные синглтоны провайдеров фабрики синглтонов контекстов.

IQ>>>PS и вот еще какая проблема — каждому "сервису" надо дать имя. И если методу еще как-то что-то можно вымучить исходя из его поведения. То с сервисами все обстоит гораздо хуже. Имена дают нелогичные, непонятные и ошибочные, камменты быстро деградируют и чтобы узнать о том, что же таки эта зависимость делает приходится лезть в ее реализацию,

IQ>·>Вот уж это совсем не проблема. Рефакторинг rename method/class — занимает около 1 минуты, включая коммит+пуш.
IQ>Шпасиба друг! А я и не знал, что "Рефакторинг rename method/class" поможет придумать грамотные, понятные и верные названия для сервисов.
Конечно помогает. Как только придумаешь — зафиксируешь это в коде. Если не придумаешь сразу — придумай хоть что-нибудь и запиши как кажется на текущий момент, отливать в граните ничего не надо.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[32]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 29.09.16 13:50
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Вот нету у меня понимания примеров полезности DI. Все предлагают какой-то академический мусор за который в реальном проекте лупят ссаными тряпками. Да я сам похожий мусор когда-то плодил и довольно быстро увидел минусы. Плюсов пока разглядеть не получается, конечно я признаю, что повышение абстрактности кода потенциально полезно, но не понимаю — для чего, хотя я допускаю, что в некоторых проектах (которых я не видел) это может быть очень важно.

IQ>·>Ага, понимания нет, но используешь что попалось под руку. На каком основании ты именно ambient context выбрал? Почему? Привычнее? Выбираешь сердцем?
IQ>Я его не выбирал я использую решение 12 летней давности. Просто ambient context более подходит по описанию.
Повезло, что проект сильно не развивается 12 лет.

IQ>>>Пеар buzz на меня не действует.

IQ>·>Ты даже чайнико-адаптированную книгу привёл с разжевыванием и примерами что и как делается, почему так делается и чем это грозит. Причём тут баззворды?
IQ>При том, что на мой взгляд, "как надо" эти техники использоваться не будут...
Up to you. Причём тут техники?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[14]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 29.09.16 20:37
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>Забавный ответ от uncle Bob

IQ>https://youtu.be/Nltqi7ODZTM?t=2025
IQ>Я признаться был готов перестать его уважать, но после этого видео зауважал еще больше. Рекомендую смотреть сначала мне очень понравилось.
Он говорит о Dependency Injection Framework (ака IoC-container), то же самое, что я и писал в этом топике
Автор: ·
Дата: 01.09.16
.
Ты вот любишь свой Ambient Context, а ведь это тоже один из способов реализации Dependency Injection. Как же так позволил себе использовать DI?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[33]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 07:42
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>Вот нету у меня понимания примеров полезности DI. Все предлагают какой-то академический мусор за который в реальном проекте лупят ссаными тряпками. Да я сам похожий мусор когда-то плодил и довольно быстро увидел минусы. Плюсов пока разглядеть не получается, конечно я признаю, что повышение абстрактности кода потенциально полезно, но не понимаю — для чего, хотя я допускаю, что в некоторых проектах (которых я не видел) это может быть очень важно.

IQ>>·>Ага, понимания нет, но используешь что попалось под руку. На каком основании ты именно ambient context выбрал? Почему? Привычнее? Выбираешь сердцем?
IQ>>Я его не выбирал я использую решение 12 летней давности. Просто ambient context более подходит по описанию.
·>Повезло, что проект сильно не развивается 12 лет.

))) проектов более 20 3 из них введены в продакшен в этом году. EF, ajax, asp.net mvc все как надо.

IQ>>>>Пеар buzz на меня не действует.

IQ>>·>Ты даже чайнико-адаптированную книгу привёл с разжевыванием и примерами что и как делается, почему так делается и чем это грозит. Причём тут баззворды?
IQ>>При том, что на мой взгляд, "как надо" эти техники использоваться не будут...
·>Up to you. Причём тут техники?

Успех технологии определяется тем, способна ли большая часть инженеров освоить техники и эффективно их использовать...
Re[15]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 07:53
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>Не надо рассказывать о "больших многомодульных проектах" в топиках где обсуждают малые проекты плохого качества. Стартуйте свой топик о "больших многомодульных проектах" и мне, там стыдно будет предлагать вам не использовать DI. Но в этом топике разговор о другом.

·>Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

Не спорю, DI всего лишь еще один важный повод.

IQ>>Совсем не понятно откуда такая уверенность.

·>Из моего опыта, я повидал и Spring разных версий, и Guice, и JBoss Seam, и доморощенный код на всяких синглтонах и прочих контекстах, и чисто java код, где даже большинство стандартных JDK-классов (типа String) не используется, и даже, прости господи, EJB. Так вот самый дубовый и простой в написании и поддержке код это именно DI+CI с явно выделенным composition root. К сожалению, делать просто — сложно, а делать сложно — просто.

))) пост не о том, где DI хорош (кстати это имхо был бы крайне полезный пост), а о том, где он плох.

IQ>>·>Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается.

IQ>>Ох... ну раз в книге написано, значит г..нопроектов откуда я отхреначивал наивный DI не было, может они мне приснились...
·>По-моему опыту так же. Что такое "отхреначивать наивный DI" ты так и не прояснил. Как я понял — ты заменял CI на глобальные переменные.

Ага на 2-3 глобальных сервиса. Ну глобальные они только формально, на самом деле они в local context, как собственно и сервисы DI.

·>В чём именно было улучшение-то от этого твоего отхреначивания?


Хелперы стали хелперами без паутины зависимостей, которая в рамках конкретно этих проектов была излишняя. Ну и количество интерфейсов уменьшилось на 90%

IQ>>>>Идеи то вроде бы и правильные, а вот их воплощение имхо абсолютно негодное.

IQ>>·>Воплощение должно быть таким, чтобы код был всё ещё понимаемым и легко при желании изменяемым. Явные зависимости этому делу хорошо способствуют.
IQ>>Вот эти вынужденные фасады над фасадами над фасадами это "понимаемо" и "легко изменяемо"?
·>Что значит вынужденные? Если они вынуждены, то дело не в CI, а с твоими любимыми глобальными переменными получится амбиентные синглтоны провайдеров фабрики синглтонов контекстов.

Вы же сами ссылку на главу "6.4. Обсуждение феномена Constructor Over-injection" давали. Вы текст не читали что ли? Марк Симан по эстетическим причинам разговор про "Рефакторинг по направлению к Фасадным сервисам" завел?
Re[15]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 07:57
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>Забавный ответ от uncle Bob

IQ>>https://youtu.be/Nltqi7ODZTM?t=2025
IQ>>Я признаться был готов перестать его уважать, но после этого видео зауважал еще больше. Рекомендую смотреть сначала мне очень понравилось.
·>Он говорит о Dependency Injection Framework (ака IoC-container), то же самое, что я и писал в этом топике
Автор: ·
Дата: 01.09.16
.

·>Ты вот любишь свой Ambient Context, а ведь это тоже один из способов реализации Dependency Injection. Как же так позволил себе использовать DI?

А я не отрицаю, что использую топорную версию DI. Главное имхо то, что (на малых проектах) меня и менее умудренных коллег она ограничивает, в отличии от DI, с помощью которого, наивные энтузиасты творят ад.
Re[5]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 08:02
Оценка:
Здравствуйте, Vladek, Вы писали:

V>Здравствуйте, IQuerist, Вы писали:


IQ>>А вы пост-то вообще читали? Смысл поста — обозначить очевидную проблему. В результате обсуждения, "адепты DI" наличие описанной в посте проблемы признавать отказались. Нет никакой проблемы, пишите как писали и не замарачивайтесь.


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


V>Процесс занимает 5-10 лет внимательного программирования.


да... все так , рекламный бум спадет и кривоватую технологию вытеснит более ясная и понятная. Но имхо хочется примерно понимать в какую сторону надо смотреть уже сегодня.
Re[16]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 30.09.16 09:28
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>·>Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

IQ>Не спорю, DI всего лишь еще один важный повод.
Повод для чего?

IQ>·>Из моего опыта, я повидал и Spring разных версий, и Guice, и JBoss Seam, и доморощенный код на всяких синглтонах и прочих контекстах, и чисто java код, где даже большинство стандартных JDK-классов (типа String) не используется, и даже, прости господи, EJB. Так вот самый дубовый и простой в написании и поддержке код это именно DI+CI с явно выделенным composition root. К сожалению, делать просто — сложно, а делать сложно — просто.

IQ>))) пост не о том, где DI хорош (кстати это имхо был бы крайне полезный пост), а о том, где он плох.
Как выяснилось нигде он не плох. Плохи бывают IoC-контейнеры. Вот даже у тебя ambient context — это тот же DI, но один из плохих его видов реализации.

IQ>>>·>Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается.

IQ>>>Ох... ну раз в книге написано, значит г..нопроектов откуда я отхреначивал наивный DI не было, может они мне приснились...
IQ>·>По-моему опыту так же. Что такое "отхреначивать наивный DI" ты так и не прояснил. Как я понял — ты заменял CI на глобальные переменные.
IQ>Ага на 2-3 глобальных сервиса. Ну глобальные они только формально, на самом деле они в local context, как собственно и сервисы DI.
Изменяемые данные в статических полях есть? Значит глобальные и формально, и на самом деле.
В продуманной архитектуре зависимостей нет контекста, есть composition root.

IQ>·>В чём именно было улучшение-то от этого твоего отхреначивания?

IQ>Хелперы стали хелперами без паутины зависимостей, которая в рамках конкретно этих проектов была излишняя.
Хелпер вообще-то антипаттерн практически, не понимаю почему ты этим хвастаешься. Это индикация, что ты толком не понимаешь что данный класс делает, ну и называешь его хелпер. Вот вспомним об SRP. Какая обязанность у хелпера?

IQ>Ну и количество интерфейсов уменьшилось на 90%

Десятый раз повторяю, что интерфейсы для DI+CI не нужны, да и рефакторинг тривиален. Ты их мог и так уменьшить, сохраняя управляемость зависимостей.

IQ>>>Вот эти вынужденные фасады над фасадами над фасадами это "понимаемо" и "легко изменяемо"?

IQ>·>Что значит вынужденные? Если они вынуждены, то дело не в CI, а с твоими любимыми глобальными переменными получится амбиентные синглтоны провайдеров фабрики синглтонов контекстов.
IQ>Вы же сами ссылку на главу "6.4. Обсуждение феномена Constructor Over-injection" давали. Вы текст не читали что ли? Марк Симан по эстетическим причинам разговор про "Рефакторинг по направлению к Фасадным сервисам" завел?
Ты похоже вообще не читал, почитай, таки да, по эстетическим:

Тем не менее, некоторым людям неудобно, если число зависимостей растет. Они не любят конструкторы со слишком большим числом параметров.

Мало того, что DI+CI тут не причём, т.к.

Этот плохо пахнущий код не появляется, но усугубляется в результате использования DI

Вместо того чтобы чувствовать неловкость из-за Constructor Over-injection, мы должны принять его как удачный побочный эффект внедрения в конструктор. Это сигнал, который предупреждает нас всякий раз, когда класс берет на себя слишком большую ответственность.

но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 10:16
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>·>Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

IQ>>Не спорю, DI всего лишь еще один важный повод.
·>Повод для чего?

Плодить интерфейсы

IQ>>·>Из моего опыта, я повидал и Spring разных версий, и Guice, и JBoss Seam, и доморощенный код на всяких синглтонах и прочих контекстах, и чисто java код, где даже большинство стандартных JDK-классов (типа String) не используется, и даже, прости господи, EJB. Так вот самый дубовый и простой в написании и поддержке код это именно DI+CI с явно выделенным composition root. К сожалению, делать просто — сложно, а делать сложно — просто.

IQ>>))) пост не о том, где DI хорош (кстати это имхо был бы крайне полезный пост), а о том, где он плох.
·>Как выяснилось нигде он не плох. Плохи бывают IoC-контейнеры. Вот даже у тебя ambient context — это тот же DI, но один из плохих его видов реализации.

Любая, самая идеальная вещь может быть плохой там, где она лишняя.

IQ>>>>·>Написано же в книге, что сам по себе такой конструктор проблем не создаёт, просто страдает эстетика, но код всё равно относительно легко контролируется и понимается.

IQ>>>>Ох... ну раз в книге написано, значит г..нопроектов откуда я отхреначивал наивный DI не было, может они мне приснились...
IQ>>·>По-моему опыту так же. Что такое "отхреначивать наивный DI" ты так и не прояснил. Как я понял — ты заменял CI на глобальные переменные.
IQ>>Ага на 2-3 глобальных сервиса. Ну глобальные они только формально, на самом деле они в local context, как собственно и сервисы DI.
·>Изменяемые данные в статических полях есть? Значит глобальные и формально, и на самом деле.

В статических полях исключительно stateless сервисы. Изменяемые данные в local context. Это или thread contect или httpcontext.

·>В продуманной архитектуре зависимостей нет контекста, есть composition root.


Вы думаете local context такой стойкий потому что разработчики ленивые? local context такой стойкий потому, что в него отлично ложатся контексты бизнес операций.

IQ>>·>В чём именно было улучшение-то от этого твоего отхреначивания?

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

Я не хвастаюсь. Просто раньше из этих хелперов состояли DI сервисы.

·>Это индикация, что ты толком не понимаешь что данный класс делает, ну и называешь его хелпер. Вот вспомним об SRP. Какая обязанность у хелпера?


Обязанность хелпера — быть помойкой хелперных методов

IQ>>Ну и количество интерфейсов уменьшилось на 90%

·>Десятый раз повторяю, что интерфейсы для DI+CI не нужны, да и рефакторинг тривиален. Ты их мог и так уменьшить, сохраняя управляемость зависимостей.

Я тут запоздало сообразил, что не видел вашего варианта DI. Варианты с DI фреймворками понятны. Я глянул ваши ответы и не смог найти механизм, который будет в вашем случае создавать и хранить сервисы и инжектить их в клиенты.

IQ>>>>Вот эти вынужденные фасады над фасадами над фасадами это "понимаемо" и "легко изменяемо"?

IQ>>·>Что значит вынужденные? Если они вынуждены, то дело не в CI, а с твоими любимыми глобальными переменными получится амбиентные синглтоны провайдеров фабрики синглтонов контекстов.
IQ>>Вы же сами ссылку на главу "6.4. Обсуждение феномена Constructor Over-injection" давали. Вы текст не читали что ли? Марк Симан по эстетическим причинам разговор про "Рефакторинг по направлению к Фасадным сервисам" завел?
·>Ты похоже вообще не читал, почитай, таки да, по эстетическим:
·>

Тем не менее, некоторым людям неудобно, если число зависимостей растет. Они не любят конструкторы со слишком большим числом параметров.

·>Мало того, что DI+CI тут не причём, т.к.
·>

Этот плохо пахнущий код не появляется, но усугубляется в результате использования DI

·>

Вместо того чтобы чувствовать неловкость из-за Constructor Over-injection, мы должны принять его как удачный побочный эффект внедрения в конструктор. Это сигнал, который предупреждает нас всякий раз, когда класс берет на себя слишком большую ответственность.


Ладно, оставим это все на совести адептов DI. Собсна цель моего поста не в том, чтобы запрещать им ковырять в носу.
Re[18]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 30.09.16 11:03
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>·>Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

IQ>>>Не спорю, DI всего лишь еще один важный повод.
IQ>·>Повод для чего?
IQ>Плодить интерфейсы
Так плодит интерфейсы невежество, а не DI. В каком конкретно месте DI требует интерфейсов? Я даже уверен, что большинство IoC-фреймворков вполне могут без них обходиться.

IQ>>>))) пост не о том, где DI хорош (кстати это имхо был бы крайне полезный пост), а о том, где он плох.

IQ>·>Как выяснилось нигде он не плох. Плохи бывают IoC-контейнеры. Вот даже у тебя ambient context — это тот же DI, но один из плохих его видов реализации.
IQ>Любая, самая идеальная вещь может быть плохой там, где она лишняя.
Так отказывайся от ambient context. Он лишний же.

IQ>>>·>По-моему опыту так же. Что такое "отхреначивать наивный DI" ты так и не прояснил. Как я понял — ты заменял CI на глобальные переменные.

IQ>>>Ага на 2-3 глобальных сервиса. Ну глобальные они только формально, на самом деле они в local context, как собственно и сервисы DI.
IQ>·>Изменяемые данные в статических полях есть? Значит глобальные и формально, и на самом деле.
IQ>В статических полях исключительно stateless сервисы. Изменяемые данные в local context. Это или thread contect или httpcontext.
TLS это то же статическое поле, по сути это статическая мапа с локами, где где ключом является currentThreadId. Глобальная переменная, перенесённая под реалии многопоточного программирования. httpcontext.current это тоже TLS.

IQ>·>В продуманной архитектуре зависимостей нет контекста, есть composition root.

IQ> Вы думаете local context такой стойкий потому что разработчики ленивые? local context такой стойкий потому, что в него отлично ложатся контексты бизнес операций.
Нет, просто невежественные, перечитай топик — много народу тут отметилось которые вообще не знают что такое CI. Вот посмотри на код даже хорошего трудолюбивого студента — код плохой потому что у студента мало опыта и знаний, а не потому что код так лёг.

IQ>>>·>В чём именно было улучшение-то от этого твоего отхреначивания?

IQ>>>Хелперы стали хелперами без паутины зависимостей, которая в рамках конкретно этих проектов была излишняя.
IQ>·>Хелпер вообще-то антипаттерн практически, не понимаю почему ты этим хвастаешься.
IQ>Я не хвастаюсь. Просто раньше из этих хелперов состояли DI сервисы.
Так куда эта паутина зависимостей делась? Замели под коврик?
Зашли в тёмный подвал, включили свет — ух сколько грязи и паутины, давайте лучше лампочку разобьём, чтобы этого ничего не было видно, ну и напишем пост "О наивном освещении в подвале".

IQ>>>Ну и количество интерфейсов уменьшилось на 90%

IQ>·>Десятый раз повторяю, что интерфейсы для DI+CI не нужны, да и рефакторинг тривиален. Ты их мог и так уменьшить, сохраняя управляемость зависимостей.
IQ>Я тут запоздало сообразил, что не видел вашего варианта DI. Варианты с DI фреймворками понятны.
Вот же: http://rsdn.org/forum/design/6560633.flat#6560633
Автор: ·
Дата: 22.09.16

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

IQ>Я глянул ваши ответы и не смог найти механизм, который будет в вашем случае создавать и хранить сервисы и инжектить их в клиенты.

Зачем хранить сервисы? Сразу создавай и связывай что как надо в composition root. Инжектятся они с помощью CI, десятый раз говорю.

IQ> Ладно, оставим это все на совести адептов DI. Собсна цель моего поста не в том, чтобы запрещать им ковырять в носу.

Ты не отмахивайся, а читай и борись с невежеством, а не с DI.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 12:13
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>·>Плодить интерфейсы можно и без DI. То что их плодят выкрикивая "DI!" — виновато лишь невежество, а не DI. Бороться надо с невежеством, а не с DI.

IQ>>>>Не спорю, DI всего лишь еще один важный повод.
IQ>>·>Повод для чего?
IQ>>Плодить интерфейсы
·>Так плодит интерфейсы невежество, а не DI. В каком конкретно месте DI требует интерфейсов? Я даже уверен, что большинство IoC-фреймворков вполне могут без них обходиться.

Марк Симан невежество, не я сказал...

IQ>>>>))) пост не о том, где DI хорош (кстати это имхо был бы крайне полезный пост), а о том, где он плох.

IQ>>·>Как выяснилось нигде он не плох. Плохи бывают IoC-контейнеры. Вот даже у тебя ambient context — это тот же DI, но один из плохих его видов реализации.
IQ>>Любая, самая идеальная вещь может быть плохой там, где она лишняя.
·>Так отказывайся от ambient context. Он лишний же.

Он собственно появился по одной простой причине — сугубо синтаксическая группировка всех часто используемых сервисов. Его можно смело выкинуть и создавать все нужные сервисы с помощью new.

IQ>>·>В продуманной архитектуре зависимостей нет контекста, есть composition root.

IQ>> Вы думаете local context такой стойкий потому что разработчики ленивые? local context такой стойкий потому, что в него отлично ложатся контексты бизнес операций.
·>Нет, просто невежественные, перечитай топик — много народу тут отметилось которые вообще не знают что такое CI. Вот посмотри на код даже хорошего трудолюбивого студента — код плохой потому что у студента мало опыта и знаний, а не потому что код так лёг.

Имхо если мало знаний нефиг принимать серьезные решения.

IQ>>>>·>В чём именно было улучшение-то от этого твоего отхреначивания?

IQ>>>>Хелперы стали хелперами без паутины зависимостей, которая в рамках конкретно этих проектов была излишняя.
IQ>>·>Хелпер вообще-то антипаттерн практически, не понимаю почему ты этим хвастаешься.
IQ>>Я не хвастаюсь. Просто раньше из этих хелперов состояли DI сервисы.
·>Так куда эта паутина зависимостей делась? Замели под коврик?

Эта паутина, в данном конкретном случае, никогда никого не интересовала (и до сих пор не интересует). Как например и clr code проекта или как sql сервер парсит запросы и т.д. В этом мире прорва вещей детали которых здесь и сейчас абсолютно не важны.

IQ>>>>Ну и количество интерфейсов уменьшилось на 90%

IQ>>·>Десятый раз повторяю, что интерфейсы для DI+CI не нужны, да и рефакторинг тривиален. Ты их мог и так уменьшить, сохраняя управляемость зависимостей.
IQ>>Я тут запоздало сообразил, что не видел вашего варианта DI. Варианты с DI фреймворками понятны.
·>Вот же: http://rsdn.org/forum/design/6560633.flat#6560633
Автор: ·
Дата: 22.09.16

·>Более разжёвано почитай в том талмуде, который ты показывал, но, похоже, не ещё читал. Задавай вопросы, если что-то непонятно.
·>Спасибо, что ты наконец-то решил почитать что тут пишут.

Ну вы уж совсем меня за хейтера держите. О DI читал очень давно и сперва мне показалось, что из за ада с интерфейсами никто его использовать не будет. И так я думал до тех пор, пока меня не подключили к загибавшемуся проекту где бедолага программер просто утонул в зависимостях которые сам наплодил и конечно же он понятия не имел нафига они ему нужны в ядре бизнес логики, которое нужно исключительно для 1 проекта.

IQ>>Я глянул ваши ответы и не смог найти механизм, который будет в вашем случае создавать и хранить сервисы и инжектить их в клиенты.

·>Зачем хранить сервисы? Сразу создавай и связывай что как надо в composition root. Инжектятся они с помощью CI, десятый раз говорю.

Хотя бы раз назовите фреймворк, который используете. В composition root регистрируются сервисы с клиентами кто их связывает? Что такое CI (constructor injection)? Кто/что вам его предоставляет?
Отредактировано 30.09.2016 12:31 IQuerist . Предыдущая версия .
Re[20]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 30.09.16 14:32
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Плодить интерфейсы

IQ>·>Так плодит интерфейсы невежество, а не DI. В каком конкретно месте DI требует интерфейсов? Я даже уверен, что большинство IoC-фреймворков вполне могут без них обходиться.
IQ>Марк Симан невежество, не я сказал...
"Требовать" и "предлагать" — несколько разные вещи. Да, какие-то аспекты архитектуры требуют интерфейсов, но это не DI.

IQ>>>Любая, самая идеальная вещь может быть плохой там, где она лишняя.

IQ>·>Так отказывайся от ambient context. Он лишний же.
IQ>Он собственно появился по одной простой причине — сугубо синтаксическая группировка всех часто используемых сервисов. Его можно смело выкинуть и создавать все нужные сервисы с помощью new.
Хорошо, но уже лучше. Правильно, можно выкинуть. Осталось выделить все эти new в отдельный код, называемый composition root и получится DI здорового человека.

IQ>>> Вы думаете local context такой стойкий потому что разработчики ленивые? local context такой стойкий потому, что в него отлично ложатся контексты бизнес операций.

IQ>·>Нет, просто невежественные, перечитай топик — много народу тут отметилось которые вообще не знают что такое CI. Вот посмотри на код даже хорошего трудолюбивого студента — код плохой потому что у студента мало опыта и знаний, а не потому что код так лёг.
IQ>Имхо если мало знаний нефиг принимать серьезные решения.
Хм... Как мило.
Т.е. применить ambient context это несерьёзное решение:

Правильная реализация Ambient Context может оказаться непростой задачей.

а вот constructor injection это серьёзное решение:

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


IQ>>>Я не хвастаюсь. Просто раньше из этих хелперов состояли DI сервисы.

IQ>·>Так куда эта паутина зависимостей делась? Замели под коврик?
IQ>Эта паутина, в данном конкретном случае, никогда никого не интересовала (и до сих пор не интересует). Как например и clr code проекта или как sql сервер парсит запросы и т.д. В этом мире прорва вещей детали которых здесь и сейчас абсолютно не важны.
Правильно, зачем думать — прыгать надо.

IQ>·>Вот же: http://rsdn.org/forum/design/6560633.flat#6560633
Автор: ·
Дата: 22.09.16

IQ>·>Более разжёвано почитай в том талмуде, который ты показывал, но, похоже, не ещё читал. Задавай вопросы, если что-то непонятно.
IQ>·>Спасибо, что ты наконец-то решил почитать что тут пишут.
IQ> Ну вы уж совсем меня за хейтера держите. О DI читал очень давно и сперва мне показалось, что из за ада с интерфейсами никто его использовать не будет. И так я думал до тех пор, пока меня не подключили к загибавшемуся проекту где бедолага программер просто утонул в зависимостях которые сам наплодил и конечно же он понятия не имел нафига они ему нужны в ядре бизнес логики, которое нужно исключительно для 1 проекта.
Что ты читал? И где там написано, что интерфейсы обязательны?

IQ>>>Я глянул ваши ответы и не смог найти механизм, который будет в вашем случае создавать и хранить сервисы и инжектить их в клиенты.

IQ>·>Зачем хранить сервисы? Сразу создавай и связывай что как надо в composition root. Инжектятся они с помощью CI, десятый раз говорю.
IQ>Хотя бы раз назовите фреймворк, который используете.
Никакой, plain java.

IQ>В composition root регистрируются сервисы с клиентами кто их связывает?

В composition root никто не регистрируется, какие ещё сервисы-клиенты? Твой вопрос не имеет смысла, т.к.

A Composition Root is a (preferably) unique location in an application where modules are composed together.

Пример по ссылке выше, в конце сообщения.

IQ>Что такое CI (constructor injection)?

Передача зависимостей в конструктор объекта. Пример там же. Ну и в твоём талмуде.

IQ>Кто/что вам его предоставляет?

Java Language Specification.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 30.09.16 15:16
Оценка:
Здравствуйте, ·, Вы писали:

IQ>>В composition root регистрируются сервисы с клиентами кто их связывает?

·>В composition root никто не регистрируется, какие ещё сервисы-клиенты? Твой вопрос не имеет смысла, т.к.
·>

A Composition Root is a (preferably) unique location in an application where modules are composed together.

·>Пример по ссылке выше, в конце сообщения.

IQ>>Что такое CI (constructor injection)?

·>Передача зависимостей в конструктор объекта. Пример там же. Ну и в твоём талмуде.

Это не мой талмуд, это талмуд Марка Симана.

IQ>>Кто/что вам его предоставляет?

·>Java Language Specification.

Э... т.е. вы создаете все сервисы и все связи на старте приложения операцией new? И потом все их скопом передаете в какой-то диспечер бизнес логики, который их хранит и подставляет в вызовы бизнес операций?
Re[22]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 30.09.16 16:02
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>>Кто/что вам его предоставляет?

IQ>·>Java Language Specification.
IQ>Э... т.е. вы создаете все сервисы и все связи на старте приложения операцией new? И потом все их скопом передаете в какой-то диспечер бизнес логики, который их хранит и подставляет в вызовы бизнес операций?
Создаём. Непонятно — что такое диспечер бизнес-логики?
Может быть какой-то фреймворк для взаимодействия с внешним миром. В одном приложении далеко не всегда такой фреймворк единственный. там может и какой-нибуь messaging с UDP-сокетами, или субд api.
Скажем веб-сервер это такой фреймворк, который публикует какие-то объекты как доступные по некоему url. Вот например, классическое web-приложение с субд и Web Server (Jetty).
public static void main(String args[])
{
...
        DbConnection dbConnection = new DbConnection(connectionString);
        OurServiceHttpHandler ourServiceHttpHandler = new OurServiceHttpHandler(dbConnection);
...

        ContextHandler ourServiceContext = new ContextHandler("/ourService");
        ourServiceContext.setHandler(ourServiceHttpHandler);

        Server server = new Server(httpPortNumber);
        server.setHandler(ourServiceContext);

        // Start the server
        server.start();
        server.join();
}

Только это всё инфраструктура, а не бизнес-логика.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Отредактировано 30.09.2016 16:03 · . Предыдущая версия .
Re[23]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 05.10.16 12:29
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>>Кто/что вам его предоставляет?

IQ>>·>Java Language Specification.
IQ>>Э... т.е. вы создаете все сервисы и все связи на старте приложения операцией new? И потом все их скопом передаете в какой-то диспечер бизнес логики, который их хранит и подставляет в вызовы бизнес операций?
·>Создаём.

В общем и целом в финале выяснилось, что я сплошь и рядом использую constructor Dependency Injection да еще и с ambient context (пусть и самодельным), без DI фреймворков, ненужных интерфейсов и прочих code-перделок. Найду краткий материал, который наглядно это показал и впишу выводы в пост.

PS Интересный момент... Имхо DI без фреймворков, на моей памяти не провоцировал разработчиков делать сервис из любого мусора по любому поводу. Мусор закономерно отправлялся в хелперы где справедливо служил источником code smell.
Отредактировано 05.10.2016 12:35 IQuerist . Предыдущая версия .
Re[24]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 10.10.16 12:40
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>В общем и целом в финале выяснилось, что я сплошь и рядом использую constructor Dependency Injection да еще и с ambient context (пусть и самодельным), без DI фреймворков, ненужных интерфейсов и прочих code-перделок. Найду краткий материал, который наглядно это показал и впишу выводы в пост.


Обновил.
Re[25]: О "наивном" DI и об архитектурном бессилии
От: · Великобритания  
Дата: 10.10.16 22:18
Оценка:
Здравствуйте, IQuerist, Вы писали:

IQ>>В общем и целом в финале выяснилось, что я сплошь и рядом использую constructor Dependency Injection да еще и с ambient context (пусть и самодельным), без DI фреймворков, ненужных интерфейсов и прочих code-перделок. Найду краткий материал, который наглядно это показал и впишу выводы в пост.

IQ>Обновил.
Добро пожаловать в секту. Му-ха-ха!!!

А троллить ты первый начал со своей Colonoscopy Injection. Хотя... какой rsdn без троллинга...
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[26]: О "наивном" DI и об архитектурном бессилии
От: IQuerist Мухосранск  
Дата: 11.10.16 08:18
Оценка:
Здравствуйте, ·, Вы писали:

·>Здравствуйте, IQuerist, Вы писали:


IQ>>>В общем и целом в финале выяснилось, что я сплошь и рядом использую constructor Dependency Injection да еще и с ambient context (пусть и самодельным), без DI фреймворков, ненужных интерфейсов и прочих code-перделок. Найду краткий материал, который наглядно это показал и впишу выводы в пост.

IQ>>Обновил.
·>Добро пожаловать в секту. Му-ха-ха!!!

Не оказалось секта прячется в тени DI.

·>А троллить ты первый начал со своей Colonoscopy Injection.


И до сих пор считаю это определение годным конечно относительно стиля навязываемого DI фреймворками.
Отредактировано 11.10.2016 9:21 IQuerist . Предыдущая версия .
Re[6]: О "наивном" DI и об архитектурном бессилии
От: vdimas Россия  
Дата: 20.10.16 19:56
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>Видимо "параметр" звучит недостаточно солидно и паттерново


Это специфический параметр, за который можно дергать кого-то третьего. ))
Re[7]: О "наивном" DI и об архитектурном бессилии
От: Evgeny.Panasyuk Россия  
Дата: 20.10.16 20:26
Оценка:
Здравствуйте, vdimas, Вы писали:

EP>>Видимо "параметр" звучит недостаточно солидно и паттерново

V>Это специфический параметр, за который можно дергать кого-то третьего. ))

Callback жеж
Re[8]: О "наивном" DI и об архитектурном бессилии
От: vdimas Россия  
Дата: 21.10.16 06:58
Оценка:
Здравствуйте, Evgeny.Panasyuk, Вы писали:

EP>>>Видимо "параметр" звучит недостаточно солидно и паттерново

V>>Это специфический параметр, за который можно дергать кого-то третьего. ))
EP>Callback жеж

Тут терминология от философии конкретного этого места зависит.

Если внешний единичный колбэк (или целая группа их в виде абстрактного интерфейса) используется для оповещения третьих лиц о событиях, то это "распространение событий", эдакая "реактивность" и прочее.

А если этот колбэк или интерфейс используется для получения от третьих лиц неких данных или абстрактных объектов, то это уже DI.

Понятно, что техника и там и там одинакова — это вызов ф-ии по косвенному адресу (единичной или в составе интерфейса).
Re[4]: О "наивном" DI и об архитектурном бессилии
От: licedey  
Дата: 08.11.16 21:20
Оценка:
Здравствуйте, vsb, Вы писали:

vsb>Здравствуйте, IQuerist, Вы писали:


vsb>>>Так что вы предлагаете, учитывая, что тестировать надо? Я пока ничего лучше DI не видел.


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


vsb>Но ведь юнит-тестирование это стандарт-де факто в современном софтостроении. Писать софт без тестов это как пользоваться винраром для контроля версий.


Если речь только про юнит тесты, посмотрите в сторону Microsoft Fakes или аналогов. Из коробки дает доступ к приватным и статическим членам, гененрируя свой Мок-класс обертку.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.