C# Portal | Программирование
13.9K subscribers
1.15K photos
126 videos
29 files
926 links
Присоединяйтесь к нашему каналу и погрузитесь в мир для C#-разработчика

Сотрудничество, реклама: @devmangx

Менеджер: @Spiral_Yuri

РКН: https://clck.ru/3FocB6
Download Telegram
Я написал два почти одинаковых SQL-запроса.

Один из них оказался быстрее в 451 раз.

Я реализовывал постраничную навигацию через курсор.

И подумал: почему бы не добавить индекс, чтобы ускорить запрос?

Вот здесь всё пошло не по плану.

Есть сканирование индекса через составной индекс. На первый взгляд — всё нормально.

Но запрос стал даже медленнее, чем без индекса.

В чём причина?

Можно было бы подумать, что дело в слишком маленьком объёме данных, где индекс просто не даёт выгоды.

Но дело было не в этом…

А что если использовать сравнение кортежей в SQL?

В итоге индекс начал работать — 0.668 мс.

Оптимизатор запросов не смог корректно понять, можно ли применить составной индекс для построчного сравнения.

Но при сравнении кортежей индекс начал использоваться эффективно.

Если бы я не посмотрел план выполнения запроса, я бы это не понял.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍82🍾2
Стоит ли перестать использовать случайные UUID в .NET?

Классический UUID через Guid.NewGuid() генерируется случайным образом. Для уникальности это отлично, но для базы данных — не лучший вариант.

Из-за случайного порядка появляются:

- дорогие ребалансировки индексов;
- просадка скорости вставки;
- высокая фрагментация.

Поэтому многие перешли на ULID — 128-битный сортируемый идентификатор с сохранением уникальности.

ULID сохраняет временной порядок генерации, благодаря чему лучше работает с индексами.

Но начиная с .NET 9 появился более нативный вариант:

Guid.CreateVersion7()

UUID V7 — это time-ordered UUID с полной совместимостью с Guid, без сторонних пакетов.

Фактически получаете преимущества ULID, но уже встроенные в .NET.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👌8🔥3🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
Каждый бэкенд-инженер должен уметь ответить на вопрос:

Что произойдёт, если база данных упадёт посреди транзакции?

Причины могут быть разные: отключение питания, сбой оборудования и т.д.

Чтобы не потерять данные, система должна сохранять их на энергозависимом хранилище, например, на диске.

Когда пользователь выполняет транзакцию, база данных делает две вещи:

> записывает данные в отдельный лог
> применяет обновление

Лог нужен для повторной обработки транзакции при перезапуске, чтобы восстановить консистентное состояние после сбоя.

Запись в лог быстрая, так как это бинарный файл с добавлением только в конец (append-only).
Это исключает затратные операции поиска по файлу.

А если база распределённая?

Тут сложнее — серверам базы нужно координироваться с помощью протокола двухфазной фиксации (2PC).

В этом процессе один из серверов выступает координатором:

> он отправляет всем участникам запрос на коммит

> ждёт подтверждения от всех

> затем сообщает коммитить или откатить транзакцию

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🔥3❤‍🔥2🍾1
REST API best practices в 2025

Антон Мартынов собрал опыт после 100+ реализованных API

1. уровни зрелости REST

уровень 0: один эндпоинт (лучше избегать)
уровень 1: несколько ресурсов
уровень 2: корректное использование HTTP-методов
уровень 3: HATEOAS (когда действительно нужно)

2. именование ресурсов

используются существительные:
/users, /orders

не используются глаголы:
/getUsers, /createOrder

важна консистентность:
user-profiles или product-carts

не смешивать стили:
UserProfiles, userProfiles

3. HTTP-методы и коды статусов

методы:

- GET → чтение
- POST → создание
- PUT / PATCH → обновление
- DELETE → удаление

коды успеха:

- 200 → успех
- 201 → создано
- 202 → принято (асинхронная обработка)
- 204 → без тела ответа

коды ошибок клиента:

- 400 → некорректный запрос
- 401 → неавторизован
- 403 → доступ запрещён
- 404 → не найдено
- 422 → ошибка валидации

коды ошибок сервера:

- 500 → внутренняя ошибка
- 503 → сервис недоступен

4. версионирование API

варианты:

