Ключевые темы HighLoad++ 2025
2 дня конференции, 5000+ участников, 10 параллельных треков, 121 доклад, 10 мастер-классов и, конечно же, Fail-митап. (На котором, я, надеюсь, не сильно зафэйлился. 😃) Вот таким стал прошедший HL++.🚀 Очень много информации, которую нужно обработать и структурировать.
Из примечательного. Онтико продолжает активно развивать тему воркшопов и мастер-классов. Их стало значительно больше, и они были оба дня. Это очень продуктивный формат, предполагающий постоянный интерактив. На будущее особенно рекомендую посещать те из них, которые не записываются.
Много докладов было про AI (16). Очевидно, что эта тема стремительно врывается в нашу жизнь и диктует новые правила игры. Пока многие практические применения AI выглядят как обучение медведя катанию на велосипеде с целью его дальнейшей отправки на олимпиаду. Однако очень хорошо, что компании пытаются найти границы применимости AI. Короче, держим хвост по ветру и не теряем бдительности.🐈
Традиционно для HL++ много докладов про архитектуру и масштабируемость (34), про мои любимые базы данных (17), низкоуровневые и хардкорные оптимизации. Короче, всё, за что мы любим HL++.😄 Что-то я успел посмотреть очно, но большая часть находится в моём бэклоге. ⭐️
Были доклады, которые дали ответы на интересующие меня вопросы или подтвердили мою точку зрения. Наверняка, обо всём этом я напишу отдельные посты.
А ещё для нас смертных устроили открытую встречу с министром цифрового развития М.И. Шадаевым. Разговор получился долгим и достаточно откровенным. Надеюсь, что видео будет доступно в ближайшее время.
На финальной фотке виновники всего торжества, включая меня. Очень рад, что стал частью этой команды и мероприятия и, надеюсь, смог сделать его чуточку лучше.❤️
#conf
2 дня конференции, 5000+ участников, 10 параллельных треков, 121 доклад, 10 мастер-классов и, конечно же, Fail-митап. (На котором, я, надеюсь, не сильно зафэйлился. 😃) Вот таким стал прошедший HL++.
Из примечательного. Онтико продолжает активно развивать тему воркшопов и мастер-классов. Их стало значительно больше, и они были оба дня. Это очень продуктивный формат, предполагающий постоянный интерактив. На будущее особенно рекомендую посещать те из них, которые не записываются.
Много докладов было про AI (16). Очевидно, что эта тема стремительно врывается в нашу жизнь и диктует новые правила игры. Пока многие практические применения AI выглядят как обучение медведя катанию на велосипеде с целью его дальнейшей отправки на олимпиаду. Однако очень хорошо, что компании пытаются найти границы применимости AI. Короче, держим хвост по ветру и не теряем бдительности.
Традиционно для HL++ много докладов про архитектуру и масштабируемость (34), про мои любимые базы данных (17), низкоуровневые и хардкорные оптимизации. Короче, всё, за что мы любим HL++.
Были доклады, которые дали ответы на интересующие меня вопросы или подтвердили мою точку зрения. Наверняка, обо всём этом я напишу отдельные посты.
А ещё для нас смертных устроили открытую встречу с министром цифрового развития М.И. Шадаевым. Разговор получился долгим и достаточно откровенным. Надеюсь, что видео будет доступно в ближайшее время.
На финальной фотке виновники всего торжества, включая меня. Очень рад, что стал частью этой команды и мероприятия и, надеюсь, смог сделать его чуточку лучше.
#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2🔥2
Меры предосторожности при работе с РСУБД
В пылу сражения легко забыть базовые меры предосторожности.👊 Именно по этой причине разговоры о подобных вещах всегда актуальны. Предлагаю пройтись по ключевым рекомендациям при работе с РСУБД. За основу взят зажигательный доклад "Хайлоад на ровном месте", дополненный моими комментариями. 🔥
0️⃣ Количество соединений с БД — это дорогой и ограниченный ресурс, который контролируется как со стороны БД, так и со стороны приложения. Чем больше параллельных обращений к БД, тем большего размера нужен пул соединений; иначе тот, кому не досталось соединения, зависнет до появления свободного. Следовательно, будут таймауты, рост числа wait-потоков, рост потребления памяти (как минимум, на стек), рост потребления CPU (как минимум, на переключение контекста) и множество ярких эмоций. 😄
1️⃣ Idle-соединение — это открытое, но не используемое соединение. Например, приложение открывает соединение, а затем начинает делать длительные вычисления (или даже поход во внешние сервисы), и только в конце начинает выполнять запросы к БД. При таком подходе пул соединений будет израсходован очень быстро, и указанные выше проблемы возникнут практически сразу.
2️⃣ Idle-in-transaction-соединение — это idle-соединение, в котором началось выполнение транзакции. Чаще всего такое провоцируют фреймворки. Например, Spring-аннотация
3️⃣ Если транзакция открывается только для чтения (SELECTs), то при уровне изоляции Read Committed её лучше убрать, т.к. "толку" от неё всё равно не будет. Благодаря этому можно избавиться от idle-in-transaction-соединений. А вот если транзакция всё-таки нужна, тогда нужно повышать уровень изоляции, как минимум, до Repeatable Read, но такое нужно далеко не каждому.
4️⃣ Для минимизации времени блокировок в БД все UPDATEs в коде нужно сместить ближе к месту закрытия транзакции. Конечно, это не избавит от idle-in-transaction-соединений, но это лучше, чем ничего.
5️⃣ Пессимистичную блокировку следует применять, если много коллизий, т.е. имеется высокая конкурентность при изменениях. Однако часто достаточно оптимистичной блокировки, которая избавляет от необходимости явного открытия обрамляющей транзакции, следовательно, от описанных выше проблем. Если же пессимистичная блокировка всё-таки нужна, то её можно реализовать не на уровне БД, а с помощью внешних механизмов (например, key-value-хранилищ).
6️⃣ Медленные запросы могут исчерпать пул соединений, даже если таких запросов не очень много. Поэтому контролируем время выполнения запросов и анализируем планы запросов (explain). Частые проблемы: нет индексов на внешние ключи (foreign keys); используется антипаттерн OrIsNull; используется offset pagination (часто в сочетании с OrIsNull) вместо keyset pagination; выбираются лишние данные (особенно TOAST).
#tip #dev #devops
В пылу сражения легко забыть базовые меры предосторожности.
@Transactional, помещённая на верхний уровень процесса обработки запроса, захватит не только работу с БД, но и весь остальной код. Ко всем вышеуказанным проблемам можно смело докинуть увеличение времени транзакции, длительные блокировки в БД, расходы на хранение версий (MVCC), раздувание WAL (Wall-Ahead Log).🗂 Для "защиты" PostgreSQL от неблагонадёжных приложений следует использовать PgBouncer, который проксирует обращения к базе с целью пулинга соединений. Он позволяет активным соединениям вытеснять idle-соединения (но не idle-in-transaction), увеличивая тем самым общую пропускную способность.
#tip #dev #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤1🔥1
Базовые элементы архитектурного фреймворка
Рано или поздно каждый уважающий себя разработчик задаётся вопросом: что такое архитектура ПО. И это не просто философия, это попытка систематизировать свой опыт, свои решения, ответить на вопрос, почему я поступал так, а не иначе. И как только находим ответ, последующие решения принимаются намного легче и уверенней.💪
Многие определения архитектуры хоть и остроумны, но слишком абстрактны, чтобы из этого можно было бы извлечь значимую пользу или найти практическую применимость. Именно по этой причине мне импонирует как М. Ричардс и Н. Форд подошли к ответу на этот вопрос. Они не дают определение, а описывают составляющие архитектуры:
Как видите, архитектура системы — это не точка на прямой, а точка в многомерном пространстве (согласно авторам — в 4-мерном пространстве). В этом и кроется причина, по которой мы не можем дать архитектуре односложное определение, но можем описать её с разных сторон, одновременно отвечая на вопрос, почему решение именно такое, какое есть. Невозможно составить полное представление об архитектуре системы только по одному измерению, их нужно рассматривать в комплексе.
1️⃣ Структура системы (structure of the system) — тип используемого архитектурного стиля (или стилей). Например, микросервисная, многоуровневая, микроядерная и т.д. Стиль задаёт структуру, но не отвечает на вопрос "почему". Без всего остального — это просто прямоугольники и стрелки.
2️⃣ Свойства архитектуры (architecture characteristics) — важнейшие черты системы, определяющие критерии успеха. Свойства не связаны с функциональными возможностями системы, но нужны для её корректной работы. Авторы называют их "словами с окончанием
3️⃣ Архитектурные решения (architecture decisions) — правила построения системы и ограничения. Например, "доступ к базе данных возможен только с уровня бизнес-логики". Естественно, что решения не высечены в камне, и их можно и нужно подвергать сомнению. Главное, чтобы вокруг всего этого был выстроен процесс архитектурного контроля.
4️⃣ Принципы проектирования (design principles) — верхнеуровневые установки и рекомендации. Например, "для повышения производительности и ослабления связанности отдавать предпочтение асинхронному взаимодействию"; "для улучшения наблюдаемости использовать трассировку всех публичных методов сервиса" и т.п.
Как видите, все эти измерения взаимосвязаны: изменения в одном измерении, скорей всего, отразится в других. Задача архитектора — найти наиболее устойчивое положение в пространстве. И это положение, очевидно, будет совокупностью компромиссов, о которых все так любят говорить. Но главное, что поиск такого положения будет формировать целостный взгляд, структурированный и осознанный ответ на вопрос "почему".
➡️ Как это всё связано с практикой и при чём тут фреймворк? Посмотрите на свою систему сквозь призму этих измерений. Для каждого ограниченного контекста определите 3 самых важных архитектурных свойства. Если у каждого контекста свой набор свойств, а у вас "монолит", тогда вам, возможно, следует задуматься о декомпозиции. Затем посмотрите на свои архитектурные решения и проверьте, способствуют ли они достижению выбранных свойств. А структура и принципы проектирования работают на общее дело? Я думаю, что вы уже поняли, как это работает.
Резонный вопрос: "Почему только 4 измерения? Можно больше или меньше?" Больше, наверное, можно, меньше — не думаю. Главное, чтобы за всем этим вы видели технологию, которая позволяет в работе перейти от интуиции к системности.
〰️ 〰️ 〰️
Если вам зашла эта тема, ставьте реакции и я расскажу, как подобная практика может помочь избежать неприятностей в разработке.😏
#arch
Рано или поздно каждый уважающий себя разработчик задаётся вопросом: что такое архитектура ПО. И это не просто философия, это попытка систематизировать свой опыт, свои решения, ответить на вопрос, почему я поступал так, а не иначе. И как только находим ответ, последующие решения принимаются намного легче и уверенней.
Многие определения архитектуры хоть и остроумны, но слишком абстрактны, чтобы из этого можно было бы извлечь значимую пользу или найти практическую применимость. Именно по этой причине мне импонирует как М. Ричардс и Н. Форд подошли к ответу на этот вопрос. Они не дают определение, а описывают составляющие архитектуры:
🗂 Архитектура состоит из структуры системы в сочетании со свойствами архитектуры, которые должны поддерживаться системой, архитектурными решениями и принципами проектирования.
Как видите, архитектура системы — это не точка на прямой, а точка в многомерном пространстве (согласно авторам — в 4-мерном пространстве). В этом и кроется причина, по которой мы не можем дать архитектуре односложное определение, но можем описать её с разных сторон, одновременно отвечая на вопрос, почему решение именно такое, какое есть. Невозможно составить полное представление об архитектуре системы только по одному измерению, их нужно рассматривать в комплексе.
-ость" (англ. -ility): масштабируемость, производительность, доступность, безопасность и т.д.Как видите, все эти измерения взаимосвязаны: изменения в одном измерении, скорей всего, отразится в других. Задача архитектора — найти наиболее устойчивое положение в пространстве. И это положение, очевидно, будет совокупностью компромиссов, о которых все так любят говорить. Но главное, что поиск такого положения будет формировать целостный взгляд, структурированный и осознанный ответ на вопрос "почему".
Резонный вопрос: "Почему только 4 измерения? Можно больше или меньше?" Больше, наверное, можно, меньше — не думаю. Главное, чтобы за всем этим вы видели технологию, которая позволяет в работе перейти от интуиции к системности.
Если вам зашла эта тема, ставьте реакции и я расскажу, как подобная практика может помочь избежать неприятностей в разработке.
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
👍10🔥3
Декомпозиция в стиле квантовой архитектуры
Какие способы декомпозиции на сервисы мы знаем? И самое главное: как именно сделать такую декомпозицию, в которой мы будем уверены? Попробуем разобраться.🌌
Например, К. Ричардсон выделяет два основных подхода к декомпозиции:
🕚 По бизнес-возможностям (by business capability). Система разбивается на области, в которых бизнес генерирует прибыль. Бизнес-возможности организации определяют то, чем она является. Это более стабильное описание, в отличие от того, как организация ведёт свой бизнес. Например, обработка платежей будет всегда, и неважно, как именно она будет реализована.
🕚 По поддоменам (by subdomains). Способ декомпозиции системы на основе подходов Domain-driven design (DDD). Каждый поддомен определяет ограниченный контекст (bounded context), который соответствует одному сервису.
И несмотря на то, что всё делаешь "по науке", продолжает терзать мысль: всё ли правильно и как в этом убедиться.
Пожалуй, первое, что приходит на ум, это принципы ООП, сформулированные Р. Мартином, включая SRP (Single Responsibility) и CCP (Common Closure), а также его метрики успешности декомпозиции: абстрактность (соотношение абстрактных элементов к конкретным); нестабильность (соотношение исходящих связей компонента ко всем).
Однако всё это мне никогда не давало полной уверенности. Позже я понял причину: они нацелены в первую очередь на техническую сторону вопроса, а не прикладную; оценку существующего кода, а не того, который предстоит написать.
Думаю, по этой причине М. Ричардс и Н. Форд ввели понятие архитектурного кванта — уникального набора архитектурных свойств, действующих в рамках единицы развертывания — компонента (сервиса). При этом к свойствам предъявляются следующие требования.
1️⃣ Непредметный взгляд на проектирование. Функциональные требования определяют, что должно делать приложение, а архитектурные свойства задают эксплуатационные критерии успеха, способствующие реализации требований.
2️⃣ Влияние на структурные аспекты проектирования. Архитектурное свойство является таковым, если оно влияет на структуру проекта. Например, в одном случае безопасность — это архитектурное свойство, а в другом нет. При обработке платежей через сторонний сервис безопасность важна, но она не повлияет на структуру проекта и будет ограничена технологическими мерами (шифрование, хэширование и т.п.). А вот самостоятельная реализация платежей, возможно, потребует структурной и физической изоляции платёжного сервиса.
3️⃣ Ключевая или важная роль в успешности решения. Архитектурное свойство является таковым, если оно необходимо для успешной реализации. Поддержка каждого свойства усложняет проектирование, поддержка множества свойств — бессмысленна. Выбранные свойства должны работать на вас, а не наоборот.
О чём это говорит?
➡️ Производительность, масштабируемость, безопасность, надёжность, доступность — это только слова! В рамках отдельно взятого компонента они могут стать архитектурными свойствами только в том случае, если без них успех проекта невозможен. Понимание этого позволяет сфокусироваться на самых важных вещах и правильно расставить приоритеты.
И как это помогает оценить успешность декомпозиции?
➡️ Возьмите два взаимосвязанных сервиса и определите для них 3 самых важных архитектурных свойства. Каждый сервис — архитектурный квант, он определяет границы действия архитектурных свойств. Мысленно следуя по связи между сервисами, проверьте её адекватность. Если производительный сервис зависит от непроизводительного; безопасный — от небезопасного; масштабируемый — от немасштабируемого и т.д., значит, вы сделали что-то не так.
〰️ 〰️ 〰️
Всем добра и правильной декомпозиции! Если тема показалась интересной, поддержите меня. В следующий раз разберём, что есть помимо cohesion и coupling, и зачем это на практике.❤️
#arch
Какие способы декомпозиции на сервисы мы знаем? И самое главное: как именно сделать такую декомпозицию, в которой мы будем уверены? Попробуем разобраться.
Например, К. Ричардсон выделяет два основных подхода к декомпозиции:
🗂 Есть и более экзотические методы, которые я описывал ранее в статье "Как еще определять границы микросервисов".
И несмотря на то, что всё делаешь "по науке", продолжает терзать мысль: всё ли правильно и как в этом убедиться.
Пожалуй, первое, что приходит на ум, это принципы ООП, сформулированные Р. Мартином, включая SRP (Single Responsibility) и CCP (Common Closure), а также его метрики успешности декомпозиции: абстрактность (соотношение абстрактных элементов к конкретным); нестабильность (соотношение исходящих связей компонента ко всем).
Однако всё это мне никогда не давало полной уверенности. Позже я понял причину: они нацелены в первую очередь на техническую сторону вопроса, а не прикладную; оценку существующего кода, а не того, который предстоит написать.
Думаю, по этой причине М. Ричардс и Н. Форд ввели понятие архитектурного кванта — уникального набора архитектурных свойств, действующих в рамках единицы развертывания — компонента (сервиса). При этом к свойствам предъявляются следующие требования.
О чём это говорит?
И как это помогает оценить успешность декомпозиции?
Всем добра и правильной декомпозиции! Если тема показалась интересной, поддержите меня. В следующий раз разберём, что есть помимо cohesion и coupling, и зачем это на практике.
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤3👍3
Порочные связи между компонентами
Думаю, многие пытались оценивать качество своей архитектуры, анализируя входящие и исходящие связи между элементами. В этом контексте принято говорить о cohesion и coupling. А что насчёт качества связей?😏
Принцип каскадного снижения связанности, предложенный Русланом Сафиным, контролирует баланс между cohesion и coupling на разных уровнях декомпозиции. Однако данный принцип, как и сами понятия cohesion и coupling, не отвечает на вопрос, насколько оправданы существующие связи, насколько они здоровы. Что если наличие связи между элементами не связывает их, а привязывает один к другому, сдерживая развитие обоих? Такие связи можно назвать обременительными, нездоровыми, порочными.🫠
Большую попытку категоризировать виды связей предпринял Meilir Page-Jones в своей книге "What Every Programmer Should Know About Object-Oriented Design" (1996), введя понятие connascence (от лат. "рождённые вместе"). В русскоязычной литературе можно встретить прямую транслитерацию — коннасценция, но я предпочитаю слово взаимозависимость (interdependence), т.к. сам автор сказал, что это точный синоним.
Вместе с определением было предложено несколько степеней взаимозависимости, которые подразделяются на две группы: статические (в программном коде) и динамические (во время исполнения). Подробные примеры можно найти на сайте https://connascence.io/
Как это можно привязать к практике?
➡️ Предлагается уменьшать общую взаимозависимость путём декомпозиции на инкапсулированные элементы. В первую очередь удалять те связи, которые нарушают границы инкапсуляции, а для оставшихся связей — уменьшать степень взаимосвязанности, двигаться от динамических связей к статическим. И чем больше расстояние между элементами, тем слабей должна быть степень.
Всё равно непонятно, давай рассмотрим пример!
➡️ Короче, во-первых, нужно убедиться, что декомпозиция сделана правильно. Это уже решит большую часть проблем со связями или, наоборот, выявит недостатки. Во-вторых, выявленные взаимозависимости нужно удалить или свести их влияние к минимуму. Например, вы заметили, как модель одного ограниченного контекста передается без изменений в другой. Что будет, если эта модель поменяется в одном из контекстов? Возможно, стоит задуматься об инкапсуляции транспортного слоя между двумя контекстами? Самый банальный вариант — использовать DTO.
❗️ Идея оценки связей путём их категоризации вполне разумна, но в оригинальном подходе есть недостатки. Во-первых, весь фокус смещается с архитектуры, которая должна определять правила игры, на детали реализации, качество и чистоту кода. Во-вторых, многие предложенные категории устарели и требуют пересмотра. Например, формы статической взаимозависимости уже давно неактуальны.
Возьму на себя смелость сформулировать категории связей, актуальные на сегодняшний день:
🔗 Явная/неявная. Например, АОП провоцирует множество неявных связей и взаимополаганий.
🔗 Статическая/динамическая. Связь между компонентами предопределена или определяется во время исполнения.
🔗 Асинхронная/синхронная. Есть ли жесткая синхронизация взаимодействия компонентов, управляемая оркеструющим алгоритмом/механизмом.
🔗 Надёжная/ненадёжная. Насколько связь устойчива к различным сбоям и сверхнагрузкам, способна ли она восстанавливаться после такого.
Список можно и нужно уточнять. Однако, как мне кажется, такая категоризация хорошо укладывается в концепцию архитектурных свойств и позволяет прорабатывать каждую категорию в отдельности. Так например, если нужна надёжная связь, то она сопряжена с такими эксплуатационными свойствами как надёжность, прочность, устойчивость и адаптивность.
〰️ 〰️ 〰️
Желаю всем здоровых связей!❤️ А в следующий раз разберём, что с этим делать дальше. 🚀
#arch
Думаю, многие пытались оценивать качество своей архитектуры, анализируя входящие и исходящие связи между элементами. В этом контексте принято говорить о cohesion и coupling. А что насчёт качества связей?
Принцип каскадного снижения связанности, предложенный Русланом Сафиным, контролирует баланс между cohesion и coupling на разных уровнях декомпозиции. Однако данный принцип, как и сами понятия cohesion и coupling, не отвечает на вопрос, насколько оправданы существующие связи, насколько они здоровы. Что если наличие связи между элементами не связывает их, а привязывает один к другому, сдерживая развитие обоих? Такие связи можно назвать обременительными, нездоровыми, порочными.
Большую попытку категоризировать виды связей предпринял Meilir Page-Jones в своей книге "What Every Programmer Should Know About Object-Oriented Design" (1996), введя понятие connascence (от лат. "рождённые вместе"). В русскоязычной литературе можно встретить прямую транслитерацию — коннасценция, но я предпочитаю слово взаимозависимость (interdependence), т.к. сам автор сказал, что это точный синоним.
Два элемента взаимозависимы, если для поддержания общей работоспособности они должны изменяться одновременно.
Вместе с определением было предложено несколько степеней взаимозависимости, которые подразделяются на две группы: статические (в программном коде) и динамические (во время исполнения). Подробные примеры можно найти на сайте https://connascence.io/
Как это можно привязать к практике?
Всё равно непонятно, давай рассмотрим пример!
Возьму на себя смелость сформулировать категории связей, актуальные на сегодняшний день:
Список можно и нужно уточнять. Однако, как мне кажется, такая категоризация хорошо укладывается в концепцию архитектурных свойств и позволяет прорабатывать каждую категорию в отдельности. Так например, если нужна надёжная связь, то она сопряжена с такими эксплуатационными свойствами как надёжность, прочность, устойчивость и адаптивность.
Желаю всем здоровых связей!
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4
9 архитектурных заблуждений о распределённых системах
По сути, каждый, кто впервые создаёт распределённое приложение, делает следующие 8 предположений. Все они в конечном итоге оказываются ложными и все приводят к большим проблемам и болезненному опыту. 🍑
Это цитата, а сами заблуждения сформулированы более 30 лет назад (1991-1997) и до сих пор актуальны. Авторство приписывают Peter Deutsch и некоторым инженерам из Sun Microsystems.
1️⃣ Сеть надёжна. Думаем о том, как будет совершаться вызов или доставляться сообщение. Обеспечение надёжности передачи можно возложить на внешние механизмы (инфраструктуру, очереди, оркестраторы, outbox и т.п.); и/или самостоятельную реализацию (retries, dead letter, deadline propagation, circuit breakers и т.п.). На этом же уровне думаем о возможной многократной доставке, порядке и идемпотентности обработки.
2️⃣ Нулевая задержка. Думаем, в какой сети происходит взаимодействие: в локальной или глобальной (через горы-моря-океаны). Задержка более проблематична, чем пропускная способность, ведь есть физические ограничения по скорости передачи. Соответственно, стараемся минимизировать количество сетевых взаимодействий; размер передаваемых данных; оптимизируем маршруты, необходимые для выполнения каждого сценария; вспоминаем про кэширование, пакетную обработку и локальность вычислений.
3️⃣ Неограниченная пропускная способность. Пропускная способность растет, но растут и наши потребности. Вопрос лишь в том, насколько они адекватны. Насколько адекватно, когда сервис возвращает модель из множества атрибутов, но из всех нужен только один? Умножаем размер одного такого сообщения на их количество в секунду и сравниваем полученный результат с пропускной способностью используемой сети, принимая во внимание возможные сетевые потери. Только на оптимизации трафика можно существенно сэкономить и улучшить показатели. Тут можно вспомнить и про бинарные форматы (Avro, Protobuf, MessagePack).
4️⃣ Сеть безопасна. С одной стороны, уровень безопасности должен соответствовать уровню возможных угроз. С другой, для атаки всегда пытаются найти самое слабое звено. Поэтому в идеале защита не только по внешнему периметру, но и внутри. Как минимум, стоит задуматься об аутентификации/авторизации запросов, разделении аккаунтов доступа к используемым ресурсам (БД и т.п.). Для себя я нашел очень хорошую шпаргалку по этой теме — OWASP Cheat Sheet.
5️⃣ Топология не меняется. После развертывания приложение уже не под вашим контролем. Считаем, что приложение развертывается в дикой и враждебной среде, где узлы появляются и исчезают в случайные моменты времени. Никогда не полагаемся на конкретные маршруты, узлы и IP-адреса; всё должно быть адаптивно. Изменение топологии не должно заставлять менять приложение.
6️⃣ Администратор всегда один. Проблема проявляется сильней, если есть отдельная операционная команда или даже отдельная организация, которая выполняет эту роль. Налаживаем коммуникации, автоматизируем развертывание, добавляем средства диагностики и инструкции использования. Всё это работает в обе стороны: упрощаете жизнь операционной команде — упрощаете жизнь себе.
7️⃣ Передача данных бесплатна. Сериализация/десериализация — это затраты на память и CPU; возможность передачи по сети — это затраты на оборудование и его обслуживание. Здесь архитектор и разработчик должны еще раз вернуться к заблуждениям 2 и 3.
8️⃣ Сеть однородна. Даже в локальной сети однородность — редкое достижение. Разные производители и ресурсы, ОС и приложения, разные версии API и т.д. Выжить в этом безумном мире помогает стандартизация и обратная совместимость.
И 9-е бонусное заблуждение лично от меня😏
9️⃣ Контейнеры бесплатны. Не хватает производительности — докинем еще несколько экземпляров! Выглядит разумно для "тушения пожаров", но не в долгосрочной перспективе. Оптимизация кода или пересмотр решения — улучшают производительность; масштабирование — позволяет справиться с нагрузкой!
〰️ 〰️ 〰️
Думаю, что каждый увидел себя в каждом эпизоде! Но кто без греха?! 😃 Всем поменьше заблуждений!❤️
#arch
По сути, каждый, кто впервые создаёт распределённое приложение, делает следующие 8 предположений. Все они в конечном итоге оказываются ложными и все приводят к большим проблемам и болезненному опыту. 🍑
Это цитата, а сами заблуждения сформулированы более 30 лет назад (1991-1997) и до сих пор актуальны. Авторство приписывают Peter Deutsch и некоторым инженерам из Sun Microsystems.
И 9-е бонусное заблуждение лично от меня
Думаю, что каждый увидел себя в каждом эпизоде! Но кто без греха?! 😃 Всем поменьше заблуждений!
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8🤝3❤2
Трансформация конференций
Если кто-то пропустил, то в течение года нарастал хайп на тему того, что текущий формат конференций уже устарел. И вот накануне нового года Онтико сформулировало концепцию "конференций развития", заявив об этом во всех своих каналах и чатах.
Честно говоря, концепция больше похожа на манифест, и можно только догадываться, какие именно трансформации произойдут. Между тем, очевиден вектор развития — практическая направленность и ориентация на текущие потребности аудитории. Пожалуй, в эпоху доступности информации это единственно правильное направление развития. Не рассчитываю, что ближайшие конференции сразу получатся такими, как заявлено, т.к. новый формат требует перестройки на всех уровнях (сознания), но очень надеюсь на итоговый успех.🔥
#conf
Если кто-то пропустил, то в течение года нарастал хайп на тему того, что текущий формат конференций уже устарел. И вот накануне нового года Онтико сформулировало концепцию "конференций развития", заявив об этом во всех своих каналах и чатах.
Честно говоря, концепция больше похожа на манифест, и можно только догадываться, какие именно трансформации произойдут. Между тем, очевиден вектор развития — практическая направленность и ориентация на текущие потребности аудитории. Пожалуй, в эпоху доступности информации это единственно правильное направление развития. Не рассчитываю, что ближайшие конференции сразу получатся такими, как заявлено, т.к. новый формат требует перестройки на всех уровнях (сознания), но очень надеюсь на итоговый успех.
#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥3
Первичный анализ задачи поиска медицинских документов
Сегодня предлагаю рассмотреть вполне конкретную задачу из реального проекта. Думаю, что подобный кейс достаточно интересен и его можно рассматривать для прокачки своих навыков по System Design.💪
Разбор получился большим, поэтому я оформил его в виде статьи. Зато в ней всё, что мы любим: архитектура и базы данных. В статье рассматривается вариант реализации быстрого поиска по метаданным медицинских документов; некоторые проблемы производительности SQL-хранилищ; преимущества OLAP-хранилищ и колоночных баз данных, включая ClickHouse.🌌
Сразу скажу, что мы ещё не полностью решили описанную в статье задачу. Представленное решение — лишь один из возможных вариантов, черновик, который ещё не проверен на практике. Однако, выполнив достаточно подробный анализ, я решил поделиться им с вами, а не оставлять пылиться результаты проделанной работы у себя в столе. В статье постарался адаптировать материал, чтобы он был понятен широкому кругу читателей и не требовал глубокого погружения в предметную область. Надеюсь, у меня получилось, и желаю вам приятного чтения!❤️
➡️ Ссылка на статью ⬅️
〰️ 〰️ 〰️
Всё чаще появляются новости об ограничении доступа к информационным ресурсам, включая Telegram. Решил, что было бы неплохо обзавестись web-версией своего канала, в том числе для публикации статей, которые не помещаются в размер поста.
#arch #db
Сегодня предлагаю рассмотреть вполне конкретную задачу из реального проекта. Думаю, что подобный кейс достаточно интересен и его можно рассматривать для прокачки своих навыков по System Design.
Разбор получился большим, поэтому я оформил его в виде статьи. Зато в ней всё, что мы любим: архитектура и базы данных. В статье рассматривается вариант реализации быстрого поиска по метаданным медицинских документов; некоторые проблемы производительности SQL-хранилищ; преимущества OLAP-хранилищ и колоночных баз данных, включая ClickHouse.
Сразу скажу, что мы ещё не полностью решили описанную в статье задачу. Представленное решение — лишь один из возможных вариантов, черновик, который ещё не проверен на практике. Однако, выполнив достаточно подробный анализ, я решил поделиться им с вами, а не оставлять пылиться результаты проделанной работы у себя в столе. В статье постарался адаптировать материал, чтобы он был понятен широкому кругу читателей и не требовал глубокого погружения в предметную область. Надеюсь, у меня получилось, и желаю вам приятного чтения!
Всё чаще появляются новости об ограничении доступа к информационным ресурсам, включая Telegram. Решил, что было бы неплохо обзавестись web-версией своего канала, в том числе для публикации статей, которые не помещаются в размер поста.
#arch #db
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍1
Итоги 2025 года
Вот и пришло время подводить итоги года. Стараюсь следовать своим же рекомендациям и делать небольшой ретроспективный анализ своей деятельности.😏
👨🏻💻 Рабочий год у меня прошёл под девизом "импортозамещения". На моей совести была разработка общего подхода и инструмента для миграции данных с одной базы в другую. Миграция прошла практически безукоризненно, перенесли две больших базы — на 5 млрд и 40 млрд строк соответственно. Всё было онлайн, всё без остановки работы системы. Ещё остались некоторые работы, но считаю, что основная и самая сложная часть уже позади. Помимо этого удалось переработать и отдать в разработку новую концептуальную архитектуру своего любимого олимпиадного проекта.
👨🏻🎨 Творческий год был не менее продуктивным. Моему каналу исполнился 1 год, и я искренне рад, что мой контент находит своего читателя. Спасибо вам большое, Вы — супер!⭐️ За минувший год моя тяга к графомании заставила меня написать 62 поста и 5 статей. 🙈 Мне удалось посетить 3 крупных конференции в роли докладчика; поучаствовать в 3 публичных митапах, один из которых был Fail-митапом; поучаствовать в десятке online-конференций. Возможно, для кого-то не так много, зато по делу. 😃 В конце года оформил веб-версию блога, в котором старательно собрал подборку постов, статей и публичных выступлений. В следующем году могу пожелать себе быть не менее заряженным и продуктивным! 🚀
Желаю всем счастливого и продуктивного Нового года! 🎄 И не забывайте, что помимо рабочего и творческого года, есть еще и семейный год, который должен занимать центральное место в нашей жизни!❤️
〰️ 〰️ 〰️
Думаю, что первые две недели января я буду сохранять молчание в эфире. Но чтобы вам не было скучно и, как и мне, было чем заняться свободными зимними вечерами, поделюсь своей подборкой каналов.
🕚 Архитектура ИТ-решений — хотите прокачать свои навыки в архитектуре корпоративных информационных систем или находиться в курсе того, что там происходит, тогда вам точно сюда. Канал полезен не только постами, но и последующими обсуждениями в комментариях.
🕚 Архитектура распределённых систем — об ИТ-архитектуре и разработке. С Русланом я знаком лично уже много лет, мне очень близки его взгляды, нравится нестандартный и свежий взгляд на, казалось бы, привычные вещи.
🕚 Позовите Олега | Архитектура и разработка — привычные нам всем вещи про архитектуру, разработку и менеджмент в ИТ, но с упором на личный опыт и практику. Всё чётко, структурно, обстоятельно и по делу.
🕚 Токсичный (it) архитектор — даёт заряд отрицательной энергии, которая помогает принять правильное и взвешенное архитектурное решение. Несмотря на намеренно провокационную стилистику, посты всегда имеют аргументацию позиции автора.
🕚 Саша Раковский — про экстремальное программирование и разработку программного обеспечения, которые, очевидно, пропитаны годами бесценного опыта. Саша на самом деле выдаёт уникальный контент, как он сам о себе всегда говорит.
🕚 Инженер и Менеджер — если вы в поисках здравого смысла в менеджменте ИТ, то заходите. Захватывающая и местами манипулятивная подача, злободневные темы и инженерный взгляд на управленческие вопросы.
#summary
Вот и пришло время подводить итоги года. Стараюсь следовать своим же рекомендациям и делать небольшой ретроспективный анализ своей деятельности.
👨🏻💻 Рабочий год у меня прошёл под девизом "импортозамещения". На моей совести была разработка общего подхода и инструмента для миграции данных с одной базы в другую. Миграция прошла практически безукоризненно, перенесли две больших базы — на 5 млрд и 40 млрд строк соответственно. Всё было онлайн, всё без остановки работы системы. Ещё остались некоторые работы, но считаю, что основная и самая сложная часть уже позади. Помимо этого удалось переработать и отдать в разработку новую концептуальную архитектуру своего любимого олимпиадного проекта.
👨🏻🎨 Творческий год был не менее продуктивным. Моему каналу исполнился 1 год, и я искренне рад, что мой контент находит своего читателя. Спасибо вам большое, Вы — супер!
Желаю всем счастливого и продуктивного Нового года! 🎄 И не забывайте, что помимо рабочего и творческого года, есть еще и семейный год, который должен занимать центральное место в нашей жизни!
Думаю, что первые две недели января я буду сохранять молчание в эфире. Но чтобы вам не было скучно и, как и мне, было чем заняться свободными зимними вечерами, поделюсь своей подборкой каналов.
#summary
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7🎄4👍2
Throttling == бесполезная трата CPU
К такому выводу я пришёл на одном из проектов. Если контейнер приложения находится в состоянии тротлинга, это может вызвать не только замедление вычислений, но и бессмысленный перерасход CPU. Суммарно перерасход может достигать 50%, т.е. до половины выделенных процессорных ресурсов может уходить на "обогрев воздуха", а не на полезную работу.🔥
Всё началось с того, что нужно было достаточно точно измерить время использования CPU (CPU Usage) параллельно выполняющихся процессов ОС. Точность измерения оценивалась относительно аналогичного показателя, полученного при последовательном выполнении. По итогу нужно было выполнить калибровку системы и найти оптимальный уровень параллелизма, при котором CPU Usage каждого процесса приемлемо близок к эталону.
Иначе говоря, представьте, что есть некоторая вычислительная программа (задача, функция). Сначала делается серия последовательных запусков программы, и для каждого процесса измеряется его CPU Usage. Затем делается серия параллельных запусков с разным уровнем параллелизма. Например, в первой серии запускается по 2 одновременно работающих процесса; во второй – по 4, в третьей – по 8 и т.д. Все процессы запускаются в одном и том же окружении и выполняют одну и ту же вычислительную работу. По условию задачи уровень параллелизма считается приемлемым, если CPU Usage параллельного исполнения не превышает 30% последовательного.
Для чего всё это нужно?
➡️ Если у вас есть большой объём/поток вычислительных задач, и нужно обработать его как можно быстрей, но так, чтобы вычислительные затраты на каждую задачу были минимальны. Минимальны, значит, основная работа должна идти на вычисления, а не на переключение контекста и прочие накладные расходы, связанные с организацией параллелизма.
Конкретно в моём случае требовалось сделать проверку олимпиадных решений по программированию. Сделать это нужно было как можно скорей, а CPU Usage при этом использовался как критерий оценки корректности решения.
Проведя серию экспериментов, я ожидаемо подтвердил закон Амдала, но самое интересное заключалось в другом. С ростом уровня параллелизма CPU Usage начинает значительно деградировать – в среднем до 50% относительно эталона (иллюстрация).
Положительный момент в том, что деградация не бесконечна и имеет предел; отрицательный – большая часть вычислительных ресурсов тратится на организацию параллелизма (иллюстрация). Выводы очевидны, но полученные мной показатели заставили относиться к вопросу более серьёзно.
Какие из этого можно сделать выводы?
1️⃣ Частый тротлинг – проблема в конфигурации лимитов или неадекватно большом уровне параллелизма. В Kubernetes для контроля тротлинга можно использовать метрику container_cpu_cfs_throttled_seconds_total.
2️⃣ Тротлинг – это момент, когда потоки ОС часто и много конкурируют за CPU, следовательно, значительная часть вычислительных ресурсов используется впустую. Это справедливо, ведь большая часть приложений – это многопоточные web-приложения.
3️⃣ Превалирование принудительных переключений – это CPU-bound-задачи или высокий уровень параллелизма. Для большинства приложений справедливо второе. Подтвердить данный факт можно, посмотрев на соотношение метрик
4️⃣ CPU Usage – это не абсолют, это плавающий показатель. Анализируя или сравнивая профили производительности приложения, смотрите не только на CPU Usage, но и на Elapsed Time, также принимая во внимание количество параллельных вычислений, производимых во время снятия профиля.
〰️ 〰️ 〰️
А какие подходы позволяют контролировать уровень параллелизма, рассмотрим в следующий раз. Всем добра и поменьше параллельных активностей!❤️
#dev #devops
К такому выводу я пришёл на одном из проектов. Если контейнер приложения находится в состоянии тротлинга, это может вызвать не только замедление вычислений, но и бессмысленный перерасход CPU. Суммарно перерасход может достигать 50%, т.е. до половины выделенных процессорных ресурсов может уходить на "обогрев воздуха", а не на полезную работу.
Всё началось с того, что нужно было достаточно точно измерить время использования CPU (CPU Usage) параллельно выполняющихся процессов ОС. Точность измерения оценивалась относительно аналогичного показателя, полученного при последовательном выполнении. По итогу нужно было выполнить калибровку системы и найти оптимальный уровень параллелизма, при котором CPU Usage каждого процесса приемлемо близок к эталону.
Иначе говоря, представьте, что есть некоторая вычислительная программа (задача, функция). Сначала делается серия последовательных запусков программы, и для каждого процесса измеряется его CPU Usage. Затем делается серия параллельных запусков с разным уровнем параллелизма. Например, в первой серии запускается по 2 одновременно работающих процесса; во второй – по 4, в третьей – по 8 и т.д. Все процессы запускаются в одном и том же окружении и выполняют одну и ту же вычислительную работу. По условию задачи уровень параллелизма считается приемлемым, если CPU Usage параллельного исполнения не превышает 30% последовательного.
Для чего всё это нужно?
Конкретно в моём случае требовалось сделать проверку олимпиадных решений по программированию. Сделать это нужно было как можно скорей, а CPU Usage при этом использовался как критерий оценки корректности решения.
Проведя серию экспериментов, я ожидаемо подтвердил закон Амдала, но самое интересное заключалось в другом. С ростом уровня параллелизма CPU Usage начинает значительно деградировать – в среднем до 50% относительно эталона (иллюстрация).
Положительный момент в том, что деградация не бесконечна и имеет предел; отрицательный – большая часть вычислительных ресурсов тратится на организацию параллелизма (иллюстрация). Выводы очевидны, но полученные мной показатели заставили относиться к вопросу более серьёзно.
🗂 Интересно и то, что ОС включает затраты на переключение контекста в статистику процесса. Это справедливо, но немного неожиданно, ведь за переключение контекста отвечает диспетчер задач ОС, а не процесс.
Какие из этого можно сделать выводы?
voluntary_ctxt_switches и nonvoluntary_ctxt_switches (добровольные и принудительные переключения), которые доступны в файле статуса Linux-процесса /proc/<PID>/status.А какие подходы позволяют контролировать уровень параллелизма, рассмотрим в следующий раз. Всем добра и поменьше параллельных активностей!
#dev #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥1
OOM/Killer к нам приходит
Думаю, каждый хотя бы раз сталкивался с Out Of Memory (OOM), а особо удачливые встречали OOM Killer. Страшней всего, когда это происходит без явных предпосылок в коде. 🙈
Скажу честно, проблемы с памятью обычно встречаю с чувством тревоги. Во-первых, чаще всего OOM происходит в приложениях с монолитной архитектурой, которые отличаются обилием функциональности. Во-вторых, как правило, OOM — инцидент, и нет времени на долгие исследования. Наконец, объективно OOM случается крайне редко, чтобы каждый был гуру в этом вопросе.
Чтобы побороть животные страхи, нужно немного разобраться в теме и попытаться классифицировать возможные ситуации. Определить, что перед нами: ошибка в коде или конфигурировании окружения. Поэтому не соглашайтесь уходить в исследование дампов, пока не узнаете всю предысторию возникновения OOM/Killer, иначе будете гоняться за призраками.
В ОС для контроля памяти есть два основных показателя:
1️⃣ Сколько выделено. Сколько памяти ОС выделила процессу, включая данные кучи (heap), стека (stack), код процесса и используемых библиотек, но исключая память, которая была выгружена в swap. Показатель отражает фактическое состояние дел на текущий момент. В Linux — это Resident Set Size (RSS); в Windows — Working Set; в Kubernetes — container_memory_working_set_bytes.
2️⃣ Сколько запрошено. Сколько памяти процесс запросил у ОС. Совсем не факт, что запрошенный объем имеется сейчас в наличии или будет доступен в будущем. Это преднамеренное поведение, называемое резервированием (overcommitment). Показатель всегда больше RSS и отражает намерения процесса. В Linux — это VmData; в Windows — Private Bytes; в Kubernetes — нет аналога.
Что это даёт?
➡️ Большой объем выделенной памяти не всегда свидетельство утечек. Часто приложение просто "жирное", потому что так написано. В таких случаях проблема с OOM решается увеличением лимитов и заведением задач на оптимизацию кода.
➡️ Если нужно контролировать и предотвращать нежелательное поведение процесса, нужно следить за динамикой запрашиваемой памяти. Например, сразу прерывать процесс, если он запросил больше лимита.
Как анализировать расход памяти?
🕚 Пилообразный график. Это нормально, например, при наличии повторяющихся задач или сборщика мусора.
🕚 На продолжительном интервале видна тенденция к росту. Это нормально, например, при наполнении кэшей или повышении нагрузки.
🕚 Взрывной рост. Это нормально, например, при повышении нагрузки или выполнении тяжёлых операций (импорт/экспорт данных, формирование отчётов и т.д.).
➡️ Проанализируйте динамику роста, сопоставьте её с тем, что вы знаете про приложение и что этому предшествовало, и уже после этого выносите вердикт, является ли поведение аномальным и говорящим об утечке памяти.
А теперь вернемся к двум возможным ситуациям:
🔥 OOM — приложение упёрлось в лимит и завершилось самостоятельно.
🔥 OOM Killer — в системе возникла острая нехватка памяти. Защитный механизм ОС вызывает OOM Killer, который убивает самые "жирные" процессы. Под раздачу может попасть кто угодно, включая само приложение. Особенно неприятно, когда приложение умирает, а контейнер продолжает жить.
❗️ Первопричины обеих ситуаций схожие. Операции с памятью инертны: память выделяется/освобождается не сразу. Сборка мусора, активные аллокации, пиковые нагрузки, шумные соседи и т.п. Всё это может привести к тому, что упираемся в лимит быстрей, чем рассчитывали. Однако OOM Killer чаще всего означает ошибку конфигурирования окружения:
➡️ Если анализ возможных причин указывает, что утечек нет, просто такой код и такие обстоятельства, то увеличиваем лимиты и спокойно идём оптимизировать код, анализируя снятый дамп памяти. Либо откатываемся. Так решается большинство ситуаций с OOM, и они не требуют героизма. В противном случае страдаем по полной. 😄
〰️ 〰️ 〰️
Будьте бдительны. И да прибудет с вами Память!❤️
#dev #devops
Думаю, каждый хотя бы раз сталкивался с Out Of Memory (OOM), а особо удачливые встречали OOM Killer. Страшней всего, когда это происходит без явных предпосылок в коде. 🙈
Скажу честно, проблемы с памятью обычно встречаю с чувством тревоги. Во-первых, чаще всего OOM происходит в приложениях с монолитной архитектурой, которые отличаются обилием функциональности. Во-вторых, как правило, OOM — инцидент, и нет времени на долгие исследования. Наконец, объективно OOM случается крайне редко, чтобы каждый был гуру в этом вопросе.
Чтобы побороть животные страхи, нужно немного разобраться в теме и попытаться классифицировать возможные ситуации. Определить, что перед нами: ошибка в коде или конфигурировании окружения. Поэтому не соглашайтесь уходить в исследование дампов, пока не узнаете всю предысторию возникновения OOM/Killer, иначе будете гоняться за призраками.
В ОС для контроля памяти есть два основных показателя:
Что это даёт?
Как анализировать расход памяти?
А теперь вернемся к двум возможным ситуациям:
limits не учитывает всплески или выбран неправильный QoS.🗂 Приход OOM/Killer всегда сопровождается повышенной нагрузкой на CPU, т.к. в этот момент система судорожно пытается найти свободные страницы памяти.
Будьте бдительны. И да прибудет с вами Память!
#dev #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥2
Плохо знаешь данные - рискуешь здоровьем
Я следовал твоим рекомендациям, мой код написан почти идеально и полностью покрыт тестами. Более того, он уже год работает в проде! Почему вдруг сегодня всё упало?! 🐒
На этой неделе я наткнулся на не очень приятный кусок кода и понял, что в причины возникновения проблем с CPU/RAM не включил еще одну➡️ плохое знание своих данных.
Почему мы плохо знаем данные и как это контролировать - тема отдельного обсуждения. Не до конца разобрались в предметной области; не предполагали такого сценария использования системы; не рассчитывали на популярность какой-то функции; не заметили наличия бэкдора; тестовый стенд содержал мало данных; временное решение осталось постоянным; всосали всю таблицу в кэш и т.д. Главное, что подобные упущения приводят к тому, что в некоторых сценариях существующие алгоритмы начинают работать крайне неэффективно или даже деструктивно. И мы на собственной шкуре начинаем понимать, что такое сложность🫥
Например, недавно был кейс. Пользователи нашего API догадались завести "синтетический агрегат", на который отношением many-to-one подвесили несколько тысяч связанных сущностей. Изначально предполагалось, что количество связей не будет превышать сотни. Естественно, что большая часть кода была написана без расчёта на подобный объем данных.
Но вот на днях попался пример откровенного вредительства. Возможно, некоторые скажут, что это могло быть временное решение, которое осталось постоянным, но на самом деле, немного зная историю проекта, я так сказать не могу. Приведу пример кода на Java (я его изменил, но суть проблемы должна быть ясна).
Вопрос даже не в том, как это сделано, а в том, что тут делается и почему! Ясно, что с ростом таблицы
➡️ Если мы плохо знаем свои данные, мы закладываем уродливую пасхалку и мину замедленного действия.
Как этого избежать?
➡️ При работе с данными всегда себя спрашиваю: "А что если?" Что, если тут будет не 100 элементов, а 100000? Что, если этот запрос будет выполняться не 10 мс, а 10 секунд?
Конечно, это не всегда спасает, но приём точно рабочий!😏
#dev
Я следовал твоим рекомендациям, мой код написан почти идеально и полностью покрыт тестами. Более того, он уже год работает в проде! Почему вдруг сегодня всё упало?! 🐒
На этой неделе я наткнулся на не очень приятный кусок кода и понял, что в причины возникновения проблем с CPU/RAM не включил еще одну
Почему мы плохо знаем данные и как это контролировать - тема отдельного обсуждения. Не до конца разобрались в предметной области; не предполагали такого сценария использования системы; не рассчитывали на популярность какой-то функции; не заметили наличия бэкдора; тестовый стенд содержал мало данных; временное решение осталось постоянным; всосали всю таблицу в кэш и т.д. Главное, что подобные упущения приводят к тому, что в некоторых сценариях существующие алгоритмы начинают работать крайне неэффективно или даже деструктивно. И мы на собственной шкуре начинаем понимать, что такое сложность
O(n), проблема с N+1 запросами, почему файлы нужно обрабатывать блоками, почему не нужно логику засовывать в транзакцию БД и т.п. Например, недавно был кейс. Пользователи нашего API догадались завести "синтетический агрегат", на который отношением many-to-one подвесили несколько тысяч связанных сущностей. Изначально предполагалось, что количество связей не будет превышать сотни. Естественно, что большая часть кода была написана без расчёта на подобный объем данных.
Но вот на днях попался пример откровенного вредительства. Возможно, некоторые скажут, что это могло быть временное решение, которое осталось постоянным, но на самом деле, немного зная историю проекта, я так сказать не могу. Приведу пример кода на Java (я его изменил, но суть проблемы должна быть ясна).
List<City> getCities(String regionCode) {
return em.createNativeQuery(
"SELECT DISTINCT " +
" city_code AS code, " +
" city_name AS name " +
"FROM patients " +
"WHERE region_code = :region " +
"ORDER BY city_name ASC",
City.class)
.setParameter("region", regionCode)
.getResultList();
}Вопрос даже не в том, как это сделано, а в том, что тут делается и почему! Ясно, что с ростом таблицы
patients будет расти время выполнения запроса; следовательно, соединение БД будет держаться дольше; быстрей упрёмся в нехватку соединений. Вишенка на торте: у таблицы patients нет индекса на region_code.Как этого избежать?
Конечно, это не всегда спасает, но приём точно рабочий!
#dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🔥1
Архитектура лечит причину
Архитектура должна лечить причину; в противном случае будете обречены бесконечно бороться с симптомами. Постараюсь объяснить эту аксиому на трёх кейсах из практики.⬇️
У меня не получилось без потери качества уместить весь материал в размер поста, поэтому решил не ограничивать себя в объеме и написал небольшую статью. 🙈 Здесь оставлю прямые ссылки на описание каждого кейса.
1️⃣ Аналог LeetCode
2️⃣ Поиск медицинских документов
3️⃣ Гетерогенное хранилище документов
Если архитектура не решает корень проблемы, пересматривайте её! Цепляясь за неудачное архитектурное решение, вы провоцируете лишь бесконтрольное усложнение системы. В итоге у разработчиков, как у самураев, не будет цели, только путь; каждый следующий шаг на этом пути будет тяжелей предыдущего, а повернуть назад однажды может быть очень непросто. Не становитесь самураями, своевременно производите реструктуризацию решения и не забывайте о неизбежности эволюции программных систем.
И еще одно важное дополнение. Если кто-то озадачился вопросом, почему предлагаемые выше решения не были очевидны изначально. Во-первых, следует вспомнить закон Гола: сложные рабочие системы получаются только из простых и рабочих. Во-вторых, иногда осознание причины требует глубокого погружения в детали проекта и должной широты взгляда на все процессы системы.
#arch
Архитектура должна лечить причину; в противном случае будете обречены бесконечно бороться с симптомами. Постараюсь объяснить эту аксиому на трёх кейсах из практики.
У меня не получилось без потери качества уместить весь материал в размер поста, поэтому решил не ограничивать себя в объеме и написал небольшую статью. 🙈 Здесь оставлю прямые ссылки на описание каждого кейса.
Если архитектура не решает корень проблемы, пересматривайте её! Цепляясь за неудачное архитектурное решение, вы провоцируете лишь бесконтрольное усложнение системы. В итоге у разработчиков, как у самураев, не будет цели, только путь; каждый следующий шаг на этом пути будет тяжелей предыдущего, а повернуть назад однажды может быть очень непросто. Не становитесь самураями, своевременно производите реструктуризацию решения и не забывайте о неизбежности эволюции программных систем.
И еще одно важное дополнение. Если кто-то озадачился вопросом, почему предлагаемые выше решения не были очевидны изначально. Во-первых, следует вспомнить закон Гола: сложные рабочие системы получаются только из простых и рабочих. Во-вторых, иногда осознание причины требует глубокого погружения в детали проекта и должной широты взгляда на все процессы системы.
#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4❤1⚡1🤔1
Domain Vision Statement
Волею судьбы мне достался крайне аскетичный репозиторий. Постепенно приводя его в порядок, продолжил думать, чего ещё обычно не хватает на старте знакомства с проектом.👔
Вот приходите вы в новую команду, уже успели прочитать базовую документацию для знакомства с проектом и предметной областью, подходите к наставнику, а он вам: "Давай расскажу суть проекта, познакомлю со структурой и с чем придётся работать в ближайшее время." И далее обычно следует, действительно, короткий, но очень ёмкий, точный, последовательный и понятный рассказ. Рассказ, которого вы не видели ни в документации, ни в README репозитория.
Скажу честно, я сам так делал много раз, объясняя суть проекта новым сотрудникам, но всегда старался это делать до того, как они пойдут читать первые страницы документации или смотреть код. И однажды я решил прекратить заниматься этой полезной, но очень неблагодарной работой.
Код и его первый запуск в локальном окружении — это первое, что хочет видеть каждый разработчик, вступающий в проект. Поэтому мне очень импонирует подход, когда ключевые знания о технической реализации проекта лежат в репозитории с кодом. Пусть первое, что видит каждый, кто открывает репозиторий, будет README, в котором в самом начале изложена суть проекта.
Вот ровно то, чтобы вы рассказали новому члену команды в первые 5 минут разговора. Два-три абзаца: просто, чётко и по делу. Это изложение должно определять цель и назначение проекта и конкретно данной кодовой базы.
Что включить в описание?
☑️ Название проекта, понятное всем и каждому. Без сложных аббревиатур и терминов предметной области, т.к. с этим человек познакомится позже.
☑️ Общая цель проекта. Какую основную задачу или проблему решаете. Возможно, тут придётся поверхностно пояснить небольшие особенности предметной области.
☑️ Положение проекта в общей экосистеме. Как именно встраиваетесь в общее решение, описание назначения интеграций с внешними системами.
❗️ Не грузите деталями, которые могут измениться. Никаких микросервисов, баз данных или технологических особенностей! Основной фокус и упор — создание правильного представления о предназначении проекта.
Не получилось с первого раза?
➡️ Не страшно! Отлаживайте и итеративно дорабатывайте это описание. Можете начать с одного предложения или абзаца. Сделайте сами или попросите AI сгенерировать базовый вариант. Вы всегда сможете добавить необходимые детали, по мере своего погружения в предметную область.
Хорошо, давай пример!
Если однажды решу, что это описание не работает как нужно, сделаю его лучше и точней!
И уже после этого я ожидаю увидеть какой-то интерактивный навигатор по репозиторию, включающий всё то, что помогает разобраться со структурой и начать работу.
Ты не придумал ничего нового!
➡️ Да, верно. Эрик Эванс назвал это описание "Domain Vision Statement", указывая, что оно задает разработчикам общее направление, на чем должны быть сконцентрированы все усилия. Фокус не на технологиях и алгоритмах, а на решаемой задаче. Именно эту эстафету и нужно передать на входе.
И еще. Пишите не для себя в будущем, а для себя в прошлом! Пишите для незнакомца, который только-только начинает работу с проектом. И будет замечательно, если такие незнакомцы будут выступать основными рецензентами.
〰️ 〰️ 〰️
А что у вас в README корня репозитория? Как вы доносите суть до новичков? 😉
#arch #dev
Волею судьбы мне достался крайне аскетичный репозиторий. Постепенно приводя его в порядок, продолжил думать, чего ещё обычно не хватает на старте знакомства с проектом.
Вот приходите вы в новую команду, уже успели прочитать базовую документацию для знакомства с проектом и предметной областью, подходите к наставнику, а он вам: "Давай расскажу суть проекта, познакомлю со структурой и с чем придётся работать в ближайшее время." И далее обычно следует, действительно, короткий, но очень ёмкий, точный, последовательный и понятный рассказ. Рассказ, которого вы не видели ни в документации, ни в README репозитория.
Скажу честно, я сам так делал много раз, объясняя суть проекта новым сотрудникам, но всегда старался это делать до того, как они пойдут читать первые страницы документации или смотреть код. И однажды я решил прекратить заниматься этой полезной, но очень неблагодарной работой.
Код и его первый запуск в локальном окружении — это первое, что хочет видеть каждый разработчик, вступающий в проект. Поэтому мне очень импонирует подход, когда ключевые знания о технической реализации проекта лежат в репозитории с кодом. Пусть первое, что видит каждый, кто открывает репозиторий, будет README, в котором в самом начале изложена суть проекта.
Вот ровно то, чтобы вы рассказали новому члену команды в первые 5 минут разговора. Два-три абзаца: просто, чётко и по делу. Это изложение должно определять цель и назначение проекта и конкретно данной кодовой базы.
Что включить в описание?
Не получилось с первого раза?
Хорошо, давай пример!
Основное назначение проекта — формирование реестра с данными о паллиативных пациентах и организация процесса сопровождения и ухода за ними, а именно: планирование записей на осмотр, организация работы выездной службы и проведение осмотров. Реестр формируется на основе событий от внешних служб, интеграция с которыми производится через корпоративную шину сообщений. Некоторые недостающие данные запрашиваются у внешних сервисов (например, данные о пациенте, данные о смерти, поиск медицинских документов)...
Если однажды решу, что это описание не работает как нужно, сделаю его лучше и точней!
И уже после этого я ожидаю увидеть какой-то интерактивный навигатор по репозиторию, включающий всё то, что помогает разобраться со структурой и начать работу.
Ты не придумал ничего нового!
И еще. Пишите не для себя в будущем, а для себя в прошлом! Пишите для незнакомца, который только-только начинает работу с проектом. И будет замечательно, если такие незнакомцы будут выступать основными рецензентами.
А что у вас в README корня репозитория? Как вы доносите суть до новичков? 😉
#arch #dev
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤4🔥2
Workflow Event pattern
Зрелость системы в том числе определяется её прочностью и устойчивостью. Если адаптируемость — важное архитектурное свойство системы, то она должна уметь подстраиваться под определенные условия эксплуатации. Сегодня хочу поделиться интересным шаблоном, в который очень хорошо вписывается использование AI/ML. 🤖
Контекст
Имеется источник слабоструктурированных событий или событий, в которых допускаются ошибки ввода или частичное нарушение формата. Необходимо организовать потоковую обработку таких событий.
Чтобы лучше понять контекст, можно рассмотреть несколько возможных ситуаций.
✅ Интеграция с внешними системами. Источником событий является сервис, на качество которого мы не можем повлиять. Например, какой-то баг или особенность работы внешней системы, приводящая к нарушению контракта.
✅ Ручной ввод или частичное заполнение. Корректировка пользовательского ввода или необходимость обогащения события данными. Например, уточнить адрес заказа по GPS-координатам пользователя.
✅ Некачественная или шумная телеметрия. Показания выходят за допустимый диапазон, и трудно сказать, что это было: случайный выброс или начало нового тренда из-за недели распродаж. Постанализ может сделать алармы более интеллектуальными.
✅ Первичная отбраковка событий. Основной обработчик производит быструю проверку события на пригодность. Например, грубая/быстрая проверка выявила признаки необходимости блокировки транзакции, и нужна более тщательная проверка.
✅ Устаревшие справочные данные. Внешние системы продолжают присылать события со ссылкой на устаревшие справочные данные. Чтобы не сломать интеграцию, вместо отказа можно делать автоматическое сопоставление и корректировку.
Проблема
Некорректное событие нарушает workflow его обработки или даже останавливает обработку всего потока событий (этого и всех последующих). Последнее характерно для log-based-брокеров.
Решение
Если основной обработчик (Event Consumer) не может обработать очередное событие, оно направляется на детальный анализ и корректировку (Event Collector). Причиной может послужить, например, исключение при чтении данных события (десериализация, приведение к типу, нарушение формата и т.д.), недостаточность данных, нарушение диапазона допустимых значений и т.д. и т.п. в зависимости от прикладного сценария. Анализ и корректировка выполняется асинхронно, а основной обработчик тем временем переходит к следующему событию в очереди.
Корректировщик (Event Collector) может:
⛔️ отбросить событие, как действительно некорректное;
✅ исправить его и направить на повторную обработку;
➡️ отправить на интеллектуальное исправление (AI/ML Corrector).
Предполагается, что корректировщик (Event Corrector) работает на базе аналитического алгоритма, а интеллектуальное исправление (AI/ML Corrector) производится на базе AI/ML как попытка автоматизировать действия человека, например, сотрудников службы поддержки.
Интеллектуальный корректировщик (AI/ML Corrector) может:
⛔️ отбросить событие, как действительно некорректное;
✅ исправить его и направить на повторную обработку;
🧑 призвать на помощь человека.
Шаги аналитической и интеллектуальной корректировки могут взаимодополнять или заменять друг друга. Также допустимо (и даже разумно), если интеллектуальная корректировка будет вызываться асинхронно.
Плюсы
👍 Непрерывная обработка потока событий — некорректные события не блокируют поток.
👍 Возможное увеличение скорости обработки — некорректные события откладываются.
👍 Улучшение адаптируемости системы — подстройка под реалии.
Минусы
👎 Решение никак не учитывает и может нарушить порядок следования событий.
Если это критически важно, то можно предложить, как минимум, два возможных решения.
✅ Сделать событие, содержащее все элементы, порядок обработки которых важен. Иначе говоря, мелкие события группируются в одно крупное (batch event), которое либо целиком обрабатывается, либо целиком отправляется на корректировку.
✅ Сделать корректировку частью конвейера обработки. Однако это уже совершенно другой архитектурный подход.
#tip #arch #ai
Зрелость системы в том числе определяется её прочностью и устойчивостью. Если адаптируемость — важное архитектурное свойство системы, то она должна уметь подстраиваться под определенные условия эксплуатации. Сегодня хочу поделиться интересным шаблоном, в который очень хорошо вписывается использование AI/ML. 🤖
Контекст
Имеется источник слабоструктурированных событий или событий, в которых допускаются ошибки ввода или частичное нарушение формата. Необходимо организовать потоковую обработку таких событий.
Чтобы лучше понять контекст, можно рассмотреть несколько возможных ситуаций.
Проблема
Некорректное событие нарушает workflow его обработки или даже останавливает обработку всего потока событий (этого и всех последующих). Последнее характерно для log-based-брокеров.
Решение
Если основной обработчик (Event Consumer) не может обработать очередное событие, оно направляется на детальный анализ и корректировку (Event Collector). Причиной может послужить, например, исключение при чтении данных события (десериализация, приведение к типу, нарушение формата и т.д.), недостаточность данных, нарушение диапазона допустимых значений и т.д. и т.п. в зависимости от прикладного сценария. Анализ и корректировка выполняется асинхронно, а основной обработчик тем временем переходит к следующему событию в очереди.
Корректировщик (Event Collector) может:
Предполагается, что корректировщик (Event Corrector) работает на базе аналитического алгоритма, а интеллектуальное исправление (AI/ML Corrector) производится на базе AI/ML как попытка автоматизировать действия человека, например, сотрудников службы поддержки.
Интеллектуальный корректировщик (AI/ML Corrector) может:
Шаги аналитической и интеллектуальной корректировки могут взаимодополнять или заменять друг друга. Также допустимо (и даже разумно), если интеллектуальная корректировка будет вызываться асинхронно.
Плюсы
Минусы
Если это критически важно, то можно предложить, как минимум, два возможных решения.
#tip #arch #ai
Please open Telegram to view this post
VIEW IN TELEGRAM
1👍6🔥2
Intention-Revealing Interface
Я думаю, что у каждого было такое при чтении кода. В одном случае всё понятно с первой строчки, метода, класса. В другом случае можно перерыть тонну кода, но уверенности в его понимании не возникает. В первом случае часто говорят, что его писал профи. Так ли это? И как научиться писать понятный код?!
🔻 Сразу сделаю оговорку, что понятный код — дело относительное, ведь чтобы иметь возможность что-то понять, нужно иметь какую-то базу, необходимую для возникновения понимания. В дальнейших рассуждениях будем считать, что у нас есть такая база при знакомстве с проектом и его кодом. Также не будем рассматривать случаи низкоуровневой оптимизации, когда код пишется в угоду производительности, а не читабельности.
Рассматриваемый ниже принцип в каком-то смысле является следствием второго закона архитектуры, и для себя я коротко его формулирую так:
Говоря "код", я в том числе имею в виду и его организацию: структура проекта, наименование каталогов, модулей, файлов, классов, методов, аргументов и переменных.
➡️ Код является отражением каких-то операций предметной области. Если он написан в стиле "как", то он не раскрывает намерения написанного, не проясняет логический смысл производимых операций, создаёт когнитивную перегрузку и, наконец, обесценивает инкапсуляцию. Такой код обычно нуждается в комментариях, без которых очень легко сделать неправильные выводы, допустить ошибки, нарушить авторскую задумку или даже архитектуру. Всё это не оставляет читателю шансов на выстраивание короткой и единственно верной логической цепочки, лежащей в основе реализации, необходимой для запуска критического мышления и осознанного сопровождения.
Код, написанный в стиле "как", напоминает обезьяну, которая таскает кокосы из одной корзины в другую. 🐒 И даже обезьяна не ответит вам на вопрос, почему именно она; почему кокосы, а не бананы; и почему их нужно переносить из корзины в корзину. И чтобы найти ответы, приходится перерыть не только код, но и всё в округе: документацию, историю репозитория и задач, данные в базе, и даже поговорить с людьми, кто в курсе истории проекта.
Перейдем к примерам.
Посмотрите на следующий отвратительно красочный пример-гиперболу. В нём беспощадно использован мощный инструмент — Spring Data JPA Query Methods, который строит SQL-запрос по имени метода.
Что мы вынуждены делать в таких случаях? Провалиться в реализацию метода и начать ментально исполнять код.
🤖 findBy PersonId In (personIds) And DeletedAt Null And Bindings NotNull OrderBy PersonId Asc UpdatedAt Desc
Давайте снимем эту ненужную ментальную нагрузку.
Согласитесь, что стало "легче", но этого недостаточно! Метод по-прежнему отвечает на вопрос "как".
Допустим, нужен не просто список аккаунтов, а список аккаунтов, удовлетворяющий условиям рассылки уведомлений. В итоге, используя имеющийся словарь предметной области проекта (ubiquitous language), принимаем решение назвать метод
Рассмотренный принцип называется Intention-Revealing Interface. Он является шаблоном рефакторинга в DDD и естественен для последователей TDD. Помимо прочего, принцип провоцирует писать тесты, которые проверяют функциональность, а не то, как написан код.
May the Clarity be with you!❤️
#arch #dev
Я думаю, что у каждого было такое при чтении кода. В одном случае всё понятно с первой строчки, метода, класса. В другом случае можно перерыть тонну кода, но уверенности в его понимании не возникает. В первом случае часто говорят, что его писал профи. Так ли это? И как научиться писать понятный код?!
Рассматриваемый ниже принцип в каком-то смысле является следствием второго закона архитектуры, и для себя я коротко его формулирую так:
Код должен отвечать на вопрос что, а не как.
Говоря "код", я в том числе имею в виду и его организацию: структура проекта, наименование каталогов, модулей, файлов, классов, методов, аргументов и переменных.
Код, написанный в стиле "как", напоминает обезьяну, которая таскает кокосы из одной корзины в другую. 🐒 И даже обезьяна не ответит вам на вопрос, почему именно она; почему кокосы, а не бананы; и почему их нужно переносить из корзины в корзину. И чтобы найти ответы, приходится перерыть не только код, но и всё в округе: документацию, историю репозитория и задач, данные в базе, и даже поговорить с людьми, кто в курсе истории проекта.
Давайте такие имена элементам кода — классам, методам и т.п., чтобы они описывали их назначение и результат, но не реализацию.
Перейдем к примерам.
Посмотрите на следующий отвратительно красочный пример-гиперболу. В нём беспощадно использован мощный инструмент — Spring Data JPA Query Methods, который строит SQL-запрос по имени метода.
interface AccountRepository {
List<Account> findByPersonIdInAndDeletedAtNullAndBindingsNotNullOrderByPersonIdAscUpdatedAtDesc(List<UUID> personIds);
}Что мы вынуждены делать в таких случаях? Провалиться в реализацию метода и начать ментально исполнять код.
Давайте снимем эту ненужную ментальную нагрузку.
@Query("""
SELECT a
FROM Account a
WHERE a.personId IN :personIds
AND a.deletedAt IS NULL
AND a.bindings IS NOT NULL
ORDER BY a.personId ASC, a.updatedAt DESC
""")
List<Account> findByPersonId(List<UUID> personIds);Согласитесь, что стало "легче", но этого недостаточно! Метод по-прежнему отвечает на вопрос "как".
Допустим, нужен не просто список аккаунтов, а список аккаунтов, удовлетворяющий условиям рассылки уведомлений. В итоге, используя имеющийся словарь предметной области проекта (ubiquitous language), принимаем решение назвать метод
findDeliverableAccounts. Так мы чётко выражаем намерения и исключаем какие-либо попытки сделать неверные предположения о назначении этого кода.Рассмотренный принцип называется Intention-Revealing Interface. Он является шаблоном рефакторинга в DDD и естественен для последователей TDD. Помимо прочего, принцип провоцирует писать тесты, которые проверяют функциональность, а не то, как написан код.
May the Clarity be with you!
#arch #dev
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥3👍2
Я принёс тебе аналитику
Наши действия или намерения – это проекция нашего сознания. Есть какой-то внешний стимул, есть субъективная интерпретация этого стимула. Стоит ли говорить, что интерпретация может быть неверной?! На подобные мысли меня навел предыдущий пост и недавние события на текущем проекте.
Эта проблема известна всем, кто работает по принципу, когда между пользователем, бизнесом и разработчиком стоит некоторый посредник. Это может быть представитель заказчика, бизнес-аналитик, системный аналитик, архитектор или автор задачи. Вся эта цепочка посредников часто образует "глухой телефон", результат работы которого как цунами обрушивается на непосредственного исполнителя.😮💨
Императив не работает так, как вы хотите! Императив – это ваша субъективная проекция исходной мысли, не более. Не случайно приверженцы гибких методологий очень любят такой инструмент, как User Story, ведь он несет в себе изначальный посыл и предполагает наличие обратной связи. Имея цепочку посредников-аналитиков-архитекторов между пользователем и разработчиком, обязательно включайте в описание сведения о том, для чего это делается, почему это делается, что на самом деле от нас ждут, укажите важные требования и ограничения. И только после этого, если считаете, что это действительно несет ценность, опишите ваш способ решения – как вы предлагаете это сделать. При этом под словом "как" я больше имею в виду что-то близкое к Use Cases или пошаговому формату без перегрузки деталями, которые непременно устареют.
Что это даёт?
Сколько раз мне приносили многостраничные документы, изначальный посыл которых становился понятен только после прочтения последнего предложения; и только после того, как я прочитал это на раза 2-3. Пожалуйста, никогда не делайте так! Пусть в самом начале повествования будет побуждающий мотив, а затем ваша версия решения. Видя цель, читатель вовлекается постепенно, его мыслительный процесс практически сразу запускает "обратную связь", критическое мышление, которое будет работать от первой до последней страницы. В результате он придёт к вам с правильными вопросами и, возможно, укажет на ошибки или недочёты, и их можно будет устранить на ранних этапах.
Свежий пример того, как не нужно делать.
Всей командой разбирались со странным поведением приложения. Если быть конкретным, то приложение должно было отображать дату последнего вызова скорой помощи. Однако после первого вызова скорой эта дата не отображалась. По коду всё выглядело как ошибка разработчика. Тестов, естественно, не было; а в системной аналитике был только императив – пошаговый алгоритм, больше напоминающий псевдокод. К счастью, к концу дня мы смогли найти документ с бизнес-постановкой, в которой скромно затесалась фраза: "Вызов скорой помощи является для пользователя сигнальной информацией, начиная со второго". Эта простая и короткая фраза могла бы сэкономить кучу времени и сил. Трудно было её добавить в постановку задачи или в комментарий к коду, написать тест для этого кейса? Не думаю.
➡️ Если коротко, то предлагаю и настаиваю всегда сохранять исходный контекст, не терять его в цепочке документов, и даже дублировать при необходимости. Использовать преимущественно декларативный, а не императивный стиль изложения.
Только так вы добьётесь эффективности в работе и получите желаемый результат.
#arch #tip
Наши действия или намерения – это проекция нашего сознания. Есть какой-то внешний стимул, есть субъективная интерпретация этого стимула. Стоит ли говорить, что интерпретация может быть неверной?! На подобные мысли меня навел предыдущий пост и недавние события на текущем проекте.
Эта проблема известна всем, кто работает по принципу, когда между пользователем, бизнесом и разработчиком стоит некоторый посредник. Это может быть представитель заказчика, бизнес-аналитик, системный аналитик, архитектор или автор задачи. Вся эта цепочка посредников часто образует "глухой телефон", результат работы которого как цунами обрушивается на непосредственного исполнителя.
Императив не работает так, как вы хотите! Императив – это ваша субъективная проекция исходной мысли, не более. Не случайно приверженцы гибких методологий очень любят такой инструмент, как User Story, ведь он несет в себе изначальный посыл и предполагает наличие обратной связи. Имея цепочку посредников-аналитиков-архитекторов между пользователем и разработчиком, обязательно включайте в описание сведения о том, для чего это делается, почему это делается, что на самом деле от нас ждут, укажите важные требования и ограничения. И только после этого, если считаете, что это действительно несет ценность, опишите ваш способ решения – как вы предлагаете это сделать. При этом под словом "как" я больше имею в виду что-то близкое к Use Cases или пошаговому формату без перегрузки деталями, которые непременно устареют.
Что это даёт?
Сколько раз мне приносили многостраничные документы, изначальный посыл которых становился понятен только после прочтения последнего предложения; и только после того, как я прочитал это на раза 2-3. Пожалуйста, никогда не делайте так! Пусть в самом начале повествования будет побуждающий мотив, а затем ваша версия решения. Видя цель, читатель вовлекается постепенно, его мыслительный процесс практически сразу запускает "обратную связь", критическое мышление, которое будет работать от первой до последней страницы. В результате он придёт к вам с правильными вопросами и, возможно, укажет на ошибки или недочёты, и их можно будет устранить на ранних этапах.
Свежий пример того, как не нужно делать.
Всей командой разбирались со странным поведением приложения. Если быть конкретным, то приложение должно было отображать дату последнего вызова скорой помощи. Однако после первого вызова скорой эта дата не отображалась. По коду всё выглядело как ошибка разработчика. Тестов, естественно, не было; а в системной аналитике был только императив – пошаговый алгоритм, больше напоминающий псевдокод. К счастью, к концу дня мы смогли найти документ с бизнес-постановкой, в которой скромно затесалась фраза: "Вызов скорой помощи является для пользователя сигнальной информацией, начиная со второго". Эта простая и короткая фраза могла бы сэкономить кучу времени и сил. Трудно было её добавить в постановку задачи или в комментарий к коду, написать тест для этого кейса? Не думаю.
Только так вы добьётесь эффективности в работе и получите желаемый результат.
#arch #tip
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🔥2👍1
Словарь предметной области
Мне много раз приходилось знакомиться с новыми для себя проектами. Для ускорения понимания проекта и кода я каждый раз начинал с одного и того же: составлял словарь предметной области. 📔
И это не про графоманию, а про необходимость и реально рабочий инструмент – базис Domain-Driven Design – Ubiquitous Language. Чтобы общаться на иностранном языке, нужно пополнять словарный запас.
Вы можете обратиться к трудам Эрика Эванса, но не найдете там того, как именно должно выглядеть описание языка. Поэтому делюсь своим способом оформления и использования словаря.
Оформление
Формат словаря прост – это таблица из трёх колонок:
1️⃣ Термин – как должно быть.
2️⃣ Синонимы – как на самом деле в коде и моделях.
3️⃣ Определение – очень краткое толкование простым языком.
Термин и синонимы часто просто слова, иногда аббревиатуры или словосочетания. При необходимости в синонимах можно указать перевод.
Например:
🕚 Термин:
🕚 Синонимы:
🕚 Определение:
Использование
Синонимы позволяют увидеть отсутствие терминологической однородности. Это может быть нормально, но чаще является признаком наличия проблем в коде или модели, а именно:
➡️ В коде нет единства именования. Не страшно, но это делает код более хаотичным и менее понятным; провоцирует развитие беспорядка и появление ошибок. Это сродни тому, когда иностранец говорит с акцентом, а абориген его плохо понимает.
➡️ Модель имеет неточность или какое-то упрощение. К сожалению, это распространенная проблема, и синонимы часто скрывают какие-то бизнес-процессы, с которыми вы ещё не столкнулись или не выявили. Подобные ошибки могут обойтись очень дорого, но словарь позволяет заметить эту проблему заранее.
❗️ Словарь не всегда прямолинеен: "термин – синонимы". Бывает, когда разные термины по факту имеют один и тот же синоним. И это уже очень серьёзный сигнал!
Например, в одном из проектов перечисление (enum) объединяло в один список два разных набора, которые использовались в двух разных бизнес-контекстах. Как например, если бы вы объединили в один список месяцы и дни недели. В реальной жизни эти списки используются по отдельности, но в коде они были объединены в один, который интерпретировался в каждой ситуации по-своему. Не трудно догадаться, какие проблемы в коде может породить подобное. Самое безобидное – это увеличение цикломатической сложности из-за обилия проверок и фильтров.
В таких случаях я создаю в словаре столько терминов, сколько требует прикладная область, но в синонимы записываю одно и тоже.
Хранение
Словарь предлагаю хранить в Markdown-файле в корне git-репозитория. И пусть корневой
Не рекомендую использовать внешние wiki вроде Confluence по многим причинам. Во-первых, словарь должен отражать текущее положение дел, следовательно, требует версионирования. Во-вторых, нет необходимости доступа к внешним ресурсам, что удобно как для человека, так и для машины (AI). Хотите словарь в wiki – сделайте его копию, но оригинал пусть будет в репозитории.
Достоинства
1️⃣ Ускорение входа в проект. Это реально так: 30 минут на освоение словаря и вы готовы читать и понимать код и диаграммы, разговаривать на "птичьем" языке с коллегами по цеху. 🐥
2️⃣ Обнаружение неточностей в моделях. Словарь позволяет вскрывать проблемы моделирования и скрытые концепты.
3️⃣ Помощь в унификации именования в коде. В идеале все синонимы должны стать терминами.
4️⃣ Реальное подспорье для онбординга и AI-агентов. Думаю, что это становится крайне важно в современных реалиях.
И пусть ваш код говорит без акцента!❤️
#arch #devops
Мне много раз приходилось знакомиться с новыми для себя проектами. Для ускорения понимания проекта и кода я каждый раз начинал с одного и того же: составлял словарь предметной области. 📔
И это не про графоманию, а про необходимость и реально рабочий инструмент – базис Domain-Driven Design – Ubiquitous Language. Чтобы общаться на иностранном языке, нужно пополнять словарный запас.
Вы можете обратиться к трудам Эрика Эванса, но не найдете там того, как именно должно выглядеть описание языка. Поэтому делюсь своим способом оформления и использования словаря.
Оформление
Формат словаря прост – это таблица из трёх колонок:
Термин и синонимы часто просто слова, иногда аббревиатуры или словосочетания. При необходимости в синонимах можно указать перевод.
Например:
ProblemTask, ЗадачаЗадача по программированиюИспользование
Синонимы позволяют увидеть отсутствие терминологической однородности. Это может быть нормально, но чаще является признаком наличия проблем в коде или модели, а именно:
Например, в одном из проектов перечисление (enum) объединяло в один список два разных набора, которые использовались в двух разных бизнес-контекстах. Как например, если бы вы объединили в один список месяцы и дни недели. В реальной жизни эти списки используются по отдельности, но в коде они были объединены в один, который интерпретировался в каждой ситуации по-своему. Не трудно догадаться, какие проблемы в коде может породить подобное. Самое безобидное – это увеличение цикломатической сложности из-за обилия проверок и фильтров.
В таких случаях я создаю в словаре столько терминов, сколько требует прикладная область, но в синонимы записываю одно и тоже.
Хранение
Словарь предлагаю хранить в Markdown-файле в корне git-репозитория. И пусть корневой
readme.md имеет ссылку на этот файл где-то в самом начале.Не рекомендую использовать внешние wiki вроде Confluence по многим причинам. Во-первых, словарь должен отражать текущее положение дел, следовательно, требует версионирования. Во-вторых, нет необходимости доступа к внешним ресурсам, что удобно как для человека, так и для машины (AI). Хотите словарь в wiki – сделайте его копию, но оригинал пусть будет в репозитории.
Достоинства
🗂 Если у вас еще нет словаря, то у меня для вас отличная новость: хорошую заготовку можно легко и быстро сгенерировать с помощью AI. Например, используя такой промт.
И пусть ваш код говорит без акцента!
#arch #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7👍3🔥3
Consumer-Driven Contracts
Относительно давно интересуюсь темой Consumer-Driven Contracts и тестированием контрактов. В своём текущем проекте начал пробовать использовать Pact (и он уже помог найти несколько багов). И вот недавно мне попалась интересная подборка ссылок на эту тему.
Скажу честно, мне не удалось просмотреть весь найденный материал, но зато я актуализировал ссылки из оригинальной статьи. Результат решил оставить у себя на странице, чтобы никуда не пропало.😏
➡️ Подборка материалов на тему Consumer-Driven Contracts ⬅️
От себя лично добавлю, что для входа в тему лучше почитать соответствующие главы из книги "Microservices Patterns" (Chris Richardson). Недавно вышло 2-е издание, а 1-е есть в русском переводе. Книга хорошо и пошагово разбирает многие нюансы разработки микросервисов, включая тестирование. Особенно полезно, если вы ведёте разработку на Java-стеке.
Более краткий и универсальный вариант изучения – это документация Pact. Pact поддерживает множество языков и, кажется, в своей документации они собрали самую лучшую и актуальную информацию на тему CDC. Кстати, иллюстрация к посту как раз с их сайта.
〰️ 〰️ 〰️
🔥 Также приглашаю вас 17-18 апреля принять участие в конференции Merge 2026, которая пройдёт в Казани (Иннополис). Промокод MEZHOV даёт скидку 20%. Также у меня есть 1 бесплатный билет, который я готов отдать тому, кто хочет и может побывать на этой конференции. Если что, то пишите в ЛС или в комментариях к посту. 😉
#tip
Относительно давно интересуюсь темой Consumer-Driven Contracts и тестированием контрактов. В своём текущем проекте начал пробовать использовать Pact (и он уже помог найти несколько багов). И вот недавно мне попалась интересная подборка ссылок на эту тему.
🗂 Consumer-Driven Contracts и инструменты, автоматизирующие этот процесс, хорошо подходят при использовании MSA и в случае, когда в проекте есть важные интеграции, сломать которые было бы кране нежелательно.
Скажу честно, мне не удалось просмотреть весь найденный материал, но зато я актуализировал ссылки из оригинальной статьи. Результат решил оставить у себя на странице, чтобы никуда не пропало.
От себя лично добавлю, что для входа в тему лучше почитать соответствующие главы из книги "Microservices Patterns" (Chris Richardson). Недавно вышло 2-е издание, а 1-е есть в русском переводе. Книга хорошо и пошагово разбирает многие нюансы разработки микросервисов, включая тестирование. Особенно полезно, если вы ведёте разработку на Java-стеке.
Более краткий и универсальный вариант изучения – это документация Pact. Pact поддерживает множество языков и, кажется, в своей документации они собрали самую лучшую и актуальную информацию на тему CDC. Кстати, иллюстрация к посту как раз с их сайта.
#tip
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4❤2
Неожиданный параллелизм при обработке сообщений в Kafka
Есть распространённое заблуждение, что в рамках одной консюмер-группы сообщения одной и той же партиции топика Apache Kafka обрабатываются последовательно, одно за другим. И конкурентный доступ к сообщениям партиции со стороны консюмера невозможен. Спешу вас разуверить, такое возможно, и вот вам моя история.
Рассмотрим последовательность событий:
1️⃣ Партиция
2️⃣
3️⃣
4️⃣ Случилась ребалансировка.
5️⃣ Иных консюмеров нет.
6️⃣ Партиция
7️⃣
8️⃣
➡️ Что тут может пойти не так?
Если консюмер осуществляет обработку событий в отдельном пуле потоков (worker threads pool), то копии считанных сообщений будут находиться в памяти клиентского приложения. Следовательно, в момент, когда консюмер после ребалансировки еще раз считает и начнёт обработку тех же самых сообщений, но в рамках другого потока из пула, возникает коллизия. Как минимум, могут существовать два потока, которые одновременно обрабатывают одни и те же сообщения.
➡️ Может ли такое произойти в вашем проекте?
В целом, может, и вот по какой причине.
С одной стороны, Kafka предлагает достаточно простой и универсальный API для обслуживания сообщений топика. Продюсер пишет сообщения, консюмер их читает, обрабатывает и сдвигает указатель на следующую пачку сообщений. Партиция, действительно назначается одному-единственному консюмеру в группе с гарантией, что только этот консюмер будет её обслуживать.
С другой стороны, Kafka API определяет событийную модель и предполагает, что все клиенты следуют некоторому предопределённому регламенту обработки этих событий. Из основных событий можно выделить назначение и отзыв партиций. То, как именно будут обрабатываться данные события, во многом определяется реализацией используемого Kafka Client или прикладным кодом. И тут начинается самое интересное.
В целом, основная ответственность ложится на прикладной код: будете ли вы обрабатывать момент ребалансировки, чтобы отменить уже запущенную обработку. И тут нужно ответить на два вопроса:
1️⃣ Насколько критично, если сообщение обработается дважды (idempotence)?
2️⃣ Насколько критично, если одни и те же сообщения будут обрабатываться параллельно (concurrency)?
К первому чаще всего многие готовы, а вот ко второму – нет.
К сожалению, в моём текущем проекте не был готов и я, ибо для работы с Kafka пришлось использовать проприетарную библиотеку, в которой не было никакой возможности обрабатывать момент ребалансировки. Конечно, сейчас я к этому готов, но осадочек остался, поскольку в какой-то степени понадеялся на фреймворк.😮💨
Надеюсь, что эта небольшая, но поучительная история, поможет вам обойти стороной подобную проблему.❤️
#dev #tip
Есть распространённое заблуждение, что в рамках одной консюмер-группы сообщения одной и той же партиции топика Apache Kafka обрабатываются последовательно, одно за другим. И конкурентный доступ к сообщениям партиции со стороны консюмера невозможен. Спешу вас разуверить, такое возможно, и вот вам моя история.
Рассмотрим последовательность событий:
MyTopic#0 назначена консюмеру MyConsumer#0.MyConsumer#0 считал из партиции N сообщений.MyConsumer#0 начал обработку сообщений.MyTopic#0 вновь назначена MyConsumer#0.MyConsumer#0 вновь считал из партиции те же сообщения.MyConsumer#0 вновь начал обработку тех же сообщений.Если консюмер осуществляет обработку событий в отдельном пуле потоков (worker threads pool), то копии считанных сообщений будут находиться в памяти клиентского приложения. Следовательно, в момент, когда консюмер после ребалансировки еще раз считает и начнёт обработку тех же самых сообщений, но в рамках другого потока из пула, возникает коллизия. Как минимум, могут существовать два потока, которые одновременно обрабатывают одни и те же сообщения.
В целом, может, и вот по какой причине.
С одной стороны, Kafka предлагает достаточно простой и универсальный API для обслуживания сообщений топика. Продюсер пишет сообщения, консюмер их читает, обрабатывает и сдвигает указатель на следующую пачку сообщений. Партиция, действительно назначается одному-единственному консюмеру в группе с гарантией, что только этот консюмер будет её обслуживать.
С другой стороны, Kafka API определяет событийную модель и предполагает, что все клиенты следуют некоторому предопределённому регламенту обработки этих событий. Из основных событий можно выделить назначение и отзыв партиций. То, как именно будут обрабатываться данные события, во многом определяется реализацией используемого Kafka Client или прикладным кодом. И тут начинается самое интересное.
В целом, основная ответственность ложится на прикладной код: будете ли вы обрабатывать момент ребалансировки, чтобы отменить уже запущенную обработку. И тут нужно ответить на два вопроса:
К первому чаще всего многие готовы, а вот ко второму – нет.
К сожалению, в моём текущем проекте не был готов и я, ибо для работы с Kafka пришлось использовать проприетарную библиотеку, в которой не было никакой возможности обрабатывать момент ребалансировки. Конечно, сейчас я к этому готов, но осадочек остался, поскольку в какой-то степени понадеялся на фреймворк.
Надеюсь, что эта небольшая, но поучительная история, поможет вам обойти стороной подобную проблему.
#dev #tip
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍5❤2
Важность авторского контроля
Каждый раз ловлю себя на мысли, что пока какая-то концепция не укоренится в реализации проекта, она неминуемо требует авторского контроля. И чем сложней решение, тем сильней должен быть контроль, особенно на старте разработки.
Вроде бы очевидные вещи, но раз за разом вижу, что это правило нарушается с завидной регулярностью. Приходишь на новый проект и видишь два-три варианта реализации одного и того же. Начинаешь разбираться, и не находишь концептуальных различий в вариантах. И чаще всего такое случается просто потому, что автор не довел идею до конца, а тот, кто продолжил разработку, не понял изначальной концепции и стал делать всё то же самое, но на свой лад.
Такое бывает, в том числе, когда в команде нет ротации знаний, нет фиксации ADR, и каждый годами сидит на своём "участке". Естественно, что с уходом такого сотрудника, возникший коллапс начинает быстро заполняться чем-то новым и, как правильно, не содержащим принципиальных отличий. В таком случае можно сказать, что подобная ситуация вызвана недостатком знаний, но я считаю, что исходная причина в слабости архитектурных границ и отсутствии вектора развития.
Архитектура в том числе – вектор, направление развития. Если направления нет, то мы будем крутиться на месте, как корабль в полный штиль. В начале пути архитектор задаёт и корректирует этот вектор, поэтому очень важна обратная связь с разработкой, с помощью чего происходит уточнение и усиление направления движения.
К чему все эти рассуждения?
➡️ Во-первых, если вы даёте архитектору задание, а он в ответ выдаёт вам какой-то концепт, то пусть он за него и отвечает, сопровождая разработку до того момента, пока не будет достигнут хотя бы минимальный успех. В противном случае те идеи, те квадратики и стрелочки будут интерпретированы не так, как задумано, и все останутся недовольны.
➡️ Во-вторых, есть вещи, которые достаточно затруднительно передать в одних только диаграммах и ADR. Понимание общей концепции, взгляд со стороны, опыт, позволяющий понять, что началось отклонение от курса, всё это позволяет вовремя среагировать и не допустить ухода от цели.
К сожалению, был свидетелем, когда архитектора приглашали как "художника", а потом обижались, почему по его письменам получился не тот результат, на который рассчитывали. Был свидетелем, когда потеря направления приводила не к решению проблемы, а её перемещению из одного угла в другой. Всё это я связываю только с одним – отсутствием авторского контроля и, как следствие, непонимание направления движения, уход от цели и последующий хаос в действиях.
Почему это особенно важно сейчас?
➡️ С бурным развитием AI человеку – архитектору и разработчику – остаётся всё больше человеческой работы, а именно: следить за порядком и задавать направление развития. Агентская разработка приумножает, а мы определяем, что именно: хаос или порядок. Это во многом объясняет успешное сочетание AI со стратегическими шаблонами DDD.
Теперь, как мне кажется, нам очень важно не только навести порядок и заложить правильный курс, определив концепцию разработки в каком-нибудь
Guide your force and may the order be with you!❤️
#arch #ai
Каждый раз ловлю себя на мысли, что пока какая-то концепция не укоренится в реализации проекта, она неминуемо требует авторского контроля. И чем сложней решение, тем сильней должен быть контроль, особенно на старте разработки.
Вроде бы очевидные вещи, но раз за разом вижу, что это правило нарушается с завидной регулярностью. Приходишь на новый проект и видишь два-три варианта реализации одного и того же. Начинаешь разбираться, и не находишь концептуальных различий в вариантах. И чаще всего такое случается просто потому, что автор не довел идею до конца, а тот, кто продолжил разработку, не понял изначальной концепции и стал делать всё то же самое, но на свой лад.
Такое бывает, в том числе, когда в команде нет ротации знаний, нет фиксации ADR, и каждый годами сидит на своём "участке". Естественно, что с уходом такого сотрудника, возникший коллапс начинает быстро заполняться чем-то новым и, как правильно, не содержащим принципиальных отличий. В таком случае можно сказать, что подобная ситуация вызвана недостатком знаний, но я считаю, что исходная причина в слабости архитектурных границ и отсутствии вектора развития.
Архитектура в том числе – вектор, направление развития. Если направления нет, то мы будем крутиться на месте, как корабль в полный штиль. В начале пути архитектор задаёт и корректирует этот вектор, поэтому очень важна обратная связь с разработкой, с помощью чего происходит уточнение и усиление направления движения.
К чему все эти рассуждения?
К сожалению, был свидетелем, когда архитектора приглашали как "художника", а потом обижались, почему по его письменам получился не тот результат, на который рассчитывали. Был свидетелем, когда потеря направления приводила не к решению проблемы, а её перемещению из одного угла в другой. Всё это я связываю только с одним – отсутствием авторского контроля и, как следствие, непонимание направления движения, уход от цели и последующий хаос в действиях.
Почему это особенно важно сейчас?
Теперь, как мне кажется, нам очень важно не только навести порядок и заложить правильный курс, определив концепцию разработки в каком-нибудь
CLAUDE.md или AGENTS.md, но и, как капитану корабля, неустанно следить за сохранением этого курса. И для каждой новой идеи эта навигация должна осуществляться до тех пор, пока все члены команды не начнут придерживаться общей цели.Guide your force and may the order be with you!
#arch #ai
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥1