6 ошибок в EF Core queries, которые кажутся безобидными в development, но дорого обходятся в production:
• Фильтры, которые не позволяют эффективно использовать indexes
• Загрузка целых entities, когда нужны всего несколько columns
• Result sets, которые растут без каких-либо ограничений
• Загрузка связанных данных, приводящая к N+1 queries или огромным
Буферизация тысяч строк, когда данные можно обрабатывать через streaming
Tracking entities, которые вы не собираетесь обновлять
В статье каждый пункт разобран на примерах: компромиссы разных подходов и то, что стоит проверять в первую очередь, когда EF Core endpoint начинает тормозить.
Полная статья здесь
👉 @KodBlog
• Фильтры, которые не позволяют эффективно использовать indexes
• Загрузка целых entities, когда нужны всего несколько columns
• Result sets, которые растут без каких-либо ограничений
• Загрузка связанных данных, приводящая к N+1 queries или огромным
JOINБуферизация тысяч строк, когда данные можно обрабатывать через streaming
Tracking entities, которые вы не собираетесь обновлять
В статье каждый пункт разобран на примерах: компромиссы разных подходов и то, что стоит проверять в первую очередь, когда EF Core endpoint начинает тормозить.
Полная статья здесь
Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🍾1
Одна из самых крутых возможностей .NET, о которой почти никто не говорит:
→ Channels
Найти их можно в namespace
Channels позволяют организовать асинхронный обмен сообщениями с помощью простого C#-кода. Они предоставляют два основных API:
• для записи сообщений в channel
• для асинхронного чтения сообщений из channel
В background можно запустить worker, который будет забирать сообщения из channel и отправлять их на дальнейшую обработку.
Например, на основе Channels можно реализовать простой in-memory message bus — разумеется, со всеми ограничениями такого подхода.
Пример реализации: https://milanjovanovic.tech/blog/lightweight-in-memory-message-bus-using-dotnet-channels
👉 @KodBlog
→ Channels
Найти их можно в namespace
System.Threading.Channels.Channels позволяют организовать асинхронный обмен сообщениями с помощью простого C#-кода. Они предоставляют два основных API:
• для записи сообщений в channel
• для асинхронного чтения сообщений из channel
В background можно запустить worker, который будет забирать сообщения из channel и отправлять их на дальнейшую обработку.
Например, на основе Channels можно реализовать простой in-memory message bus — разумеется, со всеми ограничениями такого подхода.
Пример реализации: https://milanjovanovic.tech/blog/lightweight-in-memory-message-bus-using-dotnet-channels
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾1
Нужно получить ID авторизованного пользователя в Web API?
(При условии, что User ID был добавлен как claim при генерации token.)
✔️ Создайте интерфейс
✔️ Реализуйте его для получения ID из claims
✔️ Зарегистрируйте зависимости
✔️ Внедрите
👉 @KodBlog
(При условии, что User ID был добавлен как claim при генерации token.)
✔️ Создайте интерфейс
IUser✔️ Реализуйте его для получения ID из claims
✔️ Зарегистрируйте зависимости
✔️ Внедрите
IUser и получайте ID пользователя в нужном месте приложенияPlease open Telegram to view this post
VIEW IN TELEGRAM
👍6🍾1
Я встречаю этот code smell почти в каждом production-коде, который приходится разбирать.
→ Magic numbers и magic strings.
Главная проблема таких значений — отсутствие смысла. Это просто произвольное число или строка, из которых непонятно, что именно они означают. Из-за этого код сложнее понимать и проще сломать. Что разработчики могут сделать, чтобы добавить смысл?
Мой предпочтительный вариант — вынести значение в config или использовать enum. То есть дать magic number или string понятное имя.
Имя уже объясняет намерение кода и делает его гораздо проще для понимания. Это лишь один из способов сделать код чище.
Сегодня Clean Code Sunday, поэтому вот ещё 5 советов по рефакторингу C#: 5 Awesome C# Refactoring Tips
👉 @KodBlog
→ Magic numbers и magic strings.
Главная проблема таких значений — отсутствие смысла. Это просто произвольное число или строка, из которых непонятно, что именно они означают. Из-за этого код сложнее понимать и проще сломать. Что разработчики могут сделать, чтобы добавить смысл?
Мой предпочтительный вариант — вынести значение в config или использовать enum. То есть дать magic number или string понятное имя.
Имя уже объясняет намерение кода и делает его гораздо проще для понимания. Это лишь один из способов сделать код чище.
Сегодня Clean Code Sunday, поэтому вот ещё 5 советов по рефакторингу C#: 5 Awesome C# Refactoring Tips
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🍾1
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2❤1
Clean Code — это не про то, чтобы писать больше кода.
Это про то, чтобы делать код понятнее, проще для тестирования и поддержки. Вот 5 практических советов по Clean Code для .NET-разработчиков:
1/ Давайте понятные имена
Код должен объяснять себя сам и не требовать лишних комментариев.
2/ Старайтесь не возвращать
Так можно сократить количество постоянных null checks и снизить риск
3/ Делайте классы и методы небольшими
Разделяйте ответственности, чтобы код было проще понимать, тестировать и поддерживать.
4/ Не изобретайте велосипед
Используйте готовые abstractions и libraries из .NET вместо того, чтобы заново решать уже решённые задачи.
5/ Используйте подходящие инструменты и IDE
Освойте возможности своей IDE, а для единообразия между проектами используйте
👉 @KodBlog
Это про то, чтобы делать код понятнее, проще для тестирования и поддержки. Вот 5 практических советов по Clean Code для .NET-разработчиков:
1/ Давайте понятные имена
Код должен объяснять себя сам и не требовать лишних комментариев.
2/ Старайтесь не возвращать
nullТак можно сократить количество постоянных null checks и снизить риск
NullReferenceException.3/ Делайте классы и методы небольшими
Разделяйте ответственности, чтобы код было проще понимать, тестировать и поддерживать.
4/ Не изобретайте велосипед
Используйте готовые abstractions и libraries из .NET вместо того, чтобы заново решать уже решённые задачи.
5/ Используйте подходящие инструменты и IDE
Освойте возможности своей IDE, а для единообразия между проектами используйте
.editorconfig и общие .props файлы.Please open Telegram to view this post
VIEW IN TELEGRAM
❤5🍾1
Распространённая ошибка в software architecture, которую я часто встречаю:
→ Код организован без учёта бизнес-задач и частоты изменений.
К счастью, Vertical Slice Architecture (VSA) решает эту проблему довольно просто. Вместо разделения приложения на горизонтальные layers, VSA организует код вокруг конкретных features или use cases.
Почему это важно?
• Такой подход даёт несколько преимуществ:
• Повышает cohesion
• Упрощает поддержку
• Снижает общую сложность
• Фокусирует код на business logic
Вот с чего можно начать: https://milanjovanovic.tech/blog/vertical-slice-architecture-structuring-vertical-slices
👉 @KodBlog
→ Код организован без учёта бизнес-задач и частоты изменений.
К счастью, Vertical Slice Architecture (VSA) решает эту проблему довольно просто. Вместо разделения приложения на горизонтальные layers, VSA организует код вокруг конкретных features или use cases.
Почему это важно?
• Такой подход даёт несколько преимуществ:
• Повышает cohesion
• Упрощает поддержку
• Снижает общую сложность
• Фокусирует код на business logic
Вот с чего можно начать: https://milanjovanovic.tech/blog/vertical-slice-architecture-structuring-vertical-slices
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍2🍾1
17 ключевых слов C#, которые стоит запомнить
1/
2/
3/
4/
5/
6/
7/
8/
9/
10/
11/
12/
13/
14/
15/
16/
17/
👉 @KodBlog
1/
static — принадлежит самому типу, а не конкретному экземпляру.2/
const — определяет константное значение, известное на этапе компиляции.3/
readonly — значение можно присвоить только при объявлении или в конструкторе.4/
async / await — используются для написания асинхронного кода без блокировки потока во время ожидания.5/
yield — упрощает создание итераторов, возвращая значения по мере их запроса.6/
ref — передаёт переменную по ссылке, позволяя методу изменять её.7/
out — передаёт переменную по ссылке, при этом вызываемый метод должен присвоить ей значение.8/
params — позволяет методу принимать переменное количество аргументов.9/
is / as — используются для проверки типа и безопасного приведения типов.10/
lock — обеспечивает эксклюзивный доступ к критической секции в многопоточном коде.11/
base — предоставляет доступ к членам и конструкторам базового класса.12/
this — ссылается на текущий экземпляр.13/
new — создаёт объект или скрывает унаследованный член.14/
abstract — определяет классы или члены, предназначенные для реализации в производных типах.15/
sealed — запрещает наследование от класса.16/
override — предоставляет новую реализацию унаследованного virtual-члена.17/
partial — позволяет разделить определение типа между несколькими файлами.Please open Telegram to view this post
VIEW IN TELEGRAM
❤6🍾1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3🍾1
Не отставайте от рынка — учитесь со скидкой 16%
Если чувствуете, что стоите на месте, и хотите освоить востребованную профессию, — сейчас хороший момент начать.
Потому что до 30 сентября на все курсы Практикума действует скидка 16%.
Выбрать курс
Вы сможете:
— получить актуальные навыки;
— освоить ИИ-инструменты для работы;
— перенять опыт экспертов, которые двигают индустрию;
— попасть в сообщество выпускников, где можно попросить совета и, возможно, найти будущих коллег.
Просто выберите курс, начните учиться бесплатно и получите скидку 16% — она автоматически появится в личном кабинете.
Учиться!
Erid: 2SDnjePZCP5
Название: ООО "ЯНДЕКС"
ИНН: 7736207543
Если чувствуете, что стоите на месте, и хотите освоить востребованную профессию, — сейчас хороший момент начать.
Потому что до 30 сентября на все курсы Практикума действует скидка 16%.
Выбрать курс
Вы сможете:
— получить актуальные навыки;
— освоить ИИ-инструменты для работы;
— перенять опыт экспертов, которые двигают индустрию;
— попасть в сообщество выпускников, где можно попросить совета и, возможно, найти будущих коллег.
Просто выберите курс, начните учиться бесплатно и получите скидку 16% — она автоматически появится в личном кабинете.
Учиться!
Erid: 2SDnjePZCP5
Название: ООО "ЯНДЕКС"
ИНН: 7736207543
❤1
В .NET можно использовать Wolverine как Mediator, не создавая отдельные handler interfaces для каждого request.
Вот как это настраивается:
1/ Установите Wolverine
Добавьте пакет Wolverine в проект.
2/ Зарегистрируйте Wolverine
Настройте Wolverine при конфигурации приложения.
3/ Создайте Request
Определите request как обычный
4/ Создайте Handler
Добавьте метод
5/ Вызовите из Endpoint
Внедрите
6/ Wolverine обработает весь flow
В результате получается чистый request/response flow с меньшим количеством boilerplate, связанного с Mediator pattern.
При этом возможности Wolverine не ограничиваются mediation: он также поддерживает asynchronous messaging, durable messaging, scheduled delivery, retries, sagas и transactional messaging.
👉 @KodBlog
Вот как это настраивается:
1/ Установите Wolverine
Добавьте пакет Wolverine в проект.
2/ Зарегистрируйте Wolverine
Настройте Wolverine при конфигурации приложения.
3/ Создайте Request
Определите request как обычный
record или class. Специальный mediator interface не требуется.4/ Создайте Handler
Добавьте метод
Handle. Wolverine сам найдёт подходящий handler по conventions.5/ Вызовите из Endpoint
Внедрите
IMessageBus и отправьте request из API endpoint.6/ Wolverine обработает весь flow
Endpoint → Request → Wolverine → Handler → ResponseВ результате получается чистый request/response flow с меньшим количеством boilerplate, связанного с Mediator pattern.
При этом возможности Wolverine не ограничиваются mediation: он также поддерживает asynchronous messaging, durable messaging, scheduled delivery, retries, sagas и transactional messaging.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4❤3🍾1
Я попросил AI-ассистента написать всего один метод.
В итоге он принял за меня с десяток решений — и ни об одном не предупредил.
Промпт был простым: «Получи заказы для списка пользователей». В ответ я получил 10 строк аккуратного C#-кода. Всё компилировалось. Тесты проходили. Казалось, всё отлично.
А потом я внимательно посмотрел на код. Вот какие решения AI молча принял за меня:
• Новый
• Нет timeout
• Нет retries
• Нет ограничения на количество параллельных requests
• Нет cancellation
• Нет logging и tracing
• Ошибка для одного пользователя ломает весь batch
Сегодня ни один из этих пунктов не выглядит как явный bug. На моей машине всё работает. Но каждый из них может стать проблемой в production. Поэтому я это исправил.
👉 @KodBlog
В итоге он принял за меня с десяток решений — и ни об одном не предупредил.
Промпт был простым: «Получи заказы для списка пользователей». В ответ я получил 10 строк аккуратного C#-кода. Всё компилировалось. Тесты проходили. Казалось, всё отлично.
А потом я внимательно посмотрел на код. Вот какие решения AI молча принял за меня:
• Новый
HttpClient при каждом вызове• Нет timeout
• Нет retries
• Нет ограничения на количество параллельных requests
• Нет cancellation
• Нет logging и tracing
• Ошибка для одного пользователя ломает весь batch
Сегодня ни один из этих пунктов не выглядит как явный bug. На моей машине всё работает. Но каждый из них может стать проблемой в production. Поэтому я это исправил.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6❤2😐2👌1🍾1
На дворе 2026 год, а вы всё ещё не используете OpenTelemetry?
Вот как он может упростить жизнь software engineer. Если вам важна observability, стоит знать про OpenTelemetry.
Это vendor-neutral open-source стандарт для инструментирования приложений и сбора telemetry data.
Если проще — речь про:
• Logs
• Traces
• Metrics
Работает ли это с .NET? Да. Для .NET есть несколько библиотек, которые достаточно легко интегрировать в приложение.
Вот простой гайд, с которого можно начать знакомство: https://milanjovanovic.tech/blog/introduction-to-distributed-tracing-with-opentelemetry-in-dotnet
👉 @KodBlog
Вот как он может упростить жизнь software engineer. Если вам важна observability, стоит знать про OpenTelemetry.
Это vendor-neutral open-source стандарт для инструментирования приложений и сбора telemetry data.
Если проще — речь про:
• Logs
• Traces
• Metrics
Работает ли это с .NET? Да. Для .NET есть несколько библиотек, которые достаточно легко интегрировать в приложение.
Вот простой гайд, с которого можно начать знакомство: https://milanjovanovic.tech/blog/introduction-to-distributed-tracing-with-opentelemetry-in-dotnet
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2
Ваш .NET API отлично работает локально. Но это ещё не значит, что он готов к продакшену.
Перед релизом я проверяю 8 вещей, которые помогают избежать множества проблем в будущем: наблюдаемость, CORS, документацию API, версионирование, хранение данных, обработку ошибок, проверки работоспособности и ограничение частоты запросов.
В статье я разобрал, что важно в каждом пункте, почему это имеет значение и как всё настроить на практике в .NET.
Полная статья: https://mwaseemzakir.substack.com/p/before-your-net-api-goes-to-production
👉 @KodBlog
Перед релизом я проверяю 8 вещей, которые помогают избежать множества проблем в будущем: наблюдаемость, CORS, документацию API, версионирование, хранение данных, обработку ошибок, проверки работоспособности и ограничение частоты запросов.
В статье я разобрал, что важно в каждом пункте, почему это имеет значение и как всё настроить на практике в .NET.
Полная статья: https://mwaseemzakir.substack.com/p/before-your-net-api-goes-to-production
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🍾1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤4🍾1
Когда мне нужна функциональность в реальном времени, я выбираю проверенное решение:
→ SignalR
SignalR позволяет добавить взаимодействие в реальном времени в .NET-приложения. При этом клиент может быть написан на React, Angular или обычном JavaScript.
Вы создаёте класс SignalR Hub. Это центральный компонент приложения, который управляет клиентскими подключениями и обменом сообщениями. Клиенты подключаются к Hub, чтобы отправлять и получать сообщения, поэтому связь может быть двусторонней.
SignalR скрывает детали транспортного механизма. Обычно используется WebSockets, но при необходимости библиотека может переключиться на Server-Sent Events или опрос сервера.
Всё, что нужно для начала: статья.
SignalR определённо входит в число лучших библиотек экосистемы .NET.
👉 @KodBlog
→ SignalR
SignalR позволяет добавить взаимодействие в реальном времени в .NET-приложения. При этом клиент может быть написан на React, Angular или обычном JavaScript.
Вы создаёте класс SignalR Hub. Это центральный компонент приложения, который управляет клиентскими подключениями и обменом сообщениями. Клиенты подключаются к Hub, чтобы отправлять и получать сообщения, поэтому связь может быть двусторонней.
SignalR скрывает детали транспортного механизма. Обычно используется WebSockets, но при необходимости библиотека может переключиться на Server-Sent Events или опрос сервера.
Всё, что нужно для начала: статья.
SignalR определённо входит в число лучших библиотек экосистемы .NET.
Please open Telegram to view this post
VIEW IN TELEGRAM
❤7🔥1🍾1
Please open Telegram to view this post
VIEW IN TELEGRAM
❤3👍3👎3🍾1
Ваш API входа раскрывает злоумышленникам, у кого есть аккаунт?
Распространённая ошибка: Если email не существует, возвращать «Пользователь не найден». Если пароль неверный, возвращать «Неверные учётные данные».
Это уязвимость, позволяющая перебирать учётные записи. Любой может отправить список email-адресов в ваш API и точно узнать, какие из них зарегистрированы, даже не пытаясь подобрать пароль.
Обычное исправление: всегда возвращать «Неверные учётные данные», независимо от причины ошибки. Хорошее начало. Но есть второй канал утечки, который многие упускают.
Когда пользователя не существует, вы пропускаете проверку пароля и быстро возвращаете ответ. Когда пользователь существует, вы обрабатываете введённый пароль с помощью bcrypt или Argon2, а это занимает ощутимое время.
Сообщение одинаковое. Время ответа разное. Злоумышленник просто измеряет миллисекунды и составляет тот же список зарегистрированных аккаунтов, используя секундомер вместо текста ошибки.
Вот как закрыть эту брешь:
Хешируйте фиктивный пароль, даже если пользователь не существует, чтобы обе ветки обработки занимали одинаковое время.
Для фиктивной проверки используйте тот же алгоритм и параметр вычислительной сложности, что и для реальных пользователей.
В дополнение к фиктивному хешированию установите фиксированную минимальную длительность ответа.
Ограничивайте попытки входа по IP и по учётной записи, чтобы атаки по времени становились слишком медленными и невыгодными.
👉 @KodBlog
Распространённая ошибка: Если email не существует, возвращать «Пользователь не найден». Если пароль неверный, возвращать «Неверные учётные данные».
Это уязвимость, позволяющая перебирать учётные записи. Любой может отправить список email-адресов в ваш API и точно узнать, какие из них зарегистрированы, даже не пытаясь подобрать пароль.
Обычное исправление: всегда возвращать «Неверные учётные данные», независимо от причины ошибки. Хорошее начало. Но есть второй канал утечки, который многие упускают.
Когда пользователя не существует, вы пропускаете проверку пароля и быстро возвращаете ответ. Когда пользователь существует, вы обрабатываете введённый пароль с помощью bcrypt или Argon2, а это занимает ощутимое время.
Сообщение одинаковое. Время ответа разное. Злоумышленник просто измеряет миллисекунды и составляет тот же список зарегистрированных аккаунтов, используя секундомер вместо текста ошибки.
Вот как закрыть эту брешь:
Хешируйте фиктивный пароль, даже если пользователь не существует, чтобы обе ветки обработки занимали одинаковое время.
Для фиктивной проверки используйте тот же алгоритм и параметр вычислительной сложности, что и для реальных пользователей.
В дополнение к фиктивному хешированию установите фиксированную минимальную длительность ответа.
Ограничивайте попытки входа по IP и по учётной записи, чтобы атаки по времени становились слишком медленными и невыгодными.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍7🔥2🍾1
Если вы используете ИИ-агентов для написания кода, стоит разобраться в архитектурном тестировании.
Вот почему.
Архитектурные тесты помогают контролировать технический долг. Он возникает, когда скорость разработки ставят выше продуманной структуры кода. А ИИ-агенты выдают код быстрее, чем мы с вами когда-либо смогли бы.
С помощью архитектурных тестов можно контролировать:
• Направление зависимостей.
• Соглашения об именовании.
• Различные правила проектирования.
Подробное руководство, которое, думаю, вам понравится: читать статью.
Можно даже объяснить агенту правила вашей архитектуры, и он напишет тесты для проверки их соблюдения. Затем достаточно запускать эти тесты в CI, чтобы гораздо быстрее выявлять нарушения.
Добавили бы такую проверку в свой процесс ревью кода?
👉 @KodBlog
Вот почему.
Архитектурные тесты помогают контролировать технический долг. Он возникает, когда скорость разработки ставят выше продуманной структуры кода. А ИИ-агенты выдают код быстрее, чем мы с вами когда-либо смогли бы.
С помощью архитектурных тестов можно контролировать:
• Направление зависимостей.
• Соглашения об именовании.
• Различные правила проектирования.
Подробное руководство, которое, думаю, вам понравится: читать статью.
Можно даже объяснить агенту правила вашей архитектуры, и он напишет тесты для проверки их соблюдения. Затем достаточно запускать эти тесты в CI, чтобы гораздо быстрее выявлять нарушения.
Добавили бы такую проверку в свой процесс ревью кода?
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2🍾1
Можете найти ошибку в этом фрагменте кода?
Второй пример вставляет 10 000 записей в базу данных в 43 раза быстрее. Откуда такая огромная разница в производительности?
Код в обоих примерах выглядит похоже. Но если понимать, как EF работает под капотом, ответ становится очевидным.
Каждый вызов
Вот как правильно решить эту задачу: читать статью.
Лишние запросы к БД — одна из главных причин падения производительности. Не допускайте этой ошибки в своём коде.
👉 @KodBlog
Второй пример вставляет 10 000 записей в базу данных в 43 раза быстрее. Откуда такая огромная разница в производительности?
Код в обоих примерах выглядит похоже. Но если понимать, как EF работает под капотом, ответ становится очевидным.
Каждый вызов
SaveChanges означает обращение к базе данных. В первом примере для вставки каждой записи выполняется отдельный вызов. И накладные расходы быстро накапливаются…Вот как правильно решить эту задачу: читать статью.
Лишние запросы к БД — одна из главных причин падения производительности. Не допускайте этой ошибки в своём коде.
Please open Telegram to view this post
VIEW IN TELEGRAM
😐4🍾4❤3😁2
Интерактивные курсы по Git
GitHub запустила cборку онлайн курсов, где можно прокачать навыки работы с Git и GitHub бесплатно. Ветки, коммиты, pull request’ы, Actions и реальные командные сценарии.
Быстрый и лёгкий способ подтянуть базу и перестать гуглить «как откатить коммит» в неподходящий момент.
👉 @KodBlog
GitHub запустила cборку онлайн курсов, где можно прокачать навыки работы с Git и GitHub бесплатно. Ветки, коммиты, pull request’ы, Actions и реальные командные сценарии.
Быстрый и лёгкий способ подтянуть базу и перестать гуглить «как откатить коммит» в неподходящий момент.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2