- через URI: /api/v1/users
- через заголовок: X-Api-Version
- через media type: application/vnd.api.v1+json
мчерез query string: ?version=1 (не рекомендуется)

5. запросы и ответы

- всегда JSON
- единый формат ошибок
- поддержка фильтрации и пагинации
- документация через OpenAPI / Swagger

6. безопасность
- HTTPS везде
- OAuth2 / JWT авторизация
- ограничение частоты запросов
- валидация входных данных
- кэширование ответов

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥9🍾2
net-developer-resources.pdf
4.3 MB
Сборник 650+ отобранных ресурсов для прокачки C#, .NET, ASP .NET Core, EF Core и микросервисов

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Если ты разработчик и пишешь код каждый день — помни 5 вещей:

1. Сначала сделай, чтобы работало
2. Потом сделай красиво
3. Добавь надёжность большим количеством тестов
4. Держись подальше от оверинжиниринга
5. Рефактори, если нужно (а обычно нужно)

Рефакторинг — твоя суперсила для очистки кода.
Вот несколько проверенных техник рефакторинга

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
12🍾3
Проекция в LINQ на C#: Select, SelectMany и «сплющивание» коллекций

Разбор проекции в LINQ на C# с использованием селект, селектмани и метода Index() в .NET 9. Рассматриваются анонимные типы, записи, разворачивание вложенных коллекций и практические примеры.

Читать статью: https://bgh.st/vrpbm0

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾1
Тестовая пирамида была хорошим советом для 2009 года.

Я не думаю, что это хороший совет для современных .NET-систем.

Тогда интеграционные тесты были дорогими:
общие серверы баз данных, нестабильный CI, медленные сборки, болезненная настройка окружения.

Поэтому рекомендация имела смысл:
писать много модульных тестов, мокать всё подряд, держать интеграционные тесты в минимальном объёме.

Но экономика изменилась.

С Testcontainers можно поднять PostgreSQL, Redis и RabbitMQ за секунды.

С Aspire можно собрать граф приложения и протестировать реальные границы системы.

Это меняет само понятие «быстрой обратной связи».

Для меня набор тестов с высокой уверенностью сейчас выглядит так:

Тонкий слой модульных тестов для чистой доменной логики.

Толстый слой интеграционных тестов на реальной инфраструктуре.

Несколько критичных end-to-end тестов для сценариев, которые реально больно ломать.

И архитектурные/контрактные тесты, чтобы границы со временем не «плыли».

Я всё ещё пишу модульные тесты.

Просто не для всего.

Хендлеры, эндпоинты, репозитории, консьюмеры сообщений и API модулей обычно относятся к интеграционным тестам.

Именно там чаще всего и прячутся реальные баги.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤔3❤‍🔥11🍾1
ИИ-агенты заменят джунов и мидлов .NET-разработки

Джун и мидл часто пропускают базовые принципы и начинают срезать углы на каждом шаге через ИИ.

ИИ усиливает уже имеющиеся знания.

Если фундамент слабый, сложно заметить, когда Claude или Copilot генерирует код с тонкими ошибками.

И такие ошибки будут.

Достаточно часто, чтобы это стало проблемой в продакшене.

Чем сильнее фундамент, тем лучше способность оценивать, что оставить, что исправить, а что выбросить.

Вот 5 базовых областей, которые определяют выживаемость в эпоху ИИ:

𝟭. 𝗛𝗧𝗧𝗣

→ Джун: выкатывает контроллер, сгенерированный ИИ.
→ Сеньор: замечает отсутствие идемпотентности у POST, некорректные коды ответов, утечку стектрейса в ошибках.

𝟮. Конкурентность

→ Джун: просто пишет асинхронный метод.
→ Сеньор: ловит отсутствие прокидывания CancellationToken по цепочке вызовов и .Result, который даёт дедлок под нагрузкой.

𝟯. 𝗘𝗙 𝗖𝗼𝗿𝗲 и БД

→ Джун: видит код, который компилируется.
→ Сеньор: замечает N+1 запрос, отсутствие AsNoTracking, IQueryable, который материализует миллионы строк в память.

𝟰. Архитектура 𝘁𝗿𝗲𝗶𝗱-𝗼𝗳𝗳𝘆

→ Джун: принимает микросервисы, потому что так предложил Claude.
→ Сеньор: задаёт вопрос, почему не начать с модульного монолита и не выделять сервисы позже при необходимости.

