Архитектоника в ИТ
280 subscribers
87 photos
6 files
88 links
Канал Александра Межова с заметками про ИТ-архитектуру и разработку.

ЛС @AlexanderMezhov

Сайт - https://amezhov.ru/blog/
Download Telegram
TechLeadConf X 2025

Прошедшие три недели у меня получились очень насыщенными. 🔥 Получился настоящий марафон. 🏃🏻‍♂️‍➡️ Сначала был отпуск в Нижнем Новгороде, затем в Москве, после чего началась стадия итоговой подготовки доклада, состоялся финальный прогон и, наконец, выступление. 🎙 И, конечно, же работа. 😃

Нижний Новгород остался в моём сердце навсегда. ❤️ Невероятно красивый, спокойный и комфортный город. Набережная, виды на Волгу и Оку, зеленые парки, храмы, фонтаны и, конечно, закаты. Если вы не были там, то посетите его при первой возможности.

По прошествии конференции отдельное спасибо хочется сказать программному комитету и организаторам. ❤️ Всё было на высоте, как и всегда. Надеюсь, что участникам и слушателям моего доклада всё также понравилось. 🙈😃

Роль докладчика даёт классную возможность быть и участником конференции, слушать доклады лидеров индустрии. Мне удалось посмотреть несколько докладов очно и в записи. Сделал для себя небольшой конспект самых интересных, на мой взгляд, мыслей, которыми подробней поделюсь чуть позже. Пока отмечу, что много говорилось про необходимость и важность архитектурного контроля (AaC, ADR), про инженерные практики, способы борьбы с техдолгом и legacy. (Полагаю, что растущая популярность последнего напрямую связана с импортозамещением.)

Всем желаю короткой, но очень продуктивной рабочей недели! 🚀

#conf
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥81👍1👏1
Безопасное исполнение ненадёжного кода

Дал слово — держи! 💪 Так я и сделал, оформив тезисы своего доклада в виде статьи на Дзен. 🚀 Да-да, после "марафона" я решил не останавливаться и еще немного прокатиться на волне вдохновения. 🏄🏻‍♂️ Чуть позже обещают выложить видео, а пока желаю приятного чтения всем интересующимся. 😉

#conf #dev #arch #untrusted_code
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Борьба с техническим долгом и Legacy

Если 10-15 лет назад рассказывали, что такое технический долг, почему он возникает и как может повлиять на дальнейшую разработку, то сейчас начали рассказывать, как с ним бороться. Очевидно, за прошедшие годы многие сильно задолжали. 😂

Судите сами, на прошедшей конференции TechLeadConf 2025 около 30% докладов была посвящена борьбе с техническим долгом и замене Legacy. ⚔️⚔️

Каждого волнует вопрос, как именно бороться с техдолгом, как его идентифицировать, оценить критичность, существующие и будущие издержки и риски, разработать план по его устранению, устранить и, наконец, убедиться в том, что проблема действительно ушла. У каждого своя тактика и стратегия, так как многое зависит от масштаба компании и её возможностей, но, к счастью, многие сходятся во мнении. Я бы сказал, что у более крупных компаний методы борьбы с техдолгом более системны и основательны.

Сегодня поделюсь заметками, сделанными во время докладов. Я обобщил и выделил наиболее примечательные и полезные идеи и советы, которые, по моему мнению, заслуживают внимания. В итоге получилось достаточно хорошая памятка, с которой рекомендую ознакомиться. 😉🔽

#conf #arch #dev #tip
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥51👍1
Конкурс авторских каналов

Сегодня ничего технического, но должно быть полезно. 😃

Я решил устроить себе встряску и найти дополнительную мотивации, поэтому подал заявку на конкурс авторских Telegram-каналов. 🙈 Как минимум, обещают дать обратную связь, что для меня очень ценно.

Зачем я вам про это рассказываю? Если вы автор, то приглашаю поучаствовать. 😉 Если вы читатель, то на канале конкурса @tg_contest_main можно будет найти для себя еще больше интересных новых авторов и подписаться на них. С началом конкурса начнётся публикация избранных авторских постов, и вы сможете поддержать своих фаворитов. Ну, и меня тоже. 😜
🔥6👏1
Ускорение интеграционных тестов

Недавно я узнал об инструменте Zonky, который на одном из проектов позволил ускорить выполнение интеграционных тестов в среднем в 3.5-4 раза. 🚀 Делать практически ничего не пришлось: подключил зависимость и добавил аннотацию.

Об инструменте

Если вы испытываете проблемы с долгим выполнением интеграционных тестов, пишете на Java/Kotlin, используете Spring (не обязательно) и Testcontainers, то сможете за пару часов повторить мой опыт и проверить эффективность использования Zonky в своём проекте.

🗂 У меня есть страсть — узнавать происхождение необычных слов. Оказалось, что зонки — искусственно созданные виды непарнокопытных. Гибрид зебры и осла, выведенный в XIX веке. На вид они мультяшно-миловидные, но свободолюбивые и упрямые. Впрочем, это уже совсем другая история. 😃


