Как сделать настройки приложения строго типизированными?
Рекомендуемый способ — использовать паттерн Options.
Он обеспечивает строго типизированный доступ к конфигурации приложения.
В .NET паттерн Options реализован через три интерфейса:
>
>
>
Чтобы создать строго типизированную конфигурацию, можно использовать классы или record-типы.
❗️ Нельзя использовать позиционные record-типы — нужен конструктор без параметров, обязательный для десериализации конфигурации.
Преимущества использования record-типов:
> Иммутабельность
> Читаемость
> Сравнение по значению (value equality)
Вы можете просто зарегистрировать тип в DI-контейнере и использовать его там, где нужно.
Реализация — простая, а преимущества очевидны:
> Строгая типизация конфигурации
> Разделение ответственности
> Централизация и согласованность
Этого достаточно, чтобы начать использовать подход в продакшн-проектах
👉 @KodBlog
Рекомендуемый способ — использовать паттерн Options.
Он обеспечивает строго типизированный доступ к конфигурации приложения.
В .NET паттерн Options реализован через три интерфейса:
>
IOptions<T>
— доступ к строго типизированным параметрам>
IOptionsSnapshot<T>
— доступ к значениям конфигурации на момент запроса>
IOptionsMonitor<T>
— доступ к текущим значениям и возможность подписки на измененияЧтобы создать строго типизированную конфигурацию, можно использовать классы или record-типы.
Преимущества использования record-типов:
> Иммутабельность
> Читаемость
> Сравнение по значению (value equality)
Вы можете просто зарегистрировать тип в DI-контейнере и использовать его там, где нужно.
Реализация — простая, а преимущества очевидны:
> Строгая типизация конфигурации
> Разделение ответственности
> Централизация и согласованность
Этого достаточно, чтобы начать использовать подход в продакшн-проектах
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Самое раздражающее при отладке C#-кода?
(что может серьёзно замедлить процесс)
Проверка значений в коллекции.
Приходится разворачивать каждый элемент, чтобы посмотреть значения свойств.
Чтобы решить эту проблему, в Visual Studio недавно появилась функция закрепляемых свойств (pinnable properties).
Она позволяет быстро отслеживать нужные свойства.
Чтобы воспользоваться, наведите курсор на свойство и нажмите на иконку закрепления.
См. видео-пример, как это использовать🕵️♀️
👉 @KodBlog
(что может серьёзно замедлить процесс)
Приходится разворачивать каждый элемент, чтобы посмотреть значения свойств.
Чтобы решить эту проблему, в Visual Studio недавно появилась функция закрепляемых свойств (pinnable properties).
Она позволяет быстро отслеживать нужные свойства.
Чтобы воспользоваться, наведите курсор на свойство и нажмите на иконку закрепления.
См. видео-пример, как это использовать
Please open Telegram to view this post
VIEW IN TELEGRAM
Как сделать систему масштабируемой?
Современные приложения должны справляться с резкими всплесками трафика без сбоев.
Когда один сервер достигает предела, это чревато задержками, ошибками или полной недоступностью.
Есть два основных подхода:
> Вертикальное масштабирование → увеличение ресурсов одного сервера
> Горизонтальное масштабирование → добавление серверов за балансировщиком нагрузки
Для горизонтального масштабирования отличным выбором является YARP — высокопроизводительный обратный прокси от Microsoft для .NET.
В моих тестах с K6 масштабирование до 5 экземпляров API дало прирост:
✅ Время отклика: с 9.68 мс до 4.65 мс
✅ Пропускная способность: с 2260 RPS до 3881 RPS
Настроить YARP и запустить масштабирование можно за считанные минуты.
👉 Подробности: read
👉 @KodBlog
Современные приложения должны справляться с резкими всплесками трафика без сбоев.
Когда один сервер достигает предела, это чревато задержками, ошибками или полной недоступностью.
Есть два основных подхода:
> Вертикальное масштабирование → увеличение ресурсов одного сервера
> Горизонтальное масштабирование → добавление серверов за балансировщиком нагрузки
Для горизонтального масштабирования отличным выбором является YARP — высокопроизводительный обратный прокси от Microsoft для .NET.
В моих тестах с K6 масштабирование до 5 экземпляров API дало прирост:
Настроить YARP и запустить масштабирование можно за считанные минуты.
Please open Telegram to view this post
VIEW IN TELEGRAM
This media is not supported in your browser
VIEW IN TELEGRAM
Событийно-ориентированные фоновые задачи в C#
BackgroundWorker — это легковесный инструмент для выполнения асинхронной работы.
Обмен сообщениями между хостом и рабочим происходит через события.
Есть встроенная поддержка отмены задач и обновлений прогресса.
LINQPad визуализирует весь процесс :
вызвал
Хочешь, стилизуй вывод с помощью CSS.
👉 Полный скрипт для загрузки доступен по ссылке: https://share.linqpad.net/phkul63s.linq
👉 @KodBlog
BackgroundWorker — это легковесный инструмент для выполнения асинхронной работы.
Обмен сообщениями между хостом и рабочим происходит через события.
Есть встроенная поддержка отмены задач и обновлений прогресса.
LINQPad визуализирует весь процесс :
вызвал
Dump()
— и данные сразу в окне Results как HTML.Хочешь, стилизуй вывод с помощью CSS.
Please open Telegram to view this post
VIEW IN TELEGRAM
#1 ошибка, которую я вижу у .NET-разработчиков — это повсеместное использование null.
Ссылки на null стали причиной множества багов, уязвимостей и сбоев систем.
Вот 4 способа минимизировать использование null в C#:
1. Возвращайте пустое значение из метода
> если возможно, возвращайте пустой список вместо null
> например, используйте
2. Исключайте null с помощью nullable reference types
> представлены в C# 8.0
> заставляют вас явно учитывать возможность null
3. Используйте паттерн Null Object
> объект, реализующий поведение “ничего не делать”
> позволяет избежать проверок на null
4. Используйте оператор null-условия (?.)
> безопасно обращается к свойствам объектов
> если экземпляр равен null, всё выражение вернёт null
Хотите сократить количество сбоев? Попробуйте эти подходы.👀
👉 @KodBlog
Ссылки на null стали причиной множества багов, уязвимостей и сбоев систем.
Вот 4 способа минимизировать использование null в C#:
1. Возвращайте пустое значение из метода
> если возможно, возвращайте пустой список вместо null
> например, используйте
Enumerable.Empty<TResult>()
2. Исключайте null с помощью nullable reference types
> представлены в C# 8.0
> заставляют вас явно учитывать возможность null
3. Используйте паттерн Null Object
> объект, реализующий поведение “ничего не делать”
> позволяет избежать проверок на null
4. Используйте оператор null-условия (?.)
> безопасно обращается к свойствам объектов
> если экземпляр равен null, всё выражение вернёт null
Хотите сократить количество сбоев? Попробуйте эти подходы.
Please open Telegram to view this post
VIEW IN TELEGRAM
Пример использования паттерна IOptions в ASP dotnet
На втором примере эквивалент с использованием
А ты используешь этот паттерн?👀
👉 @KodBlog
IOptions<T>
обеспечивает безопасность на этапе компиляции и устраняет использование магических строк.На втором примере эквивалент с использованием
IConfiguration
вместо IOptions
А ты используешь этот паттерн?
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Записи действительно являются неизменяемыми.
Если вы знаете, как их определять.
Если запись объявлена традиционным способом, нет ограничений на использование обычного сеттера, что позволяет изменять объект после инициализации.
Однако, если в записи используется init только для части свойств, то такая запись не является полностью неизменяемой.
Так как же сделать их неизменяемыми?
Используйте позиционные записи.
Такой тип записей компилятор генерирует со свойствами только для инициализации (init-only).
Может показаться, что первый и второй вариант определения идентичны.
Но позвольте развеять это заблуждение.
Первая форма компилируется во вторую, и во втором случае вы можете заменить🐸
👉 @KodBlog
Если вы знаете, как их определять.
Если запись объявлена традиционным способом, нет ограничений на использование обычного сеттера, что позволяет изменять объект после инициализации.
Однако, если в записи используется init только для части свойств, то такая запись не является полностью неизменяемой.
Так как же сделать их неизменяемыми?
Используйте позиционные записи.
Такой тип записей компилятор генерирует со свойствами только для инициализации (init-only).
Может показаться, что первый и второй вариант определения идентичны.
Но позвольте развеять это заблуждение.
Первая форма компилируется во вторую, и во втором случае вы можете заменить
init
на set
и тем самым нарушить основную характеристику записей. Please open Telegram to view this post
VIEW IN TELEGRAM
MongoDB теперь нативно доступен на Azure.
Больше никаких "костылей" между сервисами.
Теперь можно:
> Запускать MongoDB Atlas напрямую из Azure Portal
> Интегрироваться с Azure AI, Databricks, OpenAI — в одном потоке
> Получать единый биллинг по всему стеку
Это будущее cloud-native разработки?
Или тесная интеграция с облаком — палка о двух концах для свободы разработчиков?
Полная разбивка: https://fnf.dev/4n1fsLd✌️
👉 @KodBlog
Больше никаких "костылей" между сервисами.
Теперь можно:
> Запускать MongoDB Atlas напрямую из Azure Portal
> Интегрироваться с Azure AI, Databricks, OpenAI — в одном потоке
> Получать единый биллинг по всему стеку
Это будущее cloud-native разработки?
Или тесная интеграция с облаком — палка о двух концах для свободы разработчиков?
Полная разбивка: https://fnf.dev/4n1fsLd
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
Сократил время выполнения SQL-запроса с 70 мс до 1 мс.
Без изменений в коде. Без кэширования. Просто добавил filtered index (фильтрованный индекс).
Фильтрованные индексы — одна из самых недооценённых возможностей SQL.
Они позволяют индексировать только подмножество строк, соответствующих определённому условию — идеально подходят для флагов вроде
Но есть нюанс: если условие выполняется для большинства строк, индекс не даст прироста производительности.
Эта оптимизация дала огромный прирост в одном из проектов.
В статье подробно разбирается реализацию и показывается, как это использовать: читать
👉 @KodBlog
Без изменений в коде. Без кэширования. Просто добавил filtered index (фильтрованный индекс).
Фильтрованные индексы — одна из самых недооценённых возможностей SQL.
Они позволяют индексировать только подмножество строк, соответствующих определённому условию — идеально подходят для флагов вроде
ProcessedAt IS NULL
.Но есть нюанс: если условие выполняется для большинства строк, индекс не даст прироста производительности.
Эта оптимизация дала огромный прирост в одном из проектов.
В статье подробно разбирается реализацию и показывается, как это использовать: читать
Please open Telegram to view this post
VIEW IN TELEGRAM
В EF Core 9 улучшена функция
Небольшое, но полезное улучшение.
Эта возможность появилась в EF Core 8 — для производительного обновления данных в базе без загрузки в память.
Однако изначально она поддерживала только примитивные типы.
Если нужно было обновить комплексный тип, приходилось вручную перечислять все его свойства… до выхода EF Core 9.
Теперь комплексные типы полностью поддерживаются — больше не нужно делать это вручную🙂
👉 @KodBlog
ExecuteUpdate
Небольшое, но полезное улучшение.
Эта возможность появилась в EF Core 8 — для производительного обновления данных в базе без загрузки в память.
Однако изначально она поддерживала только примитивные типы.
Если нужно было обновить комплексный тип, приходилось вручную перечислять все его свойства… до выхода EF Core 9.
Теперь комплексные типы полностью поддерживаются — больше не нужно делать это вручную
Please open Telegram to view this post
VIEW IN TELEGRAM
Rider 2025.2 EAP 4 уже тут
Этот билд приносит поддержку SQL-проектов базы данных через встроенный плагин — без доп. настройки:
> Шаблоны SQL-проектов в стиле SDK
> Сравнение схем и публикация проекта
> Импорт из БД, добавление ссылок и другое
Подробнее > jetbrains.com/rider/nextversion🐸
👉 @KodBlog
Этот билд приносит поддержку SQL-проектов базы данных через встроенный плагин — без доп. настройки:
> Шаблоны SQL-проектов в стиле SDK
> Сравнение схем и публикация проекта
> Импорт из БД, добавление ссылок и другое
Подробнее > jetbrains.com/rider/nextversion
Please open Telegram to view this post
VIEW IN TELEGRAM
Улучшения производительности
👉 @KodBlog
FrozenDictionary
с целочисленными (int
) ключами в .NET 10FrozenDictionary
представляют собой коллекции, оптимизированные для чтения (Dictionary
и Set
), создание которых занимает больше времени, но чтение из них происходит быстрее по сравнению с неизменяемыми (immutable
) коллекциями.Please open Telegram to view this post
VIEW IN TELEGRAM
В чём проблема с синглтоном (Singleton) в многопоточности?
Как реализовать потокобезопасный синглтон?
Две нити (потока) могут одновременно проверить, является ли экземпляр null, и обе получат true.
В результате каждая из них создаст собственный экземпляр, что нарушает основное правило паттерна Singleton — наличие только одного экземпляра.
Кроме того, экземпляр может быть уже создан до этой проверки, но другие потоки могут не увидеть его сразу, если не принять меры для обеспечения корректной видимости.
Как сделать реализацию потокобезопасной?
Один из распространённых способов — использование блокировки (locking), например, с применением double-check locking (двойной проверки).
Однако это сложный способ, и при неправильной реализации может привести к ошибкам.
Какое решение лучше?
На мой взгляд, универсального «лучшего» решения нет — всё зависит от конкретной ситуации. Мне нравится и я рекомендую использовать Lazy.
Вот как можно реализовать паттерн Singleton с использованием Lazy:
>
>
>
Такой подход рекомендуется в современной разработке на C#, поскольку он использует встроенные возможности .NET Framework для безопасной инициализации в многопоточной среде.🙂
👉 @KodBlog
Как реализовать потокобезопасный синглтон?
Две нити (потока) могут одновременно проверить, является ли экземпляр null, и обе получат true.
В результате каждая из них создаст собственный экземпляр, что нарушает основное правило паттерна Singleton — наличие только одного экземпляра.
Кроме того, экземпляр может быть уже создан до этой проверки, но другие потоки могут не увидеть его сразу, если не принять меры для обеспечения корректной видимости.
Как сделать реализацию потокобезопасной?
Один из распространённых способов — использование блокировки (locking), например, с применением double-check locking (двойной проверки).
Однако это сложный способ, и при неправильной реализации может привести к ошибкам.
Какое решение лучше?
На мой взгляд, универсального «лучшего» решения нет — всё зависит от конкретной ситуации. Мне нравится и я рекомендую использовать Lazy.
Вот как можно реализовать паттерн Singleton с использованием Lazy:
>
Lazy Initialization:
Класс Lazy автоматически управляет отложенной инициализацией экземпляра Singleton. Экземпляр создаётся только при первом обращении.>
Потокобезопасность:
Lazy обеспечивает создание экземпляра в потокобезопасном режиме, поэтому нет необходимости использовать блокировки или double-check locking вручную.>
Простота и сопровождаемость:
Код становится проще и легче поддерживать, так как вся логика синхронизации инкапсулирована внутри Lazy.Такой подход рекомендуется в современной разработке на C#, поскольку он использует встроенные возможности .NET Framework для безопасной инициализации в многопоточной среде.
Please open Telegram to view this post
VIEW IN TELEGRAM
Внедрение настроек в .NET? Существует три основных интерфейса:
>
>
>
Используйте
Подробнее о том, как работает паттерн Options и когда какой интерфейс использовать: read
👉 @KodBlog
>
IOptions:
кэшируется на всё время жизни приложения>
IOptionsSnapshot:
переоценивается при каждом запросе (scoped)>
IOptionsMonitor:
позволяет получать текущее значение и реагировать на измененияИспользуйте
IOptions
для статической конфигурации, IOptionsSnapshot
— в веб-приложениях, где конфигурация может меняться между запросами, а IOptionsMonitor
— когда нужно отслеживать изменения настроек.Подробнее о том, как работает паттерн Options и когда какой интерфейс использовать: read
Please open Telegram to view this post
VIEW IN TELEGRAM
EF Core:
👉 @KodBlog
DbContextOptionsBuilder
используется для настройки DbContext
, как показано в примере для консольного проекта. Также он может применяться вместе с внедрением зависимостей (dependency injection)Please open Telegram to view this post
VIEW IN TELEGRAM
Ставить точку или не ставить точку в сообщениях об исключениях? 👀
Байкшеддинг (bikeshedding) — большая проблема в нашей сфере.
Что такое "Bikeshedding"?
"Bikeshedding" — это феномен, также известный как закон тривиальности Паркинсона, при котором в организации несоразмерно много внимания уделяется незначительным вопросам. Это часто происходит на встречах: сложные темы быстро проходят без обсуждения (из-за нехватки знаний), а простые и понятные, вроде оформления сообщений об ошибках вызывают долгие споры.
Термин введён в книге Паркинсона "Law of Triviality". В ней описывается вымышленный комитет, обсуждающий проект ядерного реактора. Технические детали реактора одобряются без вопросов, никто не понимает их глубоко. А вот над проектом велосипедного сарая (bike shed) ведутся долгие дебаты: это всем понятно, каждый хочет высказаться.
Вот типичные примеры bikeshedding в разработке ПО — темы, на которые часто тратится непропорционально много времени, хотя они имеют минимальное влияние на результат:
Стиль кода и форматирование
> Tabs vs. spaces (табуляция или пробелы)
> Максимальная длина строки
> Расположение фигурных скобок {}
> Стиль комментариев и выравнивание docstring'ов
> Формат именования переменных (
Выборы в UI-дизайне
> Цвет кнопки или текст (“Отправить” vs “Отослать”)
> Пиксельная точность отступов
> Выбор иконки или шрифта
> Как открывать модалку — слайдом или затуханием
Структура проекта / имена файлов
> Где разместить папку utils
> Куда класть services — в Services/ или Domain/
> PascalCase vs kebab-case для файлов
Инструменты и конфигурация
> Что выбрать: ESLint или Prettier (или оба)
> Нужно ли требовать запятую в конце в массиве
> Какой task runner использовать: npm scripts или Gulp
Конвенции тестирования
> Формат имён тестов (*.test.js vs *.spec.js)
> Использовать Moq или NSubstitute
> Хранить тесты рядом с кодом или в папке tests/
Выбор зависимостей (при равной приемлемости)
> Axios или Fetch API
> EF Core или Dapper для CRUD
> Redux или Zustand в простом фронте
Технический педантизм
> Оверинжиниринг мелкой фичи "на будущее"
> Дебаты: функциональный подход или ООП в хелпере
> Внедрение шаблона проектирования там, где он не нужен
👉 @KodBlog
Байкшеддинг (bikeshedding) — большая проблема в нашей сфере.
Что такое "Bikeshedding"?
"Bikeshedding" — это феномен, также известный как закон тривиальности Паркинсона, при котором в организации несоразмерно много внимания уделяется незначительным вопросам. Это часто происходит на встречах: сложные темы быстро проходят без обсуждения (из-за нехватки знаний), а простые и понятные, вроде оформления сообщений об ошибках вызывают долгие споры.
Термин введён в книге Паркинсона "Law of Triviality". В ней описывается вымышленный комитет, обсуждающий проект ядерного реактора. Технические детали реактора одобряются без вопросов, никто не понимает их глубоко. А вот над проектом велосипедного сарая (bike shed) ведутся долгие дебаты: это всем понятно, каждый хочет высказаться.
Вот типичные примеры bikeshedding в разработке ПО — темы, на которые часто тратится непропорционально много времени, хотя они имеют минимальное влияние на результат:
Стиль кода и форматирование
> Tabs vs. spaces (табуляция или пробелы)
> Максимальная длина строки
> Расположение фигурных скобок {}
> Стиль комментариев и выравнивание docstring'ов
> Формат именования переменных (
user_id
vs userId
)Выборы в UI-дизайне
> Цвет кнопки или текст (“Отправить” vs “Отослать”)
> Пиксельная точность отступов
> Выбор иконки или шрифта
> Как открывать модалку — слайдом или затуханием
Структура проекта / имена файлов
> Где разместить папку utils
> Куда класть services — в Services/ или Domain/
> PascalCase vs kebab-case для файлов
Инструменты и конфигурация
> Что выбрать: ESLint или Prettier (или оба)
> Нужно ли требовать запятую в конце в массиве
> Какой task runner использовать: npm scripts или Gulp
Конвенции тестирования
> Формат имён тестов (*.test.js vs *.spec.js)
> Использовать Moq или NSubstitute
> Хранить тесты рядом с кодом или в папке tests/
Выбор зависимостей (при равной приемлемости)
> Axios или Fetch API
> EF Core или Dapper для CRUD
> Redux или Zustand в простом фронте
Технический педантизм
> Оверинжиниринг мелкой фичи "на будущее"
> Дебаты: функциональный подход или ООП в хелпере
> Внедрение шаблона проектирования там, где он не нужен
Please open Telegram to view this post
VIEW IN TELEGRAM