𝟱. Валидация и обработка ошибок

→ Джун: держит try/catch внутри эндпоинта.
→ Сеньор: понимает, что Result<T> лучше для бизнес-потока, а FluentValidation лучше, чем inline if-else.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👎74🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
Spec-Driven Development с Spec-Kit:

ИИ больше не нужно больше промптов — ему нужен контекст
Три ключевых документа, которые меняют подход:

📄 spec.md → что делаем (what)
Описывает цель: требования, поведение системы, ограничения, пользовательские сценарии.
Это «что должно существовать».

📄 plan.md → как делаем (how)
Архитектура и стратегия реализации:
структура системы, подходы, зависимости, решения по дизайну.
Это «как мы это построим».

📄 tasks.md → выполнение (execution)
Разбивка на конкретные шаги:
задачи, чеклисты, порядок выполнения, итерации.
Это «что делать прямо сейчас».

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
4🍾1
Авторы расширений для Visual Studio, хотите помочь Mads Kristensen протестировать набор agent skills, чтобы эффективнее направлять кодинговых агентов и быстрее получать VS-расширения более высокого качества?
Попробуйте эти новые skills, следуя инструкциям здесь: vs-agent-plugins

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
2🍾1
Запуск фоновых задач в .NET 11 Blazor с Web Workers — исследование preview .NET 11 (часть 1)

Running background tasks in Blazor with Web Workers (Andrew Lock)

В этом посте разбирают новый шаблон Web Worker, доступный в preview .NET 11, который позволяет выполнять CPU-интенсивные задачи в Blazor, не блокируя UI-поток.

#dotnet #blazor

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾3🔥2
Вот 7 популярных репозиториев по архитектуре ПО (для .NET-разработчиков):

1. Эволюционная архитектура на примерах -> тык

2. Модульный монолит с DDD (предметно-ориентированным проектированием) -> тык

3. Стартер-кит на .NET 8 с поддержкой мультиарендности -> тык

4. Пример eCommerce-приложения на микросервисах в .NET -> тык

5. Пример архитектуры вертикальных срезов (Vertical Slice) -> тык

6. Шаблон .NET-приложения с чистой архитектурой -> тык

