Re: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 11.10.13 03:31
Оценка: 33 (5) +5 -1 :)
Здравствуйте, CEMb, Вы писали:

Если библиотека навязывает свою архитектуру — отказать.
Если библиотека мелкая и используется в паре мест — отказать.
Если библиотека реализует DI или прочий IoC — 99% отказать.

Если не противоречит вышесказанному, то 100% не отказывать, если:

— библиотека реализует специфичный функционал, с которым самому придётся долго разбираться, например, рендереры pdf/excel.
— своя реализация займёт человеко месяцо/годы.
— является общепринятым стандартом, знакомым подавляющему большинству разработчиков.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: Abalak США  
Дата: 22.10.13 20:12
Оценка: 135 (6) -1
Здравствуйте, Dziman, Вы писали:

D>Можно пример проблемы именно из-за DI?


Легко. Вот пилю сейчас часть проекта, где запихнули MEF куда только можно. Решил попользовать готовый объект, часть ДАЛа, что б не городить велосипед самому. Пишу как положено — new бла-бла-бла. Вроде все создается и даже работает. Потом хочу дернуть нужное свойство и бац все падает в рантайме. Начинаю копать код, а там оказывается куча непубличных полей, которые инициализируются через рефлекшн МЕФом и которые никак по другому не проинициализировать, а тащить весь контекст приложения, туда где он не нужен — зло. Понятно, проблема не напрямую в DI, а в дизайне, но такие дизайны сплошь и рядом. Хотя по рукам надо бить и MS, которая такие финты позволяет. Возникают сложности там где не нужно, в итоге нормальной с первого взгляда объект можно использовать без лишнего геммороя только в единственном месте, там где это задумал мегаархитектор.
Re: своё vs. сторонее
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 12.10.13 08:33
Оценка: 86 (4) +2 -1
Здравствуйте, CEMb, Вы писали:

CEM>Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?


В современном мире программного обеспечения (где все тысячи раз переписано сначала для мейнфреймов, потом для PC, потом для облаков etc.) написать свой толковый и быстро работающий велосипед _с нуля_ невозможно. Сначала всегда требуется детально изучить существующие аналоги, понять их преимущества и недостатки. И только окончательно убедившись в том, что недостатков больше и что они критичны для бизнеса, кидаться радостно кодить свое.
Торвальдс сначала помучился с Minix, и только потом стал писать свою ОС. Амазон сначала уперлась во все мыслимые и немыслимые ограничения промышленных СУБД и файловых систем, только потом написала свои сервисы хранения данных и только еще более потом вывела их в онлайн.

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

Далее наступает этап тестирования, на котором часть выбранных компонентов может быть отсеяна и заменена/переписана. Наконец, проект выходит в продакшн, в процессе жизни которого еще какая-то часть компонентов признается не выдерживающей критики и заменяется/переписывается (заметьте: проект уже в продакшене и приносит деньги!).

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

Как-то так.
Re: своё vs. сторонее
От: smallpoxlet Ниоткуда  
Дата: 14.10.13 09:50
Оценка: 43 (5)
Здравствуйте, CEMb, Вы писали:

CEM>по мотивам этого поста
Автор: Vzhyk
Дата: 09.10.13
отдельно

CEM>захотелось обсудить как раз идею использования сторонних библиотек и написания
CEM>на их основе своего кода.

CEM>Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?


У нас в компании принята политика выбора библиотек.
1. Обязательно open source под либеральной лицензией (GPL идет лесом сразу, проприетарщина допустима только при наличии саппорт контракта не менее чем на срок жизни проекта с прибитым гвоздями SLA или при наличии исходников)
2. Библиотека в обязательном порядке проходит acceptance review при котором проверяется качество кода, вменяемость разработчика, политику патчей, активность комьюнити, покрытие тестами, систему сборки и т.п. По результатам AR может быть три вердикта: "в топку", "берем" и "берем под свою ответственность". Последнее означает что мы посылаем разработчика в пень и форкаем проект в свою инфрастркутуру, налаживаем систему сборки, тестирование и т.п. В некоторых проектах наши люди становятся основными контрибуторами и эти проекты фактически переходят под наш контроль.
3. Если библиотека признана годной, то она проходит compatibility review на котором проверяется насколько архитектура библиотеки совместима с нашими проектами. Часто при этом пишутся тесты на типичные сценарии из наших проектов. Обычно этим занимаются интерны/джуниоры под наблюдением старших. Если уж они способны справится с библиотекой, то и нормальные разработчики смогут.
4. Если оба ревью пройдены библиотека считается разрешенной к использованию. Библиотеке назначается внутренний мейнтейнер который собирает ее в пакет, следит за обновлениями, отправляет патчи, общается в списках рассылки, рекомендует или наоборот запрещает переход на новые версии. Как правило этим занимается тот же человек что проводил AR, но иногда на эту роль мы берем на контракт разработчика библиотеки.

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

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

Для статистики: протокол прошли >100 библиотек из них разрешены к использованию 32 из них активно используются 12. Включены в инфраструктуру компании и опубликованы — 5.
Дислексия — чума XXI века
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 13.10.13 23:40
Оценка: 21 (1) +4
Здравствуйте, Dziman, Вы писали:

D>Мне кажется вы рассматриваете не ту проблему: DI — это построение графа объектов, а в приведенном примере проблема не в том как построен граф, а как взаимодействуют объекты графа.


DI &mdash; это 25-ти доллоровый термин для 5-ти центовой концепции. Я вообще не понимаю чего с ним так все носятся. Складывается такое впечатление, что DI — это некий верхний предел познания для большинства. Тот кто познал DI прётся от этого необычайно. Хотя даже концепцией это назвать можно с натяжкой. Так себе, не самый лучший паттерн, от которого проблемы возникают сразу и по всему коду, а что он даёт ценного внятно не может объяснить ни один из его апологетов.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 13.10.13 17:28
Оценка: 7 (1) +3
Здравствуйте, Dziman, Вы писали:

IT>> Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.


D>А конкретней? Ну т.е. DI не панацея как и любое общее решение, но ты-то как бы обобщаешь, что DI всегда ерунда.


DI всегда привносит дополнительную сложность в проект, впрочем как и любой другой инструмент. Но компенсировать эту сложность удаётся далеко не всегда и не всем. В этом смысле да, я обобщаю. И главным в том топике, да и в этом тоже, для меня была попытка понять как можно компенсировать ту сложность, которую даёт DI. Ответа я не услышал. Зато много раз услышал "ты не понимаешь"

IT>> Doc>Для избавления от жестких зависимостей и в случаях когда конкретные реализации не известны на момент написания кода как ответы не подходят?


D>Очень никакой пример: тут можно сделать что и так и этак 'правильно'


Этот пример показывает способ избавления от жестких зависимостей. DI такое и не снилось в самых радужных снах.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[19]: своё vs. сторонее
От: fddima  
Дата: 25.10.13 21:16
Оценка: 22 (1) +2
Здравствуйте, ., Вы писали:

Ребята. Если вы не авторы PaypalCreditCardProcessor — то вам нефиг его тестить.
Если вы хоть кто-нибудь хоть когда-нибудь сталкивались с разработкой процессинга этих самых платежных карт — то вся ветка кажется смешной.
Если хочется написать стаб на него — это пожалуйста, только прийдётся перед этим хорошенько изучить реальный сервис, как он работает — иначе стаб будет врать. Кроме того, наличие тестов на стабах не отменяет тестов на тестовых окружениях. При чём up to 6 levels.
Как тут рядом IT — говорил — не то тестируете. Ну или не то обсуждаете. Мне лично пофигу, насколько процессор хорошо умеет посылать куда-нибудь запросы. Но мне жутко не пофигу, что комплекс отвечает бизнес требованиям. Особенно смешно это всё выглядит в купе с пробегавшим рядом примером с DateTime.Now, когда реально необходимо обрабатывать (откатывать) ну... переведя на простонародное холды, через десять дней, с учётом таблиц роутинга и кучи другой прочей херни, которая должна быть учтена именно временем транзации. DateTime.Now — это точно хрень, нет нигде такого. Ну а если вспомнить о offile/batch-процессинге документов — то now и так параметр как ни крути.
Всё вышесказанное не опровергает необходимость DI, но только лично в моей практике — это всё хрень. DI или не DI. Хотите реально протестировать скажем так CardProcessing, то вам прийдётся всегда иметь что-нибудь из этого, или всё сразу:
а) вам прийдётся общаться с ним чуть ли не на терминальном уровне
б) вам прийдётся иметь таки реальный процессинг и общаться с ним (и вас всегда ожидает эта стадия, т.к. реальные FI всегда это будут требовать)
в) для "долгоиграющих запросов", на подобии режекта холда — как-то это надо учитывать, ваши стубики тут ничем не помогут
г) вэлком в реальный мир. DI — нихера не помогает в тестировании.

PS: Как с эмулировать CardProcessing без DI? Слышал ли кто-нибудь о socket или http listener?
Re[3]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 12.10.13 05:34
Оценка: +2 :)
Здравствуйте, Doc, Вы писали:

IT>>Если библиотека реализует DI или прочий IoC — 99% отказать.


Doc>Это как


DI от лукавого. Мне тут в соседней ветке пытались объяснить что такого даёт DI, очень долго пытались, но так и не смогли.

Замечу, что я в курсе определний из педевикии, но мой вопрой именно про "зачем". Ну и аргументы типа "да ты не понимаешь" меня тоже как бы не особо устраивают.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[5]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 00:40
Оценка: +3
Здравствуйте, koodeer, Вы писали:

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


Это назвается job security. Манагерам и студентам надо понять одну простую вещь. Наличие в проекте DI — это очень чёткий признак over-design приложения. В 9 из 10 приложений DI нафиг не нужен, в том числе и для тестирования. Просто те, кто им начинает увлекаться уже по другому задизайнить приложение не в состоянии. Жалко их, людей с искалеченной DI судьбой.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[17]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 03:30
Оценка: +3
Здравствуйте, Doc, Вы писали:

Doc>Ты перенес её в другой класс приложения.


Я её не переносил, она там, где и должна быть. Ты слишком однобоко понимаешь применение инструментов. DI — это не только ценный мех, цена которого, кстати, 0.5 по 10-ти бальной шкале. Это ещё и привнесённая в приложение сложность и эта сложность на порядок больше пользы.

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


Нет, жидким слоем, это не про зависимости, это про логику. Вот смотришь на такие погрызенные DI-ем методы и думашеь, что же они делают? За деревьями леса не видно. Одни, мля, какие-то левые сервисы дёргаются.

Doc>С IoC не пришлось бы вызывающим классам знакомиться с _service.


В случае с DI с ними вообще трудно познакомиться. Даже разработчику. Захочешь, хрен найдёшь.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: своё vs. сторонее
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 30.11.13 06:16
Оценка: -1 :))
Здравствуйте, CEMb, Вы писали:

CEM>по мотивам этого поста
Автор: Vzhyk
Дата: 09.10.13
отдельно

CEM>захотелось обсудить как раз идею использования сторонних библиотек и написания
CEM>на их основе своего кода.

О наболевшем?

С одной стороны — "все самому написать просто нереально". Это я еще в 99 понял.

А с другой — в последнее время (у меня) не получается украсть позаимствовать даже элементарные вещи.

Я уже не говорю о том, чтобы взять что-то чужое готовое и встроить в свой код. Без бубна и танцев. Тут со своим иногда напляшешься.

Два года назад начал писать на C#. Кругом тонны кода. Казалось бы — изобретать уже ничего не надо. А вот хрена лысого. Хорошо перед этим я внимательно прочитал Рихтера. И там (буквально в трех строчках) была прописана истина — по-человечески никто под .NET не пишет

В итоге — пришлось все изобретать с нуля. Может поэтому удалось добраться до финиша. И, глядя на код, не возникает желание переписать его.

Так что — "все сам, все сам, своими руками"

Но самое забавное — результат всей деятельности продается другим "программистам". Иногда встречаются даже без кавычек — с такими интересно работать
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[12]: своё vs. сторонее
От: Baudolino  
Дата: 23.10.13 09:17
Оценка: 11 (2)
IT>Я уже устал об этом говорить. DI ломает навигацию по проекту
В 2003 году? В 2013 не ломает, если вы используете правильные инструменты (при программировании в блокноте, согласен, навигация никакая, даже без DI).

IT>Бизнес логика разбивается на части и разносится по разным частям приложения.

Это проблема не DI, а криворукого архитектора. Мне понятна ваша боль по поводу говнокода, однако вы ошибочно ее приписываете не тому адресату. Если человеку религия не позволяет писать new в проекте с DI, отказ от DI проблему не решит, потому что упоротые псевдоархитекторы всегда найдут, чем заморочиться. Они напишут свой DI на self-managed singletons, с разливным пивом, рефлексией и марусями, накидают сотню фабрик и адаптеров, конфигурируемых в XML, просто потому, что не освоили ООП перед чтением GoF. Но это не проблема библиотек, это проблема общего дефицита кадров в нашей индустрии и некомпетентности сениоров и архитектов, получивших свою позицию, в лучшем случае, по выслуге лет, а то и просто потому, что за пару лет после выпуска из института успели пройти по верхам десяток фреймворков. Применять NIH-подход и отказываться от лучших практик отрасли только поэтому — это лишь ухудшать ситуацию.

IT>Это затрудняет модификацию приложения.

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

IT>А всегда ли это нужно?

В проекте объемом больше пары десятков тысяч строк — да, уже имеет смысл. На всяких мелких — не обязательно, но по рельсам паровоз обычно едет лучше, чем по говну.
Re[10]: своё vs. сторонее
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 16.10.13 20:05
Оценка: 4 (2)
Здравствуйте, IT, Вы писали:

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


Согласен полностью и не могу не поделиться.

Имею вот щас на руках проект. Сервис обрабатывает разнообразные сообщения. DI доведен до абсурда. Ну т.е. вот буквально была поставлена цель — ни одного оператора new в коде. И казалось бы, оно имеет смысл — messaging же!

По принципу: обработчик резолвится через DI, получает в свой конструктор толпу объектов из DI, те, в свою очередь, тоже получают в свои конструкторы что-то из DI и т.д.

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

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

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

Повысили, в общем, тестируемость кода, ага.
Re: своё vs. сторонее
От: Vzhyk  
Дата: 10.10.13 17:46
Оценка: +2
Здравствуйте, CEMb, Вы писали:

CEM>Точнее, как принимать решение об использовании сторонних библиотек vs. написания своего кода.

Всегда использую сторонние, если это возможно и только если не подходят делаю свой велосипед.
Чтобы определить, что подходят делаю набор тестов, что мне нужны и удовлетворяю их с помощью сторонней библиотеки. Если библиотека не удовлетворяет меня по ~40% тестов, ищу другую, иначе пишу сам.
Re[5]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 12.10.13 22:57
Оценка: -1 :)
Здравствуйте, Doc, Вы писали:

IT>>DI от лукавого. Мне тут в соседней ветке пытались объяснить что такого даёт DI, очень долго пытались, но так и не смогли.

Doc>И какая альтернатива используется? new?

Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.

IT>>Замечу, что я в курсе определний из педевикии, но мой вопрой именно про "зачем".

Doc>Для избавления от жестких зависимостей и в случаях когда конкретные реализации не известны на момент написания кода как ответы не подходят?

Пример из того же типика:

void MyVeryPrimitiveMethod()
{
    var value1 = _service1.GetValue1();
    var value2 = _service2.GetValue2();

    var result = value1 * value2;

    _service3.SetResult(result);
}

И это всё вместо:

int MyVeryPrimitiveMethod(int value1, int value2)
{
    return value1 * value2;
}

Как по-твоему где больше зависимостей?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[6]: своё vs. сторонее
От: Dziman США http://github.com/Dziman
Дата: 12.10.13 23:24
Оценка: +1 -1
Здравствуйте, IT, Вы писали:

IT> IT>>DI от лукавого. Мне тут в соседней ветке пытались объяснить что такого даёт DI, очень долго пытались, но так и не смогли.


IT> Doc>И какая альтернатива используется? new?


IT> Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.


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

IT> IT>>Замечу, что я в курсе определний из педевикии, но мой вопрой именно про "зачем".


IT> Doc>Для избавления от жестких зависимостей и в случаях когда конкретные реализации не известны на момент написания кода как ответы не подходят?


IT> Пример из того же типика:


IT>
IT> void MyVeryPrimitiveMethod()
IT> {
IT>     var value1 = _service1.GetValue1();
IT>     var value2 = _service2.GetValue2();

IT>     var result = value1 * value2;

IT>     _service3.SetResult(result);
IT> }
IT>

IT> И это всё вместо:

IT>
IT> int MyVeryPrimitiveMethod(int value1, int value2)
IT> {
IT>     return value1 * value2;
IT> }
IT>

IT> Как по-твоему где больше зависимостей?

Очень никакой пример: тут можно сделать что и так и этак 'правильно'
avalon 1.0rc3 build 430, zlib 1.2.5
Re[7]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 13.10.13 17:43
Оценка: +2
Здравствуйте, Doc, Вы писали:

Doc>По сути согласен с уже высказанным рядом мнением — DI не панацея, более того не в каждый тем более готовый проект его легко прикрутить.


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

Doc>То что зависимость вынесена в вызывающий класс, не значит что ее нет. Да, у класса, кусок кода которого показан, стало меньше зависимостей. Зато другой класс (и возможно не один) теперь должны знать где брать value1 и value2.


И в чём проблема?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: своё vs. сторонее
От: Mr.Delphist  
Дата: 14.10.13 10:05
Оценка: +1 -1
Здравствуйте, IT, Вы писали:

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


IT>>> Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.


D>>А конкретней? Ну т.е. DI не панацея как и любое общее решение, но ты-то как бы обобщаешь, что DI всегда ерунда.


IT>DI всегда привносит дополнительную сложность в проект, впрочем как и любой другой инструмент. Но компенсировать эту сложность удаётся далеко не всегда и не всем. В этом смысле да, я обобщаю. И главным в том топике, да и в этом тоже, для меня была попытка понять как можно компенсировать ту сложность, которую даёт DI. Ответа я не услышал. Зато много раз услышал "ты не понимаешь"


Если DI даёт сложность — то да, это неправильный DI. Или неподходящая архитектура (да, все мы грешили в своё время MyClass.getInstance()-рукоблудием)

IT>>> Doc>Для избавления от жестких зависимостей и в случаях когда конкретные реализации не известны на момент написания кода как ответы не подходят?


D>>Очень никакой пример: тут можно сделать что и так и этак 'правильно'


IT>Этот пример показывает способ избавления от жестких зависимостей. DI такое и не снилось в самых радужных снах.


Похоже, действительно "Вы не понимаете"
Что такое сервисы 1 и 2? откуда они и кто их создаёт?
Кто вбрасывает первое и второе значения в MyVeryPrimitiveMethod()? возможны ли иные кроме перемножения варианты вычислений?

Ответы на эти вопросы и определяют, надо ли "депенденсиинжектировать" данный кусок кода. Если же DI применено по уму, то
1) упрощается тестирование, т.к. легко можно собрать каждый компонент системы с разными моками вместо прочих компонентов и прогнать хоть интеграционные, хоть нагрузочные, хоть ещё какие тесты
2) упрощается конфигурирование, т.к. можно менять поведение системы "на лету" без перекомпиляции (и редеплоя, что очень важно для всяких энтерпрайзов)
Re[15]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 00:30
Оценка: +1 -1
Здравствуйте, Doc, Вы писали:

IT>>Дай и я угадаю, в твоей луковице десятки классов выше.

Doc>Не понял вопрос. Если про общее число классов, то да. Если про глубину вызовов, то нет.

Ну а если нет, то в чём проблема?

IT>>Ты пишешшь библиотеки, состоящие из одного класса на одну строчку функциональности?

Doc>Если надо по архитектуре приложения, то ничего страшного не вижу. Но только не "класс ради класса".

Я могу тебе ответить тоже самое на твой вопрос.

IT>>Вообще-то ещё существуют делегаты, интерфейсы (да, да, интерфейсы можно использовать не только для сервисов!)


Doc>Ух ты, method injection ? Все же используешь DI?


Вот! То о чём я и говорю. Больные люди! Им везде мерещится DI.

Doc>Но в примере ты все равно от зависимости не избавился. Да, перенес её в другой класс, но и там её надо как-то разруливать.


И что? Я убрал нежелательную зависимость? Убрал. Да ещё так убрал, как DI и не снилось. А твой DI — это переливание из пустого в порожнее. Из одного места убираем, в другое добавляем, в треьем размазываем жидким слоем.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re: сторонее? да ни за что
От: Аноним  
Дата: 23.10.13 11:51
Оценка: +2
Здравствуйте, CEMb, Вы писали:

CEM>Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?


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

Так что теперь избегаю использовать сторонние библиотеки без крайней необходимости. Сначала пытаюсь сделать сам, если вижу, что уйдет много времени — только тогда ищу готовую библиотеку.
Re[15]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 25.10.13 17:41
Оценка: +2
Здравствуйте, Baudolino, Вы писали:

IT>>Если очень хочется пообсуждать криворукость архитектуры и архитекторов, то достаточно показать здесь свой наиправильнейший код. Или слабо?

B>Это аргумент из серии "сперва добейся"? Ну-ну. Я связан NDA с нынешним и бывшими своими работодателями. Хочешь посмотреть мой код — устройся для начала ко мне на работу.

Понятно. Стандартная отмазка. Впрочем, не очень то и хотелось ни твоего кода, ни уж тем более к тебе на работу.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 18:24
Оценка: 6 (1)
Здравствуйте, Ikemefula, Вы писали:

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


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


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

I>Вобщем, после таких слов для тебя самый удобный вариант это : "Заканчиваю троллить, иду работать"


Вас очень сложно тролить. На любое моё "покажите код" у вас один ответ — "ты не понимаешь".
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 20:04
Оценка: 6 (1)
Здравствуйте, IT, Вы писали:

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


