.NET Разработчик
6.56K subscribers
443 photos
4 videos
14 files
2.13K links
Дневник сертифицированного .NET разработчика. Заметки, советы, новости из мира .NET и C#.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
Какая из перегрузок метода AddNumbers будет выбрана? (см. картинку в первом комментарии)
#Quiz #CSharp
Anonymous Quiz
45%
int[]
31%
IEnumerable<int>
24%
ReadOnlySpan<int>
👍12👎1
День 1941. #Книги
«Как пасти котов. Наставление для программистов, руководящих другими программистами» (Рейнвотер Дж. — СПб.: Питер, 2022).

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

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

Если вы нацелились на роль тимлида, обязательно прочитайте, что вас ждёт и как с этим справиться.
👍25👎2
День 1942. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 10. Требования должны быть достаточно хорошими, чтобы разработка могла продолжаться с приемлемым уровнем риска

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

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

Нет явного индикатора, достаточно ли хороши требования. Бизнес-аналитику сложно судить, были ли выявлены все соответствующие требования и достаточно ли точно они изложены. Но кто-то должен решить, в какой момент требования к продукту смогут обеспечить достаточно прочную основу для его разработки. Системные архитекторы, проектировщики и разработчики могут помочь принять это решение.

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

Полноту требований можно представить в трех измерениях:
1. Типы информации
Простого набора функциональных требований или пользовательских историй недостаточно. Разработчики должны знать об источниках данных, ограничениях, бизнес-правилах, требованиях к качеству и внешнему интерфейсу.

2. Широта знаний
Объём информации, содержащейся в спецификации. В неё входят все требования пользователей или только высокоприоритетные? Учитываются все атрибуты качества или только первостепенные? Очевидно ли читателю требований, что перед ним полные или не полные требования? Если набор требований неполный, то все ли читатели увидят одни и те же пробелы? Если подразумеваемые и предполагаемые требования нигде не фиксируются, то высока вероятность, что они останутся незамеченными.

3. Глубина детализации
Учитывают ли требования возможные исключения (ошибки) и определяют ли, как система должна их обрабатывать? Если спецификация определяет нефункциональное требование, например установку, охватывает ли она также удаление, повторную установку, восстановление и установку обновлений и исправлений? Любые требования, и функциональные, и нефункциональные, должны быть достаточно полными и точными, чтобы их можно было проверить в реализованном решении.

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

Многие команды Agile-разработки ПО не оформляют все детали требований в письменном виде, но это не значит, что эти детали не нужны разработчикам и тестировщикам. Если письменная информация недоступна во время реализации, то должна быть возможность получить её из нужного источника. В противном случае члены команды должны будут сами восполнять пробелы, что может быть отмечено заказчиком как недостаток. А это будет означать, что требования не полностью готовы для реализации.

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍8
День 1943. #Оффтоп
Быть Разработчиком ПО «На Вызове» - это Нормально?
Сегодня (в выходной день для обычных людей) рассмотрим вопрос с одного из форумов Stackexchange по поводу работы дежурными «на вызове».

Вопрос:
На команду разработчиков возложили обязанности участвовать в ротации дежурных (on-call, т.е. быть доступным в нерабочее время на случай сбоев), чтобы все команды в компании были в одинаковых условиях. Понятно, что люди против того, что с них требуют дополнительную работу без дополнительной компенсации. Но кажется, что ротация дежурств довольно стандартная практика для наёмных разработчиков. Если ПО сломается в нерабочее время, кто ещё его исправит, если не разработчики?

Ответ:
Всё зависит от конкретного типа компании. Многие разработчики работают в компаниях, создающих ПО для продажи. Для разработчика из Microsoft, было бы очень необычно иметь необходимость оказывать поддержку в нерабочее время. В компании существует отдельная служба поддержки, которая принимает звонки, когда какая-то компания сталкивается с критической ошибкой в 3 часа ночи.

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

