А какая разница для прикладного программиста, как там внутри происходит магия, главное чтобы все работало :)
Плюс работа ведется с домеными обьектами и всегда есть возможность спустится на уровень ниже и самому написать запрос или вообще имплементацию метода.
Так вот на мой взгляд это все усложнит код вместо тупого и прямого использование репозиториев которые вы можете отнаследовать от какого то базового который дает стандартные методы get/save/…
Посмотрите на Спринг Дата Репозиторий там вообще кода может не быть даже SQL:
и все — у вас есть для сущности Ордер весь стандартный набор операций плюс кастомный поиск по заказчику и все это гибко без статических методов и выдумывания что делать если надо изменить имплементацию метода.
А потом добавится еще три новых поля и вы пойдете переписывать все слои. Вместо того чтобы добавить эти параметры в ДТО и изменения затронут только те части где работы с этими новыми параметрами нужна.
Второй вариант состоит в том, чтобы добавить к Db возможности редиса и переопределить (где угодно) Get и ByIdRequired как Get(this Db channel, ...) и уже внутри него различать что — в базу, что — в редис.
Это уже не чистая архитектура.
Также у вас интерфейс начнет со временем разбегаться тк редиса захочется использовать чисто его плюшки.
Смотрите у вас код в сервисе вот такой From<Db>().Get<MeasurementUnit>().ByIdRequired(id) и Db может использоваться для работы еще с какими то ентити. Те мы жестко зафиксировали канал в коде. И теперь перенеся Unit ентити в Редис канал(который мы реализовали) мы получаем что все ентити по прежнему достаются из Db а за Юнитом надо идти уже по другому From<Redis>().Get<MeasurementUnit>().ByIdRequired(id)
Верно я понимаю?
Если да то вот про это прибивание гвоздями я и говорю что сервис обьект должен знать про конкретную имплементацию канала для каждой ентити.
А что делать если ентити надо писать и в Редис и ДБ? А читать из Редиса сперва а только потом из ДБ?
Я так понимаю, что ваш вопрос состоял в том, что случится при переходе к Mongodb. Отвечаю: скорее всего у вас поменяется набор плюшек у канала, потому что Mongo не является реляционной БД и работать с ней надо другими средствами.
Вот поэтому у нас и есть объект репозиторий который скрывает имплементацию и все сервисы с ним работающие не знают ничего про его внутренности. А у вас получается что архитектура намертво сбитая где изменения одного слоя автоматически означают изменения в других слоях. Что в моем понимании не есть идеальная архитектура.
И на моей практике надо было делать как полную миграцию с Монги на Постгрес так частичную — часть мы пишем в Постгрес, а часть в Редис. И это было не больно, когда нормально сделаные слои и IoC.
Я полагаю, документация по EF расскажет об этом лучше и подробнее чем я.
спасибо за разъяснение.
ровно то, о чём я писал в статье когда говорил про длинные портянки IoC.
Тем самым вы приколачиваете свои сервис классы к конкретной имплементации сторадж для конкретного ентити. И как только у вас возникнет нужда один (или все) перевести с <Db> на <Mongo> вам придется править весь проект включая тесты которые по хорошему для тестирования бизнес логики и не должны меняться.
Возможно, я смотрю по примерам что есть и ассоциатирую со статьей.Что внутри фреймворка простым программистам зачастую фиолетово. Главное как жить с этим фреймворком.
а там куда не ткни везде вопросы
public void RenameMeasurementUnit(int id, string name, string shortName)
{
var unit = From<Db>().Get<MeasurementUnit>().ByIdRequired(id);
unit.Name = name;
unit.ShortName = shortName;
To<Db>().Update(unit, x => x.Name, x => x.ShortName);
}
где ДТО, почему вместо них просто строки?
как добавить кеш и ее инвалидацию?
как сделать оптимистик локинг?
почему вы считаете что это From<Db>().Get<MeasurementUnit>().ByIdRequired(id) гораздо лучше и проще чем measurementUnitRepository.getById(id). Потому я считаю что Сервис класс не должен знать про никакой <Db> это не его забота как получают и сохраняют MeasurementUnit а забота репозитория для этого обекта. Потому что однажды вы захотите вынести какую нить сущность в Монго например и вот мы начинаем менять по всем сервисам From<Db> на From<Mongo>
Если статья называется Я десять лет страдал от ужасных архитектур в C# приложениях — и вот нашел, как их исправить то код должен быть чтобы комар носа не подточил.
Не только на Джава, но к Шапру имею отдаленное представление. Зачем глубоко понимать Шарп если вот здесь явно видно что вы идете в базу проверяете нет ли такого measurement unit а потом сохраняете. И это неверно тк вы не сможете гарантировать что после того как вы проверили данные другая транзакция не вставит такой же юнит.
Потому что он подтверждает корректную работу реального бизнес-сценария
тестконтейнеры это не юнит тесты. Я подымаю в них постгрес, редис, кафку и начинаю гонять интеграционные тесты. Когда надо сделать бизнес сценарий то можно взять или spock или cucumber или не заморачиваться и просто JUnit и вынести каждый бизнес сценарий в отдельный класс и разбить по тест методам на которые навесить аннотации очередности.
он ещё в разработке, как и сам инструмент
проблема в том что я смотря на код и примеры в плейграунде не вижу легкости и желания работать с этим инструментом. Вот пример спринг дата с еще накрученым кешом сверху. Любой программист поймет что здесь к чему и проще уже некуда.
А у вас то вылазят статик методы а значит все гвоздями прибито, или как вкорячить Редис для персистент стораджа?
Что будет если я два раза добавлю where тут
public IQueryFor<TEntity> That(Expression<Func<TEntity, bool>> @where)
{
_thatExpressions.Add(@where);
return this;
}
или вот здесь зачем приведение к типу? это уже bad smell для меня.
internal T Key<T>(IAddition<IPrimaryKey<T>> keyedAddition)
{
var a = (Add)keyedAddition;
...
Такой код вообще подразумевает что речи о конкурентных запросах не может идти тк толку от проверки на уникальность в коде нет.
Те вы пишите статью с провокационным названием и наполнением заставляющим задуматься, а реализация вызывает недоумение.
В мире шарпа я вообще ничего не знаю, но ради интереса посмотрел код и… останусь я пожалуй в мире джавы и дальше, где все просто и нет у меня боли когда использую Spring или Quarkus или Guice.
Тесты — вот такие портянки я вообще даже не хочу пытаться понять. Лучше я и дальше буду работать с тестконтейнерами, моками и другими библиотеками.
Вот такой класс ошибки это нормально? Где информация типа код ошибки, sql вызвавший ошибку и тд.
У нас принято использовать liquibase или flyway и мне больно видеть вот такое
Метод в сервисе public IAddition<MeasurementUnit> CreateMeasurementUnit(string name, string shortName) — а может стоит использовать домен модели или ДТО какой то? Вы расказываете как все плохо сейчас, но вот такой код приводит что CreateMeasurementUnit("Name #1", "Name #1") непонятно что он принимает просто глядя на метод, легко перепутать аргументы.
что он вообще делает в Features/Reinforced.Tecture.Features.Orm.Query.cs, как это относится к методу, или SOLID это тоже плохо? А что будет если у меня пойдет мультипотоковость и я параллельно буду операции делать ?
Для меня код на Хаскеле понятней чем ваш на шарпе. И я точно бы не захотел чтобы мне пришлось работать с таким велосипедом.
Оверхед в в Яве во времени старта, «прогрева» и потреблении памяти.
Да есть такое, но мы можем взять GraalVM и у нас будет бинарник с быстрым стартом.
По поводу памяти, на каком нить синтетическом тесте где Го все алоцирует на стеке конечно будет большая разница. Насколько будет разница будет в реальном мире — я не знаю, не сравнивал. Если у вас есть сравнения и исходники то я буду благодарен.
Но если у нас все упирается в память то давайте возьмем Раст или разница в год на 1Гб памяти в AWS будет около 90$. Это для хорошего калифорнийского програмиста будет меньше часы работы.
А по сложности языков лично я Го и Яву плюс минус считаю одинаковыми.
Да я тоже так примерно считаю.
P.S. Таргетинг: Го создан как замена Явы, Гугл vs Оракл в энтерпрайзе.
А вот тут проблема, поскольку бизнес логику на Го писать неудобно. Поскольку там не нужны горутины, а нужны способы выразить разные абстракции. А в Го с этим проблематично :( Ни генериков, ни тип-сум, чуть в сторону и торчат уши interface{}
Или как вы будете реализовывать на Го
type User struct {
FirstName String
LastName String
}
но так чтобы он был имутабельный, создавать его можно было с определенным набором данных чтобы быть уверенным что там всегда лежат правильные данные и мы могли читать его свойства FirstName/LastName
Вот пример на Джаве
@Getter
public final class User {
private final String firstName;
private final String lastName;
public User(String firstName, String lastName) {
..../validate
this.firstName = firstName;
this.lastName = lastName;
}
}
и это мне гарантирует что никто его не изменит, никто не подсунет в метод другую имплементацию этого класса, объект будет всегда создан валидным и при этом все могут читать его свойства(это мы еще брали модули с ждк9, где вообще можно разделить доступ).
Вот недавняя статья про Го и чистую архитектуру. Как по мне то для 2020 года такой код выкладывать как эталон чистой архитектуры это печально :(
Давайте и я попробую в последний раз написать как я вижу нашу беседу:
Вы:
VM Java создает не нужный оверхед при исполнении и при разработке.
нет ни каких либо примером или фактов, на что я вам отвечаю
На Джаве программы пишутся быстрее чем на Го. Взять например простой рест ендпоинт который ассинхронный и что то читает с базы и отдает потом жсон наружу. в Джаве со спрингом это будет буквально две строчки кода, в Го я думаю вам придется написать их гораздо больше.
те я готов подтвердить свое утверждение что на Джава я напишу быстрее вот такое чем вы на Го. Я не говорил что должны писать только на чистом Го из коробки без всяких библиотек и так же если я говорю что буду брать спрингбут то это подразумевает что вы вольны брать любую библиотеку тоже.
Ваш ответ
Натянутый пример.
Все упирается в том какие готовые инструменты (библиотеки и пр.) вы используете.
Те вы вместо того чтобы согласиться и показать мне как надо, рассказываете что задание ужасное и вообще все дело в спрингбуте. Так как это соотносится с вашим самым первым сообщением где Джава тормоз в разработке если на все мои попытки ее посрамить вы уходите в какие то разговоры ?
Потом я пытался вам сказать, что бизнесу пофиг на все наши терки, ему главное какая стоимость разработки его пожеланий. И если кто то может делать на готовых кубиках, так это только отлично. Это я к тому, что в реальном мире надо рассматривать эко-системы Джавы и Го целиком, А не считать, что в чистом Го есть горутины а Джаве только системные потоки и значит на Джаве нельзя сделать что либо кроме Thread per Request.
Дальше вы обиделись и начали меня называть тролем.
Поэтому, в который раз, чтобы не флудить словами, а доказать делом мы с вами сделаем вот такой проект и сравним сколько времени заняло, сколько строк кода получилось, какую нагрузку держит и сколько памяти жрет. Это будет лучше чем тысячи слов.
Вот ваше сообщение
в нем нет ни каких фактов, ни примеров, есть только надо быть как Гугл и делать все на Го, а Джава и Раст тормоз в разработке, а Джава так еще и тормоз в рантайме.
Мои предложения о том, что взять и сделать что то одинаковое и потом сравнить, вы просто игнорируете.
Но троль я :))))))
Я могу взять SpringBoot, а могу Quarkus и сделать через GraalVM готовый бинарник. Могу взять Azul GC или вообще без ГЦ запускать. Те с Джава я могу покрыть огромное кол-во use case оставаясь в рамках одной системы и мне не надо менять ни утилиты для работы ни разработчиков. Или взять node.js и тайпсрипт и быть в гармонии на фронтенде и бекенде.
А про Го мне приходится допытываться хоть про какую конкретику.
На Джаве программы пишутся быстрее чем на Го. Взять например простой рест ендпоинт который ассинхронный и что то читает с базы и отдает потом жсон наружу
и вы сказали что это не показатель потому что я буду использовать что то готовое а это не честно. Теперь вы говорите что на Го надо брать библиотеки.
Ну тогда давайте вы покажите пример проекта на Го в котором будет простой ендпоинт который будет ходить в Редис за данными в какой нить лист и отдавать жсон этого листа наружу. Так же проект обернуть тестами с моками для сервис layer и какими нить интеграционными для хождения в Редис. И все должно тестироваться и собираться и потом создавать докер образ — причем под Линуксом/Виндовс/Мак чтобы разработчики могли это все локально собирать и смотреть.
и мы сравним с таким же проектом от меня. и посмотрим кто сколько времени потратил и какой код на выходе получился.
Это имеет отношении к реальности. Если я решаю задачи бизнеса за Х денег на Джаве, а вы за Х*2 на Го, то бизнес не будет волновать, что я читер и взял спрингбут и погнали, а вы с нуля на чистом Го реализовываете весь стек.
П.С. И я все еще хочу увидеть типичный пример микро-сервиса который на Джаве будет тормознутым, а на Расте его реализовать потребуется куча времени, а реализация Го будет быстра и в разработке и рантайме.
Почему натянутый? по большому счету большинство микро-сервисов получили запрос, куда то сходили за данными, как то их по преобразовывали и вернули результат.
Ну или вы скажите пример какой типичный микросервис будет писаться быстрее на Го а на Джаве или Расте это будет ужас ужас.
А какая разница для прикладного программиста, как там внутри происходит магия, главное чтобы все работало :)
Плюс работа ведется с домеными обьектами и всегда есть возможность спустится на уровень ниже и самому написать запрос или вообще имплементацию метода.
Так вот на мой взгляд это все усложнит код вместо тупого и прямого использование репозиториев которые вы можете отнаследовать от какого то базового который дает стандартные методы get/save/…
Посмотрите на Спринг Дата Репозиторий там вообще кода может не быть даже SQL:
и все — у вас есть для сущности Ордер весь стандартный набор операций плюс кастомный поиск по заказчику и все это гибко без статических методов и выдумывания что делать если надо изменить имплементацию метода.
А потом добавится еще три новых поля и вы пойдете переписывать все слои. Вместо того чтобы добавить эти параметры в ДТО и изменения затронут только те части где работы с этими новыми параметрами нужна.
Смотрите у вас код в сервисе вот такой
From<Db>().Get<MeasurementUnit>().ByIdRequired(id)иDbможет использоваться для работы еще с какими то ентити. Те мы жестко зафиксировали канал в коде. И теперь перенеся Unit ентити в Редис канал(который мы реализовали) мы получаем что все ентити по прежнему достаются изDbа за Юнитом надо идти уже по другомуFrom<Redis>().Get<MeasurementUnit>().ByIdRequired(id)Верно я понимаю?
Если да то вот про это прибивание гвоздями я и говорю что сервис обьект должен знать про конкретную имплементацию канала для каждой ентити.
А что делать если ентити надо писать и в Редис и ДБ? А читать из Редиса сперва а только потом из ДБ?
Первая часть вашего комментария отличная. Спасибо
Вот поэтому у нас и есть объект репозиторий который скрывает имплементацию и все сервисы с ним работающие не знают ничего про его внутренности. А у вас получается что архитектура намертво сбитая где изменения одного слоя автоматически означают изменения в других слоях. Что в моем понимании не есть идеальная архитектура.
И на моей практике надо было делать как полную миграцию с Монги на Постгрес так частичную — часть мы пишем в Постгрес, а часть в Редис. И это было не больно, когда нормально сделаные слои и IoC.
поправил :) — почему вместо них просто строки.
спасибо за разъяснение.
Тем самым вы приколачиваете свои сервис классы к конкретной имплементации сторадж для конкретного ентити. И как только у вас возникнет нужда один (или все) перевести с
<Db>на<Mongo>вам придется править весь проект включая тесты которые по хорошему для тестирования бизнес логики и не должны меняться.Возможно, я смотрю по примерам что есть и ассоциатирую со статьей.Что внутри фреймворка простым программистам зачастую фиолетово. Главное как жить с этим фреймворком.
а там куда не ткни везде вопросы
где ДТО, почему вместо них просто строки?
как добавить кеш и ее инвалидацию?
как сделать оптимистик локинг?
почему вы считаете что это
From<Db>().Get<MeasurementUnit>().ByIdRequired(id)гораздо лучше и проще чемmeasurementUnitRepository.getById(id). Потому я считаю что Сервис класс не должен знать про никакой<Db>это не его забота как получают и сохраняютMeasurementUnitа забота репозитория для этого обекта. Потому что однажды вы захотите вынести какую нить сущность в Монго например и вот мы начинаем менять по всем сервисамFrom<Db>наFrom<Mongo>Если статья называется
Я десять лет страдал от ужасных архитектур в C# приложениях — и вот нашел, как их исправитьто код должен быть чтобы комар носа не подточил.Не только на Джава, но к Шапру имею отдаленное представление. Зачем глубоко понимать Шарп если вот здесь явно видно что вы идете в базу проверяете нет ли такого
measurement unitа потом сохраняете. И это неверно тк вы не сможете гарантировать что после того как вы проверили данные другая транзакция не вставит такой же юнит.тестконтейнеры это не юнит тесты. Я подымаю в них постгрес, редис, кафку и начинаю гонять интеграционные тесты. Когда надо сделать бизнес сценарий то можно взять или spock или cucumber или не заморачиваться и просто JUnit и вынести каждый бизнес сценарий в отдельный класс и разбить по тест методам на которые навесить аннотации очередности.
проблема в том что я смотря на код и примеры в плейграунде не вижу легкости и желания работать с этим инструментом. Вот пример спринг дата с еще накрученым кешом сверху. Любой программист поймет что здесь к чему и проще уже некуда.
А у вас то вылазят статик методы а значит все гвоздями прибито, или как вкорячить Редис для персистент стораджа?
Что будет если я два раза добавлю
whereтутили вот здесь зачем приведение к типу? это уже bad smell для меня.
Такой код вообще подразумевает что речи о конкурентных запросах не может идти тк толку от проверки на уникальность в коде нет.
Те вы пишите статью с провокационным названием и наполнением заставляющим задуматься, а реализация вызывает недоумение.
В мире шарпа я вообще ничего не знаю, но ради интереса посмотрел код и… останусь я пожалуй в мире джавы и дальше, где все просто и нет у меня боли когда использую Spring или Quarkus или Guice.
Тесты — вот такие портянки я вообще даже не хочу пытаться понять. Лучше я и дальше буду работать с тестконтейнерами, моками и другими библиотеками.
Вот такой класс ошибки это нормально? Где информация типа код ошибки, sql вызвавший ошибку и тд.
У нас принято использовать liquibase или flyway и мне больно видеть вот такое
Метод в сервисе
public IAddition<MeasurementUnit> CreateMeasurementUnit(string name, string shortName)— а может стоит использовать домен модели или ДТО какой то? Вы расказываете как все плохо сейчас, но вот такой код приводит чтоCreateMeasurementUnit("Name #1", "Name #1")непонятно что он принимает просто глядя на метод, легко перепутать аргументы.Вот этот код
что он вообще делает в
Features/Reinforced.Tecture.Features.Orm.Query.cs, как это относится к методу, или SOLID это тоже плохо? А что будет если у меня пойдет мультипотоковость и я параллельно буду операции делать ?Для меня код на Хаскеле понятней чем ваш на шарпе. И я точно бы не захотел чтобы мне пришлось работать с таким велосипедом.
Да интересно, жаль что я пока связан с aws jdk aka corretto образом и попробовать новые ГЦ в боевых условиях пока не получается :(
интересная статья
Да есть такое, но мы можем взять GraalVM и у нас будет бинарник с быстрым стартом.
По поводу памяти, на каком нить синтетическом тесте где Го все алоцирует на стеке конечно будет большая разница. Насколько будет разница будет в реальном мире — я не знаю, не сравнивал. Если у вас есть сравнения и исходники то я буду благодарен.
Но если у нас все упирается в память то давайте возьмем Раст или разница в год на 1Гб памяти в AWS будет около 90$. Это для хорошего калифорнийского програмиста будет меньше часы работы.
Да я тоже так примерно считаю.
А вот тут проблема, поскольку бизнес логику на Го писать неудобно. Поскольку там не нужны горутины, а нужны способы выразить разные абстракции. А в Го с этим проблематично :( Ни генериков, ни тип-сум, чуть в сторону и торчат уши
interface{}Или как вы будете реализовывать на Го
но так чтобы он был имутабельный, создавать его можно было с определенным набором данных чтобы быть уверенным что там всегда лежат правильные данные и мы могли читать его свойства
FirstName/LastNameВот пример на Джаве
и это мне гарантирует что никто его не изменит, никто не подсунет в метод другую имплементацию этого класса, объект будет всегда создан валидным и при этом все могут читать его свойства(это мы еще брали модули с ждк9, где вообще можно разделить доступ).
Вот недавняя статья про Го и чистую архитектуру. Как по мне то для 2020 года такой код выкладывать как эталон чистой архитектуры это печально :(
Давайте и я попробую в последний раз написать как я вижу нашу беседу:
Вы:
нет ни каких либо примером или фактов, на что я вам отвечаю
те я готов подтвердить свое утверждение что на Джава я напишу быстрее вот такое чем вы на Го. Я не говорил что должны писать только на чистом Го из коробки без всяких библиотек и так же если я говорю что буду брать спрингбут то это подразумевает что вы вольны брать любую библиотеку тоже.
Ваш ответ
Те вы вместо того чтобы согласиться и показать мне как надо, рассказываете что задание ужасное и вообще все дело в спрингбуте. Так как это соотносится с вашим самым первым сообщением где Джава тормоз в разработке если на все мои попытки ее посрамить вы уходите в какие то разговоры ?
Потом я пытался вам сказать, что бизнесу пофиг на все наши терки, ему главное какая стоимость разработки его пожеланий. И если кто то может делать на готовых кубиках, так это только отлично. Это я к тому, что в реальном мире надо рассматривать эко-системы Джавы и Го целиком, А не считать, что в чистом Го есть горутины а Джаве только системные потоки и значит на Джаве нельзя сделать что либо кроме Thread per Request.
Дальше вы обиделись и начали меня называть тролем.
Поэтому, в который раз, чтобы не флудить словами, а доказать делом мы с вами сделаем вот такой проект и сравним сколько времени заняло, сколько строк кода получилось, какую нагрузку держит и сколько памяти жрет. Это будет лучше чем тысячи слов.
Вот ваше сообщение
в нем нет ни каких фактов, ни примеров, есть только надо быть как Гугл и делать все на Го, а Джава и Раст тормоз в разработке, а Джава так еще и тормоз в рантайме.
Мои предложения о том, что взять и сделать что то одинаковое и потом сравнить, вы просто игнорируете.
Но троль я :))))))
Хорошего вам вечера.
Я могу взять SpringBoot, а могу Quarkus и сделать через GraalVM готовый бинарник. Могу взять Azul GC или вообще без ГЦ запускать. Те с Джава я могу покрыть огромное кол-во use case оставаясь в рамках одной системы и мне не надо менять ни утилиты для работы ни разработчиков. Или взять node.js и тайпсрипт и быть в гармонии на фронтенде и бекенде.
А про Го мне приходится допытываться хоть про какую конкретику.
Я не решил как раз, я вам банальный пример привел
и вы сказали что это не показатель потому что я буду использовать что то готовое а это не честно. Теперь вы говорите что на Го надо брать библиотеки.
Ну тогда давайте вы покажите пример проекта на Го в котором будет простой ендпоинт который будет ходить в Редис за данными в какой нить лист и отдавать жсон этого листа наружу. Так же проект обернуть тестами с моками для сервис layer и какими нить интеграционными для хождения в Редис. И все должно тестироваться и собираться и потом создавать докер образ — причем под Линуксом/Виндовс/Мак чтобы разработчики могли это все локально собирать и смотреть.
и мы сравним с таким же проектом от меня. и посмотрим кто сколько времени потратил и какой код на выходе получился.
Это имеет отношении к реальности. Если я решаю задачи бизнеса за Х денег на Джаве, а вы за Х*2 на Го, то бизнес не будет волновать, что я читер и взял спрингбут и погнали, а вы с нуля на чистом Го реализовываете весь стек.
П.С. И я все еще хочу увидеть типичный пример микро-сервиса который на Джаве будет тормознутым, а на Расте его реализовать потребуется куча времени, а реализация Го будет быстра и в разработке и рантайме.
Почему натянутый? по большому счету большинство микро-сервисов получили запрос, куда то сходили за данными, как то их по преобразовывали и вернули результат.
Ну или вы скажите пример какой типичный микросервис будет писаться быстрее на Го а на Джаве или Расте это будет ужас ужас.