Перед запуском интеграционных тестов Zonky создаёт и настраивает указанную embedded-базу данных и регистрирует её в качестве источника. Заявлена поддержка PostgreSQL, MSSQL, MySQL, MariaDB, H2, HSQLDB и Derby. Библиотека интегрирована со Spring, генераторами схемы данных Liquibase и Flyway, может работать без Docker (проверено для PostgreSQL). В основе реализации два ключевых момента: использование embedded-базы данных и оптимизация процессов её инициализации и восстановления. Для базового использования достаточно пометить тестовый класс аннотацией @AutoConfigureEmbeddedDatabase(provider = ZONKY).

О тестировании

Долгое прохождение тестов — явный признак нарушения пирамиды тестирования. 😏 Проект, где я ускорил тесты, имеет очень мало модульных и очень много интеграционных тестов. Это и стало причиной получения столь значительного эффекта.

Если с пирамидой тестирования всё нормально, то инструменты, подобные Zonky, скорей всего, не принесут желаемого ускорения. В этом случае лучше продолжать использовать популярный и проверенный временем Testcontainers. Если же тяжёлых интеграционных тестов с участием баз данных очень много, то Zonky поможет сэкономить время. Однако последнее я бы воспринимал как инвестицию: сэкономленное время лучше потратить на наведение порядка и выравнивание пирамиды тестирования. 😉

#dev #db #tip
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥511
📌 Подборка постов

Для удобства навигации по каналу собрал подборку постов. 🚀

Потоки данных
🟡Ускорение потоков данных
🟡Log-based- и Queue-based-брокеры сообщений
🟡Фэйл с RabbitMQ и Kubernetes API
🟡Гарантированная отправка сообщений

Базы данных
🟡Что не так с PostgreSQL
🟡ACID, AID или AD
🟡Calvin Protocol для распределенных транзакций
🟡Проблемы изоляции транзакций
🟡Конкурентный доступ к данным
🟡Слабая или сильная изоляция транзакций
🟡Распределенные SQL-базы
🟡Выбор UUID для первичного ключа таблицы
🟡Lamport Timestamp: генерация целочисленного идентификатора в распределённой БД без ACID-транзакций
🟡Snowflake ID: генерация целочисленного идентификатора в распределённой системе
🟡Интеграция и внешние идентификаторы
🟡Моделирование данных / Структуризация
🟡Моделирование данных / Переиспользование
🟡Моделирование данных / Производительность
🟡Решардирование данных через промежуточный топик
🟡Вспомогательная таблица для ускорения выборки
🟡Меры предосторожности при работе с РСУБД

Архитектура и разработка
🟡Надёжность, прочность, устойчивость
🟡Принцип прочности
🟡Структура, высеченная в камне
🟡Чего не написано - того нет
🟡Способы борьбы с Legacy-кодом
🟡Борьба с техническим долгом и Legacy
🟡Неизбежность эволюции программных систем
🟡Безопасное исполнение ненадёжного кода
🟡Как еще определять границы микросервисов
🟡Оптимистичная архитектура
🟡Доступность
🟡Волшебная кнопка
🟡Второй закон архитектуры
🟡Базовые элементы архитектурного фреймворка
🟡Декомпозиция в стиле квантовой архитектуры
🟡Порочные связи между компонентами
🟡9 архитектурных заблуждений о распределённых системах
🟡Первичный анализ задачи поиска медицинских документов
🟡Плохо знаешь данные - рискуешь здоровьем
🟡Архитектура лечит причину
🟡Domain Vision Statement

Системное программирование
🟡Борьба с зомби-процессами
🟡Устранение уязвимостей в коде
🟡Throttling == бесполезная трата CPU
🟡OOM/Killer к нам приходит

Алгоритмы и шаблоны
🟡Удаление конфиденциальных данных
🟡Миграция данных и HLL

Безопасность
🟡DevSecOps & Shift-Left
🟡DevSecOps - build phase
🟡Контракт между приложением и окружением

📱 Мои статьи и лонгриды доступны на тут ⬅️

#pin
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍3
Архитектоника в ИТ pinned «📌 Подборка постов Для удобства навигации по каналу собрал подборку постов. 🚀 Потоки данных 🟡Ускорение потоков данных 🟡Log-based- и Queue-based-брокеры сообщений 🟡Фэйл с RabbitMQ и Kubernetes API 🟡Гарантированная отправка сообщений Базы данных 🟡Что не так…»
Голосование за канал

Я уже говорил, что участвую в конкурсе авторских каналов. В минувшее воскресенье закончился приём заявок и началось голосование. 🏆

Прежде всего, предлагаю пройтись по списку номинаций и выбрать для себя что-то интересненькое. 😉 Если после этого у вас останутся силы, проголосуйте за своих фаворитов, они этого ждут. 😃 Однако есть нюанс: чтобы исключить вероятность накрутки, голосовать могут только подписчики @tg_contest_main. 🙈

Если что, мой канал находится в номинации "Разработка и управление командой" — список каналов и форма для голосования тут. 😏

Помимо этого, участники нашей номинации сформировали подборку каналов и оформили её в виде Telegram-папки. Открывайте, смотрите, выбирайте, что по душе. 🚀
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6
Стала доступна 📱 видеозапись моего доклада "Безопасное исполнение ненадежного кода" с TechLead Conf X 2025. Также напомню, что ранее я выкладывал текстовый вариант и презентацию. 😉