IT>Ты видимо прочитал лишь то, что хотел. Это бывает. Объясняю ещё раз. В случае DI объект получает не весь необходимый контекст, а вообще всё, что можно.


Если объект тащит все что можно, то он и получит все что надо.

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


У тебя одна строчка и сразу целый вагон всего Я пока на своем примере покажу, ты все равно ничего путного пока не привел

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

Есть проблема, вот эти самые Find Usages, если базовй метод используется очень часто, то поиск по ём ничего не даст, надо искать ссылки на интерфейс и анализировать использование этих ссылок. Здесь проблема с привидением интерфейса к базовым типам.

требуется отчуждение кода от системы

Сложность отчуждения в зависимости от
A. количества депенденсов. Если компонент требует вагон депенденсов, то отчуждение это боль и DI не поможет, т.к. проблема в большом количестве депенденсов.
SRP не помогает, тупо вместо одного компонента станет пачка, но вся эта пачка будет тащить суммарно все те же депенденсы, что и большой компонент.
B. Управления депенденсами. Если депенденсы оформлены явно и нет всевозможных прямых ссылок, ссылок на God Object, Dependency Pack, Context with All dependencies, то отчуждение довольно простое, при условии что компонент заточен под DI.

При чем, п.A дает сильно нелинейную зависимость. Скажем, я в своем примере совершенно не представляю как можно отчуждать компоненты вроде OpenDocumentCommand. Скажем, простейший воркфлоу такой:
0. закрыть текущий документ — депенденс на соответствующую команду, DI
1. найти пекадж, раззиповать, определить формат и версию — целых три депенденса, тащится напрямую
2. проверить лицензию — тоже депенденсы, DI
3. провалидировать кое какие свойтсва , значть открыть часть данных — еще около трех депенденсов, все DI
4. показать форму для недостающих пропертей — депенденс на форму — DI
5. вычислить недостающие вычислимые проперти — депенденс на сервис который выполнит эту операцию по конкретному конфигу DI
6. загрузить сам пекадж — собственно депенденсы в зависимости от формата, загрузчик, все руками напрямую
7. добавить документ в MRU — депенденсы на модель приложения
8. Вся хрень делается в фоне, стало быть депенденсы на бекграунд воркер, который умеет с прогресом работать. Операцию можно откатить- есть депенденсы соответсвующие. Эта хрень захардкожена, ибо так проще, все под рукой.

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

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

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

при его рефакторингах и модификациях,
Сложность рефакторинга и модификации зависит от
1 количества и качества депенденсов.
2 количества и качества обязанностей

Лично я отчуждаемый код делаю не иначе как с помощью обрезания депенденсов. Без этого компоненты можно отчуждать только наполовину, для использования в родственном проекте.
Правда часто случается так, что после обрезания депенденсов ничего не остаётся. Там, где для задачи требуется вагон депенденсов совершенно не ясно что делать.
DI может помочь с диспетчеризацией, но отчуждение все равно будет АДъ и Израиль.

Здесь нужен конкретный пример от тебя, правда я не уверен, что смогу быстро вникнуть в твою проблему, у меня пока что нет скилов решать любые проблемы за время написания сообщения на форуме


I>>Вобщем, после таких слов для тебя самый удобный вариант это : "Заканчиваю троллить, иду работать"


IT>Вас очень сложно тролить. На любое моё "покажите код" у вас один ответ — "ты не понимаешь".


Я ж показал код Ссылку на репозиторий тебе дать чтоли ?
Re[13]: своё vs. сторонее
От: Abalak США  
Дата: 23.10.13 15:00
Оценка: 4 (1)
Здравствуйте, ., Вы писали:

.>И причём тут архитектура? Так, синтаксис немного неудобный для кривого использования.


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

.>Если тебе так хочется использовать new и религия не позволяет использовать IoC-контейнер, то можно слегка отрефакторить: переделать field injection в constructor injection (и это правильно), в общем всё. Или даже просто объявить поля публичными, чтобы насладиться ручным DI.


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

Проблему я конечно же решил в течении пары часов, просто дополнил контсруктор инициализацией нужных полей и добавил в код несколько проверок. Я просто хотел показать и ответить на вопрос, что вот она конкретная проблема, вызванная чрезмерной увлеченностью DI. А был бы на моем месте другой, точно бы нагородил кучу нечитаемого кода, но сделал бы все по паттернам.
Re: своё vs. сторонее
От: Sharowarsheg  
Дата: 13.10.13 17:50
Оценка: -1
Здравствуйте, CEMb, Вы писали:

CEM>Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?


Стараюсь писать своё. Оно обычно получается практически довольно быстро, пригодного качества, и можно исправлять, если сломается. Сторонние компоненты прекрасны, пока не сломаются, после чего отладке не поддаются.
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 13:44
Оценка: :)
Здравствуйте, Mr.Delphist, Вы писали:

MD>Если DI даёт сложность — то да, это неправильный DI.


DI даёт сложность всегда и без всяких если.

MD>Похоже, действительно "Вы не понимаете"


Ага. Началось.

MD>1) упрощается тестирование, т.к. легко можно собрать каждый компонент системы с разными моками вместо прочих компонентов и прогнать хоть интеграционные, хоть нагрузочные, хоть ещё какие тесты


Предыдущим товарищам было предложено упростить тестирование в конкретном проекте с помощью DI. Не смогли

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


В случае отсутствия DI отсутствует и всякое конфигурирование. Как можно упростить то, чего нет?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 14:40
Оценка: +1
Здравствуйте, Dziman, Вы писали:

D>Можно пример проблемы именно из-за DI?


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

IT>> а что он даёт ценного внятно не может объяснить ни один из его апологетов.

D>Decoupling

А всегда ли это нужно?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 14:51
Оценка: :)
Здравствуйте, Doc, Вы писали:

Doc>Как видим, зависимость никуда не делась, ибо value1 и value2 откуда-то должны браться.


Это уже проблема вызывающего класса. У обсуждаемого класса зависимостей нет вообще.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 00:50
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

G>Нужно понимать что все методы, не примитивные, из одной строчки. Каждый их них потенциально может лезть в БД, использовать параметры и другие "сервисы" приложения. Тут DI начинает очень сильно помогать.


Если очень захотеть, то DI можно впихнуть куда угодно. Это не проблема. Только в твоём примере такой необходимости нет ни в одном месте. Валидация — это часть логики, какой-то тут DI? Юзер проверяется атрибутами, как правило доступен в контексте или обрабатвается более сложными способами вроде фильтрации данных SQL запросами, что фактически является частью безнес логики. Кеширование тоже лучше всего делается атрибутами, ну или простейшим хелпером на худой конец.

G>Кроме того, для улучшения unit-тестирования самого Method1 можно часть вызываемых функций тоже подсовывать через DI. Другая часть функций может быть вынесена вне методов обработки запросов и внезапно такой AoP тоже реализуется через DI.


Я же говорю, запихать можно куда угодно. Только надо ли?

G>В итоге DI помогает собирать приложения по кусочкам, концентрируясь при этом на самих кусочках, а не на сборке.


В собранном по кусочкам приложении невозможно разобраться. Зачастую, что бы понять его логику нужно запускать его под отладчиком. В общем, я уже устал это повторять. DI — это сломанная навигация по коду и логика, размазанная жидким поносом по всему приложению. Как правило от таких приложений смердит за версту и всякими другими архитектурными излишествами.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 15:06
Оценка: +1
Здравствуйте, gandjustas, Вы писали:

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

G>Необходимости в DI вообще никогда нет. Любой код может быть написан без DI. Но альтернатива в виде ball-of-mud архитектуры зачастую хуже, чем DI на каждый чих. Можно конечно писать слабосвязный код и без DI, но там мало кто умеет.

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

G>Если у тебя есть решарпер, то не проблема. Я уже и без решарпера научился разбирать сильно DI код.


Это не более чем умение ходить на ходулях по граблям. Зачем мне это, если без этого можно обойтись?

IT>>Как правило от таких приложений смердит за версту и всякими другими архитектурными излишествами.

G>Я такого и без DI видел много раз.

Зато такого как с DI я не видел нигде.
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.10.13 20:07
Оценка: +1
Здравствуйте, IT, Вы писали:

IT>Здесь:


IT>
IT>  var n = MyVeryPrimitiveMethod(1, 2);
IT>


Это больше на фобию похоже.
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 01:37
Оценка: +1
Здравствуйте, Dziman, Вы писали:

D>Я вот не могу понять это троллинг или что-то еще? Если 1 и 2 это константы то там DI делать нечего, но если эти значения приходят 'извне', то рано или поздно надо будет сделать getParam1 и getParam2. И там есть вероятность, что DI пригодится.


Может быть пригодится, а может быть скорее всего нет. Почему-то все понимают, что преждевременная оптимизация — это плохо, но решительно не понимают, что преждевременный дизайн — ещё хуже.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 18.10.13 01:24
Оценка: +1
Здравствуйте, Ikemefula, Вы писали:

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

I>Вобщем, после таких слов для тебя самый удобный вариант это : "Заканчиваю троллить, иду работать"

Что-то мне подсказывает, что под DI он понимает Service Locator. То да, тогда будет все как он пишет — и проброс всего и вся внутрь, и муторные попытки понять что именно требует тот или иной класс.
Re[14]: своё vs. сторонее
От: Baudolino  
Дата: 25.10.13 14:32
Оценка: :)
Здравствуйте, IT, Вы писали:

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


IT>>>Я уже устал об этом говорить. DI ломает навигацию по проекту

B>>В 2003 году? В 2013 не ломает, если вы используете правильные инструменты (при программировании в блокноте, согласен, навигация никакая, даже без DI).
IT>Сколько пафоса! Можно подумать ты пишешь программы с помощью мысленного инструмента, а не с помощью клавиатуры.
Интересно, каким образом здесь появилось слово "мысленный" и какое отношение к навигации по проекту имеет клавиатура?

IT>Если очень хочется пообсуждать криворукость архитектуры и архитекторов, то достаточно показать здесь свой наиправильнейший код. Или слабо?

Это аргумент из серии "сперва добейся"? Ну-ну. Я связан NDA с нынешним и бывшими своими работодателями. Хочешь посмотреть мой код — устройся для начала ко мне на работу.

IT>>>А всегда ли это нужно?

B>>В проекте объемом больше пары десятков тысяч строк — да, уже имеет смысл. На всяких мелких — не обязательно, но по рельсам паровоз обычно едет лучше, чем по говну.
IT>Ничего не понял Какой паровоз...
Это метафора, намекающая на то, что в небольших проектах DI тоже может быть полезным, позволяя сфокусироваться на бизнес-логике и не тратить время на инфраструктуру.
Re: своё vs. сторонее
От: Аноним  
Дата: 10.12.13 23:40
Оценка: :)
Здравствуйте, CEMb, Вы писали:

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

А потом случилось так, что меня назначили менеджером проекта, а из нашего проекта захотели сделать SDK. И тут, неожиданно для себя, я увидел, что самописность дает однозначное преимущество в виде отсутствия зависимостей от сторонних библиотек. Более того, один из будущих заказчиков (известная крупная компания) прямо сказал, что не будет использовать наш SDK, если он будет зависеть от той библиотеки, на которую мы было собирались перейти. Также я обнаружил, что с позиции менеджера все несколько по-другому выглядит, чем с позиции разработчика. В итоге железно решили никуда не переходить, а оставить самописное, благо, что все и так уже в основном было разработано.

Такие дела. Мораль можете вывести сами.
Re: своё vs. сторонее
От: minorlogic Украина  
Дата: 15.12.13 13:18
Оценка: +1
Здравствуйте, CEMb, Вы писали:


CEM>Сам я обычно стараюсь ничего стороннего не брать, потому что:

CEM>минусы:
CEM>0. чужие баги, тормоза, ограниченность функционала. и всё в самый неподходящий момент. Медленная тех.поддержка.

Т.е. свои баги не так ранят душу? Обратите внимание что беря качественную билиотеку мы существенно сокращаем шанс багов , ибо протестирована на порядок лучше.

CEM>1. надо изучать возможности библиотеки. Как правило, несколько библиотек, чтобы выбрать.


Это в любом случае быстрее чем писать свое, априори.

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


Не всегда , это сильно зависит от быбраной библиотеки.

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


Опять же зависит от библиотеки.

CEM>4. лицензии. Если это платное, то можно в любой момент ждать что-нибудь новенькое от авторов (2 раза было на моей памяти)

CEM>плюсы своего кода:

см. выше.


CEM>0. свой код быстро модифицируется под новые нужды

Странное магическое свойство кода . Да и зачем модифицировать если либа хорошая ?

CEM>1. опыт написания своих компонентов

CEM>2. опыт разработки архитектуры всяких мини-платформ

Звучит не серьезно.

CEM>ну и вообще, со временем появляется навык быстрого определения объёма работы в обоих случаях, что в разы облегчает жизнь


Проблемы с лицензией, иначе надо разрабатывать либы отдельно от работы .


CEM>Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?


Практической целесообразностью.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[17]: своё vs. сторонее
От: minorlogic Украина  
Дата: 15.12.13 21:24
Оценка: +1
Здравствуйте, <Аноним>, Вы писали:

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


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


.>>>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.

M>>Пример по ссылке вообще является феерическим звездецом.
А>Выделенное главное. Остальное — неинтересная критика.

Простейший и очевидный вариант
  Receipt chargeOrder(CreditCardProcessor processor, TransactionLog transactionLog, PizzaOrder order, CreditCard creditCard);


M>>1. Функция stateless которая делает примитивные действия , реализуется через класс.

А>Не примитивные действия, а бизнес-логику. Опять же. Смотри выделенное.

Издеваешься? Может лучше назвать позаковырестее, и оно поменяет смысл?

M>>2. Половина данных передается как мемберы , половина как параметры вызова. WTF ???

А>Данные как параметры вызова. Сервисы обработки данных — инжектятся.

Вот тут я рекомендую подучить классику типа "Совершенный код", и войти в контекст "stateless функция"

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

А>Каких данных?

CreditCardProcessor processor, TransactionLog transactionLog если это не очевидно.


Хамство поскипано.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
своё vs. сторонее
От: CEMb  
Дата: 10.10.13 17:36
Оценка:
по мотивам этого поста
Автор: Vzhyk
Дата: 09.10.13
отдельно
захотелось обсудить как раз идею использования сторонних библиотек и написания
на их основе своего кода.

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

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

Там, где я работаю, стараются брать сторонние библиотеки, потому что:
плюсы:
0. выше уровень разработки.
1. платформа обкатана, есть документация, форумы, поддержка
2. опыт в разработке на этой платформе
минусы своего кода:
0. долго
1. требуется отладка написанного

Сам я обычно стараюсь ничего стороннего не брать, потому что:
минусы:
0. чужие баги, тормоза, ограниченность функционала. и всё в самый неподходящий момент. Медленная тех.поддержка.
1. надо изучать возможности библиотеки. Как правило, несколько библиотек, чтобы выбрать.
2. надо изучать много чужого кода, примеров, чтобы понять, подходит это или нет. Писать тесты.
3. инсталляторы, тяжёлые библиотеки, из которых используется меньше половины, несовместимость, неактуальность и так далее
4. лицензии. Если это платное, то можно в любой момент ждать что-нибудь новенькое от авторов (2 раза было на моей памяти)
плюсы своего кода:
0. свой код быстро модифицируется под новые нужды
1. опыт написания своих компонентов
2. опыт разработки архитектуры всяких мини-платформ
ну и вообще, со временем появляется навык быстрого определения объёма работы в обоих случаях, что в разы облегчает жизнь

Вот интересно, кто как и на основе чего в своей работе руководствуется при таком выборе?
Re[2]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 11.10.13 07:37
Оценка:
Здравствуйте, IT, Вы писали:

IT>Если библиотека реализует DI или прочий IoC — 99% отказать.


Это как — свои реализации DI используешь? Или это просто выделенный пункт из общего про навязывание архитектуры (в смысле что навязывает в проект жестко заданную библиотеку IoC)? Или что-то еще?
Re[3]: своё vs. сторонее
От: evgeny.e Китай  
Дата: 11.10.13 09:19
Оценка:
IT>>Если библиотека реализует DI или прочий IoC — 99% отказать.

Doc>Это как — свои реализации DI используешь? Или это просто выделенный пункт из общего про навязывание архитектуры (в смысле что навязывает в проект жестко заданную библиотеку IoC)? Или что-то еще?


присоединяюсь к вопросу,
некоторое время назад начало во мне расти недовольство спрингом на фоне любви всех вокруг к @Autowire, и я на небольшом (1 год на 2 разработчика) проекте решил попробовать всё инжектить прямо в джаве, написал свой ApplicationContextBuilder который возвращает ApplicationContext со всеми торчащими наружу сервисами,
и вполне доволен результатом,
интересно что другие в этом случае делают
Re[3]: своё vs. сторонее
От: Нахлобуч Великобритания https://hglabhq.com
Дата: 11.10.13 13:05
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>(в смысле что навязывает в проект жестко заданную библиотеку IoC)?


Это как? Его же вообще не видно нигде, кроме как в "бутстраппере" -- о каком навязывании речь?
HgLab: Mercurial Server and Repository Management for Windows
Re[4]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 11.10.13 14:48
Оценка:
Здравствуйте, Нахлобуч, Вы писали:

Н>Это как? Его же вообще не видно нигде, кроме как в "бутстраппере" -- о каком навязывании речь?


Ну например какая-нибудь мелкая библиотека, которая сама использует конкретную реализацию IoC.
Re[4]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 12.10.13 08:00
Оценка:
Здравствуйте, IT, Вы писали:

IT>DI от лукавого. Мне тут в соседней ветке пытались объяснить что такого даёт DI, очень долго пытались, но так и не смогли.


И какая альтернатива используется? new?

IT>Замечу, что я в курсе определний из педевикии, но мой вопрой именно про "зачем".


Для избавления от жестких зависимостей и в случаях когда конкретные реализации не известны на момент написания кода как ответы не подходят?
Re[6]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 13.10.13 03:04
Оценка:
Здравствуйте, IT, Вы писали:

IT>Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.


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

IT>Пример из того же типика:

[skip]
IT>Как по-твоему где больше зависимостей?

То что зависимость вынесена в вызывающий класс, не значит что ее нет. Да, у класса, кусок кода которого показан, стало меньше зависимостей. Зато другой класс (и возможно не один) теперь должны знать где брать value1 и value2.
Re[8]: своё vs. сторонее
От: Dziman США http://github.com/Dziman
Дата: 13.10.13 18:36
Оценка:
Здравствуйте, IT, Вы писали:

IT> Doc>То что зависимость вынесена в вызывающий класс, не значит что ее нет. Да, у класса, кусок кода которого показан, стало меньше зависимостей. Зато другой класс (и возможно не один) теперь должны знать где брать value1 и value2.


IT> И в чём проблема?


Мне кажется вы рассматриваете не ту проблему: DI — это построение графа объектов, а в приведенном примере проблема не в том как построен граф, а как взаимодействуют объекты графа.
avalon 1.0rc3 build 430, zlib 1.2.5
Re[8]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 14.10.13 02:07
Оценка:
Здравствуйте, IT, Вы писали:

IT>Прикрутить его легко, для этого много ума не надо. Достаточно почитать блоги и восторженные посты от людей, которые ещё не наигрались в паттерны и вот это овно уже в проекте и жидким слоем размазано по всему коду.


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

IT>И в чём проблема?


В том, что зависимость не ушла. Её переложили с одного класса на другой. А, как говориться, от перемены мест слагаемых сумма не изменяется.
Re[2]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 14.10.13 02:12
Оценка:
Здравствуйте, scale_tone, Вы писали:

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


Для каких-то глобальных вещей — да. Но вы забываете что еще есть всякая мелочь типа jQuery библиотек для UI и прочее. Протестить все за разумное время не реально. И вот тут иногда проще написать велосипед (свой и подконтрольный), чем выбирать 1 из 1000 на первый взгляд близнецов и возиться потом с чужим кодом.
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 03:01
Оценка:
Здравствуйте, Doc, Вы писали:

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


Ещё как изменится. Эта аналогия в данном случае не работает и поэтому не уместна.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[10]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 14.10.13 07:22
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ещё как изменится. Эта аналогия в данном случае не работает и поэтому не уместна.


И как изменится? Что вижу я тут http://www.rsdn.ru/forum/design/5329186.1:
Автор: IT
Дата: 13.10.13


Первый код: есть класс А, зависящий от _service, и (должен быть) класс B, вызывающий его метод MyVeryPrimitiveMethod.

После переделки: есть класс А, и класс B, вызывающий его метод MyVeryPrimitiveMethod и зависящий от _service.

Как видим, зависимость никуда не делась, ибо value1 и value2 откуда-то должны браться.
Re[2]: своё vs. сторонее
От: Sni4ok  
Дата: 14.10.13 07:25
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>В современном мире программного обеспечения (где все тысячи раз переписано сначала для мейнфреймов, потом для PC, потом для облаков etc.) написать свой толковый и быстро работающий велосипед _с нуля_ невозможно.


ну вот реально нету быстрого свободного логера например, с оверхедом с учётом формотирования не более 1мкс например, и хоть убей- нужно писать самому.
Re[3]: своё vs. сторонее
От: Sinix  
Дата: 14.10.13 07:47
Оценка:
Здравствуйте, Sni4ok, Вы писали:

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

Если только под win — можно использовать ETW. Вот тут обещают 600k/sec для простого примера на шарпе. Если код нативнцый — подозреваю, будет быстрее.
Re[4]: своё vs. сторонее
От: Sni4ok  
Дата: 14.10.13 08:23
Оценка:
Здравствуйте, Sinix, Вы писали:

S>Вот тут[/url] обещают 600k/sec для простого примера на шарпе. Если код нативнцый — подозреваю, будет быстрее.


