День 2358. #ЧтоНовенького #NET10
Разбираем Возможности dotnet run app.cs. Продолжение
Начало
Зачем?
Прежде всего, команда .NET ясно дала понять, что это делается для того, чтобы сделать обучение новичков .NET максимально удобным. Во многих других языках, будь то Node.js или Python, например, есть однофайловый интерфейс, а теперь он есть и в .NET. Новичок теперь может начать просто с файла .cs, и постепенно вводить новые концепции.
Постепенно вы дойдёте до точки, когда будет иметь смысл создать проект, например, для объединения нескольких CS-файлов. Тогда можно просто преобразовать отдельный файл в проект, выполнив:
Выполнение этой команды на примере из предыдущего поста создаст файл проекта, который выглядит следующим образом:
Все добавленные директивы включены в проект, а также добавлены другие значения по умолчанию. Это очень плавный переход от файловых приложений к файлам проектов.
Кроме того, есть несколько сценариев, где избавление от необходимости в отдельном проекте (и соответствующем каталоге) имеет смысл. Например:
1. Сервисные скрипты. Раньше вы, вероятно, использовали бы bash или PowerShell, но теперь, если хотите, можете легко использовать C#.
2. Примеры. Многие библиотеки или фреймворки предлагают несколько примеров приложений для демонстрации функций, каждому из которых требуется отдельная папка и файл проекта. Теперь у вас может быть одна папка, где каждый CS-файл будет примером приложения.
Дополнительные функции
Также существуют различные файлы, которые однофайловое приложение будет неявно использовать, если они доступны. К ним относятся:
- global.json
- NuGet.config
- Directory.Build.props
- Directory.Build.targets
- Directory.Packages.props
- Directory.Build.rsp
- MSBuild.rsp
Пожалуй, самый полезный из этих файлов — Directory.Build.props, который, по сути, позволяет «улучшить» ваше однофайловое приложение, добавив всё, что вы обычно помещаете в файл .csproj. Это особенно полезно, если у вас, например, есть несколько однофайловых приложений в каталоге, и вы хотите задать свойство или добавить пакет для всех, не обновляя каждое из них.
Это всё немного абстрактно, но вы можете увидеть различные примеры подобных вещей в репозитории «runfile Playground» Дэмиана Эдвардса, посвящённом этой функции!
Окончание следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
Разбираем Возможности dotnet run app.cs. Продолжение
Начало
Зачем?
Прежде всего, команда .NET ясно дала понять, что это делается для того, чтобы сделать обучение новичков .NET максимально удобным. Во многих других языках, будь то Node.js или Python, например, есть однофайловый интерфейс, а теперь он есть и в .NET. Новичок теперь может начать просто с файла .cs, и постепенно вводить новые концепции.
Постепенно вы дойдёте до точки, когда будет иметь смысл создать проект, например, для объединения нескольких CS-файлов. Тогда можно просто преобразовать отдельный файл в проект, выполнив:
dotnet project convert app.cs
Выполнение этой команды на примере из предыдущего поста создаст файл проекта, который выглядит следующим образом:
<Project Sdk="Microsoft.NET.Sdk">
<Sdk Name="Aspire.AppHost.Sdk" Version="9.3.0" />
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<PropertyGroup>
<UserSecretsId>2eec9746-c21a-4933-90af-c22431f35459</UserSecretsId>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Aspire.Hosting.AppHost" Version="9.3." />
</ItemGroup>
</Project>
Все добавленные директивы включены в проект, а также добавлены другие значения по умолчанию. Это очень плавный переход от файловых приложений к файлам проектов.
Кроме того, есть несколько сценариев, где избавление от необходимости в отдельном проекте (и соответствующем каталоге) имеет смысл. Например:
1. Сервисные скрипты. Раньше вы, вероятно, использовали бы bash или PowerShell, но теперь, если хотите, можете легко использовать C#.
2. Примеры. Многие библиотеки или фреймворки предлагают несколько примеров приложений для демонстрации функций, каждому из которых требуется отдельная папка и файл проекта. Теперь у вас может быть одна папка, где каждый CS-файл будет примером приложения.
Дополнительные функции
Также существуют различные файлы, которые однофайловое приложение будет неявно использовать, если они доступны. К ним относятся:
- global.json
- NuGet.config
- Directory.Build.props
- Directory.Build.targets
- Directory.Packages.props
- Directory.Build.rsp
- MSBuild.rsp
Пожалуй, самый полезный из этих файлов — Directory.Build.props, который, по сути, позволяет «улучшить» ваше однофайловое приложение, добавив всё, что вы обычно помещаете в файл .csproj. Это особенно полезно, если у вас, например, есть несколько однофайловых приложений в каталоге, и вы хотите задать свойство или добавить пакет для всех, не обновляя каждое из них.
Это всё немного абстрактно, но вы можете увидеть различные примеры подобных вещей в репозитории «runfile Playground» Дэмиана Эдвардса, посвящённом этой функции!
Окончание следует…
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
👍5
День 2359. #ЧтоНовенького #NET10
Разбираем Возможности dotnet run app.cs. Окончание
Начало
Продолжение
Наконец, посмотрим, что ещё готовится для однофайловых приложений.
Нет гарантии, что описанные ниже функции попадут в финальную версию, но есть большие шансы на это, учитывая, что первые несколько функций уже объединены в ветку следующего превью.
1. Публикация однофайловых приложений
Одна из функций, которая должна появиться в превью 6, — это возможность публиковать однофайловые приложения с помощью:
При этом по умолчанию приложения будут публиковаться как приложения NativeAOT! Вы можете отключить это, добавив #:property PublishAot false, но, скорее всего, всё будет работать без проблем во многих сценариях, для которых предназначены однофайловые приложения.
2. Запуск через dotnet app.cs
Поддержка запуска однофайловых приложений без использования команды run, т.е. вы можете использовать
вместо
Одно из главных преимуществ этого подхода заключается в том, что он делает поддержку шебангов в Linux более надёжной. Например, если вы хотите использовать /usr/bin/env для поиска исполняемого файла dotnet, вместо того, чтобы предполагать, что он находится в /usr/bin/dotnet, раньше нужно было сделать что-то вроде этого:
К сожалению, из-за того, что здесь приходится предоставлять несколько аргументов ("dotnet run"), это может не работать в некоторых оболочках. Однако с новой поддержкой dotnet app.cs вы можете использовать более простой и широко поддерживаемый вариант:
3. Запуск C# напрямую из стандартного ввода
Недавно была добавлена поддержка конвейеризации C#-кода напрямую в dotnet run, что позволяет выполнять такие действия:
Это перенаправляет приложение Hello World прямо из консоли в dotnet run и запускает его. Классический случай, когда «так делать ни в коем случае нельзя, но люди постоянно это делают», — скачиваем код из сети через curl и запускаем его напрямую - теперь возможен:
Чего не будет?
1. Одна из важных функций, которая не появится в .NET 10, — это поддержка нескольких файлов. Изначально планировалось включить её, причём такие вещи, как «вложенные» файлы и подкаталоги, которые неявно включались в компиляцию. Вместо этого эта работа была перенесена на .NET 11, чтобы сосредоточиться на максимальном улучшении взаимодействия с одним файлом.
Вы можете косвенно получить поддержку нескольких файлов, используя Directory.Build.props и Directory.Build.targets, а также добавляя ссылки на файлы «вручную».
2. Поддержка отдельных файлов не появится в Visual Studio. Поддержка от Microsoft будет реализована только в Visual Studio Code (и, разумеется, в CLI).
3. На данном этапе поддержка отдельных файлов будет реализована только для файлов .cs, а не для файлов .vb или .fs. Команда разработчиков не исключает полностью эту возможность, но маловероятно, что Microsoft сами добавят такую поддержку.
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
Разбираем Возможности dotnet run app.cs. Окончание
Начало
Продолжение
Наконец, посмотрим, что ещё готовится для однофайловых приложений.
Нет гарантии, что описанные ниже функции попадут в финальную версию, но есть большие шансы на это, учитывая, что первые несколько функций уже объединены в ветку следующего превью.
1. Публикация однофайловых приложений
Одна из функций, которая должна появиться в превью 6, — это возможность публиковать однофайловые приложения с помощью:
dotnet publish app.cs
При этом по умолчанию приложения будут публиковаться как приложения NativeAOT! Вы можете отключить это, добавив #:property PublishAot false, но, скорее всего, всё будет работать без проблем во многих сценариях, для которых предназначены однофайловые приложения.
2. Запуск через dotnet app.cs
Поддержка запуска однофайловых приложений без использования команды run, т.е. вы можете использовать
dotnet app.cs
вместо
dotnet run app.cs
Одно из главных преимуществ этого подхода заключается в том, что он делает поддержку шебангов в Linux более надёжной. Например, если вы хотите использовать /usr/bin/env для поиска исполняемого файла dotnet, вместо того, чтобы предполагать, что он находится в /usr/bin/dotnet, раньше нужно было сделать что-то вроде этого:
#!/usr/bin/env dotnet run
К сожалению, из-за того, что здесь приходится предоставлять несколько аргументов ("dotnet run"), это может не работать в некоторых оболочках. Однако с новой поддержкой dotnet app.cs вы можете использовать более простой и широко поддерживаемый вариант:
#!/usr/bin/env dotnet
3. Запуск C# напрямую из стандартного ввода
Недавно была добавлена поддержка конвейеризации C#-кода напрямую в dotnet run, что позволяет выполнять такие действия:
> 'Console.WriteLine("Hello, World!");' | dotnet run -
Hello, World!
Это перенаправляет приложение Hello World прямо из консоли в dotnet run и запускает его. Классический случай, когда «так делать ни в коем случае нельзя, но люди постоянно это делают», — скачиваем код из сети через curl и запускаем его напрямую - теперь возможен:
> curl -S https://totally-safe-not-scary-at-all.com/ | dotnet run -
All your bases are belong to us!
Чего не будет?
1. Одна из важных функций, которая не появится в .NET 10, — это поддержка нескольких файлов. Изначально планировалось включить её, причём такие вещи, как «вложенные» файлы и подкаталоги, которые неявно включались в компиляцию. Вместо этого эта работа была перенесена на .NET 11, чтобы сосредоточиться на максимальном улучшении взаимодействия с одним файлом.
Вы можете косвенно получить поддержку нескольких файлов, используя Directory.Build.props и Directory.Build.targets, а также добавляя ссылки на файлы «вручную».
2. Поддержка отдельных файлов не появится в Visual Studio. Поддержка от Microsoft будет реализована только в Visual Studio Code (и, разумеется, в CLI).
3. На данном этапе поддержка отдельных файлов будет реализована только для файлов .cs, а не для файлов .vb или .fs. Команда разработчиков не исключает полностью эту возможность, но маловероятно, что Microsoft сами добавят такую поддержку.
Источник: https://andrewlock.net/exploring-dotnet-10-preview-features-1-exploring-the-dotnet-run-app.cs/
👍7
День 2360. #ЗаметкиНаПолях
Улучшаем Обработку Ошибок в Минимальных API с ProblemDetails
Будем честны: обработка ошибок — обычно последнее, о чём мы думаем при разработке API. Но она должна быть одной из первых.
Представьте, фронтенд вызывает API и получает в ответ следующее: "Object reference not set to an instance of an object." Вряд ли это сообщение ясно и полезно. Для сравнения:
Это полезно и понятно. Именно это нам и даёт ProblemDetails.
Что это?
Стандартный способ возврата сообщений об ошибках в API, определённый в RFC 7807. Вместо случайного текста или несогласованного JSON вы возвращаете структурированные ошибки, например:
В ASP.NET есть встроенная поддержка ProblemDetails, и она прекрасно работает и в минимальных API. Создадим пример минимального API, который
получает продукт по ID и возвращает ошибки, используя ProblemDetails.
Теперь запрос несуществующего продукта вернёт стандартный ответ ProblemDetails.
Дополнительные поля
Вы можете расширять ProblemDetails дополнительными данными:
Затем возвращайте его через Results.Problem(…) и передавайте дополнительные метаданные.
Преимущества
- Чистые ответы об ошибках;
- Легкость для понимания фронтендерами;
- Стандарт (RFC 7807);
- Встроено в .NET.
Глобальную обработку ошибок, начиная с .NET 8, можно настроить с помощью IExceptionHandler, который также будет выдавать ProblemDetails.
Источник: https://thecodeman.net/posts/better-error-handling-with-problemdetails
Улучшаем Обработку Ошибок в Минимальных API с ProblemDetails
Будем честны: обработка ошибок — обычно последнее, о чём мы думаем при разработке API. Но она должна быть одной из первых.
Представьте, фронтенд вызывает API и получает в ответ следующее: "Object reference not set to an instance of an object." Вряд ли это сообщение ясно и полезно. Для сравнения:
{
"title": "Что-то пошло не так.",
"status": 500,
"detail": "Пожалуйста, свяжитесь с поддержкой.",
"instance": "/products/0"
}
Это полезно и понятно. Именно это нам и даёт ProblemDetails.
Что это?
Стандартный способ возврата сообщений об ошибках в API, определённый в RFC 7807. Вместо случайного текста или несогласованного JSON вы возвращаете структурированные ошибки, например:
{
"title": "Product not found",
"status": 404,
"detail": "No product with ID 42.",
"instance": "/products/42"
}
В ASP.NET есть встроенная поддержка ProblemDetails, и она прекрасно работает и в минимальных API. Создадим пример минимального API, который
получает продукт по ID и возвращает ошибки, используя ProblemDetails.
public record Product(int Id, string Name);
…
// получаем продукт
app.MapGet("/products/{id:int}", (int id, HttpContext http) =>
{
var prod = context.Products
.FirstOrDefault(p => p.Id == id);
if (prod is null)
{
var notFound = new ProblemDetails
{
Title = "Продукт не найден",
Status = StatusCodes.Status404NotFound,
Detail = $"Продукт с ID={id} не найден.",
Instance = http.Request.Path
};
return Results.Problem(
title: notFound.Title,
detail: notFound.Detail,
statusCode: notFound.Status,
instance: notFound.Instance
);
}
return Results.Ok(prod);
});
app.Run();
Теперь запрос несуществующего продукта вернёт стандартный ответ ProblemDetails.
Дополнительные поля
Вы можете расширять ProblemDetails дополнительными данными:
public class CustomProblemDetails : ProblemDetails
{
public string ErrorCode { get; set; } = default!;
}
Затем возвращайте его через Results.Problem(…) и передавайте дополнительные метаданные.
Преимущества
- Чистые ответы об ошибках;
- Легкость для понимания фронтендерами;
- Стандарт (RFC 7807);
- Встроено в .NET.
Глобальную обработку ошибок, начиная с .NET 8, можно настроить с помощью IExceptionHandler, который также будет выдавать ProblemDetails.
Источник: https://thecodeman.net/posts/better-error-handling-with-problemdetails
👍13
День 2361. #Testing #BestPractices
Лучшие Практики Интеграционного Тестирования с Testcontainers. Начало
Интеграционные тесты с Testcontainers — мощный инструмент, но их поддержка может быстро превратиться в кошмар. Сегодня рассмотрим шаблоны, которые делают тесты Testcontainers надёжными, быстрыми и простыми в поддержке.
Традиционные интеграционные тесты часто используют общие тестовые БД или БД в памяти, которые не соответствуют поведению в рабочей среде. Вам либо приходится сталкиваться с загрязнением тестов между запусками, либо жертвовать реализмом ради скорости.
Testcontainers решает эту проблему, разворачивая настоящие Docker-контейнеры для ваших зависимостей. Тесты выполняются с использованием реальных PostgreSQL, Redis или любого другого сервиса, используемого в рабочей среде. После завершения тестов контейнеры уничтожаются, каждый раз позволяя вам начинать с чистого листа.
Всё происходит через API Docker. Testcontainers управляет всем жизненным циклом: извлечение образов, запуск контейнеров, ожидание готовности и очистка. Тестовому коду нужно лишь знать, как подключиться.
1. Подготовка
Убедитесь, что у вас есть необходимые пакеты:
Пакеты TestContainers существуют для множества сервисов.
2. Создание
Вот так можно создать контейнеры для PostgreSql и Redis:
3. Использование
Чтобы запускать и останавливать контейнеры в тестах, нужно реализовать IAsyncLifetime в вашей WebApplicationFactory:
Это гарантирует готовность контейнеров до запуска тестов и их очистку после них. Т.е. отсутствие остаточного состояния Docker или состояний гонки.
Совет: закрепите версии образов (например, postgres:17), чтобы избежать сюрпризов от изменений версий зависимостей.
4. Передача конфигурации в приложение
Testcontainers назначает динамические порты. Не пишите жёсткие строки подключения в коде. Вместо этого внедряйте значения через WebApplicationFactory.ConfigureWebHost:
Здесь используется метод UseSetting для динамической передачи строк подключения. Это также позволяет избежать состояний гонки или конфликтов с другими тестами, которые могут выполняться параллельно. Это гарантирует, что тесты всегда будут подключаться к правильным портам, независимо от того, что назначает Docker.
Нет необходимости удалять сервисы из коллекции сервисов или настраивать их вручную. Просто задайте строки подключения, и ваше приложение будет использовать их автоматически.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
Лучшие Практики Интеграционного Тестирования с Testcontainers. Начало
Интеграционные тесты с Testcontainers — мощный инструмент, но их поддержка может быстро превратиться в кошмар. Сегодня рассмотрим шаблоны, которые делают тесты Testcontainers надёжными, быстрыми и простыми в поддержке.
Традиционные интеграционные тесты часто используют общие тестовые БД или БД в памяти, которые не соответствуют поведению в рабочей среде. Вам либо приходится сталкиваться с загрязнением тестов между запусками, либо жертвовать реализмом ради скорости.
Testcontainers решает эту проблему, разворачивая настоящие Docker-контейнеры для ваших зависимостей. Тесты выполняются с использованием реальных PostgreSQL, Redis или любого другого сервиса, используемого в рабочей среде. После завершения тестов контейнеры уничтожаются, каждый раз позволяя вам начинать с чистого листа.
Всё происходит через API Docker. Testcontainers управляет всем жизненным циклом: извлечение образов, запуск контейнеров, ожидание готовности и очистка. Тестовому коду нужно лишь знать, как подключиться.
1. Подготовка
Убедитесь, что у вас есть необходимые пакеты:
Install-Package Microsoft.AspNetCore.Mvc.Testing
Install-Package Testcontainers.PostgreSql
Install-Package Testcontainers.Redis
Пакеты TestContainers существуют для множества сервисов.
2. Создание
Вот так можно создать контейнеры для PostgreSql и Redis:
var _pg = new PostgreSqlBuilder()
.WithImage("postgres:17")
.WithDatabase("mydb")
.WithUsername("postgres")
.WithPassword("postgres")
.Build();
var _redis = new RedisBuilder()
.WithImage("redis:latest")
.Build();
3. Использование
Чтобы запускать и останавливать контейнеры в тестах, нужно реализовать IAsyncLifetime в вашей WebApplicationFactory:
public sealed class IntegrationWebAppFactory :
WebApplicationFactory<Program>, IAsyncLifetime
{
public async Task InitializeAsync()
{
await _pg.StartAsync();
await _redis.StartAsync();
// Старт других зависимостей
}
public async Task DisposeAsync()
{
await _pg.StopAsync();
await _redis.StopAsync();
// Остановка других зависимостей
}
}
Это гарантирует готовность контейнеров до запуска тестов и их очистку после них. Т.е. отсутствие остаточного состояния Docker или состояний гонки.
Совет: закрепите версии образов (например, postgres:17), чтобы избежать сюрпризов от изменений версий зависимостей.
4. Передача конфигурации в приложение
Testcontainers назначает динамические порты. Не пишите жёсткие строки подключения в коде. Вместо этого внедряйте значения через WebApplicationFactory.ConfigureWebHost:
protected override void
ConfigureWebHost(IWebHostBuilder bldr)
{
bldr.UseSetting("ConnectionStrings:Database",
_pg.GetConnectionString());
bldr.UseSetting("ConnectionStrings:Redis",
_redis.GetConnectionString());
}
Здесь используется метод UseSetting для динамической передачи строк подключения. Это также позволяет избежать состояний гонки или конфликтов с другими тестами, которые могут выполняться параллельно. Это гарантирует, что тесты всегда будут подключаться к правильным портам, независимо от того, что назначает Docker.
Нет необходимости удалять сервисы из коллекции сервисов или настраивать их вручную. Просто задайте строки подключения, и ваше приложение будет использовать их автоматически.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
👍12
День 2362. #Testing #BestPractices
Лучшие Практики Интеграционного Тестирования с Testcontainers. Окончание
Начало
5. Совместное использование настроек с фикстурами xUnit
Фикстура — это общий контекст для тестов, позволяющий настроить дорогостоящие ресурсы, такие как БД или брокеры сообщений, один раз и использовать их повторно в нескольких тестах. Выбор между фикстурами классов и коллекций влияет как на производительность тестов, так и на изоляцию.
Фикстура класса — один контейнер на каждый тестовый класс.
Используйте, когда тесты изменяют глобальное состояние или когда отладка тестовых взаимодействий становится затруднительной. Применяйте, когда требуется полная изоляция между тестовыми классами (это медленнее, но безопаснее).
Фикстура коллекции — один контейнер, общий для нескольких тестовых классов.
Используйте, когда тесты не изменяют общее состояние или когда вы можете надёжно выполнить очистку между тестами. Т.е. когда тестовые классы не мешают друг другу (это быстрее, но требует дисциплины).
При использовании фикстур коллекций необходимо позаботиться об очистке любого состояния, которое может сохраняться между тестами. Это может включать сброс БД, очистку кэшей или удаление тестовых данных. Если этого не сделать, тесты могут влиять друг на друга, что приведёт к нестабильным результатам.
6. Вспомогательные методы для аутентификации и очистки
Фикстура может предоставлять вспомогательные методы для упрощения написания тестов:
Эти методы могут выполнять настройку аутентификации и очистку БД, чтобы не повторять шаблонный код в каждом тесте.
7. Написание поддерживаемых интеграционных тестов
При правильной настройке инфраструктуры ваши тесты должны быть сосредоточены на бизнес-логике. Сложность контейнеров должна быть скрыта за грамотно спроектированными базовыми классами и вспомогательными методами. В тестах вы не должны заботиться о правильной имитаций Postgres или Redis, а должны тестировать реальное поведение.
Итого
Testcontainers преобразовывает интеграционное тестирование, давая вам уверенность, которую приносит тестирование с реальными зависимостями. Больше не нужно беспокоиться о том, соответствует ли поведение вашей базы в памяти поведению производственной базы, или работать с общими тестовыми средами, которые выходят из строя при запуске тестов кем-то другим.
Начните с простого: выберите один интеграционный тест, который в настоящее время использует моки или БД в памяти, и преобразуйте его для использования Testcontainers. Вы сразу заметите разницу в уверенности, когда тест пройдёт успешно. Затем постепенно расширяйте его, чтобы охватить критически важные бизнес-процессы.
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
Лучшие Практики Интеграционного Тестирования с Testcontainers. Окончание
Начало
5. Совместное использование настроек с фикстурами xUnit
Фикстура — это общий контекст для тестов, позволяющий настроить дорогостоящие ресурсы, такие как БД или брокеры сообщений, один раз и использовать их повторно в нескольких тестах. Выбор между фикстурами классов и коллекций влияет как на производительность тестов, так и на изоляцию.
Фикстура класса — один контейнер на каждый тестовый класс.
Используйте, когда тесты изменяют глобальное состояние или когда отладка тестовых взаимодействий становится затруднительной. Применяйте, когда требуется полная изоляция между тестовыми классами (это медленнее, но безопаснее).
public class AddItemToCartTests :
IClassFixture<IntegrationWebAppFactory>
{
private IntegrationWebAppFactory _factory;
public AddItemToCartTests(
IntegrationWebAppFactory factory)
{
_factory = factory;
}
[Fact]
public async Task ShouldFail_WhenNotEnoughQuantity()
{ … }
}
Фикстура коллекции — один контейнер, общий для нескольких тестовых классов.
Используйте, когда тесты не изменяют общее состояние или когда вы можете надёжно выполнить очистку между тестами. Т.е. когда тестовые классы не мешают друг другу (это быстрее, но требует дисциплины).
[CollectionDefinition(nameof(IntegrationCollection))]
public sealed class IntegrationCollection :
ICollectionFixture<IntegrationWebAppFactory>
{
}
// Применение
[Collection(nameof(IntegrationCollection))]
public class AddItemToCartTests :
IntegrationTestFixture
{
public AddItemToCartTests(
IntegrationWebAppFactory factory)
: base(factory) { }
[Fact]
public async Task Should_Fail_WhenNotEnoughQuantity()
{ … }
}
При использовании фикстур коллекций необходимо позаботиться об очистке любого состояния, которое может сохраняться между тестами. Это может включать сброс БД, очистку кэшей или удаление тестовых данных. Если этого не сделать, тесты могут влиять друг на друга, что приведёт к нестабильным результатам.
6. Вспомогательные методы для аутентификации и очистки
Фикстура может предоставлять вспомогательные методы для упрощения написания тестов:
public async Task<HttpClient>
CreateAuthenticatedClientAsync() { … }
protected async Task CleanupDBAsync() { … }
Эти методы могут выполнять настройку аутентификации и очистку БД, чтобы не повторять шаблонный код в каждом тесте.
7. Написание поддерживаемых интеграционных тестов
При правильной настройке инфраструктуры ваши тесты должны быть сосредоточены на бизнес-логике. Сложность контейнеров должна быть скрыта за грамотно спроектированными базовыми классами и вспомогательными методами. В тестах вы не должны заботиться о правильной имитаций Postgres или Redis, а должны тестировать реальное поведение.
Итого
Testcontainers преобразовывает интеграционное тестирование, давая вам уверенность, которую приносит тестирование с реальными зависимостями. Больше не нужно беспокоиться о том, соответствует ли поведение вашей базы в памяти поведению производственной базы, или работать с общими тестовыми средами, которые выходят из строя при запуске тестов кем-то другим.
Начните с простого: выберите один интеграционный тест, который в настоящее время использует моки или БД в памяти, и преобразуйте его для использования Testcontainers. Вы сразу заметите разницу в уверенности, когда тест пройдёт успешно. Затем постепенно расширяйте его, чтобы охватить критически важные бизнес-процессы.
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
👍4
День 2363. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 58. Если не тратить время на учёбу и совершенствование, то не стоит ждать, что следующий проект будет реализован лучше предыдущего
Процесс размышления о событии, имеющий целью пережить следующее событие, называется ретроспективой («обзором результатов разработки» или «постмортемом» - даже если проект был реализован). Все команды разработчиков ПО должны проводить ретроспективы в конце цикла разработки (выпуска или итерации), по завершении проекта и при возникновении неожиданного или разрушительного события.
Ретроспектива позволяет учиться и совершенствоваться. Команда определяет, что получилось хорошо, а что нет, и благодаря этому получает возможность применить полученный опыт в будущей работе.
Ретроспектива помогает ответить на четыре вопроса:
1. Что получилось хорошо и что мы хотели бы повторить?
2. Что получилось не так хорошо и где в следующий раз следует поступить иначе?
3. Что нас удивило и может быть опасным в будущем?
4. Есть ли что-то, чего мы ещё не понимаем и должны исследовать?
Ретроспектива должна проводиться с привлечением всех участников и не должна использоваться для обвинения кого-то. Важно объективно и беспристрастно исследовать прошлый опыт. Каждый участник ретроспективы должен помнить первый закон Керта: «Какие бы факты ни вскрылись в ходе ретроспективы, мы должны понимать и искренне верить, что каждый старался делать свою работу максимально хорошо, с учётом имеющейся информации, навыков и способностей, доступных ресурсов и ситуации, сложившейся на тот момент.»
Время ретроспективы зависит от объёма проекта, качества выполнения работы и количества нового материала, который еще предстоит узнать. Agile-команде может потребоваться 30-60 минут на обсуждение итогов двухнедельного спринта. В больших проектах можно выделять до нескольких дней. Чем больше потенциальных рычагов для улучшения будущих результатов, тем целесообразнее тратить время на подведение итогов.
Ретроспектива — структурированная и ограниченная по времени последовательность действий: планирование, начало мероприятия, сбор информации, определение приоритетов проблем, анализ проблем и принятие решения о том, что делать с информацией. Члены команды делятся своим опытом работы над проектом: что произошло, когда и чем закончилось. Рекомендуется спрашивать мнение всех участников проекта, поскольку точка зрения каждого уникальна. Важно узнать эмоциональный фон участников во время выполнения проекта. Это позволяет найти идеи, повышающие чувство удовлетворенности работой.
Участники ретроспективы сообщают любые данные, собранные командой, в виде типичных метрик:
- размер — количество и объём требований, пользовательских историй и других элементов;
- трудозатраты — запланированные и фактические;
- время — запланированная и фактическая календарная продолжительность;
- качество — количество дефектов и их виды, производительность системы и другие качественные характеристики.
Результаты ретроспективы обязательно должны учитываться в текущей деятельности по совершенствованию процессов. Люди, проводящие ретроспективы, должны уделить время изучению способов решения прошлых проблем. В это время они не смогут заниматься решением задач проекта, поэтому усилия по совершенствованию должны быть добавлены в графики проекта. Если проектная команда проводит ретроспективу, но руководство не предоставляет ресурсы для решения выявленных проблем, то такая ретроспектива бесполезна.
Поэтому добавляйте в график время для обучения и экспериментов, чтобы люди могли учиться эффективно применять новые практики, инструменты и методы. Проведение ретроспектив без внесения каких-либо изменений в процессы — пустая трата времени, отбивающая у участников охоту участвовать в них. Высший признак успеха ретроспективы — наличие устойчивых изменений. Это говорит о том, что время, потраченное командой на размышления о прошлых событиях, приносит долговременную пользу.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 7.
Уроки 50 Лет Разработки ПО
Урок 58. Если не тратить время на учёбу и совершенствование, то не стоит ждать, что следующий проект будет реализован лучше предыдущего
Процесс размышления о событии, имеющий целью пережить следующее событие, называется ретроспективой («обзором результатов разработки» или «постмортемом» - даже если проект был реализован). Все команды разработчиков ПО должны проводить ретроспективы в конце цикла разработки (выпуска или итерации), по завершении проекта и при возникновении неожиданного или разрушительного события.
Ретроспектива позволяет учиться и совершенствоваться. Команда определяет, что получилось хорошо, а что нет, и благодаря этому получает возможность применить полученный опыт в будущей работе.
Ретроспектива помогает ответить на четыре вопроса:
1. Что получилось хорошо и что мы хотели бы повторить?
2. Что получилось не так хорошо и где в следующий раз следует поступить иначе?
3. Что нас удивило и может быть опасным в будущем?
4. Есть ли что-то, чего мы ещё не понимаем и должны исследовать?
Ретроспектива должна проводиться с привлечением всех участников и не должна использоваться для обвинения кого-то. Важно объективно и беспристрастно исследовать прошлый опыт. Каждый участник ретроспективы должен помнить первый закон Керта: «Какие бы факты ни вскрылись в ходе ретроспективы, мы должны понимать и искренне верить, что каждый старался делать свою работу максимально хорошо, с учётом имеющейся информации, навыков и способностей, доступных ресурсов и ситуации, сложившейся на тот момент.»
Время ретроспективы зависит от объёма проекта, качества выполнения работы и количества нового материала, который еще предстоит узнать. Agile-команде может потребоваться 30-60 минут на обсуждение итогов двухнедельного спринта. В больших проектах можно выделять до нескольких дней. Чем больше потенциальных рычагов для улучшения будущих результатов, тем целесообразнее тратить время на подведение итогов.
Ретроспектива — структурированная и ограниченная по времени последовательность действий: планирование, начало мероприятия, сбор информации, определение приоритетов проблем, анализ проблем и принятие решения о том, что делать с информацией. Члены команды делятся своим опытом работы над проектом: что произошло, когда и чем закончилось. Рекомендуется спрашивать мнение всех участников проекта, поскольку точка зрения каждого уникальна. Важно узнать эмоциональный фон участников во время выполнения проекта. Это позволяет найти идеи, повышающие чувство удовлетворенности работой.
Участники ретроспективы сообщают любые данные, собранные командой, в виде типичных метрик:
- размер — количество и объём требований, пользовательских историй и других элементов;
- трудозатраты — запланированные и фактические;
- время — запланированная и фактическая календарная продолжительность;
- качество — количество дефектов и их виды, производительность системы и другие качественные характеристики.
Результаты ретроспективы обязательно должны учитываться в текущей деятельности по совершенствованию процессов. Люди, проводящие ретроспективы, должны уделить время изучению способов решения прошлых проблем. В это время они не смогут заниматься решением задач проекта, поэтому усилия по совершенствованию должны быть добавлены в графики проекта. Если проектная команда проводит ретроспективу, но руководство не предоставляет ресурсы для решения выявленных проблем, то такая ретроспектива бесполезна.
Поэтому добавляйте в график время для обучения и экспериментов, чтобы люди могли учиться эффективно применять новые практики, инструменты и методы. Проведение ретроспектив без внесения каких-либо изменений в процессы — пустая трата времени, отбивающая у участников охоту участвовать в них. Высший признак успеха ретроспективы — наличие устойчивых изменений. Это говорит о том, что время, потраченное командой на размышления о прошлых событиях, приносит долговременную пользу.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 7.
👍6
День 2364. #ЗаметкиНаПолях
5 Ошибок, из-за Которых Код Становится Неподдерживаемым. Начало
Вот 5 самых распространённых ошибок в проектировании ПО, из-за которых работа с кодом становится кошмаром. Все эти ошибки со временем, по мере роста объёма кода, делают его неподдерживаемым.
1. Недопустимое состояние и проблемы с согласованностью данных
Ошибка связана с тем, что данные оказываются в недопустимом состоянии и сталкиваются с проблемами согласованности. Обычно это происходит из-за отсутствия надлежащего контроля над изменяющимся состоянием.
Представьте, что в приложении есть две разные системы — скажем, биллинг и управление доставкой — и биллинг меняет состояние доставки. Этого не должно быть. Нужна одна система, которая будет контролировать изменение своего состояния. Все изменения состояния всегда должны быть допустимыми, и данные всегда должны быть в допустимом состоянии.
В монолите применим тот же принцип. Вам необходимо определить владельцев данных, которые управляют своим состоянием. Недопустимо, чтобы любая часть монолита могла менять любое состояние в любой точке системы.
Если вы когда-либо сталкивались с вопросом: «Как мы оказались в таком состоянии? Почему данные вообще выглядят именно так? Как это произошло?», и не имели об этом ни малейшего понятия, то причина в отсутствии владения данными. Возможно, кто-то вручную подключился к БД, или другой сервис или приложение интегрировалось и изменило состояние.
Решение — явно определить владельцев данных. Определите API, с которым взаимодействуют другие части системы — это контракт. Когда вы хотите изменить состояние части системы, вы вызываете её API, и она управляет изменением своего состояния. Т.е. за изменение состояния отвечает одно конкретное место.
Ещё лучше определить команды и запросы:
- Команды изменяют состояние.
- Запросы только получают данные, относящиеся к определённой части системы.
Каждое взаимодействие проходит через единое место, которое владеет командами и запросами.
2. Кодовая база неявная
Обычно кодовая база основана на CRUD-операциях над сущностями. Если взглянуть на вашу кодовую базу, можно ли точно сказать, что она делает и каковы её возможности? Обычно нет, поскольку рабочие процессы, управляемые конечными пользователями, не описаны явно.
Это легко представить на примере событий домена. Предположим, у вас есть груз, и одним из необходимых действий является получение груза водителем. Когда водитель это делает, вы часто назначаете коносамент (bill of lading - BOL). Если вы используете только CRUD, вы можете обновить отгрузку с помощью BOL. Тогда возникает событие «изменение отгрузки».
Но почему отгрузка изменилась? Вы не знаете. Кто-то ввёл BOL впервые? Или добавил его повторно? Или же это был самовывоз?
В этом заключается существенная разница между явным и неявным описанием. Вместо стандартного события «изменение отгрузки» нужно явное событие, например, «отгрузка подготовлена к самовывозу», которое включает идентификатор отгрузки, местоположение, дату, время и коносамент. Это гораздо понятнее и точно показывает, что произошло.
Когда ваш API — это просто «изменение отгрузки», вы не знаете, что на самом деле пытается сделать пользователь. Вам остаётся только пытаться понять, что означает изменение данных и что вы хотите сделать после этого. Но часто дело не только в том, что данные изменились, но и в том, почему они изменились.
Явное описание значительно упрощает навигацию по кодовой базе. И вот связь с первой ошибкой: если у вас есть явные команды, они отвечают за владение и обеспечение корректности состояния.
Окончание следует…
Источник: https://codeopinion.com/5-mistakes-that-make-your-code-unmaintainable/
5 Ошибок, из-за Которых Код Становится Неподдерживаемым. Начало
Вот 5 самых распространённых ошибок в проектировании ПО, из-за которых работа с кодом становится кошмаром. Все эти ошибки со временем, по мере роста объёма кода, делают его неподдерживаемым.
1. Недопустимое состояние и проблемы с согласованностью данных
Ошибка связана с тем, что данные оказываются в недопустимом состоянии и сталкиваются с проблемами согласованности. Обычно это происходит из-за отсутствия надлежащего контроля над изменяющимся состоянием.
Представьте, что в приложении есть две разные системы — скажем, биллинг и управление доставкой — и биллинг меняет состояние доставки. Этого не должно быть. Нужна одна система, которая будет контролировать изменение своего состояния. Все изменения состояния всегда должны быть допустимыми, и данные всегда должны быть в допустимом состоянии.
В монолите применим тот же принцип. Вам необходимо определить владельцев данных, которые управляют своим состоянием. Недопустимо, чтобы любая часть монолита могла менять любое состояние в любой точке системы.
Если вы когда-либо сталкивались с вопросом: «Как мы оказались в таком состоянии? Почему данные вообще выглядят именно так? Как это произошло?», и не имели об этом ни малейшего понятия, то причина в отсутствии владения данными. Возможно, кто-то вручную подключился к БД, или другой сервис или приложение интегрировалось и изменило состояние.
Решение — явно определить владельцев данных. Определите API, с которым взаимодействуют другие части системы — это контракт. Когда вы хотите изменить состояние части системы, вы вызываете её API, и она управляет изменением своего состояния. Т.е. за изменение состояния отвечает одно конкретное место.
Ещё лучше определить команды и запросы:
- Команды изменяют состояние.
- Запросы только получают данные, относящиеся к определённой части системы.
Каждое взаимодействие проходит через единое место, которое владеет командами и запросами.
2. Кодовая база неявная
Обычно кодовая база основана на CRUD-операциях над сущностями. Если взглянуть на вашу кодовую базу, можно ли точно сказать, что она делает и каковы её возможности? Обычно нет, поскольку рабочие процессы, управляемые конечными пользователями, не описаны явно.
Это легко представить на примере событий домена. Предположим, у вас есть груз, и одним из необходимых действий является получение груза водителем. Когда водитель это делает, вы часто назначаете коносамент (bill of lading - BOL). Если вы используете только CRUD, вы можете обновить отгрузку с помощью BOL. Тогда возникает событие «изменение отгрузки».
Но почему отгрузка изменилась? Вы не знаете. Кто-то ввёл BOL впервые? Или добавил его повторно? Или же это был самовывоз?
В этом заключается существенная разница между явным и неявным описанием. Вместо стандартного события «изменение отгрузки» нужно явное событие, например, «отгрузка подготовлена к самовывозу», которое включает идентификатор отгрузки, местоположение, дату, время и коносамент. Это гораздо понятнее и точно показывает, что произошло.
Когда ваш API — это просто «изменение отгрузки», вы не знаете, что на самом деле пытается сделать пользователь. Вам остаётся только пытаться понять, что означает изменение данных и что вы хотите сделать после этого. Но часто дело не только в том, что данные изменились, но и в том, почему они изменились.
Явное описание значительно упрощает навигацию по кодовой базе. И вот связь с первой ошибкой: если у вас есть явные команды, они отвечают за владение и обеспечение корректности состояния.
Окончание следует…
Источник: https://codeopinion.com/5-mistakes-that-make-your-code-unmaintainable/
👍15👎1
День 2365. #ЗаметкиНаПолях
5 Mistakes That Make Your Code Unmaintainable
Начало
3. Добавление косвенности без осознания
Вы добавляете косвенность, заботясь о соблюдении принципа единой ответственности, и думаете, что поступаете хорошо, но на самом деле это не так. Косвенность возникает, когда вызывающий объект вызывает целевой объект, а вы добавляете что-то промежуточное, разделяя ответственность. Типичный пример — доступ к данным.
То, что кажется простым, например, контроллер, вызывающий уровень доступа к данным, часто реализовано гораздо сложнее. Контроллер вызывает сервис, вызывающий другой сервис, использующий метод расширения, который вызывает ORM, обращающийся к БД. Такая косвенная связь часто невидима, но затрудняет отслеживание запросов. Ошибка заключается в неосознавании добавляемой косвенности и того, представляет ли она реальную ценность.
Если ваш вызывающий код тесно связан с абстракцией, созданной только для того, чтобы скрыть зависимость от сторонних компонентов, это может быть оправдано, если есть несколько реализаций или вы хотите упростить API. Но если абстракция используется только в одном месте и не служит никакой реальной цели, она бесполезна. Бесполезные абстракции затрудняют навигацию по коду и его поддержку. Иногда лучше управлять связностью напрямую, чем создавать ненужные уровни.
Главное — помнить о добавляемой косвенности и о том, действительно ли она добавляет ценность. Слабая связность полезна. Но бесполезная косвенность и абстракции, которые не несут никакой ценности, а создаются лишь для «чистоты кода», вредны.
4. Игра в «Что, если»
Продумывание всех возможных будущих сценариев и попытка написать код, учитывающий их заранее. Это часто нарушает принцип YAGNI (You Ain't Gonna It — «Вам это не понадобится»). Вы можете подумать: «А что, если кто-то попросит похожую, но немного другую функцию?» Но если никто её ещё не запросил, как узнать, ценна ли она?
Вы можете писать слишком общий код или встраивать абстракции для гипотетических будущих изменений, например, замены технологий, которые могут никогда не произойти. Это приводит к появлению внутренних фреймворков или общего кода, который никто не понимает и не нуждается в нём, потому что существует только один реальный вариант использования.
Проблема с вопросом «что, если?» заключается в стоимости владения. Это не только первоначальные затраты на разработку, но и необходимость постоянного обслуживания и работы с кодом, который никто не использует, что добавляет сложности.
5. Неправильное управление рабочими процессами
Представьте себе простой рабочий процесс, например, размещение заказа. Вы проходите стадии оформления заказа, подтверждения, обработки оплаты и затем отправляете email с подтверждением. Кажется, просто.
Проблема, если рассматриваете это как один длинный процедурный процесс, а не как рабочий процесс с изолированными шагами. Что будет, если возникнет ошибка при списании средств с карты? Как ваш код справится с этой ситуацией? Нужно ли отменить заказ? Отправить email? Вывести ошибку пользователю?
Если ваш код слишком процедурный, у вас, вероятно, будет запутанный клубок условий и обработки исключений, который сложно отслеживать и поддерживать. Рабочие процессы следует рассматривать как небольшие блоки, которые выполняются изолированно и переходят от одного шага к другому. Такое управление значительно упрощает обработку ошибок, повторных попыток и ветвление.
Использование таких инструментов, как обмен сообщениями, очереди и т.п., поможет вам справиться с этой сложностью. Главное — распознавать рабочие процессы и использовать подходящие инструменты, а не создавать сложный процедурный код с обилием ветвлений.
Итого
Каждая из этих ошибок затрудняет поддержку и развитие кода с течением времени. Определение владения данными, чёткое указание команд и запросов, тщательное управление косвенными зависимостями, избегание преждевременного обобщения и правильная обработка рабочих процессов сделают вашу систему намного более управляемой.
Источник: https://codeopinion.com/5-mistakes-that-make-your-code-unmaintainable/
5 Mistakes That Make Your Code Unmaintainable
Начало
3. Добавление косвенности без осознания
Вы добавляете косвенность, заботясь о соблюдении принципа единой ответственности, и думаете, что поступаете хорошо, но на самом деле это не так. Косвенность возникает, когда вызывающий объект вызывает целевой объект, а вы добавляете что-то промежуточное, разделяя ответственность. Типичный пример — доступ к данным.
То, что кажется простым, например, контроллер, вызывающий уровень доступа к данным, часто реализовано гораздо сложнее. Контроллер вызывает сервис, вызывающий другой сервис, использующий метод расширения, который вызывает ORM, обращающийся к БД. Такая косвенная связь часто невидима, но затрудняет отслеживание запросов. Ошибка заключается в неосознавании добавляемой косвенности и того, представляет ли она реальную ценность.
Если ваш вызывающий код тесно связан с абстракцией, созданной только для того, чтобы скрыть зависимость от сторонних компонентов, это может быть оправдано, если есть несколько реализаций или вы хотите упростить API. Но если абстракция используется только в одном месте и не служит никакой реальной цели, она бесполезна. Бесполезные абстракции затрудняют навигацию по коду и его поддержку. Иногда лучше управлять связностью напрямую, чем создавать ненужные уровни.
Главное — помнить о добавляемой косвенности и о том, действительно ли она добавляет ценность. Слабая связность полезна. Но бесполезная косвенность и абстракции, которые не несут никакой ценности, а создаются лишь для «чистоты кода», вредны.
4. Игра в «Что, если»
Продумывание всех возможных будущих сценариев и попытка написать код, учитывающий их заранее. Это часто нарушает принцип YAGNI (You Ain't Gonna It — «Вам это не понадобится»). Вы можете подумать: «А что, если кто-то попросит похожую, но немного другую функцию?» Но если никто её ещё не запросил, как узнать, ценна ли она?
Вы можете писать слишком общий код или встраивать абстракции для гипотетических будущих изменений, например, замены технологий, которые могут никогда не произойти. Это приводит к появлению внутренних фреймворков или общего кода, который никто не понимает и не нуждается в нём, потому что существует только один реальный вариант использования.
Проблема с вопросом «что, если?» заключается в стоимости владения. Это не только первоначальные затраты на разработку, но и необходимость постоянного обслуживания и работы с кодом, который никто не использует, что добавляет сложности.
5. Неправильное управление рабочими процессами
Представьте себе простой рабочий процесс, например, размещение заказа. Вы проходите стадии оформления заказа, подтверждения, обработки оплаты и затем отправляете email с подтверждением. Кажется, просто.
Проблема, если рассматриваете это как один длинный процедурный процесс, а не как рабочий процесс с изолированными шагами. Что будет, если возникнет ошибка при списании средств с карты? Как ваш код справится с этой ситуацией? Нужно ли отменить заказ? Отправить email? Вывести ошибку пользователю?
Если ваш код слишком процедурный, у вас, вероятно, будет запутанный клубок условий и обработки исключений, который сложно отслеживать и поддерживать. Рабочие процессы следует рассматривать как небольшие блоки, которые выполняются изолированно и переходят от одного шага к другому. Такое управление значительно упрощает обработку ошибок, повторных попыток и ветвление.
Использование таких инструментов, как обмен сообщениями, очереди и т.п., поможет вам справиться с этой сложностью. Главное — распознавать рабочие процессы и использовать подходящие инструменты, а не создавать сложный процедурный код с обилием ветвлений.
Итого
Каждая из этих ошибок затрудняет поддержку и развитие кода с течением времени. Определение владения данными, чёткое указание команд и запросов, тщательное управление косвенными зависимостями, избегание преждевременного обобщения и правильная обработка рабочих процессов сделают вашу систему намного более управляемой.
Источник: https://codeopinion.com/5-mistakes-that-make-your-code-unmaintainable/
👍12
День 2366. #ProjectManagement
Измеряем Продуктивность Разработчиков. Начало
В мире разработки ПО измерение продуктивности остаётся одним из самых сложных, но в то же время критически важных аспектов управления командами разработчиков. В то время как другие бизнес-функции часто можно оценить с помощью простых метрик, разработка ПО представляет собой уникальную задачу из-за своей командной, сложной и творческой природы.
Организации в любой отрасли всё больше зависят от ПО, поэтому руководителям нужны надёжные способы оценки эффективности работы их команд разработчиков. Но остаётся вопрос: какие метрики действительно важны, а какие могут принести больше вреда, чем пользы?
Проблема измерения продуктивности
Измерение производительности труда разработчиков - сложная задача по нескольким причинам:
- Разработка ПО предполагает творческое решение задач, которое сложно выразить количественными показателями;
- Связь между входными и выходными данными значительно менее очевидна, чем в других бизнес-функциях;
- Разработка в значительной степени предполагает совместную работу, что затрудняет оценку индивидуального вклада;
- Различные уровни работы (системы, команды, отдельные лица) требуют разных подходов к измерению.
Как заметил один из руководителей инженерных отделов Microsoft: «Многие специалисты в сфере технологий давно убеждены, что невозможно правильно измерить производительность труда разработчиков и что только квалифицированные инженеры обладают достаточными знаниями, чтобы оценить работу своих коллег».
Однако по мере роста команд разработки и увеличения инвестиций организаций в инженерных специалистов подход «мы не можем это измерить» становится всё более несостоятельным.
Метрики, которые не работают (и почему)
Прежде чем углубляться в практические подходы к измерению, давайте рассмотрим некоторые распространённые, но проблемные метрики.
1. Строки кода (KLOC)
Хотя их легко измерить, строки кода — самый известный пример метрики тщеславия. Больше кода не обязательно означает лучше, и эта метрика может активно поощрять неэффективные практики:
- Поощряет многословный, неэффективный код;
- Игнорирует качество и поддерживаемость кода;
- Сильно варьируется в зависимости от языка программирования;
- Легко поддаётся манипуляциям.
2. Количество коммитов
Как и количество строк кода, измерение чистого количества коммитов мало что даёт знать о фактической производительности:
- Разработчики могут чаще вносить незначительные изменения, чтобы «обмануть» систему;
- Не отражает качество или ценность изменений;
- Игнорирует разницу в сложности между коммитами.
3. Отработанные часы
Время, затраченное на кодирование, не обязательно коррелирует с полученной ценностью:
- Поощряет презентеизм (видимость присутствия на работе), а не эффективность;
- Игнорирует качество выполненной работы;
- Может привести к выгоранию и снижению долгосрочной производительности.
Продолжение следует…
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
Измеряем Продуктивность Разработчиков. Начало
В мире разработки ПО измерение продуктивности остаётся одним из самых сложных, но в то же время критически важных аспектов управления командами разработчиков. В то время как другие бизнес-функции часто можно оценить с помощью простых метрик, разработка ПО представляет собой уникальную задачу из-за своей командной, сложной и творческой природы.
Организации в любой отрасли всё больше зависят от ПО, поэтому руководителям нужны надёжные способы оценки эффективности работы их команд разработчиков. Но остаётся вопрос: какие метрики действительно важны, а какие могут принести больше вреда, чем пользы?
Проблема измерения продуктивности
Измерение производительности труда разработчиков - сложная задача по нескольким причинам:
- Разработка ПО предполагает творческое решение задач, которое сложно выразить количественными показателями;
- Связь между входными и выходными данными значительно менее очевидна, чем в других бизнес-функциях;
- Разработка в значительной степени предполагает совместную работу, что затрудняет оценку индивидуального вклада;
- Различные уровни работы (системы, команды, отдельные лица) требуют разных подходов к измерению.
Как заметил один из руководителей инженерных отделов Microsoft: «Многие специалисты в сфере технологий давно убеждены, что невозможно правильно измерить производительность труда разработчиков и что только квалифицированные инженеры обладают достаточными знаниями, чтобы оценить работу своих коллег».
Однако по мере роста команд разработки и увеличения инвестиций организаций в инженерных специалистов подход «мы не можем это измерить» становится всё более несостоятельным.
Метрики, которые не работают (и почему)
Прежде чем углубляться в практические подходы к измерению, давайте рассмотрим некоторые распространённые, но проблемные метрики.
1. Строки кода (KLOC)
Хотя их легко измерить, строки кода — самый известный пример метрики тщеславия. Больше кода не обязательно означает лучше, и эта метрика может активно поощрять неэффективные практики:
- Поощряет многословный, неэффективный код;
- Игнорирует качество и поддерживаемость кода;
- Сильно варьируется в зависимости от языка программирования;
- Легко поддаётся манипуляциям.
2. Количество коммитов
Как и количество строк кода, измерение чистого количества коммитов мало что даёт знать о фактической производительности:
- Разработчики могут чаще вносить незначительные изменения, чтобы «обмануть» систему;
- Не отражает качество или ценность изменений;
- Игнорирует разницу в сложности между коммитами.
3. Отработанные часы
Время, затраченное на кодирование, не обязательно коррелирует с полученной ценностью:
- Поощряет презентеизм (видимость присутствия на работе), а не эффективность;
- Игнорирует качество выполненной работы;
- Может привести к выгоранию и снижению долгосрочной производительности.
Продолжение следует…
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
👍8
День 2367. #ProjectManagement
Измеряем Продуктивность Разработчиков. Продолжение
Начало
Метрики, которые действительно имеют значение
Эффективное измерение производительности требует более тонкого подхода, учитывающего как количественные, так и качественные факторы. Вот метрики, которые дают ценную информацию.
1. Метрики DORA
Метрики DevOps Research and Assessment (DORA) стали отраслевым стандартом для измерения эффективности поставки ПО:
1) Частота развёртывания (DF): как часто код успешно развёртывается в рабочей среде
- Элитные команды: несколько в день,
- Высокопроизводительные команды: от 1 в день до 1 в неделю,
2) Время внесения изменений (LTFC): от коммита до запуска в рабочей среде
- Элитные команды: менее 1 дня
- Высокопроизводительные команды: менее 1 недели
3) Процент ошибок в изменениях (CFR): процент изменений, приводящих к снижению качества обслуживания
- Элитные команды: 0–15%
- Высокопроизводительные команды: 16–30%
4) Среднее время восстановления (MTTR): время, необходимое для восстановления обслуживания после инцидента
- Элитные команды: менее часа
- Высокопроизводительные команды: менее дня
Эти метрики дают сбалансированное представление о скорости и стабильности, помогая командам оценить своё положение по сравнению с отраслевыми эталонами.
2. Фреймворк SPACE
Фреймворк SPACE предлагает более комплексный подход к измерению производительности:
- Удовлетворенность разработчиков: мотивация и баланс между работой и личной жизнью.
- Производительность: ощутимые результаты и эффективность, включая качество кода и скорость устранения ошибок.
- Действия: виды и уровни ежедневной работы по разработке, включая кодирование, отладку и совместную работу.
- Коммуникация и сотрудничество: насколько эффективно разработчики обмениваются информацией и работают вместе.
- Эффективность: насколько эффективно разработчики используют время и ресурсы для достижения целевой производительности.
SPACE признаёт, что продуктивность разработчиков включает в себя не только результаты, но и опыт, динамику работы команды и устойчивые методы работы.
Метрики процесса
Несколько метрик процесса могут дать ценную информацию:
1) Время цикла
Время для переноса кода пул-реквеста в эксплуатацию. Измеряет весь процесс PR — часто самый сложный этап разработки ПО.
2) Размер PR и время проверки
Небольшие PR (<200 строк) тесно связаны с более быстрым временем проверки и более быстрой интеграцией, т.к. обычно проверяются быстрее и тщательнее. Время проверки показывает, насколько быстро предоставляется и учитывается обратная связь.
3) Изменение и доработка кода
Объём кода, переписанного вскоре после написания, может указывать на нечёткие требования или проблемы процесса. Высокое изменение кода (>30%) может сигнализировать о проблемах с требованиями или дизайном. Отслеживание тенденций с течением времени важнее абсолютных цифр.
Внедрение эффективных измерений
Для эффективного измерения производительности требуется не просто выбор правильных метрик, а продуманный подход к их внедрению.
1. Сосредоточьтесь на командных, а не на индивидуальных метриках
Измерение производительности лучше работает на уровне команды, а не отдельного человека, т.к. разработка ПО - совместный процесс. Индивидуальные метрики часто создают нездоровую конкуренцию. Метрики на уровне команды поощряют сотрудничество и совместное владение.
2. Сочетайте опережающие и запаздывающие показатели
- Опережающие (например, размер PR или время проверки) помогают прогнозировать будущие результаты.
- Запаздывающие (частота развёртываний или процент ошибок в изменениях) подтверждают прошлые результаты.
3. Используйте данные для улучшения, а не для наказания
Основной целью должно быть постоянное совершенствование. Используйте данные для выявления узких мест. Сосредоточьте обсуждение на системных улучшениях, а не на индивидуальных показателях эффективности. Отмечайте улучшения и извлекайте уроки из неудач.
Окончание следует…
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
Измеряем Продуктивность Разработчиков. Продолжение
Начало
Метрики, которые действительно имеют значение
Эффективное измерение производительности требует более тонкого подхода, учитывающего как количественные, так и качественные факторы. Вот метрики, которые дают ценную информацию.
1. Метрики DORA
Метрики DevOps Research and Assessment (DORA) стали отраслевым стандартом для измерения эффективности поставки ПО:
1) Частота развёртывания (DF): как часто код успешно развёртывается в рабочей среде
- Элитные команды: несколько в день,
- Высокопроизводительные команды: от 1 в день до 1 в неделю,
2) Время внесения изменений (LTFC): от коммита до запуска в рабочей среде
- Элитные команды: менее 1 дня
- Высокопроизводительные команды: менее 1 недели
3) Процент ошибок в изменениях (CFR): процент изменений, приводящих к снижению качества обслуживания
- Элитные команды: 0–15%
- Высокопроизводительные команды: 16–30%
4) Среднее время восстановления (MTTR): время, необходимое для восстановления обслуживания после инцидента
- Элитные команды: менее часа
- Высокопроизводительные команды: менее дня
Эти метрики дают сбалансированное представление о скорости и стабильности, помогая командам оценить своё положение по сравнению с отраслевыми эталонами.
2. Фреймворк SPACE
Фреймворк SPACE предлагает более комплексный подход к измерению производительности:
- Удовлетворенность разработчиков: мотивация и баланс между работой и личной жизнью.
- Производительность: ощутимые результаты и эффективность, включая качество кода и скорость устранения ошибок.
- Действия: виды и уровни ежедневной работы по разработке, включая кодирование, отладку и совместную работу.
- Коммуникация и сотрудничество: насколько эффективно разработчики обмениваются информацией и работают вместе.
- Эффективность: насколько эффективно разработчики используют время и ресурсы для достижения целевой производительности.
SPACE признаёт, что продуктивность разработчиков включает в себя не только результаты, но и опыт, динамику работы команды и устойчивые методы работы.
Метрики процесса
Несколько метрик процесса могут дать ценную информацию:
1) Время цикла
Время для переноса кода пул-реквеста в эксплуатацию. Измеряет весь процесс PR — часто самый сложный этап разработки ПО.
2) Размер PR и время проверки
Небольшие PR (<200 строк) тесно связаны с более быстрым временем проверки и более быстрой интеграцией, т.к. обычно проверяются быстрее и тщательнее. Время проверки показывает, насколько быстро предоставляется и учитывается обратная связь.
3) Изменение и доработка кода
Объём кода, переписанного вскоре после написания, может указывать на нечёткие требования или проблемы процесса. Высокое изменение кода (>30%) может сигнализировать о проблемах с требованиями или дизайном. Отслеживание тенденций с течением времени важнее абсолютных цифр.
Внедрение эффективных измерений
Для эффективного измерения производительности требуется не просто выбор правильных метрик, а продуманный подход к их внедрению.
1. Сосредоточьтесь на командных, а не на индивидуальных метриках
Измерение производительности лучше работает на уровне команды, а не отдельного человека, т.к. разработка ПО - совместный процесс. Индивидуальные метрики часто создают нездоровую конкуренцию. Метрики на уровне команды поощряют сотрудничество и совместное владение.
2. Сочетайте опережающие и запаздывающие показатели
- Опережающие (например, размер PR или время проверки) помогают прогнозировать будущие результаты.
- Запаздывающие (частота развёртываний или процент ошибок в изменениях) подтверждают прошлые результаты.
3. Используйте данные для улучшения, а не для наказания
Основной целью должно быть постоянное совершенствование. Используйте данные для выявления узких мест. Сосредоточьте обсуждение на системных улучшениях, а не на индивидуальных показателях эффективности. Отмечайте улучшения и извлекайте уроки из неудач.
Окончание следует…
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
👎6
День 2368. #ProjectManagement
Измеряем Продуктивность Разработчиков. Окончание
Начало
Продолжение
Рекомендации по повышению продуктивности
Несколько практик, которые могут значительно повысить продуктивность разработчиков:
1. Снижение когнитивной нагрузки
Минимизация ненужной умственной нагрузки помогает сосредоточиться на самом важном:
- Ограничьте количество встреч, чтобы обеспечить непрерывное время для концентрации;
- По возможности поощряйте асинхронное общение;
- Создайте понятную документацию, чтобы снизить умственные затраты на переключение контекста.
2. Внедрите руководства
Структурированные рекомендации помогают снизить усталость от принятия решений:
- Создайте стандартизированные процедуры для повседневных задач;
- Разработайте стандарты и шаблоны кодирования;
- Документируйте рекомендации для обеспечения согласованности.
3. Автоматизируйте повторяющиеся задачи
Автоматизация позволяет разработчикам сосредоточиться на творческом решении проблем:
- Автоматизируйте процессы сборки, тестирования и развёртывания;
- Используйте инструменты, оптимизирующие проверку кода и управление PR;
- Внедряйте конвейеры CI/CD для снижения ручного труда.
4. Сопоставляйте сильные стороны разработчиков с проектами
Согласование работы с экспертными знаниями повышает как производительность, так и удовлетворённость:
- Создайте профили навыков для понимания потребностей разработчиков;
- Назначайте задачи на основе знаний и интересов;
- Предоставляйте возможности для роста в областях, представляющих интерес.
Реальные примеры повышения производительности
Модель «Squad» от Spotify
Spotify организовал команды в небольшие кросс-функциональные «отряды», каждый из которых отвечает за определённые функции или сервисы на всех этапах. Такой подход снизил зависимость между командами и сократил время цикла на 35%.
Опрос удовлетворённости разработчиков от Google
Google регулярно опрашивает разработчиков об их производительности и удовлетворённости. Обнаружив, что время сборки является основной проблемой, компания инвестировала в усовершенствования системы сборки, что позволило сэкономить примерно 3–5 часов на разработчика в неделю.
Индекс скорости разработки от Microsoft
В Microsoft разработали комплексную систему для измерения продуктивности разработчиков, учитывающую технические, процессные и культурные факторы. Компании, находящиеся в верхнем квартиле этого индекса, быстрее внедряют инновации и демонстрируют в 4–5 раз более высокую эффективность бизнеса.
Итого
Для эффективного измерения продуктивности разработчиков необходимо выйти за рамки простых показателей, таких как количество строк кода или отработанных часов. Вместо этого сосредоточьтесь на сбалансированных фреймворках, таких как DORA и SPACE, которые учитывают как количественные, так и качественные аспекты разработки.
Помните, что целью измерения должно быть постоянное совершенствование, а не наказание или нездоровая конкуренция. Используйте метрики для выявления узких мест на системном уровне и возможностей для улучшения, а не для оценки индивидуальной работы в отрыве от других.
Наиболее продуктивные команды разработки сочетают продуманное измерение с практиками, которые снижают трения и облегчают работу. Сосредоточившись на том, что действительно важно — эффективном создании ценности при сохранении удовлетворённости разработчиков, — организации могут создать устойчивую, высокопроизводительную инженерную культуру.
Совершенствуя свой подход к измерению и повышению продуктивности разработчиков, помните, что важнейшей метрикой является ценность, предоставляемая пользователям. Когда разработчики могут эффективно работать над значимыми задачами, производительность и удовлетворённость естественным образом растут.
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
Измеряем Продуктивность Разработчиков. Окончание
Начало
Продолжение
Рекомендации по повышению продуктивности
Несколько практик, которые могут значительно повысить продуктивность разработчиков:
1. Снижение когнитивной нагрузки
Минимизация ненужной умственной нагрузки помогает сосредоточиться на самом важном:
- Ограничьте количество встреч, чтобы обеспечить непрерывное время для концентрации;
- По возможности поощряйте асинхронное общение;
- Создайте понятную документацию, чтобы снизить умственные затраты на переключение контекста.
2. Внедрите руководства
Структурированные рекомендации помогают снизить усталость от принятия решений:
- Создайте стандартизированные процедуры для повседневных задач;
- Разработайте стандарты и шаблоны кодирования;
- Документируйте рекомендации для обеспечения согласованности.
3. Автоматизируйте повторяющиеся задачи
Автоматизация позволяет разработчикам сосредоточиться на творческом решении проблем:
- Автоматизируйте процессы сборки, тестирования и развёртывания;
- Используйте инструменты, оптимизирующие проверку кода и управление PR;
- Внедряйте конвейеры CI/CD для снижения ручного труда.
4. Сопоставляйте сильные стороны разработчиков с проектами
Согласование работы с экспертными знаниями повышает как производительность, так и удовлетворённость:
- Создайте профили навыков для понимания потребностей разработчиков;
- Назначайте задачи на основе знаний и интересов;
- Предоставляйте возможности для роста в областях, представляющих интерес.
Реальные примеры повышения производительности
Модель «Squad» от Spotify
Spotify организовал команды в небольшие кросс-функциональные «отряды», каждый из которых отвечает за определённые функции или сервисы на всех этапах. Такой подход снизил зависимость между командами и сократил время цикла на 35%.
Опрос удовлетворённости разработчиков от Google
Google регулярно опрашивает разработчиков об их производительности и удовлетворённости. Обнаружив, что время сборки является основной проблемой, компания инвестировала в усовершенствования системы сборки, что позволило сэкономить примерно 3–5 часов на разработчика в неделю.
Индекс скорости разработки от Microsoft
В Microsoft разработали комплексную систему для измерения продуктивности разработчиков, учитывающую технические, процессные и культурные факторы. Компании, находящиеся в верхнем квартиле этого индекса, быстрее внедряют инновации и демонстрируют в 4–5 раз более высокую эффективность бизнеса.
Итого
Для эффективного измерения продуктивности разработчиков необходимо выйти за рамки простых показателей, таких как количество строк кода или отработанных часов. Вместо этого сосредоточьтесь на сбалансированных фреймворках, таких как DORA и SPACE, которые учитывают как количественные, так и качественные аспекты разработки.
Помните, что целью измерения должно быть постоянное совершенствование, а не наказание или нездоровая конкуренция. Используйте метрики для выявления узких мест на системном уровне и возможностей для улучшения, а не для оценки индивидуальной работы в отрыве от других.
Наиболее продуктивные команды разработки сочетают продуманное измерение с практиками, которые снижают трения и облегчают работу. Сосредоточившись на том, что действительно важно — эффективном создании ценности при сохранении удовлетворённости разработчиков, — организации могут создать устойчивую, высокопроизводительную инженерную культуру.
Совершенствуя свой подход к измерению и повышению продуктивности разработчиков, помните, что важнейшей метрикой является ценность, предоставляемая пользователям. Когда разработчики могут эффективно работать над значимыми задачами, производительность и удовлетворённость естественным образом растут.
Источник: https://dev.to/teamcamp/measuring-developer-productivity-metrics-that-matter-and-those-that-dont-58n4
👍1
День 2369. #SystemDesign101
Шардинг Баз Данных
Шардинг (или шардирование) — это разделение хранилища на несколько независимых частей, шардов (от англ. shard — осколок). Не путайте шардирование с репликацией, в случае которой выделенные экземпляры базы данных являются не составными частями общего хранилища, а копиями друг друга.
Виды
1. По диапазону
Разделение данных на основе диапазонов определённых значений, например, деление информации о товарах в зависимости от их ценового диапазона.
2. По ключу
Работает на основе использования уникального значения, например идентификатора пользователя, в качестве входных данных для хэш-функции. Хэш-функция вычисляет выходное значение, которое используется для определения сервера, на котором должны храниться данные.
3. По директории
Предполагает наличие таблицы поиска, в которой используется ключ шарда для отслеживания того, в каком шарде хранятся те или иные данные. Подход позволяет более гибко добавлять или удалять серверы, а также изменять схему сегментирования, не влияя на работу остальной части приложения.
Источники:
- https://blog.bytebytego.com/p/a-guide-to-database-sharding-key
- https://habr.com/ru/companies/piter/articles/813133/
Шардинг Баз Данных
Шардинг (или шардирование) — это разделение хранилища на несколько независимых частей, шардов (от англ. shard — осколок). Не путайте шардирование с репликацией, в случае которой выделенные экземпляры базы данных являются не составными частями общего хранилища, а копиями друг друга.
Виды
1. По диапазону
Разделение данных на основе диапазонов определённых значений, например, деление информации о товарах в зависимости от их ценового диапазона.
2. По ключу
Работает на основе использования уникального значения, например идентификатора пользователя, в качестве входных данных для хэш-функции. Хэш-функция вычисляет выходное значение, которое используется для определения сервера, на котором должны храниться данные.
3. По директории
Предполагает наличие таблицы поиска, в которой используется ключ шарда для отслеживания того, в каком шарде хранятся те или иные данные. Подход позволяет более гибко добавлять или удалять серверы, а также изменять схему сегментирования, не влияя на работу остальной части приложения.
Источники:
- https://blog.bytebytego.com/p/a-guide-to-database-sharding-key
- https://habr.com/ru/companies/piter/articles/813133/
1👍15
День 2370. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 59. Самая удручающая закономерность в индустрии ПО — повторение одних и тех же неэффективных действий снова и снова
У нас имеются бесчисленные коллекции лучших приёмов в области разработки ПО и сборники уроков, извлечённых из практики. Существует огромное количество книг по разным аспектам разработки и управления проектами. И всё же многие проекты продолжают сталкиваться с проблемами, поскольку не практикуют мероприятия, способствующие успеху.
Группа Standish Group публикует отчёты CHAOS (Comprehensive Human Appraisal for Organizing Software - Комплексная оценка персонала при разработке ПО) с 1994 года. Отчеты основаны на данных тысяч проектов и показывают процент проектов полностью успешных, столкнувшихся с трудностями или потерпевших неудачу. Успех определяется как комбинация из трёх показателей:
1. завершение в срок,
2. непревышение бюджета,
3. удовлетворение потребностей клиентов и пользователей.
И доля полностью успешных проектов много лет не превышает 40%. Но главное, что факторы, приводящие к проблемам и неудачам, почти не меняются.
Наблюдение за закономерностями в результатах ведёт к новым парадигмам выполнения работы. Например, аналитический паралич и устаревающие требования в долгосрочных проектах помогли мотивировать стремление к поэтапной разработке. Некоторые данные в отчетах CHAOS показывают, что проекты, практикующие Agile, имеют более высокий процент успеха, чем водопадные проекты.
Разработка ПО отличается от других технических областей тем, что вы можете выполнять полезную работу, имея минимальное формальное образование и опыт, по крайней мере, до определённого момента. Никто не будет просить врача-любителя удалить ему аппендикс, но многие программисты-любители имеют достаточный объём знаний, чтобы писать небольшие приложения. Однако между ними и опытными инженерами-программистами, способными работать над большими и сложными проектами в сотрудничестве с другими, - пропасть.
Сейчас многие молодые специалисты приходят в отрасль через академическую программу в области информатики, разработки ПО или смежных областей. Однако каждый специалист по разработке ПО, имеющий формальное образование или обучавшийся самостоятельно, должен продолжать поглощать постоянно растущий объём знаний и учиться эффективно их применять. В сфере ПО многие аспекты меняются очень быстро. Чтобы идти в ногу с современными технологиями, порой приходится бежать.
Каждая организация, занимающаяся разработкой, накапливает неформальную коллекцию локальных знаний, основанных на опыте. Важно записывать полученные на горьком опыте знания в сборник извлечённых уроков. Предусмотрительные руководители проектов и разработчики с удовольствием обратятся к нему, приступая к новому начинанию.
Совершенствование процесса разработки
1. Пересмотрите посты из серии #УрокиРазработки, и определите, какие советы имеют отношение к вашему опыту совершенствования процессов разработки.
2. Можете ли вы, опираясь на свой опыт, вспомнить какие-либо другие уроки, связанные с совершенствованием процессов, которыми стоит поделиться с коллегами?
3. Вспомните три самые болезненные для вас точки и проанализируйте их первопричины, чтобы выявить факторы, на которые можно направить усилия на первом этапе совершенствования процессов.
4. Пересмотрите методы из блока «Первые шаги» в этом посте. Как каждый метод может повысить эффективность и результативность вашей команды?
5. Как бы вы определили, приносит ли желаемые результаты каждый метод из шага 4? Насколько ценны для вас эти результаты?
6. Определите любые препятствия, которые могут затруднить применение методов, перечисленных на шаге 4. Как бы вы справились с ними? Заручились бы поддержкой коллег, готовых помочь вам в реализации этих методов?
7. Какие тренинги, книги, руководства или другие ресурсы могли бы помочь вашей организации успешнее проводить мероприятия по совер¬шенствованию процессов?
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 7.
Уроки 50 Лет Разработки ПО
Урок 59. Самая удручающая закономерность в индустрии ПО — повторение одних и тех же неэффективных действий снова и снова
У нас имеются бесчисленные коллекции лучших приёмов в области разработки ПО и сборники уроков, извлечённых из практики. Существует огромное количество книг по разным аспектам разработки и управления проектами. И всё же многие проекты продолжают сталкиваться с проблемами, поскольку не практикуют мероприятия, способствующие успеху.
Группа Standish Group публикует отчёты CHAOS (Comprehensive Human Appraisal for Organizing Software - Комплексная оценка персонала при разработке ПО) с 1994 года. Отчеты основаны на данных тысяч проектов и показывают процент проектов полностью успешных, столкнувшихся с трудностями или потерпевших неудачу. Успех определяется как комбинация из трёх показателей:
1. завершение в срок,
2. непревышение бюджета,
3. удовлетворение потребностей клиентов и пользователей.
И доля полностью успешных проектов много лет не превышает 40%. Но главное, что факторы, приводящие к проблемам и неудачам, почти не меняются.
Наблюдение за закономерностями в результатах ведёт к новым парадигмам выполнения работы. Например, аналитический паралич и устаревающие требования в долгосрочных проектах помогли мотивировать стремление к поэтапной разработке. Некоторые данные в отчетах CHAOS показывают, что проекты, практикующие Agile, имеют более высокий процент успеха, чем водопадные проекты.
Разработка ПО отличается от других технических областей тем, что вы можете выполнять полезную работу, имея минимальное формальное образование и опыт, по крайней мере, до определённого момента. Никто не будет просить врача-любителя удалить ему аппендикс, но многие программисты-любители имеют достаточный объём знаний, чтобы писать небольшие приложения. Однако между ними и опытными инженерами-программистами, способными работать над большими и сложными проектами в сотрудничестве с другими, - пропасть.
Сейчас многие молодые специалисты приходят в отрасль через академическую программу в области информатики, разработки ПО или смежных областей. Однако каждый специалист по разработке ПО, имеющий формальное образование или обучавшийся самостоятельно, должен продолжать поглощать постоянно растущий объём знаний и учиться эффективно их применять. В сфере ПО многие аспекты меняются очень быстро. Чтобы идти в ногу с современными технологиями, порой приходится бежать.
Каждая организация, занимающаяся разработкой, накапливает неформальную коллекцию локальных знаний, основанных на опыте. Важно записывать полученные на горьком опыте знания в сборник извлечённых уроков. Предусмотрительные руководители проектов и разработчики с удовольствием обратятся к нему, приступая к новому начинанию.
Совершенствование процесса разработки
1. Пересмотрите посты из серии #УрокиРазработки, и определите, какие советы имеют отношение к вашему опыту совершенствования процессов разработки.
2. Можете ли вы, опираясь на свой опыт, вспомнить какие-либо другие уроки, связанные с совершенствованием процессов, которыми стоит поделиться с коллегами?
3. Вспомните три самые болезненные для вас точки и проанализируйте их первопричины, чтобы выявить факторы, на которые можно направить усилия на первом этапе совершенствования процессов.
4. Пересмотрите методы из блока «Первые шаги» в этом посте. Как каждый метод может повысить эффективность и результативность вашей команды?
5. Как бы вы определили, приносит ли желаемые результаты каждый метод из шага 4? Насколько ценны для вас эти результаты?
6. Определите любые препятствия, которые могут затруднить применение методов, перечисленных на шаге 4. Как бы вы справились с ними? Заручились бы поддержкой коллег, готовых помочь вам в реализации этих методов?
7. Какие тренинги, книги, руководства или другие ресурсы могли бы помочь вашей организации успешнее проводить мероприятия по совер¬шенствованию процессов?
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 7.
👍1
День 2371. #ЧтоНовенького #EF10
Именованные Фильтры Запросов в EF 10
Глобальные фильтры запросов EF Core долгое время были удобным способом применения общих условий ко всем запросам к сущности. Они особенно удобны в таких сценариях, как мягкое удаление и мультитенантность, когда требуется, чтобы одно и то же выражение WHERE автоматически добавлялось к каждому запросу.
Однако в предыдущих версиях EF Core было одно существенное ограничение: для каждого типа сущности можно было определить только один фильтр. Если нужно было объединить несколько условий, приходилось либо писать явные выражения &&, либо вручную отключать и повторно применять фильтры в конкретных запросах. Если HasQueryFilter вызывался дважды для одной и той же сущности, второй вызов перезаписывал первый.
Это работает, но делает невозможным выборочное отключение одного условия. IgnoreQueryFilters() отключает оба, заставляя вручную повторно применять тот фильтр, который вам ещё нужен.
EF 10 представляет альтернативу: именованные фильтры запросов. Она позволяет прикреплять несколько фильтров к одной сущности и ссылаться на них по имени. Затем можно отключать отдельные фильтры при необходимости, а не все фильтры сразу.
Чтобы прикрепить несколько фильтров к сущности, вызовите HasQueryFilter, указав имя для каждого фильтра:
Под капотом EF создаёт отдельные фильтры, идентифицируемые по указанным вами именам. Теперь вы можете отключить только фильтр мягкого удаления, сохранив фильтр клиента:
Если вы не укажете параметр, IgnoreQueryFilters() отключит все фильтры для сущности.
Совет: Используйте константы для имён фильтров
Именованные фильтры используют строковые ключи. Использование имён в виде строк в коде приводит к опечаткам и трудно уловимым ошибкам. Чтобы избежать этого, определите константы или перечисления для имён фильтров и используйте их повторно при необходимости:
Определение имён фильтров в одном месте уменьшает дублирование и повышает удобство поддержки. Другой рекомендуемый подход — обернуть вызов в метод расширения:
Это делает ваши намерения явными и централизует логику фильтрации в одном месте.
Итого
Добавление именованных фильтров запросов в EF 10 устраняет одно из давних ограничений функции глобальных фильтров запросов EF. Теперь вы можете:
- Прикреплять несколько фильтров к одной сущности и управлять ими по отдельности;
- Выборочно отключать определённые фильтры в запросе LINQ с помощью IgnoreQueryFilters(["FilterName"]);
- Упрощать распространённые шаблоны, такие как мягкое удаление и мультитенантность, без использования сложной условной логики.
Именованные фильтры запросов могут стать мощным инструментом для поддержания чистоты запросов и инкапсуляции логики предметной области.
Источник: https://www.milanjovanovic.tech/blog/named-query-filters-in-ef-10-multiple-query-filters-per-entity
Именованные Фильтры Запросов в EF 10
Глобальные фильтры запросов EF Core долгое время были удобным способом применения общих условий ко всем запросам к сущности. Они особенно удобны в таких сценариях, как мягкое удаление и мультитенантность, когда требуется, чтобы одно и то же выражение WHERE автоматически добавлялось к каждому запросу.
Однако в предыдущих версиях EF Core было одно существенное ограничение: для каждого типа сущности можно было определить только один фильтр. Если нужно было объединить несколько условий, приходилось либо писать явные выражения &&, либо вручную отключать и повторно применять фильтры в конкретных запросах. Если HasQueryFilter вызывался дважды для одной и той же сущности, второй вызов перезаписывал первый.
modelBuilder.Entity<Order>()
.HasQueryFilter(o => !o.IsDeleted && o.TenantId == id);
Это работает, но делает невозможным выборочное отключение одного условия. IgnoreQueryFilters() отключает оба, заставляя вручную повторно применять тот фильтр, который вам ещё нужен.
EF 10 представляет альтернативу: именованные фильтры запросов. Она позволяет прикреплять несколько фильтров к одной сущности и ссылаться на них по имени. Затем можно отключать отдельные фильтры при необходимости, а не все фильтры сразу.
Чтобы прикрепить несколько фильтров к сущности, вызовите HasQueryFilter, указав имя для каждого фильтра:
modelBuilder.Entity<Order>()
.HasQueryFilter("SoftDeletionFilter",
o => !o.IsDeleted)
.HasQueryFilter("TenantFilter",
o => o.TenantId == tenantId);
Под капотом EF создаёт отдельные фильтры, идентифицируемые по указанным вами именам. Теперь вы можете отключить только фильтр мягкого удаления, сохранив фильтр клиента:
var allOrders = await context
.Orders
.IgnoreQueryFilters(["SoftDeletionFilter"])
.ToListAsync();
Если вы не укажете параметр, IgnoreQueryFilters() отключит все фильтры для сущности.
Совет: Используйте константы для имён фильтров
Именованные фильтры используют строковые ключи. Использование имён в виде строк в коде приводит к опечаткам и трудно уловимым ошибкам. Чтобы избежать этого, определите константы или перечисления для имён фильтров и используйте их повторно при необходимости:
public static class OrderFilters
{
public const string SoftDelete = nameof(SoftDelete);
public const string Tenant = nameof(Tenant);
}
modelBuilder.Entity<Order>()
.HasQueryFilter(OrderFilters.SoftDelete,
o => !o.IsDeleted)
.HasQueryFilter(OrderFilters.Tenant,
o => o.TenantId == tenantId);
…
// В запросе
var allOrders = await context
.Orders
.IgnoreQueryFilters([OrderFilters.SoftDelete])
.ToListAsync();
Определение имён фильтров в одном месте уменьшает дублирование и повышает удобство поддержки. Другой рекомендуемый подход — обернуть вызов в метод расширения:
public static IQueryable<Order>
IncludeSoftDeleted(this IQueryable<Order> query)
=> query.IgnoreQueryFilters([OrderFilters.SoftDelete]);
Это делает ваши намерения явными и централизует логику фильтрации в одном месте.
Итого
Добавление именованных фильтров запросов в EF 10 устраняет одно из давних ограничений функции глобальных фильтров запросов EF. Теперь вы можете:
- Прикреплять несколько фильтров к одной сущности и управлять ими по отдельности;
- Выборочно отключать определённые фильтры в запросе LINQ с помощью IgnoreQueryFilters(["FilterName"]);
- Упрощать распространённые шаблоны, такие как мягкое удаление и мультитенантность, без использования сложной условной логики.
Именованные фильтры запросов могут стать мощным инструментом для поддержания чистоты запросов и инкапсуляции логики предметной области.
Источник: https://www.milanjovanovic.tech/blog/named-query-filters-in-ef-10-multiple-query-filters-per-entity
👍16
День 2372. #ЗаметкиНаПолях
Библиотеки, Которые Используют в Microsoft. Начало
Устали от постоянных рекомендаций AutoMapper’а и Polly? Вот библиотеки, которые инженеры Microsoft действительно используют в продакшене. Они проверены в реальных условиях, оптимизированы по памяти и созданы для решения реальных масштабных задач.
1. Microsoft.IO.RecyclableMemoryStream
Проблема:
В API с большими объёмами трафика или заданиях экспорта использование new MemoryStream() приводит к фрагментации кучи больших объектов (LOH) и частым остановкам на сборки мусора. В масштабах Bing это приводило к исключениям OutOfMemoryException.
Решение:
Библиотека
- повторно использует внутренние буферы с помощью пула,
- сокращает выделение памяти и не использует LOH,
- предоставляет подробную диагностику использования памяти.
Когда использовать:
- API ASP.NET, возвращающие PDF-файлы, изображения и Excel;
- Фоновые задания, выполняющие операции с файлами;
- Бэкенды gRPC и SignalR.
До:
После:
Бенчмарк:
2. Генератор кода LoggerMessage
Проблема:
В API с высоким трафиком или микросервисах логирования, вроде такого:
…кажутся безобидными, но под капотом они вызывают:
- Аллокации памяти в куче из-за интерполяции строк;
- Упаковку типов-значений (например, int, bool);
- Излишнюю нагрузку на сборщик мусора при каждом запросе.
В масштабе Azure это быстро приводит к снижению пропускной способности, резким скачкам задержек и чрезмерному использованию памяти.
Решение:
Генератор исходного кода LoggerMessage, представленный в .NET 8, создаёт оптимизированные на этапе компиляции методы логирования, которые:
- Избегают интерполяции строк и упаковки;
- Используют структурированное форматирование на основе Span<T>;
- Генерируют IL без выделения памяти;
- В 5–10 раз быстрее традиционного ILogger.LogInformation(…).
Когда использовать:
- Высоконагруженное логирование в веб-API, рабочих процессах или обработчиках событий;
- Критичные к производительности пути, такие как конвейеры телеметрии или обработка запросов;
- Везде, где ILogger внедряется и часто вызывается.
До (аллокация):
После (генерация кода):
Бонус: вы можете поместить эти методы логирования в статические служебные классы для повторного использования в разных сервисах.
Продолжение следует…
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
Библиотеки, Которые Используют в Microsoft. Начало
Устали от постоянных рекомендаций AutoMapper’а и Polly? Вот библиотеки, которые инженеры Microsoft действительно используют в продакшене. Они проверены в реальных условиях, оптимизированы по памяти и созданы для решения реальных масштабных задач.
1. Microsoft.IO.RecyclableMemoryStream
Проблема:
В API с большими объёмами трафика или заданиях экспорта использование new MemoryStream() приводит к фрагментации кучи больших объектов (LOH) и частым остановкам на сборки мусора. В масштабах Bing это приводило к исключениям OutOfMemoryException.
Решение:
Библиотека
- повторно использует внутренние буферы с помощью пула,
- сокращает выделение памяти и не использует LOH,
- предоставляет подробную диагностику использования памяти.
Когда использовать:
- API ASP.NET, возвращающие PDF-файлы, изображения и Excel;
- Фоновые задания, выполняющие операции с файлами;
- Бэкенды gRPC и SignalR.
До:
using var ms = new MemoryStream();
После:
var mgr = new RecyclableMemoryStreamManager();
using var ms = mgr.GetStream();
Бенчмарк:
Method | Memory | Gen 0 | Gen 2
---------------- | -------| ----- | -----
MemoryStream | 85 KB | 1 | 1
RecyclableMemory | 2 KB | 0 | 0
2. Генератор кода LoggerMessage
Проблема:
В API с высоким трафиком или микросервисах логирования, вроде такого:
_logger.LogInformation($"Обработка заказа {orderId}");
…кажутся безобидными, но под капотом они вызывают:
- Аллокации памяти в куче из-за интерполяции строк;
- Упаковку типов-значений (например, int, bool);
- Излишнюю нагрузку на сборщик мусора при каждом запросе.
В масштабе Azure это быстро приводит к снижению пропускной способности, резким скачкам задержек и чрезмерному использованию памяти.
Решение:
Генератор исходного кода LoggerMessage, представленный в .NET 8, создаёт оптимизированные на этапе компиляции методы логирования, которые:
- Избегают интерполяции строк и упаковки;
- Используют структурированное форматирование на основе Span<T>;
- Генерируют IL без выделения памяти;
- В 5–10 раз быстрее традиционного ILogger.LogInformation(…).
Когда использовать:
- Высоконагруженное логирование в веб-API, рабочих процессах или обработчиках событий;
- Критичные к производительности пути, такие как конвейеры телеметрии или обработка запросов;
- Везде, где ILogger внедряется и часто вызывается.
До (аллокация):
_logger.LogInformation($"Обработка запроса {orderId}");
После (генерация кода):
[LoggerMessage(EventId = 100, Level = LogLevel.Information, Message = "Обработка запроса {OrderId}")]
partial void LogProcessingOrder(int orderId);
// Использование:
LogProcessingOrder(orderId);
Бонус: вы можете поместить эти методы логирования в статические служебные классы для повторного использования в разных сервисах.
Продолжение следует…
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
👍55
День 2373. #ЗаметкиНаПолях
Библиотеки, Которые Используют в Microsoft. Продолжение
Начало
3. Microsoft.SemanticKernel
Проблема:
Простых запросов и ответов недостаточно для производственных приложений ИИ. Необходимы память, декомпозиция целей и доступ к API, вроде Microsoft 365 Copilot. Реализация этого вручную в .NET — сложная задача.
Решение:
SemanticKernel — официальный SDK Microsoft для создания рабочих процессов ИИ, подобных агентам. Он обеспечивает:
- Выполнение инструментов и плагинов (C# или OpenAPI);
- Оркестровку цепочек запросов;
- Долговременную память между взаимодействиями;
- API планировщика для разбиения задач на подзадачи.
Когда использовать:
- Корпоративные ИИ-помощники (например, CRM-ассистенты, генераторы отчётов);
- Рабочие процессы ИИ, вызывающие внутренние API или функции;
- Многоэтапные чат-боты с планированием на основе целей и памятью.
До (единичнный запрос):
После (Оркестрация ИИ с SemanticKernel):
Вы можете регистрировать плагины, которые вызывают API, выполняют аутентификацию, запускают SQL-запросы или вызывают другие запросы — все из .NET. См. подробнее в документации.
4. System.Threading.Channels + IAsyncEnumerable
Проблема:
Использование BlockingCollection, ConcurrentQueue или настраиваемых очередей в высококонкурентных шаблонах «производитель/потребитель» часто приводит к нестабильной логике, избыточным блокировкам и плохому контролю, особенно под нагрузкой в телеметрических или потоковых конвейерах.
Решение:
System.Threading.Channels обеспечивает:
- Высокопроизводительный внутрипроцессный обмен сообщениями;
- Контроль пропускной способности через ограниченные каналы;
- Простую интеграцию с IAsyncEnumerable<T>;
- Асинхронную потоковую передачу без выделения памяти.
Первоначально использовавшаяся во внутренних компонентах SignalR и gRPC, теперь она является основным инструментом для создания отказоустойчивых асинхронных конвейеров в .NET.
Когда использовать:
- Сборщики телеметрии и обработчики метрик;
- Асинхронные конвейеры агрегации журналов/событий;
- Поведение, подобное очередям, без внешней инфраструктуры;
- Изоляция перегородками (Bulkhead isolation) в фоновых рабочих процессах.
До (BlockingCollection или Queue<T>):
После (Каналы и асинхронные потоки):
Работает по умолчанию с await foreach и идеально подходит для фоновых задач, связанных с вводом-выводом, потоковых API и повторяющихся рабочих процессов.
Окончание следует…
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
Библиотеки, Которые Используют в Microsoft. Продолжение
Начало
3. Microsoft.SemanticKernel
Проблема:
Простых запросов и ответов недостаточно для производственных приложений ИИ. Необходимы память, декомпозиция целей и доступ к API, вроде Microsoft 365 Copilot. Реализация этого вручную в .NET — сложная задача.
Решение:
SemanticKernel — официальный SDK Microsoft для создания рабочих процессов ИИ, подобных агентам. Он обеспечивает:
- Выполнение инструментов и плагинов (C# или OpenAPI);
- Оркестровку цепочек запросов;
- Долговременную память между взаимодействиями;
- API планировщика для разбиения задач на подзадачи.
Когда использовать:
- Корпоративные ИИ-помощники (например, CRM-ассистенты, генераторы отчётов);
- Рабочие процессы ИИ, вызывающие внутренние API или функции;
- Многоэтапные чат-боты с планированием на основе целей и памятью.
До (единичнный запрос):
var result = await openAiClient
.GetCompletionAsync("Какая погода в Москве?");
После (Оркестрация ИИ с SemanticKernel):
var kernel = Kernel.CreateBuilder().Build();
var prompt = kernel
.CreateFunctionFromPrompt("Какая погода в Москве?");
var result = await prompt.InvokeAsync();
Вы можете регистрировать плагины, которые вызывают API, выполняют аутентификацию, запускают SQL-запросы или вызывают другие запросы — все из .NET. См. подробнее в документации.
4. System.Threading.Channels + IAsyncEnumerable
Проблема:
Использование BlockingCollection, ConcurrentQueue или настраиваемых очередей в высококонкурентных шаблонах «производитель/потребитель» часто приводит к нестабильной логике, избыточным блокировкам и плохому контролю, особенно под нагрузкой в телеметрических или потоковых конвейерах.
Решение:
System.Threading.Channels обеспечивает:
- Высокопроизводительный внутрипроцессный обмен сообщениями;
- Контроль пропускной способности через ограниченные каналы;
- Простую интеграцию с IAsyncEnumerable<T>;
- Асинхронную потоковую передачу без выделения памяти.
Первоначально использовавшаяся во внутренних компонентах SignalR и gRPC, теперь она является основным инструментом для создания отказоустойчивых асинхронных конвейеров в .NET.
Когда использовать:
- Сборщики телеметрии и обработчики метрик;
- Асинхронные конвейеры агрегации журналов/событий;
- Поведение, подобное очередям, без внешней инфраструктуры;
- Изоляция перегородками (Bulkhead isolation) в фоновых рабочих процессах.
До (BlockingCollection или Queue<T>):
var queue = new Queue<int>();
lock (queue) { queue.Enqueue(42); }
int item;
lock (queue) { item = queue.Dequeue(); }
После (Каналы и асинхронные потоки):
var ch = Channel.CreateUnbounded<int>();
await ch.Writer.WriteAsync(42);
await foreach (var item in ch.Reader.ReadAllAsync())
Console.WriteLine(item);
Работает по умолчанию с await foreach и идеально подходит для фоновых задач, связанных с вводом-выводом, потоковых API и повторяющихся рабочих процессов.
Окончание следует…
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
👍20
День 2374. #ЗаметкиНаПолях
Библиотеки, Которые Используют в Microsoft. Окончание
Начало
Продолжение
5. Microsoft.Extensions.ObjectPool
Проблема:
Аллокация объектов, таких как StringBuilder, List<T> или Regex, в горячих путях (например, для каждого запроса) создает чрезмерную нагрузку на сборщик мусора, особенно в приложениях ASP.NET Core, где каждую секунду происходят тысячи аллокаций.
Решение:
ObjectPool<T> обеспечивает эффективное повторное использование дорогостоящих объектов. Это:
- Минимизирует перераспределение памяти и сборку объектов в 0 и 1 поколениях;
- Предотвращает использование LOH для больших буферов;
- Используется внутри ASP.NET Core для таких задач, как парсинг и маршрутизация запросов.
Когда использовать:
- Промежуточное ПО, создающее повторно используемые сборщики или форматировщики;
- Процедуры сериализации/десериализации;
- Пользовательские сервисы с большим объёмом выделения памяти (например, шаблонизаторы, сборка строк).
До (аллокация каждый раз):
После (повторное использование из пула):
Вы также можете создавать пользовательские политики автоматического сброса объектов в пуле (например, очистки содержимого StringBuilder перед повторным использованием).
6. Microsoft.Extensions.Caching.Memory (продвинутое использование)
Проблема:
Большинство разработчиков используют кэширование в памяти (IMemoryCache) с базовыми вызовами Set() и Get(), упуская расширенные функции, такие как уведомления о вытеснении, скользящее истечение срока действия, управление приоритетами и аннулирование на основе токенов. Это может привести к устареванию данных, раздуванию памяти или скрытым сбоям.
Решение:
Microsoft.Extensions.Caching.Memory поддерживает:
- Скользящее и абсолютное истечение срока действия;
- Приоритеты вытеснения (например, для более длительного хранения горячих элементов);
- Обратные вызовы после вытеснения для логирования или реагирования на очистку кэша;
- Аннулирование на основе токенов (например, выход пользователя из системы, перезагрузка конфигурации).
Эти функции обеспечивают более разумное использование памяти и реактивное поведение кэша в вашем приложении.
Когда использовать:
- Кэширование с логикой истечения срока действия, привязанной к сеансу пользователя или токену безопасности;
- Сценарии, требующие осведомлённости о вытеснении (например, ведение журнала, оповещения);
- Оптимизация производительности в режиме «горячего пути», когда требуется более интеллектуальное управление кэшем;
- Аннулирование записей кэша на основе внешних сигналов (например, токенов изменений).
До:
После (скользящее истечение срока с уведомлением о вытеснении):
Вы также можете связать записи с CancellationTokenSource, чтобы сделать кэш недействительным при возникновении внешних событий — отлично подходит для обновления конфигурации или отзыва авторизации.
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
Библиотеки, Которые Используют в Microsoft. Окончание
Начало
Продолжение
5. Microsoft.Extensions.ObjectPool
Проблема:
Аллокация объектов, таких как StringBuilder, List<T> или Regex, в горячих путях (например, для каждого запроса) создает чрезмерную нагрузку на сборщик мусора, особенно в приложениях ASP.NET Core, где каждую секунду происходят тысячи аллокаций.
Решение:
ObjectPool<T> обеспечивает эффективное повторное использование дорогостоящих объектов. Это:
- Минимизирует перераспределение памяти и сборку объектов в 0 и 1 поколениях;
- Предотвращает использование LOH для больших буферов;
- Используется внутри ASP.NET Core для таких задач, как парсинг и маршрутизация запросов.
Когда использовать:
- Промежуточное ПО, создающее повторно используемые сборщики или форматировщики;
- Процедуры сериализации/десериализации;
- Пользовательские сервисы с большим объёмом выделения памяти (например, шаблонизаторы, сборка строк).
До (аллокация каждый раз):
var sb = new StringBuilder();
sb.Append("Hello, GC!");
После (повторное использование из пула):
var pool = ObjectPool.Create<StringBuilder>();
var sb = pool.Get();
sb.Append("Hello, pooled!");
pool.Return(sb);
Вы также можете создавать пользовательские политики автоматического сброса объектов в пуле (например, очистки содержимого StringBuilder перед повторным использованием).
6. Microsoft.Extensions.Caching.Memory (продвинутое использование)
Проблема:
Большинство разработчиков используют кэширование в памяти (IMemoryCache) с базовыми вызовами Set() и Get(), упуская расширенные функции, такие как уведомления о вытеснении, скользящее истечение срока действия, управление приоритетами и аннулирование на основе токенов. Это может привести к устареванию данных, раздуванию памяти или скрытым сбоям.
Решение:
Microsoft.Extensions.Caching.Memory поддерживает:
- Скользящее и абсолютное истечение срока действия;
- Приоритеты вытеснения (например, для более длительного хранения горячих элементов);
- Обратные вызовы после вытеснения для логирования или реагирования на очистку кэша;
- Аннулирование на основе токенов (например, выход пользователя из системы, перезагрузка конфигурации).
Эти функции обеспечивают более разумное использование памяти и реактивное поведение кэша в вашем приложении.
Когда использовать:
- Кэширование с логикой истечения срока действия, привязанной к сеансу пользователя или токену безопасности;
- Сценарии, требующие осведомлённости о вытеснении (например, ведение журнала, оповещения);
- Оптимизация производительности в режиме «горячего пути», когда требуется более интеллектуальное управление кэшем;
- Аннулирование записей кэша на основе внешних сигналов (например, токенов изменений).
До:
_cache.Set("key", value);
После (скользящее истечение срока с уведомлением о вытеснении):
_cache.Set("key", value, new MemoryCacheEntryOptions
{
SlidingExpiration = TimeSpan.FromMinutes(5),
PostEvictionCallbacks = {
new PostEvictionCallbackRegistration
{
EvictionCallback =
(key, value, reason, state) =>
{
Console.WriteLine(
$"{key} вытеснен по причине {reason}");
}
}
}
});
Вы также можете связать записи с CancellationTokenSource, чтобы сделать кэш недействительным при возникновении внешних событий — отлично подходит для обновления конфигурации или отзыва авторизации.
Источник: https://blog.devgenius.io/7-elite-c-libraries-microsoft-uses-in-production-but-you-probably-dont-6bce3e3690ad
👍21
День 2375. #ЧтоНовенького #NET10
Новинки .NET 10 Превью 6. Начало
Microsoft анонсировали шестую превью версию .NET 10, включающую широкий спектр улучшений для среды выполнения .NET, SDK, библиотек, C#, ASP.NET Core, Blazor и .NET MAUI.
CLI
1. Инструменты .NET теперь можно публиковать с поддержкой нескольких идентификаторов среды выполнения (RID) в одном пакете. Разработчики инструментов могут объединять двоичные файлы для всех поддерживаемых платформ, а .NET CLI выберет нужный вариант при установке или запуске. Это значительно упрощает разработку и распространение кроссплатформенных инструментов.
2. Теперь вы можете использовать команду dotnet tool exec для одноразового запуска инструмента .NET без его глобальной или локальной установки. Это особенно полезно для непрерывной интеграции/разработки (CI/CD) или кратковременного использования. Инструмент будет скачан, если он не установлен локально.
3. Возможности интроспекции CLI были расширены с помощью опции --cli-schema, которая выводит машиночитаемое JSON-представление команд, облегчая автоматизацию и написание скриптов.
ASP.NET Core
Улучшено управление памятью пулов. Kestrel, IIS и HTTP.sys теперь поддерживают автоматическое освобождение неиспользуемой памяти из внутренних пулов при бездействии приложений. Как сообщается, это изменение не требует действий разработчика и призвано эффективно снизить потребление памяти. Метрики для пулов памяти теперь доступны в Microsoft.AspNetCore.MemoryPool, и разработчики могут создавать собственные пулы памяти с помощью нового интерфейса IMemoryPoolFactory.
Blazor
1. Новый компонент LinkPreload обеспечивает расширенный контроль над предварительной загрузкой ресурсов фреймворка, повышая производительность и определение базового URL-адреса.
2. Проекты Blazor WebAssembly теперь могут генерировать выходные данные, совместимые с упаковщиками JavaScript, такими как Webpack, установив WasmBundlerFriendlyBootConfig в значение true, что обеспечивает лучшую интеграцию с современными фронтенд-конвейерами.
3. Поддержка валидации в Blazor расширена и теперь включает вложенные объекты и коллекции в формах. Эта новая возможность реализуется через AddValidation() и атрибут [ValidatableType], при этом следует отметить, что атрибут остаётся экспериментальным.
4. Диагностика Blazor также была улучшена: трассировки теперь отображаются как действия верхнего уровня, что упрощает телеметрию в таких инструментах, как Application Insights.
5. Blazor Server теперь поддерживает сохранение состояния канала, позволяя пользователям возобновлять работу после повторного подключения, даже после отключения на стороне сервера. Разработчики могут управлять поведением канала с помощью новых API Blazor.pause() и Blazor.resume(), что поможет снизить потребление ресурсов сервера в периоды бездействия.
Окончание следует…
Источник: https://www.infoq.com/news/2025/07/dotnet-10-preview-6/
Новинки .NET 10 Превью 6. Начало
Microsoft анонсировали шестую превью версию .NET 10, включающую широкий спектр улучшений для среды выполнения .NET, SDK, библиотек, C#, ASP.NET Core, Blazor и .NET MAUI.
CLI
1. Инструменты .NET теперь можно публиковать с поддержкой нескольких идентификаторов среды выполнения (RID) в одном пакете. Разработчики инструментов могут объединять двоичные файлы для всех поддерживаемых платформ, а .NET CLI выберет нужный вариант при установке или запуске. Это значительно упрощает разработку и распространение кроссплатформенных инструментов.
2. Теперь вы можете использовать команду dotnet tool exec для одноразового запуска инструмента .NET без его глобальной или локальной установки. Это особенно полезно для непрерывной интеграции/разработки (CI/CD) или кратковременного использования. Инструмент будет скачан, если он не установлен локально.
3. Возможности интроспекции CLI были расширены с помощью опции --cli-schema, которая выводит машиночитаемое JSON-представление команд, облегчая автоматизацию и написание скриптов.
ASP.NET Core
Улучшено управление памятью пулов. Kestrel, IIS и HTTP.sys теперь поддерживают автоматическое освобождение неиспользуемой памяти из внутренних пулов при бездействии приложений. Как сообщается, это изменение не требует действий разработчика и призвано эффективно снизить потребление памяти. Метрики для пулов памяти теперь доступны в Microsoft.AspNetCore.MemoryPool, и разработчики могут создавать собственные пулы памяти с помощью нового интерфейса IMemoryPoolFactory.
Blazor
1. Новый компонент LinkPreload обеспечивает расширенный контроль над предварительной загрузкой ресурсов фреймворка, повышая производительность и определение базового URL-адреса.
2. Проекты Blazor WebAssembly теперь могут генерировать выходные данные, совместимые с упаковщиками JavaScript, такими как Webpack, установив WasmBundlerFriendlyBootConfig в значение true, что обеспечивает лучшую интеграцию с современными фронтенд-конвейерами.
3. Поддержка валидации в Blazor расширена и теперь включает вложенные объекты и коллекции в формах. Эта новая возможность реализуется через AddValidation() и атрибут [ValidatableType], при этом следует отметить, что атрибут остаётся экспериментальным.
4. Диагностика Blazor также была улучшена: трассировки теперь отображаются как действия верхнего уровня, что упрощает телеметрию в таких инструментах, как Application Insights.
5. Blazor Server теперь поддерживает сохранение состояния канала, позволяя пользователям возобновлять работу после повторного подключения, даже после отключения на стороне сервера. Разработчики могут управлять поведением канала с помощью новых API Blazor.pause() и Blazor.resume(), что поможет снизить потребление ресурсов сервера в периоды бездействия.
Окончание следует…
Источник: https://www.infoq.com/news/2025/07/dotnet-10-preview-6/
👍4
День 2376. #ЧтоНовенького #NET10
Новинки .NET 10 Превью 6. Окончание
Начало
ASP.NET Core Identity
Теперь поддерживает ключи доступа (passkey), что обеспечивает современную, устойчивую к фишингу аутентификацию с использованием стандартов WebAuthn и FIDO2.
Минимальные API
Теперь могут интегрировать ответы на ошибки валидации с помощью IProblemDetailsService, обеспечивая более согласованный и настраиваемый вывод ошибок. API валидации перемещены в новый пакет и пространство имен Microsoft.Extensions.Validation, что расширяет их применение за пределы ASP.NET Core.
MAUI
1. Улучшен элемент управления MediaPicker. Теперь разработчики могут выбирать несколько файлов и сжимать изображения непосредственно через API, используя параметры MaximumWidth и MaximumHeight. Эта функция упрощает обработку медиафайлов в приложениях, облегчая управление и обработку пользовательского контента без дополнительной обработки.
2. Добавлена возможность перехвата и ответа на веб-запросы, отправляемые элементами управления BlazorWebView и HybridWebView. Эта функция позволяет разработчикам изменять заголовки, перенаправлять запросы или предоставлять локальные ответы, обеспечивая более строгий контроль над веб-контентом и взаимодействием внутри приложений.
3. Что касается повышения производительности и стабильности, эта предварительная версия также включает многочисленные исправления и улучшения элементов управления и поведения макета. CollectionView, CarouselView и SearchBar теперь работают более стабильно на разных платформах, благодаря улучшенным функциям обновления выделения, обновления цветов плейсхолдеров и управления памятью. Утечка памяти в CarouselViewHandler2 на iOS была устранена, что повысило общую стабильность приложения. Элемент управления Switch теперь использует нативный цвет по умолчанию, когда свойство OnColor не задано (это свойство задаёт цвет переключателя при включении), обеспечивая более единообразный пользовательский интерфейс.
Источник: https://www.infoq.com/news/2025/07/dotnet-10-preview-6/
Новинки .NET 10 Превью 6. Окончание
Начало
ASP.NET Core Identity
Теперь поддерживает ключи доступа (passkey), что обеспечивает современную, устойчивую к фишингу аутентификацию с использованием стандартов WebAuthn и FIDO2.
Минимальные API
Теперь могут интегрировать ответы на ошибки валидации с помощью IProblemDetailsService, обеспечивая более согласованный и настраиваемый вывод ошибок. API валидации перемещены в новый пакет и пространство имен Microsoft.Extensions.Validation, что расширяет их применение за пределы ASP.NET Core.
MAUI
1. Улучшен элемент управления MediaPicker. Теперь разработчики могут выбирать несколько файлов и сжимать изображения непосредственно через API, используя параметры MaximumWidth и MaximumHeight. Эта функция упрощает обработку медиафайлов в приложениях, облегчая управление и обработку пользовательского контента без дополнительной обработки.
var result = await MediaPicker.PickMultipleAsync(
new MediaPickerOptions
{
MaximumWidth = 1024,
MaximumHeight = 768
});
2. Добавлена возможность перехвата и ответа на веб-запросы, отправляемые элементами управления BlazorWebView и HybridWebView. Эта функция позволяет разработчикам изменять заголовки, перенаправлять запросы или предоставлять локальные ответы, обеспечивая более строгий контроль над веб-контентом и взаимодействием внутри приложений.
webView.WebResourceRequested += (s, e) =>
{
if (e.Uri.ToString().Contains("api/secure"))
{
e.Handled = true;
e.SetResponse(200, "OK",
"application/json", GetCustomStream());
}
};
3. Что касается повышения производительности и стабильности, эта предварительная версия также включает многочисленные исправления и улучшения элементов управления и поведения макета. CollectionView, CarouselView и SearchBar теперь работают более стабильно на разных платформах, благодаря улучшенным функциям обновления выделения, обновления цветов плейсхолдеров и управления памятью. Утечка памяти в CarouselViewHandler2 на iOS была устранена, что повысило общую стабильность приложения. Элемент управления Switch теперь использует нативный цвет по умолчанию, когда свойство OnColor не задано (это свойство задаёт цвет переключателя при включении), обеспечивая более единообразный пользовательский интерфейс.
Источник: https://www.infoq.com/news/2025/07/dotnet-10-preview-6/
👍2
День 2377. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 60. Невозможно изменить всё сразу
Независимо от того, сколько болевых точек, идей по улучшению или желательных направлений вы определите, скорость восприятия изменений людьми и организациями ограничена. Люди не могут совершенствовать свою работу быстрее, чем позволяют их индивидуальные способности, поэтому инициатива крупномасштабных изменений, навязанная руководством, может ошеломить тех, кого она касается. Попытка изменить слишком многое и сразу может затруднить выполнение работы, поскольку люди будут пытаться понять новые веяния и стараться соответствовать им.
По аналогии с личностным ростом совершенствование процессов разработки ПО — это циклическое, а не прямолинейное движение. Изобразить цикл изменений можно, например, как на рисунке выше.
1. Оценка. Определите, где вы находитесь сегодня: каких результатов достигли ваши проекты в настоящее время и насколько хорошо идут дела. Определите самые проблемные области и самые большие возможности для улучшения.
2. Планирование. Решите, где вы хотели бы быть в будущем: каковы цели по улучшению. Наметьте план, как этого достичь.
3. Выполнение. Самое сложное - начать работать как-то иначе. Придётся познакомиться с практиками и методами, которые могут дать лучшие результаты, опробовать их и скорректировать под условия своей среды. Сохраняйте то, что работает, и изменяйте, заменяйте или отказывайтесь от того, что не работает.
4. Проверка. Позвольте новым методам закрепиться, а затем проверьте, дают ли они ожидаемые результаты. Чтобы изменить направление, требуются время и терпение. Затраты на обучение неизбежны. Улучшение показателей — это долгосрочный, но запаздывающий признак пригодности новых подходов для ваших проектов. Попробуйте определить промежуточные показатели, по которым можно понять, окупается ли то, что вы пытаетесь сделать.
Всегда найдётся над чем поработать. Возвращайтесь к шагу оценки в конце каждого цикла изменений, чтобы изучить новую ситуацию, а затем начинайте новый.
Приоритизация изменений
Вы можете определить больше желаемых изменений, чем могли бы внедрить, поэтому придётся расставить приоритеты, чтобы сосредоточить всю свою энергию на получении максимальной выгоды. Затем вы должны выкроить время для реализации каждого изменения. Если вы намеренно не выделяете время, то никогда не найдёте свободной минутки, не занятой другими хлопотами. Но если вы не сделаете первых шагов к изменениям, то не добьётесь прогресса. Выберите самые актуальные проблемы и начните работать над ними завтра. Да, завтра!
В какой области было бы наиболее желательно увидеть улучшения и уменьшить неприятные последствия? Какие изменения могли бы быть наиболее ценными? Какие изменения кажутся наиболее достижимыми при разумном вложении энергии и денег? Определите основные проблемные области и выберите возможные решения, которые окупятся с высокой вероятностью. Ищите плоды на нижних ветках — быстродостижимые улучшения — и празднуйте эти успехи.
Применяйте системный подход и на личном уровне. Начиная новый проект, определите 2 области, в которых хотелось бы совершенствоваться. Это может быть модульное тестирование, оценка, алгоритмизация, рецензирование, и т.п. Выделите часть времени на чтение литературы или прохождение курсов по выбранным темам и ищите возможности применить то, чему научились, понимая при этом, что потребуются некоторые усилия, чтобы выяснить, как получить наибольший эффект от изменений. Помните, что кривая обучения не является плавным и непрерывным переходом. У вас обязательно будут взлёты и падения. Но, применяя системный подход, вы доберётесь туда, куда хотите попасть.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 8.
Уроки 50 Лет Разработки ПО
Урок 60. Невозможно изменить всё сразу
Независимо от того, сколько болевых точек, идей по улучшению или желательных направлений вы определите, скорость восприятия изменений людьми и организациями ограничена. Люди не могут совершенствовать свою работу быстрее, чем позволяют их индивидуальные способности, поэтому инициатива крупномасштабных изменений, навязанная руководством, может ошеломить тех, кого она касается. Попытка изменить слишком многое и сразу может затруднить выполнение работы, поскольку люди будут пытаться понять новые веяния и стараться соответствовать им.
По аналогии с личностным ростом совершенствование процессов разработки ПО — это циклическое, а не прямолинейное движение. Изобразить цикл изменений можно, например, как на рисунке выше.
1. Оценка. Определите, где вы находитесь сегодня: каких результатов достигли ваши проекты в настоящее время и насколько хорошо идут дела. Определите самые проблемные области и самые большие возможности для улучшения.
2. Планирование. Решите, где вы хотели бы быть в будущем: каковы цели по улучшению. Наметьте план, как этого достичь.
3. Выполнение. Самое сложное - начать работать как-то иначе. Придётся познакомиться с практиками и методами, которые могут дать лучшие результаты, опробовать их и скорректировать под условия своей среды. Сохраняйте то, что работает, и изменяйте, заменяйте или отказывайтесь от того, что не работает.
4. Проверка. Позвольте новым методам закрепиться, а затем проверьте, дают ли они ожидаемые результаты. Чтобы изменить направление, требуются время и терпение. Затраты на обучение неизбежны. Улучшение показателей — это долгосрочный, но запаздывающий признак пригодности новых подходов для ваших проектов. Попробуйте определить промежуточные показатели, по которым можно понять, окупается ли то, что вы пытаетесь сделать.
Всегда найдётся над чем поработать. Возвращайтесь к шагу оценки в конце каждого цикла изменений, чтобы изучить новую ситуацию, а затем начинайте новый.
Приоритизация изменений
Вы можете определить больше желаемых изменений, чем могли бы внедрить, поэтому придётся расставить приоритеты, чтобы сосредоточить всю свою энергию на получении максимальной выгоды. Затем вы должны выкроить время для реализации каждого изменения. Если вы намеренно не выделяете время, то никогда не найдёте свободной минутки, не занятой другими хлопотами. Но если вы не сделаете первых шагов к изменениям, то не добьётесь прогресса. Выберите самые актуальные проблемы и начните работать над ними завтра. Да, завтра!
В какой области было бы наиболее желательно увидеть улучшения и уменьшить неприятные последствия? Какие изменения могли бы быть наиболее ценными? Какие изменения кажутся наиболее достижимыми при разумном вложении энергии и денег? Определите основные проблемные области и выберите возможные решения, которые окупятся с высокой вероятностью. Ищите плоды на нижних ветках — быстродостижимые улучшения — и празднуйте эти успехи.
Применяйте системный подход и на личном уровне. Начиная новый проект, определите 2 области, в которых хотелось бы совершенствоваться. Это может быть модульное тестирование, оценка, алгоритмизация, рецензирование, и т.п. Выделите часть времени на чтение литературы или прохождение курсов по выбранным темам и ищите возможности применить то, чему научились, понимая при этом, что потребуются некоторые усилия, чтобы выяснить, как получить наибольший эффект от изменений. Помните, что кривая обучения не является плавным и непрерывным переходом. У вас обязательно будут взлёты и падения. Но, применяя системный подход, вы доберётесь туда, куда хотите попасть.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 8.
👍7
День 2378. #TipsAndTricks
Используем COPY для Экспорта/Импорта Данных в Potgresql
В PostgreSQL есть функция, позволяющая эффективно выполнять массовый импорт и экспорт данных в таблицу и из неё. Обычно это гораздо более быстрый способ загрузки данных в таблицу и извлечения из неё, чем использование команд INSERT и SELECT.
В .NET провайдер Npgsql поддерживает три режима операции COPY: бинарный, текстовый и бинарный необработанный.
1. Бинарный
Пользователь использует API для чтения и записи строк и полей, которые Npgsql кодирует и декодирует. После завершения необходимо вызвать функцию Complete() для сохранения данных; в противном случае операция COPY будет откачена при освобождении объекта записи (это поведение важно в случае возникновения исключения).
2. Текстовый
В этом режиме данные в БД и из неё передаются в текстовом или CSV-формате PostgreSQL. Пользователь должен самостоятельно отформатировать текст или CSV-файл, Npgsql предоставляет только функции чтения или записи текста. Этот режим менее эффективен, чем бинарный, и подходит, если у вас уже есть данные в CSV, а производительность не критична.
3. Бинарный необработанный
Данные передаются в двоичном формате, но Npgsql не выполняет никакого кодирования или декодирования — данные предоставляются как необработанный поток .NET. Имеет смысл только для обработки больших объемов данных и восстановления таблицы: таблица сохраняется как BLOB-объект, который впоследствии можно восстановить. Если нужно разбирать данные, используйте обычный бинарный режим.
Отмена
Операции импорта можно отменить в любой момент, освободив (dispose) NpgsqlBinaryImporter до вызова метода Complete(). Операции экспорта можно отменить, вызвав метод Cancel().
Источник: https://www.npgsql.org/doc/copy.html
Используем COPY для Экспорта/Импорта Данных в Potgresql
В PostgreSQL есть функция, позволяющая эффективно выполнять массовый импорт и экспорт данных в таблицу и из неё. Обычно это гораздо более быстрый способ загрузки данных в таблицу и извлечения из неё, чем использование команд INSERT и SELECT.
В .NET провайдер Npgsql поддерживает три режима операции COPY: бинарный, текстовый и бинарный необработанный.
1. Бинарный
Пользователь использует API для чтения и записи строк и полей, которые Npgsql кодирует и декодирует. После завершения необходимо вызвать функцию Complete() для сохранения данных; в противном случае операция COPY будет откачена при освобождении объекта записи (это поведение важно в случае возникновения исключения).
// Импорт в таблицу с 2 полями (string, int)
using (var writer = conn.BeginBinaryImport(
"COPY my_table (field1, field2) FROM STDIN (FORMAT BINARY)"))
{
writer.WriteRow("Row1", 123);
writer.WriteRow("Row2", 123);
writer.Complete();
}
// Экспорт из таблицы с 2 полями
using (var rdr = conn.BeginBinaryExport(
"COPY my_table (field1, field2) TO STDOUT (FORMAT BINARY)"))
{
rdr.StartRow();
Console.WriteLine(rdr.Read<string>());
Console.WriteLine(rdr.Read<int>(NpgsqlDbType.Smallint));
rdr.StartRow();
// пропускает поле
rdr.Skip();
// проверяет на NULL (без перехода на следующее поле)
Console.WriteLine(rdr.IsNull);
Console.WriteLine(rdr.Read<int>());
rdr.StartRow();
// StartRow() вернёт -1 в конце данных
}
2. Текстовый
В этом режиме данные в БД и из неё передаются в текстовом или CSV-формате PostgreSQL. Пользователь должен самостоятельно отформатировать текст или CSV-файл, Npgsql предоставляет только функции чтения или записи текста. Этот режим менее эффективен, чем бинарный, и подходит, если у вас уже есть данные в CSV, а производительность не критична.
using (var writer = conn.BeginTextImport(
"COPY my_table (field1, field2) FROM STDIN"))
{
writer.Write("HELLO\t1\n");
writer.Write("GOODBYE\t2\n");
}
using (var reader = conn.BeginTextExport(
"COPY my_table (field1, field2) TO STDOUT"))
{
Console.WriteLine(reader.ReadLine());
Console.WriteLine(reader.ReadLine());
}
3. Бинарный необработанный
Данные передаются в двоичном формате, но Npgsql не выполняет никакого кодирования или декодирования — данные предоставляются как необработанный поток .NET. Имеет смысл только для обработки больших объемов данных и восстановления таблицы: таблица сохраняется как BLOB-объект, который впоследствии можно восстановить. Если нужно разбирать данные, используйте обычный бинарный режим.
int len;
var data = new byte[10000];
// Экспорт table1 в массив данных
using (var inStream = conn.BeginRawBinaryCopy(
"COPY table1 TO STDOUT (FORMAT BINARY)"))
{
// Предполагаем, что данные влезут в 10000 байт
// В реальности их нужно читать блоками
len = inStream.Read(data, 0, data.Length);
}
// Импорт данных в table2
using (var outStream = conn.BeginRawBinaryCopy(
"COPY table2 FROM STDIN (FORMAT BINARY)"))
{
outStream.Write(data, 0, len);
}
Отмена
Операции импорта можно отменить в любой момент, освободив (dispose) NpgsqlBinaryImporter до вызова метода Complete(). Операции экспорта можно отменить, вызвав метод Cancel().
Источник: https://www.npgsql.org/doc/copy.html
👍14