В компаниях, которым не нужна (или не оплачивается) круглосуточная безотказная работа (либо потому, что они маленькие, либо потому, что их сотрудники работают только в рабочее время). Вещи нечасто ломаются ночью, потому что никто не использует их в нерабочее время, а если что-то сломается, то нет инфраструктуры для мониторинга систем, чтобы обнаружить, когда что-то сломалось. Первый человек, пришедший на следующее утро, обнаруживает, что что-то сломалось, звонит в ИТ-отдел, и ИТ-отдел начинает работу по устранению неисправности.

Наконец, есть золотая середина: компании, которым необходимы круглосуточная работа ПО, но которые недостаточно велики, чтобы иметь крупные специализированные службы поддержки и процессы SDLC, гарантирующие, что все проекты пишут логи в одно место, и организация может эффективно контролировать среду для обнаружения систем и процессов, которые выходят из строя, и т. д. Если у вас нет команды, которая круглосуточно присматривает за системами и обнаруживает за годы работы, что «система A требует перезагрузки каждые пару часов из-за утечки памяти», или «если система B падает, то нужно сократить количество работающих серверов системы C, пока всё не восстановится», тогда да, вероятно, разработчикам различных систем придётся делать это самим. Для таких компаний среднего уровня очень характерно иметь ротацию дежурств среди разработчиков, потому что никто другой не может это делать. Разработчики, естественно, бывают недовольны, когда компании переходят от «нас не волнует, работают ли системы, пока все спят» к «нам нужно, чтобы системы работали 24 часа в сутки, 7 дней в неделю, но у нас нет бюджета на три смены администраторов, так что мы просто добавим ответственности разработчикам».

Расскажите в комментариях, как обстоят дела с этим в вашей компании? Есть ли у вас служба поддержки, ротация дедурств или вы решаете все проблемы только в рабочие часы?

Источник: https://workplace.stackexchange.com/questions/185868/are-on-call-responsibilities-for-software-developers-normal-or-unusual
👍7
День 1944. #ЗаметкиНаПолях
Мысли о Первичных Конструкторах. Начало

См. также Введение в Первичные Конструкторы в C#12.

Лучшие варианты использования
Рассмотрим случаи, для которых первичные конструкторы хорошо подходят.

1. Базовая инициализация поля
Первичные конструкторы сокращают объём кода, который вам нужно написать, и вместо этого компилятор генерирует этот код за вас:
public class Person(string firstName, string lastName)
{
private readonly string _firstName = firstName;
private readonly string _lastName = lastName;
}

Однако, даже добавление валидации уже делает код не таким очевидным:
public class Person(string firstName, string lastName)
{
private readonly string _firstName =
!string.IsNullOrEmpty(firstName)
? firstName
: throw new ArgumentException(
"Must not be null or empty", nameof(firstName));

}

Вы не можете использовать защитные методы, доступные в .NET 7+:
ArgumentException.ThrowIfNullOrEmpty(firstName);

и уже одно это делает код стандартного конструктора более сжатым и понятным. Понятно, что можно создать методы-помощники и сократить количество кода, продолжая использовать первичные конструкторы, но зачем?

2. Инициализация в тестовом коде
Возьмем простой пример теста xunit для типа Person:
public class PersonTests(ITestOutputHelper output)
{
[Theory]
[InlineData("Jon", "")]
public void Person_throws_if_null_or_empty(
string firstName, string lastName)
{
output.WriteLine(
$"Testing '{firstName}' and '{lastName}'");
Assert.Throws<ArgumentException>(() =>
new Person(firstName, lastName));
}
}

Опустим тут ценность этого теста, и нужно ли нам использовать ITestOutputHelper в методе. Здесь интересно то, что добавление ITestOutputHelper в качестве параметра первичного конструктора упрощает тестовый класс. Для теста не имеет значения, хранится ли ITestOutputHelper в поле или нет, и является ли он изменяемым.