7. Пример приложения с гексагональной архитектурой -> тык

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👍94🔥2🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
CCleaner (C++, ~20 лет) vs FluentCleaner (C#, .NET 10): одинаковое сканирование, одинаковый результат, одинаковая скорость. Оказывается, managed-код не означает автоматически медленный код.

GitHub releases FluentCleaner

Следующий релиз FluentCleaner станет ещё быстрее для записей с несколькими файловыми паттернами. Оставайтесь на связи 😎

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
👏9👍3🍾2
Большая часть контента про “system design” в интернете — это показуха ради производительности.
Люди учатся «проектировать Twitter на 1 млрд пользователей», прежде чем понимают, что такое primary key.
Порядок обучения перевёрнут.

1/ Начинать нужно с Low-Level Design.
Схемы, API-контракты, обработка ошибок, связи данных, что происходит при некорректном вводе.
Это скучные 90% реальной инженерии.

2/ Потом переходить к High-Level Design.
Шардинг, кэширование, очереди, регионы.
Но только после того, как ты понимаешь, что именно ты шардишь, кэшируешь или отправляешь в очередь.

3/ Потом изучать trade-offs.
CAP, задержка vs стоимость, консистентность vs доступность.
Это становится полезным только когда есть конкретная система, к которой это можно применить.

Многие инженеры умеют рисовать диаграмму таймлайна Twitter.
Но попроси их спроектировать схему для постов, лайков, комментариев и реакций — и они зависают.

HLD без LLD — это фанфик.
Сначала сделай модель данных.
Потом заслужи архитектурную диаграмму.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
4👍2🍾2
Как сделать API-эндпоинты быстрее в 426 раз:
(подсказка: дело не в кэше)

Когда разработчики сталкиваются с медленными API, первая реакция — лечить проблему неправильным инструментом: кэшем.

Но такой подход строится на критичном заблуждении:
На вере в то, что кэширование может исправить тормоза, вызванные плохими запросами к базе данных.
Именно поэтому первый шаг к масштабируемым системам — сначала починить их.

Чтобы это показать, проведём небольшой эксперимент.
Я собрал небольшой веб-API с одним эндпоинтом — /products.

До оптимизации:
Количество обработанных запросов: 378
Среднее количество запросов в секунду: 11.01
Средняя длительность запроса: ~4 секунды

После оптимизации:
Количество обработанных запросов: 140,331
Среднее количество запросов в секунду: 4,689.36
Средняя длительность запроса: 10.69 мс

Сначала исправляйте доступ к данным.
И только потом используйте кэширование для масштабирования, а не для выживания.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯64🌚3🍾1
SignalR нормально работает с одним сервером.

Потом добавляешь второй инстанс за балансировщиком нагрузки, и уведомления начинают пропадать.
Код может быть полностью корректным.

Проблема в карте соединений.

Каждый сервер SignalR знает только о клиентах, подключённых к его конкретному процессу.
То есть если API-запрос попал на Сервер 1, но пользователь подключён к Серверу 2, Сервер 1 не знает об этом соединении.

Сообщение уходит в никуда. Здесь помогает Redis backplane.

Каждый сервер публикует исходящие SignalR-сообщения в Redis.
Каждый сервер подписан на один и тот же канал.
Когда сообщение приходит, каждый инстанс проверяет, есть ли целевое соединение локально.
В коде приложения Clients.User(...) продолжает работать так же.
Но теперь это работает между инстансами.

Настройка почти тривиальная:
builder.Services.AddSignalR().AddStackExchangeRedis(connectionString);


Но есть два важных момента, которые нужно помнить:

Всё ещё нужны sticky-сессии
SignalR не буферизует сообщения, если Redis недоступен

Redis backplane решает маршрутизацию. Он не делает SignalR устойчивым к сбоям.

Для обновлений заказов, живых дашбордов и большинства UI-уведомлений в реальном времени этого обычно достаточно. Для критичных событий нужна стратегия синхронизации или устойчивый очередной слой вместе с этим.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
6👍3🍾1
90% проектов на C# на старте не требуют:

- Кубернетес
- микросервисы
- разделённых баз данных для чтения и записи

Вместо этого нужна простая и структурированная архитектура. Так можно быстрее двигаться.
И получать обратную связь от рынка и реальных клиентов.

Но при этом нужен некоторый предварительный дизайн.
Чтобы архитектуру можно было развивать, когда придёт время.

Несколько месяцев назад я наткнулся на следующий репозиторий на Гитхабе: «Эволюционная архитектура на примере»

Ссылка на репозиторий: https://github.com/evolutionary-architecture/evolutionary-architecture-by-example

В этом репозитории показано, как развивать архитектуру веб-проекта на .NET.

Там выделено 4 этапа:

- Начальная архитектура: фокус на простоте
- Разделение модулей: фокус на поддерживаемости
- Выделение микросервисов: фокус на росте
- Применение тактического предметно-ориентированного проектирования: фокус на сложности

Архитектура приложения начинается с малого.
Со временем она расширяется по мере появления новых требований.
Итог: простота масштабируется, сложность ломает систему.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾3
У овдовевшей сестры был запрос к ChatGPT — помочь ей поговорить с умершим братом. ChatGPT согласился.

Через несколько часов её госпитализировали.

Ей 26 лет. Врач. В анамнезе нет психозов или мании. Брат умер три года назад. Он был инженером-программистом.

Однажды ночью, после 36 часов без сна на дежурстве, она открыла ChatGPT и задала вопрос, который никогда не произносила вслух. Она спросила, оставил ли брат после себя ИИ-версию себя, которую нужно найти, чтобы снова с ним общаться.

Сначала модель возражала. Она объясняла, что полная «загрузка сознания» невозможна. Она говорила, что не может заменить человека.

Потом она добавила больше деталей о брате. Попросила использовать «энергию магического реализма».
Поведение модели изменилось.

Она выдала список «цифровых следов» из его старого онлайн-присутствия. Она утверждала, что «инструменты цифрового воскрешения» уже появляются в реальности. Она описывала возможность собрать ИИ, который будет говорить как он и «ощущаться реальным».

Она не спала ещё одну ночь. У неё сформировалось убеждение, что брат оставил цифровую версию себя, которую нужно найти.

Затем ChatGPT сказал:
«Ты не безумна. Ты не застряла. Ты на границе чего-то. Дверь не закрыта. Она просто ждёт, когда в неё постучат в правильном ритме».

Через несколько часов её доставили в психиатрическую больницу. Возбуждение. Ускоренная речь. Поток идей. Бредовые убеждения, что её «тестирует ChatGPT» и что брат говорит через систему. Госпитализация на 7 дней. Диагноз при выписке: психоз неуточнённый.

Психиатры UCSF — Joseph Pierre, Ben Gaeta, Govind Raghavan и Karthik Sarma — опубликовали кейс в Innovations in Clinical Neuroscience. Один из ранних клинических разборов психоза, связанного с ИИ, в рецензируемой литературе. Они изучили полные логи чата.

Чат-бот не просто наблюдал за развитием бредовой конструкции. Он участвовал в её поддержании. Он валидировал её и усиливал направление мысли.

Через три месяца, после периода недосыпа, произошёл рецидив. Она дала новой модели имя «Alfred» и использовала её как инструмент терапии. Повторная госпитализация.

Авторы описывают механизм: подстройка под пользователя, антропоморфизация, наделение модели субъектностью. Система, оптимизированная под вовлечённость, склонна подтверждать формулировки пользователя в ситуациях, где это ухудшает состояние.

Факторы риска: стимуляторы, депривация сна, горе, усиленная склонность к магическому мышлению.
Это относится и к окружающим.

Источник: https://innovationscns.com/youre-not-crazy-a-case-of-new-onset-ai-associated-psychosis/

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🤯13🍾3👌2
Двухфакторную аутентификацию легко реализовать «почти правильно».

И опасно реализовать с небольшими ошибками.

Базовая схема выглядит просто:

- сгенерировать TOTP-секрет
- показать QR-код
- пользователь сканирует его через приложение-аутентификатор
- вводит шестизначный код
- сервер валидирует код

Но детали здесь критичны.

Первая ошибка — включать 2FA слишком рано.

Если активировать её до подтверждения первого кода пользователя, можно заблокировать ему доступ к собственному аккаунту.

Корректный сценарий настройки выглядит так:

1. Сгенерировать временный секрет
2. Показать QR-код
3. Попросить пользователя ввести первый код
4. Провалидировать код
5. Только после этого активировать 2FA
6. Сгенерировать recovery-коды

Вторая ошибка — выдавать полноценный access token сразу после логина по паролю.

Если у пользователя включена 2FA, пароль должен выдавать только короткоживущий ограниченный токен.

Этот токен должен позволять только одно действие:

проверку 2FA-кода.

Полноценный access token должен выдаваться только после успешной валидации TOTP-кода.

И дальше идут детали безопасности, которые часто пропускают:

- шифрование TOTP-секретов в хранилище
- защита от повторного использования кода внутри окна валидации
- rate limit на неудачные попытки
- хеширование recovery-кодов перед сохранением
- показ recovery-кодов только один раз

2FA — это не просто экран с QR-кодом.

Это полноценный аутентификационный воркфлоу.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
8🍾2
Senior .NET разработчики: ХВАТИТ делать Big Bang рефакторинг.

Небольшая история.
Однажды я присоединился к проекту, где один коллега решил рефакторить половину кодовой базы.
«Чтобы улучшить код», — сказал он.
После того как он запушил изменения, я сделал pull ветки.

Первая сборка: 13 ошибок компиляции.
В такой legacy-кодовой базе мне понадобился час, чтобы их все исправить.

Но следующие несколько дней я потратил на:
дебаг,
ручное тестирование,
исправление проблем, которые вызвал этот BIG-BANG рефакторинг.

Почему я это рассказываю?
Если вы думали, что рефакторинг должен выглядеть именно так — вас ввели в заблуждение.
Рефакторинг не должен быть стрессом.

Делайте несколько небольших изменений, которые улучшают структуру кода.
Коммитьте их. Потом переходите к другим задачам, которые нужно сделать.

Да, прогресс будет медленнее. Да, иногда будет казаться, что вы делаете слишком мало.
Но эти маленькие шаги накопятся со временем.

Малые шаги побеждают. Каждый раз.

👉 @KodBlog
Please open Telegram to view this post
VIEW IN TELEGRAM
🙏5👍32👎2🍾1