Информационная система всё равно хранит и изменяет состояние, а делают изменения процессы.
Все верно. И в этом проблема, процессы построены на связи микросервисов через средства (Rest, gRPC и тд), которые в свою очередь ломаются и не доходят. Бизнес-логика начинает зависеть от того, как именно мы связали сервисы. Я хочу от этого уйти.
Если нужна согласованность данных, в любом случае будут правила, не допускающие повторных изменений и повторяющие попытки изменений, если они почему-то не произошли
И тут все верно, но в микросервисном мире эти правила размазаны между ними. То есть в одном сервисе 1я часть правил, во 2м вторая и так далее. В итоге согласованность - это не свойство модели, а эффект взаимодействия нескольких компонентов. Хотелось бы собрать эту логику в одном месте и сделать её атомарной и транзакционной.
Т.е. любой оркестратор, если он поддерживает согласованность данных, будет делать то, что вы описываете. И даже без оркестратора (стиль "хореография") будет то же самое, только логика размазана по сервисам.
В классическом оркестраторе согласованность данных является следствием корректно выполненного процесса: если все шаги A - B - C отработали, то состояние считается валидным. Если что-то не дошло — добавляются ретраи, компенсации и т.д. Я сознательно хочу перевернуть приоритеты. Первично не "какие шаги нужно выполнить2, а "какие инварианты состояния должны быть истинны после любого события". Процессов как таковых Engine не знает - он лишь применяет правила, пока состояние не станет согласованным, либо откатывается.
Внешне Engine действительно может выглядеть как оркестратор с жёсткой транзакцией. Отличие для меня в том, что порядок действий не кодируется явно и не является частью бизнес-логики - он выводится из зависимостей/правил между состояниями.
На мой взгляд немного не хватило теоретической глубины)
DLT предназначен не только для складирования ошибок десериализации и прочих но и обеспечения их наблюдаемости в асинхронных системах. Стоит упомянуть, что в крупных системах, сам факт сохранения доказательств и контекста сбоя для дальнейшей обработки - богоугодное дело)) По факту DLT — это не мусорка, а карантинный архив.
Не всегда Вам в pipeline дадут доступ к докеру. В этом случае могу порекомендовать Zonky который поднимет postgresQL в памяти без всяких контейнеров. Удобно и ощутимо быстрее чем с контейнерами.
Кроме того поголовное покрытие каждого метода интеграционными тестами приведет вас в Ад)) (был, видел) поэтому советую придерживаться пирамиды тестирования - много юнитов, чуть меньше модульных без контекста и мало интеграционных.
Можно все программирование свести к одной табличке. Но глубокого понимания причин того или иного решения это не даст. Этим скорее всего и отличаются кодеры от программистов.
Это не проблема в глобальном смысле, пока ты не начинаешь бороться с чистотой и производительностью кода. Странно то, что многие, в том числе из перечисленных в конце статей, не до конца осознают из-за чего это все происходит.
В целом наверно Ваше мнение поддерживает большинство. Но я так не хочу)
Наверно надо начинать материться в комментариях чтобы тебя не считали ллм) Теперь вся элементарная вежливость и знание знаков препинания и правил русского языка будет относить тебя к ним...
Вы абсолютно правы, JPA-сущности (@Entity) требуют конструктор по умолчанию. Но это другой тип класса с другим жизненным циклом, управляемым Hibernate, а не Spring DI. Мы говорим о сервисах, компонентах и репозиториях (@Service, @Component, @Repository), где вся логика работы строится на зависимостях, и их целостность критична.
Так это и проходит красной нитью через весь текст)
"К моменту завершения конструктора все инварианты должны быть выполнены. Объект, вышедший из конструктора, обязан быть целостным (consistent) и готовым к работе."
Я подумаю насчет статьи. А пока скажу, чтоsynchronized напрямую манипулирует Mark Word объекта для реализации легковесных блокировок, аReentrantLock вроде использунт механизм AQS, который практически не влияет на Mark Word самого защищаемого объекта, а иногда даже не требует отдельного объекта для блокировки
Все верно. И в этом проблема, процессы построены на связи микросервисов через средства (Rest, gRPC и тд), которые в свою очередь ломаются и не доходят. Бизнес-логика начинает зависеть от того, как именно мы связали сервисы. Я хочу от этого уйти.
И тут все верно, но в микросервисном мире эти правила размазаны между ними. То есть в одном сервисе 1я часть правил, во 2м вторая и так далее. В итоге согласованность - это не свойство модели, а эффект взаимодействия нескольких компонентов. Хотелось бы собрать эту логику в одном месте и сделать её атомарной и транзакционной.
В классическом оркестраторе согласованность данных является следствием корректно выполненного процесса: если все шаги A - B - C отработали, то состояние считается валидным. Если что-то не дошло — добавляются ретраи, компенсации и т.д. Я сознательно хочу перевернуть приоритеты. Первично не "какие шаги нужно выполнить2, а "какие инварианты состояния должны быть истинны после любого события".
Процессов как таковых Engine не знает - он лишь применяет правила, пока состояние не станет согласованным, либо откатывается.
Внешне Engine действительно может выглядеть как оркестратор с жёсткой транзакцией. Отличие для меня в том, что порядок действий не кодируется явно и не является частью бизнес-логики - он выводится из зависимостей/правил между состояниями.
Я согласен, что внешне это похоже на оркестрацию, потому что есть центральный компонент. Разница для меня не в топологии, а в том кто за что отвечает.
Оркестратор управляет процессами, сделай A → потом B → если не получилось — компенсируй C, а моя идея управляет состоянием данных.
Идеи схожи, но отличие именно в модели мышления process-first и state-first
Спасибо за статью!
На мой взгляд немного не хватило теоретической глубины)
DLT предназначен не только для складирования ошибок десериализации и прочих но и обеспечения их наблюдаемости в асинхронных системах. Стоит упомянуть, что в крупных системах, сам факт сохранения доказательств и контекста сбоя для дальнейшей обработки - богоугодное дело))
По факту DLT — это не мусорка, а карантинный архив.
Спасибо за статью)
Не всегда Вам в pipeline дадут доступ к докеру. В этом случае могу порекомендовать Zonky который поднимет postgresQL в памяти без всяких контейнеров. Удобно и ощутимо быстрее чем с контейнерами.
Кроме того поголовное покрытие каждого метода интеграционными тестами приведет вас в Ад)) (был, видел) поэтому советую придерживаться пирамиды тестирования - много юнитов, чуть меньше модульных без контекста и мало интеграционных.
Погуглите проект Valhalla
Это да. Уже не раз встречал и каждый раз страдаю)
Сразу хотел добавить демонстрационный код, но побоялся из-за объема. Сейчас подумал и добавил)
Спасибо за подсказку, добавил)
Ну на поверхности или нет, но очень часто вижу, что многие этого вовсе не знали)
Аргументов в пользу field injection кроме как удобства нет)
Ничего не понятно, но очень интересно...
Чтобы было меньше сомнений. Так пишешь-пишешь пол дня, а потом ты - ллм)
Можно все программирование свести к одной табличке. Но глубокого понимания причин того или иного решения это не даст. Этим скорее всего и отличаются кодеры от программистов.
Это не проблема в глобальном смысле, пока ты не начинаешь бороться с чистотой и производительностью кода. Странно то, что многие, в том числе из перечисленных в конце статей, не до конца осознают из-за чего это все происходит.
В целом наверно Ваше мнение поддерживает большинство. Но я так не хочу)
Наверно надо начинать материться в комментариях чтобы тебя не считали ллм) Теперь вся элементарная вежливость и знание знаков препинания и правил русского языка будет относить тебя к ним...
Вы абсолютно правы, JPA-сущности (
@Entity) требуют конструктор по умолчанию. Но это другой тип класса с другим жизненным циклом, управляемым Hibernate, а не Spring DI. Мы говорим о сервисах, компонентах и репозиториях (@Service,@Component,@Repository), где вся логика работы строится на зависимостях, и их целостность критична.Так это и проходит красной нитью через весь текст)
"К моменту завершения конструктора все инварианты должны быть выполнены. Объект, вышедший из конструктора, обязан быть целостным (consistent) и готовым к работе."
Я бы вам порекомендовал в качестве дто использовать не объекты из OpenApi, а из JOOQ. Там и record'ы есть для спокойной передачи данных
Спасибо за статью, позволю себе несколько замечаний по коду (так сказать ревью):
Mono<@NonNullVoid>- крайне спорно и по-моему бессмысленнов UserServiceотсутствует обработка ошибок. Вообще.В целом подозреваю, что все это сделано из-за быстроты и генерации части кода OpenAPI Generator. Советую поставить openApiNullable: "true".
Есть непонятный мне конфликт:
useOptional: "true", //Использовать Optional
openApiNullable: "false", // Но ничего не может быть null?!
В тесте вообще не пойму откуда
User user =newUser();Ведь если это DTO из OpenAPI то как минимум в коде вижу
UpdateUser.Да и чтоUpdateUserделает в createUser методе?)В github вообще не нашел папки по пути ru.maximserver.vmuserservice.model указанные в сервисном слое.
Очень много загадочного в проекте на мой взгляд))
Прошу простить, что надушнил, но кто-то(например я) захочет что-то изучить по вашему коду и столкнется с множеством проблем.
Спасибо за мнение!
Я подумаю насчет статьи. А пока скажу, что
synchronizedнапрямую манипулирует Mark Word объекта для реализации легковесных блокировок, аReentrantLockвроде использунт механизм AQS, который практически не влияет на Mark Word самого защищаемого объекта, а иногда даже не требует отдельного объекта для блокировки