3. Внедрение зависимостей в контроллерах MVC
В ASP.NET Core, вы, вероятно, используете внедрение зависимостей и не часто проверяете зависимости, которые внедряются в контроллеры. Это делает их хорошими кандидатами для первичных конструкторов (можно даже использовать значения напрямую):
public class MyController(
ILogger<MyController> logger,
IService service) : ControllerBase
{
[HttpGet]
public ActionResult<Thing> Get()
{
logger.LogInformation("Get the thing");
return service.GetThing();
}
}

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

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

Тем не менее, при использовании первичных конструкторов есть вещи, на которые стоит обратить внимание.

Окончание следует…

Источник:
https://andrewlock.net/thoughts-about-primary-constructors-3-pros-and-5-cons/
👍12
День 1945. #ЗаметкиНаПолях
Мысли о Первичных Конструкторах. Окончание

Начало

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

1. Повторный захват
Если вы инициализируете поле с помощью параметра первичного конструктора, а также используете его значение в другом члене класса, у вас будет два поля, хранящих одно и то же значение:
public class Person(string name)
{
private string _name = name;

public string Greeting
=> $"Hello, {name}";
}

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

2. Неявные поля не могут быть readonly
Если вы неявно захватываете параметр первичного конструктора, компилятор генерирует поле для его хранения (см. подробнее). Важно, что они изменяемы, т.е. параметру (и этому полю) можно задавать значения в теле класса. Если это то, что вам нужно, нет проблем. Но если поле не должно быть изменяемо, обычно стоит отметить его как readonly, что упрощает понимание назначения поля и устраняет целый класс ошибок, связанных со случайным изменением поля. Не удивлюсь, если это исправят в будущих версиях C#, но сейчас это немного раздражает. Решение в том, чтобы не использовать неявный захват, если вам нужны поля только для чтения.

3. Путаница в соглашениях об именах
Не большая проблема, но это придётся обсудить в команде на раннем этапе: какие соглашения следует использовать для параметров первичного конструктора? Использовать ли для параметров префикс _? Если вы используете неявный захват в коде класса, то там они будут по сути как приватные поля:
public class Person(string _firstName, string _lastName)
{
public string FullName => $"{_firstName} {_lastName}";
}

С другой стороны, создание экземпляра такого класса будет выглядеть… странно:
var p = new Person(_firstName: "Jon", _lastName: "Smith");

Microsoft рекомендует именование как параметров (без префикса). Кстати, вы не можете использовать this. в коде для обращения к параметрам первичного конструктора, такой код просто не скомпилируется.

4. Неявные поля меняют размер структур
В высокопроизводительном коде или при работе с interop иногда бывает важен размер экземпляров и как выстроено их содержимое. Если у нас есть следующая структура:
public struct Person(
string first,
string last,
int age)
{
public int Age = age;
public string FullName => $"{first} {last}";
}

То мы имеем 3 поля (1 – int и 2 – ссылки на string) для неявных полей, всего 8*3=24 байта на экземпляр. Теперь, если мы изменим первичный конструктор:
public struct Person(
string name,
int age)
{
public int Age = age;
public string FullName => name;
}

Внезапно вместо 3 полей останется 2 и размер станет 16 байт, но это без явного изменения публичных полей структуры (если вы не знаете, как реализованы первичные конструкторы). Это может иметь очень плохие последствия, если мы полагаемся на размер Person где-то в коде!

5. Путаница с записями
Всё-таки стоит помнить, что, несмотря на почти идентичный синтаксис, следующие объявления не взаимозаменяемы:
public record Person(string FirstName, string LastName);

public class Person(string FirstName, string LastName);

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

Источник: https://andrewlock.net/thoughts-about-primary-constructors-3-pros-and-5-cons/
👍16👎1
День 1946. #ЧтоНовенького
Гибридный Кэш в .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
👍36
День 1947. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных 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:
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")
?? "http://localhost:5341",
apiKey:
Environment.GetEnvironmentVariable("SEQ_API_KEY"))
.CreateLogger();

Чтобы установить контейнер Seq, работающий по адресу http://localhost:5341, выполните:
docker run --rm -it -e ACCEPT_EULA=y -p 5341:80 datalust/seq

