предложу свое решение с примером сделал интерфейс дженерик + создал классы как "тег\маркер" в итоге инджекчю то что нужно или IRedis<AwsTag> или IRedis<DockerTag>
эти маркеры это почти те же ключи, только я их строкой не передаю, и провтыкать их нереально
то что его можно инжектить это понятно, я про использование его в ConfigureServices, а еще хуже когда у вас екстеншн метод от другой библиотеки services.AddSomeService("section"), где как должна выглядеть секция знает только дока
да, и вообще IConfiguration не удобен, банально когда нужно достать конфиг во время DI регистраций, там уже нужно танцевать или делать что то на конвеншенах
Скажите, а плохая ли идея сделать так?
На какой-то бирже открыть кошельки, дальше принимать оплату на них, при получении суммы, начислить человеку баланс у себя в системе, так же при выводе и обмене делать все через свой кошелек и api
Ещё на сколько я знаю, вроде как есть, «теневой кошелек» на который можно принимать оплату, а по факту деньги улетают на другой кошелек, а этот лишь прокси и можно принимать валюту через него.
Поэтому приложение должно быть написано таким образом, чтобы не допустить получения пользователем этого потенциального несоответствия.
Я нашел эту статью как раз по запросу как писать такие приложения, жаль что тут ответа нет.
Пока что, у меня ощущения что в распределённых приложениях невозвоможно добится 100% консистентности даже eventual
Вы совместили 2 паттерна «Стратегия» и «Состояние», и получилось это не лучшим способом.
Я понял направление статьи сам некоторые вещи решаю так, но делаю немного иначе так как ваши примеры нарушают некоторые принципы SOLID + «Просто добавить новый класс» в такой реализации не выйдет. Почему не выйдет? Что Вы будете делать когда в каком-то состоянии 2 из 3 методов реализовать просто нельзя? NotImplementedException? null — нарушаем LSP.
Что Вы будете делать когда в каком-то состоянии 2 из 3 методов должны иметь ту же реализацию что и в другом стейте?
Я рекомендую сильнее дробить реализации этих паттенов, то-есть брать не целый Агрегат и описывать его состояния такими классами, а реализовывать стратегию\состояние с одним методом (Handle, Execute, Run, MoveNext, etc). В случае «Стратегии» — просто что-то делаем, «Состояние» — что то делаем и возвращаем новое состояние.
При таком дроблении у вас будет на каждый метод (Enter, Cancel, Accept) свои пачки разных реализаций, где-то 2, где-то 3, где-то 5, а какой-то класс выше уже будет всем этим рулить. Хотя и тут уже не все тривиально выглядит :), ведь все равно кто то будет через if-else выбирать реализацию
Updated:
Жалко что статья — перевод, автор не обсудит мои мысли со мной
Прекрасно понимаю SOLID. Код пишу уже более 5 лет, и появились размышления что мы делаем много на «а вдруг...». Мы платим сейчас чтоб ПОТОМ ВОЗМОЖНО заплатить меньше и мне кажется что тут больше убытка чем выгоды.
Мы в каждой задаче закладываем доп работу чтоб если-что, легче было потом, но ведь чаще это потом не наступает.
— А вдруг мы захотим сменить бд? — Камон, при смене бд самое просто поменять код под новую бд. А мигрировать данные, по мне так в разы сложнее.
— А вдруг мы захотим резко удалить наш проект и слиться? — Почему ж тут мы не делаем функционал для удаления всего по одной кнопке? (сарказм)
На хабре есть статья про то что люди уже боятся писать тестовое так как они считают лучше. Ибо я и многие другие понимают что хотят увидеть на тестовом — типичную 3-х слойную архитектуру, без кода в контролерах.
Такие реализации скорее всего о другом к примеру для паттернов Стратегия, Фабрика и тд
Но разные реализации того же репозитория — никогда. (мок не считается)
классная библиотека.
Я когда сам перешел на медиатор, мне контролеры с одной строкой казались ещё более бесполезными, я тогда написал решение похожее на эту библиотеку.
В итоге у меня появилась возможность вешать [Route] [Http...] на хендлеры медиатора.
Таким образом мы можем использовать mysql, а затем, если нам необходимо будет, мы напишем новый класс, где будет общение с другой бд
то-есть когда у Вас будет таска «переехать на другую бд» Вы сразу создадите новую реализацию и в DI её зарегистрируете вместо старой, а старая в свою очередь будет просто существовать? («А вдруг вернуться захотим?», «А вдруг захотим оба источника использовать? — тут придется ещё и интерфейс поменять»)
По мне так проще изменить сразу первую реализацию и всё.
предложу свое решение с примером
сделал интерфейс дженерик + создал классы как "тег\маркер"
в итоге инджекчю то что нужно
или IRedis<AwsTag>
или IRedis<DockerTag>
эти маркеры это почти те же ключи, только я их строкой не передаю, и провтыкать их нереально
то что его можно инжектить это понятно, я про использование его в ConfigureServices, а еще хуже когда у вас екстеншн метод от другой библиотеки services.AddSomeService("section"), где как должна выглядеть секция знает только дока
да, и вообще IConfiguration не удобен, банально когда нужно достать конфиг во время DI регистраций, там уже нужно танцевать или делать что то на конвеншенах
На какой-то бирже открыть кошельки, дальше принимать оплату на них, при получении суммы, начислить человеку баланс у себя в системе, так же при выводе и обмене делать все через свой кошелек и api
Ещё на сколько я знаю, вроде как есть, «теневой кошелек» на который можно принимать оплату, а по факту деньги улетают на другой кошелек, а этот лишь прокси и можно принимать валюту через него.
Я нашел эту статью как раз по запросу как писать такие приложения, жаль что тут ответа нет.
Пока что, у меня ощущения что в распределённых приложениях невозвоможно добится 100% консистентности даже eventual
Чем больше сила — тем больше ответственность!
мой канал на Вашем сайте заработал 500$, на деле 200$
Я понял направление статьи сам некоторые вещи решаю так, но делаю немного иначе так как ваши примеры нарушают некоторые принципы SOLID + «Просто добавить новый класс» в такой реализации не выйдет. Почему не выйдет? Что Вы будете делать когда в каком-то состоянии 2 из 3 методов реализовать просто нельзя? NotImplementedException? null — нарушаем LSP.
Что Вы будете делать когда в каком-то состоянии 2 из 3 методов должны иметь ту же реализацию что и в другом стейте?
Я рекомендую сильнее дробить реализации этих паттенов, то-есть брать не целый Агрегат и описывать его состояния такими классами, а реализовывать стратегию\состояние с одним методом (Handle, Execute, Run, MoveNext, etc). В случае «Стратегии» — просто что-то делаем, «Состояние» — что то делаем и возвращаем новое состояние.
При таком дроблении у вас будет на каждый метод (Enter, Cancel, Accept) свои пачки разных реализаций, где-то 2, где-то 3, где-то 5, а какой-то класс выше уже будет всем этим рулить. Хотя и тут уже не все тривиально выглядит :), ведь все равно кто то будет через if-else выбирать реализацию
Updated:
Жалко что статья — перевод, автор не обсудит мои мысли со мной
Мы в каждой задаче закладываем доп работу чтоб если-что, легче было потом, но ведь чаще это потом не наступает.
— А вдруг мы захотим сменить бд? — Камон, при смене бд самое просто поменять код под новую бд. А мигрировать данные, по мне так в разы сложнее.
— А вдруг мы захотим резко удалить наш проект и слиться? — Почему ж тут мы не делаем функционал для удаления всего по одной кнопке? (сарказм)
Уже справлялся.
И мы переехали на GRPC
Но разные реализации того же репозитория — никогда. (мок не считается)
Я когда сам перешел на медиатор, мне контролеры с одной строкой казались ещё более бесполезными, я тогда написал решение похожее на эту библиотеку.
В итоге у меня появилась возможность вешать [Route] [Http...] на хендлеры медиатора.
то-есть когда у Вас будет таска «переехать на другую бд» Вы сразу создадите новую реализацию и в DI её зарегистрируете вместо старой, а старая в свою очередь будет просто существовать? («А вдруг вернуться захотим?», «А вдруг захотим оба источника использовать? — тут придется ещё и интерфейс поменять»)
По мне так проще изменить сразу первую реализацию и всё.