Здравствуйте, a7d3, Вы писали:
A>>>·>Во-первых, в С++ нет интерфейсов. Так что не очень понятно что конкретно ты имеешь в виду. A>>>В каком плане в С++ нет интерфейсов? A>·>В языке такого понятия нет. A>Всегда было и вдруг исчезло? https://en.cppreference.com/w/cpp/language/abstract_class
Абстрактный класс это не то же самое, что интерфейс. Врочем, абстрактные классы для DI тоже не нужны.
A>>>И что именно понимается под интерфейсами, которые якобы не нужны в DI? A>·>Ищем в гугле "di c# example", первая ссылка вот. Там interface ICustomerDataAccess не нужен, и даже немножко вреден. A>Чем именно вреден и
Насчёт "не нужен" возражений нет?
Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму.
A>в каком из сценариев использования
Как минимум в упомянутом по ссылке выше.
A> DI (IoC)?
Ещё с терминологией надо бы разобраться. IoC — это принцип инверсии контроля. Применяя этот принцип к управлению зависимостями получаем технику Dependency Injection. И не путай IoC principle и IoC-container.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
·>Здравствуйте, a7d3, Вы писали:
A>>Всегда было и вдруг исчезло? https://en.cppreference.com/w/cpp/language/abstract_class ·>Абстрактный класс это не то же самое, что интерфейс. Врочем, абстрактные классы для DI тоже не нужны.
Спорное утверждение, таковы средства данного языка для реализации такой концепции, как интерфейсы.
A>>>>И что именно понимается под интерфейсами, которые якобы не нужны в DI? A>>·>Ищем в гугле "di c# example", первая ссылка вот. Там interface ICustomerDataAccess не нужен, и даже немножко вреден. A>>Чем именно вреден и ·>Насчёт "не нужен" возражений нет? ·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму.
В том примере интерфейсы используются для конкретного назначения, если утверждается, что можно проще то, что именно предлагается в качестве альтернативы?
Рассмотрим и тот, и этот варианты, положив на весы в плоскости конкретных, однозначно сформулированных целей и задач.
После чего станет ясно, в каком аспекте, в каком разрезе проигрывает или хорош тот или иной вариант.
Не проблема?
Здравствуйте, a7d3, Вы писали:
A>>>Всегда было и вдруг исчезло? https://en.cppreference.com/w/cpp/language/abstract_class A>·>Абстрактный класс это не то же самое, что интерфейс. Врочем, абстрактные классы для DI тоже не нужны. A>Спорное утверждение,
Которое из моих утверждений спорное?
A> таковы средства данного языка для реализации такой концепции, как интерфейсы.
Эээ. И что? Средствами даже голого C можно реализовать, например, такую концепцию как рефлексия. И что? Она внезапно там появится?
A>>>Чем именно вреден и A>·>Насчёт "не нужен" возражений нет? A>·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму. A>В том примере интерфейсы используются для конкретного назначения, если утверждается, что можно проще то, что именно предлагается в качестве альтернативы?
Тот пример вроде бы как должен демонстрировать применение DI. И примеры, как правило, должны быть минимальны. Использование интерфейса там как пятая нога.
A>Рассмотрим и тот, и этот варианты, положив на весы в плоскости конкретных, однозначно сформулированных целей и задач. A>После чего станет ясно, в каком аспекте, в каком разрезе проигрывает или хорош тот или иной вариант. A>Не проблема?
Я не понял вопрос. Тебе непонятна альтернатива что-ли? Я же уже написал — просто выкинуть interface ICustomerDataAccess и собственно всё. По-моему очевидно что должно получиться. Код что-ли привести?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
·>Здравствуйте, a7d3, Вы писали:
A>>>>Всегда было и вдруг исчезло? https://en.cppreference.com/w/cpp/language/abstract_class A>>·>Абстрактный класс это не то же самое, что интерфейс. Врочем, абстрактные классы для DI тоже не нужны. A>>Спорное утверждение, ·>Которое из моих утверждений спорное?
A>> таковы средства данного языка для реализации такой концепции, как интерфейсы. ·>Эээ. И что? Средствами даже голого C можно реализовать, например, такую концепцию как рефлексия. И что? Она внезапно там появится?
Проводить агитацию за синтаксический сахар того или иного сорта — это оффтоп.
Утверждение, что абстрактные классы в С++ не являются интерфейсами — тоже оффтоп.
A>>Рассмотрим и тот, и этот варианты, положив на весы в плоскости конкретных, однозначно сформулированных целей и задач. A>>После чего станет ясно, в каком аспекте, в каком разрезе проигрывает или хорош тот или иной вариант. A>>Не проблема? ·>Я не понял вопрос. Тебе непонятна альтернатива что-ли? Я же уже написал — просто выкинуть interface ICustomerDataAccess и собственно всё. По-моему очевидно что должно получиться. Код что-ли привести?
Конкретика должна быть такой:
1) для чего именно было решено использовать DI, с какой целью, ради каких задач.
2) какой вариант, в контексте п.1, более вменяем, нежели через интерфейсы.
Здравствуйте, ·, Вы писали:
·>Насчёт "не нужен" возражений нет?
Для простых приложений и DI не нужен. Так где DI, потребность в интерфейсах в полный рост.
·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму.
Здравствуйте, a7d3, Вы писали:
A>Конкретика должна быть такой: A>1) для чего именно было решено использовать DI, с какой целью, ради каких задач. A>2) какой вариант, в контексте п.1, более вменяем, нежели через интерфейсы.
DI ортогонален IoC, контейнерам и интерфейсам. Есть, и их масса, классов которые потребляют иные объекты через DI. Чего тут аргументировать то?
Все вывороты с интерфейсам и абстрактными классами имеют смысл только в случае, когда в рантайме мы можем предоставить разные имплементации одного и того же нечто (сервиса).
Всё о чем тут говорят — что на практике — интерфейсы плодятся без всякого повода, просто, потому, что это модно и примеры лишь подталкивают к этому. 99.9% приложений имеют единственный конкретный SQL-бэкэнд, и абстрагироваться не только нет смысла, но даже и вредно, т.к. замоченные фейки и близко не несут реальной семантики и реальных возможных проблем.
Здравствуйте, Sharov, Вы писали:
S>Для простых приложений и DI не нужен. Так где DI, потребность в интерфейсах в полный рост.
Любой объект переданный в конструктор другого объекта (или динамически присвоен, допустим в пропертю) — это и есть та самая Dependency Injection. Как ты понимаешь, данная техника стара, как всё программирование в целом.
S>·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму. S>Новички в DI не полезут.
У новичков нет проблем с DI — они его используют в полный рост, даже не зная как оно называется. Да, куча примеров, предлагают делать интерфейсы, но любой нормальный IoC контейнер может работать с конкретными типами, вдобавок IoC-контейнер — не что иное, как динамически-конфигурируемая фабрика. Несложно понять, что оно нужно далеко не всегда. И даже асп.нет приложении если ты хочешь per-request инстанцирование — интерфейс не нужен.
Безусловно в этом вопросе ты прав. Более того в C#/Java они играют ту же самую роль, и их использование предпочтительно, если думают не жопой. Отдельно стоящие интерфейсы существуют только для преодоления ограничения в наследовании (только один наследник, но множество интерфейсов). (Само собой интерфейсы накладывают меньше ограничений, что часто играет в плюс.)
Здравствуйте, scf, Вы писали:
scf>- Оформление кода. отдельный интерфейс с джавадоком — это удобная документация для программиста, не загроможденная реализацией.
Здравствуйте, Mystic Artifact, Вы писали:
MA>Здравствуйте, Sharov, Вы писали:
S>>Для простых приложений и DI не нужен. Так где DI, потребность в интерфейсах в полный рост. MA> Любой объект переданный в конструктор другого объекта (или динамически присвоен, допустим в пропертю) — это и есть та самая Dependency Injection. Как ты понимаешь, данная техника стара, как всё программирование в целом.
Это понятно, речь идет в контексте IoC контейнеров и прочих Composition Root, где граф создается еще на старте. Это нужно далеко не всегда.
Здравствуйте, Sharov, Вы писали:
S>Это понятно, речь идет в контексте IoC контейнеров и прочих Composition Root, где граф создается еще на старте. Это нужно далеко не всегда.
Ну так там же можно (и нужно) подсунуть не интерфейс, а конкретный класс реализации, если он в принципе в проекте в единственном числе.
Здравствуйте, a7d3, Вы писали:
A>>> таковы средства данного языка для реализации такой концепции, как интерфейсы. A>·>Эээ. И что? Средствами даже голого C можно реализовать, например, такую концепцию как рефлексия. И что? Она внезапно там появится? A>Проводить агитацию за синтаксический сахар того или иного сорта — это оффтоп.
Я не агитировал.
A>Утверждение, что абстрактные классы в С++ не являются интерфейсами — тоже оффтоп.
Ага. Но это я отвечал на твой вопрос про "вдруг исчезло". Онтоп был "абстрактные классы для DI тоже не нужны.". Но это ты просто проигнорировал.
A>·>Я не понял вопрос. Тебе непонятна альтернатива что-ли? Я же уже написал — просто выкинуть interface ICustomerDataAccess и собственно всё. По-моему очевидно что должно получиться. Код что-ли привести?
A>Конкретика должна быть такой: A>1) для чего именно было решено использовать DI, с какой целью, ради каких задач.
Там по ссылке расписано. Если чего неясно, задавай вопросы.
A>2) какой вариант, в контексте п.1, более вменяем, нежели через интерфейсы.
Третий раз отвечаю — всё то же самое, но без интерфесов. Просто инжектить конкретный класс.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Sharov, Вы писали:
S>·>Насчёт "не нужен" возражений нет? S>Для простых приложений и DI не нужен. Так где DI, потребность в интерфейсах в полный рост.
Если в приложении несколько зависимых классов, то как обычно уже нужен. Интерфейсы нужны гораздо реже.
S>·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму. S>Новички в DI не полезут.
Потому что оно переусложено.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Mystic Artifact, Вы писали:
MA>Здравствуйте, scf, Вы писали:
scf>>- Оформление кода. отдельный интерфейс с джавадоком — это удобная документация для программиста, не загроможденная реализацией.
MA> Получается я не один такой
? Насколько считаешь этот момент важным? MA> Я довольно часто мечусь по неизвестному коду (даже по своему...), и если это не C++ честно говоря порой офигеваю...
Нууу, почти. На мой вкус, у хедеров С++ есть два недостатка. Во-первых, они обязательны. Т.е. даже если класс или модуль очень простой или не очень важный, их все равно приходится писать. Во-вторых, хедеры всегда в отдельном файле, удваивая кол-во файлов в проекте.
Здравствуйте, Mystic Artifact, Вы писали:
scf>>- Оформление кода. отдельный интерфейс с джавадоком — это удобная документация для программиста, не загроможденная реализацией. MA> Получается я не один такой
? Насколько считаешь этот момент важным? MA> Я довольно часто мечусь по неизвестному коду (даже по своему...), и если это не C++ честно говоря порой офигеваю...
Ну как бы ты прав, момент важный. Но тут ведь как... Такая "удобная документация" — очень легко поддаётся автоматизации. А коли так, то зачем это делать вручную? Как ты упомянул уже есть туча тулзов которые это делают, вот пусть тулзы этим и занимаются, а мне лень.
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, ·, Вы писали:
A>>Конкретика должна быть такой: A>>1) для чего именно было решено использовать DI, с какой целью, ради каких задач. ·>Там по ссылке расписано. Если чего неясно, задавай вопросы.
Интересует конкретно твой кейс или множество таковых, DI не может быть самоцелью.
A>>2) какой вариант, в контексте п.1, более вменяем, нежели через интерфейсы. ·>Третий раз отвечаю — всё то же самое, но без интерфесов. Просто инжектить конкретный класс.
В четвёртый раз DI не самоцель, конкретные цели с задачами «в студию!» и только после этого обсуждать уже аспекты конкретных подходов.
Например, такой подход, когда в случае C# инжектирую конкретные классы ты будешь использовать System.Object в неявной форме, забыв что там под капотом в плане интерфейсов и занимаясь приведением типов к тому «контракту», который ожидается в жертве инжекта (клиенте).
Здравствуйте, a7d3, Вы писали:
A>>>1) для чего именно было решено использовать DI, с какой целью, ради каких задач. A>·>Там по ссылке расписано. Если чего неясно, задавай вопросы. A>Интересует конкретно твой кейс или множество таковых, DI не может быть самоцелью.
Да причём тут я? Я вообще не рассматривал никакие конкретные кейсы. Я лишь выдвинул тезис, что интерфейсы|абстактные классы к DI никакого отношения не имеют, и чаще всего не нужны.
Если тебя интересуют конкретные кейсы, давай приводи конкретный пример, обсудим.
A>>>2) какой вариант, в контексте п.1, более вменяем, нежели через интерфейсы. A>·>Третий раз отвечаю — всё то же самое, но без интерфесов. Просто инжектить конкретный класс. A>В четвёртый раз DI не самоцель, конкретные цели с задачами «в студию!» и только после этого обсуждать уже аспекты конкретных подходов.
В данном контексте цель была продемонстрировать DI. И тот туториал по ссылке (и подавляющиее число других) это делал коряво, усложнив код введением лишней сущности "интерфейс" — просто так, потому что "так принято", "хороший тон", никакого рационального обоснования там нет, и ты не привёл. Я не понимаю что ты хочешь доказать. Сформулируй свой тезис.
A>Например, такой подход, когда в случае C# инжектирую конкретные классы ты будешь использовать System.Object в неявной форме, забыв что там под капотом в плане интерфейсов и занимаясь приведением типов к тому «контракту», который ожидается в жертве инжекта (клиенте).
Не понял мысль. Можно пример кода?
но это не зря, хотя, может быть, невзначай
гÅрмония мира не знает границ — сейчас мы будем пить чай
Здравствуйте, Mystic Artifact, Вы писали:
S>>·>Вреден как минимум тем, что усложняет пример на пустом месте и учит новичков переусложнизму. S>>Новички в DI не полезут. MA> У новичков нет проблем с DI — они его используют в полный рост, даже не зная как оно называется. Да, куча примеров, предлагают делать интерфейсы, но любой нормальный IoC контейнер может работать с конкретными типами, вдобавок IoC-контейнер — не что иное, как динамически-конфигурируемая фабрика. Несложно понять, что оно нужно далеко не всегда. И даже асп.нет приложении если ты хочешь per-request инстанцирование — интерфейс не нужен.
Здравствуйте, ·, Вы писали:
·>Да причём тут я? Я вообще не рассматривал никакие конкретные кейсы. Я лишь выдвинул тезис, что интерфейсы|абстактные классы к DI никакого отношения не имеют, и чаще всего не нужны.
Подождите, мы DI рассматриваем в контексте IoC контейнеров, где мы в явном виде new никогда не вызываем, а используем,
например, абстрактную фабрику. Ну так вот IoC у меня созвучен с dip, в том плане, что это dip для контроля управления.
А dip говорит, что завязываться на детали (реализации) плохо, лучше завязываться на абстракции. Т.е. мы куда-то встраиваемся
(во фреймворк) через интерфейсы и абстрактные классы.
Здравствуйте, Sharov, Вы писали:
S>Интерфейс нужен с прицелом на юнит тестирование.
Для нормального тестирования нет такой необходимости в принципе. Ты своим утверждением просто на корню отрезаешь огромный класс тестов который чаще всего именуем как black-box тестирование. А в black-box на самом деле можно включить от "поведенческих" тестов, до интеграционных. Интеграционные ближе всех похожи на black-box, но и подсовывание фейков (а еще хуже рантайм моков) — в некотором смысле само по себе интеграционное тестирование (компонентнов).
По сути, что я хочу донести — интерфейсы никак не облегчают тестирование и не нужны для этого вообще, если вы не собрались тестировать насколько качественно компилятор успешно компилирует условные выражения.
Компиляторы сами по себе — отличнейший пример где типичное black-box тестирование работает естественным образом.
Классы достаточно часто содержат приватные методы которые нуждаются но до них невозможно добраться. И да — вместо того, что бы сделать ровно то, что нужно, чаще всего нам советуют ахинею.
Для преодоления этих ограничений, часто появляются методы навроде DoSomethingForTests. Существование подобных методов всегда говорит ровно о 2-3 вещах: 1) публичный API ущербен 2) современные языки ущербны — они не дают возможности работать со СВОИМ кодом, как того требует ситуация 3) как следствие это выражается в костылях: в C# — internal + комментарий о том что это только для тестов (учти — этот метод — констпуктор, и никаких суффиксов не имеет), а комментарий — компилятор нагло игнорирует.
Я все эти техники видел на протяжении всей жизни, они актуальны и сейчас: это говно широко распространено как в .net, абсолютно такая же ситуация в могучем C++.
Ну, и разумеется здесь есть импликация: раз вы (обобщенно) не умеете тестировать классы без зависимостей — то о чем дальше вообще можно вести речь? А вы не умеете — свществующие языки скудоумны и не позволяют. Ввести скопы видтмости это не по феншую а делать паблики *ForTests или internal + InternalVisibleTo это конечно же лучше.
Это что ни наесть — натуральный идиотизм. Никто и ничем не защитится от грубой силы, те же фреймворки навроде Fakes это отлично демонстрируют.
Именно поэтому я и говорю — интерфейс не нужен доя юнит тестирования. Возможность подменить зависимость, лишь дает иллюзию контроллируемости процесса, но на самом деле, (ну оооочень утрированно) вместо нее класс тихо потребляет статическую зависимость и делает вид что все равно работает.
А если кратко: фокусироваться нужно или на поведении или на реализации. Тестирование реализации может (и должно) потребовать доступ к инвариантам или именно импоемениации где ессно лучшие пёрлы скрыты за private. Либо фокусироваться именно на публичном контракте — но это тоже самое что black-box. Любые тесты кто внедряет фейковые зависимости — фактически неявно скрывают за собою закодированное! знание об устройстве мира. Либо тривиальеы и тестируют оператор if.
Со мной в целом то не надо соглашаться, но интерыейс ради теста... это то чего следует избегать, если это возможно в рамках разумного.