Теперь после запуска приложения, можете перейти по адресу http://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": "http://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:
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
Какого асинхронного метода НЕ существует в Entity Framework Core?
#Quiz #EFCore
Anonymous Quiz
13%
CountAsync
4%
ToListAsync
7%
SingleAsync
30%
OrderByAsync
13%
MaxAsync
32%
ForEachAsync
👍40👎16
День 1950. #Оффтоп
.NET Rocks со Скотом Хансельманом

Олды тут? Если вдруг вам нечем заняться в первое воскресенье лета, послушайте юбилейный 1900й выпуск подкаста .NET Rocks с одним из моих любимых популяризаторов программирования вообще и .NET в частности, Скотом Хансельманом.

Три «старичка» в программировании в рамках конференции Microsoft Build весело поболтали о былых временах, о том, как быть «престарелым» (ближе к 50) программистом, идеях и истоках всех подкастов и популярности в соцсетях, а также о том, что для Скотта важно сегодня. Во второй половине Карл Фрэнклин устраивает для Скотта викторину, вспомнит ли он, что он отвечал на вопросы ведущих подкаста 20-лет назад!
- Скотт, почему ты позволяешь писать анонимные комментарии к статьям на своём сайте?
- Я просто не знаю, как установить OAuth.

И множество других замечательных историй о различных конференциях, подкастах и других мероприятиях, а также о том, чему научились в процессе.
👍18
День 1951. #ЧтоНовенького
Вышел Превью 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. Клиентские на коммит – выполняются при 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 изменяет исходные файлы, и учитывая, что моментальный снимок кода уже был создан до выполнения хука, все изменённые файлы не будут частью окончательного коммита! Также 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 – манифест, который ссылается на образы выше.

Для создания образов можно использовать команду 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/
👍17
День 1956. #Карьера
Ведите Дневник Разработчика. Продолжение

Начало. Зачем?

Как?

1. Настройка
Выберите место. Подойдёт любой текстовый редактор, даже редактор кода и файл markdown (только добавьте его в .gitignore). Чем проще этот этап, тем лучше. Лучше использовать рабочую машину, т.к. возможно понадобится вставлять фрагменты кода.
Дневник — ваш личный документ, в котором можно систематизировать и обработать мысли. Текст должен быть понятным и читабельным для вас. Стремитесь к формату списка дел, а не к сочинению. Не зацикливайтесь на форматировании, организации, формулировках, опечатках. Если вы можете ориентироваться в тексте – всё хорошо!
Для начала попробуйте разбивать текст по дням. Каждый день записывайте свою цель (можно разбить её на задачи) и краткое резюме. Кроме того, у вас могут быть разделы для заметок, полезные ссылки, просто мысли о будущем и т.п. Главное – дневник можно настраивать под себя.

2. Прежде чем писать код
В начале каждого рабочего сеанса (спринта, рабочего дня, сессии «помидора») определите цель сеанса, даже если она кажется очевидной. Чего достичь сегодня? Есть ли ясная и чётко определённая задача по написанию кода, которую необходимо выполнить? Нужно ли что-то изучить в кодовой базе? Нужно проверить гипотезу? Как уменьшить двусмысленность?
Иногда будет просто, иногда сложно определиться с целями, иногда будет жгучее желание побыстрей начать писать код. Если вы чувствуете дискомфорт при формулировании своих мыслей, возможно, вы недостаточно ясно представляете своё решение. Отлично! Именно поэтому вы и ведёте дневник.

3. Пока пишете код
- Застрял – запиши
Если обнаружите, что обдумываете проблему дольше минуты, запишите свои мысли в дневник. Если вы застряли в поиске бага, запишите всё, что пробовали до сих пор. Так будет легче организовать свои мысли и обратиться за помощью, если она вам понадобится.

- Разобрался - запиши
Запишите решение или логику, которая помогла решить проблему, или в чём была ошибка. Не судите себя, просто опишите как дела. Это будет полезно для определения того, что работает для вас в долгосрочной перспективе.