1.5мкс в среднем на запись? да это тормозный платформозависимый бред, логер тут я вам привёл лишь в пример, я не против сторонних библиотек- и стараюсь использовать вначале именно их(конечно если это часть буста :D), просто они часто медленные и с кучей реалтаймового оверхеда.
Re[3]: своё vs. сторонее
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 14.10.13 08:28
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>Для каких-то глобальных вещей — да. Но вы забываете что еще есть всякая мелочь типа jQuery библиотек для UI и прочее. Протестить все за разумное время не реально. И вот тут иногда проще написать велосипед (свой и подконтрольный), чем выбирать 1 из 1000 на первый взгляд близнецов и возиться потом с чужим кодом.


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

Еще раз подчеркиваю: мы говорим о промышленной разработке коммерческого ПО. Про ситуацию "сам себе девелопер, тестер, бизнес-оунер и юзер" мы не говорим.
Re[4]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 14.10.13 08:37
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>С подачи топикстартера, речь идет о тысячах человекочасов.


В точности наоборот (из первого поста)

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


_>Протестить все действительно нереально. Но у либы из интернета в этом плане тоже есть преимущество: ее кто-то другой уже успел поюзать. И соответственно, есть шанс, что часть багов в ней уже нашли. Баги же в собственной поделке всегда приходится искать самостоятельно.


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

_>Еще раз подчеркиваю: мы говорим о промышленной разработке коммерческого ПО.


Я о том же. Про большие либы с большими затратами в человеко-часах полностью согласен (более 1-2 дня работы). Я лишь уточняю, что речь идет больше как раз о мелких либах (особенно если она используется из проекта в проект).
Re[3]: своё vs. сторонее
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 14.10.13 08:43
Оценка:
Здравствуйте, Sni4ok, Вы писали:

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


Этот кейс вполне вписывается в схему. Если его реально нету.
Re[5]: своё vs. сторонее
От: scale_tone Норвегия https://scale-tone.github.io/
Дата: 14.10.13 09:40
Оценка:
Здравствуйте, Doc, Вы писали:

Doc>В точности наоборот (из первого поста)

Doc>

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


Это да, это я ошибся.

Doc>Я о том же. Про большие либы с большими затратами в человеко-часах полностью согласен (более 1-2 дня работы). Я лишь уточняю, что речь идет больше как раз о мелких либах (особенно если она используется из проекта в проект).


ОК, сойдемся на диапазоне o-o > X > (1-2 дня).
Re[10]: своё vs. сторонее
От: Dziman США http://github.com/Dziman
Дата: 14.10.13 10:06
Оценка:
Здравствуйте, IT, Вы писали:

IT> D>Мне кажется вы рассматриваете не ту проблему: DI — это построение графа объектов, а в приведенном примере проблема не в том как построен граф, а как взаимодействуют объекты графа.


IT> DI &mdash; это 25-ти доллоровый термин для 5-ти центовой концепции. Я вообще не понимаю чего с ним так все носятся. Складывается такое впечатление, что DI — это некий верхний предел познания для большинства. Тот кто познал DI прётся от этого необычайно. Хотя даже концепцией это назвать можно с натяжкой. Так себе, не самый лучший паттерн, от которого проблемы возникают сразу и по всему коду,

Можно пример проблемы именно из-за DI?
IT> а что он даёт ценного внятно не может объяснить ни один из его апологетов.
Decoupling
avalon 1.0rc3 build 430, zlib 1.2.5
Re[10]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 14.10.13 10:28
Оценка:
Здравствуйте, IT, Вы писали:

IT>DI &mdash; это 25-ти доллоровый термин для 5-ти центовой концепции.


Кстати, забавная статья, про то, как человек открыл для себя тот факт, что DI это передача экземпляра заданного класса внутрь его класса. Он так скоро откроет, что там еще и интерфейсы можно использовать.
Re[11]: своё vs. сторонее
От: Noen  
Дата: 14.10.13 11:02
Оценка:
Здравствуйте, Doc, Вы писали:

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


IT>>DI &mdash; это 25-ти доллоровый термин для 5-ти центовой концепции.


Doc>Кстати, забавная статья, про то, как человек открыл для себя тот факт, что DI это передача экземпляра заданного класса внутрь его класса. Он так скоро откроет, что там еще и интерфейсы можно использовать.



You can have the dependency be an interface and then polymorphically pass in some polyjuice.

Re[6]: своё vs. сторонее
От: artelk  
Дата: 14.10.13 17:03
Оценка:
Здравствуйте, IT, Вы писали:

IT>Я предложил орлам рассказать мне как прикрутить DI с пользой к одному моему проекту. Они поизучали код, придрались к неотносящимся к делу мелочам, но признали, что DI там ничем не поможет, потому что такой дизайн. Вот это видимо и есть альтернатива.


Этот проект, все же, несколько отличается от того, с чем приходится сталкиваться в энтерпрайзе. Хотя бы тем, что он, чуть менее чем полностью, представляет из себя один большой преобразователь из linq выражения в sql запрос. Но я таки нашел в нем некий упрощенный контейнер:

public partial class DataConnection : ICloneable
{
    static readonly ConcurrentDictionary<string,IDataProvider> _dataProviders = new ConcurrentDictionary<string,IDataProvider>();

    //оффтоп: а почему _dataProviders потокобезопасен, а _providerDetectors нет?
    readonly static List<Func<ConnectionStringSettings,IDataProvider>> _providerDetectors = new List<Func<ConnectionStringSettings,IDataProvider>>();

    public static void AddDataProvider(string providerName, IDataProvider dataProvider)
    {
         //...
        _dataProviders[providerName] = dataProvider;
    }

    public static void AddDataProvider(IDataProvider dataProvider)
    {
         //...
        AddDataProvider(dataProvider.Name, dataProvider);
    }

    public static void AddProviderDetector(Func<ConnectionStringSettings,IDataProvider> providerDetector)
    {
        _providerDetectors.Add(providerDetector);
    }

    static DataConnection()
    {
        LinqToDB.DataProvider.SqlServer. SqlServerTools. GetDataProvider();
        LinqToDB.DataProvider.Access.    AccessTools.    GetDataProvider();
            //...
    }
}


Обращение к методам GetDataProvider имеет побочный эффект в виде вызова статических конструкторов классов. Например, смотрим SqlServerTools:

    static SqlServerTools()
    {
        AutoDetectProvider = true;

        DataConnection.AddDataProvider(ProviderName.SqlServer, _sqlServerDataProvider2008);
        DataConnection.AddDataProvider(_sqlServerDataProvider2012);
        DataConnection.AddDataProvider(_sqlServerDataProvider2008);
        DataConnection.AddDataProvider(_sqlServerDataProvider2005);
        DataConnection.AddDataProvider(_sqlServerDataProvider2000);

        DataConnection.AddProviderDetector(ProviderDetector);
    }


Т.е. так осуществляется регистрация в контейнере различных дата-провайдеров и их детектеров.
Re[7]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 17:15
Оценка:
Здравствуйте, artelk, Вы писали:

A>Обращение к методам GetDataProvider имеет побочный эффект в виде вызова статических конструкторов классов. Например, смотрим SqlServerTools:


И в чём проблема?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 14.10.13 17:20
Оценка:
Здравствуйте, artelk, Вы писали:

A>Этот проект, все же, несколько отличается от того, с чем приходится сталкиваться в энтерпрайзе.


По поводу энтерпрайза. Как раз если и использовать DI для тестирования, то в таких проектах как linq1db. В энтерпрайзах 90% логики — это работа с базами данных. А в самых запущенных случаях вся логика вообще находится в сохранённых процедурах, т.е. в самой базе данных. И если у кого-нибудь хватит мозгов использовать DI, чтобы мокать такую логику, то что, скажите вы собираетесь тестировать, умение C# генерировать вызовы методов? Так это уже давно было сделано в MS.

А те оставшиеся 10% нетривиальной логики, которую действительно нужно гонять на самых разных данных и желательно без БД, совершенно спокойно можно задизайнить таким образом, что всё, что ей нужно будет передаваться по необходимости. И всё. DI не нужен.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 15.10.13 06:23
Оценка:
Здравствуйте, IT, Вы писали:

Doc>>Как видим, зависимость никуда не делась, ибо value1 и value2 откуда-то должны браться.

IT>Это уже проблема вызывающего класса. У обсуждаемого класса зависимостей нет вообще.

Дай угадаю, с классом выше ты поступишь так же? Или ты пишешь библиотеки, состоящие из одного класса?

Кстати, а что делать будешь, если нужны будут методы _service, в который нужно передать аргументы (которые скрыты внутри самого класса)?
Re: своё vs. сторонее
От: Аноним  
Дата: 15.10.13 09:21
Оценка:
CEM>Сам я обычно стараюсь ничего стороннего не брать, потому что:

.NET библиотеки и компилятор свои или сторонние ?
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 15.10.13 13:41
Оценка:
Здравствуйте, Doc, Вы писали:

IT>>Это уже проблема вызывающего класса. У обсуждаемого класса зависимостей нет вообще.

Doc>Дай угадаю, с классом выше ты поступишь так же? Или ты пишешь библиотеки, состоящие из одного класса?

Дай и я угадаю, в твоей луковице десятки классов выше. Ты пишешшь библиотеки, состоящие из одного класса на одну строчку функциональности?

Doc>Кстати, а что делать будешь, если нужны будут методы _service, в который нужно передать аргументы (которые скрыты внутри самого класса)?


Зависит. Ты же не думаешь, что в качестве параметра можно передавать только примитивные типы. Вообще-то ещё существуют делегаты, интерфейсы (да, да, интерфейсы можно использовать не только для сервисов!) и просто классы с методами, у которых вполне могут быть параметры.
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 15.10.13 16:46
Оценка:
Здравствуйте, IT, Вы писали:

IT>Дай и я угадаю, в твоей луковице десятки классов выше.


Не понял вопрос. Если про общее число классов, то да. Если про глубину вызовов, то нет.

IT>Ты пишешшь библиотеки, состоящие из одного класса на одну строчку функциональности?


Если надо по архитектуре приложения, то ничего страшного не вижу. Но только не "класс ради класса".

IT>Вообще-то ещё существуют делегаты, интерфейсы (да, да, интерфейсы можно использовать не только для сервисов!)


Ух ты, method injection ? Все же используешь DI? Но в примере ты все равно от зависимости не избавился. Да, перенес её в другой класс, но и там её надо как-то разруливать. Плюс, еще не известно кто должен знать про _service — исходный класс или вызывающий. Но это уже от логики приложения.
Re[8]: своё vs. сторонее
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 15.10.13 20:23
Оценка:
Здравствуйте, IT, Вы писали:

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


A>>Этот проект, все же, несколько отличается от того, с чем приходится сталкиваться в энтерпрайзе.


IT>По поводу энтерпрайза. Как раз если и использовать DI для тестирования, то в таких проектах как linq1db. В энтерпрайзах 90% логики — это работа с базами данных. А в самых запущенных случаях вся логика вообще находится в сохранённых процедурах, т.е. в самой базе данных. И если у кого-нибудь хватит мозгов использовать DI, чтобы мокать такую логику, то что, скажите вы собираетесь тестировать, умение C# генерировать вызовы методов? Так это уже давно было сделано в MS.


IT>А те оставшиеся 10% нетривиальной логики, которую действительно нужно гонять на самых разных данных и желательно без БД, совершенно спокойно можно задизайнить таким образом, что всё, что ей нужно будет передаваться по необходимости. И всё. DI не нужен.


Вся логика в БД это крайне редкий случай. Сейчас средне умение писать SQL на столько низко, что мнгие не понимают что современные РСУБД это не только key-value storage.
Но даже если большая часть логики в БД, то обработка запроса выглядит так:


Result Method1(Parameters p)
{
    if(!CheckRequest(p))
    {
        return InvalidParametersResult(p);
    }

    if(!CheckUserRights(p))
    {
        return AccessDeniedResult(p);
    }

    if(CanUseCachedResult(p))
    {
        return CachedResult(p);
    }
    
    var dbResult = CallDatabase(p);

    if(!dbResult.IsValid)
    {
        return InvalidOperationResult(p, dbResult);
    }
    
    return Process(dbResult);
    
}



Нужно понимать что все методы, не примитивные, из одной строчки. Каждый их них потенциально может лезть в БД, использовать параметры и другие "сервисы" приложения. Тут DI начинает очень сильно помогать. Кроме того, для улучшения unit-тестирования самого Method1 можно часть вызываемых функций тоже подсовывать через DI. Другая часть функций может быть вынесена вне методов обработки запросов и внезапно такой AoP тоже реализуется через DI.

В итоге DI помогает собирать приложения по кусочкам, концентрируясь при этом на самих кусочках, а не на сборке.

Конечно бывает так, что разбить логику на несвязанные кусочки нельзя, тогда попытка применения DI выглядит жалко.
Re[4]: своё vs. сторонее
От: koodeer  
Дата: 15.10.13 21:02
Оценка:
Здравствуйте, IT, Вы писали:

IT>DI от лукавого. Мне тут в соседней ветке пытались объяснить что такого даёт DI, очень долго пытались, но так и не смогли.


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

Так вот, DI и прочие умные штуки дают следующее ценное свойство: они позволяют безбедно жить программистам, щедро впихнувшем в свои проекты именно эти фичи. Потому как мой некоторый личный опыт показывает следующее: те проекты, которые сделаны без этих умных фич, давно уже поддерживаются студентами/джуниорами, и первоначальным разработчикам ничего с них не перепадает. А вот те, где есть что-то эдакое, студенты не могут осилить, поэтому для внедрения каждой новой фичи обращаются к профессиональным разработчикам.
Re[2]: своё vs. сторонее
От: CEMb  
Дата: 16.10.13 02:33
Оценка:
Здравствуйте, scale_tone, Вы писали:

_>Как-то так.


Надо будет попробовать сделать проект по этой схеме правда команда у нас не большая, примерно один человек, иногда два
Re[16]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 16.10.13 03:19
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ну а если нет, то в чём проблема?


А проблем и нет.

Doc>>Ух ты, method injection ? Все же используешь DI?

IT>Вот! То о чём я и говорю. Больные люди! Им везде мерещится DI.

Просто сами шаблоны DI это не супер какая магия, а передача зависимостей. Их всего три — constructor injection, property injection и method injection. И та "магия", что творится в контейнере при создании экземпляра, к ним отношения не имеет.

Doc>>Но в примере ты все равно от зависимости не избавился. Да, перенес её в другой класс, но и там её надо как-то разруливать.


IT>И что? Я убрал нежелательную зависимость? Убрал. Да ещё так убрал, как DI и не снилось.


Ты перенес её в другой класс приложения. Вот тут как раз получается как ты и сказал "из одного места убираем, в другое добавляем, в треьем размазываем жидким слоем". С IoC не пришлось бы вызывающим классам знакомиться с _service.
Re[5]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 16.10.13 03:20
Оценка:
Здравствуйте, koodeer, Вы писали:

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


Учитесь тролить тоньше. А то очень толсто вышло
Re[18]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 16.10.13 03:44
Оценка:
Здравствуйте, IT, Вы писали:

IT>Я её не переносил, она там, где и должна быть.


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

Ты слишком однобоко понимаешь применение инструментов. DI — это не только ценный мех, цена которого, кстати, 0.5 по 10-ти бальной шкале. Это ещё и привнесённая в приложение сложность и эта сложность на порядок больше пользы.

IT>Нет, жидким слоем, это не про зависимости, это про логику. Вот смотришь на такие погрызенные DI-ем методы и думашеь, что же они делают? За деревьями леса не видно. Одни, мля, какие-то левые сервисы дёргаются.


Я так понимаю, это про то, что по F12 в сорцы не перейти (без всяких плагинов для VS)? При изучении кода конкретного метода то, что делает вызов (что должен делать) должно быть ясно из его названия и/или комментария и окружающего кода. А то, что реализующий это класс делает это корректно — из unit test-ов. Ты же не перечитываешь код System.String при каждой операции со строкой?

Хотя если методы сервиса называется DoAction1() итп то такой разработчик сам себе злобный буратино.
Re[12]: своё vs. сторонее
От: UberPsychoSvin  
Дата: 16.10.13 04:32
Оценка:
Здравствуйте, IT, Вы писали:

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


D>>Можно пример проблемы именно из-за DI?


IT>Я уже устал об этом говорить. DI ломает навигацию по проекту, что существенно затрудняет читабельность и понимабильность кода приложения. Бизнес логика разбивается на части и разносится по разным частям приложения. Это затрудняет модификацию приложения.


IT>А всегда ли это нужно?

Если DI нужно только для тестов, в С# например можно в качестве интерфейса использовать сами классы. Если нужно их мокнуть, то соответствующие методы делаются виртуальными.
Re[6]: своё vs. сторонее
От: Yoriсk  
Дата: 16.10.13 08:39
Оценка:
Здравствуйте, IT, Вы писали:

IT>
IT>void MyVeryPrimitiveMethod()
IT>{
IT>    var value1 = _service1.GetValue1();
IT>    var value2 = _service2.GetValue2();

IT>    var result = value1 * value2;

IT>    _service3.SetResult(result);
IT>}
IT>

IT>И это всё вместо:
IT>Как по-твоему где больше зависимостей?

Одинаково. Ваш код в полном виде выглядит как-то так:
{
///// far far away
var value1 = _service1.GetValue1();
var value2 = _service2.GetValue2();
var result = MyVeryPrimitiveMethod(value1 * value2);
_service3.SetResult(result);
////
}

int MyVeryPrimitiveMethod(int value1, int value2)
{
    return value1 * value2;
}




Хотя как по мне, что
_serviceInterfaceFromDI.GetValue1();

что
_concreteClass.GetValue1();

тоже в 99.9% случаях дают одинаковую зависимость, потому что в этих 99.9% в данном месте всегда будет одна и та же и совершенно конкретная имплементация.
Всё тлен, всё тщета.
Re[10]: своё vs. сторонее
От: gandjustas Россия http://blog.gandjustas.ru/
Дата: 16.10.13 09:28
Оценка:
Здравствуйте, IT, Вы писали:

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


G>>Нужно понимать что все методы, не примитивные, из одной строчки. Каждый их них потенциально может лезть в БД, использовать параметры и другие "сервисы" приложения. Тут DI начинает очень сильно помогать.


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


Необходимости в DI вообще никогда нет. Любой код может быть написан без DI. Но альтернатива в виде ball-of-mud архитектуры зачастую хуже, чем DI на каждый чих. Можно конечно писать слабосвязный код и без DI, но там мало кто умеет.

IT>Только в твоём примере такой необходимости нет ни в одном месте. Валидация — это часть логики, какой-то тут DI? Юзер проверяется атрибутами, как правило доступен в контексте или обрабатвается более сложными способами вроде фильтрации данных SQL запросами, что фактически является частью безнес логики.

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

IT>Кеширование тоже лучше всего делается атрибутами, ну или простейшим хелпером на худой конец.

Ну вот хелпер у тебя зависит от ASP.NET, а метод — не зависит. Но если у тебя нет DI, то unit-тестами сложно будет покрыть метод.


G>>Кроме того, для улучшения unit-тестирования самого Method1 можно часть вызываемых функций тоже подсовывать через DI. Другая часть функций может быть вынесена вне методов обработки запросов и внезапно такой AoP тоже реализуется через DI.

IT>Я же говорю, запихать можно куда угодно. Только надо ли?
Я видел фрейморки, которые использовали эти сам атрибуты без DI, это был ад. Так что я в этом случае за DI.

G>>В итоге DI помогает собирать приложения по кусочкам, концентрируясь при этом на самих кусочках, а не на сборке.

IT>В собранном по кусочкам приложении невозможно разобраться. Зачастую, что бы понять его логику нужно запускать его под отладчиком. В общем, я уже устал это повторять. DI — это сломанная навигация по коду и логика, размазанная жидким поносом по всему приложению.
Если у тебя есть решарпер, то не проблема. Я уже и без решарпера научился разбирать сильно DI код.


IT>Как правило от таких приложений смердит за версту и всякими другими архитектурными излишествами.

Я такого и без DI видел много раз.
Re[19]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 14:54
Оценка:
Здравствуйте, Doc, Вы писали:

IT>>Я её не переносил, она там, где и должна быть.

Doc>Лукавишь. Если изначально сервис должен был быть в вызывающих классах, то это был не пример "замены DI", а пример "исправления архитектуры".

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

Doc>Я так понимаю, это про то, что по F12 в сорцы не перейти (без всяких плагинов для VS)? При изучении кода конкретного метода то, что делает вызов (что должен делать) должно быть ясно из его названия и/или комментария и окружающего кода. А то, что реализующий это класс делает это корректно — из unit test-ов. Ты же не перечитываешь код System.String при каждой операции со строкой?


Не надо путать божий дар с яичницей. Или тебе ообъяснить разницу между System.String и GetcustomerByID? Какие требования предъявляются при разработке к одному методу, а какие к другому.

Doc>Хотя если методы сервиса называется DoAction1() итп то такой разработчик сам себе злобный буратино.


Считать себя умнее других также плохо как и считать других глупее себя. Так что давай обойдёмся без абстрактных индусов.
Если нам не помогут, то мы тоже никого не пощадим.
Re[20]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 16.10.13 15:35
Оценка:
Здравствуйте, IT, Вы писали:

IT>Кто тебе вообще сказал, что сервис должен быть изначально?


Ага, т.е. сервис в том примере вообще лишний? Если так — то это тем более пример исправления кривой архитектуры, а не изгнания IoC

IT>Не надо путать божий дар с яичницей. Или тебе ообъяснить разницу между System.String и GetcustomerByID?


Если GetcustomerByID проходит unit test — мне без разницы что внутри, до того момента, как будут основания это проверить.

IT>Считать себя умнее других также плохо как и считать других глупее себя. Так что давай обойдёмся без абстрактных индусов.


Во, начни с себя и завязывай раздавать диагнозы
Re[6]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 16.10.13 16:17
Оценка:
Здравствуйте, IT, Вы писали:

IT>Как по-твоему где больше зависимостей?


Без вызывающего кода сложно сказать.

