Использование нативной компиляции AOT в .NET для сборки DLL под Windows WinAPI: читать
Я пропустил один момент с AOT: через него можно собирать нативные библиотеки динамической компоновки. Проверил на практике — получаются небольшие стандартные DLL в стиле WinAPI, которые можно вызывать из легаси-приложений.
👉 @KodBlog
Я пропустил один момент с AOT: через него можно собирать нативные библиотеки динамической компоновки. Проверил на практике — получаются небольшие стандартные DLL в стиле WinAPI, которые можно вызывать из легаси-приложений.
Please open Telegram to view this post
VIEW IN TELEGRAM
West-Wind
Using .NET Native AOT to build Windows WinAPI Dlls
Did you know that you can use .NET AOT compilation to create native Windows DLLs to potentially replace traditional C/C++ compiled DLLs? It's now possible to build completely native DLLs that can be called from external applications and legacy applications…
👍5🍾2
.NET MAUI работает на Linux через GTK4. Команда экспериментирует с этим в maui-labs, и реализация уже выглядит очень полной. Есть Shell, Blazor Hybrid, CollectionView, жесты, анимации. Всё на нативных виджетах GTK4.
https://github.com/dotnet/maui-labs/tree/main/platforms/Linux.Gtk4
👉 @KodBlog
https://github.com/dotnet/maui-labs/tree/main/platforms/Linux.Gtk4
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥15🍾5
SkiaSharp 4.0 Preview 1 вышел — более быстрый рендеринг, более чистые API и более умное формирование текста для .NET-приложений, которые рисуют… что угодно.
Попробуй и посмотри, на что теперь способны твои графические компоненты: https://ift.tt/k9wTbRv
👉 @KodBlog
Попробуй и посмотри, на что теперь способны твои графические компоненты: https://ift.tt/k9wTbRv
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9🍾2
Я написал два почти одинаковых SQL-запроса.
Один из них оказался быстрее в 451 раз.
Я реализовывал постраничную навигацию через курсор.
И подумал: почему бы не добавить индекс, чтобы ускорить запрос?
Вот здесь всё пошло не по плану.
Есть сканирование индекса через составной индекс. На первый взгляд — всё нормально.
Но запрос стал даже медленнее, чем без индекса.
В чём причина?
Можно было бы подумать, что дело в слишком маленьком объёме данных, где индекс просто не даёт выгоды.
Но дело было не в этом…
А что если использовать сравнение кортежей в SQL?
В итоге индекс начал работать — 0.668 мс.
Оптимизатор запросов не смог корректно понять, можно ли применить составной индекс для построчного сравнения.
Но при сравнении кортежей индекс начал использоваться эффективно.
Если бы я не посмотрел план выполнения запроса, я бы это не понял.
👉 @KodBlog
Один из них оказался быстрее в 451 раз.
Я реализовывал постраничную навигацию через курсор.
И подумал: почему бы не добавить индекс, чтобы ускорить запрос?
Вот здесь всё пошло не по плану.
Есть сканирование индекса через составной индекс. На первый взгляд — всё нормально.
Но запрос стал даже медленнее, чем без индекса.
В чём причина?
Можно было бы подумать, что дело в слишком маленьком объёме данных, где индекс просто не даёт выгоды.
Но дело было не в этом…
А что если использовать сравнение кортежей в SQL?
В итоге индекс начал работать — 0.668 мс.
Оптимизатор запросов не смог корректно понять, можно ли применить составной индекс для построчного сравнения.
Но при сравнении кортежей индекс начал использоваться эффективно.
Если бы я не посмотрел план выполнения запроса, я бы это не понял.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8❤2🍾2
Стоит ли перестать использовать случайные UUID в .NET?
Классический UUID через
Из-за случайного порядка появляются:
- дорогие ребалансировки индексов;
- просадка скорости вставки;
- высокая фрагментация.
Поэтому многие перешли на ULID — 128-битный сортируемый идентификатор с сохранением уникальности.
ULID сохраняет временной порядок генерации, благодаря чему лучше работает с индексами.
Но начиная с .NET 9 появился более нативный вариант:
✅
UUID V7 — это time-ordered UUID с полной совместимостью с
Фактически получаете преимущества ULID, но уже встроенные в .NET.
👉 @KodBlog
Классический UUID через
Guid.NewGuid() генерируется случайным образом. Для уникальности это отлично, но для базы данных — не лучший вариант.Из-за случайного порядка появляются:
- дорогие ребалансировки индексов;
- просадка скорости вставки;
- высокая фрагментация.
Поэтому многие перешли на ULID — 128-битный сортируемый идентификатор с сохранением уникальности.
ULID сохраняет временной порядок генерации, благодаря чему лучше работает с индексами.
Но начиная с .NET 9 появился более нативный вариант:
Guid.CreateVersion7()UUID V7 — это time-ordered UUID с полной совместимостью с
Guid, без сторонних пакетов.Фактически получаете преимущества ULID, но уже встроенные в .NET.
Please open Telegram to view this post
VIEW IN TELEGRAM
👌8🔥3🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
Каждый бэкенд-инженер должен уметь ответить на вопрос:
Что произойдёт, если база данных упадёт посреди транзакции?
Причины могут быть разные: отключение питания, сбой оборудования и т.д.
Чтобы не потерять данные, система должна сохранять их на энергозависимом хранилище, например, на диске.
Когда пользователь выполняет транзакцию, база данных делает две вещи:
> записывает данные в отдельный лог
> применяет обновление
Лог нужен для повторной обработки транзакции при перезапуске, чтобы восстановить консистентное состояние после сбоя.
Запись в лог быстрая, так как это бинарный файл с добавлением только в конец (append-only).
Это исключает затратные операции поиска по файлу.
А если база распределённая?
Тут сложнее — серверам базы нужно координироваться с помощью протокола двухфазной фиксации (2PC).
В этом процессе один из серверов выступает координатором:
> он отправляет всем участникам запрос на коммит
> ждёт подтверждения от всех
> затем сообщает коммитить или откатить транзакцию
👉 @KodBlog
Что произойдёт, если база данных упадёт посреди транзакции?
Причины могут быть разные: отключение питания, сбой оборудования и т.д.
Чтобы не потерять данные, система должна сохранять их на энергозависимом хранилище, например, на диске.
Когда пользователь выполняет транзакцию, база данных делает две вещи:
> записывает данные в отдельный лог
> применяет обновление
Лог нужен для повторной обработки транзакции при перезапуске, чтобы восстановить консистентное состояние после сбоя.
Запись в лог быстрая, так как это бинарный файл с добавлением только в конец (append-only).
Это исключает затратные операции поиска по файлу.
А если база распределённая?
Тут сложнее — серверам базы нужно координироваться с помощью протокола двухфазной фиксации (2PC).
В этом процессе один из серверов выступает координатором:
> он отправляет всем участникам запрос на коммит
> ждёт подтверждения от всех
> затем сообщает коммитить или откатить транзакцию
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3❤🔥2🍾1
REST API best practices в 2025
Антон Мартынов собрал опыт после 100+ реализованных API
1. уровни зрелости REST
уровень 0: один эндпоинт (лучше избегать)
уровень 1: несколько ресурсов
уровень 2: корректное использование HTTP-методов
уровень 3: HATEOAS (когда действительно нужно)
2. именование ресурсов
используются существительные:
не используются глаголы:
важна консистентность:
не смешивать стили:
3. HTTP-методы и коды статусов
методы:
- GET → чтение
- POST → создание
- PUT / PATCH → обновление
- DELETE → удаление
коды успеха:
- 200 → успех
- 201 → создано
- 202 → принято (асинхронная обработка)
- 204 → без тела ответа
коды ошибок клиента:
- 400 → некорректный запрос
- 401 → неавторизован
- 403 → доступ запрещён
- 404 → не найдено
- 422 → ошибка валидации
коды ошибок сервера:
- 500 → внутренняя ошибка
- 503 → сервис недоступен
4. версионирование API
варианты:
- через URI:
- через заголовок:
- через media type:
мчерез query string:
5. запросы и ответы
- всегда JSON
- единый формат ошибок
- поддержка фильтрации и пагинации
- документация через OpenAPI / Swagger
6. безопасность
- HTTPS везде
- OAuth2 / JWT авторизация
- ограничение частоты запросов
- валидация входных данных
- кэширование ответов
👉 @KodBlog
Антон Мартынов собрал опыт после 100+ реализованных API
1. уровни зрелости REST
уровень 0: один эндпоинт (лучше избегать)
уровень 1: несколько ресурсов
уровень 2: корректное использование HTTP-методов
уровень 3: HATEOAS (когда действительно нужно)
2. именование ресурсов
используются существительные:
/users, /ordersне используются глаголы:
/getUsers, /createOrderважна консистентность:
user-profiles или product-cartsне смешивать стили:
UserProfiles, userProfiles3. HTTP-методы и коды статусов
методы:
- GET → чтение
- POST → создание
- PUT / PATCH → обновление
- DELETE → удаление
коды успеха:
- 200 → успех
- 201 → создано
- 202 → принято (асинхронная обработка)
- 204 → без тела ответа
коды ошибок клиента:
- 400 → некорректный запрос
- 401 → неавторизован
- 403 → доступ запрещён
- 404 → не найдено
- 422 → ошибка валидации
коды ошибок сервера:
- 500 → внутренняя ошибка
- 503 → сервис недоступен
4. версионирование API
варианты:
- через URI:
/api/v1/users- через заголовок:
X-Api-Version- через media type:
application/vnd.api.v1+jsonмчерез query string:
?version=1 (не рекомендуется)5. запросы и ответы
- всегда JSON
- единый формат ошибок
- поддержка фильтрации и пагинации
- документация через OpenAPI / Swagger
6. безопасность
- HTTPS везде
- OAuth2 / JWT авторизация
- ограничение частоты запросов
- валидация входных данных
- кэширование ответов
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9🍾2
net-developer-resources.pdf
4.3 MB
Сборник 650+ отобранных ресурсов для прокачки C#, .NET, ASP .NET Core, EF Core и микросервисов
👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Если ты разработчик и пишешь код каждый день — помни 5 вещей:
1. Сначала сделай, чтобы работало
2. Потом сделай красиво
3. Добавь надёжность большим количеством тестов
4. Держись подальше от оверинжиниринга
5. Рефактори, если нужно (а обычно нужно)
Рефакторинг — твоя суперсила для очистки кода.
Вот несколько проверенных техник рефакторинга
👉 @KodBlog
1. Сначала сделай, чтобы работало
2. Потом сделай красиво
3. Добавь надёжность большим количеством тестов
4. Держись подальше от оверинжиниринга
5. Рефактори, если нужно (а обычно нужно)
Рефакторинг — твоя суперсила для очистки кода.
Вот несколько проверенных техник рефакторинга
Please open Telegram to view this post
VIEW IN TELEGRAM
❤12🍾3
Проекция в LINQ на C#: Select, SelectMany и «сплющивание» коллекций
Разбор проекции в LINQ на C# с использованием селект, селектмани и метода Index() в .NET 9. Рассматриваются анонимные типы, записи, разворачивание вложенных коллекций и практические примеры.
Читать статью: https://bgh.st/vrpbm0
👉 @KodBlog
Разбор проекции в LINQ на C# с использованием селект, селектмани и метода Index() в .NET 9. Рассматриваются анонимные типы, записи, разворачивание вложенных коллекций и практические примеры.
Читать статью: https://bgh.st/vrpbm0
Please open Telegram to view this post
VIEW IN TELEGRAM
Dev Leader
LINQ Projection in C#: Select, SelectMany, and Flattening Collections
Learn LINQ projection in C# with Select, SelectMany, and the .NET 9 Index() method. Covers anonymous types, records, flattening nested collections, and real exa
🍾1
Тестовая пирамида была хорошим советом для 2009 года.
Я не думаю, что это хороший совет для современных .NET-систем.
Тогда интеграционные тесты были дорогими:
общие серверы баз данных, нестабильный CI, медленные сборки, болезненная настройка окружения.
Поэтому рекомендация имела смысл:
писать много модульных тестов, мокать всё подряд, держать интеграционные тесты в минимальном объёме.
Но экономика изменилась.
С Testcontainers можно поднять PostgreSQL, Redis и RabbitMQ за секунды.
С Aspire можно собрать граф приложения и протестировать реальные границы системы.
Это меняет само понятие «быстрой обратной связи».
Для меня набор тестов с высокой уверенностью сейчас выглядит так:
Тонкий слой модульных тестов для чистой доменной логики.
Толстый слой интеграционных тестов на реальной инфраструктуре.
Несколько критичных end-to-end тестов для сценариев, которые реально больно ломать.
И архитектурные/контрактные тесты, чтобы границы со временем не «плыли».
Я всё ещё пишу модульные тесты.
Просто не для всего.
Хендлеры, эндпоинты, репозитории, консьюмеры сообщений и API модулей обычно относятся к интеграционным тестам.
Именно там чаще всего и прячутся реальные баги.
👉 @KodBlog
Я не думаю, что это хороший совет для современных .NET-систем.
Тогда интеграционные тесты были дорогими:
общие серверы баз данных, нестабильный CI, медленные сборки, болезненная настройка окружения.
Поэтому рекомендация имела смысл:
писать много модульных тестов, мокать всё подряд, держать интеграционные тесты в минимальном объёме.
Но экономика изменилась.
С Testcontainers можно поднять PostgreSQL, Redis и RabbitMQ за секунды.
С Aspire можно собрать граф приложения и протестировать реальные границы системы.
Это меняет само понятие «быстрой обратной связи».
Для меня набор тестов с высокой уверенностью сейчас выглядит так:
Тонкий слой модульных тестов для чистой доменной логики.
Толстый слой интеграционных тестов на реальной инфраструктуре.
Несколько критичных end-to-end тестов для сценариев, которые реально больно ломать.
И архитектурные/контрактные тесты, чтобы границы со временем не «плыли».
Я всё ещё пишу модульные тесты.
Просто не для всего.
Хендлеры, эндпоинты, репозитории, консьюмеры сообщений и API модулей обычно относятся к интеграционным тестам.
Именно там чаще всего и прячутся реальные баги.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3❤🔥1❤1🍾1
ИИ-агенты заменят джунов и мидлов .NET-разработки
Джун и мидл часто пропускают базовые принципы и начинают срезать углы на каждом шаге через ИИ.
ИИ усиливает уже имеющиеся знания.
Если фундамент слабый, сложно заметить, когда Claude или Copilot генерирует код с тонкими ошибками.
И такие ошибки будут.
Достаточно часто, чтобы это стало проблемой в продакшене.
Чем сильнее фундамент, тем лучше способность оценивать, что оставить, что исправить, а что выбросить.
Вот 5 базовых областей, которые определяют выживаемость в эпоху ИИ:
𝟭. 𝗛𝗧𝗧𝗣
→ Джун: выкатывает контроллер, сгенерированный ИИ.
→ Сеньор: замечает отсутствие идемпотентности у POST, некорректные коды ответов, утечку стектрейса в ошибках.
𝟮. Конкурентность
→ Джун: просто пишет асинхронный метод.
→ Сеньор: ловит отсутствие прокидывания CancellationToken по цепочке вызовов и .Result, который даёт дедлок под нагрузкой.
𝟯. 𝗘𝗙 𝗖𝗼𝗿𝗲 и БД
→ Джун: видит код, который компилируется.
→ Сеньор: замечает N+1 запрос, отсутствие AsNoTracking, IQueryable, который материализует миллионы строк в память.
𝟰. Архитектура 𝘁𝗿𝗲𝗶𝗱-𝗼𝗳𝗳𝘆
→ Джун: принимает микросервисы, потому что так предложил Claude.
→ Сеньор: задаёт вопрос, почему не начать с модульного монолита и не выделять сервисы позже при необходимости.
𝟱. Валидация и обработка ошибок
→ Джун: держит try/catch внутри эндпоинта.
→ Сеньор: понимает, что Result<T> лучше для бизнес-потока, а FluentValidation лучше, чем inline if-else.
👉 @KodBlog
Джун и мидл часто пропускают базовые принципы и начинают срезать углы на каждом шаге через ИИ.
ИИ усиливает уже имеющиеся знания.
Если фундамент слабый, сложно заметить, когда Claude или Copilot генерирует код с тонкими ошибками.
И такие ошибки будут.
Достаточно часто, чтобы это стало проблемой в продакшене.
Чем сильнее фундамент, тем лучше способность оценивать, что оставить, что исправить, а что выбросить.
Вот 5 базовых областей, которые определяют выживаемость в эпоху ИИ:
𝟭. 𝗛𝗧𝗧𝗣
→ Джун: выкатывает контроллер, сгенерированный ИИ.
→ Сеньор: замечает отсутствие идемпотентности у POST, некорректные коды ответов, утечку стектрейса в ошибках.
𝟮. Конкурентность
→ Джун: просто пишет асинхронный метод.
→ Сеньор: ловит отсутствие прокидывания CancellationToken по цепочке вызовов и .Result, который даёт дедлок под нагрузкой.
𝟯. 𝗘𝗙 𝗖𝗼𝗿𝗲 и БД
→ Джун: видит код, который компилируется.
→ Сеньор: замечает N+1 запрос, отсутствие AsNoTracking, IQueryable, который материализует миллионы строк в память.
𝟰. Архитектура 𝘁𝗿𝗲𝗶𝗱-𝗼𝗳𝗳𝘆
→ Джун: принимает микросервисы, потому что так предложил Claude.
→ Сеньор: задаёт вопрос, почему не начать с модульного монолита и не выделять сервисы позже при необходимости.
𝟱. Валидация и обработка ошибок
→ Джун: держит try/catch внутри эндпоинта.
→ Сеньор: понимает, что Result<T> лучше для бизнес-потока, а FluentValidation лучше, чем inline if-else.
Please open Telegram to view this post
VIEW IN TELEGRAM
👎7❤4🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
Spec-Driven Development с Spec-Kit:
ИИ больше не нужно больше промптов — ему нужен контекст
Три ключевых документа, которые меняют подход:
📄 spec.md → что делаем (what)
Описывает цель: требования, поведение системы, ограничения, пользовательские сценарии.
Это «что должно существовать».
📄 plan.md → как делаем (how)
Архитектура и стратегия реализации:
структура системы, подходы, зависимости, решения по дизайну.
Это «как мы это построим».
📄 tasks.md → выполнение (execution)
Разбивка на конкретные шаги:
задачи, чеклисты, порядок выполнения, итерации.
Это «что делать прямо сейчас».
👉 @KodBlog
ИИ больше не нужно больше промптов — ему нужен контекст
Три ключевых документа, которые меняют подход:
📄 spec.md → что делаем (what)
Описывает цель: требования, поведение системы, ограничения, пользовательские сценарии.
Это «что должно существовать».
📄 plan.md → как делаем (how)
Архитектура и стратегия реализации:
структура системы, подходы, зависимости, решения по дизайну.
Это «как мы это построим».
📄 tasks.md → выполнение (execution)
Разбивка на конкретные шаги:
задачи, чеклисты, порядок выполнения, итерации.
Это «что делать прямо сейчас».
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🍾1
Авторы расширений для Visual Studio, хотите помочь Mads Kristensen протестировать набор agent skills, чтобы эффективнее направлять кодинговых агентов и быстрее получать VS-расширения более высокого качества?
Попробуйте эти новые skills, следуя инструкциям здесь: vs-agent-plugins
👉 @KodBlog
Попробуйте эти новые skills, следуя инструкциям здесь: vs-agent-plugins
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - madskristensen/vs-agent-plugins
Contribute to madskristensen/vs-agent-plugins development by creating an account on GitHub.
❤2🍾1
Запуск фоновых задач в .NET 11 Blazor с Web Workers — исследование preview .NET 11 (часть 1)
Running background tasks in Blazor with Web Workers (Andrew Lock)
В этом посте разбирают новый шаблон Web Worker, доступный в preview .NET 11, который позволяет выполнять CPU-интенсивные задачи в Blazor, не блокируя UI-поток.
#dotnet #blazor
👉 @KodBlog
Running background tasks in Blazor with Web Workers (Andrew Lock)
В этом посте разбирают новый шаблон Web Worker, доступный в preview .NET 11, который позволяет выполнять CPU-интенсивные задачи в Blazor, не блокируя UI-поток.
#dotnet #blazor
Please open Telegram to view this post
VIEW IN TELEGRAM
Andrew Lock | .NET Escapades
Running background tasks in Blazor with Web Workers
In this post I discuss the new Web Worker template available in .NET 11 for running CPU intensive tasks without blocking the UI
🍾3🔥2
Вот 7 популярных репозиториев по архитектуре ПО (для .NET-разработчиков):
1. Эволюционная архитектура на примерах -> тык
2. Модульный монолит с DDD (предметно-ориентированным проектированием) -> тык
3. Стартер-кит на .NET 8 с поддержкой мультиарендности -> тык
4. Пример eCommerce-приложения на микросервисах в .NET -> тык
5. Пример архитектуры вертикальных срезов (Vertical Slice) -> тык
6. Шаблон .NET-приложения с чистой архитектурой -> тык
7. Пример приложения с гексагональной архитектурой -> тык
👉 @KodBlog
1. Эволюционная архитектура на примерах -> тык
2. Модульный монолит с DDD (предметно-ориентированным проектированием) -> тык
3. Стартер-кит на .NET 8 с поддержкой мультиарендности -> тык
4. Пример eCommerce-приложения на микросервисах в .NET -> тык
5. Пример архитектуры вертикальных срезов (Vertical Slice) -> тык
6. Шаблон .NET-приложения с чистой архитектурой -> тык
7. Пример приложения с гексагональной архитектурой -> тык
Please open Telegram to view this post
VIEW IN TELEGRAM
GitHub
GitHub - evolutionary-architecture/evolutionary-architecture-by-example: Navigate the complex landscape of .NET software architecture…
Navigate the complex landscape of .NET software architecture with our step-by-step, story-like guide. Unpack the interplay between modular monoliths, microservices, domain-driven design, and variou...
👍9❤4🔥2🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
CCleaner (C++, ~20 лет) vs FluentCleaner (C#, .NET 10): одинаковое сканирование, одинаковый результат, одинаковая скорость. Оказывается, managed-код не означает автоматически медленный код.
GitHub releases FluentCleaner
Следующий релиз FluentCleaner станет ещё быстрее для записей с несколькими файловыми паттернами. Оставайтесь на связи😎
👉 @KodBlog
GitHub releases FluentCleaner
Следующий релиз FluentCleaner станет ещё быстрее для записей с несколькими файловыми паттернами. Оставайтесь на связи
Please open Telegram to view this post
VIEW IN TELEGRAM
👏9👍3🍾2
Большая часть контента про “system design” в интернете — это показуха ради производительности.
Люди учатся «проектировать Twitter на 1 млрд пользователей», прежде чем понимают, что такое primary key.
Порядок обучения перевёрнут.
1/ Начинать нужно с Low-Level Design.
Схемы, API-контракты, обработка ошибок, связи данных, что происходит при некорректном вводе.
Это скучные 90% реальной инженерии.
2/ Потом переходить к High-Level Design.
Шардинг, кэширование, очереди, регионы.
Но только после того, как ты понимаешь, что именно ты шардишь, кэшируешь или отправляешь в очередь.
3/ Потом изучать trade-offs.
CAP, задержка vs стоимость, консистентность vs доступность.
Это становится полезным только когда есть конкретная система, к которой это можно применить.
Многие инженеры умеют рисовать диаграмму таймлайна Twitter.
Но попроси их спроектировать схему для постов, лайков, комментариев и реакций — и они зависают.
HLD без LLD — это фанфик.
Сначала сделай модель данных.
Потом заслужи архитектурную диаграмму.
👉 @KodBlog
Люди учатся «проектировать Twitter на 1 млрд пользователей», прежде чем понимают, что такое primary key.
Порядок обучения перевёрнут.
1/ Начинать нужно с Low-Level Design.
Схемы, API-контракты, обработка ошибок, связи данных, что происходит при некорректном вводе.
Это скучные 90% реальной инженерии.
2/ Потом переходить к High-Level Design.
Шардинг, кэширование, очереди, регионы.
Но только после того, как ты понимаешь, что именно ты шардишь, кэшируешь или отправляешь в очередь.
3/ Потом изучать trade-offs.
CAP, задержка vs стоимость, консистентность vs доступность.
Это становится полезным только когда есть конкретная система, к которой это можно применить.
Многие инженеры умеют рисовать диаграмму таймлайна Twitter.
Но попроси их спроектировать схему для постов, лайков, комментариев и реакций — и они зависают.
HLD без LLD — это фанфик.
Сначала сделай модель данных.
Потом заслужи архитектурную диаграмму.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4👍2🍾2
Как сделать API-эндпоинты быстрее в 426 раз:
(подсказка: дело не в кэше)
Когда разработчики сталкиваются с медленными API, первая реакция — лечить проблему неправильным инструментом: кэшем.
Но такой подход строится на критичном заблуждении:
На вере в то, что кэширование может исправить тормоза, вызванные плохими запросами к базе данных.
Именно поэтому первый шаг к масштабируемым системам — сначала починить их.
Чтобы это показать, проведём небольшой эксперимент.
Я собрал небольшой веб-API с одним эндпоинтом —
До оптимизации:
Количество обработанных запросов: 378
Среднее количество запросов в секунду: 11.01
Средняя длительность запроса: ~4 секунды
После оптимизации:
Количество обработанных запросов: 140,331
Среднее количество запросов в секунду: 4,689.36
Средняя длительность запроса: 10.69 мс
Сначала исправляйте доступ к данным.
И только потом используйте кэширование для масштабирования, а не для выживания.
👉 @KodBlog
(подсказка: дело не в кэше)
Когда разработчики сталкиваются с медленными API, первая реакция — лечить проблему неправильным инструментом: кэшем.
Но такой подход строится на критичном заблуждении:
На вере в то, что кэширование может исправить тормоза, вызванные плохими запросами к базе данных.
Именно поэтому первый шаг к масштабируемым системам — сначала починить их.
Чтобы это показать, проведём небольшой эксперимент.
Я собрал небольшой веб-API с одним эндпоинтом —
/products.До оптимизации:
Количество обработанных запросов: 378
Среднее количество запросов в секунду: 11.01
Средняя длительность запроса: ~4 секунды
После оптимизации:
Количество обработанных запросов: 140,331
Среднее количество запросов в секунду: 4,689.36
Средняя длительность запроса: 10.69 мс
Сначала исправляйте доступ к данным.
И только потом используйте кэширование для масштабирования, а не для выживания.
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯6❤4🌚3🍾1
SignalR нормально работает с одним сервером.
Потом добавляешь второй инстанс за балансировщиком нагрузки, и уведомления начинают пропадать.
Код может быть полностью корректным.
Проблема в карте соединений.
Каждый сервер SignalR знает только о клиентах, подключённых к его конкретному процессу.
То есть если API-запрос попал на Сервер 1, но пользователь подключён к Серверу 2, Сервер 1 не знает об этом соединении.
Сообщение уходит в никуда. Здесь помогает Redis backplane.
Каждый сервер публикует исходящие SignalR-сообщения в Redis.
Каждый сервер подписан на один и тот же канал.
Когда сообщение приходит, каждый инстанс проверяет, есть ли целевое соединение локально.
В коде приложения
Но теперь это работает между инстансами.
Настройка почти тривиальная:
Но есть два важных момента, которые нужно помнить:
Всё ещё нужны sticky-сессии
SignalR не буферизует сообщения, если Redis недоступен
Redis backplane решает маршрутизацию. Он не делает SignalR устойчивым к сбоям.
Для обновлений заказов, живых дашбордов и большинства UI-уведомлений в реальном времени этого обычно достаточно. Для критичных событий нужна стратегия синхронизации или устойчивый очередной слой вместе с этим.
👉 @KodBlog
Потом добавляешь второй инстанс за балансировщиком нагрузки, и уведомления начинают пропадать.
Код может быть полностью корректным.
Проблема в карте соединений.
Каждый сервер SignalR знает только о клиентах, подключённых к его конкретному процессу.
То есть если API-запрос попал на Сервер 1, но пользователь подключён к Серверу 2, Сервер 1 не знает об этом соединении.
Сообщение уходит в никуда. Здесь помогает Redis backplane.
Каждый сервер публикует исходящие SignalR-сообщения в Redis.
Каждый сервер подписан на один и тот же канал.
Когда сообщение приходит, каждый инстанс проверяет, есть ли целевое соединение локально.
В коде приложения
Clients.User(...) продолжает работать так же.Но теперь это работает между инстансами.
Настройка почти тривиальная:
builder.Services.AddSignalR().AddStackExchangeRedis(connectionString);
Но есть два важных момента, которые нужно помнить:
Всё ещё нужны sticky-сессии
SignalR не буферизует сообщения, если Redis недоступен
Redis backplane решает маршрутизацию. Он не делает SignalR устойчивым к сбоям.
Для обновлений заказов, живых дашбордов и большинства UI-уведомлений в реальном времени этого обычно достаточно. Для критичных событий нужна стратегия синхронизации или устойчивый очередной слой вместе с этим.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤6👍3🍾1