🚫 EF Core + «репозитории» = лишний слой
Часто советуют заворачивать EF Core в Repository Pattern.
Но на практике это делает код только сложнее:
-
- Репозитории со временем превращаются в «монстров» с десятками методов
- Каждый новый фильтр = новая копипаста
В итоге — абстракция над абстракцией и трудности с поддержкой.
---
✅ Что вместо этого? Specification Pattern
Specification = маленький класс, описывающий правило или фильтр.
Вы комбинируете их и получаете сложные запросы без раздутых репозиториев.
Плюсы:
- 🧩 Простая композиция правил
- 🔍 Ясный и читаемый код
- ♻️ Повторное использование условий
- 🧪 Лёгкое тестирование
📌 Пример
💡 Итог:
EF Core = уже Repository + UoW
Репозитории поверх EF Core → лишняя абстракция
Specification Pattern → гибкость и читаемость без «метод-монстров»
Часто советуют заворачивать EF Core в Repository Pattern.
Но на практике это делает код только сложнее:
-
DbContext уже реализует Repository и Unit of Work - Репозитории со временем превращаются в «монстров» с десятками методов
- Каждый новый фильтр = новая копипаста
В итоге — абстракция над абстракцией и трудности с поддержкой.
---
✅ Что вместо этого? Specification Pattern
Specification = маленький класс, описывающий правило или фильтр.
Вы комбинируете их и получаете сложные запросы без раздутых репозиториев.
Плюсы:
- 🧩 Простая композиция правил
- 🔍 Ясный и читаемый код
- ♻️ Повторное использование условий
- 🧪 Лёгкое тестирование
📌 Пример
// Бизнес-правило: активные клиенты с заказами за последние 30 дней
public sealed class ActiveCustomersSpec : Specification<Customer>
{
public ActiveCustomersSpec(DateTime since)
{
Criteria = c => c.IsActive && c.Orders.Any(o => o.CreatedAt >= since);
AddInclude(c => c.Orders);
}
}
// Применение
var spec = new ActiveCustomersSpec(DateTime.UtcNow.AddDays(-30));
var customers = await db.Set<Customer>().Apply(spec).ToListAsync();
💡 Итог:
EF Core = уже Repository + UoW
Репозитории поверх EF Core → лишняя абстракция
Specification Pattern → гибкость и читаемость без «метод-монстров»
Forwarded from StepOne | Степан Минин
Serilog.Sinks.XUnit3 👩💻
Пришло время рассказывать про свои библиотеки!
Каждый на работе сталкивался с непонятным багом. Смотришь в код и видишь фигу)
А чтобы разобраться в проблеме надо сидеть часами в медленном отладчике и поднимать ворох окружения, чтобы отследить одно единственное значение...
Логгирование призвано помочь разрабу справиться со страданиями, но вот незадача! При запуске интеграционного теста с воспроизведением бага логи никуда не выводятся.
Поэтому я написал Serilog.Sinks.XUnit3!
Чтобы не выходя из IDE разработчик понимал, что происходит!
Призываю вас делится этой библиотекой и внедрять в свои тесты!
👩💻 GitHub: https://github.com/Stepami/serilog-sinks-xunit-v3
👩💻 NuGet: https://www.nuget.org/packages/Serilog.Sinks.XUnit3
Пришло время рассказывать про свои библиотеки!
Если вы пишете тесты на xUnit.v3 и логгируете через Serilog, то моё решение для вас!
Каждый на работе сталкивался с непонятным багом. Смотришь в код и видишь фигу)
А чтобы разобраться в проблеме надо сидеть часами в медленном отладчике и поднимать ворох окружения, чтобы отследить одно единственное значение...
Логгирование призвано помочь разрабу справиться со страданиями, но вот незадача! При запуске интеграционного теста с воспроизведением бага логи никуда не выводятся.
Поэтому я написал Serilog.Sinks.XUnit3!
Чтобы не выходя из IDE разработчик понимал, что происходит!
Призываю вас делится этой библиотекой и внедрять в свои тесты!
Please open Telegram to view this post
VIEW IN TELEGRAM
📝 TodoList gRPC: Упрощённый бэкенд для собеседований
Этот репозиторий представляет собой облегчённый форк проекта, созданного для проверки навыков кандидатов на собеседованиях. Он предоставляет чистый и компактный бэкенд на основе gRPC и ASP.NET, который используется для создания простого фронтенда, взаимодействующего с API.
🚀 Основные моменты:
- Легковесный бэкенд на C# и ASP.NET Core.
- Использует gRPC для взаимодействия с фронтендом.
- Поддерживает различные клиентские фреймворки.
- Идеален для технических собеседований и оценки навыков.
📌 GitHub: https://github.com/Steffen70/todolist-grpc
@csharp_ci
Этот репозиторий представляет собой облегчённый форк проекта, созданного для проверки навыков кандидатов на собеседованиях. Он предоставляет чистый и компактный бэкенд на основе gRPC и ASP.NET, который используется для создания простого фронтенда, взаимодействующего с API.
🚀 Основные моменты:
- Легковесный бэкенд на C# и ASP.NET Core.
- Использует gRPC для взаимодействия с фронтендом.
- Поддерживает различные клиентские фреймворки.
- Идеален для технических собеседований и оценки навыков.
📌 GitHub: https://github.com/Steffen70/todolist-grpc
@csharp_ci
🚀 Git Pro совет
Хотите быстро узнать, какие файлы менялись чаще всего в репозитории?
Используйте встроенные возможности
💡 Отличный способ найти "проблемные" файлы:
именно они чаще всего требуют правок и могут быть источником багов.
Хотите быстро узнать, какие файлы менялись чаще всего в репозитории?
Используйте встроенные возможности
git log:
# Топ-10 самых часто меняемых файлов
git log --pretty=format: --name-only | \
sort | uniq -c | sort -nr | head -10
💡 Отличный способ найти "проблемные" файлы:
именно они чаще всего требуют правок и могут быть источником багов.
Что выведет на экран этот код?
Anonymous Quiz
15%
False, False
14%
False, True
30%
True, True
34%
True, False
6%
Better Database Design 💡
Чтобы повысить безопасность и упростить управление доступом, используйте логическую изоляцию с помощью схем.
Пример: создаём отдельную схему и выделяем для неё пользователя, у которого доступ только к своей области данных.
⚡ Идея проста:
Создавайте отдельного пользователя для каждой схемы и используйте разные connection string в приложении. Это уменьшает риски и делает архитектуру чище.
Чтобы повысить безопасность и упростить управление доступом, используйте логическую изоляцию с помощью схем.
Пример: создаём отдельную схему и выделяем для неё пользователя, у которого доступ только к своей области данных.
CREATE SCHEMA Orders;
CREATE SCHEMA Shipping;
-- Orders module can only access its schema
CREATE USER OrdersUser WITH DEFAULT_SCHEMA = Orders;
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Orders TO OrdersUser;
-- Shipping module can only access its schema
CREATE USER ShippingUser WITH DEFAULT_SCHEMA = Shipping;
GRANT SELECT, INSERT, UPDATE, DELETE ON SCHEMA::Shipping TO ShippingUser;
⚡ Идея проста:
Создавайте отдельного пользователя для каждой схемы и используйте разные connection string в приложении. Это уменьшает риски и делает архитектуру чище.
🛡️ Запуск программ с защитой PPL
CreateProcessAsPPL — инструмент для запуска приложений с включенной защитой PPL. Позволяет выбирать уровень защиты для повышения безопасности выполнения программ.
🚀 Основные моменты:
- Поддержка нескольких уровней защиты PPL.
- Удобный интерфейс командной строки.
- Полезен для разработчиков и исследователей безопасности.
📌 GitHub: https://github.com/2x7EQ13/CreateProcessAsPPL
#csharp
CreateProcessAsPPL — инструмент для запуска приложений с включенной защитой PPL. Позволяет выбирать уровень защиты для повышения безопасности выполнения программ.
🚀 Основные моменты:
- Поддержка нескольких уровней защиты PPL.
- Удобный интерфейс командной строки.
- Полезен для разработчиков и исследователей безопасности.
📌 GitHub: https://github.com/2x7EQ13/CreateProcessAsPPL
#csharp
🔍 ZeroTrace: Утечка данных из браузеров и мониторинг клиентов
ZeroTrace — это мощный инструмент для сбора и анализа данных с удалённых клиентских машин. Он поддерживает извлечение паролей, куки и историю браузера, обеспечивая безопасность и эффективность работы.
🚀 Основные моменты:
- Извлечение паролей и куки из Chrome и других браузеров
- Реальное время мониторинга клиентов с анализом соединений
- Безопасная передача данных с шифрованием
- Поддержка различных операционных систем и браузеров
📌 GitHub: https://github.com/luis22d/ZeroTrace-Stealer-13-2026
#csharp
ZeroTrace — это мощный инструмент для сбора и анализа данных с удалённых клиентских машин. Он поддерживает извлечение паролей, куки и историю браузера, обеспечивая безопасность и эффективность работы.
🚀 Основные моменты:
- Извлечение паролей и куки из Chrome и других браузеров
- Реальное время мониторинга клиентов с анализом соединений
- Безопасная передача данных с шифрованием
- Поддержка различных операционных систем и браузеров
📌 GitHub: https://github.com/luis22d/ZeroTrace-Stealer-13-2026
#csharp
Что выведет на экран этот код?
Anonymous Quiz
23%
False False
15%
False True
36%
True True
8%
True False
18%
❌ Exceptions ≠ Errors
Многие разработчики путают эти понятия и проектируют приложения неправильно. Давайте разберём:
Что такое исключение (exception)?
Это ситуация, из которой приложение не может восстановиться.
Пример: критическая ошибка базы данных, повреждённый файл конфигурации.
Что такое ошибка (error)?
Это ожидаемое состояние сбоя или невыполненное предусловие.
Пример: пользователь ввёл неверный пароль, файл не найден, запрос не прошёл валидацию.
👉 Использовать исключения вместо ошибок = анти-паттерн. Так появляется flow control через исключения, который делает код непредсказуемым и запутанным.
Как правильно:
- Ошибки представляем явно в коде (например, через
- Исключения оставляем для действительно неожиданных и фатальных ситуаций.
Бонус: Явные ошибки делают намерения кода прозрачными и облегчают поддержку.
📖 Подробнее: https://milanjovanovic.tech/blog/functional-error-handling-in-dotnet-with-the-result-pattern
#dotnet #cleanCode #architecture
Многие разработчики путают эти понятия и проектируют приложения неправильно. Давайте разберём:
Что такое исключение (exception)?
Это ситуация, из которой приложение не может восстановиться.
Пример: критическая ошибка базы данных, повреждённый файл конфигурации.
Что такое ошибка (error)?
Это ожидаемое состояние сбоя или невыполненное предусловие.
Пример: пользователь ввёл неверный пароль, файл не найден, запрос не прошёл валидацию.
👉 Использовать исключения вместо ошибок = анти-паттерн. Так появляется flow control через исключения, который делает код непредсказуемым и запутанным.
Как правильно:
- Ошибки представляем явно в коде (например, через
Result, Option, Either паттерны). - Исключения оставляем для действительно неожиданных и фатальных ситуаций.
Бонус: Явные ошибки делают намерения кода прозрачными и облегчают поддержку.
📖 Подробнее: https://milanjovanovic.tech/blog/functional-error-handling-in-dotnet-with-the-result-pattern
#dotnet #cleanCode #architecture
В .NET 8 и выше есть библиотеки от Microsoft и обновлённый API Polly — популярной библиотеки для повышения надёжности и обработки сбоев.
С Polly можно легко настроить стратегии:
- повтор запросов (Retry)
- резервные сценарии (Fallback)
- ограничение времени (Timeout)
- контроль частоты (Rate-limiting)
- автоматическое отключение при сбоях (Circuit breaker)
Эти механизмы помогают облачным приложениям оставаться живыми даже в условиях ошибок и перегрузок.
Подробный разбор тут
Please open Telegram to view this post
VIEW IN TELEGRAM
@csharp_ci
Please open Telegram to view this post
VIEW IN TELEGRAM
🧪 Как правильно строить unit-тестирование в проектах с Clean Architecture
Милан Йованович делится опытом: многие проекты терпят неудачу из-за слабого тестирования.
Когда кодовая база растёт, каждое изменение становится рискованным, а уверенность команды в релизах падает.
В Clean Architecture тестируемость — одна из ключевых идей. Unit-тесты позволяют убедиться, что use cases работают так, как задумано требованиями.
📌 Подход Милана к unit-тестированию:
- использовать NSubstitute для моков зависимостей
- проверять все happy paths
- покрывать все failure paths
- обязательно тестировать обработку исключений
Такой набор тестов помогает сохранить надёжность логики и уверенность в изменениях.
✍️ Подробный разбор с пошаговым объяснением можно прочитать в его статье
Милан Йованович делится опытом: многие проекты терпят неудачу из-за слабого тестирования.
Когда кодовая база растёт, каждое изменение становится рискованным, а уверенность команды в релизах падает.
В Clean Architecture тестируемость — одна из ключевых идей. Unit-тесты позволяют убедиться, что use cases работают так, как задумано требованиями.
📌 Подход Милана к unit-тестированию:
- использовать NSubstitute для моков зависимостей
- проверять все happy paths
- покрывать все failure paths
- обязательно тестировать обработку исключений
Такой набор тестов помогает сохранить надёжность логики и уверенность в изменениях.
✍️ Подробный разбор с пошаговым объяснением можно прочитать в его статье
🛠️ Инструмент для дампа памяти защищённых процессов
WSASS использует старую программу WerfaultSecure.exe для создания дампов памяти процессов, защищённых PPL, таких как LSASS.EXE. Выходные данные сохраняются в формате MINIDUMP, с автоматической заменой заголовка на PNG для удобства.
🚀 Основные моменты:
- Дамп защищённых процессов с помощью WerfaultSecure.exe
- Выход в формате Windows MINIDUMP
- Автоматическая замена заголовка файла
- Полезен для анализа безопасности
📌 GitHub: https://github.com/TwoSevenOneT/WSASS
#csharp
WSASS использует старую программу WerfaultSecure.exe для создания дампов памяти процессов, защищённых PPL, таких как LSASS.EXE. Выходные данные сохраняются в формате MINIDUMP, с автоматической заменой заголовка на PNG для удобства.
🚀 Основные моменты:
- Дамп защищённых процессов с помощью WerfaultSecure.exe
- Выход в формате Windows MINIDUMP
- Автоматическая замена заголовка файла
- Полезен для анализа безопасности
📌 GitHub: https://github.com/TwoSevenOneT/WSASS
#csharp
GitHub
GitHub - TwoSevenOneT/WSASS: This is the tool to dump the LSASS process on modern Windows 11
This is the tool to dump the LSASS process on modern Windows 11 - TwoSevenOneT/WSASS
В какой строке возникнет ПЕРВАЯ ошибка
Anonymous Quiz
40%
1
29%
2
10%
3
2%
4
18%
ошибки не возникнет
🪄 magictools — curated-подборка инструментов и ресурсов для разработки игр
Если ты занимаешься геймдевом — этот репозиторий настоящий клад для поиска подходящих инструментов! Вот что внутри:
- Графика: от placeholders до редакторов и генераторов персонажей
- Spritesheets и анимация: инструменты для упаковки и обработки
- Фреймворки и движки: 2D/3D, физика, GUI, звук, освещение, генерация ландшафта и кастомные пайплайны
- Аудио и музыка: коллекции звуков и редакторы
- Книги, видео, подкасты, журналы и блоги: образовательное и вдохновляющее содержание
- Game Jam сообщества, исходники игр, управление проектами — всё в одном месте!
- Плюс разделы по AI, обучению, инструментам общего развития и прочему ценному
Этот список постоянно растёт и обновляется — отличное решение, чтобы не запутаться в инструментариуме.
https://github.com/ellisonleao/magictools
#GameDev #Ресурсы #Инструменты
Если ты занимаешься геймдевом — этот репозиторий настоящий клад для поиска подходящих инструментов! Вот что внутри:
- Графика: от placeholders до редакторов и генераторов персонажей
- Spritesheets и анимация: инструменты для упаковки и обработки
- Фреймворки и движки: 2D/3D, физика, GUI, звук, освещение, генерация ландшафта и кастомные пайплайны
- Аудио и музыка: коллекции звуков и редакторы
- Книги, видео, подкасты, журналы и блоги: образовательное и вдохновляющее содержание
- Game Jam сообщества, исходники игр, управление проектами — всё в одном месте!
- Плюс разделы по AI, обучению, инструментам общего развития и прочему ценному
Этот список постоянно растёт и обновляется — отличное решение, чтобы не запутаться в инструментариуме.
https://github.com/ellisonleao/magictools
#GameDev #Ресурсы #Инструменты
🧭 Зачем нужен service discovery?
Проблема микросервисов проста: как сервисам надёжно находить и вызывать друг друга? Жёстко прописанные IP и порты ломаются при любом масштабировании, перезапуске, автосборке или миграции.
Что делает service discovery
- Даёт логические имена вместо физических адресов (users-api, billing, auth).
- Динамически находит живые инстансы и балансирует запросы.
- Упрощает масштабирование, blue/green-деплой и отказоустойчивость.
Как это работает (базовый поток)
1) Сервис регистрируется в реестре (name → адреса, порты, метаданные, health).
2) Клиент запрашивает реестр и получает актуальный адрес.
3) Клиент шлёт запрос по полученному адресу (часто с ретраями и timeouts).
Паттерны
- Client-side discovery: клиент сам спрашивает реестр (Consul, Eureka).
- Server-side discovery: маршрутизация через прокси/ингресс (Envoy, API-шлюз).
- K8s-вариант: встроенный DNS/Services дают стабильные имена.
Что выбрать
- Consul/Eureka — когда вы не в Kubernetes или хотите гибкий реестр и health-чеки.
- K8s Services — когда всё крутится в Kubernetes.
- Envoy/Traefik/API-шлюз — если нужен серверный роутинг, канареечные релизы, mTLS.
Как внедрить в .NET (пример с Consul)
- Поднимите Consul-агент (dev/cluster), включите health-чеки (HTTP/TCP/TTL).
- Регистрируйте сервис на старте приложения: имя, адрес, порт, теги, check.
- Разрешайте адреса через:
- Consul API (client-side discovery в коде .NET),
- или DNS-запросы вида
- или через sidecar/Envoy, чтобы вынести логику сетевого стека из приложения.
- Добавьте политики устойчивости (Polly): retries, circuit breaker, timeouts.
- Пропишите deregistration при остановке, чтобы не висели «мертвые» инстансы.
- Логи/метрики: мониторьте failing-чеки, латентность и распределение трафика.
✨ Пример в .NET:
Итог
Service discovery — это «телефонная книга» вашего продакшена. Без него микросервисы быстро превращаются в хрупкий клубок адресов и ручных костылей. В .NET связка Consul + health-чеки + политики устойчивости даёт простой и надёжный старт.
Для пошагового гайда по .NET и Consul ищите разбор Milan Jovanovic «Service discovery in microservices with .NET and Consul».
Проблема микросервисов проста: как сервисам надёжно находить и вызывать друг друга? Жёстко прописанные IP и порты ломаются при любом масштабировании, перезапуске, автосборке или миграции.
Что делает service discovery
- Даёт логические имена вместо физических адресов (users-api, billing, auth).
- Динамически находит живые инстансы и балансирует запросы.
- Упрощает масштабирование, blue/green-деплой и отказоустойчивость.
Как это работает (базовый поток)
1) Сервис регистрируется в реестре (name → адреса, порты, метаданные, health).
2) Клиент запрашивает реестр и получает актуальный адрес.
3) Клиент шлёт запрос по полученному адресу (часто с ретраями и timeouts).
Паттерны
- Client-side discovery: клиент сам спрашивает реестр (Consul, Eureka).
- Server-side discovery: маршрутизация через прокси/ингресс (Envoy, API-шлюз).
- K8s-вариант: встроенный DNS/Services дают стабильные имена.
Что выбрать
- Consul/Eureka — когда вы не в Kubernetes или хотите гибкий реестр и health-чеки.
- K8s Services — когда всё крутится в Kubernetes.
- Envoy/Traefik/API-шлюз — если нужен серверный роутинг, канареечные релизы, mTLS.
Как внедрить в .NET (пример с Consul)
- Поднимите Consul-агент (dev/cluster), включите health-чеки (HTTP/TCP/TTL).
- Регистрируйте сервис на старте приложения: имя, адрес, порт, теги, check.
- Разрешайте адреса через:
- Consul API (client-side discovery в коде .NET),
- или DNS-запросы вида
service-name.service.consul (удобно для простых клиентов),- или через sidecar/Envoy, чтобы вынести логику сетевого стека из приложения.
- Добавьте политики устойчивости (Polly): retries, circuit breaker, timeouts.
- Пропишите deregistration при остановке, чтобы не висели «мертвые» инстансы.
- Логи/метрики: мониторьте failing-чеки, латентность и распределение трафика.
✨ Пример в .NET:
builder.Services
.AddHttpClient<ReportingServiceClient>(client =>
{
client.BaseAddress = new Uri("https://reporting-service");
})
.AddServiceDiscovery()
.AddRoundRobinLoadBalancer();
Итог
Service discovery — это «телефонная книга» вашего продакшена. Без него микросервисы быстро превращаются в хрупкий клубок адресов и ручных костылей. В .NET связка Consul + health-чеки + политики устойчивости даёт простой и надёжный старт.
Для пошагового гайда по .NET и Consul ищите разбор Milan Jovanovic «Service discovery in microservices with .NET and Consul».
⚙️ Создание фоновых задач в .NET с Quartz
Если тебе нужно планировать фоновые задачи в .NET — попробуй Quartz.
Всё просто: реализуешь интерфейс, регистрируешь задачу — и Quartz берёт на себя расписание и выполнение.
✨ Что делает Quartz удобным:
- Глубокая интеграция с Dependency Injection — можно внедрять сервисы, логеры и репозитории;
- Scoped-область задач — безопасно использовать
- Умный планировщик: без ручных таймеров и бесконечных циклов.
После Quartz уже не хочется возвращаться к ручным решениям.
📘 Подробный гайд по продвинутой работе с Quartz в .NET
Если тебе нужно планировать фоновые задачи в .NET — попробуй Quartz.
Всё просто: реализуешь интерфейс, регистрируешь задачу — и Quartz берёт на себя расписание и выполнение.
✨ Что делает Quartz удобным:
- Глубокая интеграция с Dependency Injection — можно внедрять сервисы, логеры и репозитории;
- Scoped-область задач — безопасно использовать
DbContext без проблем с жизненным циклом; - Умный планировщик: без ручных таймеров и бесконечных циклов.
После Quartz уже не хочется возвращаться к ручным решениям.
📘 Подробный гайд по продвинутой работе с Quartz в .NET