📱 YouTube
📱 VK Video

Для тех, кто не в курсе истории появления и развития содержательной части доклада, можно воспользоваться хэш-кодом #untrusted_code. Всё началось с обещания рассказать, как справляться с потенциально вредоносным кодом. Чтобы не делать доклад слишком прикладным и скучным, привязанным к какому-то конкретному домену, я обобщил подход и выделил ключевые, повторно используемые приёмы.

🗂О чём доклад? Даю определение ненадёжного кода и рассматриваю различные способы его исполнения. Рассказываю про уровни изоляции кода, методы ограничения ресурсов процесса операционной системы, проблемы жёсткого лимитирования и техники их устранения. Сравниваю два архитектурных подхода управления песочницами. Затрагиваю вопросы использования инструментов контейнеризации.


〰️〰️〰️
Я рад, что в канале стало больше людей. Ваше внимание вдохновляет меня. Спасибо! ❤️

#conf #untrusted_code
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍2
Как еще определять границы микросервисов

Прочитал статью "Microservices antipatterns and pitfalls" (Mark Richards). Особенно интересными показались дополнительные способы проверки границ микросервисов. Если вы собираетесь переходить или уже перешли на микросервисную архитектуру, то вам должно понравиться. ⬇️⬇️⬇️

1️⃣Объем функциональности сервиса

В чём заключается функциональность сервиса? Письменный или устный ответ на этот вопрос — отличный способ понять, перегружен ли сервис. Чем чаще в описании встречаются соединительные союзы "и", "а также", тем выше вероятность, что сервис имеет слишком много обязанностей.

Этот способ оценки мне напоминает школьные задачи по логике, которые формулируются в стиле "найди лишний элемент в последовательности". И, действительно, это очень хорошее и эффективное упражнение, которым я часто пользуюсь. Выписываешь операции какого-либо сервиса и смотришь, что выбивается из общего ряда.

При этом важно принимать во внимание то, насколько прочны логические связи между перечисленными функциями сервиса, насколько они логически согласованы и сочетаются друг с другом. Если изъянов нет, то процесс декомпозиции выполнен успешно и нет причин для беспокойства. (По этой теме рекомендую обратить внимание на "Принцип каскадного снижения связанности", сформулированный Русланом Сафиным.)

Без преувеличения, это достаточно мощный аналитический приём 💪, который следует использовать крайне хладнокровно, принимая во внимание и другие факторы. Пожалуй, более разумно начинать с грубой декомпозиции и крупных сервисов, а к деталям переходить позже, по мере улучшения понимания предметной области и знаний о работе системы.

2️⃣Необходимость распределенных транзакций

Все ли операции сервиса умещаются в единую ACID-транзакцию? Если нет, то это повод задуматься, ведь иначе придётся самостоятельно обеспечивать согласованность и изоляцию данных, а это серьёзно усложняет решение. Распределённые транзакции, workflow-оркестраторы, саги, inbox/outbox-шаблоны, eventual consistency, идемпотентность и т.п. Действительно ли получаемые выгоды стоят того?

Или стоит более пристально взглянуть на существующие потоки данных и выявить изъяны? 🤨 Возможно, те данные, которые находятся в стороннем сервисе, должны находиться в нашем. Возможно, стороннему сервису достаточно иметь реплику какой-то части данных нашего сервиса. Конечно, тут могут быть разные варианты, но это отличный способ посмотреть на существующее решение под другим углом.

Тут стоит внести важное дополнение. Часто наличие ACID является сдерживающим фактором декомпозиции сервиса, даже в те моменты, когда она действительно нужна. В итоге получаются распределённые монолиты, которые лишаются преимуществ и ACID-транзакций, и микросервисов.


3️⃣Степень общительности сервисов

Насколько много внешних сервисов задействованы при выполнении операций целевого? Это в какой-то степени допустимо для API-шлюзов и workflow-оркестраторов, но в иных случаях это "черная метка". Каждое обращение к внешнему сервису снижает пропускную способность и надёжность.

Наличие подобной ситуации — признак неправильной декомпозиции и/или чрезмерной детализации. 🙅‍♂️ Возможные и не исключающие друг друга варианты решения — укрупнение сервисов путём их объединения и пересмотр их границ (bounded context). Улучшить, но не исправить ситуацию, может замена синхронного взаимодействия на асинхронное.

4️⃣Соответствие целям бизнеса

Для чего делается сервис? Какую проблему бизнеса он решает? Ответы на эти вопросы могут существенным образом повлиять на итоговое решение. 👔 Например, если в основе требований бизнеса — уменьшение TTM (Time-To-Market), то будет стремление к множеству мелких сервисов; если повышение надёжности, то будет стремление к укрупнению сервисов.

Марк Ричардс рекомендует перед началом каждого обсуждения выписывать основные цели бизнеса, чтобы они всегда находились в поле зрения. Таким образом, любая идея, предложение или инструмент всегда будут проходить верификацию на соответствие целям.

〰️〰️〰️
А что для вас является маркерами, когда дело доходит до декомпозиции сервисов? 💬
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍31
Snowflake ID: генерация целочисленного идентификатора в распределённой системе