Вот вызывающй код для первого случая
  var instance = new PrimitiveClass();

  instance.MyVeryPrimitiveMethod();



Вот для второго:
  var instance = new PrimitiveClass();

 _service3.SetResult(instance.MyVeryPrimitiveMethod(_service1.GetValue1(), _service2.GetValue2()));


Где меньше зависимостей ?
Re[21]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 18:29
Оценка:
Здравствуйте, Doc, Вы писали:

IT>>Кто тебе вообще сказал, что сервис должен быть изначально?

Doc>Ага, т.е. сервис в том примере вообще лишний?

В каком примере?

IT>>Не надо путать божий дар с яичницей. Или тебе ообъяснить разницу между System.String и GetcustomerByID?

Doc>Если GetcustomerByID проходит unit test — мне без разницы что внутри, до того момента, как будут основания это проверить.

Понятно. Разницы между библиотечной функцией общего назначения и логикой бизнес-приложения для тебя не существует.

Doc>Во, начни с себя и завязывай раздавать диагнозы


Опять начался детский сад. Судя по нашему предыдущему общению дальнейшая дискуссия с тобой начинает тепять всякий смысл. Пока.
Если нам не помогут, то мы тоже никого не пощадим.
Re[7]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 16.10.13 18:31
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Где меньше зависимостей ?


Здесь:

  var n = MyVeryPrimitiveMethod(1, 2);
Если нам не помогут, то мы тоже никого не пощадим.
Re[8]: своё vs. сторонее
От: Dziman США http://github.com/Dziman
Дата: 16.10.13 19:20
Оценка:
Здравствуйте, IT, Вы писали:

IT> I>Где меньше зависимостей ?


IT> Здесь:


IT>
IT>   var n = MyVeryPrimitiveMethod(1, 2);
IT>


Я вот не могу понять это троллинг или что-то еще? Если 1 и 2 это константы то там DI делать нечего, но если эти значения приходят 'извне', то рано или поздно надо будет сделать getParam1 и getParam2. И там есть вероятность, что DI пригодится.
avalon 1.0rc3 build 430, zlib 1.2.5
Re[9]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 01:38
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Это больше на фобию похоже.


Фобия — это боязнь, а бояться тут нечего. У меня стойкое отвращение. Фууу!
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[22]: своё vs. сторонее
От: Doc Россия http://andrey.moveax.ru
Дата: 17.10.13 06:21
Оценка:
Здравствуйте, IT, Вы писали:

IT>В каком примере?


Который ты и привел, и про который говорим
http://www.rsdn.ru/forum/design/5329186.1
Автор: IT
Дата: 13.10.13


IT>Понятно. Разницы между библиотечной функцией общего назначения и логикой бизнес-приложения для тебя не существует.


Зависит от цели изучения кода и покрытия его логики тестами. Но то, что я не буду при каждом изучении кода смотреть что внутри каждого вызова — это факт. Сначала максимально локализовать проблему, а потом уже копаться.

IT>Опять начался детский сад. Судя по нашему предыдущему общению дальнейшая дискуссия с тобой начинает тепять всякий смысл. Пока.


Ну да, прошу не вешать ярлыки и смысл у тебя пропал сразу. Бывает
Re[10]: своё vs. сторонее
От: evgeny.e Китай  
Дата: 17.10.13 09:11
Оценка:
IT>Может быть пригодится, а может быть скорее всего нет. Почему-то все понимают, что преждевременная оптимизация — это плохо, но решительно не понимают, что преждевременный дизайн — ещё хуже.

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

лично я предпочитаю без DI, но, на мой взгляд, архитектура с DI будет лучше чем архитектура созданная средним разработчиком без DI, но лучше чем хорошим разработчиком без DI
Re[8]: своё vs. сторонее
От: . Великобритания  
Дата: 17.10.13 09:34
Оценка:
Здравствуйте, IT, Вы писали:

I>>Где меньше зависимостей ?


IT>Здесь:


IT>
IT>  var n = MyVeryPrimitiveMethod(1, 2);
IT>

Зачем так всё сложно? Может уж сразу
  var n = 1 * 2;

Или даже так?
  ;
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 12:13
Оценка:
Здравствуйте, IT, Вы писали:

I>>Это больше на фобию похоже.


IT>Фобия — это боязнь, а бояться тут нечего. У меня стойкое отвращение. Фууу!


Ладно, годная отмазка. Вот другой пример

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

Вызов открытия документа снаружи достаточно простой — Application.Documents.Open(args);
Все что нужно сделать для другого кастомера — поменять логику открытия документа без необходимости городить конские иерархии наследования и тд.

Весь внутренний АПИ сделан примерно так. Есть N компонентов, похожих на команды или транзакции, интерфейс с вызывающей стороны примерно такой

interface ICommandXXX<TArgs> {
  void Execute(TArgs args);
  void CanExecute(TArgs args);
}


Documents.Open имеет вот такую реализацию

IDocument Open(OpenDocumentArgs args)
{
  var cmd = Resolve<IOpenDocument>();

  if(cmd.CanExecute(args))
     cmd.Execute(args);
}


Вот эта логика не меняется, её в принципе можно и генерить.
Скажем часть UI, это тулбары и меню, обновляется в зависимости от состояния приложения. Это всего лишь конфигурирование, при том в итоге вызывается чтото навроде barItem.StateFrom(cmd.Status) и конкретный итем будет исправно менять своё состояние без каких либо проблем.
Таких итемов примерно несколько сотен, может даже больше. Выписывать вьюмодельки совершенно неинтересно — вспотеешь учитывать все детали.

Фокус в том, что такие компоненты, как IOpenDocument, требуют целую кучу депенденсов, фактически, нужен весь АПИ приложения, и куча фунционала навроде зипа, скриптов и тд и тд и тд. Причем каждому нужно свое.
Внешний АПИ приложения не дает доступа ко всем сервисам, что очевидно. Внутренний сделан так, чт бы его можно было конфигурировать прозрачно для вызывающего кода
Решение получается такое

interface ICommandXXX<TArgs> {
...
  IScriptHost ScriptHost {get; set;}
  IRemoteHost RemoteHost {get; set;}
  IStatus Status {get; set;}
  IValidation Validator {get; set;}
}


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

var cmd = Resolve<ICommandYYY<TArgs>>();

cmd.Execute(args);


Очевидно, реализация ICommandYYY<TArgs> может варьироваться в зависимости от приложения. т.е. достаточно сконфигурировать.
На старте приложения DI подымает конфигурацию, а во время работы расставляет нужные депенденсы по требованию.
В итоге, со стороны кастомерского кода не надо возить с депенденсами. Со стороны внутреннего АПИ надо всего лишь объявить требуемые депенденсы. Унутре компонента все депенденсы уже будут в наличии.
Написание нового функционала сводится к таким вещам — объявить интерфейс, объявить депенденсы, написать внутреннюю логику. Вся инициализация и связывание перекладывается на DI.
БОлее того, на этот DI можно переложить контроль времени жизни некоторых объектов, можно сделать вложеные контексты и много чего другого.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 15:23
Оценка:
Здравствуйте, evgeny.e, Вы писали:

EE>преждевременный дизайн это плохо??


Плохо. Всё преждевременное плохо. Послевременное тоже плохо. Хорошо только своевременное.

EE>по всем исследованиям стоимость ошибки тем меньше, чем раньше она обнаружена, а раньше дизайна некуда,


Ты говоришь про ошибочный дизайн, который чего-то не учитывает. Я говорю о дизайне, который учитыват всё подряд, но никому не нужное, т.е. представляет собой over design.

EE>разница между преждевременным дизайном и оптимизацией в том, что оптимизация это реально работающий (в продакшене) код, а дизайн это обычно писульки в визио,


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

EE>задизайнить использование DI там где он не нужен это плохо не потому что дизайн преждевременный, а потому что такой дизайн — хренов


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

EE>лично я предпочитаю без DI, но, на мой взгляд, архитектура с DI будет лучше чем архитектура созданная средним разработчиком без DI, но лучше чем хорошим разработчиком без DI


Это как?
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 17:05
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Есть задача — для кастомных модулей подменять функционал.


Ну подменяй. Что требуется от меня?
Если нам не помогут, то мы тоже никого не пощадим.
Re[12]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 17:11
Оценка:
Здравствуйте, IT, Вы писали:

I>>Есть задача — для кастомных модулей подменять функционал.


IT>Ну подменяй. Что требуется от меня?


Как аргумент в пользу DI годится или как ?
Re[11]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 17:13
Оценка:
Здравствуйте, evgeny.e, Вы писали:

EE>задизайнить использование DI там где он не нужен это плохо не потому что дизайн преждевременный, а потому что такой дизайн — хренов


плохой потому что плохой. Сильная идея. DI, там где он не нужен, плохой потому, что DI не нужен. Как-то так
Re[12]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 17:58
Оценка:
Здравствуйте, IT, Вы писали:

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


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

Вобщем, после таких слов для тебя самый удобный вариант это : "Заканчиваю троллить, иду работать"
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 17.10.13 18:17
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Есть задача — для кастомных модулей подменять функционал.

IT>>Ну подменяй. Что требуется от меня?
I>Как аргумент в пользу DI годится или как ?

Надо смотреть. По крайней мере ты это используешь не для тестирования. Похоже, что у тебя нет другого выхода и ты вынужден использвать DI.
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 17.10.13 18:29
Оценка:
Здравствуйте, IT, Вы писали:

I>>>>Есть задача — для кастомных модулей подменять функционал.

IT>>>Ну подменяй. Что требуется от меня?
I>>Как аргумент в пользу DI годится или как ?

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


Примерно так, да.
Re[14]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 18.10.13 04:25
Оценка:
Здравствуйте, Doc, Вы писали:

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

I>>Вобщем, после таких слов для тебя самый удобный вариант это : "Заканчиваю троллить, иду работать"

Doc>Что-то мне подсказывает, что под DI он понимает Service Locator. То да, тогда будет все как он пишет — и проброс всего и вся внутрь, и муторные попытки понять что именно требует тот или иной класс.


Чтото навроде.
Re[14]: своё vs. сторонее
От: Legion13  
Дата: 21.10.13 07:02
Оценка:
Здравствуйте, IT, Вы писали:

IT>Ты видимо прочитал лишь то, что хотел. Это бывает. Объясняю ещё раз. В случае DI объект получает не весь необходимый контекст, а вообще всё, что можно. При этом понять что именно объекту нужно, а что ему передали просто нереально. Поэтому при изучении кода, при его рефакторингах и модификациях, в случаях когда требуется отчуждение кода от системы, работа с таких кодом превращается в одну сплошную невыносимую головную боль.


То, о чем вы говорите, по описанию похоже на Service Locator, который действительно хренов.
Но ведь Dependency Injection возможно реализовать, например, как Constructor Injection, т.е. все зависимости получаются через конструктор. и сразу видно, что класс требует. Тут свой недостаток тоже будет — если это делается с использованием IoC-контейнера, то поиск по вызову конструктора класса ничего не найдет.
Re[15]: своё vs. сторонее
От: . Великобритания  
Дата: 21.10.13 10:38
Оценка:
Здравствуйте, Legion13, Вы писали:

IT>>Ты видимо прочитал лишь то, что хотел. Это бывает. Объясняю ещё раз. В случае DI объект получает не весь необходимый контекст, а вообще всё, что можно. При этом понять что именно объекту нужно, а что ему передали просто нереально. Поэтому при изучении кода, при его рефакторингах и модификациях, в случаях когда требуется отчуждение кода от системы, работа с таких кодом превращается в одну сплошную невыносимую головную боль.


L>То, о чем вы говорите, по описанию похоже на Service Locator, который действительно хренов.

L>Но ведь Dependency Injection возможно реализовать, например, как Constructor Injection, т.е. все зависимости получаются через конструктор. и сразу видно, что класс требует. Тут свой недостаток тоже будет — если это делается с использованием IoC-контейнера, то поиск по вызову конструктора класса ничего не найдет.
Dependency Injection и Service Locator это 2 противоположных решения задачи связывания зависимостей. Как это можно путать? DI — в объект инжектят зависимости (constructor/field/method injection), а SL — есть глобальный реестр из которого запрашиваются зависимости (выше по топику "var cmd = Resolve<ICommandYYY<TArgs>>();").
Просто большинство IoC-контейнеров обычно предоставляют и DI, и SL. Видимо, некоторые этого не понимают и юзают корявый SL, но почему-то называют это DI, излучая лучи поноса.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: своё vs. сторонее
От: Legion13  
Дата: 21.10.13 14:34
Оценка:
Здравствуйте, ., Вы писали:

.>Dependency Injection и Service Locator это 2 противоположных решения задачи связывания зависимостей. Как это можно путать?


Это вы мне? Я их не путаю.
Re[12]: своё vs. сторонее
От: . Великобритания  
Дата: 22.10.13 23:06
Оценка:
Здравствуйте, Abalak, Вы писали:

D>>Можно пример проблемы именно из-за DI?

A>Легко. Вот пилю сейчас часть проекта, где запихнули MEF куда только можно. Решил попользовать готовый объект, часть ДАЛа, что б не городить велосипед самому. Пишу как положено — new бла-бла-бла. Вроде все создается и даже работает. Потом хочу дернуть нужное свойство и бац все падает в рантайме. Начинаю копать код, а там оказывается куча непубличных полей, которые инициализируются через рефлекшн МЕФом и которые никак по другому не проинициализировать, а тащить весь контекст приложения, туда где он не нужен — зло. Понятно, проблема не напрямую в DI, а в дизайне, но такие дизайны сплошь и рядом. Хотя по рукам надо бить и MS, которая такие финты позволяет. Возникают сложности там где не нужно, в итоге нормальной с первого взгляда объект можно использовать без лишнего геммороя только в единственном месте, там где это задумал мегаархитектор.
И причём тут архитектура? Так, синтаксис немного неудобный для кривого использования.
Если тебе так хочется использовать new и религия не позволяет использовать IoC-контейнер, то можно слегка отрефакторить: переделать field injection в constructor injection (и это правильно), в общем всё. Или даже просто объявить поля публичными, чтобы насладиться ручным DI.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[10]: своё vs. сторонее
От: Baudolino  
Дата: 23.10.13 09:29
Оценка:
Здравствуйте, IT, Вы писали:
IT>Валидация — это часть логики, какой-то тут DI?
Вы тесты в своей жизни когда-нибудь писали или отдаёте на продакшн кота в мешке, прощупанного за яйца Равичандрой из QA (но, поскольку кот — в мешке, Равичандра уверен, что это персики, как и сказано в техзадании)?
Re[12]: своё vs. сторонее
От: . Великобритания  
Дата: 23.10.13 10:41
Оценка:
Здравствуйте, IT, Вы писали:

D>>Можно пример проблемы именно из-за DI?

IT>Я уже устал об этом говорить. DI ломает навигацию по проекту, что существенно затрудняет читабельность и понимабильность кода приложения.
Каким образом? Если вы начинаете на каждый чих создавать интерфейсы, то причём тут DI? Контейнерам не нужны интерфейсы (только если AOP требуется, но причём тут DI?), они могут и простые классы инжектить.

IT> Бизнес логика разбивается на части и разносится по разным частям приложения. Это затрудняет модификацию приложения.

А можно пример? Каким образом тут DI приплетён? Если вдруг после того как зависимости стали делать управляемыми, ВНЕЗАПНО стало заметно, что у какого-то класса 50 зависимостей, 10000 строк кода и 0 юнит-тестов, то это не вина DI.

IT>>> а что он даёт ценного внятно не может объяснить ни один из его апологетов.

D>>Decoupling
IT>А всегда ли это нужно?
Чаще чем не нужно, если ты пишешь что-то сложнее, чем фреймворк для умножения двух чисел
Автор: IT
Дата: 13.10.13
.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[14]: своё vs. сторонее
От: . Великобритания  
Дата: 24.10.13 11:56
Оценка:
Здравствуйте, Abalak, Вы писали:

A>Да при том, что объект заранее спроектирован криво и расчитан на использование костылей, которые допускает в данном случае MEF.

Допустим, что было спроектировано криво, костылесовместимость решений от M$ всегда высока, поубивав бы. Но тебе понадобился лишь элементарный рефакторинг с минимальным импактом, чтобы это поправить. Если бы не было явного DI, то скорее всего была бы мешанина ещё более кривых архитектурных решений, такие как рассыпанные по всему коду класса операторы new, глобальные синглтоны, статические фабрики, магические контексты и прочий шлак, рефакторинг которого довльно сложная задача со слабо предсказуемыми последствиями.

Главное не избегать заранее кривое проектирование (это утопия), а минимизировать последствия неудачного проектирования. Судя по тому, что ты написал, DI в этом помогло отлично.

.>>Если тебе так хочется использовать new и религия не позволяет использовать IoC-контейнер, то можно слегка отрефакторить: переделать field injection в constructor injection (и это правильно), в общем всё. Или даже просто объявить поля публичными, чтобы насладиться ручным DI.


A>Мне религия не позволяет городить тонну кода на ровном месте. По сути мне нужно было написать крохотную dll, которая будет дергаться планировщиком, выполнять несколько хранимок и писать в базу результаты. Там кода на 100-200 строк, поэтому и решил использовать объект из основного проекта, который позволяет сконфигурировать все эти вызовы и буквально одной строкой получать данные. Так вот, из-за кривости реализации ты мне предлагаешь тащить кучу доп. зависимостей и сделать "как правильно", вместо того, что бы сделать как проще и понятнее.

Я не знаю как там в C# мире, но в Яве чтобы минимально заюзать DI нужно добавить ~500k либу и написать пол дюжины строк кода. И объём этого кода будет явно меньше, чем если бы конфигурировал эти все вызовы вручную.

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

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

Что-то мне кажется, что все эти нападки направлены на что угодно, но не DI. DI это очень тривиальный и маленький паттерн, альтернативы ему — сложнее или кривее.
В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[15]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 24.10.13 22:59
Оценка:
Здравствуйте, Legion13, Вы писали:

L>То, о чем вы говорите, по описанию похоже на Service Locator, который действительно хренов.


О! ServiceLocator — это вообще круто, особенно, когда некоторые умельцы используют его совместно с DI

L>Но ведь Dependency Injection возможно реализовать, например, как Constructor Injection, т.е. все зависимости получаются через конструктор. и сразу видно, что класс требует. Тут свой недостаток тоже будет — если это делается с использованием IoC-контейнера, то поиск по вызову конструктора класса ничего не найдет.


Во-первых, IoC. Во-вторых, как правило передаваемый интерфейс не содержит в себе один единственный метод. Чаще всего это целая гроздь? зачастую слабосвязанных друг с другом методов, у которых свои собственные зависимости. И среди этих зависимостей могут легко оказаться зависимости никак не связанные с целевым объектом. Этого сложно избежать, даже если за этим строго следить. А так как это вообще-то нафиг никому не нужно, то имеет то, что имеем. А именно сложно отчуждаемый код, котоый выдрать из контекста можно только с мясом.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[11]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 24.10.13 23:04
Оценка:
Здравствуйте, Baudolino, Вы писали:

IT>>Валидация — это часть логики, какой-то тут DI?

B>Вы тесты в своей жизни когда-нибудь писали или отдаёте на продакшн кота в мешке, прощупанного за яйца Равичандрой из QA (но, поскольку кот — в мешке, Равичандра уверен, что это персики, как и сказано в техзадании)?

Ты что-то хотел сказать?
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 24.10.13 23:09
Оценка:
Здравствуйте, Baudolino, Вы писали:

IT>>Я уже устал об этом говорить. DI ломает навигацию по проекту

B>В 2003 году? В 2013 не ломает, если вы используете правильные инструменты (при программировании в блокноте, согласен, навигация никакая, даже без DI).

Сколько пафоса! Можно подумать ты пишешь программы с помощью мысленного инструмента, а не с помощью клавиатуры.

IT>>Бизнес логика разбивается на части и разносится по разным частям приложения.

B>Это проблема не DI, а криворукого архитектора.

Если очень хочется пообсуждать криворукость архитектуры и архитекторов, то достаточно показать здесь свой наиправильнейший код. Или слабо?

IT>>А всегда ли это нужно?

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

Ничего не понял Какой паровоз...
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 24.10.13 23:14
Оценка:
Здравствуйте, ., Вы писали:

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

.>Каким образом? Если вы начинаете на каждый чих создавать интерфейсы, то причём тут DI? Контейнерам не нужны интерфейсы (только если AOP требуется, но причём тут DI?), они могут и простые классы инжектить.

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

IT>> Бизнес логика разбивается на части и разносится по разным частям приложения. Это затрудняет модификацию приложения.

.>А можно пример? Каким образом тут DI приплетён? Если вдруг после того как зависимости стали делать управляемыми, ВНЕЗАПНО стало заметно, что у какого-то класса 50 зависимостей, 10000 строк кода и 0 юнит-тестов, то это не вина DI.

При чём тут количество зависимосей, объём коди и юнит тесы?

IT>>А всегда ли это нужно?

.>Чаще чем не нужно, если ты пишешь что-то сложнее, чем фреймворк для умножения двух чисел
Автор: IT
Дата: 13.10.13
.


Я уже устал от таких аргументов. Особенно когда под сложностью понимают не сложность задачи, а сложность собственной имплементации, которая в результате образовывается в том числе и из-за использования DI.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[14]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 00:19
Оценка:
Здравствуйте, IT, Вы писали:

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

.>>Каким образом? Если вы начинаете на каждый чих создавать интерфейсы, то причём тут DI? Контейнерам не нужны интерфейсы (только если AOP требуется, но причём тут DI?), они могут и простые классы инжектить.
IT>Вообще-то смысл DI в устранении зависимостей от реализации, т.е. в использовании интерфейсов вместо классов.
Да, а реализация определяется только оператором new. Если используется класс, то всегда можно отнаследовать и переопределить метод, что и позволит подменять реализацию зависимости не меняя код зависимого. А ещё одна из основных целей DI — упрощение юнит-тестов достигается библиотекой моков, которая генерит наследников сама.
Код с DI можно писать с классами изначально, а если реально возникает потребность подставлять разные зависимости, то делается элементарный рефакторинг "extract interface", который тоже не затрагивает код зависимого. OCP и всё такое.

