День 1946. #ЧтоНовенького
Гибридный Кэш в .NET 9
В .NET 9 Превью 4 появился новый гибридный вид кэширования.
Кэш в памяти
IMemoryCache - позволяет кэшировать объекты в памяти. Это простое хранилище пар ключ-значение:
Конечно, вы можете задать, как долго будет жить запись в кэше и прочие параметры. Важно, что кэш потеряется в случае перезапуска приложения.
Распределённый кэш
IDistributedCache - обычно используется для связи между несколькими сервисами и/или если вам необходимо сохранить данные в течение всего срока службы вашего приложения (то есть после завершения работы и перезапуска сервера). Известный пример: Redis.
Распределённый кэш не имеет такого удобного метода, как GetOrCreateAsync, поэтому вам придётся вручную пытаться извлечь значение из кэша с помощью GetAsync, а если он вернёт null, то получить значение и сохранить его в кэш.
«Паника в кэше» (cache stampede) — это тип каскадного сбоя, который может возникнуть при высокой нагрузке. Сбой возникает, если на получение значения требуется больше времени, чем время между запросами этого значения. Тогда все эти запросы не будут использовать кэш, а вызовут код получения значения. В этом случае ожидание заполнения кэша может быть лучшей стратегией, но этот код нужно писать вручную.
Гибридный кэш
HybridCache (абстрактный класс, а не интерфейс!) - представлен в превью .NET 9, но доступен (благодаря netstandard2.0) даже для .NET Framework 4.7.2 и призван заменить оба предыдущих вида:
Это очень похоже на API IMemoryCache, но «под капотом» ведёт себя как IDistrubtedCache, при этом решая проблемы паники в кэше. По умолчанию используется кэш в памяти, но при добавлении распределённого кэша в сервисы, он будет подключен к гибридному кэшу автоматически. Кроме того, он добавляет несколько новых функций, таких как создание тэгов и возможность удалить все значения в кэше по тегу или флаги, например, чтобы отключить сохранение данных в распределённом кэше.
Источник: https://steven-giesel.com/blogPost/e3ee537a-f70b-43d3-8d13-5cf81bc4406b/memorycache-distributedcache-and-hybridcache
Гибридный Кэш в .NET 9
В .NET 9 Превью 4 появился новый гибридный вид кэширования.
Кэш в памяти
IMemoryCache - позволяет кэшировать объекты в памяти. Это простое хранилище пар ключ-значение:
builder.Services.AddMemoryCache();
…
public async BlogPost GetPost(
int id, CancellationToken ct = default)
{
// Cache key
var key = $"BlogPost_{id}";
var post = await _memoryCache
.GetOrCreateAsync(key, async entry =>
{
return await _blogRepo.GetPostAsync(id, ct);
});
return post;
}
Конечно, вы можете задать, как долго будет жить запись в кэше и прочие параметры. Важно, что кэш потеряется в случае перезапуска приложения.
Распределённый кэш
IDistributedCache - обычно используется для связи между несколькими сервисами и/или если вам необходимо сохранить данные в течение всего срока службы вашего приложения (то есть после завершения работы и перезапуска сервера). Известный пример: Redis.
builder.Services
.AddStackExchangeRedisCache();
Распределённый кэш не имеет такого удобного метода, как GetOrCreateAsync, поэтому вам придётся вручную пытаться извлечь значение из кэша с помощью GetAsync, а если он вернёт null, то получить значение и сохранить его в кэш.
«Паника в кэше» (cache stampede) — это тип каскадного сбоя, который может возникнуть при высокой нагрузке. Сбой возникает, если на получение значения требуется больше времени, чем время между запросами этого значения. Тогда все эти запросы не будут использовать кэш, а вызовут код получения значения. В этом случае ожидание заполнения кэша может быть лучшей стратегией, но этот код нужно писать вручную.
Гибридный кэш
HybridCache (абстрактный класс, а не интерфейс!) - представлен в превью .NET 9, но доступен (благодаря netstandard2.0) даже для .NET Framework 4.7.2 и призван заменить оба предыдущих вида:
builder.Services.AddHybridCache();
…
public async BlogPost GetPost(
int id, CancellationToken ct = default)
{
return await cache.GetOrCreateAsync(
$"BlogPost_{id}",
async cancel =>
await _blogRepo.GetPostAsync(id, cancel),
token: ct
);
}
Это очень похоже на API IMemoryCache, но «под капотом» ведёт себя как IDistrubtedCache, при этом решая проблемы паники в кэше. По умолчанию используется кэш в памяти, но при добавлении распределённого кэша в сервисы, он будет подключен к гибридному кэшу автоматически. Кроме того, он добавляет несколько новых функций, таких как создание тэгов и возможность удалить все значения в кэше по тегу или флаги, например, чтобы отключить сохранение данных в распределённом кэше.
Источник: https://steven-giesel.com/blogPost/e3ee537a-f70b-43d3-8d13-5cf81bc4406b/memorycache-distributedcache-and-hybridcache
👍35
День 1947. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Начало
В этой серии рассмотрим, как с максимальной пользой использовать Serilog в приложениях минимальных API ASP.NET Core 8. Серия будет состоять из 3х частей.
1. Настройка
Приложения ASP.NET Core — «всего лишь» консольные приложения. Вы можете настроить Serilog и использовать его вообще без каких-либо особенностей ASP.NET Core. Для «пустого» проекта «минимального API» файл Program.cs будет выглядеть так:
Установим Serilog и консольный приёмник (sink):
В начале Program.cs создадим пайплайн логирования и назначим его статическому свойству Log.Logger:
Теперь при запуске должно появиться сообщение «Starting up» от Serilog, а затем вывод по умолчанию от ASP.NET.
Если приложение не запускается, мы хотим перехватить все возникающие исключения, а также убедиться, что все события буферизованного журнала записаны перед завершением процесса. Добавим try/catch/finally:
Здесь мы можем использовать класс Log для записи собственных структурированных событий журнала.
Возможно, сейчас у вас возникнет соблазн добавить ещё несколько приёмников для журнала. Не торопитесь, обсудим это в следующем разделе.
Продолжение следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Начало
В этой серии рассмотрим, как с максимальной пользой использовать Serilog в приложениях минимальных API ASP.NET Core 8. Серия будет состоять из 3х частей.
1. Настройка
Приложения ASP.NET Core — «всего лишь» консольные приложения. Вы можете настроить Serilog и использовать его вообще без каких-либо особенностей ASP.NET Core. Для «пустого» проекта «минимального API» файл Program.cs будет выглядеть так:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Установим Serilog и консольный приёмник (sink):
dotnet add package Serilog
dotnet add package Serilog.Sinks.Console
В начале Program.cs создадим пайплайн логирования и назначим его статическому свойству Log.Logger:
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
Log.Information("Starting up");
// … остальной код минимального API
Теперь при запуске должно появиться сообщение «Starting up» от Serilog, а затем вывод по умолчанию от ASP.NET.
Если приложение не запускается, мы хотим перехватить все возникающие исключения, а также убедиться, что все события буферизованного журнала записаны перед завершением процесса. Добавим try/catch/finally:
using Serilog;
// … пайплайн логирования
try
{
// … код минимального API
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Unhandled exception");
return 1;
}
finally
{
await Log.CloseAndFlushAsync();
}
Здесь мы можем использовать класс Log для записи собственных структурированных событий журнала.
Возможно, сейчас у вас возникнет соблазн добавить ещё несколько приёмников для журнала. Не торопитесь, обсудим это в следующем разделе.
Продолжение следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍5
День 1948. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Продолжение
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
Это очень просто. Установим Serilog.Extensions.Hosting:
И вызовем AddSerilog():
Теперь логи приложения будут писаться в Serilog.
Если вы хотите записывать события в логи, нужно настроить место назначения: путь к файлу или URL сервера логов.
Для примера используем Seq:
Добавим его в пайплайн.
Вариант 1 – в коде, используя переменные среды:
Чтобы установить контейнер Seq, работающий по адресу https://localhost:5341, выполните:
Теперь после запуска приложения, можете перейти по адресу https://localhost:5341 в браузере и увидеть логи приложения.
Этот вариант удобен, т.к. компилятор проверит, предоставлены ли все необходимые параметры, и всё, что не изменяется во время развёртывания, может быть указано в строго типизированном C#. Он также надёжно работает при публикации приложения одним файлом.
Вариант 2 — использовать Serilog.Settings.Configuration для загрузки из appsettings.json.
Конфигурация доступна не сразу, т.е. мы не сможем отслеживать исключения, возникающие на ранних этапах запуска. Совет — не усложнять себе жизнь, упростив Program.cs до чего-то вроде:
appsettings.json будет выглядеть примерно так (Seq можно заменить другим хранилищем):
Подробнее о синтаксисе конфигурации см. здесь.
Для правильной настройки конфигурации JSON может потребоваться немного больше работы, она более хрупкая и требует немного больше тестирования.
Окончание следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Продолжение
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
Это очень просто. Установим Serilog.Extensions.Hosting:
dotnet add package Serilog.Extensions.Hosting
И вызовем AddSerilog():
…
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSerilog();
…
Теперь логи приложения будут писаться в Serilog.
Если вы хотите записывать события в логи, нужно настроить место назначения: путь к файлу или URL сервера логов.
Для примера используем Seq:
dotnet add package Serilog.Sinks.Seq
Добавим его в пайплайн.
Вариант 1 – в коде, используя переменные среды:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.Seq(
Environment.GetEnvironmentVariable("SEQ_URL")
?? "https://localhost:5341",
apiKey:
Environment.GetEnvironmentVariable("SEQ_API_KEY"))
.CreateLogger();
Чтобы установить контейнер Seq, работающий по адресу https://localhost:5341, выполните:
docker run --rm -it -e ACCEPT_EULA=y -p 5341:80 datalust/seq
Теперь после запуска приложения, можете перейти по адресу https://localhost:5341 в браузере и увидеть логи приложения.
Этот вариант удобен, т.к. компилятор проверит, предоставлены ли все необходимые параметры, и всё, что не изменяется во время развёртывания, может быть указано в строго типизированном C#. Он также надёжно работает при публикации приложения одним файлом.
Вариант 2 — использовать Serilog.Settings.Configuration для загрузки из appsettings.json.
powershell
dotnet add package Serilog.Settings.Configuration
Конфигурация доступна не сразу, т.е. мы не сможем отслеживать исключения, возникающие на ранних этапах запуска. Совет — не усложнять себе жизнь, упростив Program.cs до чего-то вроде:
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSerilog(lc => lc
.WriteTo.Console()
.ReadFrom.Configuration(builder.Configuration));
var app = builder.Build();
…
appsettings.json будет выглядеть примерно так (Seq можно заменить другим хранилищем):
{
"Serilog": {
"Using": ["Serilog.Sinks.Seq"],
"WriteTo": [
{
"Name": "Seq",
"Args": {
"serverUrl": "https://localhost:5341",
"apiKey": "<API key here>"
}
}
]
},
"AllowedHosts": "*"
}
Подробнее о синтаксисе конфигурации см. здесь.
Для правильной настройки конфигурации JSON может потребоваться немного больше работы, она более хрупкая и требует немного больше тестирования.
Окончание следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍16
День 1949. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Окончание
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
3. Запись веб-запросов
Приложение записывает несколько событий в журнал при обработке каждого веб-запроса. Далее рассмотрим, как объединить эту информацию в одно красиво отформатированное событие.
Классический способ сделать это — установить Serilog.AspNetCore и добавить app.UseSerilogRequestLogging() в код запуска вашего веб-приложения сразу после builder.Build(). Но если вы настраиваете всё с нуля, в долгосрочной перспективе вы получите лучший опыт, полагаясь на встроенную поддержку активности (System.Diagnostics.Activity).
Активность - это операция с началом и концом. ASP.NET Core использует активность как обёртку вокруг каждого обрабатываемого веб-запроса. Т.к. активность завершается после выполнения всего промежуточного ПО, она даёт более точную картину продолжительности запроса и конечного кода состояния, чем может предоставить промежуточное ПО UseSerilogRequestLogging(). Также активности участвуют в распределённой трассировке, поэтому вы можете просматривать входящие и исходящие запросы вашего приложения в иерархии, если выбранный вами приёмник это поддерживает.
1) Установим SerilogTracing, поддержку форматирования вывода консоли и интеграцию с ASP.NET Core:
2) В Program.cs, добавим средство форматирования с поддержкой трассировки в приёмник консоли и снизим детализацию некоторых источников журналов Microsoft.AspNetCore.*:
Здесь мы использовали Enrich (хотя это не обязательно), чтобы добавить свойство Application ко всем событиям, поскольку это помогает отслеживать в логах операции среди нескольких сервисов.
3) Сразу после этого настроим прослушиватель, который будет записывать действия ASP.NET Core в конвейер Serilog:
SerilogTracing работает со всеми приёмниками Serilog, но на данный момент только приёмники Seq, SerilogTracing.Sinks.OpenTelemetry и SerilogTracing.Sinks.Zipkin были написаны или изменены для поддержки бэкендов с функциями иерархической трассировки.
Совет: если вы используете приемник без поддержки иерархической трассировки, добавьте
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Окончание
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
3. Запись веб-запросов
Приложение записывает несколько событий в журнал при обработке каждого веб-запроса. Далее рассмотрим, как объединить эту информацию в одно красиво отформатированное событие.
Классический способ сделать это — установить Serilog.AspNetCore и добавить app.UseSerilogRequestLogging() в код запуска вашего веб-приложения сразу после builder.Build(). Но если вы настраиваете всё с нуля, в долгосрочной перспективе вы получите лучший опыт, полагаясь на встроенную поддержку активности (System.Diagnostics.Activity).
Активность - это операция с началом и концом. ASP.NET Core использует активность как обёртку вокруг каждого обрабатываемого веб-запроса. Т.к. активность завершается после выполнения всего промежуточного ПО, она даёт более точную картину продолжительности запроса и конечного кода состояния, чем может предоставить промежуточное ПО UseSerilogRequestLogging(). Также активности участвуют в распределённой трассировке, поэтому вы можете просматривать входящие и исходящие запросы вашего приложения в иерархии, если выбранный вами приёмник это поддерживает.
1) Установим SerilogTracing, поддержку форматирования вывода консоли и интеграцию с ASP.NET Core:
dotnet add package SerilogTracing
dotnet add package SerilogTracing.Expressions
dotnet add package SerilogTracing.Instrumentation.AspNetCore
2) В Program.cs, добавим средство форматирования с поддержкой трассировки в приёмник консоли и снизим детализацию некоторых источников журналов Microsoft.AspNetCore.*:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override(
"Microsoft.AspNetCore.Hosting",
LogEventLevel.Warning)
.MinimumLevel.Override(
"Microsoft.AspNetCore.Routing",
LogEventLevel.Warning)
.Enrich.WithProperty("Application", "MyApp")
.WriteTo.Console(
Formatters.CreateConsoleTextFormatter(
theme: TemplateTheme.Code))
.WriteTo.Seq(…)
.CreateLogger();
Здесь мы использовали Enrich (хотя это не обязательно), чтобы добавить свойство Application ко всем событиям, поскольку это помогает отслеживать в логах операции среди нескольких сервисов.
3) Сразу после этого настроим прослушиватель, который будет записывать действия ASP.NET Core в конвейер Serilog:
using var listener =
new ActivityListenerConfiguration()
.Instrument.AspNetCoreRequests()
.TraceToSharedLogger();
SerilogTracing работает со всеми приёмниками Serilog, но на данный момент только приёмники Seq, SerilogTracing.Sinks.OpenTelemetry и SerilogTracing.Sinks.Zipkin были написаны или изменены для поддержки бэкендов с функциями иерархической трассировки.
Совет: если вы используете приемник без поддержки иерархической трассировки, добавьте
Enrich.WithSpanTimingMilliseconds()
, чтобы добавить свойство Elapsed для событий завершения запроса.Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍5
День 1950. #Оффтоп
.NET Rocks со Скотом Хансельманом
Олды тут? Если вдруг вам нечем заняться в первое воскресенье лета, послушайте юбилейный 1900й выпуск подкаста .NET Rocks с одним из моих любимых популяризаторов программирования вообще и .NET в частности, Скотом Хансельманом.
Три «старичка» в программировании в рамках конференции Microsoft Build весело поболтали о былых временах, о том, как быть «престарелым» (ближе к 50) программистом, идеях и истоках всех подкастов и популярности в соцсетях, а также о том, что для Скотта важно сегодня. Во второй половине Карл Фрэнклин устраивает для Скотта викторину, вспомнит ли он, что он отвечал на вопросы ведущих подкаста 20-лет назад!
И множество других замечательных историй о различных конференциях, подкастах и других мероприятиях, а также о том, чему научились в процессе.
.NET Rocks со Скотом Хансельманом
Олды тут? Если вдруг вам нечем заняться в первое воскресенье лета, послушайте юбилейный 1900й выпуск подкаста .NET Rocks с одним из моих любимых популяризаторов программирования вообще и .NET в частности, Скотом Хансельманом.
Три «старичка» в программировании в рамках конференции Microsoft Build весело поболтали о былых временах, о том, как быть «престарелым» (ближе к 50) программистом, идеях и истоках всех подкастов и популярности в соцсетях, а также о том, что для Скотта важно сегодня. Во второй половине Карл Фрэнклин устраивает для Скотта викторину, вспомнит ли он, что он отвечал на вопросы ведущих подкаста 20-лет назад!
- Скотт, почему ты позволяешь писать анонимные комментарии к статьям на своём сайте?
- Я просто не знаю, как установить OAuth.
И множество других замечательных историй о различных конференциях, подкастах и других мероприятиях, а также о том, чему научились в процессе.
.NET Rocks!
.NET Rocks! Episode 1900 with Scott Hanselman!
.NET Rocks! is a weekly talk show for anyone interested in programming on the Microsoft .NET platform. The shows range from introductory information to hardcore geekiness.
👍17
День 1951. #ЧтоНовенького
Вышел Превью Visual Studio 2022 17.11
Microsoft выпустили первый превью Visual Studio 2022 17.11. Вот некоторые новинки.
1. Пул-реквесты
Можно создавать черновики пул-реквестов и создавать описания с помощью шаблонов. Шаблон пул-реквеста по умолчанию будет использоваться при создании нового PR как для GitHub, так и для Azure DevOps. Дополнительную информацию о том, как добавить шаблон пул-реквеста в репозиторий, можно найти в документации GitHub и Azure DevOps.
2. Сочетания клавиш
Добавили
Для функции поиска инструментов (Feature Search) было добавлено сочетание клавиш
3. Отладка и профилирование
До сих пор отладка асинхронного кода, особенно в таких средах, как ASP.NET, была сложной из-за возможности возникновения исключений, переходящих через границы асинхронности. Теперь отладчик Visual Studio автоматически прерывается, когда асинхронный метод возвращает исключение в код платформы. Такой подход облегчает выявление и диагностику проблем в приложениях ASP.NET.
Профилировщик Visual Studio теперь обеспечивает автоматическую декомпиляцию библиотек .NET, когда исходный код недоступен. Декомпиляция кода во время поиска исходного кода, даже без загруженных символов или точного местоположения файлов, позволяет получить представление о структуре кода и проблемах с производительностью. Эта функция особенно полезна для анализа и оптимизации внешнего кода.
4. Файлы vsconfig
Используя файлы *.vsconfig, вы можете убедиться, что у вашей команды есть все необходимые компоненты и расширения, необходимые вашему решению. Многие команды используют файлы *.vsconfig для стандартизации установок Visual Studio. Файлы *.vsconfig можно поместить в репозиторий или каталог решения проекта, а Visual Studio теперь при открытии решения автоматически определит, присутствуют ли в установке все необходимые компоненты. Если нет, предложит их установить.
5. Пакеты NPM в обозревателе решений
Теперь вы сможете посмотреть пакеты NPM в узле Dependencies (Зависимости) в обозревателе решений в проектах JavaScript и TypeScript.
Источники:
- https://www.infoq.com/news/2024/05/vs-2022-preview-1/
- https://learn.microsoft.com/ru-ru/visualstudio/releases/2022/release-notes-preview
Вышел Превью Visual Studio 2022 17.11
Microsoft выпустили первый превью Visual Studio 2022 17.11. Вот некоторые новинки.
1. Пул-реквесты
Можно создавать черновики пул-реквестов и создавать описания с помощью шаблонов. Шаблон пул-реквеста по умолчанию будет использоваться при создании нового PR как для GitHub, так и для Azure DevOps. Дополнительную информацию о том, как добавить шаблон пул-реквеста в репозиторий, можно найти в документации GitHub и Azure DevOps.
2. Сочетания клавиш
Добавили
Ctrl+/
в качестве альтернативного сочетания клавиш для «закомментирования» строк, которое используется по умолчанию во многих других IDE и редакторах кода.Для функции поиска инструментов (Feature Search) было добавлено сочетание клавиш
Ctrl+Shift+P
, которое должно быть знакомо пользователям VS Code для открытия палитры команд.3. Отладка и профилирование
До сих пор отладка асинхронного кода, особенно в таких средах, как ASP.NET, была сложной из-за возможности возникновения исключений, переходящих через границы асинхронности. Теперь отладчик Visual Studio автоматически прерывается, когда асинхронный метод возвращает исключение в код платформы. Такой подход облегчает выявление и диагностику проблем в приложениях ASP.NET.
Профилировщик Visual Studio теперь обеспечивает автоматическую декомпиляцию библиотек .NET, когда исходный код недоступен. Декомпиляция кода во время поиска исходного кода, даже без загруженных символов или точного местоположения файлов, позволяет получить представление о структуре кода и проблемах с производительностью. Эта функция особенно полезна для анализа и оптимизации внешнего кода.
4. Файлы vsconfig
Используя файлы *.vsconfig, вы можете убедиться, что у вашей команды есть все необходимые компоненты и расширения, необходимые вашему решению. Многие команды используют файлы *.vsconfig для стандартизации установок Visual Studio. Файлы *.vsconfig можно поместить в репозиторий или каталог решения проекта, а Visual Studio теперь при открытии решения автоматически определит, присутствуют ли в установке все необходимые компоненты. Если нет, предложит их установить.
5. Пакеты NPM в обозревателе решений
Теперь вы сможете посмотреть пакеты NPM в узле Dependencies (Зависимости) в обозревателе решений в проектах JavaScript и TypeScript.
Источники:
- https://www.infoq.com/news/2024/05/vs-2022-preview-1/
- https://learn.microsoft.com/ru-ru/visualstudio/releases/2022/release-notes-preview
👍19
День 1952. #МоиИнструменты
Операции Перед Коммитом с Husky.NET. Начало
Если вам нужно выполнить операции перед коммитом в Git, вы можете положиться на перехватчики - Git-хуки (Hooks).
Git-хуки — это сценарии, которые запускаются автоматически всякий раз, когда в репозитории Git происходит определённое событие. Они позволяют настраивать внутреннее поведение Git и запускать определённые действия в ключевые моменты жизненного цикла разработки. Расширения Git-хуков позволяют вам подключать к обычному потоку Git специальные функции, такие как проверка сообщений Git, форматирование кода и т.д.
Категории Git-хуков:
1. Клиентские на коммит – выполняются при
2. Клиентские на email - выполняются при
3. Клиентские на другие операции - запускаются в локальном репозитории при операциях вроде
4. Серверные - запускаются после получения коммита в удалённом репозитории и могут отклонить операцию
Мы сосредоточимся на клиентских хуках на коммит. Они бывают 4х видов:
1. pre-commit - вызывается первым при
2. prepare-commit-msg – может использоваться для редактирования сообщения коммита по умолчанию, когда оно генерируется автоматическим инструментом.
3. commit-msg - может использоваться для проверки или изменения сообщения коммита после его ввода пользователем.
4. post-commit - вызывается после корректного выполнения коммита и обычно используется для запуска уведомлений.
Используем Husky.NET
Для Husky.NET необходимо добавить файл tool-manifest в корень решения:
Эта команда добавит файл .config/dotnet-tools.json со списком всех внешних инструментов, используемых dotnet. Теперь установим Husky:
И добавим его в приложение .NET:
Это создаст в корне решения папку .husky, содержащую файлы, которые будут использоваться для Git-хуков. Создадим хук:
Эта команда создаст файл pre-commit (без расширения) в папке .husky. На данный момент он ничего не делает, поэтому изменим его. Следующий текст хука будет компилировать код, форматировать текст (используя правила из файла .editorconfig) и выполнять тесты:
Всё готово! Хотя, погодите-ка…
Окончание следует…
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
Операции Перед Коммитом с Husky.NET. Начало
Если вам нужно выполнить операции перед коммитом в Git, вы можете положиться на перехватчики - Git-хуки (Hooks).
Git-хуки — это сценарии, которые запускаются автоматически всякий раз, когда в репозитории Git происходит определённое событие. Они позволяют настраивать внутреннее поведение Git и запускать определённые действия в ключевые моменты жизненного цикла разработки. Расширения Git-хуков позволяют вам подключать к обычному потоку Git специальные функции, такие как проверка сообщений Git, форматирование кода и т.д.
Категории Git-хуков:
1. Клиентские на коммит – выполняются при
git commit
в локальном репозитории;2. Клиентские на email - выполняются при
git am
— команды, позволяющей интегрировать почту и репозитории Git (если интересует, вот документация);3. Клиентские на другие операции - запускаются в локальном репозитории при операциях вроде
git rebase
;4. Серверные - запускаются после получения коммита в удалённом репозитории и могут отклонить операцию
git push
.Мы сосредоточимся на клиентских хуках на коммит. Они бывают 4х видов:
1. pre-commit - вызывается первым при
git commit
(если вы не используете флаг -m
, то перед запросом о добавлении сообщения) и может использоваться для проверки моментального снимка фиксируемого кода.2. prepare-commit-msg – может использоваться для редактирования сообщения коммита по умолчанию, когда оно генерируется автоматическим инструментом.
3. commit-msg - может использоваться для проверки или изменения сообщения коммита после его ввода пользователем.
4. post-commit - вызывается после корректного выполнения коммита и обычно используется для запуска уведомлений.
Используем Husky.NET
Для Husky.NET необходимо добавить файл tool-manifest в корень решения:
dotnet new tool-manifest
Эта команда добавит файл .config/dotnet-tools.json со списком всех внешних инструментов, используемых dotnet. Теперь установим Husky:
dotnet tool install Husky
И добавим его в приложение .NET:
dotnet husky install
Это создаст в корне решения папку .husky, содержащую файлы, которые будут использоваться для Git-хуков. Создадим хук:
dotnet husky add pre-commit
Эта команда создаст файл pre-commit (без расширения) в папке .husky. На данный момент он ничего не делает, поэтому изменим его. Следующий текст хука будет компилировать код, форматировать текст (используя правила из файла .editorconfig) и выполнять тесты:
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'Building code'
dotnet build
echo 'Formatting code'
dotnet format
echo 'Running tests'
dotnet test
Всё готово! Хотя, погодите-ка…
Окончание следует…
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
👍11
День 1953. #МоиИнструменты
Операции Перед Коммитом с Husky.NET. Продолжение
Начало
Управляем командой dotnet format с помощью Husky.NET
В приведённом выше примере есть проблема. Т.к. dotnet format изменяет исходные файлы, и учитывая, что моментальный снимок кода уже был создан до выполнения хука, все изменённые файлы не будут частью окончательного коммита! Также
1. Выполнить git add
Выполнение
-
-
2. Пробный прогон dotnet format
Флаг
Таким образом, если есть что форматировать, весь коммит будет отменён. Затем вам придётся запустить
Кроме того, вы не рискуете включить в снимок файлы, которые хотите сохранить в промежуточном состоянии, чтобы добавить их в последующий коммит.
3. dotnet format только для файлов коммита с помощью Husky.NET Task Runner
В папке .husky есть файл task-runner.json. Он позволяет создавать собственные сценарии с именем, группой, выполняемой командой и соответствующими параметрами. Изменим его так, чтобы
Здесь мы указали имя задачи (
или группу задач:
Теперь заменим команду
Да, сборку можно не делать отдельно, т.к. она запускается перед тестами.
И последнее. Если вы захотите сделать коммит без выполнения хука, используйте флаг
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
Операции Перед Коммитом с Husky.NET. Продолжение
Начало
Управляем командой dotnet format с помощью Husky.NET
В приведённом выше примере есть проблема. Т.к. dotnet format изменяет исходные файлы, и учитывая, что моментальный снимок кода уже был создан до выполнения хука, все изменённые файлы не будут частью окончательного коммита! Также
dotnet format
выполняет проверку каждого файла в решении, а не только тех, которые являются частью текущего снимка. Так операция может занять много времени. Есть 3 подхода к решению этой проблемы.1. Выполнить git add
Выполнение
git add .
после dotnet format
сделает все изменения частью коммита, но:-
dotnet format
всё ещё будет затрагивать все файлы;-
git add .
добавит все изменённые файлы в коммит, а не только те, которые вы хотели добавить (возможно потому что другие изменения должны были быть включены в другой коммит).2. Пробный прогон dotnet format
Флаг
--verify-no-changes
команды dotnet format
приведёт к возвращению ошибки, если хотя бы один файл необходимо обновить из-за правил форматирования.Таким образом, если есть что форматировать, весь коммит будет отменён. Затем вам придётся запустить
dotnet format
для всего решения, исправить ошибки, добавить изменения в git и попробовать сделать коммит ещё раз. Это более длительный процесс, но он позволяет вам иметь полный контроль над отформатированными файлами.Кроме того, вы не рискуете включить в снимок файлы, которые хотите сохранить в промежуточном состоянии, чтобы добавить их в последующий коммит.
3. dotnet format только для файлов коммита с помощью Husky.NET Task Runner
В папке .husky есть файл task-runner.json. Он позволяет создавать собственные сценарии с именем, группой, выполняемой командой и соответствующими параметрами. Изменим его так, чтобы
dotnet format
затрагивал только файлы, предназначенные для коммита:{
"tasks": [
{
"name": "dotnet-format-staged-files",
"group": "pre-commit-operations",
"command": "dotnet",
"args": ["format", "--include", "${staged}"],
"include": ["**/*.cs"]
}
]
}
Здесь мы указали имя задачи (
dotnet-format-staged-files
), команду для запуска (dotnet
с параметрами args
) и фильтр списка файлов, подлежащих форматированию, используя параметр ${staged}
, который заполняется Husky.NET. Мы также добавили задачу в группу pre-commit-operations
, которую мы можем использовать для задач, выполняющихся вместе. Так можно запустить отдельную задачу:dotnet husky run --name dotnet-format-staged-files
или группу задач:
dotnet husky run --group pre-commit-operations
Теперь заменим команду
dotnet format
в файле pre-commit на одну из приведённых выше, а также добавим флаги --no-restore
для сборки и теста, чтобы ускорить их выполнение:#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
echo 'Format'
dotnet husky run --name dotnet-format-staged-files
echo 'Build'
dotnet build --no-restore
echo 'Test'
dotnet test --no-restore
echo 'Completed pre-commit changes'
Да, сборку можно не делать отдельно, т.к. она запускается перед тестами.
И последнее. Если вы захотите сделать коммит без выполнения хука, используйте флаг
--no-verify
:git commit -m "my message" --no-verify
Источник: https://www.code4it.dev/blog/husky-dotnet-precommit-hooks/
👍6
День 1954. #ЗаметкиНаПолях
Создаём Мульти-Архитектурный Образ Docker для Приложения .NET
Мы переживаем переходный период, когда архитектуры x64 — не единственные доступные. Apple перешла на ARM с чипом M1, и Microsoft сейчас также продвигает ARM. Если вы хотите запускать своё приложение на архитектурах ARM64 и x64, вам необходимо создать образ Docker для каждой архитектуры. Docker поддерживает образы с несколькими архитектурами, что позволяет создавать один образ, который может работать на нескольких архитектурах.
Чтобы создать образ Docker, поддерживающий несколько архитектур, необходимо создать несколько образов для каждой архитектуры, а затем создать манифест, который будет ссылаться на все образы. Манифест будет использоваться клиентом Docker для получения правильного образа для текущей архитектуры. Вот список тегов, которые нужно создать:
- mysampleapp:1.0.0-x64 – образ для x64
- mysampleapp:1.0.0-arm64 – образ для ARM64
- mysampleapp:1.0.0 – манифест, который ссылается на образы выше.
Для создания образов можно использовать команду
Создадим новый проект:
Создадим 2 образа для x64 и ARM64:
Теперь можно объединить образы в одном манифесте и добавить манифест в реестр:
Источник: https://www.meziantou.net/create-a-multi-arch-docker-image-for-a-dotnet-application.htm
Создаём Мульти-Архитектурный Образ Docker для Приложения .NET
Мы переживаем переходный период, когда архитектуры x64 — не единственные доступные. Apple перешла на ARM с чипом M1, и Microsoft сейчас также продвигает ARM. Если вы хотите запускать своё приложение на архитектурах ARM64 и x64, вам необходимо создать образ Docker для каждой архитектуры. Docker поддерживает образы с несколькими архитектурами, что позволяет создавать один образ, который может работать на нескольких архитектурах.
Чтобы создать образ Docker, поддерживающий несколько архитектур, необходимо создать несколько образов для каждой архитектуры, а затем создать манифест, который будет ссылаться на все образы. Манифест будет использоваться клиентом Docker для получения правильного образа для текущей архитектуры. Вот список тегов, которые нужно создать:
- mysampleapp:1.0.0-x64 – образ для x64
- mysampleapp:1.0.0-arm64 – образ для ARM64
- mysampleapp:1.0.0 – манифест, который ссылается на образы выше.
Для создания образов можно использовать команду
dotnet publish
с несколькими свойствами для настройки образа. Это проще, чем создавать Dockerfile и быстрее, чем собирать образ.Создадим новый проект:
dotnet new web
Создадим 2 образа для x64 и ARM64:
powershell
$registry = "ghcr.io"
$image = "myapps/mysampleapp"
$tag = "latest"
dotnet publish -p:PublishProfile=DefaultContainer --configuration Release --os linux --arch x64 -p:ContainerImageTag=$tag-x64 -p:ContainerRepository=$image -p:ContainerRegistry=$registry
dotnet publish -p:PublishProfile=DefaultContainer --configuration Release --os linux --arch arm64 -p:ContainerImageTag=$tag-arm64 -p:ContainerRepository=$image -p:ContainerRegistry=$registry
Теперь можно объединить образы в одном манифесте и добавить манифест в реестр:
docker manifest create "$registry/${image}:$tag" "$registry/${image}:$tag-x64" "$registry/${image}:$tag-arm64"
docker manifest push "$registry/${image}:$tag"
Источник: https://www.meziantou.net/create-a-multi-arch-docker-image-for-a-dotnet-application.htm
👍12
День 1955. #Карьера
Ведите Дневник Разработчика. Начало
Разработчики погрязли в абстракциях! От проектирования системы до мельчайших деталей реализации — мы храним в голове огромное количество информации. На уровне проекта менеджер проекта, владелец продукта, тех. менеджер, бизнес аналитик (иногда все в одном лице) помогают нам понять, что делать дальше. Инструменты управления проектами, вроде Jira, отслеживают наш прогресс. Но на уровне кода легко заблудиться.
Дневник разработчика — это инструмент для отслеживания того, что вы делаете и почему. Поначалу это может показаться рутинной работой, но ведение дневника сэкономит массу времени и избавит от многих головных болей во время работы.
Зачем?
Вы напишете лучший код, если сможете сосредоточить 100% своего внимания на решении одной чётко определенной проблемы за раз, и будете расти как разработчик, анализируя, что работает для вас, а что нет. Дневник — место, где можно определить проблему, которую вы решаете, и записать, что вы пробовали и что сработало.
1. Определяем, что делать
Функция продукта может быть чётко определена, а реализация – нет. Используйте дневник, чтобы обозначить всё, что нужно для выполнения задачи, и набросать план действий.
2. Уменьшаем двусмысленность
Не пытайтесь преодолеть путаницу, написав кучу кода, это может занять часы. Потратьте пять минут на то, чтобы изложить на бумаге свои сомнения и гипотезу. Чего вы не знаете? Как это узнать? Как вы думаете, что произойдет?
3. Учимся на своём опыте
Выполнив работу, вы можете точно прочитать, что вы сделали и как вы к этому подошли, и извлечь уроки из того, что было сложно, а что удалось сделать хорошо.
4. Не отвлекаемся
Отвлекаться – естественно. Вы можете наткнуться на некачественный код и захотеть его отрефакторить, обнаружить, что работаете с той частью кодовой базы, которую не хотели трогать, а теперь нужно что-то изучить, и т.п. Постоянное переключение контекста затрудняет выполнение глубокой работы. Запишите мысли и вопросы, которые у вас возникают, в дневник, и вернётесь к ним позже.
5. Выбрасываем заботы из головы
Можно использовать дневник, чтобы отслеживать свои эмоции. «Утренние страницы» — популярный метод очистки беспорядка в голове в начале каждого дня, можно попробовать это. Нервничаете, тревожитесь, взволнованы? Запишите чувства на бумаге, чтобы очистить голову и уделить всё внимание техническим проблемам.
Продолжение следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Начало
Разработчики погрязли в абстракциях! От проектирования системы до мельчайших деталей реализации — мы храним в голове огромное количество информации. На уровне проекта менеджер проекта, владелец продукта, тех. менеджер, бизнес аналитик (иногда все в одном лице) помогают нам понять, что делать дальше. Инструменты управления проектами, вроде Jira, отслеживают наш прогресс. Но на уровне кода легко заблудиться.
Дневник разработчика — это инструмент для отслеживания того, что вы делаете и почему. Поначалу это может показаться рутинной работой, но ведение дневника сэкономит массу времени и избавит от многих головных болей во время работы.
Зачем?
Вы напишете лучший код, если сможете сосредоточить 100% своего внимания на решении одной чётко определенной проблемы за раз, и будете расти как разработчик, анализируя, что работает для вас, а что нет. Дневник — место, где можно определить проблему, которую вы решаете, и записать, что вы пробовали и что сработало.
1. Определяем, что делать
Функция продукта может быть чётко определена, а реализация – нет. Используйте дневник, чтобы обозначить всё, что нужно для выполнения задачи, и набросать план действий.
2. Уменьшаем двусмысленность
Не пытайтесь преодолеть путаницу, написав кучу кода, это может занять часы. Потратьте пять минут на то, чтобы изложить на бумаге свои сомнения и гипотезу. Чего вы не знаете? Как это узнать? Как вы думаете, что произойдет?
3. Учимся на своём опыте
Выполнив работу, вы можете точно прочитать, что вы сделали и как вы к этому подошли, и извлечь уроки из того, что было сложно, а что удалось сделать хорошо.
4. Не отвлекаемся
Отвлекаться – естественно. Вы можете наткнуться на некачественный код и захотеть его отрефакторить, обнаружить, что работаете с той частью кодовой базы, которую не хотели трогать, а теперь нужно что-то изучить, и т.п. Постоянное переключение контекста затрудняет выполнение глубокой работы. Запишите мысли и вопросы, которые у вас возникают, в дневник, и вернётесь к ним позже.
5. Выбрасываем заботы из головы
Можно использовать дневник, чтобы отслеживать свои эмоции. «Утренние страницы» — популярный метод очистки беспорядка в голове в начале каждого дня, можно попробовать это. Нервничаете, тревожитесь, взволнованы? Запишите чувства на бумаге, чтобы очистить голову и уделить всё внимание техническим проблемам.
Продолжение следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍16
День 1956. #Карьера
Ведите Дневник Разработчика. Продолжение
Начало. Зачем?
Как?
1. Настройка
Выберите место. Подойдёт любой текстовый редактор, даже редактор кода и файл markdown (только добавьте его в .gitignore). Чем проще этот этап, тем лучше. Лучше использовать рабочую машину, т.к. возможно понадобится вставлять фрагменты кода.
Дневник — ваш личный документ, в котором можно систематизировать и обработать мысли. Текст должен быть понятным и читабельным для вас. Стремитесь к формату списка дел, а не к сочинению. Не зацикливайтесь на форматировании, организации, формулировках, опечатках. Если вы можете ориентироваться в тексте – всё хорошо!
Для начала попробуйте разбивать текст по дням. Каждый день записывайте свою цель (можно разбить её на задачи) и краткое резюме. Кроме того, у вас могут быть разделы для заметок, полезные ссылки, просто мысли о будущем и т.п. Главное – дневник можно настраивать под себя.
2. Прежде чем писать код
В начале каждого рабочего сеанса (спринта, рабочего дня, сессии «помидора») определите цель сеанса, даже если она кажется очевидной. Чего достичь сегодня? Есть ли ясная и чётко определённая задача по написанию кода, которую необходимо выполнить? Нужно ли что-то изучить в кодовой базе? Нужно проверить гипотезу? Как уменьшить двусмысленность?
Иногда будет просто, иногда сложно определиться с целями, иногда будет жгучее желание побыстрей начать писать код. Если вы чувствуете дискомфорт при формулировании своих мыслей, возможно, вы недостаточно ясно представляете своё решение. Отлично! Именно поэтому вы и ведёте дневник.
3. Пока пишете код
- Застрял – запиши
Если обнаружите, что обдумываете проблему дольше минуты, запишите свои мысли в дневник. Если вы застряли в поиске бага, запишите всё, что пробовали до сих пор. Так будет легче организовать свои мысли и обратиться за помощью, если она вам понадобится.
- Разобрался - запиши
Запишите решение или логику, которая помогла решить проблему, или в чём была ошибка. Не судите себя, просто опишите как дела. Это будет полезно для определения того, что работает для вас в долгосрочной перспективе.
- Выбросьте идеи, вопросы и задачи из головы
Работая над кодом, вы естественным образом будете генерировать идеи и вопросы. В большинстве случаев не стоит прерывать работу ради них. Записывание этих задач поможет разгрузить мозг и сосредоточиться на коде. Если задача чётко определена, вы можете даже написать TODO прямо в коде. Но большинство идей не настолько детализированы, поэтому лучше записать их в дневник. Для них даже могут быть отдельные разделы «Вопросы» или «Идеи».
4. Когда закончили задачу
В конце сеанса кодирования запишите, как всё прошло. Помните, это только для вас. Будьте откровенны. Смогли ли выполнить поставленную задачу? Было ли что-то сложнее, чем вы ожидали? Вы неправильно оценили сложность задачи? Можете ли вы определить, что вас расстраивало? Хотели бы вы сделать что-нибудь по-другому, когда вернётесь к этому завтра? Где-то застряли? Сделали ли что-нибудь, чем гордитесь? Короче говоря, сделайте свою собственную ретроспективу своего дня.
Окончание следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Продолжение
Начало. Зачем?
Как?
1. Настройка
Выберите место. Подойдёт любой текстовый редактор, даже редактор кода и файл markdown (только добавьте его в .gitignore). Чем проще этот этап, тем лучше. Лучше использовать рабочую машину, т.к. возможно понадобится вставлять фрагменты кода.
Дневник — ваш личный документ, в котором можно систематизировать и обработать мысли. Текст должен быть понятным и читабельным для вас. Стремитесь к формату списка дел, а не к сочинению. Не зацикливайтесь на форматировании, организации, формулировках, опечатках. Если вы можете ориентироваться в тексте – всё хорошо!
Для начала попробуйте разбивать текст по дням. Каждый день записывайте свою цель (можно разбить её на задачи) и краткое резюме. Кроме того, у вас могут быть разделы для заметок, полезные ссылки, просто мысли о будущем и т.п. Главное – дневник можно настраивать под себя.
2. Прежде чем писать код
В начале каждого рабочего сеанса (спринта, рабочего дня, сессии «помидора») определите цель сеанса, даже если она кажется очевидной. Чего достичь сегодня? Есть ли ясная и чётко определённая задача по написанию кода, которую необходимо выполнить? Нужно ли что-то изучить в кодовой базе? Нужно проверить гипотезу? Как уменьшить двусмысленность?
Иногда будет просто, иногда сложно определиться с целями, иногда будет жгучее желание побыстрей начать писать код. Если вы чувствуете дискомфорт при формулировании своих мыслей, возможно, вы недостаточно ясно представляете своё решение. Отлично! Именно поэтому вы и ведёте дневник.
3. Пока пишете код
- Застрял – запиши
Если обнаружите, что обдумываете проблему дольше минуты, запишите свои мысли в дневник. Если вы застряли в поиске бага, запишите всё, что пробовали до сих пор. Так будет легче организовать свои мысли и обратиться за помощью, если она вам понадобится.
- Разобрался - запиши
Запишите решение или логику, которая помогла решить проблему, или в чём была ошибка. Не судите себя, просто опишите как дела. Это будет полезно для определения того, что работает для вас в долгосрочной перспективе.
- Выбросьте идеи, вопросы и задачи из головы
Работая над кодом, вы естественным образом будете генерировать идеи и вопросы. В большинстве случаев не стоит прерывать работу ради них. Записывание этих задач поможет разгрузить мозг и сосредоточиться на коде. Если задача чётко определена, вы можете даже написать TODO прямо в коде. Но большинство идей не настолько детализированы, поэтому лучше записать их в дневник. Для них даже могут быть отдельные разделы «Вопросы» или «Идеи».
4. Когда закончили задачу
В конце сеанса кодирования запишите, как всё прошло. Помните, это только для вас. Будьте откровенны. Смогли ли выполнить поставленную задачу? Было ли что-то сложнее, чем вы ожидали? Вы неправильно оценили сложность задачи? Можете ли вы определить, что вас расстраивало? Хотели бы вы сделать что-нибудь по-другому, когда вернётесь к этому завтра? Где-то застряли? Сделали ли что-нибудь, чем гордитесь? Короче говоря, сделайте свою собственную ретроспективу своего дня.
Окончание следует…
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍18
День 1957. #Карьера
Ведите Дневник Разработчика. Окончание
Начало. Зачем?
Продолжение. Как?
Ключи к успеху
1. Создаём привычку
Возьмите за привычку писать в начале и в конце каждого сеанса кодирования. Держите дневник поблизости - всегда на расстоянии одной вкладки. У вас должна быть возможность проверить свои заметки или сразу сделать дополнительные заметки. Ваш дневник становится всё более ценным, чем дольше вы его ведёте, поскольку начинают проявляться закономерности.
2. Пишем прямо
Выразите то, что думаете, словами, которые приходят на ум, как можно короче. Никто не ставит оценок, не нужно никого впечатлять красноречием.
3. Думаем о потребностях
Дневник должен включать в себя всё, что вам нужно для эффективной работы. Например, полезно озвучивать для себя свои тревоги и негативные мысли: «Не могу поверить, что уже третий день занимаюсь этой проблемой» или «Чувствую себя самозванцем». Это неприятные мысли, но, если они у вас всё равно возникают, запишите их на бумаге, чтобы сосредоточиться на работе, а не зацикливаться на размышлениях.
4. Учимся на своём опыте
В конце спринта, месяца или квартала выделите немного времени для просмотра своего дневника. Не нужно читать мелкие детали, обратите внимание на то, что вызывало трудности и что помогало их решать, и чего вы достигали каждый день.
Это полезно для:
- Понимания, какой объём работы вы способны выполнить;
- Встреч 1 на 1 с начальником;
- Помощи коллегам, чтобы помочь повысить уровень вашей команды;
- Документирования ваших достижений для будущих разговоров о карьерном росте.
Запишите выводы, полученные в результате размышлений, в том же журнале, например, в разделе «Выводы из этого спринта/проекта/квартала». Опять же, это заставит вас задуматься о том, что вы делаете. Подумайте о том, чтобы поделиться своими знаниями с командой и руководителем. Если у вас возникли проблемы с концепцией/инструментом/частью кодовой базы, скорее всего, у ваших коллег (особенно новичков) тоже.
5. Бережём внимание
Написание текста параллельно с обычной работой по программированию может показаться совершенно другой работой, но, если вы будете придерживаться этого, это станет вашей второй натурой и сэкономит вам массу времени. Гораздо лучше запутаться, описывая мысли в начале проекта, чем когда вы в середине проекта написали кучу кода в десятках файлах. Потратьте пять минут, чтобы спланировать свой день сейчас вместо того, чтобы бегать по кругу позже.
Хороший дневник разработчика должен делать три вещи:
1) Подтолкнуть к обдумыванию своих идей и планированию каждого дня, прежде чем начинать программировать.
2) Заставить более внимательно относиться к своим успехам и трудностям, чтобы вы могли повысить свой уровень.
3) Очищать ваш разум от всего, что мешает кодированию.
Попробуйте вести журнал разработки для вашего следующего проекта или спринта. Вы можете быть удивлены тем, насколько вы станете продуктивнее!
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
Ведите Дневник Разработчика. Окончание
Начало. Зачем?
Продолжение. Как?
Ключи к успеху
1. Создаём привычку
Возьмите за привычку писать в начале и в конце каждого сеанса кодирования. Держите дневник поблизости - всегда на расстоянии одной вкладки. У вас должна быть возможность проверить свои заметки или сразу сделать дополнительные заметки. Ваш дневник становится всё более ценным, чем дольше вы его ведёте, поскольку начинают проявляться закономерности.
2. Пишем прямо
Выразите то, что думаете, словами, которые приходят на ум, как можно короче. Никто не ставит оценок, не нужно никого впечатлять красноречием.
3. Думаем о потребностях
Дневник должен включать в себя всё, что вам нужно для эффективной работы. Например, полезно озвучивать для себя свои тревоги и негативные мысли: «Не могу поверить, что уже третий день занимаюсь этой проблемой» или «Чувствую себя самозванцем». Это неприятные мысли, но, если они у вас всё равно возникают, запишите их на бумаге, чтобы сосредоточиться на работе, а не зацикливаться на размышлениях.
4. Учимся на своём опыте
В конце спринта, месяца или квартала выделите немного времени для просмотра своего дневника. Не нужно читать мелкие детали, обратите внимание на то, что вызывало трудности и что помогало их решать, и чего вы достигали каждый день.
Это полезно для:
- Понимания, какой объём работы вы способны выполнить;
- Встреч 1 на 1 с начальником;
- Помощи коллегам, чтобы помочь повысить уровень вашей команды;
- Документирования ваших достижений для будущих разговоров о карьерном росте.
Запишите выводы, полученные в результате размышлений, в том же журнале, например, в разделе «Выводы из этого спринта/проекта/квартала». Опять же, это заставит вас задуматься о том, что вы делаете. Подумайте о том, чтобы поделиться своими знаниями с командой и руководителем. Если у вас возникли проблемы с концепцией/инструментом/частью кодовой базы, скорее всего, у ваших коллег (особенно новичков) тоже.
5. Бережём внимание
Написание текста параллельно с обычной работой по программированию может показаться совершенно другой работой, но, если вы будете придерживаться этого, это станет вашей второй натурой и сэкономит вам массу времени. Гораздо лучше запутаться, описывая мысли в начале проекта, чем когда вы в середине проекта написали кучу кода в десятках файлах. Потратьте пять минут, чтобы спланировать свой день сейчас вместо того, чтобы бегать по кругу позже.
Хороший дневник разработчика должен делать три вещи:
1) Подтолкнуть к обдумыванию своих идей и планированию каждого дня, прежде чем начинать программировать.
2) Заставить более внимательно относиться к своим успехам и трудностям, чтобы вы могли повысить свой уровень.
3) Очищать ваш разум от всего, что мешает кодированию.
Попробуйте вести журнал разработки для вашего следующего проекта или спринта. Вы можете быть удивлены тем, насколько вы станете продуктивнее!
Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍9
День 1958. #ЧтоНовенького #CSharp13
Типы-Расширения
Начиная с C# 3, методы расширения позволяют добавлять методы к базовому типу, даже если вы не можете изменить его код. LINQ — пример набора методов расширения IEnumerable<T>. Методы расширения LINQ выглядят так, как если бы они были методами экземпляра базового типа.
C# 13 идёт дальше, добавляя типы-расширения. Это новая разновидность типов языка, которая предоставляет элементы расширения для базового типа. Расширение включает методы, свойства и другие члены, которые могут быть как экземплярными, так и статическими. Типы-расширения экземпляра не могут хранить состояние, например, не могут включать экземплярные поля, но могут получать доступ к состоянию базового типа.
Виды
1. Неявные
Применяются ко всем экземплярам базового типа так же, как методы расширения.
2. Явные
Применяются только к экземплярам базового типа, которые были преобразованы в тип явного расширения (по аналогии с явной реализацией интерфейсов).
Пусть у нас есть базовые типы и нет доступа к изменению их кода:
Небольшой код LINQ поможет определить, является ли человек лидом. Но мы не хотим писать его каждый раз, поэтому можно написать метод расширения и контролировать доступ к нему через пространства имён. Или можно использовать неявный тип-расширение и предоставить свойство IsLead всем экземплярам Person:
Явные расширения позволяют предоставлять дополнительные возможности конкретным экземплярам типа. Например, чтобы узнать, какие команды возглавляет человек, явное расширение может предоставлять свойство Teams только лидам (через приведение экземпляра Person к типу Lead):
Как неявные, так и явные типы-расширения поддерживают и статические, и экземплярные члены. Вариант использования статических членов — предоставить значения по умолчанию, специфичные для вашего сценария. В данном случае у нас одна компания, и указывать её каждый раз при создании человека неудобно:
С точки зрения использования типы-расширения позволяют упростить код, обеспечивающий важную работу и логику приложения, настраивая конкретные экземпляры базовых объектов под ваши нужды. С технической точки зрения типы-расширения представляют собой усовершенствование методов расширения, которые вы используете сегодня.
Источник: https://devblogs.microsoft.com/dotnet/dotnet-build-2024-announcements/
Типы-Расширения
Начиная с C# 3, методы расширения позволяют добавлять методы к базовому типу, даже если вы не можете изменить его код. LINQ — пример набора методов расширения IEnumerable<T>. Методы расширения LINQ выглядят так, как если бы они были методами экземпляра базового типа.
C# 13 идёт дальше, добавляя типы-расширения. Это новая разновидность типов языка, которая предоставляет элементы расширения для базового типа. Расширение включает методы, свойства и другие члены, которые могут быть как экземплярными, так и статическими. Типы-расширения экземпляра не могут хранить состояние, например, не могут включать экземплярные поля, но могут получать доступ к состоянию базового типа.
Виды
1. Неявные
Применяются ко всем экземплярам базового типа так же, как методы расширения.
2. Явные
Применяются только к экземплярам базового типа, которые были преобразованы в тип явного расширения (по аналогии с явной реализацией интерфейсов).
Пусть у нас есть базовые типы и нет доступа к изменению их кода:
public class Person()
{
public string FirstName { get; init; }
public string LastName { get; init; }
public Company Company { get; init; }
}
public class Company()
{
public string Name { get; init; }
public List<Team> Teams { get; init; }
}
public class Team()
{
public string TeamName { get; init; }
public Person Lead { get; init; }
public IEnumerable<Person> Members { get; init; }
}
Небольшой код LINQ поможет определить, является ли человек лидом. Но мы не хотим писать его каждый раз, поэтому можно написать метод расширения и контролировать доступ к нему через пространства имён. Или можно использовать неявный тип-расширение и предоставить свойство IsLead всем экземплярам Person:
public implicit extension PersonExtension for Person
{
public bool IsLead
=> this.Company
.Teams
.Any(team => team.Lead == this);
}
// Использование
if (person.IsLead) { … }
Явные расширения позволяют предоставлять дополнительные возможности конкретным экземплярам типа. Например, чтобы узнать, какие команды возглавляет человек, явное расширение может предоставлять свойство Teams только лидам (через приведение экземпляра Person к типу Lead):
public explicit extension Lead for Person
{
public IEnumerable<Team> Teams
=> this.Company
.Teams
.Where(team => team.Lead == this);
}
Как неявные, так и явные типы-расширения поддерживают и статические, и экземплярные члены. Вариант использования статических членов — предоставить значения по умолчанию, специфичные для вашего сценария. В данном случае у нас одна компания, и указывать её каждый раз при создании человека неудобно:
public implicit extension CompanyExtension for Company
{
private static Company company
= new Company("C# Design");
public static Person CreatePerson(
string firstName, string lastName)
=> new(firstName, lastName, company);
}
// Использование
var person = Company
.CreatePerson("Jon", "Smith");
// … добавляем ещё людей и команды
if (person.IsLead)
{
Lead lead = person;
PrintReport(lead.Teams);
}
С точки зрения использования типы-расширения позволяют упростить код, обеспечивающий важную работу и логику приложения, настраивая конкретные экземпляры базовых объектов под ваши нужды. С технической точки зрения типы-расширения представляют собой усовершенствование методов расширения, которые вы используете сегодня.
Источник: https://devblogs.microsoft.com/dotnet/dotnet-build-2024-announcements/
👍24
День 1959. #ЗаметкиНаПолях
Что Такое Идемпотентность в Программных Системах? Начало
Вы часто встретите термин «идемпотентный» в ПО, особенно при разработке распределённых облачных систем. На первый взгляд эта концепция кажется простой для понимания, но важно знать тонкости идемпотентности, если вы хотите, чтобы ваши системы были масштабируемыми и надёжными.
Что это?
Возьмём для примера пульт ДУ от телевизора, который наверняка валяется у вас в гостиной. На нём обычно есть кнопки вкл./выкл., кнопки перемещения по каналам вперёд/назад и кнопки с цифрами, переключающие на конкретный канал. Так вот, независимо от того, сколько раз вы будете нажимать кнопку с цифрой канала, например, 5, вы всегда будете попадать на 5й канал (отбросим для простоты возможность включения двузначных каналов). Поэтому эта операция идемпотентна. Однако, нажатие кнопки вкл./выкл. или кнопок перемещения по каналам вверх/вниз каждый раз будет приводить к разному результату, в зависимости от текущего состояния системы, и многократное нажатие приведёт в систему в другое (неизвестное) состояние. Поэтому эта операция не идемпотентна.
Почему это важно?
Концепция идемпотентности важна в распределённых системах, поскольку трудно получить действительно надежные гарантии того, сколько раз команда будет вызываться или обрабатываться.
Сети по своей сути ненадёжны, поэтому большинство распределённых систем не могут гарантировать однократную доставку или обработку сообщений, даже при использовании брокера сообщений, вроде RabbitMQ, Azure Service Bus или Amazon SQS. Большинство брокеров предлагают доставку «хотя бы раз», полагаясь на то, что логика повторяет обработку столько раз, сколько необходимо, пока не будет подтверждено, что обработка сообщения завершена.
Это означает, что, если сообщение не может быть обработано по какой-либо причине, оно будет отправлено повторно. Допустим, у нас есть обработчик сообщений, как ТВ, описанный выше. Если сообщение однозначно, как кнопка 5, то легко написать код обработки, независимо от того, сколько раз получено сообщение. Но если это сообщение «следующий канал», ситуация усложняется. Поэтому, если каждый обработчик сообщений в нашей системе идемпотентен, мы можем повторять любое сообщение столько раз, сколько захотим, и это не повлияет на общую корректность системы.
Почему бы не сделать все обработчики идемпотентными?
Это сложно. Допустим, нужно создать нового пользователя в БД и опубликовать событие UserCreated, чтобы другие части системы знали, что произошло. Псевдокод будет примерно таким:
Теоретически - ОК, но что, если брокер сообщений не поддерживает транзакции? (Спойлер: большинство не поддерживают!) Если между этими двумя строками кода произойдет сбой, запись в базе данных будет создана, но сообщение UserCreated не будет опубликовано. При повторной отправке сообщения будет записана новая запись в БД, а затем сообщение будет опубликовано.
Эти дополнительные записи-зомби создаются в БД, большую часть времени дублируя действительные записи, без какого-либо сообщения в остальную часть системы. Это может быть трудно даже заметить, и ещё труднее потом навести порядок.
А если изменить порядок, и сначала отправлять сообщение, а потом сохранять пользователя? Теперь у нас обратная проблема. Мы создаём призрачное сообщение — объявление остальной части системы о событии, которое на самом деле не произошло. Если кто-нибудь попытается найти этого пользователя, то не найдёт, поскольку он не был создан. Но другие процессы продолжат работать на основе этого сообщения, возможно, выставляя счета, но не доставляя заказов!
При проектировании надёжной системы нужно думать, что произойдёт, если на какой-либо строке кода кто-то выдернет кабель питания сервера.
Окончание следует…
Источник: https://particular.net/blog/what-does-idempotent-mean
Что Такое Идемпотентность в Программных Системах? Начало
Вы часто встретите термин «идемпотентный» в ПО, особенно при разработке распределённых облачных систем. На первый взгляд эта концепция кажется простой для понимания, но важно знать тонкости идемпотентности, если вы хотите, чтобы ваши системы были масштабируемыми и надёжными.
Что это?
Возьмём для примера пульт ДУ от телевизора, который наверняка валяется у вас в гостиной. На нём обычно есть кнопки вкл./выкл., кнопки перемещения по каналам вперёд/назад и кнопки с цифрами, переключающие на конкретный канал. Так вот, независимо от того, сколько раз вы будете нажимать кнопку с цифрой канала, например, 5, вы всегда будете попадать на 5й канал (отбросим для простоты возможность включения двузначных каналов). Поэтому эта операция идемпотентна. Однако, нажатие кнопки вкл./выкл. или кнопок перемещения по каналам вверх/вниз каждый раз будет приводить к разному результату, в зависимости от текущего состояния системы, и многократное нажатие приведёт в систему в другое (неизвестное) состояние. Поэтому эта операция не идемпотентна.
Почему это важно?
Концепция идемпотентности важна в распределённых системах, поскольку трудно получить действительно надежные гарантии того, сколько раз команда будет вызываться или обрабатываться.
Сети по своей сути ненадёжны, поэтому большинство распределённых систем не могут гарантировать однократную доставку или обработку сообщений, даже при использовании брокера сообщений, вроде RabbitMQ, Azure Service Bus или Amazon SQS. Большинство брокеров предлагают доставку «хотя бы раз», полагаясь на то, что логика повторяет обработку столько раз, сколько необходимо, пока не будет подтверждено, что обработка сообщения завершена.
Это означает, что, если сообщение не может быть обработано по какой-либо причине, оно будет отправлено повторно. Допустим, у нас есть обработчик сообщений, как ТВ, описанный выше. Если сообщение однозначно, как кнопка 5, то легко написать код обработки, независимо от того, сколько раз получено сообщение. Но если это сообщение «следующий канал», ситуация усложняется. Поэтому, если каждый обработчик сообщений в нашей системе идемпотентен, мы можем повторять любое сообщение столько раз, сколько захотим, и это не повлияет на общую корректность системы.
Почему бы не сделать все обработчики идемпотентными?
Это сложно. Допустим, нужно создать нового пользователя в БД и опубликовать событие UserCreated, чтобы другие части системы знали, что произошло. Псевдокод будет примерно таким:
Handle(CreateUser message)
{
DB.Store(message.User);
Bus.Publish(new UserCreated());
}
Теоретически - ОК, но что, если брокер сообщений не поддерживает транзакции? (Спойлер: большинство не поддерживают!) Если между этими двумя строками кода произойдет сбой, запись в базе данных будет создана, но сообщение UserCreated не будет опубликовано. При повторной отправке сообщения будет записана новая запись в БД, а затем сообщение будет опубликовано.
Эти дополнительные записи-зомби создаются в БД, большую часть времени дублируя действительные записи, без какого-либо сообщения в остальную часть системы. Это может быть трудно даже заметить, и ещё труднее потом навести порядок.
А если изменить порядок, и сначала отправлять сообщение, а потом сохранять пользователя? Теперь у нас обратная проблема. Мы создаём призрачное сообщение — объявление остальной части системы о событии, которое на самом деле не произошло. Если кто-нибудь попытается найти этого пользователя, то не найдёт, поскольку он не был создан. Но другие процессы продолжат работать на основе этого сообщения, возможно, выставляя счета, но не доставляя заказов!
При проектировании надёжной системы нужно думать, что произойдёт, если на какой-либо строке кода кто-то выдернет кабель питания сервера.
Окончание следует…
Источник: https://particular.net/blog/what-does-idempotent-mean
👍21
День 1960. #ЗаметкиНаПолях
Что Такое Идемпотентность в Программных Системах? Окончание
Начало
Как достичь идемпотентности?
Паттерн «Исходящие» (Outbox) обеспечивает согласованность, подобную базе данных, между операциями обмена сообщениями (как получением входящего сообщения, так и отправкой исходящих сообщений) и изменениями бизнес-данных в базе. Опираясь на транзакцию БД, мы превращаем гарантию доставки «хотя бы раз» брокера сообщений в гарантию ровно одной обработки.
Для реализации паттерна Outbox логика обработки сообщений разделена на две фазы:
1. Фаза обработки сообщения
Мы не отправляем исходящие сообщения немедленно брокеру сообщений, а храним их в памяти до завершения работы обработчика сообщений. На этом этапе мы сохраняем все накопленные исходящие сообщения в таблицу БД, используя ту же транзакцию, что и для записи бизнес-данных, и Id сообщения в качестве первичного ключа.
2. Фаза отправки
Все исходящие сообщения физически отправляются брокеру сообщений. Если всё идет хорошо, исходящие сообщения отправляются, а входящие обрабатываются. Но здесь ещё возможно возникновение проблемы и отправка не всех сообщений, что вынудит нас повторить попытку. Так возникнут дублирующие сообщения, но так и задумано.
Паттерн «Исходящие» связан с паттерном «Входящие», поэтому при обработке любого повторяющегося сообщения (или повторной попытке обработки сообщения, которое не удалось выполнить на этапе отправки), сначала извлекаются данные из таблицы исходящих сообщений. Если такое сообщение существует, это означает, что оно уже успешно обработано, надо пропустить этап обработки, и перейти к этапу отправки. Если сообщение является дубликатом, и исходящие сообщения уже отправлены, то и этап отправки также можно пропустить. На псевдокоде это выглядит так:
Используя этот шаблон, мы получаем идемпотентность на стороне обработки, когда вы можете отличить дубликат, просто взглянув на id сообщения.
Итого
Идемпотентность — важный атрибут распределённых систем, но его сложно реализовать надёжно. Ошибки, возникающие в результате неправильного выполнения действий, часто легко не заметить, а затем трудно диагностировать, поскольку они кажутся результатом состояний гонки, которые невозможно воспроизвести ни в каких контролируемых условиях.
Гораздо проще использовать такую инфраструктуру, как Outbox, которая может воспользоваться транзакцией локальной базы данных, уже используемой для хранения бизнес-данных, и использовать эту транзакцию для обеспечения согласованности между операциями входящего/исходящего обмена сообщениями и бизнес-данными, хранящимися в БД.
Источник: https://particular.net/blog/what-does-idempotent-mean
Что Такое Идемпотентность в Программных Системах? Окончание
Начало
Как достичь идемпотентности?
Паттерн «Исходящие» (Outbox) обеспечивает согласованность, подобную базе данных, между операциями обмена сообщениями (как получением входящего сообщения, так и отправкой исходящих сообщений) и изменениями бизнес-данных в базе. Опираясь на транзакцию БД, мы превращаем гарантию доставки «хотя бы раз» брокера сообщений в гарантию ровно одной обработки.
Для реализации паттерна Outbox логика обработки сообщений разделена на две фазы:
1. Фаза обработки сообщения
Мы не отправляем исходящие сообщения немедленно брокеру сообщений, а храним их в памяти до завершения работы обработчика сообщений. На этом этапе мы сохраняем все накопленные исходящие сообщения в таблицу БД, используя ту же транзакцию, что и для записи бизнес-данных, и Id сообщения в качестве первичного ключа.
2. Фаза отправки
Все исходящие сообщения физически отправляются брокеру сообщений. Если всё идет хорошо, исходящие сообщения отправляются, а входящие обрабатываются. Но здесь ещё возможно возникновение проблемы и отправка не всех сообщений, что вынудит нас повторить попытку. Так возникнут дублирующие сообщения, но так и задумано.
Паттерн «Исходящие» связан с паттерном «Входящие», поэтому при обработке любого повторяющегося сообщения (или повторной попытке обработки сообщения, которое не удалось выполнить на этапе отправки), сначала извлекаются данные из таблицы исходящих сообщений. Если такое сообщение существует, это означает, что оно уже успешно обработано, надо пропустить этап обработки, и перейти к этапу отправки. Если сообщение является дубликатом, и исходящие сообщения уже отправлены, то и этап отправки также можно пропустить. На псевдокоде это выглядит так:
var message = PeekMessage();
// проверка на дубликат
var outbox = DB.GetOutboxData(message.Id);
// обработка
if(outbox == null)
{
using(var trans = DB.StartTransaction())
{
var result = ExecuteHandler(message);
outbox = new OutboxData(message.Id, result);
DB.StoreOutboxData(outbox);
trans.Commit();
}
}
// отправка
if(!outbox.IsDispatched)
{
Bus.DispatchMessage(outbox);
DB.SetAsDispatched(message.Id);
}
Используя этот шаблон, мы получаем идемпотентность на стороне обработки, когда вы можете отличить дубликат, просто взглянув на id сообщения.
Итого
Идемпотентность — важный атрибут распределённых систем, но его сложно реализовать надёжно. Ошибки, возникающие в результате неправильного выполнения действий, часто легко не заметить, а затем трудно диагностировать, поскольку они кажутся результатом состояний гонки, которые невозможно воспроизвести ни в каких контролируемых условиях.
Гораздо проще использовать такую инфраструктуру, как Outbox, которая может воспользоваться транзакцией локальной базы данных, уже используемой для хранения бизнес-данных, и использовать эту транзакцию для обеспечения согласованности между операциями входящего/исходящего обмена сообщениями и бизнес-данными, хранящимися в БД.
Источник: https://particular.net/blog/what-does-idempotent-mean
👍14👎2
День 1961. #ЗаметкиНаПолях
Ожидает ли HttpClient всё Тело Ответа?
Если вы вызываете HttpClient.GetAsync или HttpClient.PostAsync, а затем ожидаете результат, ожидается получение только заголовков или всего тела ответа?
Сервер
Создадим простой сервер, который отправляет ответ с заголовком и телом. Тело будет отправляться частями, чтобы мы могли видеть, когда оно будет получено.
Таким образом, весь запрос занимает не менее 1 секунды. Напишем простой вызов этой конечной точки.
Клиент
Если выполнить этот код, мы увидим, что время ответа составляет около 1 секунды. Таким образом, await ожидает получения всего тела:
Теперь посмотрим, как можно не ждать тела. Используем опцию HttpCompletionOption.ResponseHeadersRead:
Мы добавили флаг в вызов GetAsync. Теперь время отклика значительно меньше:
Таким образом await ожидает только получения заголовков, и вы можете исследовать их сразу, как они будут получены. Тело всё ещё принимается в фоновом режиме. Если вы хотите дождаться получения тела, можно использовать метод ReadAsStringAsync:
Важно! Мы здесь используем using var response. Объект response продолжит удерживать ресурсы после await, поэтому необходимо удалять его как можно скорее.
Итого
Использование HttpCompletionOption.ResponseHeadersRead даёт выигрыш в производительности и памяти, и вы всё равно можете прочитать тело, если захотите. Но будьте осторожны с объектом ответа, так как он может по-прежнему удерживать ресурсы, что усложняет код. Так что это не должно быть выбором по умолчанию, если в этом нет необходимости.
Источник: https://steven-giesel.com/blogPost/e2c3bcba-4f81-42b0-9b25-060da5e819fa/does-an-httpclient-await-the-header-and-the-body
Ожидает ли HttpClient всё Тело Ответа?
Если вы вызываете HttpClient.GetAsync или HttpClient.PostAsync, а затем ожидаете результат, ожидается получение только заголовков или всего тела ответа?
Сервер
Создадим простой сервер, который отправляет ответ с заголовком и телом. Тело будет отправляться частями, чтобы мы могли видеть, когда оно будет получено.
app.MapGet("/", async ctx =>
{
await ctx.Response.WriteAsync("1");
await Task.Delay(500);
await ctx.Response.WriteAsync("2");
await Task.Delay(500);
await ctx.Response.WriteAsync("3");
await ctx.Response.CompleteAsync();
});
Таким образом, весь запрос занимает не менее 1 секунды. Напишем простой вызов этой конечной точки.
Клиент
using var client = new HttpClient();
// измерим время до получения ответа
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001");
Console.WriteLine(
$"Время отклика: {sw.ElapsedMilliseconds}мс");
Если выполнить этот код, мы увидим, что время ответа составляет около 1 секунды. Таким образом, await ожидает получения всего тела:
Время отклика: 1088мс
Теперь посмотрим, как можно не ждать тела. Используем опцию HttpCompletionOption.ResponseHeadersRead:
var sw = Stopwatch.StartNew();
await client.GetAsync("https://localhost:5001",
HttpCompletionOption.ResponseHeadersRead);
Console.WriteLine(
$"Время отклика: {sw.ElapsedMilliseconds}мс");
Мы добавили флаг в вызов GetAsync. Теперь время отклика значительно меньше:
Время отклика: 78мс
Таким образом await ожидает только получения заголовков, и вы можете исследовать их сразу, как они будут получены. Тело всё ещё принимается в фоновом режиме. Если вы хотите дождаться получения тела, можно использовать метод ReadAsStringAsync:
using var response =
await client.GetAsync("https://localhost:5001",
HttpCompletionOption.ResponseHeadersRead);
var body = await response.Content.ReadAsStringAsync();
Важно! Мы здесь используем using var response. Объект response продолжит удерживать ресурсы после await, поэтому необходимо удалять его как можно скорее.
Итого
Использование HttpCompletionOption.ResponseHeadersRead даёт выигрыш в производительности и памяти, и вы всё равно можете прочитать тело, если захотите. Но будьте осторожны с объектом ответа, так как он может по-прежнему удерживать ресурсы, что усложняет код. Так что это не должно быть выбором по умолчанию, если в этом нет необходимости.
Источник: https://steven-giesel.com/blogPost/e2c3bcba-4f81-42b0-9b25-060da5e819fa/does-an-httpclient-await-the-header-and-the-body
👍38
День 1962. #УрокиРазработки
Уроки 50 Лет Разработки ПО
Урок 11. Люди не просто «собирают» требования
Когда говорят «сбор требований», можно подумать о сборе цветов или грибов. С требованиями всё не так просто. Они редко существуют в сознании пользователей в сформированном виде, готовом для передачи бизнес-аналитику. Термин «выявление требований» точнее описывает, как разработчики сотрудничают с заинтересованными сторонами, чтобы понять, как те работают, и определить, какие возможности должна предоставлять будущая программная система. Задача бизнес-аналитика во время сбора информации - задавать правильные вопросы, стимулируя обсуждение и побуждать заинтересованные стороны выходить за рамки поверхностных и очевидных решений. При этом он не просто записывает всё, что ему говорят, а выявляет детали, помогая участникам структурировать знания.
Когда выявлять требования
В Agile-проектах требования намеренно рассматриваются небольшими порциями и ожидается, что набор требований будет расширяться в процессе разработки. Команда постепенно уточняет выявленные требования до уровня детализации, необходимого разработчикам и тестировщикам.
Контекст выявления
Документ о видении и масштабах проекта устанавливает бизнес-цели проекта, сферу охвата (что явно включено) и ограничения (что явно исключается). Чтобы начать процесс выявления требований, определите заинтересованные стороны, которые могут послужить источниками информации. Спланируйте стратегию сбора информации. Выбранные методы взаимодействия будут зависеть от доступности сторон и того, какие способы обсуждения являются наиболее подходящими и сколько времени стороны могут выделить на них. Планируйте каждую встречу, чтобы гарантировать получение необходимой информации.
Методы выявления
1. Собеседования
Собеседования 1-на-1 с заинтересованными сторонами позволяют углубиться в детали, не уходя от темы, но им не хватает синергетического взаимодействия, которое часто способствует появлению новых идей в групповых дискуссиях. В любом случае бизнес-аналитик должен подготовить список исследуемых тем и вопросов, которые необходимо задать.
2. Групповые семинары
Обычно лучше подходят для изучения требований пользователей. Но любые коллективные дискуссии склонны уходить в сторону, за запланированные рамки встречи. Опытный организатор удерживает участников в теме и обеспечивает получение полезной информации.
3. Наблюдение
Наблюдение за работой пользователей в привычной обстановке позволяет получить информацию, поделиться которой им бы и не пришло в голову, отвечая не вопросы бизнес-аналитика. Можно подметить проблемы и узкие места. Наблюдать особенно полезно для дизайна UI.
4. Анализ документов
Изучение документации к существующим продуктам помогает быстро освоиться в новой прикладной области, изучить бизнес-правила, корпоративные политики и отраслевые стандарты. Но такая информация обязательно должна проверяться на актуальность.
5. Опросы
Позволяют узнать мнение о текущих продуктах у большей части пользователей. Онлайн-опросы особенно полезны, когда нет прямого доступа к представителям пользователей. Опросы должны содержать минимально возможное количество вопросов, позволяющее узнать то, что нужно, не утомляя респондента.
6. Вики
Вики и другие инструменты для совместной работы позволяют собирать информацию и идеи среди более широкого круга людей, чем семинары. Недостаток их в необходимости фильтровать обсуждение, чтобы собрать действительно ценную информацию.
7. Прототипы
Людям трудно представить, каким может быть предлагаемое решение. Прототип делает требования более осязаемыми. Даже простые эскизы UI могут помочь получить наглядное представление. Но создавать прототипы в начале исследования требований рискованно, поскольку люди могут преждевременно зациклиться на конкретном (и, возможно, неидеальном) решении.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
Уроки 50 Лет Разработки ПО
Урок 11. Люди не просто «собирают» требования
Когда говорят «сбор требований», можно подумать о сборе цветов или грибов. С требованиями всё не так просто. Они редко существуют в сознании пользователей в сформированном виде, готовом для передачи бизнес-аналитику. Термин «выявление требований» точнее описывает, как разработчики сотрудничают с заинтересованными сторонами, чтобы понять, как те работают, и определить, какие возможности должна предоставлять будущая программная система. Задача бизнес-аналитика во время сбора информации - задавать правильные вопросы, стимулируя обсуждение и побуждать заинтересованные стороны выходить за рамки поверхностных и очевидных решений. При этом он не просто записывает всё, что ему говорят, а выявляет детали, помогая участникам структурировать знания.
Когда выявлять требования
В Agile-проектах требования намеренно рассматриваются небольшими порциями и ожидается, что набор требований будет расширяться в процессе разработки. Команда постепенно уточняет выявленные требования до уровня детализации, необходимого разработчикам и тестировщикам.
Контекст выявления
Документ о видении и масштабах проекта устанавливает бизнес-цели проекта, сферу охвата (что явно включено) и ограничения (что явно исключается). Чтобы начать процесс выявления требований, определите заинтересованные стороны, которые могут послужить источниками информации. Спланируйте стратегию сбора информации. Выбранные методы взаимодействия будут зависеть от доступности сторон и того, какие способы обсуждения являются наиболее подходящими и сколько времени стороны могут выделить на них. Планируйте каждую встречу, чтобы гарантировать получение необходимой информации.
Методы выявления
1. Собеседования
Собеседования 1-на-1 с заинтересованными сторонами позволяют углубиться в детали, не уходя от темы, но им не хватает синергетического взаимодействия, которое часто способствует появлению новых идей в групповых дискуссиях. В любом случае бизнес-аналитик должен подготовить список исследуемых тем и вопросов, которые необходимо задать.
2. Групповые семинары
Обычно лучше подходят для изучения требований пользователей. Но любые коллективные дискуссии склонны уходить в сторону, за запланированные рамки встречи. Опытный организатор удерживает участников в теме и обеспечивает получение полезной информации.
3. Наблюдение
Наблюдение за работой пользователей в привычной обстановке позволяет получить информацию, поделиться которой им бы и не пришло в голову, отвечая не вопросы бизнес-аналитика. Можно подметить проблемы и узкие места. Наблюдать особенно полезно для дизайна UI.
4. Анализ документов
Изучение документации к существующим продуктам помогает быстро освоиться в новой прикладной области, изучить бизнес-правила, корпоративные политики и отраслевые стандарты. Но такая информация обязательно должна проверяться на актуальность.
5. Опросы
Позволяют узнать мнение о текущих продуктах у большей части пользователей. Онлайн-опросы особенно полезны, когда нет прямого доступа к представителям пользователей. Опросы должны содержать минимально возможное количество вопросов, позволяющее узнать то, что нужно, не утомляя респондента.
6. Вики
Вики и другие инструменты для совместной работы позволяют собирать информацию и идеи среди более широкого круга людей, чем семинары. Недостаток их в необходимости фильтровать обсуждение, чтобы собрать действительно ценную информацию.
7. Прототипы
Людям трудно представить, каким может быть предлагаемое решение. Прототип делает требования более осязаемыми. Даже простые эскизы UI могут помочь получить наглядное представление. Но создавать прототипы в начале исследования требований рискованно, поскольку люди могут преждевременно зациклиться на конкретном (и, возможно, неидеальном) решении.
Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍7👎1
День 1963. #Шпаргалка #CSS
Единицы Размеров в CSS. Начало
Поговорим немного о фронтенде. Тем более, что разобраться с UI бывает очень непросто. Многие свойства CSS принимают числа в качестве значений. Кроме того, за ними часто следуют единицы измерения. Что такое px? Чем отличаются em и rem? И как определяются итоговые размеры?
В CSS есть два типа единиц: абсолютные и относительные.
Абсолютные единицы
Каким бы ни было число, оно именно так и рассчитывается в браузере, независимо от размера других элементов. Наиболее распространённое – пиксель (px) — наименьший строительный блок для отображения графики, основанный на разрешении. На экране с высоким разрешением пиксель будет меньше, чем на экране с низким.
Абсолютные значения предсказуемы. Но, если пользователь увеличивает масштаб страницы, то всё, что определено с абсолютным значением, соответственно увеличит свой абсолютный размер.
1. Длина
-
-
-
-
-
-
-
2. Углы
Хороши, например, для направления линейного градиента (linear-gradient) или поворота (rotate) элемента.
-
-
-
-
Например,
3. Время
Тут всё просто
-
-
Например,
4. Разрешение
Количество точек на единицу измерения. Чем меньше точек, тем более «пикселизированным» и размытым будет изображение. Отлично подходит для таргетинга стилей на определенные экраны в медиа-запросах.
-
-
-
Например,
Спецификация определяет значение infinite для медиа-запросов под экраны без ограничений разрешения.
Окончание следует…
Источник: https://css-tricks.com/css-length-units/
Единицы Размеров в CSS. Начало
Поговорим немного о фронтенде. Тем более, что разобраться с UI бывает очень непросто. Многие свойства CSS принимают числа в качестве значений. Кроме того, за ними часто следуют единицы измерения. Что такое px? Чем отличаются em и rem? И как определяются итоговые размеры?
В CSS есть два типа единиц: абсолютные и относительные.
Абсолютные единицы
Каким бы ни было число, оно именно так и рассчитывается в браузере, независимо от размера других элементов. Наиболее распространённое – пиксель (px) — наименьший строительный блок для отображения графики, основанный на разрешении. На экране с высоким разрешением пиксель будет меньше, чем на экране с низким.
Абсолютные значения предсказуемы. Но, если пользователь увеличивает масштаб страницы, то всё, что определено с абсолютным значением, соответственно увеличит свой абсолютный размер.
1. Длина
-
cm
– сантиметры (96px/2.54)-
mm
– миллиметры (1/10cm)-
Q
– четверть-миллиметры (1/40cm)-
in
– дюймы (2.54cm = 96px)-
pc
– пики (1/6in)-
pt
– точки (1/72in)-
px
– пиксели (1/96in)2. Углы
Хороши, например, для направления линейного градиента (linear-gradient) или поворота (rotate) элемента.
-
deg
– градусы (полный круг – 360deg)-
grad
– грады (круг – 400grad)-
rad
– радианы (круг - 2π ~ 6.2832rad)-
turn
– повороты (круг - 1turn)Например,
rotate(180deg)
3. Время
Тут всё просто
-
s
– секунды,-
ms
- миллисекундыНапример,
animation-duration: 2s
4. Разрешение
Количество точек на единицу измерения. Чем меньше точек, тем более «пикселизированным» и размытым будет изображение. Отлично подходит для таргетинга стилей на определенные экраны в медиа-запросах.
-
dpi
– точек на дюйм-
dpcm
– точек на сантиметр-
dppx
(или x
) – точек на пиксельНапример,
@media (min-resolution: 96dpi) { … }
Спецификация определяет значение infinite для медиа-запросов под экраны без ограничений разрешения.
Окончание следует…
Источник: https://css-tricks.com/css-length-units/
👍9
День 1964. #Шпаргалка #CSS
Единицы Размеров в CSS. Окончание
Начало. Абсолютные единицы
Относительные единицы
Значение относительной единицы зависит от размера чего-то ещё. Допустим, у нас есть элемент <div> с абсолютным значением высоты 200 пикселей. Эта высота никогда не изменится. Но если задать элементу относительную ширину в 50%, он займёт половину ширины страницы (либо половину ширины своего родителя). Относительное число действует как множитель для вычисления значения, в зависимости от того, относительно какого размера мы считаем.
1. Проценты
Используются, когда нет другого контекста для задания размера.
2. Относительно шрифта
-
-
Аналогично:
-
-
-
-
-
Большинство из этого требуется только для типографии. Однако, хорошей практикой является задавать размер шрифта в пикселях для элемента <html>, а для всех остальных элементов использовать относительные em и rem:
3. Относительно области просмотра (viewport – видимая часть страницы)
Эти величины всегда считаются относительно размеров страницы.
-
-
-
-
-
-
-
-
-
4. Относительно контейнера
Эти величины считаются в контейнер-запросах относительно размеров соответствующего контейнера.
-
-
-
-
-
Например,
Когда родительский элемент блока child превысит ширину в 30 символов, он станет занимать вместо полной ширины контейнера только половину его ширины.
Источник: https://css-tricks.com/css-length-units/
Единицы Размеров в CSS. Окончание
Начало. Абсолютные единицы
Относительные единицы
Значение относительной единицы зависит от размера чего-то ещё. Допустим, у нас есть элемент <div> с абсолютным значением высоты 200 пикселей. Эта высота никогда не изменится. Но если задать элементу относительную ширину в 50%, он займёт половину ширины страницы (либо половину ширины своего родителя). Относительное число действует как множитель для вычисления значения, в зависимости от того, относительно какого размера мы считаем.
1. Проценты
%
- относительно размера родительского элемента.Используются, когда нет другого контекста для задания размера.
2. Относительно шрифта
-
em
– элемент (относительно размера шрифта родительского элемента)-
rem
– корневой элемент (относительно размера шрифта элемента <html>)Аналогично:
-
ch
и rch
– ширина символа (отличается для каждого шрифта и у разных символов, кроме моноширинных шрифтов)-
lh
и rlh
– высота строки-
cap
и rcap
– высота заглавной буквы-
ic
и ric
– ширина иероглифа-
ex
и rex
– ширина буквы X.Большинство из этого требуется только для типографии. Однако, хорошей практикой является задавать размер шрифта в пикселях для элемента <html>, а для всех остальных элементов использовать относительные em и rem:
html {
/* Наследуется всеми элементами */
font-size: 18px;
}
.parent {
/* Изменяется при смене размера в `html` */
font-size: 1.1rem;
}
.child {
/* Изменяется при смене размера в `.parent` */
font-size: 0.9em;
}
3. Относительно области просмотра (viewport – видимая часть страницы)
Эти величины всегда считаются относительно размеров страницы.
-
vh
и vw
– высота и ширина (100vh – высота экрана)-
vmin
и vmax
– минимум и максимум между vh и vw соответственно-
lvh
и lvw
– «большие» высота и ширина (в полноэкранном режиме)-
lvb
и lvi
– эквиваленты lvh и lvw для блока и строки-
svh
и svw
– «маленькие» высота и ширина (когда отображаются UI браузера и экранная клавиатура)-
svb
и svi
– эквиваленты svh и svw для блока и строки-
dvh
и dvw
– «динамические» высота и ширина (изменяются, например, при отображении/скрытии экранной клавиатуры)-
dvb
и dvi
– эквиваленты dvh и dvw для блока и строки-
dvmin
и dvmax
– минимум и максимум между dvh/dvb и dvw/dvi соответственно. 4. Относительно контейнера
Эти величины считаются в контейнер-запросах относительно размеров соответствующего контейнера.
-
cqw
– ширина контейнера (100cqw – полная ширина)-
cqh
– высота контейнера-
cqi
– ширина строкового контейнера-
cqb
– ширина блокового контейнера-
cqmin
и cqmax
– минимум или максимум между cqi и cqbНапример,
.parent {
container-type: inline-size;
}
.child {
width: 100%;
@container (width > 30ch) {
.child {
width: 50cqi;
}
}
}
Когда родительский элемент блока child превысит ширину в 30 символов, он станет занимать вместо полной ширины контейнера только половину его ширины.
Источник: https://css-tricks.com/css-length-units/
👍13