- Выбросьте идеи, вопросы и задачи из головы
Работая над кодом, вы естественным образом будете генерировать идеи и вопросы. В большинстве случаев не стоит прерывать работу ради них. Записывание этих задач поможет разгрузить мозг и сосредоточиться на коде. Если задача чётко определена, вы можете даже написать TODO прямо в коде. Но большинство идей не настолько детализированы, поэтому лучше записать их в дневник. Для них даже могут быть отдельные разделы «Вопросы» или «Идеи».

4. Когда закончили задачу
В конце сеанса кодирования запишите, как всё прошло. Помните, это только для вас. Будьте откровенны. Смогли ли выполнить поставленную задачу? Было ли что-то сложнее, чем вы ожидали? Вы неправильно оценили сложность задачи? Можете ли вы определить, что вас расстраивало? Хотели бы вы сделать что-нибудь по-другому, когда вернётесь к этому завтра? Где-то застряли? Сделали ли что-нибудь, чем гордитесь? Короче говоря, сделайте свою собственную ретроспективу своего дня.

Окончание следует…

Источник:
https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍19
День 1957. #Карьера
Ведите Дневник Разработчика. Окончание

Начало. Зачем?
Продолжение. Как?

Ключи к успеху

1. Создаём привычку
Возьмите за привычку писать в начале и в конце каждого сеанса кодирования. Держите дневник поблизости - всегда на расстоянии одной вкладки. У вас должна быть возможность проверить свои заметки или сразу сделать дополнительные заметки. Ваш дневник становится всё более ценным, чем дольше вы его ведёте, поскольку начинают проявляться закономерности.

2. Пишем прямо
Выразите то, что думаете, словами, которые приходят на ум, как можно короче. Никто не ставит оценок, не нужно никого впечатлять красноречием.

3. Думаем о потребностях
Дневник должен включать в себя всё, что вам нужно для эффективной работы. Например, полезно озвучивать для себя свои тревоги и негативные мысли: «Не могу поверить, что уже третий день занимаюсь этой проблемой» или «Чувствую себя самозванцем». Это неприятные мысли, но, если они у вас всё равно возникают, запишите их на бумаге, чтобы сосредоточиться на работе, а не зацикливаться на размышлениях.

4. Учимся на своём опыте
В конце спринта, месяца или квартала выделите немного времени для просмотра своего дневника. Не нужно читать мелкие детали, обратите внимание на то, что вызывало трудности и что помогало их решать, и чего вы достигали каждый день.
Это полезно для:
- Понимания, какой объём работы вы способны выполнить;
- Встреч 1 на 1 с начальником;
- Помощи коллегам, чтобы помочь повысить уровень вашей команды;
- Документирования ваших достижений для будущих разговоров о карьерном росте.
Запишите выводы, полученные в результате размышлений, в том же журнале, например, в разделе «Выводы из этого спринта/проекта/квартала». Опять же, это заставит вас задуматься о том, что вы делаете. Подумайте о том, чтобы поделиться своими знаниями с командой и руководителем. Если у вас возникли проблемы с концепцией/инструментом/частью кодовой базы, скорее всего, у ваших коллег (особенно новичков) тоже.

5. Бережём внимание
Написание текста параллельно с обычной работой по программированию может показаться совершенно другой работой, но, если вы будете придерживаться этого, это станет вашей второй натурой и сэкономит вам массу времени. Гораздо лучше запутаться, описывая мысли в начале проекта, чем когда вы в середине проекта написали кучу кода в десятках файлах. Потратьте пять минут, чтобы спланировать свой день сейчас вместо того, чтобы бегать по кругу позже.

Хороший дневник разработчика должен делать три вещи:
1) Подтолкнуть к обдумыванию своих идей и планированию каждого дня, прежде чем начинать программировать.
2) Заставить более внимательно относиться к своим успехам и трудностям, чтобы вы могли повысить свой уровень.
3) Очищать ваш разум от всего, что мешает кодированию.

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

Источник: https://stackoverflow.blog/2024/05/22/you-should-keep-a-developer-s-journal/
👍9