Postgres использует эффективный по кешу и CPU алгоритм, когда за
Логично, правда? Если бы вас попросили взять 10 самых больших камней из кучи в 100 камней, вы бы не выстраивали все камни от маленького к большому, а потом брали 10 самых больших. Вы бы отложили 10 в порядке, а затем сравнивали каждый камень с самым маленьким из этих 10 и заменяли бы его, если новый камень больше. (У вас есть возможности, которых нет у баз данных: «быстрый визуальный поиск больших объектов», операторы вроде «визуальная оценка размера» и «взять камень и сравнить ощущаемый вес».)
Это top-N heapsort (пирамидальная сортировка top-N).
При выполнении
Всего 25кБ памяти? Это та маленькая кучка камней, которую вы держите в памяти, пока сканируете всю таблицу.
Без
Используемая память =
А что насчёт _неразумного_ лимита?
Видели когда-нибудь URL пагинации с
Когда лимит становится слишком большим, Postgres в конечном счёте переключается на quicksort или внешнюю сортировку слиянием (а это убийственно).
Postgres принимает решение на этапе планирования, основываясь на соотношении оценочного количества входных строк к N. Когда N приближается к числу сортируемых строк, поддержание кучи перестаёт быть выгодным, и вступает quicksort. Точная точка перехода зависит от размера строки и оценки планировщика. Ниже приведён гипотетический пример переключения планировщика с top-N heapsort на quicksort. Использование памяти — это объём памяти, занятый сортировкой, а не общее потребление памяти запросом.
Не забывайте про индексы
Top-N heapsort — это оптимизация сортировки неиндексированного набора данных. Она всё равно требует полного последовательного сканирования входных данных. Для 10 самых последних событий среди 1M строк она каждый раз сканирует все 1M строк. Индекс по
👉 @KodBlog
ORDER BY следует _разумный_ LIMIT. С LIMIT алгоритм сортировки может использовать всего 25кБ памяти. Без LIMIT алгоритму сортировки требуется хранить весь результирующий набор в кеше.Логично, правда? Если бы вас попросили взять 10 самых больших камней из кучи в 100 камней, вы бы не выстраивали все камни от маленького к большому, а потом брали 10 самых больших. Вы бы отложили 10 в порядке, а затем сравнивали каждый камень с самым маленьким из этих 10 и заменяли бы его, если новый камень больше. (У вас есть возможности, которых нет у баз данных: «быстрый визуальный поиск больших объектов», операторы вроде «визуальная оценка размера» и «взять камень и сравнить ощущаемый вес».)
Это top-N heapsort (пирамидальная сортировка top-N).
При выполнении
EXPLAIN ANALYZE на запросе ниже приведён пример top-N heapsort:Sort (cost=...) (actual time=... rows=10 loops=1)
Sort Key: created_at DESC
Sort Method: top-N heapsort Memory: 25kB
-> Seq Scan on events (rows=1000000 ...)
Всего 25кБ памяти? Это та маленькая кучка камней, которую вы держите в памяти, пока сканируете всю таблицу.
Без
LIMIT используется quicksort (быстрая сортировка), которой нужно держать в памяти весь входной набор, отсортировать его, а затем вернуть первые N строк. Top-N heapsort поддерживает min-кучу фиксированного размера ровно из N кортежей и прогоняет через неё поток входных данных. Вычислительная сложность — O(M log N), где M — количество просканированных строк, а N — LIMIT. По сравнению с O(M log M) для полной сортировки, top-N heapsort также быстрее для CPU.Используемая память =
N × row_size (где N — LIMIT). Для LIMIT 10 со строками по 20 байт это 200 байт. Postgres округляет до минимума в 25кБ для выравнивания и служебных данных. В любом случае, для _разумного_ LIMIT сброса на диск не произойдёт независимо от размера таблицы.А что насчёт _неразумного_ лимита?
Видели когда-нибудь URL пагинации с
per_page=10? Что произойдёт, если изменить его на per_page=1000000, а приложение не валидирует ввод, и запрос получает LIMIT 1000000?Когда лимит становится слишком большим, Postgres в конечном счёте переключается на quicksort или внешнюю сортировку слиянием (а это убийственно).
Postgres принимает решение на этапе планирования, основываясь на соотношении оценочного количества входных строк к N. Когда N приближается к числу сортируемых строк, поддержание кучи перестаёт быть выгодным, и вступает quicksort. Точная точка перехода зависит от размера строки и оценки планировщика. Ниже приведён гипотетический пример переключения планировщика с top-N heapsort на quicksort. Использование памяти — это объём памяти, занятый сортировкой, а не общее потребление памяти запросом.
LIMIT 10: Sort Method: top-N heapsort Memory: 25kB
LIMIT 100: Sort Method: top-N heapsort Memory: 30kB
LIMIT 1,000: Sort Method: top-N heapsort Memory: 97kB
LIMIT 10,000: Sort Method: top-N heapsort Memory: 914kB
LIMIT 100,000: Sort Method: quicksort Memory: 9,113kB
Не забывайте про индексы
Top-N heapsort — это оптимизация сортировки неиндексированного набора данных. Она всё равно требует полного последовательного сканирования входных данных. Для 10 самых последних событий среди 1M строк она каждый раз сканирует все 1M строк. Индекс по
(created_at DESC) извлёк бы эти 10 строк напрямую, без сканирования всего набора данных.Please open Telegram to view this post
VIEW IN TELEGRAM
👍5🍾1
Вот лучший способ версионировать API.
Но никто его не использует.
Слышали про версионирование через media type?
Это самый чистый подход к версионированию API.
1. Вы указываете версию API в заголовке Accept.
2. Сервер направляет запросы к соответствующему эндпоинту.
Вы не засоряете URL версиями. Это также можно расширить с помощью контент-nego.
Но версионирование API — лишь средство для достижения цели. Лучший API вообще не использует версионирование.
Вместо этого вам нужен change management.
Change management означает развитие API без неожиданностей и поломок для существующих клиентов. Вместо того чтобы сразу создавать v2, вы сначала спрашиваете: можно ли сделать изменение аддитивным, могут ли старая и новая функциональность сосуществовать, безопаснее ли новая операция, чем изменение существующей, и можно ли обработать deprecation через документацию, runtime-сигналы, миграционные гайды и телеметрию.
👉 @KodBlog
Но никто его не использует.
Слышали про версионирование через media type?
Это самый чистый подход к версионированию API.
1. Вы указываете версию API в заголовке Accept.
2. Сервер направляет запросы к соответствующему эндпоинту.
Вы не засоряете URL версиями. Это также можно расширить с помощью контент-nego.
Но версионирование API — лишь средство для достижения цели. Лучший API вообще не использует версионирование.
Вместо этого вам нужен change management.
Change management означает развитие API без неожиданностей и поломок для существующих клиентов. Вместо того чтобы сразу создавать v2, вы сначала спрашиваете: можно ли сделать изменение аддитивным, могут ли старая и новая функциональность сосуществовать, безопаснее ли новая операция, чем изменение существующей, и можно ли обработать deprecation через документацию, runtime-сигналы, миграционные гайды и телеметрию.
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾4❤1
Исторический момент. Новый HTTP-метод в стандарте.
QUERY. Альтернатива GET и POST.
Как GET — не меняет состояние ресурса. Как POST — можно использовать тело запроса. Шлёшь JSON, кешируешь ответ.
Только что повышен до Proposed Standard.
👉 @KodBlog
QUERY. Альтернатива GET и POST.
Как GET — не меняет состояние ресурса. Как POST — можно использовать тело запроса. Шлёшь JSON, кешируешь ответ.
Только что повышен до Proposed Standard.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍24🤔3🍾1
This media is not supported in your browser
VIEW IN TELEGRAM
ОДИН РАЗРАБОТЧИК ЗАНОВО ПРИДУМАЛ ФОРМАТ PDF. И проблема, которую он решил, до смешного очевидна.
Банк попросил его предоставить 17 PDF-файлов для оформления ипотеки.
Он открывал их по одному.
Закрывал их по одному.
Объединял их в один файл.
Стало только хуже.
Тогда он подумал: а что, если PDF работал бы как Figma?
Горизонтальная прокрутка — между страницами.
Вертикальная — между файлами.
До него этого никто не сделал.
Поэтому он расширил стандарт PDF, добавив метаданные.
Он придумал новый формат.
Назвал его .pdfx.
Claude сделал 80% проекта за 2 часа.
В этом и разница между тем, чтобы десятилетиями жаловаться на нерешённую проблему… и однажды настолько устать от неё, что взять и исправить всё самому.
https://github.com/AlexandrosGounis/pdfx
👉 @KodBlog
Банк попросил его предоставить 17 PDF-файлов для оформления ипотеки.
Он открывал их по одному.
Закрывал их по одному.
Объединял их в один файл.
Стало только хуже.
Тогда он подумал: а что, если PDF работал бы как Figma?
Горизонтальная прокрутка — между страницами.
Вертикальная — между файлами.
До него этого никто не сделал.
Поэтому он расширил стандарт PDF, добавив метаданные.
Он придумал новый формат.
Назвал его .pdfx.
Claude сделал 80% проекта за 2 часа.
В этом и разница между тем, чтобы десятилетиями жаловаться на нерешённую проблему… и однажды настолько устать от неё, что взять и исправить всё самому.
https://github.com/AlexandrosGounis/pdfx
Please open Telegram to view this post
VIEW IN TELEGRAM
❤16🔥6🍾2🥰1
Короткий конспект по классическим паттернам проектирования.
Внутри:
→ Factory — создание объектов через единый интерфейс
→ Builder — пошаговая сборка сложных объектов
→ Prototype — клонирование объектов вместо создания с нуля
→ Singleton — один экземпляр на всё приложение
→ Chain of Responsibility — цепочка обработчиков запросов
Подходит как быстрый референс без погружения в теорию.
👉 @KodBlog
Внутри:
→ Factory — создание объектов через единый интерфейс
→ Builder — пошаговая сборка сложных объектов
→ Prototype — клонирование объектов вместо создания с нуля
→ Singleton — один экземпляр на всё приложение
→ Chain of Responsibility — цепочка обработчиков запросов
Подходит как быстрый референс без погружения в теорию.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4🍾1
Сможешь решить типичную задачу с собеседований?
Нужно понимать, как работают бинарные деревья.
Я давно с деревьями не работал — со времён университета.
Поэтому на разбор ушло несколько минут.
Вспомнил, что для обхода в ширину (Breadth-first traversal) нужна очередь, с этого и начал.
На выходе получилось:
Значит, узлы обрабатывались в правильном порядке.
Следующий вопрос — когда печатать перевод строки.
Решил отслеживать уровень каждого узла в дереве. По мере обхода увеличивал текущий уровень.
В целом — нормальное упражнение.
В универе я бы такое сделал не задумываясь.
Это вообще имеет отношение к работе?
Может и да, но люди часто не понимают смысл.
Тут проверяют умение решать задачи.
Можешь придумать другое решение?
P.S. Постарайся не использовать ИИ для этого… ради всего, что связано с разработкой.
👉 @KodBlog
Нужно понимать, как работают бинарные деревья.
Я давно с деревьями не работал — со времён университета.
Поэтому на разбор ушло несколько минут.
Вспомнил, что для обхода в ширину (Breadth-first traversal) нужна очередь, с этого и начал.
На выходе получилось:
1 2 3 4 5 6.Значит, узлы обрабатывались в правильном порядке.
Следующий вопрос — когда печатать перевод строки.
Решил отслеживать уровень каждого узла в дереве. По мере обхода увеличивал текущий уровень.
В целом — нормальное упражнение.
В универе я бы такое сделал не задумываясь.
Это вообще имеет отношение к работе?
Может и да, но люди часто не понимают смысл.
Тут проверяют умение решать задачи.
Можешь придумать другое решение?
P.S. Постарайся не использовать ИИ для этого… ради всего, что связано с разработкой.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍1🍾1
Интересный новый бенчмарк проекции языков WinRT: Rust самый быстрый, C++ недалеко позади, C# пока догоняет. Внутренний push на C# для ОС и приложений не оставляет ли слишком много производительности на столе? 🤔
https://github.com/microsoft/windows-rs/blob/master/crates%2Fsamples%2Flang_perf%2Freadme.md
(время в мс; меньше — лучше)
На фото 2 обновлено под .NET 10.
👉 @KodBlog
https://github.com/microsoft/windows-rs/blob/master/crates%2Fsamples%2Flang_perf%2Freadme.md
(время в мс; меньше — лучше)
На фото 2 обновлено под .NET 10.
Please open Telegram to view this post
VIEW IN TELEGRAM
Please open Telegram to view this post
VIEW IN TELEGRAM
2🍾1
Прежде чем код можно будет переиспользовать, он должен быть пригоден к использованию.
Большинство разработчиков строят абстракции для кода, который живёт ровно в одном месте.
Один интерфейс. Одна реализация. Один вызывающий. Навсегда.
И называют это «чистым кодом».
Вот в чём ловушка →
Абстракция, построенная для переиспользования, которое никогда не наступает — не переиспользуема. Это просто лишний слой, который надо прочитать, чтобы понять, что код на самом деле делает.
📌 Сначала удобство использования. Переиспользование — то, что вы зарабатываете потом.
Самая частая пустая трата, которую я вижу:
- ❌
- ✅ Конкретный класс, который можно прочитать от начала до конца
- ❌ Общая база «для будущей гибкости», которая никогда не гнётся
- ✅ Простая прямая версия, решающая сегодняшнюю задачу
- ❌ Фабрика, оборачивающая создание одного объекта
- ✅ Внедрение объекта напрямую через DI
Каждая лишняя абстракция усложняет использование кода.
Больше файлов для открытия. Больше косвенности для трассировки. Больше догадок, зачем это существует.
👉 Честный тест перед тем, как выносить абстракцию:
1. Есть ли у меня второй или третий реальный вызывающий код прямо сейчас? (Не «может быть потом»)
2. Это делает код проще в использовании или просто даёт повод гордиться собой?
3. Сможет ли следующий разработчик разобраться в этом без моих объяснений?
Если ответ «нет» — удаляйте слой. Пишите конкретную реализацию.
Вы не теряете переиспользование.
Вы сохраняете код удобным до тех пор, пока переиспользование действительно не появится.
А когда оно появится — правильная абстракция станет очевидной, потому что у вас наконец будет два или три реальных примера, чтобы её сформировать.
Преждевременная абстракция — это сложность, за которую вы платите сегодня ради выгоды, которая может никогда не наступить.
Сделайте код удобным сначала. Абстрагируйте только тогда, когда второй реальный сценарий использования вынудит вас это сделать.
👉 @KodBlog
Большинство разработчиков строят абстракции для кода, который живёт ровно в одном месте.
Один интерфейс. Одна реализация. Один вызывающий. Навсегда.
И называют это «чистым кодом».
Вот в чём ловушка →
Абстракция, построенная для переиспользования, которое никогда не наступает — не переиспользуема. Это просто лишний слой, который надо прочитать, чтобы понять, что код на самом деле делает.
📌 Сначала удобство использования. Переиспользование — то, что вы зарабатываете потом.
Самая частая пустая трата, которую я вижу:
- ❌
IThingService с одной реализацией «на всякий случай»- ✅ Конкретный класс, который можно прочитать от начала до конца
- ❌ Общая база «для будущей гибкости», которая никогда не гнётся
- ✅ Простая прямая версия, решающая сегодняшнюю задачу
- ❌ Фабрика, оборачивающая создание одного объекта
- ✅ Внедрение объекта напрямую через DI
Каждая лишняя абстракция усложняет использование кода.
Больше файлов для открытия. Больше косвенности для трассировки. Больше догадок, зачем это существует.
👉 Честный тест перед тем, как выносить абстракцию:
1. Есть ли у меня второй или третий реальный вызывающий код прямо сейчас? (Не «может быть потом»)
2. Это делает код проще в использовании или просто даёт повод гордиться собой?
3. Сможет ли следующий разработчик разобраться в этом без моих объяснений?
Если ответ «нет» — удаляйте слой. Пишите конкретную реализацию.
Вы не теряете переиспользование.
Вы сохраняете код удобным до тех пор, пока переиспользование действительно не появится.
А когда оно появится — правильная абстракция станет очевидной, потому что у вас наконец будет два или три реальных примера, чтобы её сформировать.
Преждевременная абстракция — это сложность, за которую вы платите сегодня ради выгоды, которая может никогда не наступить.
Сделайте код удобным сначала. Абстрагируйте только тогда, когда второй реальный сценарий использования вынудит вас это сделать.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥6👍4🍾3
Если хочешь стать по-настоящему сильным в .NET,
изучи следующие концепции:
1. CLR и JIT-компиляция
2. Сборка мусора (Garbage Collection)
3. Поколения памяти (Gen 0/1/2 и LOH)
4. Типы значений (Value Types) и ссылочные типы (Reference Types)
5. Boxing и Unboxing
6. Стек и куча (Stack vs Heap)
7. Span<T> и Memory<T>
8. ref struct и stackalloc
9. IDisposable и using
10. Финализаторы (Finalizers)
11. Async/Await
12. Task и ValueTask
13. SynchronizationContext
14. ConfigureAwait
15. CancellationToken
16. IAsyncEnumerable
17. Потоки и пул потоков (Threading & Thread Pool)
18. lock, Monitor и Semaphore
19. Channels
20. Parallel и PLINQ
21. LINQ и отложенное выполнение (Deferred Execution)
22. IEnumerable и IQueryable
23. Делегаты и события (Delegates & Events)
24. Func, Action и Predicate
25. Деревья выражений (Expression Trees)
26. Дженерики и ограничения (Generics & Constraints)
27. Ковариантность и контравариантность
28. Records и сопоставление с образцом (Pattern Matching)
29. Nullable Reference Types
30. Внедрение зависимостей (Dependency Injection)
31. Жизненные циклы сервисов (Scoped/Singleton/Transient)
32. Конвейер middleware (Middleware Pipeline)
33. Minimal APIs и Controllers
34. Привязка моделей и валидация (Model Binding & Validation)
35. Конфигурация и паттерн Options
36. IHostedService и BackgroundService
37. Entity Framework Core
38. Отслеживание изменений (Change Tracking)
39. Миграции (Migrations)
40. Проблема N+1
41. Пул подключений (Connection Pooling)
42. Dapper и Raw SQL
43. Кэширование (IMemoryCache и Distributed Cache)
44. Output Caching
45. Генераторы исходного кода (Source Generators)
46. Рефлексия и атрибуты (Reflection & Attributes)
47. AssemblyLoadContext
48. Native AOT
49. Бенчмаркинг (BenchmarkDotNet)
50. Профилирование памяти и настройка GC (Memory Profiling & GC Tuning)
👉 @KodBlog
изучи следующие концепции:
1. CLR и JIT-компиляция
2. Сборка мусора (Garbage Collection)
3. Поколения памяти (Gen 0/1/2 и LOH)
4. Типы значений (Value Types) и ссылочные типы (Reference Types)
5. Boxing и Unboxing
6. Стек и куча (Stack vs Heap)
7. Span<T> и Memory<T>
8. ref struct и stackalloc
9. IDisposable и using
10. Финализаторы (Finalizers)
11. Async/Await
12. Task и ValueTask
13. SynchronizationContext
14. ConfigureAwait
15. CancellationToken
16. IAsyncEnumerable
17. Потоки и пул потоков (Threading & Thread Pool)
18. lock, Monitor и Semaphore
19. Channels
20. Parallel и PLINQ
21. LINQ и отложенное выполнение (Deferred Execution)
22. IEnumerable и IQueryable
23. Делегаты и события (Delegates & Events)
24. Func, Action и Predicate
25. Деревья выражений (Expression Trees)
26. Дженерики и ограничения (Generics & Constraints)
27. Ковариантность и контравариантность
28. Records и сопоставление с образцом (Pattern Matching)
29. Nullable Reference Types
30. Внедрение зависимостей (Dependency Injection)
31. Жизненные циклы сервисов (Scoped/Singleton/Transient)
32. Конвейер middleware (Middleware Pipeline)
33. Minimal APIs и Controllers
34. Привязка моделей и валидация (Model Binding & Validation)
35. Конфигурация и паттерн Options
36. IHostedService и BackgroundService
37. Entity Framework Core
38. Отслеживание изменений (Change Tracking)
39. Миграции (Migrations)
40. Проблема N+1
41. Пул подключений (Connection Pooling)
42. Dapper и Raw SQL
43. Кэширование (IMemoryCache и Distributed Cache)
44. Output Caching
45. Генераторы исходного кода (Source Generators)
46. Рефлексия и атрибуты (Reflection & Attributes)
47. AssemblyLoadContext
48. Native AOT
49. Бенчмаркинг (BenchmarkDotNet)
50. Профилирование памяти и настройка GC (Memory Profiling & GC Tuning)
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥7❤4🍾1
Твоё .NET MAUI приложение, скорее всего, уже не только мобильное.
VisualStateManager + AdaptiveTrigger могут переключать layout, когда окно становится шире — прямо в XAML.
Без кода с SizeChanged и всей этой каши с событиями. Удобно.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/maui/fundamentals/triggers?view=net-maui-10.0#state-triggers
👉 @KodBlog
VisualStateManager + AdaptiveTrigger могут переключать layout, когда окно становится шире — прямо в XAML.
Без кода с SizeChanged и всей этой каши с событиями. Удобно.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/maui/fundamentals/triggers?view=net-maui-10.0#state-triggers
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🍾1
Если ты уже знал все 25 приёмов — отпишись от меня.
Почти никто не доходит до 11-го приёма по .NET.
(№23 удивил даже меня):
1. Используй async до самого низа стека вызовов. Один блокирующий .Result может привести к взаимной блокировке всей цепочки.
2. ConfigureAwait(false) нужен в библиотеках. Не в коде приложения.
3. Возвращай Task напрямую, если не используешь await. Так не создаётся лишняя state machine.
4. ValueTask подходит для горячих путей, которые обычно завершаются синхронно. Не стоит использовать его повсеместно.
5. IEnumerable — ленивый. Переберёшь его дважды — запрос выполнится дважды.
6. Здесь большинство перестаёт читать. IQueryable выполняется на стороне базы данных. IEnumerable сначала загружает всё в память.
7. Слишком ранний вызов .ToList() ломает оптимизацию фильтрации. Вызывай Where до материализации.
8. Проблема N+1 возникает незаметно. Включи логирование запросов EF Core — и увидишь её в работе.
9. Для операций чтения используй AsNoTracking(). Отслеживание изменений не бесплатно.
10. Проецируй данные в DTO через Select. Не загружай всю сущность целиком.
11. Scoped-сервис внутри Singleton — это ошибка с захваченной зависимостью, которая рано или поздно проявится.
12. Не создавай новый HttpClient для каждого запроса. Используй IHttpClientFactory.
13. Span<T> и stackalloc позволяют работать с данными без выделения памяти в куче. Нулевая нагрузка на GC.
14. В циклах используй StringBuilder вместо +=. Каждая конкатенация создаёт новую строку.
15. Предпочитай string.Create и буферы из пула, чтобы избежать скрытых выделений памяти.
16. Records подходят для неизменяемых данных. Оператор with позволяет бесплатно создавать копии с изменениями.
17. Pattern matching лучше длинных цепочек if/else. Switch-выражения читаются проще.
18. Включай nullable reference types с первого дня. Эти предупреждения — ошибки, до которых ты ещё не добрался.
19. Вместо внедрения IConfiguration используй паттерн Options. Он даёт строгую типизацию и валидацию.
20. Передавай CancellationToken во все асинхронные методы. Прокидывай его дальше по цепочке, а не игнорируй.
21. Используй BackgroundService, а не случайный Task.Run(). Пусть жизненным циклом управляет хост.
22. Сначала измеряй, потом оптимизируй. Используй BenchmarkDotNet, а не интуицию.
23. Именно это удивило меня: по умолчанию делай свои классы sealed. Это даёт JIT бесплатную возможность для оптимизации.
24. Используй Native AOT для быстрого запуска и минимального размера приложения. Убирай всё лишнее при тримминге.
25. Последнее правило — и единственное, которое действительно имеет значение: читай SQL, который генерирует EF Core. Абстракция может вводить в заблуждение, пока не посмотришь, что она создаёт.
👉 @KodBlog
Почти никто не доходит до 11-го приёма по .NET.
(№23 удивил даже меня):
1. Используй async до самого низа стека вызовов. Один блокирующий .Result может привести к взаимной блокировке всей цепочки.
2. ConfigureAwait(false) нужен в библиотеках. Не в коде приложения.
3. Возвращай Task напрямую, если не используешь await. Так не создаётся лишняя state machine.
4. ValueTask подходит для горячих путей, которые обычно завершаются синхронно. Не стоит использовать его повсеместно.
5. IEnumerable — ленивый. Переберёшь его дважды — запрос выполнится дважды.
6. Здесь большинство перестаёт читать. IQueryable выполняется на стороне базы данных. IEnumerable сначала загружает всё в память.
7. Слишком ранний вызов .ToList() ломает оптимизацию фильтрации. Вызывай Where до материализации.
8. Проблема N+1 возникает незаметно. Включи логирование запросов EF Core — и увидишь её в работе.
9. Для операций чтения используй AsNoTracking(). Отслеживание изменений не бесплатно.
10. Проецируй данные в DTO через Select. Не загружай всю сущность целиком.
11. Scoped-сервис внутри Singleton — это ошибка с захваченной зависимостью, которая рано или поздно проявится.
12. Не создавай новый HttpClient для каждого запроса. Используй IHttpClientFactory.
13. Span<T> и stackalloc позволяют работать с данными без выделения памяти в куче. Нулевая нагрузка на GC.
14. В циклах используй StringBuilder вместо +=. Каждая конкатенация создаёт новую строку.
15. Предпочитай string.Create и буферы из пула, чтобы избежать скрытых выделений памяти.
16. Records подходят для неизменяемых данных. Оператор with позволяет бесплатно создавать копии с изменениями.
17. Pattern matching лучше длинных цепочек if/else. Switch-выражения читаются проще.
18. Включай nullable reference types с первого дня. Эти предупреждения — ошибки, до которых ты ещё не добрался.
19. Вместо внедрения IConfiguration используй паттерн Options. Он даёт строгую типизацию и валидацию.
20. Передавай CancellationToken во все асинхронные методы. Прокидывай его дальше по цепочке, а не игнорируй.
21. Используй BackgroundService, а не случайный Task.Run(). Пусть жизненным циклом управляет хост.
22. Сначала измеряй, потом оптимизируй. Используй BenchmarkDotNet, а не интуицию.
23. Именно это удивило меня: по умолчанию делай свои классы sealed. Это даёт JIT бесплатную возможность для оптимизации.
24. Используй Native AOT для быстрого запуска и минимального размера приложения. Убирай всё лишнее при тримминге.
25. Последнее правило — и единственное, которое действительно имеет значение: читай SQL, который генерирует EF Core. Абстракция может вводить в заблуждение, пока не посмотришь, что она создаёт.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍15❤3🍌2😐2🍾1
Хватит использовать изменяемый Dictionary для данных, которые никогда не меняются.
Если вы строите справочные данные один раз, а читаете их часто, FrozenDictionary может подойти лучше.
Загвоздка: заморозка стоит ресурсов. Используйте его для долгоживущих справочников, а не для обычного состояния приложения.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/core/whats-new/dotnet-8/runtime#performance-focused-types
👉 @KodBlog
Если вы строите справочные данные один раз, а читаете их часто, FrozenDictionary может подойти лучше.
Загвоздка: заморозка стоит ресурсов. Используйте его для долгоживущих справочников, а не для обычного состояния приложения.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/core/whats-new/dotnet-8/runtime#performance-focused-types
Please open Telegram to view this post
VIEW IN TELEGRAM
❤2🍾1
Почему используется Event-Driven Architecture?
Представьте систему с двумя микросервисами:
1) payments
2) emails
Когда платеж подтверждён, payments вызывает emails, чтобы отправить чек.
Но приложение растёт. Теперь нужно ещё сгенерировать счёт, обновить метрики и отправить уведомление.
Чтобы это сделать, payments начинает вызывать каждый из них.
Каждая новая функциональность добавляет ещё один вызов. Со временем такой поток становится всё сложнее поддерживать.
Event-Driven Architecture предлагает другой способ коммуникации.
Когда платеж подтверждён:
1) payments публикует событие "payment confirmed".
2) emails отправляет чек.
3) billing генерирует счёт.
4) metrics обновляет дашборды.
Если завтра вы добавите ещё один микросервис, ему просто нужно реагировать на это событие. Payments не меняется.
Вот почему это так хорошо сочетается с микросервисами: каждый сохраняет единственную ответственность и может развиваться без прямой зависимости от остальных.
Очевидно, не всё только преимущества. Система также становится сложнее. Возникают такие проблемы, как повторные попытки, дублирующиеся события, порядок обработки и наблюдаемость.
На практике обычно используется брокер (например, Kafka или RabbitMQ), который получает событие и распределяет его по подписанным микросервисам.
👉 @KodBlog
Представьте систему с двумя микросервисами:
1) payments
2) emails
Когда платеж подтверждён, payments вызывает emails, чтобы отправить чек.
Но приложение растёт. Теперь нужно ещё сгенерировать счёт, обновить метрики и отправить уведомление.
Чтобы это сделать, payments начинает вызывать каждый из них.
Каждая новая функциональность добавляет ещё один вызов. Со временем такой поток становится всё сложнее поддерживать.
Event-Driven Architecture предлагает другой способ коммуникации.
Когда платеж подтверждён:
1) payments публикует событие "payment confirmed".
2) emails отправляет чек.
3) billing генерирует счёт.
4) metrics обновляет дашборды.
Если завтра вы добавите ещё один микросервис, ему просто нужно реагировать на это событие. Payments не меняется.
Вот почему это так хорошо сочетается с микросервисами: каждый сохраняет единственную ответственность и может развиваться без прямой зависимости от остальных.
Очевидно, не всё только преимущества. Система также становится сложнее. Возникают такие проблемы, как повторные попытки, дублирующиеся события, порядок обработки и наблюдаемость.
На практике обычно используется брокер (например, Kafka или RabbitMQ), который получает событие и распределяет его по подписанным микросервисам.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6👏2💯2🍾1
Ваш фоновый цикл, вероятно, не нуждается в Task.Delay.
Для периодической асинхронной работы PeriodicTimer делает намерение гораздо понятнее: дождаться следующего тика, выполнить работу, повторить.
Просто помните: один потребитель за раз, диспоозьте его, передавайте токен.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/api/system.threading.periodictimer?view=net-10.0
👉 @KodBlog
Для периодической асинхронной работы PeriodicTimer делает намерение гораздо понятнее: дождаться следующего тика, выполнить работу, повторить.
Просто помните: один потребитель за раз, диспоозьте его, передавайте токен.
Ссылка на документацию ниже.
https://learn.microsoft.com/ru-ru/dotnet/api/system.threading.periodictimer?view=net-10.0
Please open Telegram to view this post
VIEW IN TELEGRAM
👍8🍾2
Microsoft выпустила почти 100 готовых skills для AI-агентов, работающих с .NET
Microsoft без громких анонсов опубликовала набор из 99 готовых skills для AI-агентов, предназначенных для работы с .NET. Все они доступны в открытом доступе и могут использоваться в таких инструментах, как Claude Code, Codex, GitHub Copilot и Cursor.
Skills размещены в репозитории dotnet/skills и сгруппированы в 14 плагинов, включающих около 95 специализированных сценариев. Каждый skill представляет собой набор инструкций, который AI-агент автоматически загружает только при выполнении соответствующей задачи.
Среди наиболее полезных плагинов:
dotnet-data — помогает оптимизировать запросы EF Core, выявляет проблемы N+1, корректирует режимы отслеживания (tracking) и устраняет типичные узкие места производительности.
dotnet-test — крупнейший плагин, содержащий 22 skills для запуска, фильтрации и миграции тестов между различными тестовыми фреймворками.
dotnet-upgrade — автоматизирует миграцию проектов с .NET 8 на .NET 10 и включает поддержку nullable reference types.
dotnet-aspnet — предназначен для создания Web API и endpoints загрузки файлов с использованием Minimal APIs.
dotnet-ai — позволяет создавать, отлаживать и тестировать MCP-серверы с помощью C# SDK.
При этом Microsoft отмечает, что опубликованные skills решают только типовые задачи экосистемы .NET. Они не учитывают особенности конкретного проекта: структуру каталогов, архитектурные соглашения, расположение сущностей, используемые паттерны или внутренние правила разработки.
Для подобных сценариев разработчикам предлагается создавать собственные skills, которые описывают принятые в проекте конвенции и позволяют AI-агентам учитывать специфику конкретной кодовой базы.
Подробное руководство по созданию пользовательских skills, настройке Skill Creator и работе с репозиторием dotnet/skills опубликовано автором статьи на его сайте.
👉 @KodBlog
Microsoft без громких анонсов опубликовала набор из 99 готовых skills для AI-агентов, предназначенных для работы с .NET. Все они доступны в открытом доступе и могут использоваться в таких инструментах, как Claude Code, Codex, GitHub Copilot и Cursor.
Skills размещены в репозитории dotnet/skills и сгруппированы в 14 плагинов, включающих около 95 специализированных сценариев. Каждый skill представляет собой набор инструкций, который AI-агент автоматически загружает только при выполнении соответствующей задачи.
Среди наиболее полезных плагинов:
dotnet-data — помогает оптимизировать запросы EF Core, выявляет проблемы N+1, корректирует режимы отслеживания (tracking) и устраняет типичные узкие места производительности.
dotnet-test — крупнейший плагин, содержащий 22 skills для запуска, фильтрации и миграции тестов между различными тестовыми фреймворками.
dotnet-upgrade — автоматизирует миграцию проектов с .NET 8 на .NET 10 и включает поддержку nullable reference types.
dotnet-aspnet — предназначен для создания Web API и endpoints загрузки файлов с использованием Minimal APIs.
dotnet-ai — позволяет создавать, отлаживать и тестировать MCP-серверы с помощью C# SDK.
При этом Microsoft отмечает, что опубликованные skills решают только типовые задачи экосистемы .NET. Они не учитывают особенности конкретного проекта: структуру каталогов, архитектурные соглашения, расположение сущностей, используемые паттерны или внутренние правила разработки.
Для подобных сценариев разработчикам предлагается создавать собственные skills, которые описывают принятые в проекте конвенции и позволяют AI-агентам учитывать специфику конкретной кодовой базы.
Подробное руководство по созданию пользовательских skills, настройке Skill Creator и работе с репозиторием dotnet/skills опубликовано автором статьи на его сайте.
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥12❤3🍾3
У твоей очереди нет тормозов.
Если производители добавляют задачи быстрее, чем потребители успевают их обрабатывать, безграничная очередь — это просто отсроченная боль.
Пятничный .NET-совет: используйте ограниченный Channel<t>.
Когда он заполняется, вы выбираете, что делать: ждать, отбрасывать или падать с ошибкой.</t>
https://learn.microsoft.com/ru-ru/dotnet/core/extensions/channels
👉 @KodBlog
Если производители добавляют задачи быстрее, чем потребители успевают их обрабатывать, безграничная очередь — это просто отсроченная боль.
Пятничный .NET-совет: используйте ограниченный Channel<t>.
Когда он заполняется, вы выбираете, что делать: ждать, отбрасывать или падать с ошибкой.</t>
https://learn.microsoft.com/ru-ru/dotnet/core/extensions/channels
Please open Telegram to view this post
VIEW IN TELEGRAM
👍9❤3🍾2
Ваше приложение запускается без ошибок.
Затем приходит первый настоящий запрос.
Он пытается вызвать GitHub, отправить email, подключиться к сервису или использовать флаг функции.
И только тогда вы узнаёте, что одно значение конфигурации отсутствует или неверно.
Плохой URL.
Пустой токен.
Отсутствующая настройка.
Приложение никогда не было готово к запуску.
Оно просто об этом не сообщило.
ASP.NET Core предоставляет строго типизированную конфигурацию через паттерн Options. Но привязка значений к классу — это только часть работы.
Вам также нужно знать, что эти значения валидны.
И здесь может помочь FluentValidation.
Вместо добавления простых правил в класс настроек, вы можете хранить валидацию в отдельном валидаторе и чётко описать реальные правила:
→ Обязательное значение должно существовать
→ URL должен быть валидным
→ Одна настройка может зависеть от другой
→ Пользовательские проверки можно тестировать независимо
Затем добавьте валидацию при запуске.
Теперь, если конфигурация неверна, приложение падает сразу при старте.
Именно это нужно в контейнере, CI-пайплайне или новом деплое.
Сломанное приложение должно упасть до получения трафика, а не после того, как пользователь найдёт проблему за вас.
👉 @KodBlog
Затем приходит первый настоящий запрос.
Он пытается вызвать GitHub, отправить email, подключиться к сервису или использовать флаг функции.
И только тогда вы узнаёте, что одно значение конфигурации отсутствует или неверно.
Плохой URL.
Пустой токен.
Отсутствующая настройка.
Приложение никогда не было готово к запуску.
Оно просто об этом не сообщило.
ASP.NET Core предоставляет строго типизированную конфигурацию через паттерн Options. Но привязка значений к классу — это только часть работы.
Вам также нужно знать, что эти значения валидны.
И здесь может помочь FluentValidation.
Вместо добавления простых правил в класс настроек, вы можете хранить валидацию в отдельном валидаторе и чётко описать реальные правила:
→ Обязательное значение должно существовать
→ URL должен быть валидным
→ Одна настройка может зависеть от другой
→ Пользовательские проверки можно тестировать независимо
Затем добавьте валидацию при запуске.
Теперь, если конфигурация неверна, приложение падает сразу при старте.
Именно это нужно в контейнере, CI-пайплайне или новом деплое.
Сломанное приложение должно упасть до получения трафика, а не после того, как пользователь найдёт проблему за вас.
Please open Telegram to view this post
VIEW IN TELEGRAM
👍6🍾2
This media is not supported in your browser
VIEW IN TELEGRAM
НОВИНКА: Устойчивые функции (Durable Functions) в PostgreSQL 🤯
pg_durable — это расширение PostgreSQL. Состояние рабочего процесса, очередь, повторные попытки и восстановление хранятся в Postgres, и оно использует устойчивость Postgres / высокую доступность / резервное копирование / восстановление.
https://techcommunity.microsoft.com/blog/adforpostgresql/introducing-durable-functions-in-postgresql/4526821
👉 @KodBlog
pg_durable — это расширение PostgreSQL. Состояние рабочего процесса, очередь, повторные попытки и восстановление хранятся в Postgres, и оно использует устойчивость Postgres / высокую доступность / резервное копирование / восстановление.
https://techcommunity.microsoft.com/blog/adforpostgresql/introducing-durable-functions-in-postgresql/4526821
Please open Telegram to view this post
VIEW IN TELEGRAM
🍾2👀2
Перестань просто читать книги по системному дизайну и начни тестировать архитектуры на практике (с помощью Chaos Engineering) — это казалось невозможным без огромных трат на AWS.
Но эта платформа, которая уже 2 года работает в продакшене, 100% бесплатна и с открытым кодом.
Познакомьтесь с Dinamos.
Представьте, что вы симулируете инфраструктуру WhatsApp или продажу билетов на грандиозное шоу.
В Dinamos вы загружаете готовые сценарии, видите запросы, падающие на балансировщик нагрузки, и в реальном времени через «Золотые сигналы» (Golden Signals) обнаруживаете узкие места в очереди сообщений (Message Bus).
И вы можете поэкспериментировать с Chaos Engineering.
Можете намеренно добавить задержки или просто «убить» узел в своей инфраструктуре, чтобы увидеть, как система поведёт себя под нагрузкой и сможет ли она масштабироваться автоматически. На практике — без лишних сложностей.
Готовитесь к System Design интервью?
В Dinamos есть симулятор на базе фреймворка System Design Canvas. Вы рисуете схему архитектуры, записываете голосовое объяснение своего решения, а ИИ оценивает ваш ответ, подсвечивая сильные стороны и указывая, что требовало лучшего обоснования. Это бесплатный тьютор.
Проект уже 2 года развивается вместе с комьюнити. Уроки охватывают всё — от Кеширования до теорем CAP / PACELC.
И всё двуязычно (PT/EN): можете прочитать концепцию на португальском и мгновенно переключиться на английский, чтобы выучить точные термины, используемые на международном рынке.
Проект создан разработчиками для разработчиков, чтобы демократизировать доступ к высокому техническому знанию. И он будет бесплатным навсегда.
http://dinamos.net это Open Source!💵
👉 @KodBlog
Но эта платформа, которая уже 2 года работает в продакшене, 100% бесплатна и с открытым кодом.
Представьте, что вы симулируете инфраструктуру WhatsApp или продажу билетов на грандиозное шоу.
В Dinamos вы загружаете готовые сценарии, видите запросы, падающие на балансировщик нагрузки, и в реальном времени через «Золотые сигналы» (Golden Signals) обнаруживаете узкие места в очереди сообщений (Message Bus).
И вы можете поэкспериментировать с Chaos Engineering.
Можете намеренно добавить задержки или просто «убить» узел в своей инфраструктуре, чтобы увидеть, как система поведёт себя под нагрузкой и сможет ли она масштабироваться автоматически. На практике — без лишних сложностей.
Готовитесь к System Design интервью?
В Dinamos есть симулятор на базе фреймворка System Design Canvas. Вы рисуете схему архитектуры, записываете голосовое объяснение своего решения, а ИИ оценивает ваш ответ, подсвечивая сильные стороны и указывая, что требовало лучшего обоснования. Это бесплатный тьютор.
Проект уже 2 года развивается вместе с комьюнити. Уроки охватывают всё — от Кеширования до теорем CAP / PACELC.
И всё двуязычно (PT/EN): можете прочитать концепцию на португальском и мгновенно переключиться на английский, чтобы выучить точные термины, используемые на международном рынке.
Проект создан разработчиками для разработчиков, чтобы демократизировать доступ к высокому техническому знанию. И он будет бесплатным навсегда.
http://dinamos.net это Open Source!
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥4👍1🍾1