Привет!
Мысли в слух.
Наткнулся на очередную свеженькую статью по чистой архитектуре.
В двух словах: чистая архитектура - это не про пакеты - не заводите пакеты domain, application, infrastructure, web, заводите пакеты по фичам.
В целом ничего супероригинального, но любопытный аргумент в пользу пакетирования по фичам там есть — по мере жизни приложения, у него появляются новые фичи, а новые слои — практически никогда.
И так как покой мне только снится, это меня натолкнуло на мысль о потенциальной эргономичной структуре программ в4. в3 выглядит так, напомню.
Сейчас она у меня в целом работает и серьёзных нареканий нет, но мне не нравится фактическое дублирование содержания пакетов app и core, в случае если app декомпозируется по фичам.
И вот глядя на этот пост, я подумал, что гипотетически, в в4 я мог бы вернуться к декомпозиции по домену/фичам на первом уровне, но для решения проблемы лишних зависимостей добавил бы компоненты без состояния.
#posts@ergonomic_code #clean_architecture@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code
Мысли в слух.
Наткнулся на очередную свеженькую статью по чистой архитектуре.
В двух словах: чистая архитектура - это не про пакеты - не заводите пакеты domain, application, infrastructure, web, заводите пакеты по фичам.
В целом ничего супероригинального, но любопытный аргумент в пользу пакетирования по фичам там есть — по мере жизни приложения, у него появляются новые фичи, а новые слои — практически никогда.
И так как покой мне только снится, это меня натолкнуло на мысль о потенциальной эргономичной структуре программ в4. в3 выглядит так, напомню.
Сейчас она у меня в целом работает и серьёзных нареканий нет, но мне не нравится фактическое дублирование содержания пакетов app и core, в случае если app декомпозируется по фичам.
И вот глядя на этот пост, я подумал, что гипотетически, в в4 я мог бы вернуться к декомпозиции по домену/фичам на первом уровне, но для решения проблемы лишних зависимостей добавил бы компоненты без состояния.
#posts@ergonomic_code #clean_architecture@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code
Medium
Clean Architecture is NOT a project structure.
Clean Architecture is NOT a project structure. Countless articles are written about Clean Architecture, and some of the basic stuff people get right. But there’s one common issue I see over and …
Карта канала (Так же в Max)
Добро пожаловать на канал "Эргономичный код" — канал о разработке поддерживаемых кодовых баз в общем и моём подходе к этой задаче — Эргономичном подходе.
Что такое Эргономичный подход?
По большому счёту это небольшой набор принципов, взятых в основном из классической школы TDD, функциональной архитектуры и DDD, и большой набор рецептов — моделей, методик и шаблонов —, которые позволяют команде быстро создавать кодовые базы, соответствующие этим принципам и, как следствие, лёгкие в поддержке.
Подробности на сайте Эргономичного подхода
В Эргономичном подходе есть что-то уникальное?
Да. Идея представления системы как модели её эффектов в виде диаграммы эффектов и методика проектирования на базе этой модели.
"Слова дёшевы, покажи мне код!"
Trainer Advisor — некоммерческий, но реальный (~20K строк Котлин кода, 21 таблица, 2 настоящих пользователя, горки костылей, "компромиссных решений" и исторических наслоений) проект с открытым исходным кодом, разрабатываемый по Эргономичному подходу. В этот проект можно поконтрибьютить и на своём опыте прочувствовать работу с эргономичной кодовой базой.
Project Mariotte — минимальный демонстрационный пример кодовой базы, написанной по Эргономичному подходу, на примере операции бронирования номера в отеле
Есть что посмотреть или послушать?
Да, все мои публичные выступления собраны на одной странице
А почитать, кроме канала?
Да, в блоге
В блоге и канале есть подборки:
- Кейсы (в блоге, в канале #case@ergonomic_code)
- Примеры кода (в блоге)
- Эргономичный подход (в блоге, в канале #ergo_approach@ergonomic_code)
- Эргономичное тестирование (в блоге, в канале #ergo_testing@ergonomic_code)
- Функциональная архитектура (в блоге, в канале #functional_architecture@ergonomic_code)
- Эргономиный персистанс (в блоге, в канале #ergo_persistance@ergonomic_code)
- Что ещё почитать (в блоге, в канале #books@ergonomic_code, #posts@ergonomic_code, #papers@ergonomic_code)
- Что ещё посмотреть (в блоге, в канале #talks@ergonomic_code)
Какие ваши доказательства?
Исследование "Характеристики поддерживаемых кодовых баз backend-приложений"
А у меня вопрос!
Приходите в группу - там целому сообществу (более 100 крутых инженеров) можно задать любой вопрос по тематике канала - Эргономичный подход, классическая школа ТДД, ФА, ФП, в целом дизайн модели и системный дизайн
Как мне научить ИИ агента писать код по Эргономичному подходу?
Попробуйте раннюю версию моего фреймворка для ИИ-агентов.
Добро пожаловать на канал "Эргономичный код" — канал о разработке поддерживаемых кодовых баз в общем и моём подходе к этой задаче — Эргономичном подходе.
Что такое Эргономичный подход?
По большому счёту это небольшой набор принципов, взятых в основном из классической школы TDD, функциональной архитектуры и DDD, и большой набор рецептов — моделей, методик и шаблонов —, которые позволяют команде быстро создавать кодовые базы, соответствующие этим принципам и, как следствие, лёгкие в поддержке.
Подробности на сайте Эргономичного подхода
В Эргономичном подходе есть что-то уникальное?
Да. Идея представления системы как модели её эффектов в виде диаграммы эффектов и методика проектирования на базе этой модели.
"Слова дёшевы, покажи мне код!"
Trainer Advisor — некоммерческий, но реальный (~20K строк Котлин кода, 21 таблица, 2 настоящих пользователя, горки костылей, "компромиссных решений" и исторических наслоений) проект с открытым исходным кодом, разрабатываемый по Эргономичному подходу. В этот проект можно поконтрибьютить и на своём опыте прочувствовать работу с эргономичной кодовой базой.
Project Mariotte — минимальный демонстрационный пример кодовой базы, написанной по Эргономичному подходу, на примере операции бронирования номера в отеле
Есть что посмотреть или послушать?
Да, все мои публичные выступления собраны на одной странице
А почитать, кроме канала?
Да, в блоге
В блоге и канале есть подборки:
- Кейсы (в блоге, в канале #case@ergonomic_code)
- Примеры кода (в блоге)
- Эргономичный подход (в блоге, в канале #ergo_approach@ergonomic_code)
- Эргономичное тестирование (в блоге, в канале #ergo_testing@ergonomic_code)
- Функциональная архитектура (в блоге, в канале #functional_architecture@ergonomic_code)
- Эргономиный персистанс (в блоге, в канале #ergo_persistance@ergonomic_code)
- Что ещё почитать (в блоге, в канале #books@ergonomic_code, #posts@ergonomic_code, #papers@ergonomic_code)
- Что ещё посмотреть (в блоге, в канале #talks@ergonomic_code)
Какие ваши доказательства?
Исследование "Характеристики поддерживаемых кодовых баз backend-приложений"
А у меня вопрос!
Приходите в группу - там целому сообществу (более 100 крутых инженеров) можно задать любой вопрос по тематике канала - Эргономичный подход, классическая школа ТДД, ФА, ФП, в целом дизайн модели и системный дизайн
Как мне научить ИИ агента писать код по Эргономичному подходу?
Попробуйте раннюю версию моего фреймворка для ИИ-агентов.
Эргономичный подход
Редирект на индексную страницу
🔥6❤4👍3
Привет!
Наконец-то опубликовали официальную запись моего доклада "Структурный дизайн. Древний секрет простого и быстрого кода" с Joker '24 ! 🎉🎉🎉
#talks@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #structured_design@ergonomic_code
Наконец-то опубликовали официальную запись моего доклада "Структурный дизайн. Древний секрет простого и быстрого кода" с Joker '24 ! 🎉🎉🎉
#talks@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #structured_design@ergonomic_code
YouTube
Алексей Жидков — Структурный дизайн. Древний секрет простого и быстрого кода
Подробнее о Java-конференциях:
— весной — JPoint: https://jrg.su/gTrwHx
— осенью — Joker: https://jrg.su/h7yvG4
— —
Скачать презентацию с сайта Joker — https://jrg.su/TWOpZS
В докладе — краткий экскурс в структурный дизайн и, в частности, в понятие сбалансированных…
— весной — JPoint: https://jrg.su/gTrwHx
— осенью — Joker: https://jrg.su/h7yvG4
— —
Скачать презентацию с сайта Joker — https://jrg.su/TWOpZS
В докладе — краткий экскурс в структурный дизайн и, в частности, в понятие сбалансированных…
👍21🎉13🔥3
Привет!
Прочитал субстак про Radical Object-Orientation (автор его ещё дописывает)
Имхо - Эргономичная архитектура, только в профиль.
- PoMO - очень напоминает то, что у меня ресурс может быть включен только в один другой ресурс
- IOSP - очень напоминает сбалансированную форму системы
- У него тоже дизайн рекурсивен - атомарная операция ио с точки зрения оркестрации сама может оказаться оркестрацией на своём уровне абстракции
- Так же придерживатеся мнения, что абстракция != public interface - "Integrations are abstractions as well."
- Но у автора всё, включая интеграции - есть объект. У меня, по крайней мере синтаксически, объектами (штуками эксклюзивно владеющими собственными состоянием) являются только ресурсы, а операции - это скрипты которые заимствуют состояние ресурсов и тем самым разделяют его между собой. Но. Всё приложение в целом - можно считать объектом.
Из минусов:
- (Относительно) многа букаф и картинок и очень мало кода, а тот что есть - тривиальный и про консольные приложения
- Аналогия с клетками привлекательная, но не очень... Клетки действительно организуют очень крутые, сложные и адаптивные системы. Которые человечество за миллион человеко-часов понять не может - хотим ли мы поддерживать такие системы?
- А ещё я в #project_r@ergonomic_code опять (но теперь под другим углом) начал сталкиваться с тем, что инкапсуляция состояния плохо масштабируется, так как влечёт неограниченный рост поверхности АПИ ключевых/центральных/фундаментальных объектов-ресусров.
Вердикт: по принципу "повторение - мать учения" и "количество переходит в качество" - советую почитать. Но мне кажется у меня сейчас те же по сути идеи поданы лучше - как минимум у меня довольно много примеров реального кода, а не консольных утилиток.
#posts@ergonomic_code #ergo_approach@ergonomic_code #oop@ergonomic_code
Прочитал субстак про Radical Object-Orientation (автор его ещё дописывает)
Имхо - Эргономичная архитектура, только в профиль.
- PoMO - очень напоминает то, что у меня ресурс может быть включен только в один другой ресурс
- IOSP - очень напоминает сбалансированную форму системы
- У него тоже дизайн рекурсивен - атомарная операция ио с точки зрения оркестрации сама может оказаться оркестрацией на своём уровне абстракции
- Так же придерживатеся мнения, что абстракция != public interface - "Integrations are abstractions as well."
- Но у автора всё, включая интеграции - есть объект. У меня, по крайней мере синтаксически, объектами (штуками эксклюзивно владеющими собственными состоянием) являются только ресурсы, а операции - это скрипты которые заимствуют состояние ресурсов и тем самым разделяют его между собой. Но. Всё приложение в целом - можно считать объектом.
Из минусов:
- (Относительно) многа букаф и картинок и очень мало кода, а тот что есть - тривиальный и про консольные приложения
- Аналогия с клетками привлекательная, но не очень... Клетки действительно организуют очень крутые, сложные и адаптивные системы. Которые человечество за миллион человеко-часов понять не может - хотим ли мы поддерживать такие системы?
- А ещё я в #project_r@ergonomic_code опять (но теперь под другим углом) начал сталкиваться с тем, что инкапсуляция состояния плохо масштабируется, так как влечёт неограниченный рост поверхности АПИ ключевых/центральных/фундаментальных объектов-ресусров.
Вердикт: по принципу "повторение - мать учения" и "количество переходит в качество" - советую почитать. Но мне кажется у меня сейчас те же по сути идеи поданы лучше - как минимум у меня довольно много примеров реального кода, а не консольных утилиток.
#posts@ergonomic_code #ergo_approach@ergonomic_code #oop@ergonomic_code
Substack
Radical Object-Orientation | Ralf Westphal | Substack
Object-orientation grown from its roots. Click to read Radical Object-Orientation, by Ralf Westphal, a Substack publication with hundreds of subscribers.
👍8
Привет!
Heartbeat-пост.
Я жив. И канал жив. И Эргономичный подход жив.
Затишье в последнее время связано в основном с тем, что я в Trainer Adviser пилю интеграцию с ical-календарями.
Там не то чтобы прям рокетсайнс, но уже и не совсем тривиальный круд - будет больше примеров нетривиального кода по ЭП.
Но это я днём руками работают. А ночью думаю. Что взять на замену функциональной архитектуре. И у меня тут появилась идея CQTS Principle - Command-Query-Transformation Principle.
Берём старый добрый CQS скрещиваем его со сбалансированной формой системы и получаем профит. Это пока мысль в слух - не знаю стоит ли дальше этот термин педалировать или ну его.
#trainer_advisor@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #structured_design@ergonomic_code
Heartbeat-пост.
Я жив. И канал жив. И Эргономичный подход жив.
Затишье в последнее время связано в основном с тем, что я в Trainer Adviser пилю интеграцию с ical-календарями.
Там не то чтобы прям рокетсайнс, но уже и не совсем тривиальный круд - будет больше примеров нетривиального кода по ЭП.
Но это я днём руками работают. А ночью думаю. Что взять на замену функциональной архитектуре. И у меня тут появилась идея CQTS Principle - Command-Query-Transformation Principle.
Берём старый добрый CQS скрещиваем его со сбалансированной формой системы и получаем профит. Это пока мысль в слух - не знаю стоит ли дальше этот термин педалировать или ну его.
#trainer_advisor@ergonomic_code #ergo_approach@ergonomic_code #functional_architecture@ergonomic_code #structured_design@ergonomic_code
❤3👍2
Эргономичный код
Привет! С подачи Романа Русакова запоем прочитал The API. Очень крутая книга, рекомендую. Роман - спасибо:) Так же вы, возможно, задаётесь вопросом что это я затих. Вряд ли, конечно, но я всё равно отвечу - лопачу джиру Проект Э:) Чтобы понять стоило ли…
Привет!
Я тут недавно прочитал Overengineering in Onion/Hexagonal Architectures (перевод).
В целом с посылом поста я согласен (кроме мёржа REST-аннотаций в сервисы, хотя сам об этом думал), но там ничего суперкрутого - этот мой пост не про тот пост:)
А про собственную...Глу... человечность, назовём это так:)
В посте по ссылке есть тезис:
Но я в 22-ом году (на 18-ом году коммерческой практики и примерно 5-ом году знания про Чистую архитектуру, ДДД, оркестрацию и сервисы приложений) всё равно изобрёл объектно-ориентированную декомпозицию. И пошёл делать по ней #project_e. И получил ровно, то, чего позволяют избегать сервисы приложений - высокую связанность между модулями-объектами.
Сколько ещё у меня таких "изобретений" из-за того что "смотрю в книгу, вижу фигу"? Вопрос риторический, конечно. Время покажет, всё что покажет - расскажу как на духу. Сегодня начал писать пост с ретро #project_r
PS>
И в топик "простых" CRUD приложений из комментов ко вчерашнему посту: в Overengineering in Onion/Hexagonal Architectures про них тоже тоже есть:
#posts@ergonomic_code #ergo_arch@ergonomic_code #ergo_approach@ergonomic_code
Я тут недавно прочитал Overengineering in Onion/Hexagonal Architectures (перевод).
В целом с посылом поста я согласен (кроме мёржа REST-аннотаций в сервисы, хотя сам об этом думал), но там ничего суперкрутого - этот мой пост не про тот пост:)
А про собственную...
В посте по ссылке есть тезис:
To put it another way, it is a design goal of the Application Service to host orchestration logic to allow lower-level components to become less coupled to one another.
—
Другими словами, Application Services предназначены для размещения логики оркестрации, что позволяет компонентам более низкого уровня быть менее связанными друг с другом.
Но я в 22-ом году (на 18-ом году коммерческой практики и примерно 5-ом году знания про Чистую архитектуру, ДДД, оркестрацию и сервисы приложений) всё равно изобрёл объектно-ориентированную декомпозицию. И пошёл делать по ней #project_e. И получил ровно, то, чего позволяют избегать сервисы приложений - высокую связанность между модулями-объектами.
Сколько ещё у меня таких "изобретений" из-за того что "смотрю в книгу, вижу фигу"? Вопрос риторический, конечно. Время покажет, всё что покажет - расскажу как на духу. Сегодня начал писать пост с ретро #project_r
PS>
И в топик "простых" CRUD приложений из комментов ко вчерашнему посту: в Overengineering in Onion/Hexagonal Architectures про них тоже тоже есть:
Like any tool, concentric architectures are not suitable for any software project. If the domain complexity of your problem is fairly low (CRUD-like), or if the challenge of your application is NOT in the complexity of its business rules, then the Onion/Hexagonal/Ports-Adapters/Clean Architecture might not be the best choice, and you might be better off with vertical slicing, anemic model, CQRS, or another type of architecture.
—
Как и любой другой инструмент, концентрическая архитектура подходит не для всех проектов. Если сложность предметной области вашей задачи довольно низкая (CRUDо-подобная) или если сложность вашего приложения заключается не в сложности его бизнес-правил, то архитектура Onion/Hexagonal/Ports-Adapters/Clean может оказаться не лучшим выбором, и вам, возможно, лучше использовать вертикальную архитектуру, анемичную модель, CQRS или другой тип архитектуры.
#posts@ergonomic_code #ergo_arch@ergonomic_code #ergo_approach@ergonomic_code
Victor Rentea
Overengineering in Onion/Hexagonal Architectures
Clean Architecture, Onion Architecture, and Hexagonal Architecture (aka Ports-and-Adapters) have become the norm for backend system design today. Powerful influencers have promoted these architectures without stressing enough that they are (overly)complex…
❤6
Привет!
Третья большая новость наконец дозрела - я утряс все формальности и возобновил работу над Проектом Э!
Пока я пилил #project_r@ergonomic_code, заказчик пилил новый девайс, который делает замеры постоянно. И после его внедрения, нагрузка поднимется с ~3 измерений на пользователя в день до ~700.
А в самом оптимистичном сценарии - дорастёт до 50 RPS. Это ещё не хайлоад, конечно, но уже достаточно серьёзная нагрузка, которая не простит откровенно неэффективных решений.
Соответственно, сейчас моя основная задача немного допилить бэк для поддержки нового устройства и подготовить его к росту нагрузки. Плюс в бэклоге накопилась пачка фич, которые тоже надо будет сделать.
И на мой взгляд, это очень крутая новость для ЭП. Это значит, что у меня будет реальная обратная связь из первых рук о том, как ЭП масштабируется и по размеру проекта (сейчас - 40k строк Котлин-кода и 72 таблицы) и по RPS.
Кроме того, у меня был очень любопытный опыт приёма на поддержку собственного проекта после практически 1.5-летнего перерыва. Там, на самом деле есть прям много чего написать, но, к сожалению, не осилю. Если в целом общие ощущения - нот бэд, но за почти три года с момента начала разработки Проекта Э, Эргономичный подход сделал огромный шаг вперёд, особенно в части тестирования.
Плюс чуть подробнее поделюсь ещё одним инсайтом: идея, что можно в одном модуле попилить проект на вертикальные слайсы в пакетах и покрыть отсутствие циклических зависимостей между ними ArchUnit-тестом, для того чтобы вертикальные кусочки можно было легко вынести - оказалась тупиковой. В моей реализации, по крайней мере.
Во-первых, за 1.5 года в продовый код пробралось несколько циклов. И это при том, что я часа 4 потратил на то, чтобы написать максимально строгий Арч-юнит тест. Но это была меньшая из проблем - их я разорвал за несколько часов.
Потому что во-вторых - в тестах произошла тотальная катастрофа. Там образовался дикий клубок зависимостей, который я распутывал и распиливал неделю. Наверное, тесты надо покрывать ArchUnit-тестами тоже:)
В общем если вы делаете модульный монолит, и хотите иметь возможность быстро выносить модули в отдельные сервисы - не лениесь как я и заводите для них сразу отдельные модули
#project_e@ergonomic_code #ergo_approach@ergonomic_code
Третья большая новость наконец дозрела - я утряс все формальности и возобновил работу над Проектом Э!
Пока я пилил #project_r@ergonomic_code, заказчик пилил новый девайс, который делает замеры постоянно. И после его внедрения, нагрузка поднимется с ~3 измерений на пользователя в день до ~700.
А в самом оптимистичном сценарии - дорастёт до 50 RPS. Это ещё не хайлоад, конечно, но уже достаточно серьёзная нагрузка, которая не простит откровенно неэффективных решений.
Соответственно, сейчас моя основная задача немного допилить бэк для поддержки нового устройства и подготовить его к росту нагрузки. Плюс в бэклоге накопилась пачка фич, которые тоже надо будет сделать.
И на мой взгляд, это очень крутая новость для ЭП. Это значит, что у меня будет реальная обратная связь из первых рук о том, как ЭП масштабируется и по размеру проекта (сейчас - 40k строк Котлин-кода и 72 таблицы) и по RPS.
Кроме того, у меня был очень любопытный опыт приёма на поддержку собственного проекта после практически 1.5-летнего перерыва. Там, на самом деле есть прям много чего написать, но, к сожалению, не осилю. Если в целом общие ощущения - нот бэд, но за почти три года с момента начала разработки Проекта Э, Эргономичный подход сделал огромный шаг вперёд, особенно в части тестирования.
Плюс чуть подробнее поделюсь ещё одним инсайтом: идея, что можно в одном модуле попилить проект на вертикальные слайсы в пакетах и покрыть отсутствие циклических зависимостей между ними ArchUnit-тестом, для того чтобы вертикальные кусочки можно было легко вынести - оказалась тупиковой. В моей реализации, по крайней мере.
Во-первых, за 1.5 года в продовый код пробралось несколько циклов. И это при том, что я часа 4 потратил на то, чтобы написать максимально строгий Арч-юнит тест. Но это была меньшая из проблем - их я разорвал за несколько часов.
Потому что во-вторых - в тестах произошла тотальная катастрофа. Там образовался дикий клубок зависимостей, который я распутывал и распиливал неделю. Наверное, тесты надо покрывать ArchUnit-тестами тоже:)
В общем если вы делаете модульный монолит, и хотите иметь возможность быстро выносить модули в отдельные сервисы - не лениесь как я и заводите для них сразу отдельные модули
#project_e@ergonomic_code #ergo_approach@ergonomic_code
Алексей Жидков
Как я превратил легаси-проект в конфетку за полгода. Том 1 - Алексей Жидков
https://azhidkov.pro/
🔥2
И к слову, про реальную обратную связь. И про то, что мне не дают покоя лавры анкл Боба:)
Наше исследование идёт своим чередом, и там между делом зашла речь про анкл Боба. В частности, что его идеи не ложатся на реальную практику. Я высказал предположение, что анкл Боб последние лет 20 не участвует в реальной разработке. А потом спросил у гопатыча, дипсика и алисы. Дипсик и алиса подтвердили, гопатыч соврал - сослался сюда и сказал что реальный опыт есть, но по ссылке ничего об этом не написано.
Короче, не слушайте анкл Боба, слушайте меня - у меня каждая идея выстрадана и опробована в коммерческой практике:)
#ergo_approach@ergonomic_code #solid@ergonomic_code #clean_architecture@ergonomic_code
Наше исследование идёт своим чередом, и там между делом зашла речь про анкл Боба. В частности, что его идеи не ложатся на реальную практику. Я высказал предположение, что анкл Боб последние лет 20 не участвует в реальной разработке. А потом спросил у гопатыча, дипсика и алисы. Дипсик и алиса подтвердили, гопатыч соврал - сослался сюда и сказал что реальный опыт есть, но по ссылке ничего об этом не написано.
Короче, не слушайте анкл Боба, слушайте меня - у меня каждая идея выстрадана и опробована в коммерческой практике:)
#ergo_approach@ergonomic_code #solid@ergonomic_code #clean_architecture@ergonomic_code
❤7
Привет!
У нас в группе за последнюю пару недель было сразу два холивара на тему разделения на слой приложения и домена в DDD. Я смотрел на них и про себя думал, что это очень попахивает искусственной/побочной сложностью.
В ЭП тоже есть очень похожее разделение и даже с теми же названиями, потому что выросло оно у меня из ДДД. Но у меня оно сейчас если не проще, то чётче, на мой взгляд.
В слое домена у меня живёт состояние - классы сущностей/агрегатов и репозитории*.
В слое приложения живут операции системы - в первую очередь порты/точки входа - хттп эндпоинты, обработчики крон-задач, слушатели всевозможных событий и сообщений.
Если операция системы простая - меняет только один ресурс - то она реализуется прямо в порте. В идеале - единственным вызовом репозитория, но см. правила ниже.
Если же операции надо потрогать два или более репозитория, то она оформляется в отдельный класс операции с единственным публичным методом, который помещается в слой приложения и может звать уже сколько угодно репозиториев. Но тоже см. правила ниже.
И для выбора места размещения кода у меня есть два подхода на выбор разработчика.
1. снизу вверх. Код помещается на максимально низкий уровень, где доступно требуемое состояние. Трансоформация/вычисление на базе одной сущности помещается рядом с ней. Код, меняющий только один репоз помещается рядом с этим репозом. Код трансформирующий/вычисляющий на базе нескольких агрегатов/сущностей помещается в слой приложения рядом с операцией, которая его использует или в общий код пакета, содержащего все операции, которые его используют. Код работающий с несколькими ресурсами помещается аналогично максимально близко к операции(ям), его использующим
2. сверху вниз. Код помещается на самый высокий уровень, доступный всем его клиентам. Этот подход, на самом деле имеет смысл только для трансформаций сущностей и тут по большому счёту только два варианта. Трансформация одной сущности, которая используется только в одной операции помещается рядом с ней. Если он нужен нескольким операциям - помещается рядом с сущностью.
Я обычно придерживаюсь подхода снизу вверх, вынося трансформации выше если:
1. она явно относится к одной конкретной операции
2. вокруг сущности накопилось более 10 методов, многие из которых используются только в одной операции
Кроме того у меня есть пачка защитных-правил, которые предотвращают превращение реализации в кровавое месиво бизнес-логики и ввода-вывода и разных уровней абстракции:
1. каждая технология должна быть инкапсулирована либо в порте, либо в ресурсе. При том в случае ресурса инкапсуляция означает, что технология не фонит в API ресурса. В АПИ репозитория не должны упоминаться таблицы, колонки, внешние ключи и т.п. В АПИ хттп клиента внешней системы не должны упоминаться хттп методы, заголовки, куки, мультипарты и т.д.
2. Ни порты, ни операции, ни репозитории** не могут вызывать друг друга
3. метод порта не может вызывать более одной операции или метода ресурса
4. метод порта может содержать только одну конструкцию ветвления (if/when/switch) для выбора представления ответа
5. метод, который прямо или косвенно содержит ввод-вывод (методы портов, операций и репозиториев) может иметь когнитивную сложность не более 4
6. классы поведения (операции, ресурсы) должны иметь не более 7, край 10 зависимостей. А в идеале - до 5
В общем, мне кажется, хороший подход/гайдлайн/методика разработки должен минимизировать поле для холиваров и разночтений. А для этого он должен быть определён в максимально чётко сформулированных правилах, проверку которых, в идале, можно автоматизировать.
Подробнее об этом у меня написано в заготовке статьи Эргономичная архитектура
#ergo_approach@ergonomic_code #ddd@ergonomic_code
У нас в группе за последнюю пару недель было сразу два холивара на тему разделения на слой приложения и домена в DDD. Я смотрел на них и про себя думал, что это очень попахивает искусственной/побочной сложностью.
В ЭП тоже есть очень похожее разделение и даже с теми же названиями, потому что выросло оно у меня из ДДД. Но у меня оно сейчас если не проще, то чётче, на мой взгляд.
В слое домена у меня живёт состояние - классы сущностей/агрегатов и репозитории*.
В слое приложения живут операции системы - в первую очередь порты/точки входа - хттп эндпоинты, обработчики крон-задач, слушатели всевозможных событий и сообщений.
Если операция системы простая - меняет только один ресурс - то она реализуется прямо в порте. В идеале - единственным вызовом репозитория, но см. правила ниже.
Если же операции надо потрогать два или более репозитория, то она оформляется в отдельный класс операции с единственным публичным методом, который помещается в слой приложения и может звать уже сколько угодно репозиториев. Но тоже см. правила ниже.
И для выбора места размещения кода у меня есть два подхода на выбор разработчика.
1. снизу вверх. Код помещается на максимально низкий уровень, где доступно требуемое состояние. Трансоформация/вычисление на базе одной сущности помещается рядом с ней. Код, меняющий только один репоз помещается рядом с этим репозом. Код трансформирующий/вычисляющий на базе нескольких агрегатов/сущностей помещается в слой приложения рядом с операцией, которая его использует или в общий код пакета, содержащего все операции, которые его используют. Код работающий с несколькими ресурсами помещается аналогично максимально близко к операции(ям), его использующим
2. сверху вниз. Код помещается на самый высокий уровень, доступный всем его клиентам. Этот подход, на самом деле имеет смысл только для трансформаций сущностей и тут по большому счёту только два варианта. Трансформация одной сущности, которая используется только в одной операции помещается рядом с ней. Если он нужен нескольким операциям - помещается рядом с сущностью.
Я обычно придерживаюсь подхода снизу вверх, вынося трансформации выше если:
1. она явно относится к одной конкретной операции
2. вокруг сущности накопилось более 10 методов, многие из которых используются только в одной операции
Кроме того у меня есть пачка защитных-правил, которые предотвращают превращение реализации в кровавое месиво бизнес-логики и ввода-вывода и разных уровней абстракции:
1. каждая технология должна быть инкапсулирована либо в порте, либо в ресурсе. При том в случае ресурса инкапсуляция означает, что технология не фонит в API ресурса. В АПИ репозитория не должны упоминаться таблицы, колонки, внешние ключи и т.п. В АПИ хттп клиента внешней системы не должны упоминаться хттп методы, заголовки, куки, мультипарты и т.д.
2. Ни порты, ни операции, ни репозитории** не могут вызывать друг друга
3. метод порта не может вызывать более одной операции или метода ресурса
4. метод порта может содержать только одну конструкцию ветвления (if/when/switch) для выбора представления ответа
5. метод, который прямо или косвенно содержит ввод-вывод (методы портов, операций и репозиториев) может иметь когнитивную сложность не более 4
6. классы поведения (операции, ресурсы) должны иметь не более 7, край 10 зависимостей. А в идеале - до 5
В общем, мне кажется, хороший подход/гайдлайн/методика разработки должен минимизировать поле для холиваров и разночтений. А для этого он должен быть определён в максимально чётко сформулированных правилах, проверку которых, в идале, можно автоматизировать.
Подробнее об этом у меня написано в заготовке статьи Эргономичная архитектура
#ergo_approach@ergonomic_code #ddd@ergonomic_code
❤5👍3
Привет!
Я закончил большой 5-месячный долгострой на 43 коммита по интеграции Google Calendar в Trainer Advisor.
В реализации этой фичи довольно много интересных, на мой взгляд, аспектов, каждый из которых заслуживает отдельного поста. Но сейчас их писать настроения нет, поэтому я ограничился микропостом с обзором реализации. Ну как микро - 25 минут чтения по оценке ФФ:)
И чтобы вам не продираться сквозь 25 минут потока сознания в поисках чего-то интересного для себя - вот краткое содержание:)
Абстрактный ресурс
Для меня самым интересным в этой фиче было то, что для её реализации пришлось ввести некие штуки с рабочим названием «Абстрактный ресурс».
Не знаю пока что с этим делать и надо ли что-то делать.
MockServers
Паттерн для организации WireMock-стабов
Fixtures
Паттерн для сетапа фикстур, состоящих из сложных графов объектов
Пример «простого» CRUD-приложения
Я в последнее время в канале несколько раз писал о «простых» CRUD-приложения — приложениях без сложной бизнес-логики или нефункциональных требований, но, тем не менее, которые назвать простыми не поворачивается язык. И всякий раз это порождало вопросы в комментариях, что конкретно я имею ввиду.
И вот у меня, наконец появился, хороший open source-ый пример — операция отображения страницы расписания терапевта.
Рефакторинг findCalendarItemsInInterval (уровни абстракции/стратификация)
Пример приведения метода к соответствию правилу "У функции должен быть один уровень абстракции"
SourceItem → URI
К своему стыду, должен признаться, что я только недавно до конца (чуть лучше?) осознал что такое URI. Но лучше поздно, чем никогда - правда же?
И вот теперь благодаря этим новым знаниям, мне удалось сделать работу с разными календарями в Trainer Advisor чуть более "production grade".
Как добыть OAuth2AuthorizedClient без того, чтобы перетереть Authorization в SecurityContext
Я хз. Но у меня есть рабочий код, на который можно ориентироваться
И этот код мало того, что рабочий — он ещё и тестами покрыт.
Тестирование интеграции с Google OAuth и Google Calendars
Вот оно:
- GoogleAuthorizationIntegrationTest;
- GoogleCalendarsServiceTest;
- GetGoogleCalendarsSettingsEndpointTest;
- SetCalendarShouldBeShownTest;
- Тест "Страница календаря должна рендериться корректно, даже если у терапевта есть подключенный Google-календарь и запрос событий из него приводит к ошибке";
- CreateAppointmentPageTest.createAppointmntWithGoogleEvnt;
- SchedulePageControllerTest;
Верификация приложения в Google
Это 7 кругов ада. Но без них ваши токены будут протухать раз в неделю и вам надо будет снова гнать юзеров на авторизацию в гугле
#ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #case@ergonomic_code
Я закончил большой 5-месячный долгострой на 43 коммита по интеграции Google Calendar в Trainer Advisor.
В реализации этой фичи довольно много интересных, на мой взгляд, аспектов, каждый из которых заслуживает отдельного поста. Но сейчас их писать настроения нет, поэтому я ограничился микропостом с обзором реализации. Ну как микро - 25 минут чтения по оценке ФФ:)
И чтобы вам не продираться сквозь 25 минут потока сознания в поисках чего-то интересного для себя - вот краткое содержание:)
Абстрактный ресурс
Для меня самым интересным в этой фиче было то, что для её реализации пришлось ввести некие штуки с рабочим названием «Абстрактный ресурс».
Не знаю пока что с этим делать и надо ли что-то делать.
MockServers
Паттерн для организации WireMock-стабов
Fixtures
Паттерн для сетапа фикстур, состоящих из сложных графов объектов
Пример «простого» CRUD-приложения
Я в последнее время в канале несколько раз писал о «простых» CRUD-приложения — приложениях без сложной бизнес-логики или нефункциональных требований, но, тем не менее, которые назвать простыми не поворачивается язык. И всякий раз это порождало вопросы в комментариях, что конкретно я имею ввиду.
И вот у меня, наконец появился, хороший open source-ый пример — операция отображения страницы расписания терапевта.
Рефакторинг findCalendarItemsInInterval (уровни абстракции/стратификация)
Пример приведения метода к соответствию правилу "У функции должен быть один уровень абстракции"
SourceItem → URI
К своему стыду, должен признаться, что я только недавно до конца (чуть лучше?) осознал что такое URI. Но лучше поздно, чем никогда - правда же?
И вот теперь благодаря этим новым знаниям, мне удалось сделать работу с разными календарями в Trainer Advisor чуть более "production grade".
Как добыть OAuth2AuthorizedClient без того, чтобы перетереть Authorization в SecurityContext
Я хз. Но у меня есть рабочий код, на который можно ориентироваться
И этот код мало того, что рабочий — он ещё и тестами покрыт.
Тестирование интеграции с Google OAuth и Google Calendars
Вот оно:
- GoogleAuthorizationIntegrationTest;
- GoogleCalendarsServiceTest;
- GetGoogleCalendarsSettingsEndpointTest;
- SetCalendarShouldBeShownTest;
- Тест "Страница календаря должна рендериться корректно, даже если у терапевта есть подключенный Google-календарь и запрос событий из него приводит к ошибке";
- CreateAppointmentPageTest.createAppointmntWithGoogleEvnt;
- SchedulePageControllerTest;
Верификация приложения в Google
Это 7 кругов ада. Но без них ваши токены будут протухать раз в неделю и вам надо будет снова гнать юзеров на авторизацию в гугле
#ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #case@ergonomic_code
Алексей Жидков
Trainer Advisor — интеграция с Google Calendar - Алексей Жидков
https://azhidkov.pro/
❤10👍7
Привет!
Собрал микропост со сверкой рекомендаций ЭП с результатами анализа.
TLDR:
Судя по данным, собранным в рамках исследования:
— три из девяти рекомендаций Эргономичного подхода (пишите тесты, держите тесты быстрыми, исключайте циклы в зависимостях) ведут к повышению поддерживаемости;
— ещё пять (минимизация моков, разбиение модели на агрегаты, разделение IO и логики и использование неизменяемой модели данных, ограничение кол-ва зависимостей до 5–7 на компонент, использование открытой архитектуры), как минимум не снижают поддерживаемость, либо имеют небольшой тренд на её повышение;
— наконец, последняя рекомендация — не вводить интерфейсы без необходимости — никак не связана с поддерживаемостью: не повышает, но и не снижает её.
Хоть выборка у нас получилась и небольшая, но, на мой взгляд, голословные утверждения и немного статистики - это немного лучше, чем просто голословные утверждения.
—
Плюс пока писал пост накопал ещё один любопытный инсайт.
Между временем запуска одного теста и поддерживаемостью есть погранично значимая, но сильная (почти что очень сильная) связь с поддерживаемостью. И больше всего поддерживаемых (10 из 13) проектов было в категории «2–10 секунд». В то время как для категории «0-1 секунду» только лишь 2 из 7 проектов были поддерживаемым.
Здесь уже начинаются чистой воды спекуляции на результатах анализа совсем маленькой выборки (23 ответа на этот вопрос), но, кажется, эти данные можно проинтерпретировать как дважды косвенное подтверждение идеи, что фокус на качественных (работающих до 10 секунд) интеграционных тестах повышает поддерживаемость.
#ergo_approach@ergonomic_code #ergo_testing@ergonomic_code
Собрал микропост со сверкой рекомендаций ЭП с результатами анализа.
TLDR:
Судя по данным, собранным в рамках исследования:
— три из девяти рекомендаций Эргономичного подхода (пишите тесты, держите тесты быстрыми, исключайте циклы в зависимостях) ведут к повышению поддерживаемости;
— ещё пять (минимизация моков, разбиение модели на агрегаты, разделение IO и логики и использование неизменяемой модели данных, ограничение кол-ва зависимостей до 5–7 на компонент, использование открытой архитектуры), как минимум не снижают поддерживаемость, либо имеют небольшой тренд на её повышение;
— наконец, последняя рекомендация — не вводить интерфейсы без необходимости — никак не связана с поддерживаемостью: не повышает, но и не снижает её.
Хоть выборка у нас получилась и небольшая, но, на мой взгляд, голословные утверждения и немного статистики - это немного лучше, чем просто голословные утверждения.
—
Плюс пока писал пост накопал ещё один любопытный инсайт.
Между временем запуска одного теста и поддерживаемостью есть погранично значимая, но сильная (почти что очень сильная) связь с поддерживаемостью. И больше всего поддерживаемых (10 из 13) проектов было в категории «2–10 секунд». В то время как для категории «0-1 секунду» только лишь 2 из 7 проектов были поддерживаемым.
Здесь уже начинаются чистой воды спекуляции на результатах анализа совсем маленькой выборки (23 ответа на этот вопрос), но, кажется, эти данные можно проинтерпретировать как дважды косвенное подтверждение идеи, что фокус на качественных (работающих до 10 секунд) интеграционных тестах повышает поддерживаемость.
#ergo_approach@ergonomic_code #ergo_testing@ergonomic_code
Алексей Жидков
Анализ результатов исследования факторы поддерживаемости backend-проектов с точки зрения Эргономичного подхода - Алексей Жидков
https://azhidkov.pro/
1👍9🔥5
Привет!
Наткнулся на пост о фреймвоке размышлений об ошибках Марка Симана.
И он до неприличия похож на мой, независимо разработанный, подход:
1. Симан так же категоризирует ошибки по атрибутам ожидаемая/неожиданная и восстановимая/невосстановимая
2. Симан так же предлагает восстановимые ошибки возвращать (чем-то в духе nullable типа/Result/Eather etc), а невосстановимые ошибки выбрасывать исключениями.
Плюс он там выдвигает интересную идею, что невосстановимых ошибок не бывает.
Вкратце: например, для обработки отказа сохранения в БД, вы можете записать запрос на локальный диск и попробовать позже. А если локальный диск переполнен - сначала попытаться что-то почистить и сохранить, а если почистить не получилось - хотя бы попытаться придержать в памяти и дозвониться дежурному инженеру.
И это дополняет мою мысль, что доменные ошибки - это ошибки которых не должно быть.
И совместно получается, что теоретически можно написать софт который будет работать всегда. Но это будет очень дорого.
#posts@ergonomic_code #ergo_approach@ergonomic_code
Наткнулся на пост о фреймвоке размышлений об ошибках Марка Симана.
И он до неприличия похож на мой, независимо разработанный, подход:
1. Симан так же категоризирует ошибки по атрибутам ожидаемая/неожиданная и восстановимая/невосстановимая
2. Симан так же предлагает восстановимые ошибки возвращать (чем-то в духе nullable типа/Result/Eather etc), а невосстановимые ошибки выбрасывать исключениями.
Плюс он там выдвигает интересную идею, что невосстановимых ошибок не бывает.
Вкратце: например, для обработки отказа сохранения в БД, вы можете записать запрос на локальный диск и попробовать позже. А если локальный диск переполнен - сначала попытаться что-то почистить и сохранить, а если почистить не получилось - хотя бы попытаться придержать в памяти и дозвониться дежурному инженеру.
И это дополняет мою мысль, что доменные ошибки - это ошибки которых не должно быть.
И совместно получается, что теоретически можно написать софт который будет работать всегда. Но это будет очень дорого.
#posts@ergonomic_code #ergo_approach@ergonomic_code
ploeh blog
Error categories and category errors
How I currently think about errors in programming.
👍5
Привет!
Я недавно сделал Web Push уведомления в Trainer Advisor и попутно снова узнал и придумал пачку прикольных штук, о которых накатал очередной "микропост" на 30-40 минут чтения по оценке ФФ.
Ну и по традции вот вам сразу содержание, чтобы привлечь внимание мякоткой:
* Отправка пушей
* Архитектура
* Абстракция vs очевидность эффектов и разделение ввода и вывода
* И снова про уровни абстракции/стратификацию
* Пример №1: код открытия диплинка по клику
* Пример №2: фетч ресурсов с фолбэком на кэш и кастомную страницу «Сервис недоступен"
* Postgres GENERATED-колонки для ограничений целостности в JSONB
* TrainerAdvisorApis
* В Gradle-плагин GitProperties завезли поддержку git worktrees
* Отказ от Kotest Matchers в пользу shuold*-методов
#case@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #ergo_persistance@ergonomic_code
Я недавно сделал Web Push уведомления в Trainer Advisor и попутно снова узнал и придумал пачку прикольных штук, о которых накатал очередной "микропост" на 30-40 минут чтения по оценке ФФ.
Ну и по традции вот вам сразу содержание, чтобы привлечь внимание мякоткой:
* Отправка пушей
* Архитектура
* Абстракция vs очевидность эффектов и разделение ввода и вывода
* И снова про уровни абстракции/стратификацию
* Пример №1: код открытия диплинка по клику
* Пример №2: фетч ресурсов с фолбэком на кэш и кастомную страницу «Сервис недоступен"
* Postgres GENERATED-колонки для ограничений целостности в JSONB
* TrainerAdvisorApis
* В Gradle-плагин GitProperties завезли поддержку git worktrees
* Отказ от Kotest Matchers в пользу shuold*-методов
#case@ergonomic_code #ergo_approach@ergonomic_code #ergo_arch@ergonomic_code #ergo_testing@ergonomic_code #trainer_advisor@ergonomic_code #ergo_persistance@ergonomic_code
Алексей Жидков
Trainer Advisor — WebPush-уведомления - Алексей Жидков
https://azhidkov.pro/
🔥4❤3👍2
Привет!
Итоги 2025 года - лучше поздно, чем никогда, правда же?:)
Итог №1 - Больше реального кода
Больше всего сил в 2025 году (192 коммита, против 43 и 36 в вики и блог) я вложил в Trainer Advisor - публичный пример проекта, написанного по ЭП.
За 2025 год я в нём сделал 34 различных фичи и фикса, самые крупные и трудозатратные из которых были:
1. Интеграция с Гугл Календарями (PR, пост)
2. Пуш-уведомления (PR, пост)
В результате, TA дорос до 20К строк исходников и 20 таблиц.
Помимо этого в #project_e мы за прошлый год сделали пару новых сервисов и допилили новых фич в ядро на 2.2, 4.1 и 6К строк соответственно.
В итоге суммарное количество промышленного кода, написанного по ЭП, перевалило уже за 121 тысячу строк Kotlin и Java-кода.
Итог №2 - Эргономичная архитектура
Также значительным на мой взгляд итогом 2025 года стало появление Эргономичной архитектуры и её представление с помощью трёх проекций. Описание Эргономичной архитектуры всё ещё в статусе черновика и публичных обновлений не было давно, но за кулисами я весь четвёртый квартал 25-ого года работал над проекцией модели данных. С четвёртой попытки у меня вышел текст, который мне нравится, но ещё надо убрать исторические наслоения из ТА, чтобы он стал хорошей иллюстрацией и собственно добавить эту иллюстрацию.
Итог №3 - Исследование характеристик поддерживаемых кодовых баз
Затем, довольно много времени и сил я потратил на проведение исследования характеристик поддерживаемых кодовых баз backend-приложений. К сожалению, собрать достаточное количество анкет не вышло (хотя анкета всё ещё открыта и вы всё ещё можете её заполнить:) ), поэтому все эти усилия по большому счёту пошли прахом. Тем не менее, у меня появилось слабое, но подтверждение, что ЭП как минимум не вредит поддерживаемости:)
Итог №4 - Большие посты
На поприще блоггинга я смог написать два больших поста:
1. Вам не нужна Чистая архитектура. Скорее всего
2. Учимся читать SQL SELECT
А всего в блог и вики я добавил (немного пугающие) 6660 строк. Это не считая незакоммитанных черновиков:)
Итог №5 - Новые паттерны
Ещё в 2025 году у меня оформилось несколько паттернов, немного сокращающих трудозатраты на разработку (за счёт того, что не надо велосипед придумывать):
1. Переход на UUID v7 в качестве идов сущностей
2. Пресеты сложных фикстур
3. [Wire]MockServers
4. и ещё пачка более мелких см. историю коммитов
Итог №6 - +1см в направлении книги
Прошлый год начался с того, что мне написал проектный менеджер ИД Питер с предложением издать книгу. На этой волне я немного полежал в направлении книги, но переключился на исследование. Знаете как расшифровывается СДВГ? "Синдром дефицита Вау! Голубь!".
И вот в конце прошлого года ко мне пришёл представитель уже второго крупного издательства с тем же предложением. Мы с ним довольно серьёзно продвинулись в планировании книги и ред. коллегия была готова заключить договор на издание книги, но с условием, что авторский текст я сдам до конца 26 года. А я по ряду причин не готов на это подписываться, поэтому и в этот раз не срослось.
Но, держим пальчики, процесс потихоньку сходится, когда-нибудь книга обязательно будет:)
#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
Итоги 2025 года - лучше поздно, чем никогда, правда же?:)
Итог №1 - Больше реального кода
Больше всего сил в 2025 году (192 коммита, против 43 и 36 в вики и блог) я вложил в Trainer Advisor - публичный пример проекта, написанного по ЭП.
За 2025 год я в нём сделал 34 различных фичи и фикса, самые крупные и трудозатратные из которых были:
1. Интеграция с Гугл Календарями (PR, пост)
2. Пуш-уведомления (PR, пост)
В результате, TA дорос до 20К строк исходников и 20 таблиц.
Помимо этого в #project_e мы за прошлый год сделали пару новых сервисов и допилили новых фич в ядро на 2.2, 4.1 и 6К строк соответственно.
В итоге суммарное количество промышленного кода, написанного по ЭП, перевалило уже за 121 тысячу строк Kotlin и Java-кода.
Итог №2 - Эргономичная архитектура
Также значительным на мой взгляд итогом 2025 года стало появление Эргономичной архитектуры и её представление с помощью трёх проекций. Описание Эргономичной архитектуры всё ещё в статусе черновика и публичных обновлений не было давно, но за кулисами я весь четвёртый квартал 25-ого года работал над проекцией модели данных. С четвёртой попытки у меня вышел текст, который мне нравится, но ещё надо убрать исторические наслоения из ТА, чтобы он стал хорошей иллюстрацией и собственно добавить эту иллюстрацию.
Итог №3 - Исследование характеристик поддерживаемых кодовых баз
Затем, довольно много времени и сил я потратил на проведение исследования характеристик поддерживаемых кодовых баз backend-приложений. К сожалению, собрать достаточное количество анкет не вышло (хотя анкета всё ещё открыта и вы всё ещё можете её заполнить:) ), поэтому все эти усилия по большому счёту пошли прахом. Тем не менее, у меня появилось слабое, но подтверждение, что ЭП как минимум не вредит поддерживаемости:)
Итог №4 - Большие посты
На поприще блоггинга я смог написать два больших поста:
1. Вам не нужна Чистая архитектура. Скорее всего
2. Учимся читать SQL SELECT
А всего в блог и вики я добавил (немного пугающие) 6660 строк. Это не считая незакоммитанных черновиков:)
Итог №5 - Новые паттерны
Ещё в 2025 году у меня оформилось несколько паттернов, немного сокращающих трудозатраты на разработку (за счёт того, что не надо велосипед придумывать):
1. Переход на UUID v7 в качестве идов сущностей
2. Пресеты сложных фикстур
3. [Wire]MockServers
4. и ещё пачка более мелких см. историю коммитов
Итог №6 - +1см в направлении книги
Прошлый год начался с того, что мне написал проектный менеджер ИД Питер с предложением издать книгу. На этой волне я немного полежал в направлении книги, но переключился на исследование. Знаете как расшифровывается СДВГ? "Синдром дефицита Вау! Голубь!".
И вот в конце прошлого года ко мне пришёл представитель уже второго крупного издательства с тем же предложением. Мы с ним довольно серьёзно продвинулись в планировании книги и ред. коллегия была готова заключить договор на издание книги, но с условием, что авторский текст я сдам до конца 26 года. А я по ряду причин не готов на это подписываться, поэтому и в этот раз не срослось.
Но, держим пальчики, процесс потихоньку сходится, когда-нибудь книга обязательно будет:)
#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
GitHub
GitHub - ergonomic-code/Trainer-Advisor: Информационная система йогатерапевта и демонстрационный проект Эргономичного подхода
Информационная система йогатерапевта и демонстрационный проект Эргономичного подхода - ergonomic-code/Trainer-Advisor
❤8👍7🔥3
Чего ждать в 2026 году
Я даже не из тех людей, которые в начале года составляют планы на год, не говоря уж о том, чтобы придерживаться этих планов:)
Поэтому список далее - это то, что у меня сейчас есть в голове и чего хотя бы теоретически можно от меня ожидать. А что будет на самом деле - только время покажет. Вы же уже знаете, как расшифровывается СДВГ:)
Итак, чего от меня можно ожидать в 2026 году:
1. Актуализация Project Mariotte - это то, чем я занимался до итогов. Обновляю платформу и зависимости и перевожу реализацию на актуальные паттерны ЭП.
2. Пост с опытом миграции на Spring Boot 4. Я уже смигрировал Project Mariotte и два небольших сервиса в Project E. И уже словил и решил гору проблем (с Jackson 3 в основном). На горизонте пары месяцев, я надеюсь мигрировать TA и основной сервис Project E и по результатам написать большой пост с граблями (и решениями), которые я словил в процессе.
3. Рефакторинг TA на актульный гайдлайн ЭП. ТА у меня будет иллюстрацией и для ЭА и для книги, поэтому надо убрать оттуда исторические наслоения и компромиссные решения
4. Описание проекции модели данных ЭА с примером из ТА.
5. Проекция поведения ЭА - там, похоже, тоже придётся ещё повозиться
6. Описание процесса транзакционного анализа и процессов проектирования модели данных и компонентов на его основе.
7. В целом пп 3-6 - это всё работа в направлении книги. Но помимо этого, возможно удастся начать описывать кейсы.
8. Наверняка я придумаю что-то ещё, столь же неожиданное, как и исследование:)
На что я готов подписаться, так это на то, что в 2026 году я продолжу работу над ЭП и продолжу писать о своих приключениях на этом пути в канале:)
В общем как всегда: стей тюнед, будет интересно:)
#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
Я даже не из тех людей, которые в начале года составляют планы на год, не говоря уж о том, чтобы придерживаться этих планов:)
Поэтому список далее - это то, что у меня сейчас есть в голове и чего хотя бы теоретически можно от меня ожидать. А что будет на самом деле - только время покажет. Вы же уже знаете, как расшифровывается СДВГ:)
Итак, чего от меня можно ожидать в 2026 году:
1. Актуализация Project Mariotte - это то, чем я занимался до итогов. Обновляю платформу и зависимости и перевожу реализацию на актуальные паттерны ЭП.
2. Пост с опытом миграции на Spring Boot 4. Я уже смигрировал Project Mariotte и два небольших сервиса в Project E. И уже словил и решил гору проблем (с Jackson 3 в основном). На горизонте пары месяцев, я надеюсь мигрировать TA и основной сервис Project E и по результатам написать большой пост с граблями (и решениями), которые я словил в процессе.
3. Рефакторинг TA на актульный гайдлайн ЭП. ТА у меня будет иллюстрацией и для ЭА и для книги, поэтому надо убрать оттуда исторические наслоения и компромиссные решения
4. Описание проекции модели данных ЭА с примером из ТА.
5. Проекция поведения ЭА - там, похоже, тоже придётся ещё повозиться
6. Описание процесса транзакционного анализа и процессов проектирования модели данных и компонентов на его основе.
7. В целом пп 3-6 - это всё работа в направлении книги. Но помимо этого, возможно удастся начать описывать кейсы.
8. Наверняка я придумаю что-то ещё, столь же неожиданное, как и исследование:)
На что я готов подписаться, так это на то, что в 2026 году я продолжу работу над ЭП и продолжу писать о своих приключениях на этом пути в канале:)
В общем как всегда: стей тюнед, будет интересно:)
#ergo_approach@ergonomic_code #traineradvisor@ergonomic_code #ergo_book@ergonomic_code
👍10❤6🔥4
В данном случае это не плохо, а с учётом того, что публикация должна быть сделана через Transactional Outbox - неизбежно. Но если у функции появляется 2 и более подобных смежных ответственностей - это уже хороший повод, чтобы их отцепить как раз через события. Это и упростит код реализации, и надёжность работы функции повысит, и тесты ускорит и упростит.
Или, если на самом деле в зависимости от параметров функция делает "(А и Б) либо (А и В)" - то её надо разбить на две отдельных функции, переиспользующие "А".
#ergo_approach@ergonomic_code #books@ergonomic_code #project_e@ergonomic_code
Или, если на самом деле в зависимости от параметров функция делает "(А и Б) либо (А и В)" - то её надо разбить на две отдельных функции, переиспользующие "А".
#ergo_approach@ergonomic_code #books@ergonomic_code #project_e@ergonomic_code
👍3🤔1
И для того, чтобы в будущем не врюхиваться в такие приключения, я решил написать для себя манифест блога, вики и этого канала.
Манифест блога
У меня есть определённое представление о том, как надо писать код, чтобы он был поддерживаемым:
1. Код должен быть покрыт тестами (ATDD);
* Потому что это развязывает руки команде рефакторить код и поддерживать его в хорошем состоянии
2. Эти тесты должны быть преимущественно приёмочными/клиентскими/граничными (ATDD);
* Потому что такие тесты являются наиболее показательными и устойчивыми к рефакторингу и их надо наименьшее количество для того, чтобы убедиться в работоспособности системы. А современные инструменты и оборудование практически снимают их проблемы со скоростью (легко можно добиться времени выполнения 5 секунд на старт тестов плюс 20-50мс на тест) и стабильностью (сброс состояния инфраструктуры перед каждым тестом);
3. Тесты должны писаться преимущественно до кода (ATDD);
* Потому что это:
- гарантирует вообще наличие тестов и то, что тесты вообще что-то проверяют;
- задаёт ритм разработки небольшими шагами, которые легко делать, отлаживать и ревьювить.
4. Модель должна быть разбита на небольшие слабосвязанные агрегаты (DDD);
* Потому что это помогает поддерживать высокую связанность (cohesion) элементов модели;
5. Модель должна образовывать направленный ацикличный граф (DDD, FA);
* Потому что это задаёт "начало" (важные и фундаментальные части) и "конец" (вторичные, вспомогательные и периферийные части) модели и тем самым упрощает её понимание;
6. Модель должна состоять из неизменяемых классов (FP, FA);
* Потому что это:
- Способствует исключению циклов;
- Упрощает понимание кода, работающего с ними;
7. Модель должна явно кодировать свои допустимые состояния (FP, OOP);
* Потому что это повышает наглядность/упрощает понимание модели и предотвращает ошибки;
8. Сложные алгоритмы и бизнес-правила должны быть оформлены в виде чистых функций (FP);
* Потому что это упрощает их понимание, тестирование и отладку;
9. Операции должны стремиться к сбалансированной форме (ака Recawr Sandwich) (SD, FA)
* Потому что это упрощает их понимание и, как следствие, предотвращение, поиск и устранение ошибок и проблем производительности;
10. Операции должны должны иметь высокую (функциональной, последовательной или коммуникационной) связанность (cohesion) (SD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
11. Компоненты должны иметь высокую связность (cohesion) (OOD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
И есть мой базовый стек - Kotlin, Spring, Spring Data JDBC, PostgreSQL.
И в блоге я пишу о том, как на этом стеке писать поддерживаемый код:
1. Как писать быстрые клиентские тесты на Kotlin, Spring, WebTestClient, JUnit, Kotest, Testcontainers, PostgreSQL;
2. Как проектировать тест-кейсы;
3. Как начинать разработку с тестов;
4. Как проектировать агрегаты. Без доступа к экспертам;
5. Как кодировать агрегаты с помощью Spring Data Jdbc и мапить их на таблицы PostgreSQL;
6. Как писать код, работающий с неизменяемой моделью на Kotlin;
7. Как проектировать точные модели, исключающие недопустимые состояния на Kotlin;
8. Как разделять бизнес-логику и ввод-вывод на Kotlin;
9. Как группировать ввод и как группировать вывод на Kotlin, Spring и Spring Data Jdbc;
10. Как проектировать операции с высокой связанностью;
11. Как проектировать Spring beans с высокой связанностью;
12. Как все эти правила затолкать в ИИ-агента;
13. Разбор конкретных кейсов из моей практики по темам выше.
Манифест вики
Вики содержит статьи на темы №1-11 из блога.
Разница в том, что в блоге эти темы раскрываются как туториалы и кейсы, а на вики - как абстрактный справочный материал.
#ergo_approach@ergonomic_code
Манифест блога
У меня есть определённое представление о том, как надо писать код, чтобы он был поддерживаемым:
1. Код должен быть покрыт тестами (ATDD);
* Потому что это развязывает руки команде рефакторить код и поддерживать его в хорошем состоянии
2. Эти тесты должны быть преимущественно приёмочными/клиентскими/граничными (ATDD);
* Потому что такие тесты являются наиболее показательными и устойчивыми к рефакторингу и их надо наименьшее количество для того, чтобы убедиться в работоспособности системы. А современные инструменты и оборудование практически снимают их проблемы со скоростью (легко можно добиться времени выполнения 5 секунд на старт тестов плюс 20-50мс на тест) и стабильностью (сброс состояния инфраструктуры перед каждым тестом);
3. Тесты должны писаться преимущественно до кода (ATDD);
* Потому что это:
- гарантирует вообще наличие тестов и то, что тесты вообще что-то проверяют;
- задаёт ритм разработки небольшими шагами, которые легко делать, отлаживать и ревьювить.
4. Модель должна быть разбита на небольшие слабосвязанные агрегаты (DDD);
* Потому что это помогает поддерживать высокую связанность (cohesion) элементов модели;
5. Модель должна образовывать направленный ацикличный граф (DDD, FA);
* Потому что это задаёт "начало" (важные и фундаментальные части) и "конец" (вторичные, вспомогательные и периферийные части) модели и тем самым упрощает её понимание;
6. Модель должна состоять из неизменяемых классов (FP, FA);
* Потому что это:
- Способствует исключению циклов;
- Упрощает понимание кода, работающего с ними;
7. Модель должна явно кодировать свои допустимые состояния (FP, OOP);
* Потому что это повышает наглядность/упрощает понимание модели и предотвращает ошибки;
8. Сложные алгоритмы и бизнес-правила должны быть оформлены в виде чистых функций (FP);
* Потому что это упрощает их понимание, тестирование и отладку;
9. Операции должны стремиться к сбалансированной форме (ака Recawr Sandwich) (SD, FA)
* Потому что это упрощает их понимание и, как следствие, предотвращение, поиск и устранение ошибок и проблем производительности;
10. Операции должны должны иметь высокую (функциональной, последовательной или коммуникационной) связанность (cohesion) (SD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
11. Компоненты должны иметь высокую связность (cohesion) (OOD);
* Потому что это упрощает их понимание, тестирование, изменение и переиспользование;
И есть мой базовый стек - Kotlin, Spring, Spring Data JDBC, PostgreSQL.
И в блоге я пишу о том, как на этом стеке писать поддерживаемый код:
1. Как писать быстрые клиентские тесты на Kotlin, Spring, WebTestClient, JUnit, Kotest, Testcontainers, PostgreSQL;
2. Как проектировать тест-кейсы;
3. Как начинать разработку с тестов;
4. Как проектировать агрегаты. Без доступа к экспертам;
5. Как кодировать агрегаты с помощью Spring Data Jdbc и мапить их на таблицы PostgreSQL;
6. Как писать код, работающий с неизменяемой моделью на Kotlin;
7. Как проектировать точные модели, исключающие недопустимые состояния на Kotlin;
8. Как разделять бизнес-логику и ввод-вывод на Kotlin;
9. Как группировать ввод и как группировать вывод на Kotlin, Spring и Spring Data Jdbc;
10. Как проектировать операции с высокой связанностью;
11. Как проектировать Spring beans с высокой связанностью;
12. Как все эти правила затолкать в ИИ-агента;
13. Разбор конкретных кейсов из моей практики по темам выше.
Манифест вики
Вики содержит статьи на темы №1-11 из блога.
Разница в том, что в блоге эти темы раскрываются как туториалы и кейсы, а на вики - как абстрактный справочный материал.
#ergo_approach@ergonomic_code
Алексей Жидков
Посты - Алексей Жидков
Разработка и реинжиниринг ПО
👍8❤5🔥3
И я тут 5 лет спустя прикрутил анонимную аналитику к блогу и узнал, что у меня на блог есть ссылки в:
1. конфе ВК на диаграмму эффектов
2. явно каком-то корпарате с MS Teams-ом на пост про структурный дизайн
3. конфе НСПК на пост про декомпозицию на базе эффектов
Запишу себе это в ачивки:)
#ergo_approach@ergonomic_code
1. конфе ВК на диаграмму эффектов
2. явно каком-то корпарате с MS Teams-ом на пост про структурный дизайн
3. конфе НСПК на пост про декомпозицию на базе эффектов
Запишу себе это в ачивки:)
#ergo_approach@ergonomic_code
👍3⚡2❤2
Привет!
У меня периодически спрашивают как обстоят дела с перформансом у ЭП в целом и функционального стиля + Spring Data JDBC в частности.
Я всегда говорил "У меня не хайлоад и мне всегда хватало - никогда не приходилось ничего целенаправленно оптимизировать".
И вот у нас Проекте Э планируется переход от ~0.5 (3 в утренний пик) RPS к штатным 17 RPS 24/7. Тоже, конечно, не супер хайлоад, но уже существенная нагрузка, которая откровенных косяков не простит.
Я соответственно пошёл мерить и к моему небольшому удивлению, бэк сходу вывез эти 17 rps в течение 10 минут. При том по прочим метрикам вывез без проблем и мог бы больше, но я пока не стал искать предел - есть более приоритетные задачи.
Единственное что, это был только первый этап и БД была практически пустая - 100К записей в целевой таблице, а с такой нагрузкой рабочий объём будет 500-600М записей.
Тестируемая операция:
0. авторизация по JWT-токену с парсингом и верификацией и с SELECT-ом его активности в БД
1. нетривиальный парсинг json-а с поддержкой 8 минорных версий схемы, валидация и дедупликация данных
2. один SELECT с локом по юзеру
3. пара простых SELECT-ов в целевую таблицу
4. маппинги DTO -> Domain -> Persistence
5. один INSERT в целевую Postgres inherited table
6. один простой INSERT в таблицу transactional outbox-а
7. асинхронно - публикация события в rabbit mq и удаление по id из outbox-а
Чутка цифр по запросам:
0. всего запросов - 14199
1. ошибок - 0
2. avg - 115.5ms
3. p90 - 151.8ms
4. p95 - 296.5ms
5. p99 - 511.9ms
6. max - 1968.9ms.
И по железу:
1. бэк - 1 pod в k8s с лимитами 400m CPU/750Mi RAM, JVM heap 550Mi. Вот тут я прям удивился, что spring-то оказывается мохёт на 500мб РАМ О_О. А в проде уменя зачем-то 2гб стоит.
2. Postgres - cloud.ru-шный менеджед на rds.pg.x1.large.2 | 2 vCPUs | 4 GB
17 RPS - тоже нифига не хайлоад, конечно, но уже и не стыдно людям рассказать.
#ergo_approach@ergonomic_code #spring_data_jdbc@ergonomic_code #project_e@ergonomic_code
У меня периодически спрашивают как обстоят дела с перформансом у ЭП в целом и функционального стиля + Spring Data JDBC в частности.
Я всегда говорил "У меня не хайлоад и мне всегда хватало - никогда не приходилось ничего целенаправленно оптимизировать".
И вот у нас Проекте Э планируется переход от ~0.5 (3 в утренний пик) RPS к штатным 17 RPS 24/7. Тоже, конечно, не супер хайлоад, но уже существенная нагрузка, которая откровенных косяков не простит.
Я соответственно пошёл мерить и к моему небольшому удивлению, бэк сходу вывез эти 17 rps в течение 10 минут. При том по прочим метрикам вывез без проблем и мог бы больше, но я пока не стал искать предел - есть более приоритетные задачи.
Единственное что, это был только первый этап и БД была практически пустая - 100К записей в целевой таблице, а с такой нагрузкой рабочий объём будет 500-600М записей.
Тестируемая операция:
0. авторизация по JWT-токену с парсингом и верификацией и с SELECT-ом его активности в БД
1. нетривиальный парсинг json-а с поддержкой 8 минорных версий схемы, валидация и дедупликация данных
2. один SELECT с локом по юзеру
3. пара простых SELECT-ов в целевую таблицу
4. маппинги DTO -> Domain -> Persistence
5. один INSERT в целевую Postgres inherited table
6. один простой INSERT в таблицу transactional outbox-а
7. асинхронно - публикация события в rabbit mq и удаление по id из outbox-а
Чутка цифр по запросам:
0. всего запросов - 14199
1. ошибок - 0
2. avg - 115.5ms
3. p90 - 151.8ms
4. p95 - 296.5ms
5. p99 - 511.9ms
6. max - 1968.9ms.
И по железу:
1. бэк - 1 pod в k8s с лимитами 400m CPU/750Mi RAM, JVM heap 550Mi. Вот тут я прям удивился, что spring-то оказывается мохёт на 500мб РАМ О_О. А в проде уменя зачем-то 2гб стоит.
2. Postgres - cloud.ru-шный менеджед на rds.pg.x1.large.2 | 2 vCPUs | 4 GB
17 RPS - тоже нифига не хайлоад, конечно, но уже и не стыдно людям рассказать.
#ergo_approach@ergonomic_code #spring_data_jdbc@ergonomic_code #project_e@ergonomic_code
PostgreSQL Documentation
3.6. Inheritance
3.6. Inheritance # Inheritance is a concept from object-oriented databases. It opens up interesting new possibilities of database design. Let's create …
❤2👍2😁1
Привет!
Ну, моя эпопея с нагрузкой продолжается (часть 1, часть 2) и продолжает генерять материал для канала.
Я перешёл к этапу проверки работы с БД целевого размера (600М строк).
Идти решил постепенно: для начала залил 50М строк в целевую таблицу, запустил нагрузку и... Опять упрёся в ЦПУ на хэшировании паролей в транзакции при логине -> забитый пул подключений -> тормоза аутентификации целевого запроса на получении подключения для проверки активности токена.
Решил, что хватит извращений и надо залечить проблему с хэшированием в транзакции.
Залечил, запустил нагрузку, иии... Бэк начал 500-ить на логине. То есть стало хуже чем до фикса.
Полез копаться. Выяснилось:
1. я из транзакции вытащил чтение SDJ-агрегата, у которого было две связанных коллекции
2. т.е. это был не 1 запрос, а 1 + 2 (чтение корня + чтение коллекций).
3. при том второй запрос выполняется до завершения первого
4. и так как транзакции не было, SDJ для второго запроса захватывал новое подключение
5. в итоге 10 потоков логина на чтении корня агрегата выбирали все подключения из пулла, потом пытались сделать второй запрос и блокировались навечно, потому как все подключения уже были заняты предыдущим запросом корня, который ждал результатов запроса коллекций, который ждал... ну вы поняли:)
Завернул чтение агрегата обратно в транзакцию, запустил нагрузку (на 50М строк) и...
70 rps в течении 10 минут - медианное время ответа 137мс, 99 персентиль - 314мс, максимум - 1644мс.
т.е. в итоге корректный фикс срезал мидиану на 15%, а 99персентиль - на 30.
Мораль басни:
1. Не держите тяжёлые вычисления внутри транзакций
2. Но держите все обращения к SDJ внутри транзакций:) Вообще это прямым текстом написано в оф. доках - осталось только не забывать, не тупить и не лениться.
3. SDJ безусловно на порядок-два проще Hibernate, но всё равно слишком сложен для кожанного мешка
#spring_data_jdbc@ergonomic_code #project_e@ergonomic_code #ergo_approach@ergonomic_code
Ну, моя эпопея с нагрузкой продолжается (часть 1, часть 2) и продолжает генерять материал для канала.
Я перешёл к этапу проверки работы с БД целевого размера (600М строк).
Идти решил постепенно: для начала залил 50М строк в целевую таблицу, запустил нагрузку и... Опять упрёся в ЦПУ на хэшировании паролей в транзакции при логине -> забитый пул подключений -> тормоза аутентификации целевого запроса на получении подключения для проверки активности токена.
Решил, что хватит извращений и надо залечить проблему с хэшированием в транзакции.
Залечил, запустил нагрузку, иии... Бэк начал 500-ить на логине. То есть стало хуже чем до фикса.
Полез копаться. Выяснилось:
1. я из транзакции вытащил чтение SDJ-агрегата, у которого было две связанных коллекции
2. т.е. это был не 1 запрос, а 1 + 2 (чтение корня + чтение коллекций).
3. при том второй запрос выполняется до завершения первого
4. и так как транзакции не было, SDJ для второго запроса захватывал новое подключение
5. в итоге 10 потоков логина на чтении корня агрегата выбирали все подключения из пулла, потом пытались сделать второй запрос и блокировались навечно, потому как все подключения уже были заняты предыдущим запросом корня, который ждал результатов запроса коллекций, который ждал... ну вы поняли:)
Завернул чтение агрегата обратно в транзакцию, запустил нагрузку (на 50М строк) и...
70 rps в течении 10 минут - медианное время ответа 137мс, 99 персентиль - 314мс, максимум - 1644мс.
т.е. в итоге корректный фикс срезал мидиану на 15%, а 99персентиль - на 30.
Мораль басни:
1. Не держите тяжёлые вычисления внутри транзакций
2. Но держите все обращения к SDJ внутри транзакций:) Вообще это прямым текстом написано в оф. доках - осталось только не забывать, не тупить и не лениться.
3. SDJ безусловно на порядок-два проще Hibernate, но всё равно слишком сложен для кожанного мешка
#spring_data_jdbc@ergonomic_code #project_e@ergonomic_code #ergo_approach@ergonomic_code
Telegram
Эргономичный код
Привет!
У меня периодически спрашивают как обстоят дела с перформансом у ЭП в целом и функционального стиля + Spring Data JDBC в частности.
Я всегда говорил "У меня не хайлоад и мне всегда хватало - никогда не приходилось ничего целенаправленно оптимизировать".…
У меня периодически спрашивают как обстоят дела с перформансом у ЭП в целом и функционального стиля + Spring Data JDBC в частности.
Я всегда говорил "У меня не хайлоад и мне всегда хватало - никогда не приходилось ничего целенаправленно оптимизировать".…
❤3