Доказано, что каждая снежинка имеет уникальную структуру. Разработчики Twitter вдохновились этим феноменом и изобрели Snowflake ID — целочисленный глобально-уникальный идентификатор. ❄️😃

Контекст и проблема

Проблематика хорошо описана в моём предыдущем посте про Lamport Timestamp, поэтому здесь сразу перейдём к основной части.

Решение

Структура 64-битного идентификатора (от старшего бита к младшему):

🔵Sign (1 бит). Знаковый бит.

🔵Timestamp (41 бит). Количество миллисекунд от какой-либо даты. Такой размерности хватит на 69 лет. Например, если за начало отсчета взять Unit Time Epoch, генерация без переполнения будет до 2039 года. Однако правую границу можно сместить, сместив вправо точку отсчета времени.

🔵Datacenter ID (5 бит). Идентификатор ЦОД (до 32 ЦОД).

🔵Machine ID (5 бит). Идентификатор узла в каждом ЦОД (до 32 машин).

🔵Machine Sequence Number (12 бит). Счётчик генераций, который сбрасывается каждую миллисекунду (4096000 генераций в секунду на каждом узле).

В зависимости от потребностей размерность полей может варьироваться. Например, если требуется более длительное хранение данных (более 69 лет), можно увеличить размерность поля Timestamp. Изменение на 1 бит изменяет диапазон в 2 раза (42 бита — 139 лет, 43 бита — 278 лет и т.д.; аналогично в обратную сторону). Изменить размерность полей можно за счет размерности счётчика генераций. Если в системе генерации редкие (и нет значительных всплесков), то 12 разрядов слишком много.

📱 Для закрепления материала приготовил рабочий пример на Java. Он очень простой, его можно портировать на любой другой язык. Забирайте, улучшайте, делитесь опытом и впечатлениями. 😉

Плюсы

Скорость генерации.
Автономность генерации.
Растущая по времени последовательность.
Компактный глобально-уникальный идентификатор (в 2 раза меньше UUID).

Помимо прочего, всё это создаёт благоприятные условия для использования Snowflake ID в качестве ключа для B-Tree. Напомню, ранее я делал исследование на тему выбора оптимального ключа для B-Tree. Поведение Snowflake ID будет идентично целочисленному идентификатору.

Минусы

Ошибки или задержки генерации при прыжках времени назад. Неявно предполагается, что часы на рабочем узле всегда двигаются только вперед. Мы все знаем, что это не всегда так. Во-первых, так называемый Clock Drift характерен для любых часов. Часы работают с непостоянной частотой, которая в том числе зависит от нагрузки на систему. Во-вторых, Multi-Core/Multi-Socket серверы могут иметь отдельный таймер на каждое ядро, и они не обязательно синхронизированы друг с другом (см. Time on Multi-Core, Multi-Socket Servers). Вполне возможны случаи, когда последовательные обращения к Monotonic Clock (например, с помощью System.nanotime()) будут приводить к прыжкам во времени из-за того, что код выполнялся на разных ядрах. В общем случае на уровне прикладного кода выходом может служить механизм привязки к процессору (Process Affinity). Наконец, часы типа Time-of-Day благодаря NTP регулярно совершают прыжки во времени.

Генерируемое множество не является множеством натуральных чисел. Иначе говоря, отсчет начинается не с 0 и далее по порядку, а с гораздо большего числа, которое обязано должно быть 64-разрядным.

Возможны коллизии. Если два одновременно работающих узла будут иметь одинаковые Datacenter ID и Machine ID. Такое возможно, если один узел постепенно выводится из работы и заменяется своим "клоном".

Раскрытие особенностей. Из идентификатора можно получить представление об инфраструктуре (количество ЦОД и узлов).

〰️〰️〰️
Перечисленные недостатки вполне решаемы или терпимы. Например, в своей реализации я обрабатываю прыжки времени. Понравился ли вам алгоритм? 😉

#tip #db
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥5👍4👏1
Интеграция и внешние идентификаторы

Необходимость интеграции с внешней системой — для многих это уже рутина, будни распределённых систем. Мы интегрируем сервисы/микросервисы, разные домены, встраиваем чужие решения в свои или наоборот. Однако что может пойти не так в давно работающей интеграции? 😏

Сначала сформулирую капитанские тезисы, а потом перейду к истории из реальной практики.

☑️ Контролируйте характер и размерность импортируемых данных.

☑️ Храните внешние идентификаторы с использованием универсальных типов данных.

〰️〰️〰️

Имеется давно работающая интеграция между двумя системами. Первая — внешняя — отвечает за идентификацию человека по его персональной информации и присваивает ему уникальный идентификатор (назовём его PersonID). Вторая — наша — отвечает за хранение документов этого человека. Схема данных документа предельно простая: каждый документ хранит PersonID и некоторый набор атрибутов.

В публичном API тип данных PersonID определён как long — 64-разрядное целое число. Выбранной размерности более чем достаточно, поскольку предполагается хранение данных не более чем для 100 миллионов человек. Всё работает прекрасно уже 15 лет, однако на этапе импортозамещения БД документов вскрылся один критический недостаток.

