This media is not supported in your browser
VIEW IN TELEGRAM
Этот инструмент экономит время на ручном прописывании API.
Вставляешь JSON — на выходе сразу получаешь TypeScript-код.
→ http://app.quicktype.io
👉 @BackendPortal
Вставляешь JSON — на выходе сразу получаешь TypeScript-код.
→ http://app.quicktype.io
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6🤯3❤2
This media is not supported in your browser
VIEW IN TELEGRAM
Курс по git на русском прямо в браузере
Проходишь шаги от базовых команд до веток и коммитов, всё через практику.
👉 @BackendPortal
Проходишь шаги от базовых команд до веток и коммитов, всё через практику.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5👍2
Акторная модель это, по сути, подход, где между процессами/потоками (или акторами) нет общей памяти.
Разные акторы общаются, передавая сообщения. Каждый актор владеет своим состоянием, обрабатывает по одному сообщению за раз и общается с другими только через асинхронные сообщения. Локов нет.
Rust красиво ложится на это через один только трейт Send в трейте актора.
Send означает, что актора можно безопасно перемещать в другой поток. Sync не нужен, потому что ссылка на актора никогда не шарится между потоками. К актору всегда имеет доступ только один поток, и это убирает гонки данных на этапе компиляции.
👉 @BackendPortal
Разные акторы общаются, передавая сообщения. Каждый актор владеет своим состоянием, обрабатывает по одному сообщению за раз и общается с другими только через асинхронные сообщения. Локов нет.
Rust красиво ложится на это через один только трейт Send в трейте актора.
Send означает, что актора можно безопасно перемещать в другой поток. Sync не нужен, потому что ссылка на актора никогда не шарится между потоками. К актору всегда имеет доступ только один поток, и это убирает гонки данных на этапе компиляции.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
Media is too big
VIEW IN TELEGRAM
Разработчик выложил проект ShadowStream, систему отслеживания изменений в базе данных (CDC), построенную на PostgreSQL logical replication.
Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.
Как это работает:
- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов
Исходники открыты на GitHub
Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов.🙂
👉 @BackendPortal
Цель проекта — ловить любые изменения в реальном времени и передавать их в потоковую инфраструктуру.
Как это работает:
- изменения в базе (INSERT, UPDATE, DELETE) сразу перехватываются через logical replication
- события сериализуются в Protobuf и отправляются в Redis Streams для быстрого доступа
- параллельно те же данные архивируются в Kafka для надежного хранения
- Kafka использует grouped consumer'ов: два обработчика работают параллельно, плюс резервная группа с отдельным offset
- поверх всего в Django Admin добавлена визуализация gRPC-вызовов
Исходники открыты на GitHub
Проект может пригодиться тем, кто работает с потоковой обработкой данных, аналитикой, репликацией или интеграцией микросервисов.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤3🔥3
Представь, ты стримишь изменения из Postgres в Elasticsearch на Go. В деве всё работает стабильно. Потом растёт трафик, и внезапно сервис перестаёт вывозить…
Профилируешь и упираешься в JSON-сериализацию.
Каждый документ, который уходит в Elasticsearch, нужно закодировать. Когда событий тысячи в секунду, эти микросекунды начинают быстро накапливаться. Стандартная encoding/json удобная, но она сильно завязана на рефлексии.
Рефлексия удобна, потому что универсальна, но за неё платишь скоростью. Это почти всегда медленнее, чем когда структура известна на этапе компиляции.
И да, в любом языке почти никогда нет “одной библиотеки на задачу”. Люди постоянно переписывают одно и то же, и нередко делают быстрее, чем дефолт из коробки.
Так что вместо стандартной encoding/json можно взять пакет jsoniter. По бенчмаркам: декодирование среднего payload у стандартной либы занимает 35 510 ns/op и делает 99 аллокаций. У jsoniter это 5 623 ns/op и всего 3 аллокации. То есть больше чем в 6 раз быстрее и на 97% меньше аллокаций.
Дичь.
Это не значит, что надо срочно переписывать код. Но если у тебя JSON-сериализация в топе на пламеграфе :) переход на jsoniter (или на то, что в текущий момент самое эффективное) может дать ощутимый прирост
И такое есть вообще в каждом языке и почти под любую работу. Пусть этот пост будет напоминалкой: иногда стоит смотреть дальше дефолтов :)
Надеюсь, пригодится.👍
👉 @BackendPortal
Профилируешь и упираешься в JSON-сериализацию.
Каждый документ, который уходит в Elasticsearch, нужно закодировать. Когда событий тысячи в секунду, эти микросекунды начинают быстро накапливаться. Стандартная encoding/json удобная, но она сильно завязана на рефлексии.
Рефлексия удобна, потому что универсальна, но за неё платишь скоростью. Это почти всегда медленнее, чем когда структура известна на этапе компиляции.
И да, в любом языке почти никогда нет “одной библиотеки на задачу”. Люди постоянно переписывают одно и то же, и нередко делают быстрее, чем дефолт из коробки.
Так что вместо стандартной encoding/json можно взять пакет jsoniter. По бенчмаркам: декодирование среднего payload у стандартной либы занимает 35 510 ns/op и делает 99 аллокаций. У jsoniter это 5 623 ns/op и всего 3 аллокации. То есть больше чем в 6 раз быстрее и на 97% меньше аллокаций.
Дичь.
Это не значит, что надо срочно переписывать код. Но если у тебя JSON-сериализация в топе на пламеграфе :) переход на jsoniter (или на то, что в текущий момент самое эффективное) может дать ощутимый прирост
И такое есть вообще в каждом языке и почти под любую работу. Пусть этот пост будет напоминалкой: иногда стоит смотреть дальше дефолтов :)
Надеюсь, пригодится.
Please open Telegram to view this post
VIEW IN TELEGRAM
1❤4🔥4😁1
Если ты активно пользуешься JavaScript Intl API, можно выжать немного больше производительности.
Зацени intl-formatter: маленькая обертка, которая добавляет мемоизацию без настроек и при этом сохраняет тот же интерфейс Intl API. В AdonisJS мы такое используем уже много лет.
Бенчмарки: https://github.com/poppinss/intl-formatter?tab=readme-ov-file#benchmarks
👉 @BackendPortal
Зацени intl-formatter: маленькая обертка, которая добавляет мемоизацию без настроек и при этом сохраняет тот же интерфейс Intl API. В AdonisJS мы такое используем уже много лет.
Бенчмарки: https://github.com/poppinss/intl-formatter?tab=readme-ov-file#benchmarks
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
Проверяет наличие электронной почты без отправки письма.
https://github.com/reacherhq/check-if-email-exists/
👉 @BackendPortal
https://github.com/reacherhq/check-if-email-exists/
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2
Поздравляем, вы на 1 шаг ближе к работе мечты 🥳
Осталось только прочитать этот пост, подписаться на канал и откликнуться на вакансию 😉
Avito Career — место, где Авито делится актуальными вакансиями и стажировками для бэкенд-разработчиков.
Подписывайтесь, чтобы найти ту самую работу ✨
Осталось только прочитать этот пост, подписаться на канал и откликнуться на вакансию 😉
Avito Career — место, где Авито делится актуальными вакансиями и стажировками для бэкенд-разработчиков.
Подписывайтесь, чтобы найти ту самую работу ✨
❤3🤔2
Практический Docker Roadmap
Она включает более 50 практических заданий, дополненных десятками визуальных разборов и несколькими теоретическими глубокими погружениями. На данный момент вы можете изучить:
- Как запускать разные типы контейнеров (веб-приложения, CLI-утилиты, базы данных и т.д.)
- Как перечислять, инспектировать и управлять локальными контейнерами
- Как выполнять команды внутри контейнеров и отлаживать простые проблемы
- Как обновлять контейнерные образы для stateless и stateful приложений
- Как собирать контейнерные образы как профи
...и несколько других тем
https://labs.iximiuz.com/roadmaps/docker
👉 @BackendPortal
Она включает более 50 практических заданий, дополненных десятками визуальных разборов и несколькими теоретическими глубокими погружениями. На данный момент вы можете изучить:
- Как запускать разные типы контейнеров (веб-приложения, CLI-утилиты, базы данных и т.д.)
- Как перечислять, инспектировать и управлять локальными контейнерами
- Как выполнять команды внутри контейнеров и отлаживать простые проблемы
- Как обновлять контейнерные образы для stateless и stateful приложений
- Как собирать контейнерные образы как профи
...и несколько других тем
https://labs.iximiuz.com/roadmaps/docker
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2
SELECT FOR UPDATE в Postgres фактически делает записьВ heap-странице Postgres у каждого tuple есть заголовок header с метаданными.
Когда транзакция выполняет SELECT FOR UPDATE, у найденных tuple (по предикату) обновляется header: они помечаются как залоченные, а атрибут xmax фиксирует XID транзакции, которая поставила лок.
Конкретно выставляются два бита в infomask заголовка: HEAP_XMAX_EXCL_LOCK и HEAP_XMAX_LOCK_ONLY.
Из-за этого страница становится dirty и это также попадает в WAL, который потом может уехать на standby-реплику.
Позже dirty-страница может быть сброшена на диск background writer-ом.
На commit эти биты очищаются.
Забавно, что операция чтения может породить приличный объём write I/O.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
❤1
Хорошие новости для пользователей Postgres под конец года. Команда TimescaleDB выпустила и открыла исходники расширения pg_textsearch.
В Postgres уже есть встроенный полнотекстовый поиск, а это расширение делает его более современным и продвинутым за счёт добавления ранжирования BM25.
👉 @BackendPortal
В Postgres уже есть встроенный полнотекстовый поиск, а это расширение делает его более современным и продвинутым за счёт добавления ранжирования BM25.
Please open Telegram to view this post
VIEW IN TELEGRAM
Tiger Data Blog
From ts_rank to BM25. Introducing pg_textsearch: True BM25 Ranking and Hybrid Retrieval Inside Postgres | Tiger Data
pg_textsearch brings BM25 ranking to enable hybrid search to Postgres. Build RAG systems with keyword precision and vector semantics in one database.
Почему JSON жрёт ваш CPU
Ваш API тормозит. Вы грешите на базу. Потом на сеть. А реальным бутылочным горлышком может быть язык, на котором вы общаетесь.
JSON — это не формат данных. Это текстовая строка.
Каждый раз, когда вы отправляете {"id": 12345}, сервер платит скрытый налог на парсинг. Даже с современными SIMD-оптимизированными парсерами текст упирается в архитектурные ограничения, которых нет у бинарных форматов.
Разбор по инженерке:
1. Стоимость для CPU (машина состояний против арифметики)
JSON (текст):
Чтобы прочитать число 12345, CPU получает поток байт. Даже самые быстрые парсеры вроде simdjson вынуждены работать как машина состояний:
- искать структурные разделители (: и ,)
- проверять escape-последовательности ()
- конвертировать число: проход по ASCII-символам, вычитание '0', умножение на степени 10 и суммирование
Всё это — ветвления, промахи предсказателя и обращения к памяти.
-» Protobuf (бинарь):
Передаёт либо Varint (для маленьких чисел), либо фиксированную ширину (для больших).
Fixed-width (например, fixed32) — это просто memcpy. Парсинга нет вообще.
-» Varint — чтение байт по одному с проверкой старшего бита (MSB), продолжается ли число.
Итог: декодирование сводится к нескольким битовым сдвигам и маскам. Для числовых нагрузок это гарантированно быстрее любого текстового парсинга.
2. Стоимость по пропускной способности (энтропия против избыточности)
Ключ "status" передаётся снова и снова.
Контраргумент: но gzip же всё сжимает.
Ответ: gzip уменьшает трафик, но увеличивает нагрузку на CPU. Сервер делает Serialize JSON → Compress → Send. Клиент — Decompress → Parse JSON. Вы тратите CPU на сжатие избыточного текста, которого вообще не должно было быть.
--» Protobuf:
Отделяет схему от данных.
В wire-формате строка "status" заменяется ID поля, например 1: [Tag: 1][Value: "active"]. Размер сообщения меньше ещё до компрессии, а значит экономятся CPU-циклы с обеих сторон.
3. Стоимость надёжности
JSON — это схема-при-чтении.
Получатель получает blob и надеется, что id — это число. В коде появляются проверки вида if typeof(id) !== 'number или подключаются валидаторы вроде Zod или Pydantic, которые добавляют ещё один слой runtime-нагрузки.
Protobuf — это схема при записи.
Контракт enforced на границе сериализации. Он не ловит логические ошибки, но гарантирует сохранность типов. Обычно не нужны тяжёлые runtime-валидаторы, чтобы проверить, что Integer — это Integer.
Можно сказать:
JSON отлично подходит для публичных API — его легко дебажить и читать. Но для высоконагруженных микросервисов JSON — это налог.
Переход на gRPC/Protobuf — не сверхчудо. Это просто перенос сложности из парсинг текста в генерацию кода
👉 @BackendPortal
Ваш API тормозит. Вы грешите на базу. Потом на сеть. А реальным бутылочным горлышком может быть язык, на котором вы общаетесь.
JSON — это не формат данных. Это текстовая строка.
Каждый раз, когда вы отправляете {"id": 12345}, сервер платит скрытый налог на парсинг. Даже с современными SIMD-оптимизированными парсерами текст упирается в архитектурные ограничения, которых нет у бинарных форматов.
Разбор по инженерке:
1. Стоимость для CPU (машина состояний против арифметики)
JSON (текст):
Чтобы прочитать число 12345, CPU получает поток байт. Даже самые быстрые парсеры вроде simdjson вынуждены работать как машина состояний:
- искать структурные разделители (: и ,)
- проверять escape-последовательности ()
- конвертировать число: проход по ASCII-символам, вычитание '0', умножение на степени 10 и суммирование
Всё это — ветвления, промахи предсказателя и обращения к памяти.
-» Protobuf (бинарь):
Передаёт либо Varint (для маленьких чисел), либо фиксированную ширину (для больших).
Fixed-width (например, fixed32) — это просто memcpy. Парсинга нет вообще.
-» Varint — чтение байт по одному с проверкой старшего бита (MSB), продолжается ли число.
Итог: декодирование сводится к нескольким битовым сдвигам и маскам. Для числовых нагрузок это гарантированно быстрее любого текстового парсинга.
2. Стоимость по пропускной способности (энтропия против избыточности)
JSON:
[{"status": "active"}, {"status": "active"}]
Ключ "status" передаётся снова и снова.
Контраргумент: но gzip же всё сжимает.
Ответ: gzip уменьшает трафик, но увеличивает нагрузку на CPU. Сервер делает Serialize JSON → Compress → Send. Клиент — Decompress → Parse JSON. Вы тратите CPU на сжатие избыточного текста, которого вообще не должно было быть.
--» Protobuf:
Отделяет схему от данных.
В wire-формате строка "status" заменяется ID поля, например 1: [Tag: 1][Value: "active"]. Размер сообщения меньше ещё до компрессии, а значит экономятся CPU-циклы с обеих сторон.
3. Стоимость надёжности
JSON — это схема-при-чтении.
Получатель получает blob и надеется, что id — это число. В коде появляются проверки вида if typeof(id) !== 'number или подключаются валидаторы вроде Zod или Pydantic, которые добавляют ещё один слой runtime-нагрузки.
Protobuf — это схема при записи.
Контракт enforced на границе сериализации. Он не ловит логические ошибки, но гарантирует сохранность типов. Обычно не нужны тяжёлые runtime-валидаторы, чтобы проверить, что Integer — это Integer.
Можно сказать:
JSON отлично подходит для публичных API — его легко дебажить и читать. Но для высоконагруженных микросервисов JSON — это налог.
Переход на gRPC/Protobuf — не сверхчудо. Это просто перенос сложности из парсинг текста в генерацию кода
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12
Postgres CTE
-» небольшие, читаемые блоки SQL
-» можно тестировать запрос по частям
-» переиспользовать фрагменты SQL в других запросах
👉 @BackendPortal
-» небольшие, читаемые блоки SQL
-» можно тестировать запрос по частям
-» переиспользовать фрагменты SQL в других запросах
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
В небольшом приложении один HTTP-запрос обычно делает всё.
Например, пользователь регистрируется.
Бэкенд сохраняет пользователя, отправляет welcome-письмо, пишет метрики и только потом отвечает. Работает, но пользователь ждёт дольше, а если что-то ломается посередине, может упасть вся операция.
Проблема в том, что в одном потоке смешиваются критичные и второстепенные задачи.
Создать пользователя -» критично. Отправить welcome-письмо -» нет. Когда всё идёт в одном флоу, у всего одинаковый вес, и приложение начинает тормозить.
В более крупных системах это решают через Message Queue.
Бэкенд выступает как producer -» сохраняет пользователя и кладёт сообщение в очередь с отложенной задачей, например «отправить welcome-email». На этом запрос заканчивается и быстро отдаёт ответ.
Позже один или несколько воркеров забирают сообщение из очереди и выполняют задачу. Если отправка письма упала, её можно ретраить, не затрагивая пользователя.
Так создание пользователя и отправка письма перестают зависеть друг от друга.
Обратная сторона -» в системе появляется больше компонентов и растёт сложность.
👉 @BackendPortal
Например, пользователь регистрируется.
Бэкенд сохраняет пользователя, отправляет welcome-письмо, пишет метрики и только потом отвечает. Работает, но пользователь ждёт дольше, а если что-то ломается посередине, может упасть вся операция.
Проблема в том, что в одном потоке смешиваются критичные и второстепенные задачи.
Создать пользователя -» критично. Отправить welcome-письмо -» нет. Когда всё идёт в одном флоу, у всего одинаковый вес, и приложение начинает тормозить.
В более крупных системах это решают через Message Queue.
Бэкенд выступает как producer -» сохраняет пользователя и кладёт сообщение в очередь с отложенной задачей, например «отправить welcome-email». На этом запрос заканчивается и быстро отдаёт ответ.
Позже один или несколько воркеров забирают сообщение из очереди и выполняют задачу. Если отправка письма упала, её можно ретраить, не затрагивая пользователя.
Так создание пользователя и отправка письма перестают зависеть друг от друга.
Обратная сторона -» в системе появляется больше компонентов и растёт сложность.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5
Обобщённые инвертированные индексы (GIN) - мощный инструмент в Postgres.
Они хороши тем, что переворачивают привычную модель индексации.
Вместо логики вида: строка с ID 2 содержит значение "become a database expert", индекс хранит обратное соответствие: токен "database" указывает на строки с ID 1, 2 и 3, а "expert" — на строку с ID 2.
GIN-индексу на вход подаётся набор значений для каждой строки, которую нужно проиндексировать. Каждое уникальное значение становится ключом в индексе и сопоставляется с набором CTID (идентификаторов кортежей строк), в которых это значение встречается.
У такого подхода есть несколько сценариев применения, и один из самых популярных - полнотекстовый поиск. В MySQL для этого есть отдельный тип индекса FULLTEXT, а в Postgres похожая функциональность строится на более универсальных GIN-индексах.
Как это выглядит на практике:
(a) Добавляем колонку tsvector в таблицу:
(b) Заполняем её лексемами (нормализованными словами):
(c) Создаём GIN-индекс по лексемам:
(d) И выполняем запросы:
В итоге получаем быстрый и гибкий полнотекстовый поиск прямо внутри Postgres, без отдельных движков и костылей.
👉 @BackendPortal
Они хороши тем, что переворачивают привычную модель индексации.
Вместо логики вида: строка с ID 2 содержит значение "become a database expert", индекс хранит обратное соответствие: токен "database" указывает на строки с ID 1, 2 и 3, а "expert" — на строку с ID 2.
GIN-индексу на вход подаётся набор значений для каждой строки, которую нужно проиндексировать. Каждое уникальное значение становится ключом в индексе и сопоставляется с набором CTID (идентификаторов кортежей строк), в которых это значение встречается.
У такого подхода есть несколько сценариев применения, и один из самых популярных - полнотекстовый поиск. В MySQL для этого есть отдельный тип индекса FULLTEXT, а в Postgres похожая функциональность строится на более универсальных GIN-индексах.
Как это выглядит на практике:
(a) Добавляем колонку tsvector в таблицу:
CREATE TABLE post (
author TEXT,
publish_date DATE,
content TEXT NOT NULL,
search_vector tsvector
);
(b) Заполняем её лексемами (нормализованными словами):
UPDATE post
SET search_vector =
to_tsvector('english', content);
(c) Создаём GIN-индекс по лексемам:
CREATE INDEX post_search_idx
ON post USING GIN(search_vector);
(d) И выполняем запросы:
SELECT * FROM post
WHERE search_vector @@
to_tsquery('english', 'database & expert');
В итоге получаем быстрый и гибкий полнотекстовый поиск прямо внутри Postgres, без отдельных движков и костылей.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
В софте очень часто работают так: система хранит текущее состояние.
Например:
» у пользователя такой баланс
» заказ сейчас в таком статусе
» подписка активна
Event Sourcing предлагает другой подход.
Идея простая:
хранить не финальное состояние, а всю историю изменений.
То есть вместо того, чтобы сохранять
ты сохраняешь события:
А текущий баланс считается путём воспроизведения этих событий.
По сути, как бухгалтерская книга.
Что такое событие в этом контексте?
Событие это факт, который уже произошёл и не меняется.
Например:
» PaymentReceived
» OrderConfirmed
» SubscriptionCancelled
События:
» не редактируются
» не удаляются
» только добавляются
Фактически база данных становится append-only.
Зачем вообще так усложнять?
Потому что это даёт мощные возможности из коробки:
» полная аудитируемость
» сквозная трассировка
» восстановление состояния на любой момент времени
» исторический дебаг: как мы вообще сюда пришли
Никаких дополнительных логов не нужно. История уже есть.
Но важно понимать: у этого подхода есть серьёзные trade-off-ы.
Event Sourcing усложняет всё остальное:
» чтобы читать текущее состояние, нужны проекции
» ментальная модель сложнее
» миграции событий - проблема и требуют аккуратности
Это сила в обмен на сложность.
Где Event Sourcing реально уместен?
Он хорошо заходит, когда:
» домен сложный
» нужна жёсткая аудитируемость
» события важнее состояния
» бизнес постоянно спрашивает «как мы к этому пришли»
Платежи, финансы, бухгалтерия, compliance — классические кандидаты.
Где его лучше не использовать?
» простые CRUD-системы
» тривиальная бизнес-логика
» команды без опыта работы с паттерном
» случаи, когда нужен только текущий стейт
Важное уточнение:
Event Sourcing не равен CQRS.
Их часто используют вместе, но одно не требует другого.
И напоследок главное.
Event Sourcing — это не оптимизация.
Это решение по моделированию.
Ты выбираешь смотреть на систему как на последовательность фактов, а не как на таблицу с изменяемыми значениями.
👉 @BackendPortal
Например:
» у пользователя такой баланс
» заказ сейчас в таком статусе
» подписка активна
Event Sourcing предлагает другой подход.
Идея простая:
хранить не финальное состояние, а всю историю изменений.
То есть вместо того, чтобы сохранять
balance = 100
ты сохраняешь события:
deposit +200
purchase -50
adjustment -50
А текущий баланс считается путём воспроизведения этих событий.
По сути, как бухгалтерская книга.
Что такое событие в этом контексте?
Событие это факт, который уже произошёл и не меняется.
Например:
» PaymentReceived
» OrderConfirmed
» SubscriptionCancelled
События:
» не редактируются
» не удаляются
» только добавляются
Фактически база данных становится append-only.
Зачем вообще так усложнять?
Потому что это даёт мощные возможности из коробки:
» полная аудитируемость
» сквозная трассировка
» восстановление состояния на любой момент времени
» исторический дебаг: как мы вообще сюда пришли
Никаких дополнительных логов не нужно. История уже есть.
Но важно понимать: у этого подхода есть серьёзные trade-off-ы.
Event Sourcing усложняет всё остальное:
» чтобы читать текущее состояние, нужны проекции
» ментальная модель сложнее
» миграции событий - проблема и требуют аккуратности
Это сила в обмен на сложность.
Где Event Sourcing реально уместен?
Он хорошо заходит, когда:
» домен сложный
» нужна жёсткая аудитируемость
» события важнее состояния
» бизнес постоянно спрашивает «как мы к этому пришли»
Платежи, финансы, бухгалтерия, compliance — классические кандидаты.
Где его лучше не использовать?
» простые CRUD-системы
» тривиальная бизнес-логика
» команды без опыта работы с паттерном
» случаи, когда нужен только текущий стейт
Важное уточнение:
Event Sourcing не равен CQRS.
Их часто используют вместе, но одно не требует другого.
И напоследок главное.
Event Sourcing — это не оптимизация.
Это решение по моделированию.
Ты выбираешь смотреть на систему как на последовательность фактов, а не как на таблицу с изменяемыми значениями.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍3🔥1
В SQLite около 155 800 строк кода, а тестовый набор - примерно 92 миллиона строк. Это примерно в 590 раз больше тестов, чем самого кода 🤯
Вот такой уровень тестирования нужен для настоящей продакшен-базы данных. Ниже — какие типы тестов у них есть.
» Тесты на нехватку памяти (OOM)
SQLite не может просто упасть, когда заканчивается память. На встраиваемых устройствах OOM — обычное дело. Они симулируют падения malloc в каждой возможной точке и проверяют, что база корректно это переживает.
» Тесты I/O-ошибок
Диски ломаются. Сеть отваливается. Права могут измениться посреди операции. SQLite подменяет файловую систему на кастомный слой, который может симулировать сбои после N операций, и проверяет, что данные не повреждаются.
» Краш-тесты
Что будет, если питание пропадёт посреди записи? Они симулируют крэш в случайные моменты во время записи, портят несинхронизированные данные, как это делает реальная файловая система, и проверяют, что транзакция либо полностью завершилась, либо чисто откатилась. Никакой порчи данных.
» Fuzz-тестирование
В SQLite кидают кривой SQL, битые файлы базы и случайный мусор. Инструмент dbsqlfuzz прогоняет около 500 миллионов мутаций тестов в день на 16 ядрах.
» 100% покрытие ветвлений
Каждая инструкция ветвления в ядре SQLite проверяется в обе стороны. Не просто «эта строка выполнялась», а «это условие было и true, и false».
Базы данных вообще не прощают ошибок :)
Если хочется копнуть глубже, советую почитать официальную документацию SQLite про их стратегию тестирования. Очень практично и по делу. А если понравился пост - ставь реакцию👌
👉 @BackendPortal
Вот такой уровень тестирования нужен для настоящей продакшен-базы данных. Ниже — какие типы тестов у них есть.
» Тесты на нехватку памяти (OOM)
SQLite не может просто упасть, когда заканчивается память. На встраиваемых устройствах OOM — обычное дело. Они симулируют падения malloc в каждой возможной точке и проверяют, что база корректно это переживает.
» Тесты I/O-ошибок
Диски ломаются. Сеть отваливается. Права могут измениться посреди операции. SQLite подменяет файловую систему на кастомный слой, который может симулировать сбои после N операций, и проверяет, что данные не повреждаются.
» Краш-тесты
Что будет, если питание пропадёт посреди записи? Они симулируют крэш в случайные моменты во время записи, портят несинхронизированные данные, как это делает реальная файловая система, и проверяют, что транзакция либо полностью завершилась, либо чисто откатилась. Никакой порчи данных.
» Fuzz-тестирование
В SQLite кидают кривой SQL, битые файлы базы и случайный мусор. Инструмент dbsqlfuzz прогоняет около 500 миллионов мутаций тестов в день на 16 ядрах.
» 100% покрытие ветвлений
Каждая инструкция ветвления в ядре SQLite проверяется в обе стороны. Не просто «эта строка выполнялась», а «это условие было и true, и false».
Базы данных вообще не прощают ошибок :)
Если хочется копнуть глубже, советую почитать официальную документацию SQLite про их стратегию тестирования. Очень практично и по делу. А если понравился пост - ставь реакцию
Please open Telegram to view this post
VIEW IN TELEGRAM
👍13🤯7❤3
Два года назад парень сделал максимально простой демо-пример, который на уровне операционной системы показывает, что происходит, если не использовать пул соединений для Postgres.
С тех пор его рекомендуют даже LLM, и он регулярно получает такой фидбек:
«Впервые наглядно понял, как работает connection pooling».
Это и подтолкнуло поделиться этим видео с вами, друзья🎷 - смотреть
👉 @BackendPortal
С тех пор его рекомендуют даже LLM, и он регулярно получает такой фидбек:
«Впервые наглядно понял, как работает connection pooling».
Это и подтолкнуло поделиться этим видео с вами, друзья
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2
Media is too big
VIEW IN TELEGRAM
🎬 Что это? А это второй выпуск нового интерактивного шоу «АйТир Лист» от МойОфис
«АйТир Лист» – это шоу, в котором эксперты оценивают технологии, компании, фреймворки и ИТ-решения по шкале от 1 до 4. Каждый выпуск — это 14 табличек от модератора, жаркие дискуссии и итоговый рейтинг, который поможет зрителям разобраться в актуальных трендах и сделать собственные выводы.
Во втором выпуске мы оценим фичи и идиомы C++.
Гости выпуска:
— Данил Черепанов, архитектор Редакторов МойОфис
— Антон Полухин, эксперт-разработчик C++ Техплатформы Городских сервисов Яндекса
🎥 Смотрите наш юбилейный второй выпуск там, где вам удобно:
VK | YouTube | RuTube
Реклама
ООО "НОВЫЕ ОБЛАЧНЫЕ ТЕХНОЛОГИИ"
ИНН: 7703807270
erid: 2W5zFG7z16x
«АйТир Лист» – это шоу, в котором эксперты оценивают технологии, компании, фреймворки и ИТ-решения по шкале от 1 до 4. Каждый выпуск — это 14 табличек от модератора, жаркие дискуссии и итоговый рейтинг, который поможет зрителям разобраться в актуальных трендах и сделать собственные выводы.
Во втором выпуске мы оценим фичи и идиомы C++.
Гости выпуска:
— Данил Черепанов, архитектор Редакторов МойОфис
— Антон Полухин, эксперт-разработчик C++ Техплатформы Городских сервисов Яндекса
🎥 Смотрите наш юбилейный второй выпуск там, где вам удобно:
VK | YouTube | RuTube
Реклама
ООО "НОВЫЕ ОБЛАЧНЫЕ ТЕХНОЛОГИИ"
ИНН: 7703807270
erid: 2W5zFG7z16x
🔥2🤔2💊2
This media is not supported in your browser
VIEW IN TELEGRAM
Элегантное разделение ответственности в Apache Kafka даёт кучу возможностей для масштабирования.
Но за это приходится платить компромиссами.
Производитель, потребитель и брокер.
👉 @BackendPortal
Но за это приходится платить компромиссами.
Производитель, потребитель и брокер.
Please open Telegram to view this post
VIEW IN TELEGRAM