IT> На эту тему можно почитать хотя бы ту же википедию.

Там говорится interface contracts, который может быть определён и как набор публичных методов класса, а не только как ключевое слово interface.

IT>>> Бизнес логика разбивается на части и разносится по разным частям приложения. Это затрудняет модификацию приложения.

.>>А можно пример? Каким образом тут DI приплетён? Если вдруг после того как зависимости стали делать управляемыми, ВНЕЗАПНО стало заметно, что у какого-то класса 50 зависимостей, 10000 строк кода и 0 юнит-тестов, то это не вина DI.
IT>При чём тут количество зависимосей, объём коди и юнит тесы?
А можно не игнорировать вопросы? Эти три вещи в большинстве случаев и затрудняют модификацию приложения, а не DI. А то получается "отравился печенюшкой".

IT>>>А всегда ли это нужно?

.>>Чаще чем не нужно, если ты пишешь что-то сложнее, чем фреймворк для умножения двух чисел
Автор: IT
Дата: 13.10.13
.

IT>Я уже устал от таких аргументов. Особенно когда под сложностью понимают не сложность задачи, а сложность собственной имплементации, которая в результате образовывается в том числе и из-за использования DI.
А я не понимаю таких примеров, больше на троллинг похоже.
Вопрос о том как управлять зависимостями, а ответ — перепишем код так, что зависимости где-то там, уличная магия какая-то.
Давай вот тут: http://code.google.com/p/google-guice/wiki/Motivation как ты переделаешь "по правильному, без DI"?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[15]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 25.10.13 00:43
Оценка:
Здравствуйте, ., Вы писали:

.>Давай вот тут: http://code.google.com/p/google-guice/wiki/Motivation как ты переделаешь "по правильному, без DI"?


Вот! Молодец! Более тупейшего применения DI я в жизни не видел (хотя такое же видел не раз). Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод. И больше НИЧЕГО. Вся бизнес логика, которую и нужно в конце концов тестировать тупо подменена фэйк-методами. Я фигею с вас, ребята
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[15]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.10.13 10:01
Оценка:
Здравствуйте, ., Вы писали:

.>Что-то мне кажется, что все эти нападки направлены на что угодно, но не DI. DI это очень тривиальный и маленький паттерн, альтернативы ему — сложнее или кривее.

.>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.

Пример как то так себе, одна мешанина непойми чего заменилась на другую мешанину непойми чего, но на DI
Re[16]: своё vs. сторонее
От: AndrewJD США  
Дата: 25.10.13 10:20
Оценка:
Здравствуйте, Ikemefula, Вы писали:

.>>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.


I>Пример как то так себе, одна мешанина непойми чего заменилась на другую мешанину непойми чего, но на DI

А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?
"For every complex problem, there is a solution that is simple, neat,
and wrong."
Re[17]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.10.13 10:36
Оценка:
Здравствуйте, AndrewJD, Вы писали:

I>>Пример как то так себе, одна мешанина непойми чего заменилась на другую мешанину непойми чего, но на DI

AJD>А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?

Прежде всего я бы постарался избавиться от самого BillingService. В том виде, как он подан, вообще неочевидно, что он нужен как отдельный класс.
Вообще рассуждать про DI на примере одного метода с линейной логикой как то странно. Пример ничем не лучше уже показаного сделать суммирующего сервиса
Нужно как минимум смотреть что представляет из себя вызывающий код.
Re[16]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 10:43
Оценка:
Здравствуйте, IT, Вы писали:

.>>Давай вот тут: http://code.google.com/p/google-guice/wiki/Motivation как ты переделаешь "по правильному, без DI"?

IT>Вот! Молодец! Более тупейшего применения DI я в жизни не видел (хотя такое же видел не раз). Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. А кроме эмоций есть что сказать?
Покажи класс.

IT>Он тестирует умение компилятора вызывать виртуальный метод. И больше НИЧЕГО.

Что мелочиться-то? Пиши сразу: "тестирует умение компьютера выполнять код. И больше НИЧЕГО".

IT>Вся бизнес логика, которую и нужно в конце концов тестировать тупо подменена фэйк-методами. Я фигею с вас, ребята

PaypalCreditCardProcessor скажем тупо посылает http запрос и читает результат. DatabaseTransactionLog делает insert в БД. Это что-ли бизнес-логика? Предлагаешь jdk http client потестировать или протокол http?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[18]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 11:16
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>>>Пример как то так себе, одна мешанина непойми чего заменилась на другую мешанину непойми чего, но на DI

AJD>>А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?
I>Прежде всего я бы постарался избавиться от самого BillingService. В том виде, как он подан, вообще неочевидно, что он нужен как отдельный класс.
I>Вообще рассуждать про DI на примере одного метода с линейной логикой как то странно. Пример ничем не лучше уже показаного сделать суммирующего сервиса
I>Нужно как минимум смотреть что представляет из себя вызывающий код.
Это же минимальный пример. Не обращай внимание на маленькое количество кода. Представь что в этом сервисе есть ещё несколько методов, например "отмена заказа" и т.п., логика помещения заказа может быть сложнее, например, посылать email уведомления, проверять доступность скидок и т.п. Т.е. сервис нам нужен.
И обрати внимание что этот класс соответствует бизнес-сущности "биллинг". Можно, конечно, сказать что нафиг это всё и писать всё в main-методе или onclick_button, но вроде это не самая лучшая практика.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.10.13 12:34
Оценка:
Здравствуйте, ., Вы писали:

AJD>>>А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?

I>>Прежде всего я бы постарался избавиться от самого BillingService. В том виде, как он подан, вообще неочевидно, что он нужен как отдельный класс.
I>>Вообще рассуждать про DI на примере одного метода с линейной логикой как то странно. Пример ничем не лучше уже показаного сделать суммирующего сервиса
I>>Нужно как минимум смотреть что представляет из себя вызывающий код.
.>Это же минимальный пример. Не обращай внимание на маленькое количество кода. Представь что в этом сервисе есть ещё несколько методов, например "отмена заказа" и т.п., логика помещения заказа может быть сложнее, например, посылать email уведомления, проверять доступность скидок и т.п. Т.е. сервис нам нужен.

С таким подходом все сводится к "предположим, DI нужен, следовательно, DI нужен"

.>И обрати внимание что этот класс соответствует бизнес-сущности "биллинг". Можно, конечно, сказать что нафиг это всё и писать всё в main-методе или onclick_button, но вроде это не самая лучшая практика.


Это неважно, чем он соответсвует. Важно как эта сущность используется с другими сущностями, т.е. как строится вызывающий код.
Re[12]: своё vs. сторонее
От: Baudolino  
Дата: 25.10.13 14:30
Оценка:
Здравствуйте, IT, Вы писали:

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


B>>Вы тесты в своей жизни когда-нибудь писали?

IT>Ты что-то хотел сказать?
Я задал вопрос. Ответ будет?
Re[15]: своё vs. сторонее
От: Abalak США  
Дата: 25.10.13 15:03
Оценка:
Здравствуйте, ., Вы писали:

.>Допустим, что было спроектировано криво, костылесовместимость решений от M$ всегда высока, поубивав бы. Но тебе понадобился лишь элементарный рефакторинг с минимальным импактом, чтобы это поправить. Если бы не было явного DI, то скорее всего была бы мешанина ещё более кривых архитектурных решений, такие как рассыпанные по всему коду класса операторы new, глобальные синглтоны, статические фабрики, магические контексты и прочий шлак, рефакторинг которого довльно сложная задача со слабо предсказуемыми последствиями.


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

.>Главное не избегать заранее кривое проектирование (это утопия), а минимизировать последствия неудачного проектирования. Судя по тому, что ты написал, DI в этом помогло отлично.


Нет, смотри, сущность объекта я описал — лезть в базу и исполнять код, который лежит тоже в базе и вернуть данные. Он не должен вообще не от чего зависить, его нужно создать и использовать, не заботясь в каком контексте он выполняется. DI тут ничем не помог, ну никак.

.>Я не знаю как там в C# мире, но в Яве чтобы минимально заюзать DI нужно добавить ~500k либу и написать пол дюжины строк кода. И объём этого кода будет явно меньше, чем если бы конфигурировал эти все вызовы вручную.


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

.>Понимаю, можно что угодно нагородить где угодно, но DI в этом скорее будет мешать.

.>Не понимаю из твоего рассказа почему ты решил, что эта проблема вызвана DI.

Потому что, его туда притащили не понятно зачем и завязали объект на совсем независимые от него сущности.

.>Что-то мне кажется, что все эти нападки направлены на что угодно, но не DI. DI это очень тривиальный и маленький паттерн, альтернативы ему — сложнее или кривее.


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

.>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.


Я бы решил на интерфейсах. Но опять же, это то, о чем я говорил выше — отличие теории от практики.
Re[20]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 15:16
Оценка:
Здравствуйте, Ikemefula, Вы писали:

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


AJD>>>>А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?

I>>>Прежде всего я бы постарался избавиться от самого BillingService. В том виде, как он подан, вообще неочевидно, что он нужен как отдельный класс.
I>>>Вообще рассуждать про DI на примере одного метода с линейной логикой как то странно. Пример ничем не лучше уже показаного сделать суммирующего сервиса
I>>>Нужно как минимум смотреть что представляет из себя вызывающий код.
.>>Это же минимальный пример. Не обращай внимание на маленькое количество кода. Представь что в этом сервисе есть ещё несколько методов, например "отмена заказа" и т.п., логика помещения заказа может быть сложнее, например, посылать email уведомления, проверять доступность скидок и т.п. Т.е. сервис нам нужен.
I>С таким подходом все сводится к "предположим, DI нужен, следовательно, DI нужен"
Где это у меня было DI? Это ты всё в каждом предложении упоминаешь. Я лишь сказал, что нужен некий BillingService.

.>>И обрати внимание что этот класс соответствует бизнес-сущности "биллинг". Можно, конечно, сказать что нафиг это всё и писать всё в main-методе или onclick_button, но вроде это не самая лучшая практика.

I>Это неважно, чем он соответсвует. Важно как эта сущность используется с другими сущностями, т.е. как строится вызывающий код.
Да какая разница? Допустим он вызывается из servlet.onPost, парся всякие пост-параметры заказа. И, например, обрабатывает заказы из входящих емейлов/смскок.
Предложи свое видение.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[16]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 15:32
Оценка:
Здравствуйте, Abalak, Вы писали:

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


.>>Допустим, что было спроектировано криво, костылесовместимость решений от M$ всегда высока, поубивав бы. Но тебе понадобился лишь элементарный рефакторинг с минимальным импактом, чтобы это поправить. Если бы не было явного DI, то скорее всего была бы мешанина ещё более кривых архитектурных решений, такие как рассыпанные по всему коду класса операторы new, глобальные синглтоны, статические фабрики, магические контексты и прочий шлак, рефакторинг которого довльно сложная задача со слабо предсказуемыми последствиями.

A>Вот далеко не факт. Об этом сложно судить, но оправдывать существование одного говнокода вероятностью написания другого как минимум странно
Может не надо философстовать? А то тогда уж — весь код говно. И что же делать? Остаётся лишь надеется, что с каким-то говном проще возиться...

.>>Главное не избегать заранее кривое проектирование (это утопия), а минимизировать последствия неудачного проектирования. Судя по тому, что ты написал, DI в этом помогло отлично.

A>Нет, смотри, сущность объекта я описал — лезть в базу и исполнять код, который лежит тоже в базе и вернуть данные. Он не должен вообще не от чего зависить, его нужно создать и использовать, не заботясь в каком контексте он выполняется. DI тут ничем не помог, ну никак.
База — уже зависимость. А значит уже забота. Понимаю, что можно всё захардкодить... но нужно ли?

.>>Я не знаю как там в C# мире, но в Яве чтобы минимально заюзать DI нужно добавить ~500k либу и написать пол дюжины строк кода. И объём этого кода будет явно меньше, чем если бы конфигурировал эти все вызовы вручную.

A>Ну в туториалах так же, а вот в реальном мире получается редкостная колбаса, подозреваю, что ява недалеко ушла.
IoC-контейнеры в .net пришли из Явы...

.>>Понимаю, можно что угодно нагородить где угодно, но DI в этом скорее будет мешать.

.>>Не понимаю из твоего рассказа почему ты решил, что эта проблема вызвана DI.
A>Потому что, его туда притащили не понятно зачем и завязали объект на совсем независимые от него сущности.
Что значит "завязали"? И как его отвязать? Захардкодить new DependencyImpl в объект?

.>>Что-то мне кажется, что все эти нападки направлены на что угодно, но не DI. DI это очень тривиальный и маленький паттерн, альтернативы ему — сложнее или кривее.

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

.>>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.

A>Я бы решил на интерфейсах. Но опять же, это то, о чем я говорил выше — отличие теории от практики.
Что значит "на интерфейсах"? Там как раз интерфейсы почти везде. Давай, показывай свою практику, хватит теоретизировать.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.10.13 15:47
Оценка:
Здравствуйте, ., Вы писали:

.>>>Это же минимальный пример. Не обращай внимание на маленькое количество кода. Представь что в этом сервисе есть ещё несколько методов, например "отмена заказа" и т.п., логика помещения заказа может быть сложнее, например, посылать email уведомления, проверять доступность скидок и т.п. Т.е. сервис нам нужен.

I>>С таким подходом все сводится к "предположим, DI нужен, следовательно, DI нужен"
.>Где это у меня было DI? Это ты всё в каждом предложении упоминаешь. Я лишь сказал, что нужен некий BillingService.

Для BillingService не нужен никакой DI, максимум, что можно показать на ём, это Inversion of Control, т.е. вынести все лишние депенденсы куда нибудь наверх. Больше ничего на этом сервисе показать не удастся.
Потому с DI остаётся всё, как было сказано: "предположим, DI нужен, следовательно, DI нужен"

I>>Это неважно, чем он соответсвует. Важно как эта сущность используется с другими сущностями, т.е. как строится вызывающий код.

.>Да какая разница? Допустим он вызывается из servlet.onPost, парся всякие пост-параметры заказа. И, например, обрабатывает заказы из входящих емейлов/смскок.
.>Предложи свое видение.

Нужно смотреть вызывающий модуль, что в ём будет.
Re[17]: своё vs. сторонее
От: maxkar  
Дата: 25.10.13 16:00
Оценка:
Здравствуйте, AndrewJD, Вы писали:

I>>Пример как то так себе, одна мешанина непойми чего заменилась на другую мешанину непойми чего, но на DI

AJD>А можно пример того как надо сделать? Т.е. задача описана по ссылке и есть несколько решений. Расскажите, как бы вы ее задизайнили?

Задача отвратительно решена. И поставлена тоже.

Начнем с теста. Он бесполезен. Конкретно его функциональность проверяется в момент интеграционного тестирования. Мало ли какой-там CreditCardProcessor затесался в сборку. Может, там Fake лежит. А интеграционное тестирование это все покажет. Причем этот сценарий "все заказывается и работает" проверяться будет обязательно — это основной пользовательский сценарий. Ну а пицца — команде в качестве бонуса за релиз.

Далее. Тест не тестирует контракт! Тест каким-то сложным и запутанным способом проверяет, что именно написано в методе. Повторяю — не что метод делает, а что именно написано! Ну вот creditCardProcessor.getCardOfOnlyCharge() есть, для примера. А что, если потом будет сделана не одна, а несколько charge? Или сначала резервирование средств на счету, а только потом списание? Ведь "в реальной жизни" в этом creditCardProcessor куча разных методов. И некоторые вещи на самом деле можно реализовать несколькими способами. Ту же продажу, например. Так что корректно замокать этого монстрика — то еще приключение. Можно внедрить ревью кода для проверки подобных реализаций, это будет гораздо проще.

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

Сама сигнатура метода странная. Зачем там order, если используется только amount? И самая интересная вещь в виде Receipt не инжектится. Это вообще должна быть generic service, параметризованная типом Receipt.

Решение использовать Guice — тоже странное. Автор сам себя ведь выше опроверг. В пункте factory. Вы думаете, что Guice — делает что-то похожее на "dependency injection"? Нет. Это service locator в практически чистом виде, что ближе к factory. Смотрите, легкое движение руками и пример с инжектором превращается в
  public RealBillingService(Injector injector) {
    this.processor = injector.lookup(CreditCardProcessor.class);
    this.transactionLog = injector.lookup(TransactionLog.class, "realBillingTransactionLog");
  }

Второе поле — это эквивалент @Named. Я вот не понимаю, в чем крутость передавать парметры так, вместо ручной передачи через конструкторы? Как только возникает что-нибудь нетривиальное, подход с guice превращается в макароны. А что-нибудь нетривиальное возникает очень и очень легко. Например, у меня в приложении есть простенький интерфейс для кэша. Штуки три его реализации (с разными политиками). И десяток экземпляров (разные сущности, используются в разных местах). Вопрос — ну и как их инжектить? Можно взять что-нибудь менее service-locator-подобное. Какой-нибудь spring. И написать километры xml. А смысл? Можно написать те же километры кода (причем они будут короче, чем xml). А ведь можно взять scala, с помощью implicits делается аналог autowired. И при этом я в коде не ограничен условностями, могу обертки вокруг класса создать, могу метод написать (у меня сервлеты регистрируются с навеской нужных фильтров и конверторов подобным образом).

Ладно, переходим к самому интересному. BillingService не нужен. И вообще любые *Service не нужны. Да, именно не нужны. Если у нее действительно один метод, то это не service, это какой-нибудь банальный BuyProcessor. А если методов много, то службой никто в полной мере не пользуется. Она только создает лишние зависимости. Какой-то класс пользуется двумя методами из службы. Какой-то — другими тремя. И никто — всем набором методов. Зато мокать это безобразие с кучей методов — одно "удовольствие". А мокать нужно, ведь класс, зависящий от BillingService может потом изменить реализацию и использовать другие (эквивалентные) методы.

Обратите внимание, в предыдущем абзаце я описал интересный факт. Интерфейс служб зависит от нужд вышележащего уровня, а не нижележащего! Т.е. "низкоуровневая" служба может реализовывать несколько интерфейсов "более высокого" уровня. А иначе у вас какое-то безобразие получается. С одной стороны, вы хотите изолировать зависимость (и для этого как раз нормально вводить интерфейс). С другой, этот интерфейс для разделения определяется не "точкой разреза между слоями" ("cut point") а интерфейсом реализации. Те методы, которые реализует ваша RealBillingService и попадут в в BillingService. Это вообще что такое? Интерфейсы ради интерфейсов. И ведь не отрежешь — новая реализация BillingService будет похожа на RealBillingService, о какой слабой связности идет речь?

Теперь о том, как делать правильно. Где-то рядом уже правильно заметили, что интерфейс может быть и не нужен. Где пользователь этого интерфейса? Какой-нибудь обработчик веб-запросов или кликов на кнопку? А в чем великий смысл выделять интерфейс для BillingService и в нее выносить 10 тривиальных строчек? Я эти десять строчек в том фронт-контроллере размещу (в отдельном методе). Или тот обработчик будет еще с каким-то другим BillingService работать? Как-то я сомневаюсь пока, да и имя должно быть в этом случае другое (это buyProcessor). Для тестирования формата ответа фронтенда? Но, опять же, какой смысл в тестах? Интеграционное тестирование проверит и формат ответа, и работоспособность метода. Ну и пиццу даст в качестве бонуса.

Ладно, еще одно соображение. Есть несколько пользователей этого метода. Но, опять же, зачем выделять интерфейс? Можно статический метод сделать, куда передавать нужные зависимости. А можно и выделить интерфейс. И сделать одну большую службу, которая реализует много разных интерфейсов (BuyProcessor, OrderCancellingProcessor, и т.п.). Или можно сделать одну большую службу и передать ее в пользователей. Какая разница (если только не ставить задачу зачем-то протестировать все юниты)?

Итого. В самом простейшем случае вся реализация RealBillingService.chargeOrder уйдет во front controller. С большой вероятностью, туда же уйдет и TransactionLog.logChargeResult, хотя все зависит от того, как реализован этот метод. CreditCardProcessor останется интерфейсом (может быть, порезанным на мелочи вроде CreditCardAcquirer), потому как там функциональность большая, сложная и подверженная изменению. Инжектится он будет в конструкторе фронт-контроллера (самый простой и надежный способ). Учитывая, предыдущие упрощения, останется не так много сервисов. Придется инжектить: CreditCardProcessor, PizzaFactory, GlobalLog, UserManager, несколько справочников. Причем это список на все фронт-контроллеры, а не только на один конкретный.

P.S.
Я уже выше отмечал, что зависимость на Receipt в данном случае отвратительна. Поэтому небольшое упражнение на понимание DI и умение пользоваться ими. Поправим код метода.
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    long receiptId = receiptIdGenerator.???; //Здесь
    transactionLog.logReceiptProcessing(receiptId, order, creditCard);
    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(receiptId, result);

      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(receiptId, order.getAmount())
          : Receipt.forDeclinedCharge(receiptId, result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(receiptId, e.getMessage());
    }
  }

Вот такой новый код. Нужно дописать вызов метода для генерации Id, интерфейс/класс, который имеет receiptIdGenerator (название и члены класса), и то, как именно способом вы его хотите инжектить в BillingService.
Re[22]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 16:17
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Для BillingService не нужен никакой DI, максимум, что можно показать на ём, это Inversion of Control, т.е. вынести все лишние депенденсы куда нибудь наверх. Больше ничего на этом сервисе показать не удастся.

Ну покажи, посмотрим.
DI это один из вариантов реализации IoC для зависимостей. Есть ещё SL, ну и глобальные переменные. Так что ты предлагаешь-то?

I>Потому с DI остаётся всё, как было сказано: "предположим, DI нужен, следовательно, DI нужен"

I>>>Это неважно, чем он соответсвует. Важно как эта сущность используется с другими сущностями, т.е. как строится вызывающий код.
.>>Да какая разница? Допустим он вызывается из servlet.onPost, парся всякие пост-параметры заказа. И, например, обрабатывает заказы из входящих емейлов/смскок.
.>>Предложи свое видение.
I>Нужно смотреть вызывающий модуль, что в ём будет.
class PizzaOrderServlet extends HttpServlet
{
    @Inject BillingService billingService;

    @Override public void onPost(HttpRequest request, HttpResponse response)
    {
       PizzaOrder order = parseOrder(request);
       CreditCard cc = parseCreditCard(request);
       Receipt recepit = billingService.chargeOrder(order, cc);
       writeRecepit(receipt, response);
    }
    private PizzaOrder parseOrder(HttpRequest request)
    {
      /// parse and validate data from request and return new PizzaOrder
    }
...parseCreditCard, writeRecepit....
}

аналогично для емейлов и т.п.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[21]: своё vs. сторонее
От: maxkar  
Дата: 25.10.13 16:26
Оценка:
Здравствуйте, ., Вы писали:

.>>>И обрати внимание что этот класс соответствует бизнес-сущности "биллинг". Можно, конечно, сказать что нафиг это всё и писать всё в main-методе или onclick_button, но вроде это не самая лучшая практика.

I>>Это неважно, чем он соответсвует. Важно как эта сущность используется с другими сущностями, т.е. как строится вызывающий код.
.>Да какая разница? Допустим он вызывается из servlet.onPost, парся всякие пост-параметры заказа. И, например, обрабатывает заказы из входящих емейлов/смскок.
.>Предложи свое видение.

Это важно! Это очень важно. Если у вас только один транспорт, можно все заинлайнить. Это нормально.

Если же транспортов несколько, возможны варианты. Либо все ваши транспорты (http/email/sms) — придатки к одному приложению. В этом случае они зависят не от конкретных служб, а от большого фасада Application, который предоставляет все возможные функции. Это вполне конкретный класс, который внутри реализует все, что нужно. Возможно — вызывая другие службы. Возможно — своими методами.

А еще есть ненулевая вероятность, что в случае нескольких транспортов BillingService.chargeOrder будет заинлайнен в соответствующие фронтенды. По одной банальной причине — это слишком общий интерфейс для биллинга. Для "onClick" пользователь может определяться авторизацией на сайте. Для sms — номером телефона. Как вы их будете в transactionLog представлять? А еще, вероятно, в бизнес-требованиях будет задача разделять различные источники заказов для построения статистики. Кто их будет строить? Как? Вы научите BillingService/TransactionLog различать разные типы пользователей из order? Или это будут разные логгеры (и разные billing service)?

При инлайне в обработчики все станет гораздо лучше. Мы будем иметь нужный тип логгера в обработчике. Вот CreditCardProcessor может быть заинжектен в разные реализации, он имеет смысл. А BillingProcessor — слишком тривиален и слишком нестабилен по функциональности. А еще плохо расширяем. Что, если одним из способов платежа для sms будет списание с баланса телефона? Для sms-гейта это будет вызов другого "payment provider" (с другим интерфейсом), а основная обвязка вроде логирования останется общая.

И еще один интересный факт. Очень хорошо заметный на нескольких транспортах. Существующий код занимается переливанием из пустого в порожнее. Сначала упаковывает все коды в Receipt. Затем во frontend'е его if'ами/case'ами распаковывает. Если мы получили UnreacheableException (почему оно, кстати???), то на фронтенде мы можем сразу ответ начать выдавать, вместо заворачиванием этого исключения в красивую обертку. Ну и receipt в текущем виде становится странным. Там появляются хитрые варианты вроде "это вроде бы и receipt, но он не на покупку, а на системную ошибку". Его теперь приходится везде проверять на валидность.
Re[23]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.10.13 17:00
Оценка:
Здравствуйте, ., Вы писали:

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


I>>Для BillingService не нужен никакой DI, максимум, что можно показать на ём, это Inversion of Control, т.е. вынести все лишние депенденсы куда нибудь наверх. Больше ничего на этом сервисе показать не удастся.

.>Ну покажи, посмотрим.
.>DI это один из вариантов реализации IoC для зависимостей. Есть ещё SL, ну и глобальные переменные. Так что ты предлагаешь-то?

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

I>>Нужно смотреть вызывающий модуль, что в ём будет.

.>
.>class PizzaOrderServlet extends HttpServlet
.>{
.>    @Inject BillingService billingService;

.>    @Override public void onPost(HttpRequest request, HttpResponse response)
.>    {
.>       PizzaOrder order = parseOrder(request);
.>       CreditCard cc = parseCreditCard(request);
.>       Receipt recepit = billingService.chargeOrder(order, cc);
.>       writeRecepit(receipt, response);
.>    }
.>    private PizzaOrder parseOrder(HttpRequest request)
.>    {
.>      /// parse and validate data from request and return new PizzaOrder
.>    }
.>...parseCreditCard, writeRecepit....
.>}
.>

.>аналогично для емейлов и т.п.

Твой onPost объявлен, внимание, в конкретном модуле, то есть, прибит к нему гвоздями.

Вот, по ссылке
public class BillingModule extends AbstractModule {
  @Override 
  protected void configure() {
    bind(TransactionLog.class).to(DatabaseTransactionLog.class);  
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);
    bind(BillingService.class).to(RealBillingService.class);
  }
}


Все параметры биндов, внимание, это жосткие зависимости
То есть, модуль, гвоздями прибит к депенденсам.
Вот уже здесь произошел фейл — смысла в DI в данном примере нет и быть не может. Что вобщем то очевидно, у DI масштаб на порядок побольше, чем один твой onPost.
Re[13]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 25.10.13 17:41
Оценка:
Здравствуйте, Baudolino, Вы писали:

B>>>Вы тесты в своей жизни когда-нибудь писали?

IT>>Ты что-то хотел сказать?
B>Я задал вопрос. Ответ будет?

Смысл отвечать на риторику. Тебя же мой ответ всё равно не интересует. Иначе бы ты внимательнее почитал бы топик и сам бы нашёл ответ.
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[16]: своё vs. сторонее
От: fddima  
Дата: 25.10.13 20:20
Оценка:
Здравствуйте, IT, Вы писали:

IT>Понятно. Стандартная отмазка. Впрочем, не очень то и хотелось ни твоего кода, ни уж тем более к тебе на работу.

Тут пол форума NDA, так что +1. Если хочешь что-то доказать — показывай код.

PS: Я тут на днях пробовал к linq2db прикрутить csharp-sqlite (полностью мэнэджет/шарповый порт) — заработало блин, без модификации самого linq2db, с добавлением мелкого провайдера на 10 строк. Мега классная штука. Позже, возможно стоит добавть как-то в общую копилку. (поностью шарповый sqlite годен тем, когда ты на asp.net непонятно где и непонятно с кем и тупо для эмулятора сервиса например, по крайей мере так я его применяю). С нативом не так удобно (залочены длл, если приложение запущено).
Re[18]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 20:59
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Задача отвратительно решена. И поставлена тоже.

M>Начнем с теста. Он бесполезен. Конкретно его функциональность проверяется в момент интеграционного тестирования.
Это называется юнит-тест. Спор юнит-тест vs инт-тест я затевать не хочу. Что такое юнит-тестирование я рассказывать не буду. Если хочется восполнить пробел в знаниях, материала в инете полно.

M>Мало ли какой-там CreditCardProcessor затесался в сборку. Может, там Fake лежит. А интеграционное тестирование это все покажет.

Жуть какая. Ну не используйте тогда "кривые" фреймворки от M$, или руки выпрямляйте. В guice это явно выражается ровно одной строчкой кода, нет никакой магии, всё выражается явно, читай ту ссылку:
    bind(CreditCardProcessor.class).to(PaypalCreditCardProcessor.class);


М>Причем этот сценарий "все заказывается и работает" проверяться будет обязательно — это основной пользовательский сценарий. Ну а пицца — команде в качестве бонуса за релиз.

Конечно. Но это не отменяет ценность юнит-теста.

M>Далее. Тест не тестирует контракт! Тест каким-то сложным и запутанным способом проверяет, что именно написано в методе. Повторяю — не что метод делает, а что именно написано! Ну вот creditCardProcessor.getCardOfOnlyCharge() есть, для примера. А что, если потом будет сделана не одна, а несколько charge? Или сначала резервирование средств на счету, а только потом списание? Ведь "в реальной жизни" в этом creditCardProcessor куча разных методов. И некоторые вещи на самом деле можно реализовать несколькими способами. Ту же продажу, например. Так что корректно замокать этого монстрика — то еще приключение. Можно внедрить ревью кода для проверки подобных реализаций, это будет гораздо проще.

Ну-ну. А потом неудачный рефакторинг, опечатка и посыпалось. Ревью — ручное, а юнит-тесты — автоматические.
Короче, рекомендую изучить юнит-тестирование.

M>Еще стоит вспомнить, что для данного метода нужно бы какую-нибудь транзакционность проверять.

Ага, и чтобы этот метод ещё и кофе варил.

M>Сама сигнатура метода странная. Зачем там order, если используется только amount? И самая интересная вещь в виде Receipt не инжектится. Это вообще должна быть generic service, параметризованная типом Receipt.

Ну вот такя имплементация, пользоваться уже можно. Потом можно дописывать, например по составу заказа сделать текстовое описание и послать как description для платежа.
Receipt это просто данные, зачем его инжектить?
DI плохо, а зато generic пихать где попало, так пожалуйста...
Это же просто демо-проект. В реальном коде там будет побольше строчек, конечно.

M>Решение использовать Guice — тоже странное. Автор сам себя ведь выше опроверг. В пункте factory. Вы думаете, что Guice — делает что-то похожее на "dependency injection"? Нет. Это service locator в практически чистом виде, что ближе к factory.

Так DI же и делает. Видимо ты не понял что-ли что там происходит, т.к. в классе RealBillingService что-то относящееся к guice это только @Inject (т.е. ровно одна лексема!).

M>Смотрите, легкое движение руками и пример с инжектором превращается в

M>
M>    this.processor = injector.lookup(CreditCardProcessor.class);
M>

Конечно можно превратить. guice предоставляет и SL, только здесь лучше всё-таки DI.

M>Второе поле — это эквивалент @Named. Я вот не понимаю, в чем крутость передавать парметры так, вместо ручной передачи через конструкторы? Как только возникает что-нибудь нетривиальное, подход с guice превращается в макароны.

Можно и вручную передавать, в главе "Dependency Injection" это и показано как. Но guice делается ровно то же, но автоматически.

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

Это нетривиально потому что ты вручную делаешь. Для guice — тривиально. http://code.google.com/p/google-guice/wiki/BindingAnnotations

M> Можно взять что-нибудь менее service-locator-подобное. Какой-нибудь spring. И написать километры xml. А смысл? Можно написать те же километры кода (причем они будут короче, чем xml). А ведь можно взять scala, с помощью implicits делается аналог autowired. И при этом я в коде не ограничен условностями, могу обертки вокруг класса создать, могу метод написать (у меня сервлеты регистрируются с навеской нужных фильтров и конверторов подобным образом).

Ну собственно в guice как раз xml и не испольуется, и как IoC он на порядок лучше того же spring, так как продумывался именно для этого и с учётом ошибок спринга.
Скалу не обсуждаю... язык другой, там всё по другому может выглядеть. Guice писался для явы и на неё заточен с учётом её особенностей.

M>Ладно, переходим к самому интересному. BillingService не нужен. И вообще любые *Service не нужны. Да, именно не нужны. Если у нее действительно один метод, то это не service, это какой-нибудь банальный BuyProcessor. А если методов много, то службой никто в полной мере не пользуется. Она только создает лишние зависимости. Какой-то класс пользуется двумя методами из службы. Какой-то — другими тремя. И никто — всем набором методов.

Как интерфейс, скорее всего, он не нужен. Но сути не меняет. Пусть будет класс BillingService. И пусть он называется BuyProcessor. Что это меняет?

M> Зато мокать это безобразие с кучей методов — одно "удовольствие". А мокать нужно, ведь класс, зависящий от BillingService может потом изменить реализацию и использовать другие (эквивалентные) методы.

Не понял. Это тоже тривиально. Или в .net нет аналогов mockito/easymock/jmock/etc?

M>Обратите внимание, в предыдущем абзаце я описал интересный факт. Интерфейс служб зависит от нужд вышележащего уровня, а не нижележащего! Т.е. "низкоуровневая" служба может реализовывать несколько интерфейсов "более высокого" уровня. А иначе у вас какое-то безобразие получается. С одной стороны, вы хотите изолировать зависимость (и для этого как раз нормально вводить интерфейс). С другой, этот интерфейс для разделения определяется не "точкой разреза между слоями" ("cut point") а интерфейсом реализации. Те методы, которые реализует ваша RealBillingService и попадут в в BillingService. Это вообще что такое? Интерфейсы ради интерфейсов. И ведь не отрежешь — новая реализация BillingService будет похожа на RealBillingService, о какой слабой связности идет речь?

Забудь RealBillingService, для простоты можешь его переименовать в BillingService, а BillingService выкинуть, это же тривиальный рефакторинг "inline interface". Что изменится? Если же потом понадобится ещё одна реализация, сделаешь "extract interface" рефакторинг.

M>Теперь о том, как делать правильно. Где-то рядом уже правильно заметили, что интерфейс может быть и не нужен. Где пользователь этого интерфейса? Какой-нибудь обработчик веб-запросов или кликов на кнопку? А в чем великий смысл выделять интерфейс для BillingService и в нее выносить 10 тривиальных строчек? Я эти десять строчек в том фронт-контроллере размещу (в отдельном методе). Или тот обработчик будет еще с каким-то другим BillingService работать? Как-то я сомневаюсь пока, да и имя должно быть в этом случае другое (это buyProcessor). Для тестирования формата ответа фронтенда? Но, опять же, какой смысл в тестах? Интеграционное тестирование проверит и формат ответа, и работоспособность метода. Ну и пиццу даст в качестве бонуса.

Пользователей может быть несколько — один web-site, крутится в облаке, один обработчик смс — на специальном серваке с gsm-модемом, и т.п. Класс один — контексты очень разные.

M>Ладно, еще одно соображение. Есть несколько пользователей этого метода. Но, опять же, зачем выделять интерфейс?

Не хочешь — не выделяй, никто не заставляет.

M>Можно статический метод сделать, куда передавать нужные зависимости.

А там их откуда брать? Из тумбочки? А что если понадобится добавить ещё одну зависимость, например, отсылалку email-уведомлений в биллинг? В скольких местах придётся вызов этого статического метода менять, протаскивая EmailService в кучу мест?

M>А можно и выделить интерфейс. И сделать одну большую службу, которая реализует много разных интерфейсов (BuyProcessor, OrderCancellingProcessor, и т.п.). Или можно сделать одну большую службу и передать ее в пользователей. Какая разница (если только не ставить задачу зачем-то протестировать все юниты)?

Да пожалуйста, кто не даёт?

M>Итого. В самом простейшем случае вся реализация RealBillingService.chargeOrder уйдет во front controller. С большой вероятностью, туда же уйдет и TransactionLog.logChargeResult, хотя все зависит от того, как реализован этот метод. CreditCardProcessor останется интерфейсом (может быть, порезанным на мелочи вроде CreditCardAcquirer), потому как там функциональность большая, сложная и подверженная изменению.

M>Инжектится он будет в конструкторе фронт-контроллера (самый простой и надежный способ).
Опа! Т.е. если инжектить зависимость, но не называть это Dependency Injection, то это сразу становится хорошим и правильным способом? А ты случайно не заметил, что в главе "Dependency Injection with Guice" ровно это и сделано?

M>Учитывая, предыдущие упрощения, останется не так много сервисов. Придется инжектить: CreditCardProcessor, PizzaFactory, GlobalLog, UserManager, несколько справочников. Причем это список на все фронт-контроллеры, а не только на один конкретный.

И то же самое в SmsOrderProcessor... и везде. А инжектить будем магией, но главное всем молчать и не произносить "DI".

M>Вот такой новый код. Нужно дописать вызов метода для генерации Id, интерфейс/класс, который имеет receiptIdGenerator (название и члены класса), и то, как именно способом вы его хотите инжектить в BillingService.

Не понял. Что в этом коде нового?
receiptIdGenerator вообще новая сущность, будем считать что оно не нужно. Зачем ты её ввёл? В постановке задачи этого не было. Может быть оно будет браться из ChargeResult, какой-нибудь transaction reference.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re: своё vs. сторонее
От: fddima  
Дата: 25.10.13 21:23
Оценка:
Здравствуйте, CEMb, Вы писали:

Своё vs сторонее — посмотрите на TypeScript — модно, красиво, плагины к студии... но внтури — убожество.
Основная проблема JS -- отсутствие модульности. С TS — она как не была решена, так и её нет, под всяческими предлогами.
Я знаю как минимум 3 фрейворка где она решена. Dojo, Google Closure и приватный свой. Вот и думай — своё или стороннее.
При чём одно — не заменяет другое. Замкнутный круг... Но в целом — подход — хочешь хорошо — сделай сам — он как-то по жизни работает.
Re[22]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 21:38
Оценка:
Здравствуйте, maxkar, Вы писали:

M>Это важно! Это очень важно. Если у вас только один транспорт, можно все заинлайнить. Это нормально.

Никто не спорит. Но допустим транспорт не один.

M>Если же транспортов несколько, возможны варианты. Либо все ваши транспорты (http/email/sms) — придатки к одному приложению.

Может к одному, может ко многим: одно http — в облаке летает, sms на спец сервере со спец железкой, gsm-модемом...

M>В этом случае они зависят не от конкретных служб, а от большого фасада Application, который предоставляет все возможные функции. Это вполне конкретный класс, который внутри реализует все, что нужно. Возможно — вызывая другие службы. Возможно — своими методами.

God object? Увольте. guice предлагает связываение делать в виде небольших обозримых модулей, с которыми можно делать композицию в бОльшие модули.

M>А еще есть ненулевая вероятность, что в случае нескольких транспортов BillingService.chargeOrder будет заинлайнен в соответствующие фронтенды. По одной банальной причине — это слишком общий интерфейс для биллинга. Для "onClick" пользователь может определяться авторизацией на сайте. Для sms — номером телефона. Как вы их будете в transactionLog представлять? А еще, вероятно, в бизнес-требованиях будет задача разделять различные источники заказов для построения статистики. Кто их будет строить? Как? Вы научите BillingService/TransactionLog различать разные типы пользователей из order? Или это будут разные логгеры (и разные billing service)?

Для примера с пиццей вполне сойдёт. Сделаешь UserDetails объект, который будет иметь credentials и т.п. В общем к теме это уже не относится.

M>При инлайне в обработчики все станет гораздо лучше. Мы будем иметь нужный тип логгера в обработчике. Вот CreditCardProcessor может быть заинжектен в разные реализации, он имеет смысл. А BillingProcessor — слишком тривиален и слишком нестабилен по функциональности. А еще плохо расширяем. Что, если одним из способов платежа для sms будет списание с баланса телефона? Для sms-гейта это будет вызов другого "payment provider" (с другим интерфейсом), а основная обвязка вроде логирования останется общая.

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

M>И еще один интересный факт. Очень хорошо заметный на нескольких транспортах. Существующий код занимается переливанием из пустого в порожнее. Сначала упаковывает все коды в Receipt. Затем во frontend'е его if'ами/case'ами распаковывает. Если мы получили UnreacheableException (почему оно, кстати???), то на фронтенде мы можем сразу ответ начать выдавать, вместо заворачиванием этого исключения в красивую обертку. Ну и receipt в текущем виде становится странным. Там появляются хитрые варианты вроде "это вроде бы и receipt, но он не на покупку, а на системную ошибку". Его теперь приходится везде проверять на валидность.

Receipt просто данные, отправляемые юзеру как результат заказа, подразумевается, что этот объект просто рисуется пользователю. Вообще, не важно что там, по крайней мере в этом примере.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[24]: своё vs. сторонее
От: . Великобритания  
Дата: 25.10.13 22:01
Оценка:
Здравствуйте, Ikemefula, Вы писали:

.>>Ну покажи, посмотрим.

.>>DI это один из вариантов реализации IoC для зависимостей. Есть ещё SL, ну и глобальные переменные. Так что ты предлагаешь-то?
I>IoC это обрезание депенденсов, а не управление ими. А вот после обрезания ими можно управлять, хоть через локатор, хоть через DI, хоть через глобальные переменные, а можно и вовсе руками. Потому IoC != DI.
Ещё раз: "DI это один из вариантов реализации IoC для зависимостей". Где я говорю "="?

I>Твой onPost объявлен, внимание, в конкретном модуле, то есть, прибит к нему гвоздями.

Нет, этот сервлет тоже компонент, создаваемый с DI контейнером.

I>Все параметры биндов, внимание, это жосткие зависимости

I>То есть, модуль, гвоздями прибит к депенденсам.
I>Вот уже здесь произошел фейл — смысла в DI в данном примере нет и быть не может. Что вобщем то очевидно, у DI масштаб на порядок побольше, чем один твой onPost.
Правильно. Ибо это "модуль", т.е. декларативное описание куда кого байндить при конфигурировании приложения. В одном месте это будет веб-приложение, где с сервлетом, в другом приложении будут другие модули, собирающие приложение с SmsOrderProcessor и т.п.
Т.е. управление зависимостями происходит в одном месте, в простом декларативном коде.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[17]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 26.10.13 05:34
Оценка:
Здравствуйте, fddima, Вы писали:

F> PS: Я тут на днях пробовал к linq2db прикрутить csharp-sqlite (полностью мэнэджет/шарповый порт) — заработало блин, без модификации самого linq2db, с добавлением мелкого провайдера на 10 строк. Мега классная штука.


Дык потому что если с DI, который сосёт как трофейный пылесос, то в 10 строк точно было бы не уложиться
... << RSDN@Home 1.2.0 alpha 5 rev. 69>>
Если нам не помогут, то мы тоже никого не пощадим.
Re[16]: своё vs. сторонее
От: Baudolino  
Дата: 28.10.13 12:10
Оценка:
IT>Понятно. Стандартная отмазка. Впрочем, не очень то и хотелось ни твоего кода, ни уж тем более к тебе на работу.
А раз не хотелось, зачем спрашивать? Чего доказывать моим кодом собрался, какие выводы делать? Давай поговорим об этом: сколько килобайт, сколько строк тебе нужно для адекватного суждения? Проект с DI сюда копипастой не выложить — многобуков. Готов code review на Github сделать? Java подойдет?

P.S.Переход на личность оппонента — это один из признаков того, что в споре аргументы по существу закончились.
Re[16]: своё vs. сторонее
От: Baudolino  
Дата: 28.10.13 12:18
Оценка:
IT>Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод.
Это ошибочное утверждение, основанное на неверном прочтении исходного кода. Если одним словом, бред.
В приведенном примере тестируется последовательность из списания денег с карты, записи в лог и формирования корректного ответа. Не тестируются детали реализации каждого из шагов.
Вообще в этом треде все говорит за то, что вы не умеете писать (и читать) тесты, потому что подобные примеры разжеваны практически в каждой книжке по тестированию с объяснением того, зачем это нужно.
RTFM.
Re[17]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 29.10.13 11:13
Оценка:
Здравствуйте, Baudolino, Вы писали:

IT>>Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод.

B>Это ошибочное утверждение, основанное на неверном прочтении исходного кода. Если одним словом, бред.
B>В приведенном примере тестируется последовательность из списания денег с карты, записи в лог и формирования корректного ответа. Не тестируются детали реализации каждого из шагов.

Про какой именно пример ты говоришь ? Можно ссылкой ?

B>Вообще в этом треде все говорит за то, что вы не умеете писать (и читать) тесты, потому что подобные примеры разжеваны практически в каждой книжке по тестированию с объяснением того, зачем это нужно.

B>RTFM.

Ты вот сюда посмотри сначала
https://github.com/linq2db
https://github.com/linq2db?tab=members
Re[20]: своё vs. сторонее
От: . Великобритания  
Дата: 29.10.13 12:07
Оценка:
Здравствуйте, fddima, Вы писали:

F> Ребята. Если вы не авторы PaypalCreditCardProcessor — то вам нефиг его тестить.

А ещё мы не авторы софта для АЭС и на Эверест не поднимались, да и дядька в Киеве.

F>Если вы хоть кто-нибудь хоть когда-нибудь сталкивались с разработкой процессинга этих самых платежных карт — то вся ветка кажется смешной.

F>...
F> г) вэлком в реальный мир. DI — нихера не помогает в тестировании.
Ага, правильно. Без таблиц роутинга пиццу продавать нельзя, это закон природы, сразу после E=mc2.

F> PS: Как с эмулировать CardProcessing без DI? Слышал ли кто-нибудь о socket или http listener?

Правильно, твой код особенный, аккуратно продуман, чтобы быть нетестируемым. Ибо тестируемость кода — типичное ламерство. Настоящие Гуру создают Настоящий Код, тестировать Настоящий Код можно только в гамаке и стоя.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[18]: своё vs. сторонее
От: Baudolino  
Дата: 30.10.13 16:13
Оценка:
IT>>>Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод.
B>>Это ошибочное утверждение, основанное на неверном прочтении исходного кода. Если одним словом, бред.
B>>В приведенном примере тестируется последовательность из списания денег с карты, записи в лог и формирования корректного ответа. Не тестируются детали реализации каждого из шагов.
I>Про какой именно пример ты говоришь ? Можно ссылкой ?
https://code.google.com/p/google-guice/wiki/Motivation
Re[19]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 30.10.13 16:15
Оценка:
Здравствуйте, Baudolino, Вы писали:

IT>>>>Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод.

B>>>Это ошибочное утверждение, основанное на неверном прочтении исходного кода. Если одним словом, бред.
B>>>В приведенном примере тестируется последовательность из списания денег с карты, записи в лог и формирования корректного ответа. Не тестируются детали реализации каждого из шагов.
I>>Про какой именно пример ты говоришь ? Можно ссылкой ?
B>https://code.google.com/p/google-guice/wiki/Motivation

А, ну, всё в порядке, я спокоен
Re[17]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 30.10.13 17:38
Оценка:
Здравствуйте, Baudolino, Вы писали:

B>P.S.Переход на личность оппонента — это один из признаков того, что в споре аргументы по существу закончились.


Получается, что у тебя аргументы закончились с твоего самого первого сообщения в этой ветке.
Если нам не помогут, то мы тоже никого не пощадим.
Re[17]: своё vs. сторонее
От: IT Россия linq2db.com
Дата: 30.10.13 17:52
Оценка:
Здравствуйте, Baudolino, Вы писали:

IT>>Как ты думаешь, что тестирует этот якобы "тест"? Я тебе отвечу. Он тестирует умение компилятора вызывать виртуальный метод.

B>Это ошибочное утверждение, основанное на неверном прочтении исходного кода. Если одним словом, бред.

Бред — это этот твой пример и подобные тесты.

B>В приведенном примере тестируется последовательность из списания денег с карты, записи в лог и формирования корректного ответа. Не тестируются детали реализации каждого из шагов.


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

B>Вообще в этом треде все говорит за то, что вы не умеете писать (и читать) тесты, потому что подобные примеры разжеваны практически в каждой книжке по тестированию с объяснением того, зачем это нужно.


Одно из трёх — либо ты плохо умеешь читать, либо не задумываешься над тем, что прочитал и выхватываешь оттуда только устраивающее тебя, либо ты читаешь какие-то левые книжки. Выброси их на помойку или сдай в макулатуру и больше не позорься. Есть очень хороший критерий качества подачи материала — если автор расписывает только достоинства инструмента, но старательно опускает недостатки, то здесь что-то не так и всегда возникает вопрос — а в чём подвох? Если в твоих книжках не написано какие проблемы несут с собой защищаемые тобой подходы, то это плохие книжки. А если учесть, что в последнее время пошла мода издавать книжки, которые по сути являются тематической компиляцией самых разношёрстных блогов и википедий, то в качестве таких книжек сомневаться не приходится.
Если нам не помогут, то мы тоже никого не пощадим.
Re[21]: своё vs. сторонее
От: fddima  
Дата: 30.10.13 21:06
Оценка:
Здравствуйте, ., Вы писали:

Слушай, точечка — ты либо по делу скажи, либо молчи уже тогда, что-ли, если по делу вставить нечего.
Re[22]: своё vs. сторонее
От: . Великобритания  
Дата: 30.10.13 21:31
Оценка:
Здравствуйте, fddima, Вы писали:

F>Слушай, точечка — ты либо по делу скажи, либо молчи уже тогда, что-ли, если по делу вставить нечего.

На бред отвечаю бредом, уж извини.
Если тебе есть что показать, показывай, пока только пальцекидание
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[23]: своё vs. сторонее
От: fddima  
Дата: 31.10.13 11:27
Оценка:
Здравствуйте, ., Вы писали:

Я лично не писал ничего для АЭС и на эверест не подымался. Поставил бы минус, если не согласен со мной. Если у тебя другой опыт — поделись, тут все за.
Re[23]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 31.10.13 11:53
Оценка:
Здравствуйте, ., Вы писали:

F>>Слушай, точечка — ты либо по делу скажи, либо молчи уже тогда, что-ли, если по делу вставить нечего.

.>На бред отвечаю бредом, уж извини.
.>Если тебе есть что показать, показывай, пока только пальцекидание

Шота не совсем ясно, чего вы с Baudolino хотите сказать.

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

Весь метод который вы показали, это обработка ошибки и возврат результата

При этом
1 депенденсы на внутренности Receipt — forSuccessfulCharge, forDeclinedCharge, forSystemFailure
2 депенденси на внутренности ChargeResult — wasSuccessful
3 не ясно, что за процессор такой, если не умеет обрабатывать исключения и не может правильный результат вернуть
4 совершенно не ясно, почему этот процессор не логирует операции и ошибки

То есть, судя по коду, метод сервису тупо ворует обязанности у Receipt, PayPalProcessor и ChargeResult и при этом у него целый вагон депенденсов
Теперь очевидно, что DI ровно ничео не меняет — у метода вагон депенденсов, и ради трех с половиной строчек кода надо нагородить целую инфраструктуру

Внятный дизайн за счет обрезания депенденсов и перераспределения обязанностей можно сделать вот таки

CreditCardProcessor processor = ххх; // единственная "тяжёлая" депенденси

return Receipt.FromOperation(() => processor.charge(creditCard, order.getAmount()));


И вот за счет чего


// Receipt инкапсулирует все что ему надо, раз у него куча интересных методов
static class Receipt 
{

  static Receipt FromOperation(Func<ChargeResult> operation)
  {
    try {
      ChargeResult result = operaiton();
   
      return result.wasSuccessful()
          ? forSuccessfulCharge(result.getChargeAmount()) // не ясно, для чего getAmount тащить через order, если передаем его в операцию  :xz: 
          : forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      return forSystemFailure(e.getMessage());
    }
  }
}
// процессор делает логирование и минимальную обработку ошибок, возвращает внятный результат
class xxxProcessor {
  charge(CreditCard card, Amount amount)
  {
    try{
      var result = ... // internal processing
      
      transactionLog.success(result);
      
      return ToChargeResult(result, amount);
    }
    catch(xxxException ex)
    {
       transactionLog.failure(ex);
       throw; // !!!
    }  
 } 
}


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

processor.charge и Receipt.FromOperation стоит покрыть тестами, с первым неясно, что унутре, а со вторым все просто — он будет зависеть только от входного параметра, и не надо никаких моков, классов, интерфейсов и прочего говна.
Если логика процессора будет достаточно сложной, понадобятся моки, для изоляции от сети, скажем, или базы данных и тд.
Re[24]: своё vs. сторонее
От: . Великобритания  
Дата: 31.10.13 12:08
Оценка:
Здравствуйте, fddima, Вы писали:

F> Я лично не писал ничего для АЭС и на эверест не подымался. Поставил бы минус, если не согласен со мной. Если у тебя другой опыт — поделись, тут все за.

Так не с чем не соглашаться, и нет у меня цели опытом делиться, кто какой софт пишет, это в соседний форум, "О жизни". Мы тут вроде обсуждаем DI, IoC-контейнеры, я привожу пример для guice, как он помогает автоматизировать DI, в чём помогает DI, а ты отвечаешь что писать процессинг кредиток — тяжело. Кхм.. И?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[24]: своё vs. сторонее
От: . Великобритания  
Дата: 31.10.13 14:47
Оценка:
Здравствуйте, Ikemefula, Вы писали:

F>>>Слушай, точечка — ты либо по делу скажи, либо молчи уже тогда, что-ли, если по делу вставить нечего.

.>>На бред отвечаю бредом, уж извини.
.>>Если тебе есть что показать, показывай, пока только пальцекидание
I>Шота не совсем ясно, чего вы с Baudolino хотите сказать.
Объяснить что такое DI. Судя по ответам для вас это некое абстрактное зло о котором пишут только в проклятых книжках, которое нужно всеми силами избегать, и не поминать всуе.

I>Пример который вы дали, мутный — в ём ровно одна функция, очень простая, полезного кода около трех с половиной строчек. Ради этой функции сделано целых несколько классов и куча кода с различными приседаниями.

I>Мне например, совершенно не ясно, зачем вообще класс RealBillingService и все приседания вокруг него.
Класс в общем-то один (RealBillingService). Остальное — интерфейсы, которые у тебя "уже есть". Скажем, пишутся другой компанией, ты лишь подключаешь либу к себе в проект и юзаешь интерфейс.
Да, там ещё есть интерфейс BillingService, который сделан лишь "для красоты", ибо у некоторых такой стиль программирования, можно его выкинуть. Я об этом уже раз пять писал.

I>Весь метод который вы показали, это обработка ошибки и возврат результата

Это минимальный пример бизнес-логики.
I>При этом
I>1 депенденсы на внутренности Receipt — forSuccessfulCharge, forDeclinedCharge, forSystemFailure
Receipt — это просто структура данных, там никакой логики нет, обычный immutable объект, никаких внутренностей. Методы "for*" это стандартный подход замещения множества конструкторов статическими фабричными методами, чтобы в имени метода выразить назначение конструктора. Примерно как DateTime.forYMD(2013, 10, 31), DateTime.forToday() и т.п.

I>2 депенденси на внутренности ChargeResult — wasSuccessful

Ы?

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

Процессор логгирует обработку платежа. BillingService обрабатывает заказы. Это совершенно разные бизнес-сущности.

I>4 совершенно не ясно, почему этот процессор не логирует операции и ошибки

Логгирует. Но transactionLog это не наша программерская либа для логирования, а лог банковских транзакций из бизнес-требований, который пишется обычно в БД.

I>То есть, судя по коду, метод сервису тупо ворует обязанности у Receipt, PayPalProcessor и ChargeResult и при этом у него целый вагон депенденсов

I>Теперь очевидно, что DI ровно ничео не меняет — у метода вагон депенденсов, и ради трех с половиной строчек кода надо нагородить целую инфраструктуру
Не ворует, а следует SRP.

I>

I>// Receipt инкапсулирует все что ему надо, раз у него куча интересных методов
Ну и зря. Тащим бизнес-логику в класс данных.

I>// процессор делает логирование и минимальную обработку ошибок, возвращает внятный результат
А теперь добавляем BarclaysProcessor, который должен работать в американской пиццерии, т.к. они договорились с банком на меньшую коммисию, и наслаждаемся копипастой.
I>


I>Итого — DI умёр, правда без мучений

Ну-ну, а теперь покажи код как transactionLog попадает внутрь PayPalProcessor?

Теперь новое требование, мелкое изменение. Нужно при оформлении заказа, если заказ прошел успешно, послать уведомление повару приготовить пиццу. В случае с BillingService класс поменяется так:
  private final CookNotificationService cookNotificationService;
  @Inject
  public RealBillingService(CreditCardProcessor processor,
      TransactionLog transactionLog,
      CookNotificationService cookNotificationService) {
    this.processor = processor;
    this.transactionLog = transactionLog;
    this.cookNotificationService = cookNotificationService;
  }
...
  if (result.wasSuccessful())
     cookNotificationService.send(order);

Всё. Ещё, конечно, добавится класс CookNotificationService. Остальной существующий код останется без изменений. Тебе же придётся менять BarclayProcessor и PayPalProcessor и везде где есть "CreditCardProcessor processor = ххх; // единственная "тяжёлая" депенденси"
Кстати, раскрой плз что значит этот "xxx".

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


I>processor.charge и Receipt.FromOperation стоит покрыть тестами, с первым неясно, что унутре, а со вторым все просто — он будет зависеть только от входного параметра, и не надо никаких моков, классов, интерфейсов и прочего говна.

Receipt вообще покрывать не надо, там максимум конструкторы/геттеры/свойства, логику туда тащить не надо. Он сам покроется при тестировании других классов.

I>Если логика процессора будет достаточно сложной, понадобятся моки, для изоляции от сети, скажем, или базы данных и тд.

Так естественно понадобятся. У тебя есть сомнения?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[25]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 31.10.13 16:19
Оценка:
Здравствуйте, ., Вы писали:

I>>Шота не совсем ясно, чего вы с Baudolino хотите сказать.

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

В моих ответах есть подробное описание, где и как у меня применяется DI.

I>>Пример который вы дали, мутный — в ём ровно одна функция, очень простая, полезного кода около трех с половиной строчек. Ради этой функции сделано целых несколько классов и куча кода с различными приседаниями.

I>>Мне например, совершенно не ясно, зачем вообще класс RealBillingService и все приседания вокруг него.
.>Класс в общем-то один (RealBillingService). Остальное — интерфейсы, которые у тебя "уже есть". Скажем, пишутся другой компанией, ты лишь подключаешь либу к себе в проект и юзаешь интерфейс.
.>Да, там ещё есть интерфейс BillingService, который сделан лишь "для красоты", ибо у некоторых такой стиль программирования, можно его выкинуть. Я об этом уже раз пять писал.

Как то выходит, что и RealBillingService так же для красоты.

I>>Весь метод который вы показали, это обработка ошибки и возврат результата

.>Это минимальный пример бизнес-логики.
I>>При этом
I>>1 депенденсы на внутренности Receipt — forSuccessfulCharge, forDeclinedCharge, forSystemFailure
.>Receipt — это просто структура данных, там никакой логики нет, обычный immutable объект, никаких внутренностей. Методы "for*" это стандартный подход замещения множества конструкторов статическими фабричными методами, чтобы в имени метода выразить назначение конструктора. Примерно как DateTime.forYMD(2013, 10, 31), DateTime.forToday() и т.п.

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

I>>2 депенденси на внутренности ChargeResult — wasSuccessful

.>Ы?

Ога.

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

.>Процессор логгирует обработку платежа. BillingService обрабатывает заказы. Это совершенно разные бизнес-сущности.

Может и так, но судя по коду, логируется ChargeResult который спокойно может логироваться в процессоре.

I>>То есть, судя по коду, метод сервису тупо ворует обязанности у Receipt, PayPalProcessor и ChargeResult и при этом у него целый вагон депенденсов

I>>Теперь очевидно, что DI ровно ничео не меняет — у метода вагон депенденсов, и ради трех с половиной строчек кода надо нагородить целую инфраструктуру
.>Не ворует, а следует SRP.

Не ясно, где там SRP

I>>
I>>// Receipt инкапсулирует все что ему надо, раз у него куча интересных методов
.>Ну и зря. Тащим бизнес-логику в класс данных.

Эту логику можно вынести в свободные методы, собственно, у меня так и сделано.


I>>// процессор делает логирование и минимальную обработку ошибок, возвращает внятный результат
.>А теперь добавляем BarclaysProcessor, который должен работать в американской пиццерии, т.к. они договорились с банком на меньшую коммисию, и наслаждаемся копипастой.

Покажи код. Мне совсем неочевидно, почему там должна копипаста появиться. 

I>>


I>>Итого — DI умёр, правда без мучений

.>Ну-ну, а теперь покажи код как transactionLog попадает внутрь PayPalProcessor?

Это уже не важно. Я показал что приведеный пример никому не интересен

.>Теперь новое требование, мелкое изменение. Нужно при оформлении заказа, если заказ прошел успешно, послать уведомление повару приготовить пиццу. В случае с BillingService класс поменяется так:

.>Всё. Ещё, конечно, добавится класс CookNotificationService. Остальной существующий код останется без изменений. Тебе же придётся менять BarclayProcessor и PayPalProcessor и везде где есть "[i]CreditCardProcessor processor = ххх;

Смотри внимательно — в исходном примере используется CreditCardProcessor. Если его легко заменить на BarclayProcessor , то не ясно, почему это нельзя сделать в моём случае .

Покажи код, как ты собираешься всунуть нотификацию, а я покажу свой вариант. Идет ?

.>Кстати, раскрой плз что значит этот "xxx".


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

I>>processor.charge и Receipt.FromOperation стоит покрыть тестами, с первым неясно, что унутре, а со вторым все просто — он будет зависеть только от входного параметра, и не надо никаких моков, классов, интерфейсов и прочего говна.

.>Receipt вообще покрывать не надо, там максимум конструкторы/геттеры/свойства, логику туда тащить не надо. Он сам покроется при тестировании других классов.

Receipt != Receipt.FromOperation

I>>Если логика процессора будет достаточно сложной, понадобятся моки, для изоляции от сети, скажем, или базы данных и тд.

.>Так естественно понадобятся. У тебя есть сомнения?

Вот и покажи внятный пример, а не этот фейк что по ссылке
Re[26]: своё vs. сторонее
От: . Великобритания  
Дата: 31.10.13 17:37
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>В моих ответах есть подробное описание, где и как у меня применяется DI.

Видимо, я что-то пропустил. Можно ссылку на код?

I>Как то выходит, что и RealBillingService так же для красоты.

Нет, он инкапсулирует работу с заказами, в отличие от PayProcessor, который работает с платежами.

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

Что куда протаскивать? Зачем? Мне вот ничего не надо протаскивать...
Код в студию.

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

.>>Процессор логгирует обработку платежа. BillingService обрабатывает заказы. Это совершенно разные бизнес-сущности.
I>Может и так, но судя по коду, логируется ChargeResult который спокойно может логироваться в процессоре.
Для простоты просто. Допустим пусть будет "transactionLog.logChargeResult(result, order)".

I>Не ясно, где там SRP

А где там нет SRP?

I>>>// Receipt инкапсулирует все что ему надо, раз у него куча интересных методов

.>>Ну и зря. Тащим бизнес-логику в класс данных.
I>Эту логику можно вынести в свободные методы, собственно, у меня так и сделано.
Что ты имеешь в виду? У тебя вроде статич. метод в классе Receipt.

I>>>// процессор делает логирование и минимальную обработку ошибок, возвращает внятный результат

.>>А теперь добавляем BarclaysProcessor, который должен работать в американской пиццерии, т.к. они договорились с банком на меньшую коммисию, и наслаждаемся копипастой.
I>Покажи код. Мне совсем неочевидно, почему там должна копипаста появиться.
class PaypalProcessor {
  charge(CreditCard card, Amount amount)
  {
    try{
      var result = sendHttpRequestToPaypalUrl(card, amount);
      
      transactionLog.success(result);
      
      return ToChargeResult(result, amount);
    }
    catch(xxxException ex)
    {
       transactionLog.failure(ex);
       throw; // !!!
    }  
 } 
}
class BarclayProcessor {
  charge(CreditCard card, Amount amount)
  {
    try{
      var result = makeSoapRequestToBarclay(card, amount);
      
      transactionLog.success(result);
      
      return ToChargeResult(result, amount);
    }
    catch(xxxException ex)
    {
       transactionLog.failure(ex);
       throw; // !!!
    }  
 } 
}