Во-первых, было обнаружено, что есть документы, у которых значение PersonID значительно превышает заявленные 100 миллионов. Например, максимальное значение на сегодняшний день составляет 9999998756120159. 😳 Во-вторых, данные свидетельствуют о значительных пропусках в диапазонах PersonID, хотя представители внешней системы заверяли, что у них обычный Sequence в PostgreSQL. Наконец, в ходе дальнейшего разговора выяснилось, что во внешней БД PersonID представлен типом данных NUMERIC(20) — целым числом размерностью до 20 десятичных разрядов. Это была вишенка на торте 🍑, т.к. в публичном API сейчас используется long, который позволяет работать с числами до 18 (с "хвостиком") десятичных разрядов. Что это значит для нас? Если такие скачки в генерации продолжатся, значения PersonID очень скоро выйдут за пределы размерности long и наш сервис не сможет сохранять новые документы. Последнее означает полную остановку нашего сервиса на неопределённый срок, что совершенно недопустимо.

Выхода из этой ситуации два:

1️⃣ В своей системе использовать тип данных, который один-в-один соответствует типу данных во внешней системе.

2️⃣ В своей системе использовать универсальный тип данных, а преобразование типов делать только на уровне сетевого взаимодействия.

Учитывая, что внешняя команда не предоставляет ни гарантий размерности для PersonID, ни внятного объяснения причин столь странных значений этого идентификатора, было принято решение пойти по второму пути, отвязав свою систему от особенностей мироустройства внешней. В итоге в новой импортозамещенной БД документов для хранения PersonID стали использовать строковый тип данных (text).

〰️〰️〰️
В этой истории мы приблизились к (эпик)фэйлу, но не допустили его и приготовились к негативному сценарию. 😃 Не стесняйтесь, делитесь своими фэйлами в комментариях. 😉⬇️

#arch #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥4🤝1
DevSecOps & Shift-Left

Да, вы верно поняли, меня всё никак не отпускает тема безопасности 😃, поэтому я продолжаю расширять горизонты сознания, чем и хочу поделиться в ближайших постах. Возможно, кому-то эта тема не нова, но тем и лучше, ведь я искренне надеюсь на открытую дискуссию. 😉

В чём, собственно, интерес. Во-первых, я думаю, что основные открытия и изменения нас ждут в междисциплинарных областях. Одни знают, но не могут; другие могут, но не знают. Очевидно, что с этой проблемой активно помогает справляться AI. Во-вторых, разработчики в основном сконцентрированы на архитектуре и функциональности. По данным Positive Technologies 82% уязвимостей обусловлено ошибками в коде. Да, исследование не очень свежее, но я не думаю, что соотношение концептуально поменялось. Иначе говоря, разработчики обычно и не задумываются о том, что их чистый код может быть уязвим, и, как правило, даже не знакомы с инструментами проверки кода на безопасность. В общем, я решил заполнить этот пробел и подготовить несколько постов на тему "DevSecOps глазами разработчика". Надеюсь, что будет интересно и познавательно, а также создаст предпосылки для обсуждения. 😏

〰️〰️〰️

Мало нам всяких XXXOps, появился еще и DevSecOps. 🙈 Суть заключается во встраивании автопроверок безопасности в цикл разработки с целью нахождения уязвимостей на самых ранних этапах. В контексте этого направления существует концепция Shift-Left — сдвиг проверок в левую часть цикла, то есть ближе к его началу. Это позволяет не допустить ошибки или значительно удешевить стоимость их исправления. 📈

Обратите внимание, что техника Shift-Left стала популярной не только в сфере ИБ. Если посмотреть недавние доклады на тему архитектурного контроля, то можно заметить тот же "сдвиг влево". Многие компании добавляют стадию согласования технического решения до момента его реализации, а некоторые автоматизируют этот процесс. На эту тему рекомендую посмотреть доклад про TDR от Павла Лакосникова (Авито). Аналогичные истории я слышал на прошедшем TechLeadConf.


Таким образом, DevSecOps-конвейер расширяет привычный нам CI/CD и состоит из нижеследующих этапов. Можно считать их "точками расширения", в которые можно встроить инструменты проверки на ИБ.

Pre-commit — проверка кода до того, как он будет за-commit-чен (pre-commit hook). Как правило, производится сканирование кода на наличие незашифрованной конфиденциальной информации: пароли, токены, API-ключи и т.п. Типы инструментов: Secret Detection.

Pre-build — проверка кода после того, как он был за-push-ен. Производится статический анализ исходного кода и его зависимостей на наличие распространённых уязвимостей (см. OWASP Top Ten) и лицензионной совместимости. Типы инструментов: Secret Detection, SAST, SCA.

Post-build — проверка артефакта, собранного из исходного кода, например, JAR-архива, NuGet-пакета или Docker-образа. Производится анализ окружения и зависимостей приложения, отыскиваются устаревшие версии пакетов и библиотек. Типы инструментов: Binary SCA.

Test-time — проверка приложения, которое запущено с целью тестирования из собранного артефакта. Производится попытка "сломать" приложение, имитируя действия злоумышленников, или обнаружить проблемы в runtime. Типы инструментов: DAST, OAST, IAST.

