День 2398. #ЗаметкиНаПолях
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Продолжение
Начало
1. Стандарты кодирования .NET и статический анализ
Идея заключается в создании NuGet-пакета, содержащего файлы .editorconfig, анализаторы и конфигурацию MSBuild. Этот пакет предоставляет:
- Единый стиль кодирования для всех проектов, которые на него ссылаются;
- Набор анализаторов Roslyn и базовую конфигурацию для обеспечения статического анализа в соответствии с передовыми практиками и требованиями безопасности;
- Свойства, элементы и таргеты MSBuild для настройки проекта, такие как включение обнуляемых ссылочных типов, применение стиля кода при сборке, обработка предупреждений как ошибок в непрерывной интеграции, включение аудита NuGet, включение ссылок на исходный код и многое другое.
Этот пакет позволяет удалить сотни строк шаблонного кода и конфигурации из каждого проекта:
- Разделы C# и VB.NET из файла .editorconfig (~100 строк);
- Файлы конфигурации, такие как Directory.Build.props и Directory.Build.targets (~70 строк);
- Конфигурацию анализатора (до нескольких сотен строк).
Поскольку это NuGet-пакет, его легко обновлять при публикации новой версии. Все проекты могут воспользоваться преимуществами новейших стандартов кодирования и анализаторов, а также предотвратить дрейф конфигурации. Пример такого пакета можно найти на GitHub.
В качестве бонуса можно написать тесты, чтобы убедиться, что все настройки работают как надо. Некоторые тесты вы найдёте в исходном коде пакета.
Можно добавлять некоторые функции в стандарт кодирования, например, запретить использование типов Newtonsoft.Json в проектах. Для этого достаточно добавить новое свойство в файл проекта:
Теперь у вас есть единое место для предоставления функций разработчикам, и его можно обновлять под ваши требования. Разработчики могут сосредоточиться на написании кода, а не на настройке своих проектов: применяйте правила, написанные в пакете, и всё.
Если вы используете .NET, настоятельно рекомендую почитать про MSBuild. А использование пакетов SDK для MSBuild открывает множество дополнительных возможностей.
2. Конфигурация Renovate
Renovate — это инструмент для автоматизации обновления зависимостей. Его можно настроить с помощью файла renovate.json. Файл конфигурации может быть довольно большим, особенно если у вас много зависимостей или вы хотите настроить поведение Renovate. Это может привести к дублированию данных в нескольких проектах, если у каждого проекта будет свой файл renovate.json. Кроме того, каждая команда может настраивать Renovate по-своему, что приводит к несоответствиям. Например, команды могут использовать разные форматы заголовков пул-реквестов, что затрудняет создание правил для их фильтрации.
Когда пакет обновляется и меняет свою лицензию, вы можете запретить обновление для всей компании, пока юридическая служба не просмотрит новую лицензию. Если у каждого проекта есть свой файл renovate.json, вам придётся обновлять каждый файл, чтобы предотвратить обновление, что утомительно и подвержено ошибкам.
Лучшее решение — создать общий файл конфигурации Renovate и ссылаться на него в каждом проекте. Вот пример файла. Также в GitHub Renovate автоматически ссылается на общую конфигурацию, если она находится в той же организации, а репозиторий называется renovate-config. Это означает, что вы можете удалить файл renovate.json из каждого проекта и позволить Renovate использовать общую конфигурацию, если вам не нужно её переопределять.
Продолжение следует…
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Продолжение
Начало
1. Стандарты кодирования .NET и статический анализ
Идея заключается в создании NuGet-пакета, содержащего файлы .editorconfig, анализаторы и конфигурацию MSBuild. Этот пакет предоставляет:
- Единый стиль кодирования для всех проектов, которые на него ссылаются;
- Набор анализаторов Roslyn и базовую конфигурацию для обеспечения статического анализа в соответствии с передовыми практиками и требованиями безопасности;
- Свойства, элементы и таргеты MSBuild для настройки проекта, такие как включение обнуляемых ссылочных типов, применение стиля кода при сборке, обработка предупреждений как ошибок в непрерывной интеграции, включение аудита NuGet, включение ссылок на исходный код и многое другое.
Этот пакет позволяет удалить сотни строк шаблонного кода и конфигурации из каждого проекта:
- Разделы C# и VB.NET из файла .editorconfig (~100 строк);
- Файлы конфигурации, такие как Directory.Build.props и Directory.Build.targets (~70 строк);
- Конфигурацию анализатора (до нескольких сотен строк).
Поскольку это NuGet-пакет, его легко обновлять при публикации новой версии. Все проекты могут воспользоваться преимуществами новейших стандартов кодирования и анализаторов, а также предотвратить дрейф конфигурации. Пример такого пакета можно найти на GitHub.
В качестве бонуса можно написать тесты, чтобы убедиться, что все настройки работают как надо. Некоторые тесты вы найдёте в исходном коде пакета.
Можно добавлять некоторые функции в стандарт кодирования, например, запретить использование типов Newtonsoft.Json в проектах. Для этого достаточно добавить новое свойство в файл проекта:
<PropertyGroup>
<BanNewtonsoftJsonSymbols>true</BanNewtonsoftJsonSymbols>
</PropertyGroup>
Теперь у вас есть единое место для предоставления функций разработчикам, и его можно обновлять под ваши требования. Разработчики могут сосредоточиться на написании кода, а не на настройке своих проектов: применяйте правила, написанные в пакете, и всё.
Если вы используете .NET, настоятельно рекомендую почитать про MSBuild. А использование пакетов SDK для MSBuild открывает множество дополнительных возможностей.
2. Конфигурация Renovate
Renovate — это инструмент для автоматизации обновления зависимостей. Его можно настроить с помощью файла renovate.json. Файл конфигурации может быть довольно большим, особенно если у вас много зависимостей или вы хотите настроить поведение Renovate. Это может привести к дублированию данных в нескольких проектах, если у каждого проекта будет свой файл renovate.json. Кроме того, каждая команда может настраивать Renovate по-своему, что приводит к несоответствиям. Например, команды могут использовать разные форматы заголовков пул-реквестов, что затрудняет создание правил для их фильтрации.
Когда пакет обновляется и меняет свою лицензию, вы можете запретить обновление для всей компании, пока юридическая служба не просмотрит новую лицензию. Если у каждого проекта есть свой файл renovate.json, вам придётся обновлять каждый файл, чтобы предотвратить обновление, что утомительно и подвержено ошибкам.
Лучшее решение — создать общий файл конфигурации Renovate и ссылаться на него в каждом проекте. Вот пример файла. Также в GitHub Renovate автоматически ссылается на общую конфигурацию, если она находится в той же организации, а репозиторий называется renovate-config. Это означает, что вы можете удалить файл renovate.json из каждого проекта и позволить Renovate использовать общую конфигурацию, если вам не нужно её переопределять.
Продолжение следует…
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
👍11
День 2399. #ЗаметкиНаПолях
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Продолжение
Начало
Продолжение
3. Пакет ServiceDefaults
При создании нескольких веб-API или рабочих процессов вам может потребоваться повторять одну и ту же конфигурацию для каждого проекта. Например, потребуется добавить Azure AppConfiguration, настроить OpenTelemetry, логирование, проверки работоспособности, и т.п. Вместо того, чтобы дублировать эту конфигурацию во всех проектах, вы можете создать общий пакет ServiceDefaults, содержащий общую конфигурацию, и использовать его в каждом проекте. Главное преимущество — возможность лёгкого обновления с течением времени. Если вам нужно изменить конфигурацию OpenTelemetry, вы можете сделать это в пакете, и все проекты, которые на него ссылаются, обновятся.
Если вы знакомы с шаблоном .NET Aspire, вы, возможно, видели проект ServiceDefaults. Он предоставляет набор общих сервисов и конфигураций, которые можно использовать повторно в нескольких проектах в рамках одного решения. Но можно ведь создать NuGet-пакет, который можно использовать в любом проекте.
Пример проекта пакета на GitHub.
4. Задачи MSBuild
MSBuild — это расширяемая система сборки, позволяющая создавать пользовательские задачи и таргеты. На сайте nuget.org представлено несколько пакетов для добавления задач MSBuild в ваш проект. Например, вы можете автоматически устанавливать версию своего проекта с помощью MinVer, GitVersion.MsBuild или Nerdbank.GitVersioning. А, например, пакет Workleap.OpenApi.MSBuild интегрируется в процесс сборки (dotnet build), чтобы гарантировать актуальность файла спецификации OpenAPI, соответствие коду, стандартам компании и отсутствие критических изменений в API.
5. Фрагменты файлов
Иногда удалить шаблонный код невозможно. В этом случае стратегия заключается в том, чтобы поместить его в «область», которую можно легко идентифицировать и обновить. Версионирование и обновление общей части файла можно осуществлять с помощью такого инструмента, как Renovate.
Общие части файлов заключаются в комментарии
6. Конвейеры CI/CD
Конвейеры — ещё один хороший вариант для совместного использования между проектами. Существуют различные стратегии совместного использования конвейеров.
Комплаенс-конвейеры (например, SAST, DAST, сканирование зависимостей и т.д.) можно перенести на уровень организации. Это гарантирует, что все проекты будут иметь одинаковые проверки соответствия, и вы сможете обновлять их в одном месте. Это также избавит от необходимости обновлять каждый проект при изменении проверок соответствия.
GitHub предоставляет гибкие способы совместного использования частей конвейеров CI/CD:
- композитные действия
- настраиваемые действия
- повторно используемые рабочие процессы
Окончание следует…
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Продолжение
Начало
Продолжение
3. Пакет ServiceDefaults
При создании нескольких веб-API или рабочих процессов вам может потребоваться повторять одну и ту же конфигурацию для каждого проекта. Например, потребуется добавить Azure AppConfiguration, настроить OpenTelemetry, логирование, проверки работоспособности, и т.п. Вместо того, чтобы дублировать эту конфигурацию во всех проектах, вы можете создать общий пакет ServiceDefaults, содержащий общую конфигурацию, и использовать его в каждом проекте. Главное преимущество — возможность лёгкого обновления с течением времени. Если вам нужно изменить конфигурацию OpenTelemetry, вы можете сделать это в пакете, и все проекты, которые на него ссылаются, обновятся.
Если вы знакомы с шаблоном .NET Aspire, вы, возможно, видели проект ServiceDefaults. Он предоставляет набор общих сервисов и конфигураций, которые можно использовать повторно в нескольких проектах в рамках одного решения. Но можно ведь создать NuGet-пакет, который можно использовать в любом проекте.
Пример проекта пакета на GitHub.
4. Задачи MSBuild
MSBuild — это расширяемая система сборки, позволяющая создавать пользовательские задачи и таргеты. На сайте nuget.org представлено несколько пакетов для добавления задач MSBuild в ваш проект. Например, вы можете автоматически устанавливать версию своего проекта с помощью MinVer, GitVersion.MsBuild или Nerdbank.GitVersioning. А, например, пакет Workleap.OpenApi.MSBuild интегрируется в процесс сборки (dotnet build), чтобы гарантировать актуальность файла спецификации OpenAPI, соответствие коду, стандартам компании и отсутствие критических изменений в API.
5. Фрагменты файлов
Иногда удалить шаблонный код невозможно. В этом случае стратегия заключается в том, чтобы поместить его в «область», которую можно легко идентифицировать и обновить. Версионирование и обновление общей части файла можно осуществлять с помощью такого инструмента, как Renovate.
Общие части файлов заключаются в комментарии
# reference:<URL> и # endreference. Таким образом, вы можете легко найти общую часть файла и обновить её при необходимости. Версию общей части файла можно контролировать с помощью тегов и обновлять с помощью Renovate. Обратите внимание, что Renovate позволяет запускать пользовательские инструменты после обновления ссылки.
# reference:https://…/.editorconfig
root = true
[*]
indent_style = space
trim_trailing_whitespace = true
end_of_line = lf
…
# endreference
# Настройки специфичные для проекта
[*.cs]
dotnet_diagnostic.CA1008.severity = none
…
6. Конвейеры CI/CD
Конвейеры — ещё один хороший вариант для совместного использования между проектами. Существуют различные стратегии совместного использования конвейеров.
Комплаенс-конвейеры (например, SAST, DAST, сканирование зависимостей и т.д.) можно перенести на уровень организации. Это гарантирует, что все проекты будут иметь одинаковые проверки соответствия, и вы сможете обновлять их в одном месте. Это также избавит от необходимости обновлять каждый проект при изменении проверок соответствия.
GitHub предоставляет гибкие способы совместного использования частей конвейеров CI/CD:
- композитные действия
- настраиваемые действия
- повторно используемые рабочие процессы
Окончание следует…
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
День 2400. #ЗаметкиНаПолях
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Окончание
Начало
Продолжение 1-2
Продолжение 3-5
7. Dockerfile
Вам действительно нужен Dockerfile? Некоторые технологии, такие как .NET, позволяют создавать образы Docker без Dockerfile. Например, можно использовать dotnet publish для создания образа и его отправки в реестр. Это не только избавляет от шаблонного кода, но и повышает производительность. Это также позволяет избежать многих распространённых проблем с Dockerfile, таких как кэширование.
8. Helm-чарты
Поскольку вы можете устанавливать стандарты с помощью пакетов MSBuild или SDK, вы можете повторно использовать эти стандарты в Helm-чартах. Например, вы можете настроить проверки готовности и жизнеспособности в общем чарте. Вы также можете добавить параметры, специфичные для вашей инфраструктуры, такие как сертификаты, автоматическое масштабирование, идентификацию пода Azure и т.д. Таким образом, вы можете удалить шаблонный код из Helm-чартов и сделать их более пригодными для повторного использования в разных проектах. В большинстве проектов требуется задать имя образа, ограничения на ресурсы ЦП и памяти. Остальные параметры должны быть общими для большинства проектов.
9. Модули PowerShell
PowerShell — мощный язык сценариев, который можно использовать для автоматизации задач и управления системами. Он очень распространён в непрерывной интеграции (CI) или для локальных операций. Модули PowerShell — отличный способ совместного использования скриптов и функций в разных проектах. Вы можете создать модуль, содержащий общие функции и скрипты, которые можно использовать повторно в нескольких проектах, используя команду
Модули имеют версии и публикуются как NuGet-пакеты, поэтому вы можете легко обновлять их при необходимости:
- Publish-Module
- Install-Module
Обновление существующих проектов
Предоставление общих библиотек и конфигурации — это здорово, но для их использования также необходимо обновить существующие проекты. Это может быть непросто, поскольку вам, возможно, придётся обновлять сотни проектов. Лучший способ сделать это — создать инструмент, который будет автоматически это делать. Вот пример кода такого инструмента. Он клонирует все репозитории и применяет к ним миграцию. Затем создаёт пулл-реквест с изменениями. Некоторые миграции просты и могут быть написаны детерминированным способом. Для более сложных миграций скрипт миграции может использовать ИИ для помощи.
Обратите внимание, что вы можете применить стратегию ограничения изменений, чтобы избежать перегрузки не только сервера Git слишком большим количеством пулл-реквестов одновременно, но и системы сборки слишком большим количеством задач. Это помешает команде разработчиков работать над другими задачами во время выполнения миграции.
Итого
Просмотрите свои проекты и определите, есть ли что-то ещё, что можно использовать по ссылке. Например:
- Конфигурациями IDE (например, .vscode, vsconfig для Visual Studio)
- Git-хуки
- Инструменты разработки, необходимые для запуска проекта (например, dev-контейнеры, GitHub Codespaces, devbox и т. д.). Фактически, обратите внимание на всё, что не является бизнес-кодом, и подумайте, можно ли удалить это из проекта.
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
Сокращаем Шаблонный Код и Поддерживаем Согласованность Проекта. Окончание
Начало
Продолжение 1-2
Продолжение 3-5
7. Dockerfile
Вам действительно нужен Dockerfile? Некоторые технологии, такие как .NET, позволяют создавать образы Docker без Dockerfile. Например, можно использовать dotnet publish для создания образа и его отправки в реестр. Это не только избавляет от шаблонного кода, но и повышает производительность. Это также позволяет избежать многих распространённых проблем с Dockerfile, таких как кэширование.
# Dockerfile не нужен
dotnet publish -p:PublishProfile=DefaultContainer
8. Helm-чарты
Поскольку вы можете устанавливать стандарты с помощью пакетов MSBuild или SDK, вы можете повторно использовать эти стандарты в Helm-чартах. Например, вы можете настроить проверки готовности и жизнеспособности в общем чарте. Вы также можете добавить параметры, специфичные для вашей инфраструктуры, такие как сертификаты, автоматическое масштабирование, идентификацию пода Azure и т.д. Таким образом, вы можете удалить шаблонный код из Helm-чартов и сделать их более пригодными для повторного использования в разных проектах. В большинстве проектов требуется задать имя образа, ограничения на ресурсы ЦП и памяти. Остальные параметры должны быть общими для большинства проектов.
9. Модули PowerShell
PowerShell — мощный язык сценариев, который можно использовать для автоматизации задач и управления системами. Он очень распространён в непрерывной интеграции (CI) или для локальных операций. Модули PowerShell — отличный способ совместного использования скриптов и функций в разных проектах. Вы можете создать модуль, содержащий общие функции и скрипты, которые можно использовать повторно в нескольких проектах, используя команду
Import-Module -Name <ModuleName> -RequiredVersion <ModuleVersion>
Модули имеют версии и публикуются как NuGet-пакеты, поэтому вы можете легко обновлять их при необходимости:
- Publish-Module
- Install-Module
Обновление существующих проектов
Предоставление общих библиотек и конфигурации — это здорово, но для их использования также необходимо обновить существующие проекты. Это может быть непросто, поскольку вам, возможно, придётся обновлять сотни проектов. Лучший способ сделать это — создать инструмент, который будет автоматически это делать. Вот пример кода такого инструмента. Он клонирует все репозитории и применяет к ним миграцию. Затем создаёт пулл-реквест с изменениями. Некоторые миграции просты и могут быть написаны детерминированным способом. Для более сложных миграций скрипт миграции может использовать ИИ для помощи.
Обратите внимание, что вы можете применить стратегию ограничения изменений, чтобы избежать перегрузки не только сервера Git слишком большим количеством пулл-реквестов одновременно, но и системы сборки слишком большим количеством задач. Это помешает команде разработчиков работать над другими задачами во время выполнения миграции.
Итого
Просмотрите свои проекты и определите, есть ли что-то ещё, что можно использовать по ссылке. Например:
- Конфигурациями IDE (например, .vscode, vsconfig для Visual Studio)
- Git-хуки
- Инструменты разработки, необходимые для запуска проекта (например, dev-контейнеры, GitHub Codespaces, devbox и т. д.). Фактически, обратите внимание на всё, что не является бизнес-кодом, и подумайте, можно ли удалить это из проекта.
Источник: https://www.meziantou.net/reduce-boilerplate-and-maintain-project-consistency.htm
👍4
День 2401. #ЗаметкиНаПолях
Разница Между Выражениями и Инициализаторами Коллекций
Вы когда-нибудь задумывались, есть ли разница между выражением коллекции:
и инициализатором коллекции:
Давайте выясним. Для этого посмотрим, во что преобразуется каждая строчка.
Выражение коллекции:
Инициализатор коллекции:
Таким образом, выражения для коллекций ([1,2,3]) «умнее» и быстрее в том смысле, что они заранее выделяют список с точным количеством элементов, которые мы хотим добавить. Инициализатор коллекции не делает этого по одной простой причине: компилятор, согласно своей спецификации, обязан вызывать метод Add для каждого элемента в инициализаторе.
Конечно, для 3х элементов особой разницы в производительности не будет. А вот, например, бенчмарк для 17 элементов:
Вопрос, почему здесь инициализатор тратит больше времени и памяти, любят задавать на собесах. Кто знает, пишите в комментариях.
Источник: https://steven-giesel.com/blogPost/fea0b033-ccf5-4197-b62c-ffd8ca6d79c7/quick-one-difference-between-collection-expressions-and-collection-initializer
Разница Между Выражениями и Инициализаторами Коллекций
Вы когда-нибудь задумывались, есть ли разница между выражением коллекции:
List<int> list = [1, 2, 3];
и инициализатором коллекции:
List<int> list2 = new() {1,2,3};Давайте выясним. Для этого посмотрим, во что преобразуется каждая строчка.
Выражение коллекции:
int num = 3;
List<int> list = new List<int>(num);
CollectionsMarshal.SetCount(list, num);
Span<int> span = CollectionsMarshal.AsSpan(list);
int num2 = 0;
span[num2] = 1;
num2++;
span[num2] = 2;
num2++;
span[num2] = 3;
num2++;
Инициализатор коллекции:
List<int> list2 = new List<int>();
list2.Add(1);
list2.Add(2);
list2.Add(3);
Таким образом, выражения для коллекций ([1,2,3]) «умнее» и быстрее в том смысле, что они заранее выделяют список с точным количеством элементов, которые мы хотим добавить. Инициализатор коллекции не делает этого по одной простой причине: компилятор, согласно своей спецификации, обязан вызывать метод Add для каждого элемента в инициализаторе.
Конечно, для 3х элементов особой разницы в производительности не будет. А вот, например, бенчмарк для 17 элементов:
| Method | Mean | Allocated |
|-----------|---------:|----------:|
|Expression | 18.09 ns | 128 B |
|Initializer| 72.88 ns | 368 B |
Вопрос, почему здесь инициализатор тратит больше времени и памяти, любят задавать на собесах. Кто знает, пишите в комментариях.
Источник: https://steven-giesel.com/blogPost/fea0b033-ccf5-4197-b62c-ffd8ca6d79c7/quick-one-difference-between-collection-expressions-and-collection-initializer
👍41
День 2402. #ЧтоНовенького #NET10
Новинки в .NET 10 Превью 7. ASP.NET Core
1. В промежуточное ПО обработки исключений ASP.NET Core добавлен новый параметр конфигурации для управления диагностическим выводом ExceptionHandlerOptions.SuppressDiagnosticsCallback. Этот метод обратного вызова получает контекст запроса и исключения, позволяя добавить логику, определяющую, должно ли промежуточное ПО записывать логи исключения и другие телеметрические данные.
Это полезно, когда вы знаете, что исключение является временным или уже где-то обрабатывается, и вы не хотите, чтобы логи этого исключения засоряли ваш дашборд.
Кроме того, изменилось поведение промежуточного ПО обработки исключений по умолчанию: диагностические данные для исключений, обрабатываемых IExceptionHandler, больше не записываются. Согласно отзывам пользователей, логирование обработанных исключений на уровне ошибок часто было нежелательным, если IExceptionHandler.TryHandleAsync возвращал true. Вернуть предыдущее поведение можно, добавив следующий код:
2. По умолчанию неаутентифицированные и неавторизованные запросы к известным конечным точкам API, защищенным аутентификацией через cookie, теперь приводят к ответам 401 и 403, а не к перенаправлению на URI входа в систему. Такое перенаправление обычно не имеет смысла для API.
Конечные точки API идентифицируются с помощью нового интерфейса IApiEndpointMetadata, и его реализация была автоматически добавлена для следующих конечные точек:
- в [ApiController];
- в минимальных API, принимающих JSON в теле запроса или выдающих JSON-ответы;
- использующих типы возврата TypedResults;
- в SignalR.
Если вы хотите предотвратить это новое поведение, вы можете переопределить события RedirectToLogin и RedirectToAccessDenied при вызове builder.Services.AddAuthentication().AddCookie(…).
3. Упрощены и расширены API аутентификации по ключу доступа (passkey) в шаблонах веб-приложений Blazor, что упрощает реализацию сценариев входа без пароля. Можно попробовать новый шаблон приложения Blazor с поддержкой ключа доступа:
4. ASP.NET Core теперь полностью поддерживает домен верхнего уровня .localhost, что позволяет разработчикам запускать несколько локальных приложений с более чётким разделением доменов. Встроенный веб-сервер Kestrel распознаёт адреса .localhost как локальные (loopback), обеспечивая безопасную и согласованную локальную разработку.
5. MVC, Minimal API и методы HttpRequestJsonExtensions.ReadFromJsonAsync были обновлены для поддержки PipeReader в System.Text.Json, что не требует внесения каких-либо изменений в код приложений.
Для большинства приложений это не должно повлиять на поведение. Однако, если приложение использует кастомный JsonConverter, существует вероятность, что конвертер будет некорректно обрабатывать Utf8JsonReader.HasValueSequence. Это может привести к потере данных и возникновению ошибок, таких как ArgumentOutOfRangeException, при десериализации.
Быстрый способ решения проблемы (особенно если вы не являетесь владельцем используемого кастомного JsonConverter) — установить переключатель AppContext "Microsoft.AspNetCore.UseStreamBasedJsonParsing" в значение true. Это должно быть временным решением, а JsonConverter(ы) следует обновить для поддержки HasValueSequence.
6. Теперь можно использовать атрибуты валидации как для классов, так и для записей, что обеспечивает единообразие генерации кода и поведения валидации. Это повышает гибкость при проектировании моделей с использованием записей в приложениях ASP.NET Core.
Источник: https://www.infoq.com/news/2025/08/dotnet-10-preview-7/
Новинки в .NET 10 Превью 7. ASP.NET Core
1. В промежуточное ПО обработки исключений ASP.NET Core добавлен новый параметр конфигурации для управления диагностическим выводом ExceptionHandlerOptions.SuppressDiagnosticsCallback. Этот метод обратного вызова получает контекст запроса и исключения, позволяя добавить логику, определяющую, должно ли промежуточное ПО записывать логи исключения и другие телеметрические данные.
Это полезно, когда вы знаете, что исключение является временным или уже где-то обрабатывается, и вы не хотите, чтобы логи этого исключения засоряли ваш дашборд.
Кроме того, изменилось поведение промежуточного ПО обработки исключений по умолчанию: диагностические данные для исключений, обрабатываемых IExceptionHandler, больше не записываются. Согласно отзывам пользователей, логирование обработанных исключений на уровне ошибок часто было нежелательным, если IExceptionHandler.TryHandleAsync возвращал true. Вернуть предыдущее поведение можно, добавив следующий код:
app.UseExceptionHandler(new ExceptionHandlerOptions
{
SuppressDiagnosticsCallback = context => false;
});
2. По умолчанию неаутентифицированные и неавторизованные запросы к известным конечным точкам API, защищенным аутентификацией через cookie, теперь приводят к ответам 401 и 403, а не к перенаправлению на URI входа в систему. Такое перенаправление обычно не имеет смысла для API.
Конечные точки API идентифицируются с помощью нового интерфейса IApiEndpointMetadata, и его реализация была автоматически добавлена для следующих конечные точек:
- в [ApiController];
- в минимальных API, принимающих JSON в теле запроса или выдающих JSON-ответы;
- использующих типы возврата TypedResults;
- в SignalR.
Если вы хотите предотвратить это новое поведение, вы можете переопределить события RedirectToLogin и RedirectToAccessDenied при вызове builder.Services.AddAuthentication().AddCookie(…).
3. Упрощены и расширены API аутентификации по ключу доступа (passkey) в шаблонах веб-приложений Blazor, что упрощает реализацию сценариев входа без пароля. Можно попробовать новый шаблон приложения Blazor с поддержкой ключа доступа:
dotnet new blazor -au Individual
4. ASP.NET Core теперь полностью поддерживает домен верхнего уровня .localhost, что позволяет разработчикам запускать несколько локальных приложений с более чётким разделением доменов. Встроенный веб-сервер Kestrel распознаёт адреса .localhost как локальные (loopback), обеспечивая безопасную и согласованную локальную разработку.
5. MVC, Minimal API и методы HttpRequestJsonExtensions.ReadFromJsonAsync были обновлены для поддержки PipeReader в System.Text.Json, что не требует внесения каких-либо изменений в код приложений.
Для большинства приложений это не должно повлиять на поведение. Однако, если приложение использует кастомный JsonConverter, существует вероятность, что конвертер будет некорректно обрабатывать Utf8JsonReader.HasValueSequence. Это может привести к потере данных и возникновению ошибок, таких как ArgumentOutOfRangeException, при десериализации.
Быстрый способ решения проблемы (особенно если вы не являетесь владельцем используемого кастомного JsonConverter) — установить переключатель AppContext "Microsoft.AspNetCore.UseStreamBasedJsonParsing" в значение true. Это должно быть временным решением, а JsonConverter(ы) следует обновить для поддержки HasValueSequence.
6. Теперь можно использовать атрибуты валидации как для классов, так и для записей, что обеспечивает единообразие генерации кода и поведения валидации. Это повышает гибкость при проектировании моделей с использованием записей в приложениях ASP.NET Core.
Источник: https://www.infoq.com/news/2025/08/dotnet-10-preview-7/
👍9
День 2403. #TipsAndTricks
Git Worktree: Управление Несколькими Рабочими Каталогами
Git Worktree — это мощный инструмент, позволяющий связать несколько рабочих каталогов с одним репозиторием. Вместо того, чтобы переключаться между ветками и потенциально терять незафиксированную работу, вы можете одновременно извлекать разные ветки в разных каталогах без повторного клонирования репозитория.
Git Worktree создаёт дополнительные рабочие папки (деревья), связанные с тем же репозиторием. Каждое рабочее дерево может иметь извлекаемую ветку, что позволяет работать над несколькими функциями, исправлением ошибок или экспериментами без необходимости многократного клонирования всего репозитория. Главное преимущество заключается в том, что у вас есть только один индекс Git (каталог .git), что снижает использование дискового пространства и повышает производительность.
В процессе написания кода переключение контекстов может мешать работе. Рабочее дерево Git помогает:
- Сохранять контекст. Сохраняйте текущую работу без изменений, быстро переключаясь между исправлением ошибки или проверкой кода.
- Работать параллельно. Работайте над несколькими функциями одновременно без накладных расходов на переключение веток.
- Использовать ИИ-агента. Вы можете поручить ИИ-агенту работать над отдельной веткой, пока вы продолжаете выполнять текущие задачи.
- Снижать когнитивную нагрузку. Не нужно откладывать или фиксировать незавершенную работу при переключении задач.
- Сравнивать файлы. Легко сравнивайте изменения между ветками без необходимости переключаться между ними. Вы можете открыть несколько версий одного и того же файла в разных рабочих деревьях, что упрощает отслеживание того, как изменения влияют на ваш код.
Чтобы создать новое рабочее дерево:
Чтобы удалить рабочее дерево, можно использовать следующие команды:
Также можно получить список рабочих деревьев:
Рекомендации
- Храните рабочие деревья в предсказуемом месте (например, в каталогах на одном уровне с репозиториями).
- Используйте описательные имена каталогов, соответствующие названиям веток.
- Регулярно очищайте неиспользуемые рабочие деревья, чтобы избежать беспорядка.
Итого
Рабочее дерево Git — это малоиспользуемая функция, которая может значительно улучшить процесс разработки, особенно когда вам нужно одновременно поддерживать несколько контекстов.
Источник: https://www.meziantou.net/git-worktree-managing-multiple-working-directories.htm
Git Worktree: Управление Несколькими Рабочими Каталогами
Git Worktree — это мощный инструмент, позволяющий связать несколько рабочих каталогов с одним репозиторием. Вместо того, чтобы переключаться между ветками и потенциально терять незафиксированную работу, вы можете одновременно извлекать разные ветки в разных каталогах без повторного клонирования репозитория.
Git Worktree создаёт дополнительные рабочие папки (деревья), связанные с тем же репозиторием. Каждое рабочее дерево может иметь извлекаемую ветку, что позволяет работать над несколькими функциями, исправлением ошибок или экспериментами без необходимости многократного клонирования всего репозитория. Главное преимущество заключается в том, что у вас есть только один индекс Git (каталог .git), что снижает использование дискового пространства и повышает производительность.
В процессе написания кода переключение контекстов может мешать работе. Рабочее дерево Git помогает:
- Сохранять контекст. Сохраняйте текущую работу без изменений, быстро переключаясь между исправлением ошибки или проверкой кода.
- Работать параллельно. Работайте над несколькими функциями одновременно без накладных расходов на переключение веток.
- Использовать ИИ-агента. Вы можете поручить ИИ-агенту работать над отдельной веткой, пока вы продолжаете выполнять текущие задачи.
- Снижать когнитивную нагрузку. Не нужно откладывать или фиксировать незавершенную работу при переключении задач.
- Сравнивать файлы. Легко сравнивайте изменения между ветками без необходимости переключаться между ними. Вы можете открыть несколько версий одного и того же файла в разных рабочих деревьях, что упрощает отслеживание того, как изменения влияют на ваш код.
Чтобы создать новое рабочее дерево:
# Рабочее дерево для существующей ветки
git worktree add ../feature-branch feature-branch
# Рабочее дерево для новой ветки из main
git worktree add -b new-feature ../new-feature origin/main
Чтобы удалить рабочее дерево, можно использовать следующие команды:
# Удалить рабочее дерево
git worktree remove ../feature-branch
# Удалить директорию и очистить метаданные
rm -rf ../feature-branch
git worktree prune
Также можно получить список рабочих деревьев:
git worktree list
Рекомендации
- Храните рабочие деревья в предсказуемом месте (например, в каталогах на одном уровне с репозиториями).
- Используйте описательные имена каталогов, соответствующие названиям веток.
- Регулярно очищайте неиспользуемые рабочие деревья, чтобы избежать беспорядка.
Итого
Рабочее дерево Git — это малоиспользуемая функция, которая может значительно улучшить процесс разработки, особенно когда вам нужно одновременно поддерживать несколько контекстов.
Источник: https://www.meziantou.net/git-worktree-managing-multiple-working-directories.htm
👍16
День 2404. #Карьера
8 Правил Прохождения Техсобеса. Начало
Советы от шведского разработчика/архитектора ПО Виктора 'viblo' Бломквиста. Советы, основаны на его опыте работы и собеседований на «обычные» должности разработчиков в Европе, особенно в Швеции, в небольших и средних технологических компаниях, где интервьюеры не стремятся вас унизить или подшутить над вами. Думаю, они подойдут и для многих наших компаний.
1. Практика — залог успеха
Главный совет - сначала попрактиковаться! Не в смысле сотни часов на LeetCode или заучивания документации по Kubernetes. В смысле «тренировочных собеседований», чтобы освоиться в обстановке собеседования. Многие (большинство?) разработчики просто не очень комфортно чувствуют себя на собеседованиях, и практика действительно помогает. Совершенно нормально нервничать, запинаться и т.п. Но нужно уметь рассказать интервьюеру, что вы знаете! Я как-то не смог рассказать, какими способами можно передавать данные между разными процессами. Да, просто нервничал и был неудачный день. Но при этом, несмотря на солидный опыт и резюме, такого кандидата сложно рекомендовать к найму, независимо от других качеств.
В начале карьеры собеседования – это стресс. А мы не любим делать то, что вызывает стресс, поэтому боимся практиковаться. Не повторяйте эту ошибку! Практика — залог успеха!
2. Резюме. Много коротких работ
У некоторых кандидатов много коротких работ (например, 3-5 работ продолжительностью год или меньше). Это не критично, и скорее всего, вас пригласят на собеседование в любом случае. Но вам нужно иметь веские аргументы, почему на этой работе будет по-другому. Если, конечно, компания специально не ищет человека на короткий срок. Продумайте свои доводы заранее. И, вероятно, лучше упомянуть об этом до того, как вас об этом спросят.
3. Резюме. Изменения ролей
Если ваша текущая должность отличается от той, на которую вы претендуете, необходимо это осветить и объяснить. Это также важно и тогда, когда вы претендуете на более «низкую» должность. Один из типичных случаев — кандидаты, которые сейчас возглавляют небольшую команду, но подают заявку на должность разработчика. Такие кандидаты и их опыт могут быть очень ценными, особенно при найме на должность старшего разработчика в небольшой компании, где от разработчиков ожидается больше ответственности, чем просто выполнение заранее спланированной задачи. В то же время есть несколько вещей, в которых вам следует убедить интервьюеров:
- что у вас всё ещё есть технические навыки. Руководители команд нередко теряют связь с технологиями, или, возможно, изначально не были так увлечены ими;
- объяснить, почему вы хотите вернуться к программированию на постоянной основе. То, что вы не можете найти работу тимлидом – не очень хорошее объяснение.
4. Не говорите слишком много
Особенно если вы в чём-то не уверены, длительное рассуждение не поможет. Звучит очевидно, правда? Но, видимо, на практике про это забывают! Бывают кандидаты, которые могут дать достойный ответ на простой вопрос, но затем заваливают свой собственный ответ, пускаясь в рассуждения.
Связанная с этим проблема: вы, как ни парадоксально, можете не дать интервьюеру достаточно узнать о вас. Часто лучший результат технического вопроса — это обсуждение с интервьюером(-ами) на равных. Это возможно только в том случае, если вы позволите интервьюеру говорить и не будете уходить в десятиминутный монолог на заданную тему. Это особенно важно, если у вас нет глубокого опыта в этой теме или вы не умеете хорошо выступать.
Окончание следует…
Источник: https://www.viblo.se/posts/interviewing/
8 Правил Прохождения Техсобеса. Начало
Советы от шведского разработчика/архитектора ПО Виктора 'viblo' Бломквиста. Советы, основаны на его опыте работы и собеседований на «обычные» должности разработчиков в Европе, особенно в Швеции, в небольших и средних технологических компаниях, где интервьюеры не стремятся вас унизить или подшутить над вами. Думаю, они подойдут и для многих наших компаний.
1. Практика — залог успеха
Главный совет - сначала попрактиковаться! Не в смысле сотни часов на LeetCode или заучивания документации по Kubernetes. В смысле «тренировочных собеседований», чтобы освоиться в обстановке собеседования. Многие (большинство?) разработчики просто не очень комфортно чувствуют себя на собеседованиях, и практика действительно помогает. Совершенно нормально нервничать, запинаться и т.п. Но нужно уметь рассказать интервьюеру, что вы знаете! Я как-то не смог рассказать, какими способами можно передавать данные между разными процессами. Да, просто нервничал и был неудачный день. Но при этом, несмотря на солидный опыт и резюме, такого кандидата сложно рекомендовать к найму, независимо от других качеств.
В начале карьеры собеседования – это стресс. А мы не любим делать то, что вызывает стресс, поэтому боимся практиковаться. Не повторяйте эту ошибку! Практика — залог успеха!
2. Резюме. Много коротких работ
У некоторых кандидатов много коротких работ (например, 3-5 работ продолжительностью год или меньше). Это не критично, и скорее всего, вас пригласят на собеседование в любом случае. Но вам нужно иметь веские аргументы, почему на этой работе будет по-другому. Если, конечно, компания специально не ищет человека на короткий срок. Продумайте свои доводы заранее. И, вероятно, лучше упомянуть об этом до того, как вас об этом спросят.
3. Резюме. Изменения ролей
Если ваша текущая должность отличается от той, на которую вы претендуете, необходимо это осветить и объяснить. Это также важно и тогда, когда вы претендуете на более «низкую» должность. Один из типичных случаев — кандидаты, которые сейчас возглавляют небольшую команду, но подают заявку на должность разработчика. Такие кандидаты и их опыт могут быть очень ценными, особенно при найме на должность старшего разработчика в небольшой компании, где от разработчиков ожидается больше ответственности, чем просто выполнение заранее спланированной задачи. В то же время есть несколько вещей, в которых вам следует убедить интервьюеров:
- что у вас всё ещё есть технические навыки. Руководители команд нередко теряют связь с технологиями, или, возможно, изначально не были так увлечены ими;
- объяснить, почему вы хотите вернуться к программированию на постоянной основе. То, что вы не можете найти работу тимлидом – не очень хорошее объяснение.
4. Не говорите слишком много
Особенно если вы в чём-то не уверены, длительное рассуждение не поможет. Звучит очевидно, правда? Но, видимо, на практике про это забывают! Бывают кандидаты, которые могут дать достойный ответ на простой вопрос, но затем заваливают свой собственный ответ, пускаясь в рассуждения.
Связанная с этим проблема: вы, как ни парадоксально, можете не дать интервьюеру достаточно узнать о вас. Часто лучший результат технического вопроса — это обсуждение с интервьюером(-ами) на равных. Это возможно только в том случае, если вы позволите интервьюеру говорить и не будете уходить в десятиминутный монолог на заданную тему. Это особенно важно, если у вас нет глубокого опыта в этой теме или вы не умеете хорошо выступать.
Окончание следует…
Источник: https://www.viblo.se/posts/interviewing/
👍17👎2
День 2405. #Карьера
8 Правил Прохождения Техсобеса. Окончание
Начало
5. Устаревший и неактуальный опыт
Как кандидату с опытом, вам нужно быть очень осторожным, говоря об устаревших/неактуальных технологиях или опыте, который не соответствует тому, что ищет интервьюер. Проблема не в том, что у вас есть такой опыт, а в том, что интервьюер опасается, что вы не знаете или не любите то, что требуется, и что вы не сможете адаптироваться к технологиям и процессам новой компании.
Например, ваши навыки написания скриптов для Linux могут быть всё ещё актуальны для компании, работающей с собственным Kubernetes, но нужно это объяснить! Не зацикливайтесь на том, как вы написали скрипт для установки 100 физических машин, потому что в данном контексте это бесполезно. Вместо этого вы можете рассказать о том, как глубокие знания Linux помогают вам писать оптимизированные и безопасные Docker-файлы или устранять сетевые неполадки при запуске в под.
6. Признавайте свои ограничения (но не слишком!)
Большинство кандидатов хорошо осознают свои возможности и знают свои границы. Это, в общем и целом, хорошо. В большинстве случаев, когда человек говорит о теме, в которой он не очень хорошо разбирается, это и так очевидно, так что можно прямо признать это. В то же время, не будьте слишком скромными и не нужно выставлять напоказ все свои слабости!
7. Примеры
Какой бы ни была тема, всегда полезно иметь возможность обратиться к реальному опыту. Будет здорово собрать несколько хороших примеров перед собеседованием — стоит подготовиться!
Например, вас спрашивают о вашем опыте в области событийно-управляемой архитектуры, но вы пока мало что сделали в этой области. Тем не менее, однажды вы внедрили очередь работ. Расскажите об этом и объясните, что вы сделали, как и почему. Другой вариант — вспомнить случай, когда вы рассматривали возможность использования событийно-управляемой архитектуры, но отказались от неё по разным причинам. А затем завершите разговор вопросом о том, как она работает в нанимающей вас компании. У всех технологий есть свои недостатки, но понимание этого часто отсутствует, поэтому это отличный способ продемонстрировать свою зрелость и дать им возможность рассказать о своей системе. Большинство интервьюеров любят рассказывать о том, как работает их уникальная система.
Но есть кое-что, на что стоит обратить внимание, если вы кандидат с опытом! Будьте очень осторожны, приводя примеры десятилетней давности. И будьте столь же осторожны, чтобы не использовать примеры, основанные на неправильных технологиях. Если вы претендуете на должность, связанную с микросервисами, не говорите о разработке приложений WinForms больше, чем это абсолютно необходимо, даже если вы думаете, что это в тему.
8. Вопросы
Едва ли не самый популярный совет для собеседований. Не забудьте задать несколько вопросов. В конце концов, возможно, вы будете там работать, и стоит попытаться заранее обнаружить какие-либо тревожные сигналы! Или, если не получится, хотя бы воспользуйтесь возможностью, чтобы интервьюеры рассказали о чём-то, что им интересно — почти все любят описывать свою текущую архитектуру, структуру команды или повседневную работу! Просто помните, что задаваемые вами вопросы отражают вас: что вас интересует, что вас волнует?
Собеседование окончено!
Получили работу?
Поздравляю! Вас наняли. Это значит, что они считают, что вы справитесь. Поначалу всё может быть очень запутанным и пугающим, особенно если вы не знакомы с этой ролью или типом компании. Со временем всё наладится, приложите все усилия и держитесь, и через пару месяцев вы почувствуете себя как дома.
Не получили работу?
Какой бы ни была причина, не расстраивайтесь! Иногда это выгодно обеим сторонам: возможно, вы не подошли, а может быть, компания оказалась не той, о которой вы мечтали. А может быть, это просто невезение. Однажды я не смог написать простой SQL-запрос, хотя имею огромный опыт написания и оптимизации гораздо более сложных запросов и хранимых процедур. Иногда звёзды просто не сходятся.
Источник: https://www.viblo.se/posts/interviewing/
8 Правил Прохождения Техсобеса. Окончание
Начало
5. Устаревший и неактуальный опыт
Как кандидату с опытом, вам нужно быть очень осторожным, говоря об устаревших/неактуальных технологиях или опыте, который не соответствует тому, что ищет интервьюер. Проблема не в том, что у вас есть такой опыт, а в том, что интервьюер опасается, что вы не знаете или не любите то, что требуется, и что вы не сможете адаптироваться к технологиям и процессам новой компании.
Например, ваши навыки написания скриптов для Linux могут быть всё ещё актуальны для компании, работающей с собственным Kubernetes, но нужно это объяснить! Не зацикливайтесь на том, как вы написали скрипт для установки 100 физических машин, потому что в данном контексте это бесполезно. Вместо этого вы можете рассказать о том, как глубокие знания Linux помогают вам писать оптимизированные и безопасные Docker-файлы или устранять сетевые неполадки при запуске в под.
6. Признавайте свои ограничения (но не слишком!)
Большинство кандидатов хорошо осознают свои возможности и знают свои границы. Это, в общем и целом, хорошо. В большинстве случаев, когда человек говорит о теме, в которой он не очень хорошо разбирается, это и так очевидно, так что можно прямо признать это. В то же время, не будьте слишком скромными и не нужно выставлять напоказ все свои слабости!
7. Примеры
Какой бы ни была тема, всегда полезно иметь возможность обратиться к реальному опыту. Будет здорово собрать несколько хороших примеров перед собеседованием — стоит подготовиться!
Например, вас спрашивают о вашем опыте в области событийно-управляемой архитектуры, но вы пока мало что сделали в этой области. Тем не менее, однажды вы внедрили очередь работ. Расскажите об этом и объясните, что вы сделали, как и почему. Другой вариант — вспомнить случай, когда вы рассматривали возможность использования событийно-управляемой архитектуры, но отказались от неё по разным причинам. А затем завершите разговор вопросом о том, как она работает в нанимающей вас компании. У всех технологий есть свои недостатки, но понимание этого часто отсутствует, поэтому это отличный способ продемонстрировать свою зрелость и дать им возможность рассказать о своей системе. Большинство интервьюеров любят рассказывать о том, как работает их уникальная система.
Но есть кое-что, на что стоит обратить внимание, если вы кандидат с опытом! Будьте очень осторожны, приводя примеры десятилетней давности. И будьте столь же осторожны, чтобы не использовать примеры, основанные на неправильных технологиях. Если вы претендуете на должность, связанную с микросервисами, не говорите о разработке приложений WinForms больше, чем это абсолютно необходимо, даже если вы думаете, что это в тему.
8. Вопросы
Едва ли не самый популярный совет для собеседований. Не забудьте задать несколько вопросов. В конце концов, возможно, вы будете там работать, и стоит попытаться заранее обнаружить какие-либо тревожные сигналы! Или, если не получится, хотя бы воспользуйтесь возможностью, чтобы интервьюеры рассказали о чём-то, что им интересно — почти все любят описывать свою текущую архитектуру, структуру команды или повседневную работу! Просто помните, что задаваемые вами вопросы отражают вас: что вас интересует, что вас волнует?
Собеседование окончено!
Получили работу?
Поздравляю! Вас наняли. Это значит, что они считают, что вы справитесь. Поначалу всё может быть очень запутанным и пугающим, особенно если вы не знакомы с этой ролью или типом компании. Со временем всё наладится, приложите все усилия и держитесь, и через пару месяцев вы почувствуете себя как дома.
Не получили работу?
Какой бы ни была причина, не расстраивайтесь! Иногда это выгодно обеим сторонам: возможно, вы не подошли, а может быть, компания оказалась не той, о которой вы мечтали. А может быть, это просто невезение. Однажды я не смог написать простой SQL-запрос, хотя имею огромный опыт написания и оптимизации гораздо более сложных запросов и хранимых процедур. Иногда звёзды просто не сходятся.
Источник: https://www.viblo.se/posts/interviewing/
👍18
День 2406. #Книги
«.NET 8: приложения и сервисы. Практика создания проектов с использованием Blazor, .NET MAUI, gRPC, GraphQL.» 2-е изд. (Прайс М. — Астана: «Спринт Бук», 2025).
С днём знаний всех!
От издательства «Питер» мне пришла ещё одна книга на обзор.
750-страничный фолиант «обо всём». Просто по главам:
1. Обзор .NET.
2. SQL Server
3. EF Core
4. NoSQL
5. Конкурентность
6. Популярные NuGet-библиотеки
7. Дата и интернационализация
8. Минимальные API
9. Кэширование
10. Azure Functions
11. SignalR
12. GraphQL
13. gRPC
14. ASP.NET Core
15. Blazor
16. MAUI
По правде сказать, я всегда с подозрением относился к произведениям издательства <Packt> (они выпустили оригинал этой книги в 2023г.). Дело в том, что несколько лет назад я глянул пару их книг, которые выходили чуть ли не сразу после релиза какой-либо технологии, и те книги показались мне довольно поверхностными. А ещё часто они быстро переиздавали книгу, например, по очередной версии .NET, просто наспех обновляя информацию (и далеко не всегда корректно).
Но эта книга меня приятно удивила. Не обращайте внимания, что оригинал выпущен в 2023 году. В переводе (что редкость) встречаются вставки и комментарии с более актуальными данными (например, что VS 2022 с августа 2024 года не поддерживается для Mac).
Конечно, учитывая то, что книга сразу обо всём, глубокого погружения в темы от неё ждать не стоит. Но, мне кажется, она подойдёт для старших джунов/мидлов (людей, знакомых с языком и основами разработки приложений) как обзор технологий. Просто узнать, что есть в мире .NET, «что это и с чем его едят», чтобы, к примеру, встретив где-то название технологии, примерно понимать, о чём идет речь. Кроме того, в каждой главе есть ссылки на документацию и материалы для более подробного изучения. Также много внимания уделяется практике создания небольших приложений и утилит для демонстрации материала. Отдельная «фишка» - блиц-опрос в конце каждой главы для проверки, как вы усвоили материал (в конце книги есть ответы).
В общем, для знакомства с обширным миром .NET рекомендую.
PS
Это вторая книга из «трилогии» Марка Прайса.
Первая называется «C#12 and .NET 8. Modern Cross-Platform Development Fundamentals». Это «основы основ». Я не нашёл перевода книги на русский язык.
А третья книга также доступна в издательстве Питер «.NET 8: инструменты и навыки. Лучшие практики и паттерны проектирования, отладки и тестирования».
Ещё раз спасибо за подарок издательству «Питер». Присылайте что-нибудь ещё 😊
«.NET 8: приложения и сервисы. Практика создания проектов с использованием Blazor, .NET MAUI, gRPC, GraphQL.» 2-е изд. (Прайс М. — Астана: «Спринт Бук», 2025).
С днём знаний всех!
От издательства «Питер» мне пришла ещё одна книга на обзор.
750-страничный фолиант «обо всём». Просто по главам:
1. Обзор .NET.
2. SQL Server
3. EF Core
4. NoSQL
5. Конкурентность
6. Популярные NuGet-библиотеки
7. Дата и интернационализация
8. Минимальные API
9. Кэширование
10. Azure Functions
11. SignalR
12. GraphQL
13. gRPC
14. ASP.NET Core
15. Blazor
16. MAUI
По правде сказать, я всегда с подозрением относился к произведениям издательства <Packt> (они выпустили оригинал этой книги в 2023г.). Дело в том, что несколько лет назад я глянул пару их книг, которые выходили чуть ли не сразу после релиза какой-либо технологии, и те книги показались мне довольно поверхностными. А ещё часто они быстро переиздавали книгу, например, по очередной версии .NET, просто наспех обновляя информацию (и далеко не всегда корректно).
Но эта книга меня приятно удивила. Не обращайте внимания, что оригинал выпущен в 2023 году. В переводе (что редкость) встречаются вставки и комментарии с более актуальными данными (например, что VS 2022 с августа 2024 года не поддерживается для Mac).
Конечно, учитывая то, что книга сразу обо всём, глубокого погружения в темы от неё ждать не стоит. Но, мне кажется, она подойдёт для старших джунов/мидлов (людей, знакомых с языком и основами разработки приложений) как обзор технологий. Просто узнать, что есть в мире .NET, «что это и с чем его едят», чтобы, к примеру, встретив где-то название технологии, примерно понимать, о чём идет речь. Кроме того, в каждой главе есть ссылки на документацию и материалы для более подробного изучения. Также много внимания уделяется практике создания небольших приложений и утилит для демонстрации материала. Отдельная «фишка» - блиц-опрос в конце каждой главы для проверки, как вы усвоили материал (в конце книги есть ответы).
В общем, для знакомства с обширным миром .NET рекомендую.
PS
Это вторая книга из «трилогии» Марка Прайса.
Первая называется «C#12 and .NET 8. Modern Cross-Platform Development Fundamentals». Это «основы основ». Я не нашёл перевода книги на русский язык.
А третья книга также доступна в издательстве Питер «.NET 8: инструменты и навыки. Лучшие практики и паттерны проектирования, отладки и тестирования».
Ещё раз спасибо за подарок издательству «Питер». Присылайте что-нибудь ещё 😊
👍12
День 2407. #ЧтоНовенького
Самая Мощная Новинка .NET 10
Вам знакомо чувство, когда то, чем вы пользовались годами, всегда казалось… незаконченным? Например, методы-расширения. Они, конечно, крутые, но редко когда по-настоящему нужны. Это костыли, скрывающиеся за маской чистого синтаксиса. C# 14 исправляет это с помощью членов-расширений.
Методы расширения всегда были полусырыми. Какой-то статический метод, замаскированный под что-то более интересное. Ни свойств, ни операторов, никакой логической группировки связанных расширений, кроме неуклюжих статических классов. Они никогда не ощущались как принадлежащие к типу. Члены-расширения - взрослая версия того, чем всегда хотели быть методы расширения.
Пример 1: Переписывание ToObservable
Если вы использовали MVVM с WPF, Xamarin, MAUI и т.д., вы, вероятно, писали это сотню раз:
Это работает, но выглядит странно; это не похоже на расширение существующего типа. А вот то же с использованием члена-расширения:
Видите разницу? Никакого беспорядка. Никаких странных «статических методов, притворяющихся реальными членами класса». Такое ощущение, что этим поведением владеет IEnumerable<T>.
Синтаксис
Пример 2: Добавляем свойства
Простой способ проверки на пустую коллекцию вместо !col.Any() или col.Count == 0 везде:
Использование:
То, чего методы расширения никогда не могли сделать чисто, теперь кажется естественной частью системы типов.
Пример 3: Статические Методы-Расширения
Вы можете добавлять статические члены к типам, которыми вы не владеете:
Как это работает изнутри
- Они не изменяют исходный тип.
- Компилятор и метаданные рассматривают их как «присоединённые» члены.
- Инструменты (например, IntelliSense) отображают их так, как будто они принадлежат типу.
- В основе всё по-прежнему безопасно и независимо, просто умнее.
Ограничения
- Никакой магии во время выполнения, они работают только во время компиляции.
- Нельзя добавлять поля или взаимодействовать с закрытыми членами.
- Поддержка инструментов вне современных IDE может немного отставать (пока).
Итого
Члены-расширения наконец-то делают расширения полноценными гражданами. Они позволяют API развиваться естественно. Они уменьшают беспорядок. Они делают код читаемым так, как будто он всегда был разработан таким образом. Это не просто синтаксический сахар, это корректировка курса. Они берут то, что начали методы расширения, и завершают работу. Более чистые API, легко обнаруживаемые функции, меньше служебных классов, скрывающихся в случайных пространствах имён, всё это просто кажется… правильным. Они не заставляют вас переосмысливать, как вы пишете часть кода. Они заставляют вас переосмыслить, как вы в целом проектируете его.
См. также «Используем Расширения C# 14 для Парсинга Enum»
Источник: https://blog.stackademic.com/net-10s-most-powerful-feature-isn-t-what-you-think-7d507dd254dc
Самая Мощная Новинка .NET 10
Вам знакомо чувство, когда то, чем вы пользовались годами, всегда казалось… незаконченным? Например, методы-расширения. Они, конечно, крутые, но редко когда по-настоящему нужны. Это костыли, скрывающиеся за маской чистого синтаксиса. C# 14 исправляет это с помощью членов-расширений.
Методы расширения всегда были полусырыми. Какой-то статический метод, замаскированный под что-то более интересное. Ни свойств, ни операторов, никакой логической группировки связанных расширений, кроме неуклюжих статических классов. Они никогда не ощущались как принадлежащие к типу. Члены-расширения - взрослая версия того, чем всегда хотели быть методы расширения.
Пример 1: Переписывание ToObservable
Если вы использовали MVVM с WPF, Xamarin, MAUI и т.д., вы, вероятно, писали это сотню раз:
public static class ObservableExtensions
{
public static ObservableCollection<T>
ToObservable<T>(this IEnumerable<T> source)
=> new ObservableCollection<T>(source);
}
Это работает, но выглядит странно; это не похоже на расширение существующего типа. А вот то же с использованием члена-расширения:
public static class EnumerableExtensions
{
extension(IEnumerable<T> collection)
{
public ObservableCollection<T> ToObservable()
=> new ObservableCollection<T>(collection);
}
}
Видите разницу? Никакого беспорядка. Никаких странных «статических методов, притворяющихся реальными членами класса». Такое ощущение, что этим поведением владеет IEnumerable<T>.
Синтаксис
public static class NameOfExtensionClass
{
extension(YourType obj)
{
// Методы, свойства,
// операторы и вложенные типы
}
}
Пример 2: Добавляем свойства
Простой способ проверки на пустую коллекцию вместо !col.Any() или col.Count == 0 везде:
public static class CollectionExtensions
{
extension(ICollection<T> collection)
{
public bool IsEmpty => this.Count == 0;
}
}
Использование:
if (myList.IsEmpty)
{
// Наконец-то код читается, как надо
}
То, чего методы расширения никогда не могли сделать чисто, теперь кажется естественной частью системы типов.
Пример 3: Статические Методы-Расширения
Вы можете добавлять статические члены к типам, которыми вы не владеете:
public static class DateTimeExtensions
{
extension(DateTime)
{
public static DateTime UnixEpoch
=> new DateTime(1970, 1, 1);
}
}
Как это работает изнутри
- Они не изменяют исходный тип.
- Компилятор и метаданные рассматривают их как «присоединённые» члены.
- Инструменты (например, IntelliSense) отображают их так, как будто они принадлежат типу.
- В основе всё по-прежнему безопасно и независимо, просто умнее.
Ограничения
- Никакой магии во время выполнения, они работают только во время компиляции.
- Нельзя добавлять поля или взаимодействовать с закрытыми членами.
- Поддержка инструментов вне современных IDE может немного отставать (пока).
Итого
Члены-расширения наконец-то делают расширения полноценными гражданами. Они позволяют API развиваться естественно. Они уменьшают беспорядок. Они делают код читаемым так, как будто он всегда был разработан таким образом. Это не просто синтаксический сахар, это корректировка курса. Они берут то, что начали методы расширения, и завершают работу. Более чистые API, легко обнаруживаемые функции, меньше служебных классов, скрывающихся в случайных пространствах имён, всё это просто кажется… правильным. Они не заставляют вас переосмысливать, как вы пишете часть кода. Они заставляют вас переосмыслить, как вы в целом проектируете его.
См. также «Используем Расширения C# 14 для Парсинга Enum»
Источник: https://blog.stackademic.com/net-10s-most-powerful-feature-isn-t-what-you-think-7d507dd254dc
👍31
День 2408. #Архитектура #БазыДанных
Postgres Слишком Хорош. Начало
Разные инди-разработчики и основатели стартапов лихорадочно собирают технологические стеки с Redis для кэширования, RabbitMQ для очередей, Elasticsearch для поиска и MongoDB, потому что… так надо? Оказывается, есть слон в комнате, которого никто не хочет замечать: Postgres может буквально всё это. И он делает это лучше, чем вы думаете.
Миф о том, что Postgres не масштабируется
Часто говорят, что Postgres — это «всего лишь РСУБД», и для решения специализированных задач нужны специализированные инструменты. Но Instagram масштабируется до 14 миллионов пользователей на одном экземпляре Postgres. Discord обрабатывает миллиарды сообщений. Notion построил весь свой продукт на Postgres. Только они не используют Postgres так, будто на дворе 2005 год.
1. Системы Очередей
В Postgres есть нативная поддержка LISTEN/NOTIFY, и он может обрабатывать очереди заданий лучше, чем многие специализированные решения:
Это обеспечивает обработку «ровно один раз» без дополнительной инфраструктуры.
2. Хранилище Ключ-значение
В Postgres есть JSONB, который выполняет большую часть того, что вам нужно:
Оператор @> - секретное оружие Postgres'а. Он быстрее большинства запросов NoSQL, и ваши данные остаются согласованными.
3. Полнотекстовый поиск
Кластеры Elasticsearch дороги и сложны. В Postgres есть встроенный полнотекстовый поиск, который поразительно хорош:
Это позволяет без проблем обрабатывать нечёткое соответствие, стемминг и ранжирование по релевантности.
4. Функции Реального Времени
Postgres LISTEN/NOTIFY обеспечивает обновления в реальном времени без дополнительных сервисов:
Ваше приложение отслеживает эти уведомления и отправляет обновления пользователям.
Окончание следует…
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
Postgres Слишком Хорош. Начало
Разные инди-разработчики и основатели стартапов лихорадочно собирают технологические стеки с Redis для кэширования, RabbitMQ для очередей, Elasticsearch для поиска и MongoDB, потому что… так надо? Оказывается, есть слон в комнате, которого никто не хочет замечать: Postgres может буквально всё это. И он делает это лучше, чем вы думаете.
Миф о том, что Postgres не масштабируется
Часто говорят, что Postgres — это «всего лишь РСУБД», и для решения специализированных задач нужны специализированные инструменты. Но Instagram масштабируется до 14 миллионов пользователей на одном экземпляре Postgres. Discord обрабатывает миллиарды сообщений. Notion построил весь свой продукт на Postgres. Только они не используют Postgres так, будто на дворе 2005 год.
1. Системы Очередей
В Postgres есть нативная поддержка LISTEN/NOTIFY, и он может обрабатывать очереди заданий лучше, чем многие специализированные решения:
-- Простая очередь на Postgres
CREATE TABLE job_queue (
id SERIAL PRIMARY KEY,
job_type VARCHAR(50),
payload JSONB,
status VARCHAR(20) DEFAULT 'pending',
created_at TIMESTAMP DEFAULT NOW(),
processed_at TIMESTAMP
);
-- ACID-совместимая обработка заданий
BEGIN;
UPDATE job_queue
SET status = 'processing', processed_at = NOW()
WHERE id = (
SELECT id FROM job_queue
WHERE status = 'pending'
ORDER BY created_at
FOR UPDATE SKIP LOCKED
LIMIT 1
)
RETURNING *;
COMMIT;
Это обеспечивает обработку «ровно один раз» без дополнительной инфраструктуры.
2. Хранилище Ключ-значение
В Postgres есть JSONB, который выполняет большую часть того, что вам нужно:
-- Альтернатива Redis
CREATE TABLE kv_store (
key VARCHAR(255) PRIMARY KEY,
value JSONB,
expires_at TIMESTAMP
);
-- GIN индекс для запросов к JSON
CREATE INDEX idx_kv_value ON kv_store USING GIN (value);
SELECT * FROM kv_store
WHERE value @> '{"user_id": 12345}';
Оператор @> - секретное оружие Postgres'а. Он быстрее большинства запросов NoSQL, и ваши данные остаются согласованными.
3. Полнотекстовый поиск
Кластеры Elasticsearch дороги и сложны. В Postgres есть встроенный полнотекстовый поиск, который поразительно хорош:
-- Добавляем поиск к любой таблице
ALTER TABLE posts ADD COLUMN search_vector tsvector;
-- Авто-обновляемый индекс поиска
CREATE OR REPLACE FUNCTION update_search_vector()
RETURNS trigger AS $$
BEGIN
NEW.search_vector := to_tsvector('english',
COALESCE(NEW.title, '') || ' ' ||
COALESCE(NEW.content, '')
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
-- Ранжированные результаты поиска
SELECT title, ts_rank(search_vector, query) as rank
FROM posts, to_tsquery('startup & postgres') query
WHERE search_vector @@ query
ORDER BY rank DESC;
Это позволяет без проблем обрабатывать нечёткое соответствие, стемминг и ранжирование по релевантности.
4. Функции Реального Времени
Postgres LISTEN/NOTIFY обеспечивает обновления в реальном времени без дополнительных сервисов:
-- Уведомления клиентов об изменениях
CREATE OR REPLACE FUNCTION notify_changes()
RETURNS trigger AS $$
BEGIN
PERFORM pg_notify('table_changes',
json_build_object(
'table', TG_TABLE_NAME,
'action', TG_OP,
'data', row_to_json(NEW)
)::text
);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
Ваше приложение отслеживает эти уведомления и отправляет обновления пользователям.
Окончание следует…
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
👍49
День 2409. #Архитектура #БазыДанных
Postgres Слишком Хорош. Окончание
Начало
Скрытая стоимость «специализированных» инструментов
Помимо собственно платы за каждый специализированный сервис, есть много скрытых расходов на них.
Операционные расходы
- Мониторинг, обновления и отладка разных сервисов;
- Разные шаблоны масштабирования и режимы сбоев;
- Необходимость поддержки нескольких конфигураций;
- Раздельные процедуры резервного копирования и аварийного восстановления;
- Разные аспекты безопасности для каждого сервиса.
Сложности разработки
- Разные клиентские библиотеки и шаблоны подключения;
- Координация развёртываний нескольких сервисов;
- Несогласованность данных между системами;
- Сложные сценарии тестирования;
- Разные подходы к настройке производительности.
Если вы размещаете сервер самостоятельно, добавьте управление сервером, исправления безопасности и неизбежные сеансы отладки, когда Redis решает израсходовать всю вашу память, и т.п. Postgres делает всё это в одном сервисе, которым вы уже управляете.
Единая масштабируемая БД
Большинство людей не осознаёт, что один экземпляр Postgres может справиться с огромными объёмами данных. Речь идёт о миллионах транзакций в день, терабайтах данных и тысячах одновременных подключений. Вся магия кроется в архитектуре Postgres. Она невероятно хорошо масштабируется вертикально, а когда вам наконец понадобится горизонтальное масштабирование, у вас есть проверенные решения, такие как:
- Реплики чтения для масштабирования запросов;
- Партиционирование для больших таблиц;
- Организация пулов подключений для конкурентности;
- Логическая репликация для распределённых конфигураций.
Большинство компаний никогда до этого не доходят. Вас, вероятно, устроит один экземпляр, пока вы не начнёте обслуживать миллионы пользователей или сложные аналитические задачи. Сравните это с управлением отдельными сервисами, каждый из которых масштабируется по-разному.
Остановите оверинжиниринг с первого дня
Главная ловушка современной разработки — архитектурная астронавтика. Мы проектируем системы для задач, которых у нас нет, с трафиком, которого мы никогда не видели, для масштаба, которого, возможно, никогда не достигнем.
Начните с простого, с Postgres. Отслеживайте реальные узкие места, а не воображаемые. Масштабируйте конкретные компоненты, когда достигаете реальных ограничений. Добавляйте сложность только тогда, когда это решает реальные проблемы. Пользователям не важна ваша архитектура. Им важно, работает ли ваш продукт и решает ли он их проблемы.
Postgres может быть вашей основной БД, кэшем, очередью, поисковой системой и системой реального времени одновременно. И всё это с поддержкой ACID-транзакций во всех областях:
Итого
Postgres может быть слишком хорош сам по себе. Он настолько мощен, что делает большинство других сервисов ненужными для 90% приложений. Индустрия убедила нас, что нам нужны специализированные инструменты для всего, но, возможно, мы просто усложняем задачу.
Ваш стартап не должен быть витриной распределённых систем. Он должен решать реальные проблемы для реальных людей. Postgres позволяет вам сосредоточиться на этом. Поэтому в следующий раз, когда кто-то предложит добавить Redis «для производительности» или MongoDB «для гибкости», спросите: «Вы попробовали сначала сделать это в Postgres?»
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
Postgres Слишком Хорош. Окончание
Начало
Скрытая стоимость «специализированных» инструментов
Помимо собственно платы за каждый специализированный сервис, есть много скрытых расходов на них.
Операционные расходы
- Мониторинг, обновления и отладка разных сервисов;
- Разные шаблоны масштабирования и режимы сбоев;
- Необходимость поддержки нескольких конфигураций;
- Раздельные процедуры резервного копирования и аварийного восстановления;
- Разные аспекты безопасности для каждого сервиса.
Сложности разработки
- Разные клиентские библиотеки и шаблоны подключения;
- Координация развёртываний нескольких сервисов;
- Несогласованность данных между системами;
- Сложные сценарии тестирования;
- Разные подходы к настройке производительности.
Если вы размещаете сервер самостоятельно, добавьте управление сервером, исправления безопасности и неизбежные сеансы отладки, когда Redis решает израсходовать всю вашу память, и т.п. Postgres делает всё это в одном сервисе, которым вы уже управляете.
Единая масштабируемая БД
Большинство людей не осознаёт, что один экземпляр Postgres может справиться с огромными объёмами данных. Речь идёт о миллионах транзакций в день, терабайтах данных и тысячах одновременных подключений. Вся магия кроется в архитектуре Postgres. Она невероятно хорошо масштабируется вертикально, а когда вам наконец понадобится горизонтальное масштабирование, у вас есть проверенные решения, такие как:
- Реплики чтения для масштабирования запросов;
- Партиционирование для больших таблиц;
- Организация пулов подключений для конкурентности;
- Логическая репликация для распределённых конфигураций.
Большинство компаний никогда до этого не доходят. Вас, вероятно, устроит один экземпляр, пока вы не начнёте обслуживать миллионы пользователей или сложные аналитические задачи. Сравните это с управлением отдельными сервисами, каждый из которых масштабируется по-разному.
Остановите оверинжиниринг с первого дня
Главная ловушка современной разработки — архитектурная астронавтика. Мы проектируем системы для задач, которых у нас нет, с трафиком, которого мы никогда не видели, для масштаба, которого, возможно, никогда не достигнем.
Начните с простого, с Postgres. Отслеживайте реальные узкие места, а не воображаемые. Масштабируйте конкретные компоненты, когда достигаете реальных ограничений. Добавляйте сложность только тогда, когда это решает реальные проблемы. Пользователям не важна ваша архитектура. Им важно, работает ли ваш продукт и решает ли он их проблемы.
Postgres может быть вашей основной БД, кэшем, очередью, поисковой системой и системой реального времени одновременно. И всё это с поддержкой ACID-транзакций во всех областях:
-- Одна транзакция, несколько операций
BEGIN;
INSERT INTO users (email) VALUES ('user@example.com');
INSERT INTO job_queue (job_type, payload)
VALUES ('send_welcome_email', '{"user_id": 123}');
UPDATE kv_store SET value = '{"last_signup": "2024-01-15"}'
WHERE key = 'stats';
COMMIT;
Итого
Postgres может быть слишком хорош сам по себе. Он настолько мощен, что делает большинство других сервисов ненужными для 90% приложений. Индустрия убедила нас, что нам нужны специализированные инструменты для всего, но, возможно, мы просто усложняем задачу.
Ваш стартап не должен быть витриной распределённых систем. Он должен решать реальные проблемы для реальных людей. Postgres позволяет вам сосредоточиться на этом. Поэтому в следующий раз, когда кто-то предложит добавить Redis «для производительности» или MongoDB «для гибкости», спросите: «Вы попробовали сначала сделать это в Postgres?»
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
👍23
День 2410. #TipsAndTricks
Улучшаем Отладку EF Core с Помощью Тегов Запросов
Отладка запросов к БД в EF Core иногда напоминает поиск иголки в стоге сена. Когда ваше приложение генерирует десятки или сотни SQL-запросов, определить, какое LINQ-выражение сгенерировало тот или иной SQL-запрос, становится настоящей проблемой. К счастью, есть элегантное решение: теги запросов.
Теги запросов
Теги запросов позволяют добавлять пользовательские комментарии к SQL-запросам, сгенерированным LINQ-выражениями. Эти комментарии отображаются непосредственно в сгенерированном SQL-коде, что позволяет легко сопоставлять SQL-запрос с кодом, который его создал. Чтобы использовать эту функцию, необходимо применить метод TagWith к любому объекту IQueryable и передать описательный комментарий:
Это сгенерирует примерно такой SQL-запрос:
Вместо того, чтобы пытаться определить, какой код сгенерировал тот или иной SQL-запрос, вы можете сразу увидеть цель и источник каждого запроса в логах БД или профилировщике.
Вы можете объединить несколько вызовов TagWith для добавления дополнительного контекста, а также добавлять значения переменных во время выполнения:
Результат:
*CorrelationId помогает проследить весь путь пользовательского запроса (см. подробнее).
Примечания:
1. Хотя влияние TagWith на производительность минимально, избегайте чрезмерно длинных тегов или сложной интерполяции строк в горячих путях.
2. Теги запросов должны быть строковыми литералами, и не могут принимать параметры. Однако можно использовать интерполяцию строк (как видно выше), а также многострочные строковые литералы.
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
Улучшаем Отладку EF Core с Помощью Тегов Запросов
Отладка запросов к БД в EF Core иногда напоминает поиск иголки в стоге сена. Когда ваше приложение генерирует десятки или сотни SQL-запросов, определить, какое LINQ-выражение сгенерировало тот или иной SQL-запрос, становится настоящей проблемой. К счастью, есть элегантное решение: теги запросов.
Теги запросов
Теги запросов позволяют добавлять пользовательские комментарии к SQL-запросам, сгенерированным LINQ-выражениями. Эти комментарии отображаются непосредственно в сгенерированном SQL-коде, что позволяет легко сопоставлять SQL-запрос с кодом, который его создал. Чтобы использовать эту функцию, необходимо применить метод TagWith к любому объекту IQueryable и передать описательный комментарий:
var оrders = context.Orders
.TagWith("Заказы больше $1000")
.Where(o => o.Total > 1000)
.Include(o => o.Customer)
.ToList();
Это сгенерирует примерно такой SQL-запрос:
-- Заказы больше $1000
SELECT [o].[Id], [o].[CustomerId], [o].[Total], [c].[Id], [c].[Name]
FROM [Orders] AS [o]
INNER JOIN [Customers] AS [c] ON [o].[CustomerId] = [c].[Id]
WHERE [o].[Total] > 1000.0
Вместо того, чтобы пытаться определить, какой код сгенерировал тот или иной SQL-запрос, вы можете сразу увидеть цель и источник каждого запроса в логах БД или профилировщике.
Вы можете объединить несколько вызовов TagWith для добавления дополнительного контекста, а также добавлять значения переменных во время выполнения:
var userOrders = context.Orders
.TagWith("Запрос с дэшборда")
.TagWith($"User ID: {userId}")
.TagWith($"CorrelationId: {correlationId}")
.Where(o => o.CustomerId == userId)
.OrderByDescending(o => o.OrderDate)
.Take(10)
.ToList();
Результат:
-- Запрос с дэшборда
-- User ID: 12345
-- CorrelationId: 987654321
SELECT TOP(10) [o].[Id], [o].[CustomerId], [o].[OrderDate]
FROM [Orders] AS [o]
WHERE [o].[CustomerId] = 12345
ORDER BY [o].[OrderDate] DESC
*CorrelationId помогает проследить весь путь пользовательского запроса (см. подробнее).
Примечания:
1. Хотя влияние TagWith на производительность минимально, избегайте чрезмерно длинных тегов или сложной интерполяции строк в горячих путях.
2. Теги запросов должны быть строковыми литералами, и не могут принимать параметры. Однако можно использовать интерполяцию строк (как видно выше), а также многострочные строковые литералы.
Источник: https://dev.to/shayy/postgres-is-too-good-and-why-thats-actually-a-problem-4imc
1👍34
День 2411. #SystemDesign101 #Testing
9 Видов Тестирования API
1. Дымовое (Smoke) тестирование
Проводится после завершения разработки API. Просто проверяется работоспособность API и отсутствие сбоев.
2. Функциональное тестирование
Составление плана тестирования на основе функциональных требований и сравнение результатов с ожидаемыми.
3. Интеграционное тестирование
Тестирование объединяет несколько вызовов API для выполнения сквозных тестов. Тестируются внутрисервисные коммуникации и передача данных.
4. Регрессионное тестирование
Тестирование гарантирует, что исправления ошибок или новые функции не нарушат текущее поведение API.
5. Нагрузочное тестирование
Тестирование производительности приложений путем моделирования различных нагрузок. Затем мы можем рассчитать пропускную способность приложения.
6. Стресс-тестирование
Мы намеренно создаем высокие нагрузки на API и проверяем его работоспособность.
7. Тестирование безопасности
Тестирование API на предмет всех возможных внешних угроз.
8. Тестирование пользовательского интерфейса
Тестирование взаимодействия пользовательского интерфейса с API для обеспечения корректного отображения данных.
9. Фаззинг-тестирование
Этот метод внедряет недействительные или неожиданные входные данные в API и пытается вызвать сбой в его работе. Таким образом, выявляются уязвимости API.
Источник: https://blog.bytebytego.com/
9 Видов Тестирования API
1. Дымовое (Smoke) тестирование
Проводится после завершения разработки API. Просто проверяется работоспособность API и отсутствие сбоев.
2. Функциональное тестирование
Составление плана тестирования на основе функциональных требований и сравнение результатов с ожидаемыми.
3. Интеграционное тестирование
Тестирование объединяет несколько вызовов API для выполнения сквозных тестов. Тестируются внутрисервисные коммуникации и передача данных.
4. Регрессионное тестирование
Тестирование гарантирует, что исправления ошибок или новые функции не нарушат текущее поведение API.
5. Нагрузочное тестирование
Тестирование производительности приложений путем моделирования различных нагрузок. Затем мы можем рассчитать пропускную способность приложения.
6. Стресс-тестирование
Мы намеренно создаем высокие нагрузки на API и проверяем его работоспособность.
7. Тестирование безопасности
Тестирование API на предмет всех возможных внешних угроз.
8. Тестирование пользовательского интерфейса
Тестирование взаимодействия пользовательского интерфейса с API для обеспечения корректного отображения данных.
9. Фаззинг-тестирование
Этот метод внедряет недействительные или неожиданные входные данные в API и пытается вызвать сбой в его работе. Таким образом, выявляются уязвимости API.
Источник: https://blog.bytebytego.com/
👍10
День 2412. #Оффтоп
Berghain-Челлендж
Вот такой мистический билборд увидели на улицах Сан-Франциско. Попробуйте расшифровать.
Если у вас (как и у меня) ничего не получилось, то, видимо, вы мало знаете про AI 😊 На самом деле, это набор o200k токенов, которые все вместе складываются в URL listenlabs.ai/puzzle
Там вас ждёт следующий челлендж.
Berghain*-Челлендж
Berghain — ночной техно-клуб в Берлине. Вы — вышибала в ночном клубе. Ваша цель — заполнить заведение N=1000 людьми, соблюдая ограничения, например, «не менее 40% местных жителей Берлина» или «не менее 80% одеты в чёрное». Люди приходят по одному, и вам нужно сразу же решить, впускать их или нет. Ваша задача — заполнить заведение, получив как можно меньше отказов, соблюдая при этом все минимальные требования.
Как это работает
- Люди приходят последовательно с бинарными признаками (например, женщина/мужчина, молодой/старый, постоянный/новичок).
- Вы должны немедленно принимать решения о принятии/отклонении.
- Игра заканчивается, когда:
(a) заведение заполнено (1000 человек).
(b) вы отклонили 20 000 человек.
Сценарии и подсчёт очков
Возможно 3 различных сценария. Для каждого из них вам предоставляется список ограничений и статистика распределения признаков. Можно предположить, что участники отбираются независимо друг от друга, то есть распределение характеристик не изменится в течение вечера. Вы знаете общую относительную частоту встречаемости каждой характеристики и корреляцию между ними. Точное распределение вам неизвестно.
Ваш результат — это количество людей, которым вы отказали до заполнения площадки (чем меньше, тем лучше).
Приз
Человек, занявший первое место в таблице лидеров на 15 сентября в 6:00 по тихоокеанскому времени, станет победителем и получит билет в Berghain за счёт оргазизаторов! Также вы сможете пройти собеседование с Listen.
Все подробности тут.
PS: Если вдруг кто решит принять участие, пожалуйста, отпишитесь в комментариях о результатах.
Berghain-Челлендж
Вот такой мистический билборд увидели на улицах Сан-Франциско. Попробуйте расшифровать.
Там вас ждёт следующий челлендж.
Berghain*-Челлендж
Berghain — ночной техно-клуб в Берлине. Вы — вышибала в ночном клубе. Ваша цель — заполнить заведение N=1000 людьми, соблюдая ограничения, например, «не менее 40% местных жителей Берлина» или «не менее 80% одеты в чёрное». Люди приходят по одному, и вам нужно сразу же решить, впускать их или нет. Ваша задача — заполнить заведение, получив как можно меньше отказов, соблюдая при этом все минимальные требования.
Как это работает
- Люди приходят последовательно с бинарными признаками (например, женщина/мужчина, молодой/старый, постоянный/новичок).
- Вы должны немедленно принимать решения о принятии/отклонении.
- Игра заканчивается, когда:
(a) заведение заполнено (1000 человек).
(b) вы отклонили 20 000 человек.
Сценарии и подсчёт очков
Возможно 3 различных сценария. Для каждого из них вам предоставляется список ограничений и статистика распределения признаков. Можно предположить, что участники отбираются независимо друг от друга, то есть распределение характеристик не изменится в течение вечера. Вы знаете общую относительную частоту встречаемости каждой характеристики и корреляцию между ними. Точное распределение вам неизвестно.
Ваш результат — это количество людей, которым вы отказали до заполнения площадки (чем меньше, тем лучше).
Приз
Человек, занявший первое место в таблице лидеров на 15 сентября в 6:00 по тихоокеанскому времени, станет победителем и получит билет в Berghain за счёт оргазизаторов! Также вы сможете пройти собеседование с Listen.
Все подробности тут.
PS: Если вдруг кто решит принять участие, пожалуйста, отпишитесь в комментариях о результатах.
👍5
День 2413. #BestPractices
Сегодня порекомендую вам для воскресного просмотра выступление Скотта Заубера на недавней NDC Conference в Осло "10 Things I Do On Every .NET App" (10 вещей, которые я делаю в каждом .NET приложении)
По мере того, как приложение добавляет всё больше и больше функций, если вы не будете осторожны, оно может быстро превратиться в приложение, над которым никто в команде не хочет работать.
Выступление структурировано как серия коротких докладов на различные темы, которые помогут вам улучшить поддержку ваших .NET-приложений. Разговор пойдёт о библиотеках и передовые практиках, которые помогут в организации кода, валидации, ORM, автоматизированном тестировании, безопасности и многом другом. Вы сможете почерпнуть несколько идей, которые сможете сразу же начать реализовывать, вернувшись к работе над улучшением кодовых баз .NET.
Приятного просмотра.
PS: 20 звёзд, и я разберу все советы на канале😉
Сегодня порекомендую вам для воскресного просмотра выступление Скотта Заубера на недавней NDC Conference в Осло "10 Things I Do On Every .NET App" (10 вещей, которые я делаю в каждом .NET приложении)
По мере того, как приложение добавляет всё больше и больше функций, если вы не будете осторожны, оно может быстро превратиться в приложение, над которым никто в команде не хочет работать.
Выступление структурировано как серия коротких докладов на различные темы, которые помогут вам улучшить поддержку ваших .NET-приложений. Разговор пойдёт о библиотеках и передовые практиках, которые помогут в организации кода, валидации, ORM, автоматизированном тестировании, безопасности и многом другом. Вы сможете почерпнуть несколько идей, которые сможете сразу же начать реализовывать, вернувшись к работе над улучшением кодовых баз .NET.
Приятного просмотра.
31👍27
День 2414. #Книги
«C# Concurrency. Асинхронное программирование и многопоточность» (Добовицки Н. — «Питер», 2026).
Очередная книга, над переводом которой довелось поработать совместно с сообществом DotNetRu Translate.
Многопоточность и асинхронность, наверное, всегда будут главными темами вопросов на собеседованиях, а также рассуждений и споров в командах разработчиков. Тема неисчерпаема, и полностью её понимают, кажется, очень немногие. Эта книга - довольно компактное (всего 270 страниц), но при этом полезное руководство по тому, как работает конкурентность в C#, и как вам работать с ней. Автор неплохо раскрывает все особенности и нюансы. Для начинающих в начале книги на доступных аналогиях из жизни разбираются основы многопоточности и асинхронности. Если для вас async/await до сих пор было магией, из первых глав книги вы узнаете, что ничего волшебного там нет, и как это всё устроено "под капотом". Для опытных разработчиков, уже знакомых с основами, в последующих главах разбираются более продвинутые способы применения. Поэтому независимо от того, только начинаете вы изучение конкурентности, либо просто хотите освежить материал и закрепить знания, книга вам подойдёт.
PS
А ещё внезапно так получилось, что на конференции DotNext в Питере в конце первого дня я поучаствую в проведении BoF-сессии «Перевод IT-книг. От идеи до книжной полки» совместно с представителями издательства «Питер». Приглашаю всех, кому интересно узнать про сообщество переводчиков, зачем вообще мы этим занимаемся, как проходит процесс перевода, какие скиллы требуются, чтобы поучаствовать, и как вообще издаются переводы книг на русском языке. Буду рад всех видеть.
«C# Concurrency. Асинхронное программирование и многопоточность» (Добовицки Н. — «Питер», 2026).
Очередная книга, над переводом которой довелось поработать совместно с сообществом DotNetRu Translate.
Многопоточность и асинхронность, наверное, всегда будут главными темами вопросов на собеседованиях, а также рассуждений и споров в командах разработчиков. Тема неисчерпаема, и полностью её понимают, кажется, очень немногие. Эта книга - довольно компактное (всего 270 страниц), но при этом полезное руководство по тому, как работает конкурентность в C#, и как вам работать с ней. Автор неплохо раскрывает все особенности и нюансы. Для начинающих в начале книги на доступных аналогиях из жизни разбираются основы многопоточности и асинхронности. Если для вас async/await до сих пор было магией, из первых глав книги вы узнаете, что ничего волшебного там нет, и как это всё устроено "под капотом". Для опытных разработчиков, уже знакомых с основами, в последующих главах разбираются более продвинутые способы применения. Поэтому независимо от того, только начинаете вы изучение конкурентности, либо просто хотите освежить материал и закрепить знания, книга вам подойдёт.
PS
А ещё внезапно так получилось, что на конференции DotNext в Питере в конце первого дня я поучаствую в проведении BoF-сессии «Перевод IT-книг. От идеи до книжной полки» совместно с представителями издательства «Питер». Приглашаю всех, кому интересно узнать про сообщество переводчиков, зачем вообще мы этим занимаемся, как проходит процесс перевода, какие скиллы требуются, чтобы поучаствовать, и как вообще издаются переводы книг на русском языке. Буду рад всех видеть.
👍37
День 2415. #ЗаметкиНаПолях
Реальная Цена Абстракций в .NET. Начало
Мы, разработчики, любим абстракции. Репозитории, сервисы, конвертеры, обёртки. Они делают наш код «чистым», обещают тестируемость и дают нам ощущение гибкости. Некоторые абстракции оправдывают себя, изолируя реальную волатильность и защищая систему от изменений. Другие же незаметно увеличивают сложность, замедляют внедрение и скрывают проблемы производительности за слоями косвенности. Рассмотрим, когда абстракции приносят дивиденды, а когда они становятся техническим долгом.
Когда абстракции окупаются
Лучшие абстракции изолируют реальную волатильность — те части вашей системы, которые вы действительно ожидаете изменить. Пример: обработка платежей. Ваша бизнес-логика не должна напрямую зависеть от API или SDK платёжной системы. Если вы когда-нибудь перейдёте на другую, вы не хотите, чтобы это повлияло на множество мест вашей кодовой базы. Здесь абстракция имеет смысл:
Теперь бизнес-логика может сфокусироваться на домене:
Эта абстракция изолирует действительно нестабильную зависимость (платёжного провайдера), сохраняя при этом независимость логики оформления заказа. Когда Stripe поменяет свой API или вы поменяете провайдера, нужно изменить только один класс. Это хорошая абстракция. Она даёт опциональность там, где она действительно нужна.
Когда абстракции становятся техническим долгом
Проблемы возникают, когда мы абстрагируем то, что на самом деле не является изменчивым. В итоге мы оборачиваем стабильные библиотеки или создаём слои, которые не приносят реальной ценности. «Чистый» слой, добавленный вами сегодня, завтра становится обузой для обслуживания.
Большинство команд начинают с чего-то разумного:
Но по мере изменения требований, растёт и интерфейс:
Внезапно репозиторий начинает пропускать логику запросов в свой интерфейс. Каждый новый способ получения пользователей означает новый метод, и «абстракция» становится сборищем всевозможных запросов.
Между тем, Entity Framework уже предоставляет всё это через LINQ: строго типизированные запросы, которые напрямую соответствуют SQL. Вместо того, чтобы использовать эту мощь, вы ввели слой косвенности. Паттерн репозитория имел смысл, когда ORM были незрелыми. Сегодня это часто просто формальность.
Частью взросления разработчика является умение распознавать, когда паттерны становятся антипаттернами. Репозитории имеют смысл, когда они инкапсулируют сложную логику запросов или предоставляют унифицированный API для нескольких источников данных. Но вы должны стремиться, чтобы они были сосредоточены на логике предметной области. Как только они разрастаются в мириады методов для каждого возможного запроса, это признак того, что абстракция дала сбой.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
Реальная Цена Абстракций в .NET. Начало
Мы, разработчики, любим абстракции. Репозитории, сервисы, конвертеры, обёртки. Они делают наш код «чистым», обещают тестируемость и дают нам ощущение гибкости. Некоторые абстракции оправдывают себя, изолируя реальную волатильность и защищая систему от изменений. Другие же незаметно увеличивают сложность, замедляют внедрение и скрывают проблемы производительности за слоями косвенности. Рассмотрим, когда абстракции приносят дивиденды, а когда они становятся техническим долгом.
Когда абстракции окупаются
Лучшие абстракции изолируют реальную волатильность — те части вашей системы, которые вы действительно ожидаете изменить. Пример: обработка платежей. Ваша бизнес-логика не должна напрямую зависеть от API или SDK платёжной системы. Если вы когда-нибудь перейдёте на другую, вы не хотите, чтобы это повлияло на множество мест вашей кодовой базы. Здесь абстракция имеет смысл:
public interface IPaymentProcessor
{
Task ProcessAsync(
Order order, CancellationToken ct);
}
public class StripePaymentProcessor
: IPaymentProcessor
{
public async Task ProcessAsync(
Order order, CancellationToken ct)
{
// Реализация для Stripe
}
}
Теперь бизнес-логика может сфокусироваться на домене:
public class CheckoutService(
IPaymentProcessor processor)
{
public Task CheckoutAsync(
Order order, CancellationToken ct) =>
processor.ProcessAsync(order, ct);
}
Эта абстракция изолирует действительно нестабильную зависимость (платёжного провайдера), сохраняя при этом независимость логики оформления заказа. Когда Stripe поменяет свой API или вы поменяете провайдера, нужно изменить только один класс. Это хорошая абстракция. Она даёт опциональность там, где она действительно нужна.
Когда абстракции становятся техническим долгом
Проблемы возникают, когда мы абстрагируем то, что на самом деле не является изменчивым. В итоге мы оборачиваем стабильные библиотеки или создаём слои, которые не приносят реальной ценности. «Чистый» слой, добавленный вами сегодня, завтра становится обузой для обслуживания.
Большинство команд начинают с чего-то разумного:
public interface IUserRepository
{
Task<IEnumerable<User>> GetAllAsync();
}
Но по мере изменения требований, растёт и интерфейс:
public interface IUserRepository
{
Task<IEnumerable<User>> GetAllAsync();
Task<User?> GetByEmailAsync(string email);
Task<IEnumerable<User>> GetActiveUsersAsync();
Task<IEnumerable<User>> GetUsersByRoleAsync(string role);
Task<IEnumerable<User>> SearchAsync(string keyword, int page, int pageSize);
// ...и т.д.
}
Внезапно репозиторий начинает пропускать логику запросов в свой интерфейс. Каждый новый способ получения пользователей означает новый метод, и «абстракция» становится сборищем всевозможных запросов.
Между тем, Entity Framework уже предоставляет всё это через LINQ: строго типизированные запросы, которые напрямую соответствуют SQL. Вместо того, чтобы использовать эту мощь, вы ввели слой косвенности. Паттерн репозитория имел смысл, когда ORM были незрелыми. Сегодня это часто просто формальность.
Частью взросления разработчика является умение распознавать, когда паттерны становятся антипаттернами. Репозитории имеют смысл, когда они инкапсулируют сложную логику запросов или предоставляют унифицированный API для нескольких источников данных. Но вы должны стремиться, чтобы они были сосредоточены на логике предметной области. Как только они разрастаются в мириады методов для каждого возможного запроса, это признак того, что абстракция дала сбой.
Продолжение следует…
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
👍22
День 2416. #ЗаметкиНаПолях
Реальная Цена Абстракций в .NET. Продолжение
Начало
Обёртки Сервисов: контекст имеет значение
✅ Хороший пример
При интеграции с внешними API обёртка действительно полезна, поскольку централизует задачи:
Эта обёртка изолирует детали API GitHub. При изменении аутентификации или развитии конечных точек вы обновляете одно место. Вашей бизнес-логике не нужно разбираться с HTTP-заголовками, базовыми URL или JSON-сериализацией.
❌ Плохой пример
Проблемы начинаются, когда мы обёртываем наши собственные стабильные сервисы, не добавляя им ценности:
Этот UserService только добавляет косвенности. Всё, что он делает, — перенаправляет вызовы в IUserRepository. Он не обеспечивает соблюдение бизнес-правил, не добавляет валидацию, не реализует кэширование и не предоставляет никакой реальной функциональности. Это слой, существующий только потому, что «сервисы — это хорошая архитектура».
По мере того, как эти атрофированные обёртки множатся, ваша кодовая база превращается в лабиринт. Разработчики тратят время на перемещение по слоям вместо того, чтобы сосредоточиться на том, где на самом деле находится бизнес-логика.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
Реальная Цена Абстракций в .NET. Продолжение
Начало
Обёртки Сервисов: контекст имеет значение
✅ Хороший пример
При интеграции с внешними API обёртка действительно полезна, поскольку централизует задачи:
public interface IGitHubClient
{
Task<UserDto?> GetUserAsync(string username);
Task<IReadOnlyList<RepoDto>>
GetRepositoriesAsync(string username);
}
public class GitHubClient(HttpClient httpClient)
: IGitHubClient
{
public Task<UserDto?> GetUserAsync(string username) =>
httpClient
.GetFromJsonAsync<UserDto>($"/users/{username}");
public Task<IReadOnlyList<RepoDto>>
GetRepositoriesAsync(string username) =>
httpClient
.GetFromJsonAsync<IReadOnlyList<RepoDto>>(
$"/users/{username}/repos");
}
Эта обёртка изолирует детали API GitHub. При изменении аутентификации или развитии конечных точек вы обновляете одно место. Вашей бизнес-логике не нужно разбираться с HTTP-заголовками, базовыми URL или JSON-сериализацией.
❌ Плохой пример
Проблемы начинаются, когда мы обёртываем наши собственные стабильные сервисы, не добавляя им ценности:
public class UserService(IUserRepository userRepository)
{
// Просто перенаправляем вызовы
public Task<User?> GetByIdAsync(Guid id)
=> userRepository.GetByIdAsync(id);
public Task<IEnumerable<User>> GetAllAsync()
=> userRepository.GetAllAsync();
public Task SaveAsync(User user)
=> userRepository.SaveAsync(user);
}
Этот UserService только добавляет косвенности. Всё, что он делает, — перенаправляет вызовы в IUserRepository. Он не обеспечивает соблюдение бизнес-правил, не добавляет валидацию, не реализует кэширование и не предоставляет никакой реальной функциональности. Это слой, существующий только потому, что «сервисы — это хорошая архитектура».
По мере того, как эти атрофированные обёртки множатся, ваша кодовая база превращается в лабиринт. Разработчики тратят время на перемещение по слоям вместо того, чтобы сосредоточиться на том, где на самом деле находится бизнес-логика.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
👍16👎1
День 2417. #ЗаметкиНаПолях
Реальная Цена Абстракций в .NET. Окончание
Начало
Продолжение
Принимаем более взвешенные решения
Вот как следует понимать, когда абстракции стоят того:
1. Абстрактные политики, а не механизмы
Политики — решения, которые могут измениться: какой платёжный сервис использовать, как обрабатывать кэширование, стратегии повторных попыток для внешних вызовов.
Механизмы — стабильные детали реализации: LINQ в EF Core, конфигурация HttpClient, сериализация JSON.
Абстрагируйте политики, т.к. они обеспечивают гибкость. Не абстрагируйте механизмы — это уже стабильные API, которые редко меняются критически.
2. Дождитесь второй реализации
Если у вас только одна реализация, не поддавайтесь соблазну создать интерфейс. Одна реализация не оправдывает абстрагирование, это преждевременное обобщение, которое добавляет сложности без какой-либо пользы.
Абстракция возникает естественным образом, когда она действительно нужна. Интерфейс раскрывается через реальные требования, а не воображаемые.
3. Реализации внутри, абстракции на границах
Внутри приложения отдавайте предпочтение конкретным типам. Используйте EF напрямую, настраивайте HttpClient как типизированные клиенты, работайте с сущностями домена. Вводите абстракции только там, где система взаимодействует с внешним миром: внешними API, сторонними SDK, инфраструктурными сервисами. Именно там изменения наиболее вероятны, и там абстракции оправдывают себя.
Рефакторинг плохих абстракций
Регулярно задавайте себе вопрос: если я уберу эту абстракцию, код станет проще или сложнее? Если удаление интерфейса или сервисного уровня сделает код более понятным и прямолинейным, эта абстракция, вероятно, стоит больше, чем приносит пользы. Не бойтесь удалять ненужные уровни.
Выявив проблемные абстракции, вот как их безопасно удалить:
1. Определите реальных потребителей. Кому на самом деле нужна абстракция?
2. Встройте интерфейс. Замените абстрактные вызовы конкретными реализациями.
3. Удалите обёртку - ненужные косвенные обращения.
4. Упростите вызывающий код. Воспользуйтесь возможностями конкретного API.
Например, замените репозиторий прямым использованием EF:
Конкретная версия более явно описывает, какие данные она извлекает и как. Если вам нужен один и тот же запрос в нескольких местах, вы можете перенести его в метод расширения, чтобы сделать его общим.
Итого
Абстракции — мощные инструменты для управления сложностью и изменениями, но они не бесплатны. Каждая добавляет косвенные издержки, когнитивные накладные расходы и нагрузку на поддержку. Самая чистая архитектура — та, где каждый слой имеет чёткое и обоснованное назначение.
Прежде чем добавлять следующую абстракцию, спросите себя:
- Я абстрагирую политику или просто механизм?
- У меня две реализации, или я размышляю о будущих потребностях?
- Сделает ли это мою систему более адаптивной или просто более сложной для понимания?
- Если я уберу этот слой, станет ли код проще?
Помните: абстракции — это кредиты, по которым со временем начисляются проценты. Убедитесь, что вы берёте их по правильным причинам, а не просто по привычке.
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
Реальная Цена Абстракций в .NET. Окончание
Начало
Продолжение
Принимаем более взвешенные решения
Вот как следует понимать, когда абстракции стоят того:
1. Абстрактные политики, а не механизмы
Политики — решения, которые могут измениться: какой платёжный сервис использовать, как обрабатывать кэширование, стратегии повторных попыток для внешних вызовов.
Механизмы — стабильные детали реализации: LINQ в EF Core, конфигурация HttpClient, сериализация JSON.
Абстрагируйте политики, т.к. они обеспечивают гибкость. Не абстрагируйте механизмы — это уже стабильные API, которые редко меняются критически.
2. Дождитесь второй реализации
Если у вас только одна реализация, не поддавайтесь соблазну создать интерфейс. Одна реализация не оправдывает абстрагирование, это преждевременное обобщение, которое добавляет сложности без какой-либо пользы.
// 1: Начинаем с конкретного
public class EmailNotifier
{
public async Task SendAsync(
string to, string subject, string body)
{
// Реализация в SMTP
}
}
// 2: Нужны SMS? Теперь абстрагируемся
public interface INotifier
{
Task SendAsync(string to, string subject, string body);
}
public class EmailNotifier : INotifier { … }
public class SmsNotifier : INotifier { … }
Абстракция возникает естественным образом, когда она действительно нужна. Интерфейс раскрывается через реальные требования, а не воображаемые.
3. Реализации внутри, абстракции на границах
Внутри приложения отдавайте предпочтение конкретным типам. Используйте EF напрямую, настраивайте HttpClient как типизированные клиенты, работайте с сущностями домена. Вводите абстракции только там, где система взаимодействует с внешним миром: внешними API, сторонними SDK, инфраструктурными сервисами. Именно там изменения наиболее вероятны, и там абстракции оправдывают себя.
Рефакторинг плохих абстракций
Регулярно задавайте себе вопрос: если я уберу эту абстракцию, код станет проще или сложнее? Если удаление интерфейса или сервисного уровня сделает код более понятным и прямолинейным, эта абстракция, вероятно, стоит больше, чем приносит пользы. Не бойтесь удалять ненужные уровни.
Выявив проблемные абстракции, вот как их безопасно удалить:
1. Определите реальных потребителей. Кому на самом деле нужна абстракция?
2. Встройте интерфейс. Замените абстрактные вызовы конкретными реализациями.
3. Удалите обёртку - ненужные косвенные обращения.
4. Упростите вызывающий код. Воспользуйтесь возможностями конкретного API.
Например, замените репозиторий прямым использованием EF:
// До: Скрыто за репозиторием
var users = await _userRepo
.GetActiveUsersWithRecentOrders();
// После: Прямой запрос
var users = await _context.Users
.Where(u => u.IsActive)
.Where(u => u.Orders.Any(o => o.CreatedAt > DateTime.Now.AddDays(-30)))
.Include(u => u.Orders.Take(5))
.ToListAsync();
Конкретная версия более явно описывает, какие данные она извлекает и как. Если вам нужен один и тот же запрос в нескольких местах, вы можете перенести его в метод расширения, чтобы сделать его общим.
Итого
Абстракции — мощные инструменты для управления сложностью и изменениями, но они не бесплатны. Каждая добавляет косвенные издержки, когнитивные накладные расходы и нагрузку на поддержку. Самая чистая архитектура — та, где каждый слой имеет чёткое и обоснованное назначение.
Прежде чем добавлять следующую абстракцию, спросите себя:
- Я абстрагирую политику или просто механизм?
- У меня две реализации, или я размышляю о будущих потребностях?
- Сделает ли это мою систему более адаптивной или просто более сложной для понимания?
- Если я уберу этот слой, станет ли код проще?
Помните: абстракции — это кредиты, по которым со временем начисляются проценты. Убедитесь, что вы берёте их по правильным причинам, а не просто по привычке.
Источник: https://www.milanjovanovic.tech/blog/the-real-cost-of-abstractions-in-dotnet
👍15👎2