Этот динамический парсинг JSON уже не раз меня подводил — я обычно кастую к
В JSON.NET (
Не первый раз на это натыкаюсь, и, скорее всего, не последний😂
👉 @KodBlog
string через as string, где это возможно.В JSON.NET (
JObject / JValue) значения ведут себя как dynamic при цепочках обращений, но при этом не кастуются, потому что по сути это Expando-подобные объекты.Не первый раз на это натыкаюсь, и, скорее всего, не последний
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🤩1🍾1
Модули в модульном монолите могут взаимодействовать только через свой публичный API.
Но как это обеспечить на уровне архитектуры?
С помощью тестирования архитектуры.
Вот пример кода с тестом, который проверяет направление зависимостей между модулями.
👉 @KodBlog
Но как это обеспечить на уровне архитектуры?
С помощью тестирования архитектуры.
Вот пример кода с тестом, который проверяет направление зависимостей между модулями.
[Fact]
public void TicketingModule_ShouldNotHaveDependencyOn_AnyOtherModule()
{
string[] otherModules = [
UsersNamespace,
EventsNamespace,
AttendanceNamespace
];
string[] integrationEventsModules = [
UsersIntegrationEventsNamespace,
EventsIntegrationEventsNamespace,
AttendanceIntegrationEventsNamespace
];
List<Assembly> ticketingAssemblies =
[
typeof(Order).Assembly,
Modules.Ticketing.Application.AssemblyReference.Assembly,
Modules.Ticketing.Presentation.AssemblyReference.Assembly,
typeof(TicketingModule).Assembly
];
Types.InAssemblies(ticketingAssemblies)
.That()
.DoNotHaveDependencyOnAny(integrationEventsModules)
.Should()
.NotHaveDependencyOnAny(otherModules)
.GetResult()
.ShouldBeSuccessful();
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤2🍾1
Кто-то собрал все задачи с LeetCode, сгруппированные по компаниям, и выложил это в публичный репозиторий на GitHub. Более 300 компаний: Google, Meta, Amazon, Jane Street, Citadel, Stripe, Snowflake — практически каждый крупный работодатель в техе, у каждого своя папка.
Внутри папок всё отсортировано по тому, насколько недавно задача встречалась — за последние 30 дней, 60 дней, 90 дней и за всё время.
Это означает, что если у тебя интервью в Google в пятницу, ты можешь открыть папку Google и увидеть, какие задачи они задавали в этом месяце.
Не самая приятная правда, которая здесь вскрывается: компании месяцами переиспользуют одни и те же задачи. Интервью — это не непредсказуемое испытание, а набор паттернов. А паттерны можно изучать.
Большинство кандидатов решают 500 случайных задач на LeetCode и надеются на лучшее. Те, кто знают про этот репозиторий, тратят то же время на 30 задач, которые их целевая компания задавала за последние 30 дней.
Те же усилия. Совершенно другие шансы.
Технические интервью больше вознаграждают подготовку, чем способности — сильнее, чем кто-либо в найме готов это признать. Этот репозиторий просто делает это очевидным.
Лично я этим не пользовался, делюсь на случай, если кому-то пригодится.
P.S. Мы всё ещё решаем LeetCode в 2026?
👉 @KodBlog
Внутри папок всё отсортировано по тому, насколько недавно задача встречалась — за последние 30 дней, 60 дней, 90 дней и за всё время.
Это означает, что если у тебя интервью в Google в пятницу, ты можешь открыть папку Google и увидеть, какие задачи они задавали в этом месяце.
Не самая приятная правда, которая здесь вскрывается: компании месяцами переиспользуют одни и те же задачи. Интервью — это не непредсказуемое испытание, а набор паттернов. А паттерны можно изучать.
Большинство кандидатов решают 500 случайных задач на LeetCode и надеются на лучшее. Те, кто знают про этот репозиторий, тратят то же время на 30 задач, которые их целевая компания задавала за последние 30 дней.
Те же усилия. Совершенно другие шансы.
Технические интервью больше вознаграждают подготовку, чем способности — сильнее, чем кто-либо в найме готов это признать. Этот репозиторий просто делает это очевидным.
Лично я этим не пользовался, делюсь на случай, если кому-то пригодится.
P.S. Мы всё ещё решаем LeetCode в 2026?
Please open Telegram to view this post
VIEW IN TELEGRAM
😁3🤔1
Пользовательские SQL-запросы в миграциях EF? Это возможно.
Пользовательские SQL-команды полезны, когда мы не можем выразить что-то через Fluent API EF.
Я использовал их для переноса данных из одного столбца в другой или для создания сложных индексов.
- Создайте пустую миграцию
- Напишите свои SQL-запросы
👉 @KodBlog
Пользовательские SQL-команды полезны, когда мы не можем выразить что-то через Fluent API EF.
Я использовал их для переноса данных из одного столбца в другой или для создания сложных индексов.
- Создайте пустую миграцию
- Напишите свои SQL-запросы
public partial class Update_Products : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql("<YOUR CUSTOM SQL HERE>");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
// You are also responsible for reverting any changes.
}
}
Please open Telegram to view this post
VIEW IN TELEGRAM
👏3👍2
Младший разработчик использует EF Core напрямую в контроллере.
Средний разработчик использует BaseRepository, IUnitOfWork, IOrderRepository, IOrderDataAccess, IOrderQueryBuilder.
Старший разработчик использует EF Core без репозитория.
Когда ваше приложение маленькое, использование паттерна Репозиторий кажется простым.
То, что начинается как простая операция CRUD с 4 методами, быстро превращается в большой класс с запросами для чтения и записи в базу данных для всех возможных случаев.
По мере роста вашего домена вы сталкиваетесь со следующими проблемами:
- Вы создаете репозиторий для каждой новой сущности
- Куда относятся методы, работающие с несколькими сущностями?
- Вы создаете репозитории с 10-20 методами
Я часто слышу следующие распространенные оправдания для использования репозиториев:
𝟭. "Мы можем позже сменить базу данных."
В 99% случаев вам не нужно будет менять базу данных.
- Переход от одной SQL базы данных к другой? EF Core справится с этим.
- Использование хранимых процедур, триггеров? Тогда их нужно переписать на уровне базы данных.
- Переход от реляционной базы данных к документной? Вам нужно будет изменить модель данных, запросы и шаблоны доступа. Вы не сможете просто заменить реализации репозиториев.
𝟮. "Это облегчает тестирование."
Некоторые утверждают, что мокирование репозитория проще, чем мокирование DbContext.
Но это скрывает большую проблему: вы тестируете абстракцию абстракции.
Мокирование репозиториев часто приводит к хрупким тестам, которые не отражают реальное поведение запросов.
Вместо этого лучше использовать реальный EF Core с базой данных в памяти или, что еще лучше, писать интеграционные тесты.
𝟯. "Это обеспечивает разделение ответственностей."
Репозитории часто используются для того, чтобы держать бизнес-слой отдельно от EF Core. Но на практике это разделение создает больше путаницы, чем ясности.
По мере того как ваши фичи растут, вам приходится:
- Внедрять несколько репозиториев в ваши сервисы
- Или переносить логику, работающую с несколькими сущностями, в жирный репозиторий
Вместо чистого разделения вы получаете больше косвенных ссылок, больше шаблонного кода и трудный для понимания код.
DbContext в EF Core уже реализует паттерны Репозиторий и Unit of Work, как указано в официальном описании кода DbContext.
Я использую EF Core напрямую в кейсах использования и сервисах моего приложения. Это прагматичный подход, который приносит мне больше преимуществ, чем недостатков.
👉 @KodBlog
Средний разработчик использует BaseRepository, IUnitOfWork, IOrderRepository, IOrderDataAccess, IOrderQueryBuilder.
Старший разработчик использует EF Core без репозитория.
Когда ваше приложение маленькое, использование паттерна Репозиторий кажется простым.
То, что начинается как простая операция CRUD с 4 методами, быстро превращается в большой класс с запросами для чтения и записи в базу данных для всех возможных случаев.
По мере роста вашего домена вы сталкиваетесь со следующими проблемами:
- Вы создаете репозиторий для каждой новой сущности
- Куда относятся методы, работающие с несколькими сущностями?
- Вы создаете репозитории с 10-20 методами
Я часто слышу следующие распространенные оправдания для использования репозиториев:
𝟭. "Мы можем позже сменить базу данных."
В 99% случаев вам не нужно будет менять базу данных.
- Переход от одной SQL базы данных к другой? EF Core справится с этим.
- Использование хранимых процедур, триггеров? Тогда их нужно переписать на уровне базы данных.
- Переход от реляционной базы данных к документной? Вам нужно будет изменить модель данных, запросы и шаблоны доступа. Вы не сможете просто заменить реализации репозиториев.
𝟮. "Это облегчает тестирование."
Некоторые утверждают, что мокирование репозитория проще, чем мокирование DbContext.
Но это скрывает большую проблему: вы тестируете абстракцию абстракции.
Мокирование репозиториев часто приводит к хрупким тестам, которые не отражают реальное поведение запросов.
Вместо этого лучше использовать реальный EF Core с базой данных в памяти или, что еще лучше, писать интеграционные тесты.
𝟯. "Это обеспечивает разделение ответственностей."
Репозитории часто используются для того, чтобы держать бизнес-слой отдельно от EF Core. Но на практике это разделение создает больше путаницы, чем ясности.
По мере того как ваши фичи растут, вам приходится:
- Внедрять несколько репозиториев в ваши сервисы
- Или переносить логику, работающую с несколькими сущностями, в жирный репозиторий
Вместо чистого разделения вы получаете больше косвенных ссылок, больше шаблонного кода и трудный для понимания код.
DbContext в EF Core уже реализует паттерны Репозиторий и Unit of Work, как указано в официальном описании кода DbContext.
Я использую EF Core напрямую в кейсах использования и сервисах моего приложения. Это прагматичный подход, который приносит мне больше преимуществ, чем недостатков.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11💯6👎2❤1👏1
𝟭𝟱 инструментов и библиотек .NET, которые использует сообщество
Я задал в r/dotnet один вопрос: какие библиотеки .NET вы реально используете, о которых никто не говорит?
Тред собрал сотни ответов. Я отфильтровал те, у которых 10+ апвоутов.
CSharpier набрал 62 голоса. Refit — на втором месте. Дальше — набор инструментов с 30–31 голосами, о большинстве из которых разработчики либо не знают, либо почти не упоминают в туториалах.
Несколько моментов, которые бросились в глаза:
Сообщество стало скептически относиться к зависимостям. FluentAssertions, IdentityServer и MediatR — к ним уже нет прежнего доверия. Самый залайканный комментарий (не про библиотеку) был: «Batteries included, stay away from dependencies» (используй встроенные возможности и избегай лишних зависимостей). Этот контекст важен при чтении списка.
LINQPad — это не NuGet-пакет, но он постоянно всплывал в обсуждении. Команды строят на нём целые вспомогательные воркфлоу.
Vogen меня удивил. Type-safe value objects, генерируемые на этапе компиляции без runtime-оверхеда. Я видел баги в продакшене из-за путаницы с orderId/customerId — это как раз решает такие проблемы.
👉 @KodBlog
Я задал в r/dotnet один вопрос: какие библиотеки .NET вы реально используете, о которых никто не говорит?
Тред собрал сотни ответов. Я отфильтровал те, у которых 10+ апвоутов.
CSharpier набрал 62 голоса. Refit — на втором месте. Дальше — набор инструментов с 30–31 голосами, о большинстве из которых разработчики либо не знают, либо почти не упоминают в туториалах.
Несколько моментов, которые бросились в глаза:
Сообщество стало скептически относиться к зависимостям. FluentAssertions, IdentityServer и MediatR — к ним уже нет прежнего доверия. Самый залайканный комментарий (не про библиотеку) был: «Batteries included, stay away from dependencies» (используй встроенные возможности и избегай лишних зависимостей). Этот контекст важен при чтении списка.
LINQPad — это не NuGet-пакет, но он постоянно всплывал в обсуждении. Команды строят на нём целые вспомогательные воркфлоу.
Vogen меня удивил. Type-safe value objects, генерируемые на этапе компиляции без runtime-оверхеда. Я видел баги в продакшене из-за путаницы с orderId/customerId — это как раз решает такие проблемы.
Please open Telegram to view this post
VIEW IN TELEGRAM
😁1
Как версионировать Minimal API?
Нужно определить
Более удобный подход — создать
👉 @KodBlog
Нужно определить
ApiVersionSet и применить его к эндпоинтам.Более удобный подход — создать
route group, назначить ему версию API, а затем использовать этот route group для маппинга отдельных эндпоинтов.Please open Telegram to view this post
VIEW IN TELEGRAM
👍2👀1
Нужно быстро написать небольшой скрипт или прототип на C#?
JetBrains Rider 2026.1 теперь поддерживает file-based C# программы, которые можно запускать без
Доступны:
- полноценный автокомплит (code completion)
- отладка (debugging)
- run-маркеры для top-level statements и
👉 @KodBlog
JetBrains Rider 2026.1 теперь поддерживает file-based C# программы, которые можно запускать без
.csproj.Доступны:
- полноценный автокомплит (code completion)
- отладка (debugging)
- run-маркеры для top-level statements и
#! (shebang)Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👀2
Устанвока:
/plugin marketplace add dotnet/skillsОдна команда — и твой coding-агент получает .NET-суперсилы
Работает в Copilot CLI, VScode, и VS 2026.
https://github.com/dotnet/skills/tree/main/plugins/dotnet-upgrade
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥3😁1🥴1
Нужно предотвратить race conditions в базе данных?
Когда несколько запросов могут обновлять одни и те же строки, требуется блокировка.
Типичный пример: фоновые воркеры обрабатывают одну и ту же таблицу.
Забудьте про тяжёлые уровни изоляции. Вместо этого используйте блокировки на уровне строк:
- PostgreSQL:
- SQL Server:
Это можно использовать с «сырым» SQL в EF Core.
Я использовал
Вот как это применить в .NET: https://milanjovanovic.tech/blog/a-clever-way-to-implement-pessimistic-locking-in-ef-core
Важно отметить, что такая блокировка живёт в течение всей транзакции.
👉 @KodBlog
Когда несколько запросов могут обновлять одни и те же строки, требуется блокировка.
Типичный пример: фоновые воркеры обрабатывают одну и ту же таблицу.
Забудьте про тяжёлые уровни изоляции. Вместо этого используйте блокировки на уровне строк:
- PostgreSQL:
FOR UPDATE / FOR UPDATE SKIP LOCKED- SQL Server:
WITH (UPDLOCK)Это можно использовать с «сырым» SQL в EF Core.
Я использовал
SKIP LOCKED, чтобы масштабировать свой Outbox-процессор до более чем 2 млрд сообщений в день.Вот как это применить в .NET: https://milanjovanovic.tech/blog/a-clever-way-to-implement-pessimistic-locking-in-ef-core
Важно отметить, что такая блокировка живёт в течение всей транзакции.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3👀2
Автор масштабировал свой outbox-процессор до более чем 2B+ сообщений в день.
Вот 4 вещи, которые он сделал:
- Добавил покрывающий индекс → index-only scan’ы
- Внедрил батчинг при публикации сообщений
- Масштабировал через параллельные процессоры
- Использовал
Реализовать паттерн Outbox — просто.
А вот масштабировать его — уже настоящая задача.
Полный разбор здесь
👉 @KodBlog
Вот 4 вещи, которые он сделал:
- Добавил покрывающий индекс → index-only scan’ы
- Внедрил батчинг при публикации сообщений
- Масштабировал через параллельные процессоры
- Использовал
FOR UPDATE SKIP LOCKED для обработки конкуренцииРеализовать паттерн Outbox — просто.
А вот масштабировать его — уже настоящая задача.
Полный разбор здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👏3
Одна из самых распространенных ошибок, которые я вижу при подключении к существующим проектам:
разработчики помещают всю бизнес-логику внутрь сервисных классов.
Что это дает?
Запутанный клубок из бизнес-правил, запросов к базе данных и логики отправки email, запихнутых в один метод.
Результат:
- Новая фича ломает 3 вещи, которые ты даже не трогал.
- Тесты, где нужно 15 моков, чтобы проверить одно бизнес-правило.
- Мигрень каждый раз, когда клиент говорит: «Просто небольшое изменение…»
Корневая причина? Структура кода.
Но есть 3 простых паттерна из DDD, которые это исправляют.
Кратко, что они дают:
- Один паттерн позволяет тестировать сложные бизнес-правила без единого мока — буквально просто
- Один изолирует логику фильтрации запросов, чтобы переиспользовать ее в разных обработчиках без копирования LINQ-выражений
- Один отделяет сайд-эффекты (email, фоновые задачи, синхронизация с CRM), так что добавление нового сайд-эффекта занимает минуты, а не рефакторинг, который забивает контекст AI-агента за 5 минут
Я использовал все три на легаси-кодовой базе возрастом 7 лет.
Полные примеры кода в статье:
https://thearchitecturelab.com/post/3-ddd-patterns
👉 @KodBlog
разработчики помещают всю бизнес-логику внутрь сервисных классов.
Что это дает?
Запутанный клубок из бизнес-правил, запросов к базе данных и логики отправки email, запихнутых в один метод.
Результат:
- Новая фича ломает 3 вещи, которые ты даже не трогал.
- Тесты, где нужно 15 моков, чтобы проверить одно бизнес-правило.
- Мигрень каждый раз, когда клиент говорит: «Просто небольшое изменение…»
Корневая причина? Структура кода.
Но есть 3 простых паттерна из DDD, которые это исправляют.
Кратко, что они дают:
- Один паттерн позволяет тестировать сложные бизнес-правила без единого мока — буквально просто
new Invoice() и проверка результата- Один изолирует логику фильтрации запросов, чтобы переиспользовать ее в разных обработчиках без копирования LINQ-выражений
- Один отделяет сайд-эффекты (email, фоновые задачи, синхронизация с CRM), так что добавление нового сайд-эффекта занимает минуты, а не рефакторинг, который забивает контекст AI-агента за 5 минут
Я использовал все три на легаси-кодовой базе возрастом 7 лет.
Полные примеры кода в статье:
https://thearchitecturelab.com/post/3-ddd-patterns
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾4❤2
Clean Architecture & Vertical Slices
Clean Architecture дает четкие границы.
Vertical Slice Architecture дает четкие фичи.
Вот как я это организую:
1) Domain — ядро бизнес-логики
Никакого EF Core. Никакого HTTP. Никаких внешних зависимостей. Только чистые бизнес-правила.
Паттерн Result, базовые сущности и доменные модели — все без привязки к фреймворкам.
2) Application — здесь раскрывается VSA
Вместо папки "Services" с 20 файлами — каждый use case имеет свою собственную папку.
Каждый slice = Command/Query → Validator → Handler.
Хочешь понять “Create Todo”? Открываешь одну папку — и все. Без поиска по слоям.
3) Infrastructure — слой реализации
Базы данных, EF Core, кэширование, identity — все детали реализации живут здесь.
Слой Application определяет, что ему нужно (интерфейсы).
Infrastructure предоставляет реализацию. Чистая инверсия зависимостей.
4) Api — тонкий слой, без бизнес-логики
Этот слой принимает запросы и возвращает ответы. И все.
Минимальные API с endpoint-классами.
Каждый endpoint просто валидирует запрос, передает его в handler и возвращает результат.
5) Tests — защита архитектуры
Юнит-тесты повторяют структуру feature-папок.
Архитектурные тесты гарантируют, что зависимости всегда направлены внутрь —
Domain не ссылается на Infrastructure, Application не ссылается на Api.
👉 @KodBlog
Clean Architecture дает четкие границы.
Vertical Slice Architecture дает четкие фичи.
Вот как я это организую:
1) Domain — ядро бизнес-логики
Никакого EF Core. Никакого HTTP. Никаких внешних зависимостей. Только чистые бизнес-правила.
📁 Domain
├── 📁 Common
│ ├── AuditableEntity.cs
│ ├── BaseEntity.cs
│ ├── Error.cs
│ ├── PagedResult.cs
│ └── Result.cs
└── 📁 Entities
├── ApplicationUser.cs
└── TodoItem.cs
Паттерн Result, базовые сущности и доменные модели — все без привязки к фреймворкам.
2) Application — здесь раскрывается VSA
Вместо папки "Services" с 20 файлами — каждый use case имеет свою собственную папку.
📁 Application
├── 📁 Abstractions
│ ├── 📁 Data
│ │ └── IAppDbContext.cs
│ ├── 📁 Identity
│ │ ├── ICurrentUser.cs
│ │ └── ITokenService.cs
│ └── 📁 Messaging
│ ├── ICommand.cs
│ ├── ICommandHandler.cs
│ ├── IQuery.cs
│ └── IQueryHandler.cs
├── 📁 Features
│ ├── 📁 Identity
│ │ ├── 📁 Login
│ │ ├── 📁 Register
│ │ └── 📁 RefreshToken
│ └── 📁 Todos
│ ├── 📁 Create
│ │ ├── CreateTodoCommand.cs
│ │ ├── CreateTodoCommandHandler.cs
│ │ └── CreateTodoValidator.cs
└── DependencyInjection.cs
Каждый slice = Command/Query → Validator → Handler.
Хочешь понять “Create Todo”? Открываешь одну папку — и все. Без поиска по слоям.
3) Infrastructure — слой реализации
Базы данных, EF Core, кэширование, identity — все детали реализации живут здесь.
📁 Infrastructure
├── 📁 Persistence
│ ├── 📁 Configurations
│ │ ├── ApplicationUserConfiguration.cs
│ │ └── TodoItemConfiguration.cs
│ ├── 📁 Migrations
│ ├── AppDbContext.cs
│ └── AppDbSeeder.cs
├── 📁 Identity
├── 📁 Caching
└── DependencyInjection.cs
Слой Application определяет, что ему нужно (интерфейсы).
Infrastructure предоставляет реализацию. Чистая инверсия зависимостей.
4) Api — тонкий слой, без бизнес-логики
Этот слой принимает запросы и возвращает ответы. И все.
📁 Api
├── 📁 Endpoints
│ ├── TodoEndpoints.cs
├── 📁 Extensions
│ ├── GlobalExceptionHandler.cs
│ ├── ResultExtensions.cs
│ └── ValidationFilter.cs
└── Program.cs
Минимальные API с endpoint-классами.
Каждый endpoint просто валидирует запрос, передает его в handler и возвращает результат.
5) Tests — защита архитектуры
📁 tests
├── 📁 Application.UnitTests
│ └── 📁 Features/Todos
│ ├── CreateTodoCommandHandlerTests.cs
└── 📁 Architecture.Tests
└── ArchitectureTests.cs
Юнит-тесты повторяют структуру feature-папок.
Архитектурные тесты гарантируют, что зависимости всегда направлены внутрь —
Domain не ссылается на Infrastructure, Application не ссылается на Api.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12❤4👀2
C# модификатор
Компилятор всегда создаёт временную переменную, если требуется преобразование аргумента, есть неявное преобразование типа аргумента, или если аргумент — это значение, а не переменная.
Пример
👉 @KodBlog
in позволяет компилятору создать временную переменную для аргумента и передать на неё ссылку только для чтения.Компилятор всегда создаёт временную переменную, если требуется преобразование аргумента, есть неявное преобразование типа аргумента, или если аргумент — это значение, а не переменная.
Пример
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8👀2
Пример итерации по словарю с деконструкцией
#dotnet #csharp
👉 @KodBlog
KeyValuePair с осмысленными именами переменных вместо использования Key/Value, что делает код более читаемым.#dotnet #csharp
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥11🤔4
Вашему .NET-приложению не обязательно быть медленным в 2026 году.
Кэширование — один из самых простых способов повысить производительность, и
- Очень быстрый
- Простой в использовании
- Не требует внешних зависимостей
Но есть компромиссы:
- Данные теряются при перезапуске
- Ограничено памятью одного сервера
Нужно более надёжное или масштабируемое решение?
Вот гайд по вариантам распределённого кэширования в .NET:
P.S. Не забывайте, что кэширование не решает корневую проблему производительности. Поэтому обязательно сначала проанализируйте и устраните её.
👉 @KodBlog
Кэширование — один из самых простых способов повысить производительность, и
IMemoryCache — самый простой вариант, с которого можно начать:- Очень быстрый
- Простой в использовании
- Не требует внешних зависимостей
Но есть компромиссы:
- Данные теряются при перезапуске
- Ограничено памятью одного сервера
Нужно более надёжное или масштабируемое решение?
Вот гайд по вариантам распределённого кэширования в .NET:
P.S. Не забывайте, что кэширование не решает корневую проблему производительности. Поэтому обязательно сначала проанализируйте и устраните её.
Please open Telegram to view this post
VIEW IN TELEGRAM
🐳2🍾2❤1👍1
This media is not supported in your browser
VIEW IN TELEGRAM
Docker за 2 минуты
Большинство разработчиков используют Docker каждый день, не понимая, что происходит под капотом. Вот всё, что нужно знать.
У Docker есть 3 основных компонента:
1. Docker Client: место, где ты вводишь команды, которые через API общаются с Docker daemon.
2. Docker Host: здесь работает daemon, который делает всю основную работу (сборка образов, запуск контейнеров и управление ресурсами)
3. Docker Registry: хранилище Docker-образов. Docker Hub — публичный, но компании часто поднимают приватные registry.
Вот что происходит, когда ты запускаешь
• Docker подтягивает образ из registry (если его нет локально)
• Docker создаёт новый контейнер из этого образа
• Docker выделяет контейнеру файловую систему с возможностью записи (read-write)
• Docker создаёт сетевой интерфейс для подключения контейнера
• Docker запускает контейнер
Вот и всё.
Client, host и registry могут находиться на разных машинах. Именно поэтому Docker хорошо масштабируется.
Понимание этой архитектуры сильно упрощает дебаг контейнеров — ты точно знаешь, где искать проблему, если что-то ломается.
👉 @KodBlog
Большинство разработчиков используют Docker каждый день, не понимая, что происходит под капотом. Вот всё, что нужно знать.
У Docker есть 3 основных компонента:
1. Docker Client: место, где ты вводишь команды, которые через API общаются с Docker daemon.
2. Docker Host: здесь работает daemon, который делает всю основную работу (сборка образов, запуск контейнеров и управление ресурсами)
3. Docker Registry: хранилище Docker-образов. Docker Hub — публичный, но компании часто поднимают приватные registry.
Вот что происходит, когда ты запускаешь
docker run:• Docker подтягивает образ из registry (если его нет локально)
• Docker создаёт новый контейнер из этого образа
• Docker выделяет контейнеру файловую систему с возможностью записи (read-write)
• Docker создаёт сетевой интерфейс для подключения контейнера
• Docker запускает контейнер
Вот и всё.
Client, host и registry могут находиться на разных машинах. Именно поэтому Docker хорошо масштабируется.
Понимание этой архитектуры сильно упрощает дебаг контейнеров — ты точно знаешь, где искать проблему, если что-то ломается.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍12🕊2
Я годами использовал WebApplicationFactory и TestContainers.
Потом попробовал тестирование в .NET Aspire — и назад не вернусь.
Вот почему: тесты через WebApplicationFactory проверяют API в изоляции.
Остальные сервисы ты мокируешь.
Это значит, что ты никогда не ловишь баги, которые возникают при взаимодействии сервисов A и B в проде.
Традиционный сетап выглядит так:
→ Прямая ссылка на проект API
→ Ручной подъём Docker-контейнеров через TestContainers
→ Переопределение connection string через переменные окружения
→ Мок внешних сервисов, от которых зависит API
→ Надежда, что в проде всё будет работать вместе
Слишком много glue-кода ради одного теста.
.NET Aspire поднимает ВСЮ распределённую систему в рамках одного теста:
→ Все API запущены
→ Реальные контейнеры PostgreSQL и Redis
→ Реальные HTTP-вызовы между сервисами
→ Ноль моков
Вот 3 конкретных плюса, которые я получил сразу:
𝟭. Больше нет boilerplate с TestContainers
Раньше: 50+ строк на конфигурацию PostgreSQL-контейнера, connection string и переменных окружения.
Теперь: одна строка — ссылка на AppHost.
Aspire делает всё сам.
𝟮. Тесты поймали ломающее изменение API-контракта
Products API изменил модель ответа.
С моками тесты всё ещё проходили.
С Aspire — Stocks API сразу упал, потому что не смог десериализовать ответ. Поймали до продакшена.
𝟯. Порядок старта сервисов автоматический
Больше нет случайных падений тестов из-за того, что API стартовал раньше, чем PostgreSQL был готов. Aspire автоматически ждёт зависимости.
Завтра я отправлю полный гайд для 25,149+ .NET-разработчиков:
- Точный сетап DistributedApplicationTestingBuilder, который я использую
- Как шарить один инстанс приложения на 100+ тестов (сильный буст скорости)
- Моя стратегия очистки базы, которая предотвращает «загрязнение» тестов
- 2 продвинутых паттерна: тестирование фоновых задач и очередей сообщений
Это тот подход к тестированию, который наконец сделал распределённые системы тестируемыми.
👉 @KodBlog
Потом попробовал тестирование в .NET Aspire — и назад не вернусь.
Вот почему: тесты через WebApplicationFactory проверяют API в изоляции.
Остальные сервисы ты мокируешь.
Это значит, что ты никогда не ловишь баги, которые возникают при взаимодействии сервисов A и B в проде.
Традиционный сетап выглядит так:
→ Прямая ссылка на проект API
→ Ручной подъём Docker-контейнеров через TestContainers
→ Переопределение connection string через переменные окружения
→ Мок внешних сервисов, от которых зависит API
→ Надежда, что в проде всё будет работать вместе
Слишком много glue-кода ради одного теста.
.NET Aspire поднимает ВСЮ распределённую систему в рамках одного теста:
→ Все API запущены
→ Реальные контейнеры PostgreSQL и Redis
→ Реальные HTTP-вызовы между сервисами
→ Ноль моков
Вот 3 конкретных плюса, которые я получил сразу:
𝟭. Больше нет boilerplate с TestContainers
Раньше: 50+ строк на конфигурацию PostgreSQL-контейнера, connection string и переменных окружения.
Теперь: одна строка — ссылка на AppHost.
Aspire делает всё сам.
𝟮. Тесты поймали ломающее изменение API-контракта
Products API изменил модель ответа.
С моками тесты всё ещё проходили.
С Aspire — Stocks API сразу упал, потому что не смог десериализовать ответ. Поймали до продакшена.
𝟯. Порядок старта сервисов автоматический
Больше нет случайных падений тестов из-за того, что API стартовал раньше, чем PostgreSQL был готов. Aspire автоматически ждёт зависимости.
Завтра я отправлю полный гайд для 25,149+ .NET-разработчиков:
- Точный сетап DistributedApplicationTestingBuilder, который я использую
- Как шарить один инстанс приложения на 100+ тестов (сильный буст скорости)
- Моя стратегия очистки базы, которая предотвращает «загрязнение» тестов
- 2 продвинутых паттерна: тестирование фоновых задач и очередей сообщений
Это тот подход к тестированию, который наконец сделал распределённые системы тестируемыми.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥8👍5🕊2
5 Архитектурных Тестов Необходимых Каждому .NET-Проекту.
Каждый проект начинается с благих намерений. Вы согласовываете границы слоёв, соглашения об именовании, направление зависимостей. Через полгода кто-то переносит доменный сервис в проект инфраструктуры, обработчик получает имя не по соглашению или внутренний класс становится публичным, потому что это значение по умолчанию. Архитектурные тесты предотвращают это. Они превращают архитектурные правила в автоматизированные тесты, которые запускаются в CI. Вот архитектурные тесты, которые пригодятся каждому проекту.
👉 @KodBlog
Каждый проект начинается с благих намерений. Вы согласовываете границы слоёв, соглашения об именовании, направление зависимостей. Через полгода кто-то переносит доменный сервис в проект инфраструктуры, обработчик получает имя не по соглашению или внутренний класс становится публичным, потому что это значение по умолчанию. Архитектурные тесты предотвращают это. Они превращают архитектурные правила в автоматизированные тесты, которые запускаются в CI. Вот архитектурные тесты, которые пригодятся каждому проекту.
Please open Telegram to view this post
VIEW IN TELEGRAM
Milan Jovanović
5 Architecture Tests You Should Add to Your .NET Projects
Learn about five essential architecture tests that can help ensure the quality and maintainability of your .NET projects.
❤1👏1
Перестань дублировать JOINы — используй USING
Если ты давно пишешь SQL-запросы, ты, скорее всего, привык к
Вот почему стоит на него перейти.
Гораздо чище, правда?
Использование
Убедись, что твоя СУБД поддерживает
👉 @KodBlog
Если ты давно пишешь SQL-запросы, ты, скорее всего, привык к
ON. Он работает. Но когда ты джоинишь две таблицы по колонкам с одинаковыми именами, есть более чистый и элегантный способ — USING.Вот почему стоит на него перейти.
SELECT
e.Employee_ID,
e.Employee_Name,
e.Department,
s.Net_Sales
FROM Employees e
JOIN sales s
ON e.Employee_ID = s.Employee_ID
ON работает, но он многословный. Приходится повторять имена таблиц и колонок. Если имя колонки одинаковое в обеих таблицах, ты фактически пишешь одно и то же дважды. Хуже того, при выборке ты получишь два столбца Employee_ID, если явно их не квалифицировать.USING — это сокращённая форма для JOIN по равенству колонок с одинаковыми именами. Тот же запрос:SELECT
e.Employee_ID,
e.Employee_Name,
e.Department,
s.Net_Sales
FROM Employees e
JOIN sales s
USING (Employee_ID);
Гораздо чище, правда?
USING автоматически сопоставляет колонки с одинаковым именем и выполняет INNER JOIN (или LEFT/RIGHT JOIN — в зависимости от типа соединения). Ты указываешь имя колонки только один раз.Использование
USING — небольшое изменение, которое делает SQL более лаконичным и самодокументируемым. Это снижает вероятность ошибок и делает результирующие наборы данных чище.Убедись, что твоя СУБД поддерживает
USING.Please open Telegram to view this post
VIEW IN TELEGRAM
❤13👎3😁1
Agent Framework: фоновые ответы решают проблему таймаутов у долгоживущих агентов
Агенты, использующие reasoning-модели, могут выполнять задачу несколько минут — глубокое исследование, многошаговый анализ, генерация объёмного контента. Держать HTTP-соединение открытым всё это время ненадёжно: балансировщики нагрузки рвут соединение по таймауту, мобильные клиенты отваливаются, и любая ошибка приводит к потере всего накопленного прогресса.
Фоновые ответы в Microsoft Agent Framework позволяют вынести такие долгие операции в background, чтобы приложение оставалось отзывчивым и устойчивым независимо от того, сколько времени агенту нужно на выполнение задачи.
👉 @KodBlog
Агенты, использующие reasoning-модели, могут выполнять задачу несколько минут — глубокое исследование, многошаговый анализ, генерация объёмного контента. Держать HTTP-соединение открытым всё это время ненадёжно: балансировщики нагрузки рвут соединение по таймауту, мобильные клиенты отваливаются, и любая ошибка приводит к потере всего накопленного прогресса.
Фоновые ответы в Microsoft Agent Framework позволяют вынести такие долгие операции в background, чтобы приложение оставалось отзывчивым и устойчивым независимо от того, сколько времени агенту нужно на выполнение задачи.
Please open Telegram to view this post
VIEW IN TELEGRAM
👏1