🚀 Post-deploy — обеспечение безопасности приложения после развёртывания в production-среде. Совокупность мер и средств, которые осуществляют мониторинг, анализ, обнаружение и блокировку подозрительной активности. Типы инструментов: RASP, Sandboxing, Self-sandboxing.

〰️〰️〰️

Предлагаю сильно не переживать на счёт неизвестных аббревиатур, т.к. в последующих постах я расскажу, что это такое и почему это не так страшно. 👔 А пока предлагаю посмотреть на OWASP Cheat Sheet Series — серию практичных рекомендаций, как можно улучшить безопасность своего кода (слева в навигаторе можно выбрать язык или технологию).

Делитесь историями про свою первую встречу с ИБ. 😃⬇️

#security #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🔥21
DevSecOps - build phase

Первая фаза DevSecOps-конвейера относится к сборке. Сегодня предлагаю рассмотреть возможные проверки и инструменты этой фазы. Преимущество буду отдавать популярным open-source-решениям. ⬇️

Все проверки этой фазы выполняются методом белого/серого ящика — анализируется код, файлы проекта или метаданные артефактов сборки.


Pre-commit

На этапе Pre-commit можно настроить Secret Detection. Вызов сканера интегрируется в Git через pre-commit hook. Преимущества понятны, а вот к недостаткам следует отнести необходимость локальной установки и настройки, поддержка идентичности которой отдельная и крайне неприятная задача. Между тем, многие настройки можно положить в Git.

Управление секретами — прежде всего определённый уровень инженерной культуры проекта. Иначе говоря, сначала нужно договориться о способе работы с секретами, а потом вводить инструменты контроля. 👔


Инструменты:

🕚Trivy — универсальный сканер для обнаружения проблем с безопасностью. Производит анализ пакетов в SBOM, находит известные уязвимости (CVE), некорректные настройки в IaC, конфиденциальную информацию и секреты, проблемы с лицензированием. Имеет подробную документацию и интеграцию с множеством инструментов.

🕚gitleaks — сканер для детектирования секретов в Git-репозитории, файловой системе и stdin. Позволяет гибко настраивать правила проверки.

Pre-build

На этом уровне можно настроить следующие проверки:

Secret Detection — обнаружение секретов, но уже после того, как изменения отправлены в центральный репозиторий. Инструменты: GitLab Secret Detection 🆓; Trivy; gitleaks.

Static Application Security Testing (SAST) — анализ исходного кода на наличие распространённых уязвимостей. Отчёт включает список уязвимостей со ссылкой на конкретные фрагменты кода. 🎯 Статический анализ не запускает проверяемый код, следовательно, провоцирует множество ложно-положительных срабатываний и пропускает некоторые виды уязвимостей. Инструменты: GitLab SAST 🆓, GitFlic SAST; PVS-Studio SAST; SonarQube.

Software Composition Analysis (SCA) — обнаружение уязвимостей в используемых зависимостях с открытым исходным кодом, анализ лицензионной совместимости и возможные риски нарушения лицензионных прав. Инструменты: Trivy; PVS-Studio SCA; GitLab Dependency Scanning; GitFlic SCA.

Как мне кажется, несмотря на все недостатки, по соотношению прилагаемых усилий и получаемого эффекта статический анализ остаётся самым простым и рабочим инструментом. Обратите внимание, что часть проверок доступна из коробки CI/CD, следовательно, подключить эти проверки будет проще. Некоторые инструменты могут быть интегрированы в IDE (Trivy, PVS-Studio).


📱 Для SCA требуется сформировать файл SBOM (метаописание проектных зависимостей). Они бывают разных форматов, поэтому выбирать нужно тот, который совместим с используемым SCA. В Java файл SBOM проще всего формировать на этапе сборки. Например, для генерации SBOM в формате CycloneDX используйте официальный Gradle-плагин.

Post-build

На этом уровне выполняется Binary SCA — обнаружение уязвимостей в бинарных артефактах, полученных после сборки. Проверяться может как содержимое файлов, так и их хэш-сумма. В последнем случае по хэш-сумме находят сведения о файле в открытых базах уязвимостей. Инструменты: GitLab Container Scanning 🆓; Trivy; grype; clair.

〰️〰️〰️

Был ли у вас позитивный опыт использования статических сканеров? 😉 Я тут вспомнил одну историю... ⬇️

#security #devops
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1
Моделирование данных / Структуризация

На что в первую очередь следует обратить внимание, проектируя модель данных? 😏 Вопрос провокационный и не имеет единственно верного ответа. Между тем, предлагаю рассмотреть такие свойства, как структура, переиспользование и производительность.

Моделирование данных должно начинаться с выстраивания общей системы. К счастью, это интуитивное правило, ведь человеческий мозг любит всё упорядочивать. Сталкиваясь с неизвестным, с новой предметной областью, проектом, задачей, мы в первую очередь думаем о структуре. Например, адресную информацию мы тут же раскладываем в виде дерева, в узлах которого располагаем страны, регионы, города, улицы и т.д. При описании социальных связей используем граф.

Я уже писал о том, что структура очень важна, она не высечена в камне, и её нужно адаптировать к изменениям. С другой стороны, структура задаёт нужную жёсткость, скелет системы. Именно поэтому глобальные структурные изменения переносятся очень тяжело, их нужно делать своевременно, итеративно, чтобы избежать негативных последствий.

Именно жёсткость позволяет структурированным системам стремиться оставаться структурированными. И чем удачней организация, тем сильней проявляется это свойство.

К примеру, файлы, разложенные по каталогам, естественным образом указывают на местоположение интересующего элемента или место, где нужно создать новый. Каталог с хорошо организованными файлами проще поддерживать, т.к. его содержимое является его же описанием.


Что нужно для хорошей организации:

☑️ Сформировать словарь предметной области. Язык предметной области (ubiquitous language), единство терминологии — это кости скелета системы. Расположите термины и их определения там, где они чаще всего используются. Например, в корне Git-репозитория. На ревью жёстко пресекайте любые вольности с терминологией.

☑️ Сформулировать соглашение об именовании. Единство стиля, единство подхода задаёт узнаваемую форму и устраняет разночтения и недопонимания. Некоторые IDE позволяют сохранять правила именования в Git-репозиторий, чтобы ими пользовалась вся команда. Дополнительно можно создать модульные тесты на проверку структуры.

☑️ Выбрать корректный критерий структуризации. Важность данного требования трудно переоценить, т.к. оно задаёт направление развития, определяет точки роста. Для этого нужны хорошие познания предметной области или, как минимум, проблематики. Согласитесь, что иначе предусмотреть логические слои или очертить ограниченные контексты будет крайне затруднительно. Подобные решения обязательно отражайте в ADR и технической документации.

Не раз сталкивался, когда игнорирование этих правил приводило к фрагментированным, частным решениям, за которыми было невозможно разглядеть что-то общее. Всё это в конечном счёте усложняло и код, и архитектуру. Находишь такой кусок, начинаешь в нём разбираться и видишь, например, что одна и та же функциональность реализована пятью разными способами, имеет пять названий и расположена в пяти местах.


Структура — важная составляющая для функционального роста системы. Именно по этой причине в основе известных подходов моделирования данных лежит определение способа организации данных. Например, Kimball's modeling, Inmon's modeling, Data Vault. Между тем, отсутствие единственно верного подхода подчёркивает, что нет универсальной и всеобъемлющей структуры, которая бы подходила всем. Мы, как архитекторы и разработчики, должны выбрать наиболее подходящий вариант, исходя из условий и ограничений.

〰️〰️〰️

Завтра я раскрою два других аспекта моделирования данных — переиспользование и производительность. А пока по традиции предлагаю делиться собственным опытом. 😉 Насколько у вас сильный болевой порог, когда видите беспорядок или нелогичность в организации? 😃

#view #arch #dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🔥2
Моделирование данных / Переиспользование

Удачная модель данных склонна к повторному использованию. Это позволяет строить новые конструкции на основе существующих. 🚀

Что нужно для переиспользования:

☑️ Смотреть на задачу чуть шире. Это достаточно абстрактная рекомендация, но, думаю, она интуитивно понятна любому инженеру. Нужно постараться представить дальнейший ход событий или попробовать посмотреть на задачу с высоты птичьего полёта: не является ли она частью чего-то более общего или развитием уже существующего.

☑️ Сделать декомпозицию модели. С одной стороны, чем меньше элементы, тем больше шансов, что они могут быть переиспользованы. С другой, высокая гранулярность создаёт риск переиспользования элементов в неподходящих контекстах. Более того, множество элементов добавляет дополнительные уровни в иерархии, что в свою очередь усложняет восприятие и поддержку.

Например, стоит или нет выделять адрес клиента в отдельный элемент (Value Object или Entity)? Или лучше поместить эти данные in-plane в агрегат клиента? Если добавить отдельный элемент, то что делать, когда адрес может быть указан частично? Или когда адрес не может быть изменён, т.к. является частью бизнес-события, допустим, "адрес платежа". Даже в таком простом примере очень много нюансов.


Важно отметить, что повторное использование относится не только к структурным элементам, но и к данным. Например, для работы с часто используемыми и редко меняющимися данными лучше использовать нормализацию. Данные или результаты вычислений, необходимые многим на последующих этапах (downstream), следует выносить на ранние (upstream).

#view #arch #dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🔥1
Моделирование данных / Производительность

Модель данных должна соответствовать характеру ее использования. Любое расхождение с этим приводит к снижению производительности. 📈

Такое часто наблюдается при использовании одной и той же модели для принципиально разных целей. Классический пример: сырые данные (OLTP) используются для построения отчётов (OLAP).

Моделирование не должно быть в отрыве от возможностей используемой базы данных. Иначе это будет то, на что чаще всего похоже использование ORM: швейцарский нож, который может многое, но имеет кучу ограничений — недонож, недоштопор, недоотвертка. (Заранее прошу прощения, если задел чувства верующих. 😃)

Если не определились с базой данных, то нужно определиться с ее типом (реляционная, колоночная, документная, графовая и т.п.). Для баз одного типа характерны общие подходы к моделированию и общие ограничения.

Например, нужно создать журнал аудита, содержащий информацию о событиях изменения документов. Иначе говоря, должна быть возможность получить список всех действий по каждому документу.

В реляционной базе можно создать плоскую таблицу, в которой каждая строка соответствует событию. Очевидно, что в такой таблице будет колонка document_id, по которой будет построен индекс. Индекс позволит быстро получать список событий по каждому документу.

В колоночной базе лучше создать таблицу по типу "ключ-значение", т.к. в таких базах очень слабая поддержка вторичных индексов. В качестве ключа будет выступать document_id, а в качестве значения — список событий документа.


В контексте производительности очень важно не перейти ту черту, когда начинают решать проблемы, с которыми никогда в жизни не столкнутся. Для понимания, где проходит эта черта, нужно глубоко погрузиться в контекст, но обычно неоправданно агрессивную оптимизацию видно сразу. Если текущее решение имеет недостатки и несёт риски, но не завтрашнего дня, а далёкой перспективы, отразите их в ADR.

〰️〰️〰️

Я постарался описать моменты, на которые обращаю внимание в работе. Получается ли у меня всегда всё делать идеально? Нет, конечно. 😃 Есть разные преграды и обстоятельства, приходится идти на вынужденные компромиссы. Однако, главное — видеть цель и идти к ней. 💪

#view #arch #dev #db
Please open Telegram to view this post
VIEW IN TELEGRAM
👍43
Оптимистичная архитектура

Сегодня будет сказ про оптимистичную архитектуру. В нём можно разглядеть себя или своих знакомых. Основано на реальных событиях, но все совпадения случайны! 🎲😃

〰️〰️〰️

Однажды перед разработчиками встала задача — разработать микроядро для хранения документов клиента. Функциональность подразумевала создание CRUD-сервиса и сервиса поиска. Поиск должен был предоставлять возможность находить документы выбранного клиента по произвольному фильтру, который строился на основе атрибутов документа.

Архитекторы решили не ограничивать API поиска, предоставив будущему пользователю абсолютную свободу действий. Сейчас уже и не найдешь истинной причины такого оптимистичного решения. Возможно, используемая реляционная база и ORM натолкнули на такую мысль; возможно, не хотелось в будущем менять контракт взаимодействия. Так или иначе, для существующих и будущих интеграций API поиска позволял указать предикат любой сложности.

Время шло, проект развивался, вокруг него выстроилась целая плеяда систем. В связи с этим база документов выросла до значительных размеров, и с каждым годом этот рост только ускорялся. Поначалу всё шло хорошо. API поиска использовался так, как было задумано: поиск сводился к фильтрации документов выбранного клиента. Однако после пользователи API смекнули, что искать можно как угодно! И понеслось...

"Верни мне документы, которые удовлетворяют <этим> критериям, а из найденного я возьму только один-единственный атрибут"; "Найди все документы <этого> типа за всю историю существования системы, а я возьму только их количество"; "Найди <подобные> документы у всех клиентов" и т.д.


Подобные запросы были редкими, но крайне неприятными. Они провоцировали повышенную загрузку ресурсов и выполнялись крайне медленно. А что делают пользователи в этом случае? Правильно, идут жаловаться на поставщика услуги! И правильно делают, ведь они используют официально предоставленный публичный контракт.

Выяснилось, что подобные запросы — это попытки внешних систем сделать какую-либо аналитику (OLAP) на основе исходных данных (OLTP). Однако микроядро по своей сути задумывалось как OLTP-фасад с функцией фильтрации документов внутри агрегата клиента. Однако благодаря оптимистично-многообещающему API поиска ситуация начала выходить из-под контроля.

Пользователи требовали быстрый поиск, команда микроядра делала его оптимизацию, затаскивая в проект всё новые и новые частные прикладные сценарии...

〰️〰️〰️

Думаю, что история ясна и пора перейти к капитанским советам:

☑️ Не давай обещания, которые не собираешься выполнять. Предоставь ровно ту функциональность, которая требуется. Если нужно заложить точки роста, заложи, но в рамках здравого смысла и понимания перспектив развития. Если кому-то понадобится "больше", то он придёт и заявит об этом явно. Так процесс развития станет прозрачным и понятным каждому участнику интеграции.

☑️ Не соглашайся с навязыванием условий. В тот момент, когда сервис начали использовать не по назначению, поднимай красный флаг. Выясни причины, определи и запланируй возможные шаги для исправления. Иногда данный вопрос может быть решён административно.

☑️ Отделяй общее от частного. Проанализируй запросы, возможно, что часть подсистем нуждается в какой-то общей функциональности, а часть должна быть реализована на местах. Например, некоторым подсистемам нужен один и тот же срез данных, а другие должны самостоятельно организовать специфичные витрины данных.

☑️ Универсальных моделей не бывает. Модель данных должна соответствовать характеру её использования. Мы не можем игнорировать этот аспект, в том числе и на уровне API. Если строим аналитику и отчётность на базе сырых данных, то важно помнить, что это может создать риски в будущем.

⁉️ А вы попадали в похожую долговую яму?

#arch
Please open Telegram to view this post
VIEW IN TELEGRAM
5👍21🔥1