I>>>Итого — DI умёр, правда без мучений

.>>Ну-ну, а теперь покажи код как transactionLog попадает внутрь PayPalProcessor?
I>Это уже не важно. Я показал что приведеный пример никому не интересен
Так это и есть самое важное! Ровно это пример и показывает!
Так и говори: "Зависимость TransactionLog инжектится внутрь PayPalProcessor, но это не Dependency Injection, т.к. я в это верю, а ты еретик", что виляешь-то? Разговор на этом и закончим.

.>>Теперь новое требование, мелкое изменение. Нужно при оформлении заказа, если заказ прошел успешно, послать уведомление повару приготовить пиццу. В случае с BillingService класс поменяется так:

.>>Всё. Ещё, конечно, добавится класс CookNotificationService. Остальной существующий код останется без изменений. Тебе же придётся менять BarclayProcessor и PayPalProcessor и везде где есть "[i]CreditCardProcessor processor = ххх;

I>Смотри внимательно — в исходном примере используется CreditCardProcessor. Если его легко заменить на BarclayProcessor , то не ясно, почему это нельзя сделать в моём случае .

Там CreditCardProcessor это интерфейс, его реализация в примере PayPalProcessor. Допустим ещё существует BarclayProcessor. Этого в твоём примере нет. У тебя имплементацию подменять нельзя.

I>Покажи код, как ты собираешься всунуть нотификацию, а я покажу свой вариант. Идет ?

Так я ж показал:
  public Receipt chargeOrder(PizzaOrder order, CreditCard creditCard) {
    try {
      ChargeResult result = processor.charge(creditCard, order.getAmount());
      transactionLog.logChargeResult(result);
      if (result.wasSuccessful())
        cookNotificationService.send(order);
      return result.wasSuccessful()
          ? Receipt.forSuccessfulCharge(order.getAmount())
          : Receipt.forDeclinedCharge(result.getDeclineMessage());
     } catch (UnreachableException e) {
      transactionLog.logConnectException(e);
      return Receipt.forSystemFailure(e.getMessage());
    }
  }


.>>Кстати, раскрой плз что значит этот "xxx".

I>В вызывающем коде гарантировано есть нужная депенденси, её напрямую можно юзать
Откуда? Давай показывай, не стесняйся. В примере это есть:
 public static void main(String[] args) {
    Injector injector = Guice.createInjector(new BillingModule());
    BillingService billingService = injector.getInstance(BillingService.class);
    // это я допишу, чтобы не напрягать твоё воображение:
    CreditCard cc = askUserCreditCardDetailsFromConsole();
    PizzaOrder order = parseOrder(args);
    billingService.chargeOrder(cc, order);
  }

Вот такой command-line interface для заказа пиццы.

I>>>processor.charge и Receipt.FromOperation стоит покрыть тестами, с первым неясно, что унутре, а со вторым все просто — он будет зависеть только от входного параметра, и не надо никаких моков, классов, интерфейсов и прочего говна.

.>>Receipt вообще покрывать не надо, там максимум конструкторы/геттеры/свойства, логику туда тащить не надо. Он сам покроется при тестировании других классов.
I>Receipt != Receipt.FromOperation
Ну правильно, вначале понапиал туда логики, теперь проблемы возникли, что класс тестить теперь приходится. "- Я так делаю, и у меня болит. — Так не делай так".

I>>>Если логика процессора будет достаточно сложной, понадобятся моки, для изоляции от сети, скажем, или базы данных и тд.

.>>Так естественно понадобятся. У тебя есть сомнения?
I>Вот и покажи внятный пример, а не этот фейк что по ссылке
Давай свой пример, а то опять что-то не понравится, но не двухстрочный фреймворк для умножения двух чисел, а что-то с несколькими бизнес-сущностями. Я же не знаю что ты ожидаешь.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[27]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 01.11.13 10:41
Оценка:
Здравствуйте, ., Вы писали:

I>>В моих ответах есть подробное описание, где и как у меня применяется DI.

.>Видимо, я что-то пропустил. Можно ссылку на код?

На код сильно вряд ли, на гитхабе его нет
http://rsdn.ru/forum/design/5334700.1
Автор: Ikemefula
Дата: 18.10.13

http://rsdn.ru/forum/design/5334226.1
Автор: Ikemefula
Дата: 17.10.13


I>>Как то выходит, что и RealBillingService так же для красоты.

.>Нет, он инкапсулирует работу с заказами, в отличие от PayProcessor, который работает с платежами.

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

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

.>Что куда протаскивать? Зачем? Мне вот ничего не надо протаскивать...
.>Код в студию.

Код уже есть по той самой ссылке, где мега-тест который тестирует виртуальный вызов
Receipt.forSuccessfulCharge
Receipt.forDeclinedCharge
Receipt.forSystemFailure

Как видишь, в Receipt есть и код, и депенденси на методы уже протащены куда попало.

I>>Может и так, но судя по коду, логируется ChargeResult который спокойно может логироваться в процессоре.

.>Для простоты просто. Допустим пусть будет "transactionLog.logChargeResult(result, order)".

Ты снова корректируешь исходный пример.

I>>Не ясно, где там SRP

.>А где там нет SRP?

Смотри сам — charge, логирование, которые, как ты утверждаешь, важная обязанность, обработка ошибок и конструирование результата.

.>>>Ну и зря. Тащим бизнес-логику в класс данных.

I>>Эту логику можно вынести в свободные методы, собственно, у меня так и сделано.
.>Что ты имеешь в виду? У тебя вроде статич. метод в классе Receipt.

А в исходном примере надо полагать это не так сделано ? Там целых три метода, а у меня один.

На вторую часть попозже отвечу, у меня лимит времени на одно сообщение
Re[27]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 02.11.13 07:26
Оценка:
Здравствуйте, ., Вы писали:

I>>>>// процессор делает логирование и минимальную обработку ошибок, возвращает внятный результат

.>>>А теперь добавляем BarclaysProcessor, который должен работать в американской пиццерии, т.к. они договорились с банком на меньшую коммисию, и наслаждаемся копипастой.
I>>Покажи код. Мне совсем неочевидно, почему там должна копипаста появиться.

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

I>>Это уже не важно. Я показал что приведеный пример никому не интересен

.>Так это и есть самое важное! Ровно это пример и показывает!

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

Что ты хотел сказать, я не понял.

I>>Смотри внимательно — в исходном примере используется CreditCardProcessor. Если его легко заменить на BarclayProcessor , то не ясно, почему это нельзя сделать в моём случае .

.>Там CreditCardProcessor это интерфейс, его реализация в примере PayPalProcessor. Допустим ещё существует BarclayProcessor. Этого в твоём примере нет. У тебя имплементацию подменять нельзя.

У меня используется CreditCardProcessor, если внимательно посмотришь. Имплементация подменяется точно так же как и у тебя, только не надо дополнительный класс.


I>>Покажи код, как ты собираешься всунуть нотификацию, а я покажу свой вариант. Идет ?

.>Так я ж показал:

Идею понял, пудозреваю, если такой код не в единственном числе, то правильно оформлять как транзакцию, по завершении которой и вызовется нотификация.

Эту нотификацию нужно бросать когда Ордер переходит в состояние Paid. Этого кода нет и близко, а BillingService по прежнему как то ни о чем

Т.е. будет чтото вот так

Order order = Order.FromXXX
order.StateChange += FireNotification;
...
order.State(OrderState.Paid);
...
order.AcceptChanges(); // вот здесь будет файриться нотификация.


.>>>Кстати, раскрой плз что значит этот "xxx".

I>>В вызывающем коде гарантировано есть нужная депенденси, её напрямую можно юзать
.>Откуда? Давай показывай, не стесняйся. В примере это есть:
.>
.> public static void main(String[] args) {
.>    Injector injector = Guice.createInjector(new BillingModule());
.>    CreditCardProcessor processor = injector.getInstance(CreditCardProcessor.class);

.>  }
.>

.>Вот такой command-line interface для заказа пиццы.

Я добавил, что надо. Если в вызывающем коде есть BillingService, то нет никакой проблемы получить там же и процессор конкретный.

.>Ну правильно, вначале понапиал туда логики, теперь проблемы возникли, что класс тестить теперь приходится. "- Я так делаю, и у меня болит. — Так не делай так".


Не понял. Это я, по твоему, добавил логики в виде
Receipt.forSuccessfulCharge
Receipt.forDeclinedCharge
Receipt.forSystemFailure


I>>Вот и покажи внятный пример, а не этот фейк что по ссылке

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

Ты не волнуйся, в моем коде есть все что нужно. А вот благодаря евангелистам, которые приводят код навроде того, что по ссылке, DI воспринимается как серебряная пулька, лекарство сразу от всех болезней, в том числе и будущих.
Re[2]: своё vs. сторонее
От: QrystaL Украина  
Дата: 30.11.13 09:26
Оценка:
Здравствуйте, Коваленко Дмитрий, Вы писали:
КД>В итоге — пришлось все изобретать с нуля.
Прямо-таки всё? и ADO.NET, и ASP.NET, и впф/винформы, свои коллекции, свой IO и т.д.?

КД>Может поэтому удалось добраться до финиша.

Как же другим удается добираться, практически ничего не переписывая?
Re[3]: своё vs. сторонее
От: Коваленко Дмитрий Россия http://www.ibprovider.com
Дата: 01.12.13 15:08
Оценка:
Здравствуйте, QrystaL, Вы писали:

КД>>В итоге — пришлось все изобретать с нуля.

QL>Прямо-таки всё? и ADO.NET, и ASP.NET, и впф/винформы, свои коллекции, свой IO и т.д.?

Проект связан с заменой System.Data.OleDb на более продвинутую нормальную реализацию.

Была бы возможность — я бы исправил некоторые вещи в System.Data.Common.

КД>>Может поэтому удалось добраться до финиша.

QL>Как же другим удается добираться, практически ничего не переписывая?

До моих финишей пока добирался только я
-- Пользователи не приняли программу. Всех пришлось уничтожить. --
Re[13]: своё vs. сторонее
От: TK Лес кывт.рф
Дата: 10.12.13 06:26
Оценка:
Здравствуйте, Ikemefula, Вы писали:

IT>>Ну подменяй. Что требуется от меня?

I>Как аргумент в пользу DI годится или как ?

Откуда DI знает какой именно IOpenDocument нужен в данном контексте?
Скорее всего тут несколько вариантов:
Либо Resolve<IOpenDocument> выплюнет все возможные реализации IOpenDocument из разряда "выбери что больше нравится" (а дальше будут циклы и ifы).
Либо Resolve знает какой именно IOpenDocument надо выдать. Зачем тогда нужны OpenDocumentArgs и CanExecute?
Либо Resolve<IOpenDocument>() это доступ к какому-то синглтону?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[14]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.12.13 07:46
Оценка:
Здравствуйте, TK, Вы писали:

IT>>>Ну подменяй. Что требуется от меня?

I>>Как аргумент в пользу DI годится или как ?

TK>Откуда DI знает какой именно IOpenDocument нужен в данном контексте?


В конфигурации DI-контейнера описывается.

TK>Скорее всего тут несколько вариантов:

TK>Либо Resolve<IOpenDocument> выплюнет все возможные реализации IOpenDocument из разряда "выбери что больше нравится" (а дальше будут циклы и ifы).

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

TK>Либо Resolve знает какой именно IOpenDocument надо выдать. Зачем тогда нужны OpenDocumentArgs и CanExecute?


xxxArgs и CanExecute нужны не для DI, а для унификации интерфейсов команд. Документы можно открывать разные — форматы, версии. Еще можно открывать по разному — с переопределением некоторых значений, с запросом у юзера тех же значений, игнорируя недостающие значения и тд и тд.
CanExecute тоже не для DI, он для UI.


TK>Либо Resolve<IOpenDocument>() это доступ к какому-то синглтону?


Не нужно никаких синглтонов Еще такой момент, кое где будет вот так Resolve("IOpenDocument") Это в основном для старого кода, который конфигурируется из xml.
Re[15]: своё vs. сторонее
От: TK Лес кывт.рф
Дата: 10.12.13 09:13
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Это не нужно, в приложении только одна реализация этого интерфейса. Для других интерфейсов может быть несколько реализаций, тогда DI-контейнер получает чтото наводе подсказки или контекста.


Если реализация одна то, все можно упростить до _openDocument.Execute(args).
А передавать в контейнер подсказки или контекст это фактически прибить логику работы к реализации контейнера.
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[16]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.12.13 09:18
Оценка:
Здравствуйте, TK, Вы писали:

TK>Если реализация одна то, все можно упростить до _openDocument.Execute(args).

TK>А передавать в контейнер подсказки или контекст это фактически прибить логику работы к реализации контейнера.

А где мне объявлять и инициализировать эту переменную ?

Где объявлять и инициализировать еще пару сотен таких же команд ?
Re[17]: своё vs. сторонее
От: TK Лес кывт.рф
Дата: 10.12.13 10:04
Оценка:
Здравствуйте, Ikemefula, Вы писали:

TK>>Если реализация одна то, все можно упростить до _openDocument.Execute(args).

TK>>А передавать в контейнер подсказки или контекст это фактически прибить логику работы к реализации контейнера.

I>А где мне объявлять и инициализировать эту переменную ?


В конструкторе.

I>Где объявлять и инициализировать еще пару сотен таких же команд ?


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

I>В конфигурации DI-контейнера описывается.


Кстати, а DI программируется кодом или XML'ем или через "мне повезет"?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[18]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.12.13 12:25
Оценка:
Здравствуйте, TK, Вы писали:

I>>А где мне объявлять и инициализировать эту переменную ?


TK>В конструкторе.


Я шота не сильно понимаю твой аргумент
Какой профит я получу, если вытащу cmd в конструктор ? Все команды, например, пересоздаются на каждый вызов, их слишком много, что бы держать в памяти, и каждая довольно много весит.
IDocument Open(OpenDocumentArgs args)
{
  var cmd = Resolve<IOpenDocument>();

  if(cmd.CanExecute(args))
     cmd.Execute(args);
}


I>>Где объявлять и инициализировать еще пару сотен таких же команд ?


TK>Если было не лень написать сотню классов то, пару строк на вызов конструктора это не самая большая проблема.


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

I>>В конфигурации DI-контейнера описывается.


TK>Кстати, а DI программируется кодом или XML'ем или через "мне повезет"?


Часть через XML, осталось с незапамятных времен. Часть собтсвенно кодом, в основном команды.
XML даёт некоторый профит — приложение умеет сохранять, загружать и модифицировать свою собтсвенную конфигурацию. Теоретически это можно было и через Code Dom сорганизовать или чтото навроде, но эти требования появились где то через 5 лет после того, как ядро уже устаканилось.
Re[19]: своё vs. сторонее
От: TK Лес кывт.рф
Дата: 10.12.13 13:33
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Я шота не сильно понимаю твой аргумент

I>Какой профит я получу, если вытащу cmd в конструктор ? Все команды, например, пересоздаются на каждый вызов, их слишком много, что бы держать в памяти, и каждая довольно много весит.

Если команда это некий workflow то, зачем хранить состояние в самой команде? А если состояния как такового нет то, откуда каждая команда будет много весить?
Если у Вас нет паранойи, то это еще не значит, что они за Вами не следят.
Re[20]: своё vs. сторонее
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 10.12.13 15:03
Оценка:
Здравствуйте, TK, Вы писали:

I>>Я шота не сильно понимаю твой аргумент

I>>Какой профит я получу, если вытащу cmd в конструктор ? Все команды, например, пересоздаются на каждый вызов, их слишком много, что бы держать в памяти, и каждая довольно много весит.

TK>Если команда это некий workflow то, зачем хранить состояние в самой команде? А если состояния как такового нет то, откуда каждая команда будет много весить?


Команда удерживает довольно большой контекст.
Re[2]: своё vs. сторонее
От: minorlogic Украина  
Дата: 14.12.13 18:17
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>Такие дела. Мораль можете вывести сами.


"Shit happens"
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re: своё vs. сторонее
От: c-smile Канада http://terrainformatica.com
Дата: 14.12.13 18:44
Оценка:
Здравствуйте, CEMb, Вы писали:

стороннее для тебя это всегда свое для кого-то.
стороннее для кого-то может быть и что-то твое.

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

Я хочу сказать что чужой-свой не есть проблема формализуемого дизайна и общих рекомендаций. Сугубо персональное дело.
Re[2]: своё vs. сторонее
От: minorlogic Украина  
Дата: 15.12.13 11:54
Оценка:
Дай ссылку на обсуждение DI. Судя по вики и по статьям DI называют любое нормальное использование интерфейсов. Т.е. зачем вообще вводить такие "паттерны" ума не приложу.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[15]: своё vs. сторонее
От: minorlogic Украина  
Дата: 15.12.13 12:29
Оценка:
Здравствуйте, ., Вы писали:

.>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.


Пример по ссылке вообще является феерическим звездецом.

1. Функция stateless которая делает примитивные действия , реализуется через класс.

2. Половина данных передается как мемберы , половина как параметры вызова. WTF ???

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

Резюме, феерический бред.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[11]: своё vs. сторонее
От: minorlogic Украина  
Дата: 15.12.13 13:07
Оценка:
Здравствуйте, Doc, Вы писали:

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


IT>>DI &mdash; это 25-ти доллоровый термин для 5-ти центовой концепции.


Doc>Кстати, забавная статья, про то, как человек открыл для себя тот факт, что DI это передача экземпляра заданного класса внутрь его класса. Он так скоро откроет, что там еще и интерфейсы можно использовать.


Т.е. такие статьи и сущности как DI это типа попытка научить индусов програмированию ?
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
Re[16]: своё vs. сторонее
От: Аноним  
Дата: 15.12.13 20:41
Оценка:
Здравствуйте, minorlogic, Вы писали:

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


.>>В общем вот почитай: http://code.google.com/p/google-guice/wiki/Motivation и выскажи что такого неправильного в предложенном решении c DI и как бы ты сам решал такую задачу.

M>Пример по ссылке вообще является феерическим звездецом.
Выделенное главное. Остальное — неинтересная критика.

M>1. Функция stateless которая делает примитивные действия , реализуется через класс.

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

M>2. Половина данных передается как мемберы , половина как параметры вызова. WTF ???

Данные как параметры вызова. Сервисы обработки данных — инжектятся.

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

Каких данных?

M>Резюме, феерический бред.

Резюме: тупая критика.
Re[18]: своё vs. сторонее
От: . Великобритания  
Дата: 15.12.13 22:56
Оценка:
Здравствуйте, minorlogic, Вы писали:

M>Простейший и очевидный вариант

M>
M>  Receipt chargeOrder(CreditCardProcessor processor, TransactionLog transactionLog, PizzaOrder order, CreditCard creditCard); 
M>

Допустим. Вопросы:
1. В каком классе этот метод будет и почему?
2. Когда этот метод будет вызываться, откуда вызывающая сторона будет брать CreditCardProcessor и TransactionLog?
3. Считаешь ли ты хорошим дизайном, что вызывающая сторона должна знать внутренюю реализацию, все внутренние зависимости метода?
4. Если появится ещё одна зависимость, например CookerNotificationService (отсылка уведомления повару при успешном заказе), как ты будешь менять код?

M>>>1. Функция stateless которая делает примитивные действия , реализуется через класс.

А>>Не примитивные действия, а бизнес-логику. Опять же. Смотри выделенное.
M>Издеваешься? Может лучше назвать позаковырестее, и оно поменяет смысл?
Как яхту назовёте, так и поплывёт.

M>>>2. Половина данных передается как мемберы , половина как параметры вызова. WTF ???

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

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

А>>Каких данных?
M>CreditCardProcessor processor, TransactionLog transactionLog если это не очевидно.
Это не данные.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Re[19]: своё vs. сторонее
От: Evgeny.Panasyuk Россия  
Дата: 15.12.13 23:56
Оценка:
Здравствуйте, ., Вы писали:

M>>Простейший и очевидный вариант

M>>
M>>  Receipt chargeOrder(CreditCardProcessor processor, TransactionLog transactionLog, PizzaOrder order, CreditCard creditCard); 
M>>

.>Допустим. Вопросы:
.>1. В каком классе этот метод будет и почему?

В нормальных языках такой вопрос вообще не стоит — он не должен быть членом какого-либо класса.
А в C#/Java будет что-то типа BankUtils наполненный static методами.

.>3. Считаешь ли ты хорошим дизайном, что вызывающая сторона должна знать внутренюю реализацию, все внутренние зависимости метода?


Это не внутренние зависимости хотя бы потому, что при использовании IoC-Container'ов вызывающая сторона:
a) и так знает об этих зависимостях (она же видит конструкторы класса)
b) может подменить эти зависимости (либо используя класс напрямую, либо покрутив IoC-Container)

M>>>>1. Функция stateless которая делает примитивные действия , реализуется через класс.

А>>>Не примитивные действия, а бизнес-логику. Опять же. Смотри выделенное.
M>>Издеваешься? Может лучше назвать позаковырестее, и оно поменяет смысл?
.>Как яхту назовёте, так и поплывёт.

Всё-таки, что в stateless бизнес-логике такого особенного, что её нужно класть в class?

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

А>>>Каких данных?
M>>CreditCardProcessor processor, TransactionLog transactionLog если это не очевидно.
.>Это не данные.

Это терминологический вопрос. Пусть будут тогда "дефолтные параметры".
Re[19]: своё vs. сторонее
От: minorlogic Украина  
Дата: 16.12.13 07:35
Оценка:
Здравствуйте, ., Вы писали:


Погорячился , вчера не заметил что класс реализует интерфейс BillingService и тем самым задает сигнатуру вызовов и т.д. В этом случае действительно оправданно агрегировать данные и изолировать их от интерфейса. В противном случае это создает больше проблем чем удобств.
... << RSDN@Home 1.2.0 alpha 5 rev. 1539>>
Ищу работу, 3D, SLAM, computer graphics/vision.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.