.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1134. #DDD
Коллекции и Одержимость Примитивными Типами. Окончание
Начало

Пользовательские классы коллекций
А что насчёт коллекций? Допустим, у нас есть следующий класс:
public class Customer
{
public IReadOnlyList<Order> Orders { get; }
}
Может коллекция должна быть представлена специальным классом, например:
public class Customer
{
public OrderList Orders { get; }
}

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

Рассмотрим примеры выше.
1. Коллекция сущностей

public IReadOnlyList<Order> Orders { get; }

Какие бизнес-правила могут быть реализованы в этой коллекции? Допустим, не может быть повторяющихся заказов. Требует ли это введения нового класса? Нет. Чтобы соблюсти это бизнес-правило, все новые заказы должны проходить валидацию. Но нам не нужен для этого отдельный класс, эту ответственность может взять на себя сам класс Customer.

Нам нужно, чтобы свойство Orders не могло быть изменено напрямую, а это уже сделано путем представления этого свойства как IReadOnlyList. Значит нужно изменить класс Customer, добавив метод с необходимой проверкой:
public class Customer
{
private List<Order> _orders;
public IReadOnlyList<Order> Orders => _orders;

public void AddOrder(Order order)
{
if (_orders.Contains(order))
throw new Exception();

_orders.Add(order);
}
}
В некотором роде Customer уже представляет собой пользовательский класс, инкапсулирующий коллекцию Orders.

2. Пользовательский класс коллекции
Если коллекция не принадлежит никакой другой сущности, то имеет смысл создать для неё отдельный класс. Например, если вам нужно отслеживать всех пользователей, которые в данный момент находятся в сети, лучше всего представить их в виде пользовательского класса:
public class OnlineUsers
{
private List<User> _users;
public void ForceLogOff(long userId)
{
// …
}
}

Здесь подразумевается, что, помимо собственно коллекции, необходимы некоторые дополнительные функции (например, описанный выше метод ForceLogOff), в противном случае класс OnlineUsers не нужен.

Итого
Одержимость примитивными типами — это использование примитивных типов для моделирования предметной области.
Вам может понадобиться или не понадобиться отдельный класс для коллекции. Если коллекция представляет собой набор связанных сущностей, присоединённых к родительской сущности, то эта родительская сущность фактически действует как пользовательский класс. Отдельный класс для самой коллекции не нужен.
Если же коллекция является коллекцией корневого уровня, то для неё нужен пользовательский класс (при условии, что помимо самой коллекции необходимы дополнительные функции).

Источник: https://enterprisecraftsmanship.com/posts/collections-primitive-obsession/
👍14
День 1135. #ЗаметкиНаПолях
Избегаем Проблем с DNS в HttpClient
HttpClient позволяет отправлять HTTP-запросы. Подразумевается, что он создаётся однократно и повторно используется на протяжении всего жизненного цикла приложения. HttpClient имеет пул для повторного использования соединений. Если вы отправите несколько запросов на один и тот же хост, они будут повторно использовать одно и то же соединение. Таким образом, приложение экономит доступные ему сокеты. Кроме того, это повышает производительность приложения, избегая рукопожатий TCP и TLS для каждого запроса к одному и тому же хосту.

Сохранение соединений открытыми - хорошо с точки зрения производительности, но вы должны быть осторожны, чтобы не хранить устаревшие соединения. Если срок жизни DNS истёк, хост может изменить свой IP-адрес. В этом случае открытые соединения должны быть закрыты. HttpClient не делает этого автоматически, поскольку ему ничего не известно о сроке жизни DNS.

Когда происходит изменение DNS?
- При сине-зелёном развёртывании (в Azure, когда вы выполняете развёртывание в промежуточном слоте, а затем переключаете рабочий/промежуточный слоты).
- При изменении настроек в диспетчере трафика Azure.
- В случае отказа основного сервера и перехода на бекап и т.п.

Чтобы исправить эту проблему, вы можете указать время ожидания для автоматического закрытия соединения. SocketsHttpHandler используется для настройки поведения HttpClient и его пула соединений. Необходимо настроить 2 свойства:
- PooledConnectionIdleTimeout,
- PooledConnectionLifetime.
Эти свойства заставляют HttpClient закрыть соединение через определённое время. Таким образом, следующий запрос к тому же хосту должен будет открыть новое соединение и использовать новый DNS или другие изменения в сети.

По умолчанию простаивающие соединения закрываются через 1 минуту. Однако активные соединения никогда не закрываются. Вы должны явно установить для PooledConnectionLifetime желаемое значение.
using System.Threading;
using System.Net.Http;

using var handler = new SocketsHttpHandler()
{
// Максимальное время простоя соединения в пуле. Если в течение этого времени нет запросов, соединение разрывается. По умолчанию: 1 минута
PooledConnectionIdleTimeout =
TimeSpan.FromMinutes(1),

// Максимальное время жизни соединения в пуле, независимо от активности. Периодически соединение пересоздаётся для обновления DNS или других сетевых изменений. По умолчанию: никогда.
PooledConnectionLifetime =
TimeSpan.FromMinutes(1)
};

using var client = new HttpClient(handler);

var timer = new PeriodicTimer(
TimeSpan.FromSeconds(10));

while (await timer.WaitForNextTickAsync())
{
_ = await client
.GetStringAsync("https://www.google.com");
}

Замечание: Другой способ избежать проблем с изменённым DNS – использовать IHttpClientFactory:
services
.AddHttpClient<IMyService, MyService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(1));

Источник: https://www.meziantou.net/avoid-dns-issues-with-httpclient-in-dotnet.htm
👍6
День 1136. #ЗаметкиНаПолях #AsyncTips
Модульное тестирование async-методов

Задача:
Имеется async-метод, для которого необходимо провести модульное тестирование.

Решение
Многие современные фреймворки модульного тестирования, включая MSTest, NUnit и xUnit, поддерживают методы модульного тестирования async Task. Пример асинхронного модульного теста в MSTest:
[TestMethod]
public async Task MethodAsync_False()
{
var sut = …;
var result = await sut.iss.onethodAsync();
Assert.IsFalse(result);
}

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

Если ваш фреймворк модульного тестирования не поддерживает модульные тесты с async Task, то ему придётся помочь с ожиданием тестируемой асинхронной операции. Один из вариантов — использовать GetAwaiter().GetResult() для синхронного блокирования по задаче. Использование GetAwaiter().GetResult() вместо Wait() позволит избежать обёртки в AggregateException, когда в задаче произойдёт исключение.

Имитация (mocking) асинхронных зависимостей на первый взгляд кажется немного неуклюжей. Всегда желательно хотя бы проверить, как ваши методы реагируют на синхронный успех (имитация с Task.FromResult), синхронные ошибки (имитация с Task.FromException) и асинхронный успех (имитация с Task.Yield и возвратом значения). Task.FromResult и Task.FromException рассматривались здесь. Task.Yield может использоваться для принудительного применения асинхронного поведения и задействуется прежде всего при модульном тестировании:
interface IMyInterface
{
Task<int> SomeAsync();
}
class SyncSuccess : IMyInterface
{
public Task<int> SomeAsync()
{
return Task.FromResult(42);
}
}

class SyncError : IMyInterface
{
public Task<int> SomeAsync()
{
return Task.FromException<int>(
new InvalidOperationException());
}
}

class AsyncSuccess : IMyInterface
{
public async Task<int> SomeAsync()
{
// Принудительно включаем асинхронное поведение
await Task.Yield();
return 42;
}
}

При тестировании асинхронного кода взаимоблокировки и состояния гонки могут проявляться чаще, чем при тестировании синхронного кода. Может быть полезным назначение тайм-аута тестам. Тестовому методу можно задать атрибут Timeout(int timeOut), передав ему количество миллисекунд таймаута. Значение по умолчанию - TestTimeout.Infinite ("бесконечно").

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 7.
👍8
День 1137.
Развёртывайте Чаще
Если вы ещё не практикуете непрерывное развёртывание, скорее всего, ваша команда и компания выиграют от более частых развёртываний.

Развёртывание (deploy) ПО — это процесс переноса его из среды разработки в производственную (или другую) среду. Развёртывание не то же самое, что выпуск (release). В идеале вы должны иметь возможность часто развёртывать ПО, выпуская новые функции для клиентов только тогда, когда это целесообразно с точки зрения бизнеса.

Считаете ли вы развёртывание стрессовым, болезненным и требующим от членов команды внеурочной работы? Что, если бы вы могли избавиться от этого, развёртывая ПО в любое время, но выпуская его только тогда, когда это удобно для вашей команды и/или пользователей?

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

Клиенты, с которыми я работал, развёртывали ПО нерегулярно, примерно раз в 6-8 недель по решению руководства. Поскольку их клиенты приходили в офис к 8 утра, команда должна была начать развёртывание в 3 часа ночи. Процесс почти никогда не проходил по плану: хотя первоначальное развёртывание занимало всего 10-15 минут, остальное время уходило на тестирование, исправление ошибок и повторное развёртывание, чтобы система заработала к 8 утра. А иногда приходилось откатываться и планировать развёртывание на другой день.

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

Для моих клиентов сначала мы собрали метрики о периодичности развёртываний и их успешности. Успешным считалось развёртывание, которое не пришлось откатывать или немедленно исправлять ошибки в нём. Оказалось, что развёртывания, которые выполнялись спустя неделю после предыдущего, почти никогда не были успешными. Тогда как те, что выполнялись спустя день, в большинстве случаев не требовали исправлений.

«Если больно, делай это чаще».

Мы решили выполнять развёртывание чаще. Команде предложение не понравилось. Дни развертывания никому не нравились. Это были дни сильного стресса, бессонницы, которые мешали работе и личной жизни людей. А их просили делать это чаще.

Однако, мы выяснили, что развёртывания после длинного перерыва были высоким стрессом и полной неопределенностью, тогда как те, что выполнялись сразу после, проходили гораздо легче. Это понятно, ведь изменений было немного. Так почему бы не продолжать в том же духе?

Команда решила проводить развёртывания по вторникам и четвергам. Они планировали выполнить 50 развёртываний в год вместо 10, как было раньше. Однако им удалось сделать 100 и более 90% из них были успешными. Больше никому не приходилось выполнять стрессовое развёртывание в 3 часа ночи.

Итого
Процесс доставки ПО является важной частью успеха вашей команды (и компании). Существует множество причин, по которым вы должны предоставлять функционал клиентам раньше и чаще. Проблемы, которые непропорционально возрастают с размером развёртывания, можно контролировать. Стоимость тестирования и исправления ошибок растёт со временем не линейно, а экспоненциально, поэтому, чаще развёртывая, вы сокращаете время, в течение которого могут возникнуть большие проблемы. А с мелкими, которые успевают возникнуть, справиться гораздо легче.

Источник: https://ardalis.com/deploy-more-often/
Автор оригинала: Steve “Ardalis” Smith
👍9
День 1138. #юмор
Думаю, что у всех так было.
Бесит или норм?
👍3
День 1139. #ЗаметкиНаПолях
Выполнение Кода Перед Main
Вообще, я не любитель подобных извращений. Но чисто ради лулзов иногда интересно узнать, что так можно.

Согласно документации, «Метод Main — это точка входа в приложение C#. При запуске приложения метод Main вызывается первым.» На самом деле метод Main может быть не первым методом сборки, который будет выполняться при запуске приложения. Существуют различные методы, которые могут выполняться перед методом Main.

1. Статический конструктор
Статический конструктор используется для инициализации любых статических данных или для выполнения определённого действия, которое необходимо выполнить только один раз. Он вызывается автоматически перед созданием первого экземпляра или обращением к любым статическим элементам. Поэтому статический конструктор вызовется перед методом Main.
class Program
{
static Program() =>
Console.WriteLine("Program.cctor");
static void Main() =>
Console.WriteLine("Hello, World!");
}

2. Инициализаторы модулей
Инициализаторы модулей позволяют библиотекам выполнять однократную инициализацию при загрузке без необходимости явного вызова пользователем чего-либо. Когда среда выполнения загружает модуль (DLL), она вызывает методы инициализации модуля перед выполнением любого кода из этого модуля.
using System.Runtime.CompilerServices;
class Initializer
{
// Статический конструктор выполняется
// перед инициализаторами модуля
static Initializer()
=> Console.WriteLine("Init.cctor");

[ModuleInitializer]
public static void Initialize1() =>
Console.WriteLine("Module Init 1");

[ModuleInitializer]
public static void Initialize2() =>
Console.WriteLine("Module Init 2");
}

3. Стартап хуки
Переменная среды DOTNET_STARTUP_HOOKS может использоваться для указания списка управляемых сборок, содержащих тип StartupHook с публичным статическим методом Initialize():
class StartupHook
{
static StartupHook() =>
Console.WriteLine("StartupHook.cctor");

// Запустите приложение с переменной среды
// DOTNET_STARTUP_HOOKS=<полный путь к сборке с этим классом>
public static void Initialize() =>
Console.WriteLine("Startup hook");
}

Каждый из этих методов будет вызываться в указанном порядке перед точкой входа Main:
Init.cctor
Module Init 1
Module Init 2
StartupHook.cctor
Startup hook
program.cctor
Hello, World!

Источник: https://www.meziantou.net/executing-code-before-main-in-dotnet.htm
👍9
День 1140. #CodeReview
Про обзоры кода на канале было уже много постов. Найти их можно по тегу в заголовке. А сегодня, пока ютуб окончательно не заблокировали, порекомендую вам очередное видео от Дейва Пламера «The Secret Society of Code Reviewers at Microsoft»

В видео он рассказывает о том, зачем нужны обзоры кода, как они проходили в Майкрософт на заре систем контроля версий, 5 советов, как проводить обзоры кода, и 5 советов, чего не надо делать при обзорах кода.

PS: из-за скорости речи и некоторого акцента автора, понять его иногда довольно трудно. Можете поставить скорость 0,75 и включить субтитры.
👍5
День 1141. #ЗаметкиНаПолях
Совместное Использование Кода Между
ASP.NET и ASP.NET Core
Перенос существующего кода в ASP.NET Core часто кажется серьёзным шагом. Однако уже сегодня можно внести небольшие изменения, которые упростят переход на ASP.NET Core завтра.

Первым шагом является создание нового проекта ASP.NET Core Web App (Model-View-Controller). Этот шаблон добавит поддержку контроллеров и сопоставит маршрут по умолчанию для контроллеров в файле Program.cs. После этого можно удалить созданные по умолчанию контроллер HomeController и представления Home/Index и Home/Privacy.

Контроллеры
Многие команды хотят, чтобы новый веб-сайт работал так же, как текущий. Если вы исправляете ошибку в проекте, важно, чтобы это исправление отображалось на обоих сайтах. Один из самых простых способов обеспечить это — предоставить общий доступ к одному и тому же файлу в обоих проектах. К счастью, ASP.NET Core использует новые файлы проектов в стиле SDK. Это означает, что файл csproj легко открыть и внести некоторые изменения. Нужно создать <ItemGroup> и добавить ссылку на существующий класс:
<ItemGroup>
<Compile
Include="..HomeController.cs"
LinkBase="Controllers" />
</ItemGroup>

Теперь проект ASP.NET Core больше не компилируется. В ASP.NET Core класс Controller использует не System.Web.Mvc, а Microsoft.AspNetCore.Mvc. Это можно исправить с помощью директив препроцессора:
#if NET
using Microsoft.AspNetCore.Mvc;
#else
using System.Web.Mvc;
#endif
Аналогичный код можно добавить и в других нужных местах, чтобы заставить оба проекта компилироваться. Кроме того, можно создать частичные классы и выделить крупные блоки кода в новые методы, различающиеся в разных проектах, а затем, используя csproj, включать в проект только нужные файлы.

Модели
Для этого подойдут те же советы, что и при совместном использовании контроллеров. Также директивы препроцессора можно использовать для атрибутов:
#if !NET
[Bind(Exclude="Id")]
#endif
public partial class Order
{
[ScaffoldColumn(false)]
#if NET
[BindNever]
#endif
public int Id { get; set; }


Представления
Опять же можно использовать csproj для совместного использования файлов, таких как _Layout.cshtml. Внутри представления вы можете продолжать использовать директивы препроцессора:
@{
#if NET
<text>
@await
Component.InvokeAsync("CartSummary")
</text>
#else
@Html.RenderAction(
"CartSummary",
"ShoppingCart");
#endif
}

Аналогично можно совместно использовать статический контент (CSS, JavaScript и изображения). Также обновите все NuGet-пакеты и ваши собственные библиотеки под использование netstandard, чтобы они могли совместно использоваться в обоих проектах.

Пошаговые инструкции по переносу на примере проекта MvcMusicStore приведены здесь. Там также описано, как можно запускать ASP.NET и ASP.NET Core из одного и того же пула приложений IIS для постепенной миграции вашего веб-приложения по одному контроллеру за раз.

Источник: https://devblogs.microsoft.com/dotnet/sharing-code-between-aspnet-and-aspnetcore/
👍5
День 1142.
25 Лет Visual Studio
Сегодня исполняется 25 лет с выпуска Visual Studio в 1997 году, и такая важная веха заслуживает надлежащего празднования. Празднование 25-й годовщины Visual Studio начнётся сегодня, 17 марта, в 19:00 по Москве. Обещают эксклюзивный контент и захватывающие новости, знакомые лица из прошлого и настоящего Visual Studio, которые расскажут закулисные истории и забавные факты, накопившиеся за 25 лет истории.

Также Microsoft призывает всех поделиться своей историей использования Visual Studio в социальных сетях, используя хэштег #MyVSStory.

Источник: https://devblogs.microsoft.com/visualstudio/happy-25th-birthday-visual-studio/
👍6
День 1143. #юмор
10x-Инженеры
Рекрутеры, менеджеры и основатели стартапов, если вы когда-нибудь столкнётесь с этой редкой породой инженеров, хватайте их. Если у вас есть 10x-инженер в команде, вы значительно увеличиваете шансы на успех вашего проекта. А теперь сложный вопрос. Как распознать 10x-инженера?

1. 10x-инженеры ненавидят собрания. Они считают, что это пустая трата времени и обсуждаются очевидные вещи. Они посещают эти собрания только потому, что менеджер их позвал.

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

3. Цвет фона экрана 10x-инженера обычно черный (они всегда меняют цвет по умолчанию). Буквы i, j, x на их клавиатуре обычно больше изношены.

4. Большинство 10x-инженеров — фулл-стеки. Для них код есть код, им всё равно, это клиентская часть, серверная часть, API, база данных или бессерверная функция.

5. 10x-инженеры могут преобразовать «мысль» в «код» в уме и написать его итеративно. Имея характеристику продукта, они могут написать весь код по ней за один или два сеанса по 4-6 часов, не отвлекаясь, питаясь напитком с кофеином.

6. 10x-инженеры редко смотрят в документацию. Они знают всё наизусть и всегда могут вспомнить нужный класс или метод. Они пишут код так же легко, как обычный текст. Без перерывов, без пауз, просто печатают. У некоторых 10x-инженеров 11 пальцев для дополнительной производительности при наборе текста.

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

8. 10x-инженеры — плохие наставники. Они не могут научить других что-то делать или делегировать работу, т.к всегда думают, что «обучение или обсуждение с другими занимает слишком много времени, я лучше сделаю это сам». Они также плохие интервьюеры.

9. 10x-инженеры не придумывают костыли. Они пишут качественный код и точно знают, как этот код должен развиваться, и имеют ментальную модель общей структуры кода. Они пишут максимум один проектный документ, а остальное очевидно из кода.

10. 10x-инженеры знают, что великие инженеры на самом деле 8x, иногда 16x, а не 10x.

11. 10x-инженеры знают каждую строчку выпущенного кода. Если QA или сотрудники службы поддержки сообщают о проблеме, они точно знают, где находится ошибка, и могут исправить её в кратчайшее время. Лучшие 10x-инженеры смогут сказать вам строку и позицию ошибки в вашем коде, просто слушая шум процессора, когда он выполняет код.

12. 10x-инженеры редко ищут работу или уходят из компании. Они уходят, только потому что вы делаете их жизнь невыносимой из-за правил, собраний, обучения и других действий, не добавляющих ценности. Если вы встретите их, держитесь за них, любите их.

Источник: https://twitter.com/skirani/status/1149302828420067328
👍19
День 1144. #ЗаметкиНаПолях #AsyncTips
Неизменяемые стеки и очереди

Задача
Вам нужна коллекция — стек или очередь, которая изменяется не очень часто и к которой можно безопасно обращаться из нескольких потоков. Например, очередь для представления последовательности выполняемых операций, а стек — для представления последовательности операций отмены.

Решение
Неизменяемые стеки и очереди из пространства имён System.Collections.Immutable по поведению очень близки к стандартным коллекциям Stack<T> и Queue<T> и обладают практически такой же временной сложностью. Впрочем, в простых сценариях с частым обновлением стандартные стеки и очереди работают быстрее.

Неизменяемый стек
var stack = ImmutableStack<int>.Empty;
stack = stack.Push(13);
stack = stack.Push(7);

// Выводит "7", затем "13".
foreach (int item in stack)
Console.WriteLine(item);

stack = stack.Pop(out int last);
// last == 7

В этом примере многократно перезаписывается локальная переменная stack. Неизменяемые коллекции возвращают обновлённую коллекцию, а ссылка на исходную остаётся без изменений. Это означает, что, если имеется ссылка на экземпляр неизменяемой коллекции, она никогда не изменится:
var stack = ImmutableStack<int>.Empty;
stack = stack.Push(13);
var biggerStack = stack.Push(7);

// Выводит "7", затем "13".
foreach (int item in biggerStack)
Console.WriteLine(item);

// Выводит только "13".
foreach (int item in stack)
Console.WriteLine(item);

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

Неизменяемая очередь
var queue = ImmutableQueue<int>.Empty;
queue = queue.Enqueue(13);
queue = queue.Enqueue(7);
// Выводит "13", затем "7".
foreach (int item in queue)
Console.WriteLine(item);

queue = queue.Dequeue(out int next);
// Выводит "13".
Console.WriteLine(next);

Вот некоторые важные принципы проектирования, справедливые для всех неизменяемых коллекций:
- Экземпляр неизменяемой коллекции никогда не изменяется.
- Экземпляр неизменяемой коллекции потокобезопасен по своей природе, но ссылка на него потокобезопасной не является. Переменная, ссылающаяся на неизменяемую коллекцию, нуждается в такой же синхронизационной защите, как и любая другая переменная.
- При вызове изменяющего метода для неизменяемой коллекции возвращается новая измененная коллекция.

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

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

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 9.
👍7
День 1145. #ЗаметкиНаПолях
Использование Встроенных Файлов в dotnet core
Мы хотим прочитать файл JSON с диска. Мы не хотим полагаться на абсолютные пути к файлам, параметрам среды, копировать файлы в выходной каталог и т.п. Файл JSON выглядит следующим образом:
file.json
{
"data": true
}

Можно использовать функцию EmbeddedResource. Тогда при сборке проекта файл json будет включён в dll. Чтобы пометить файл как EmbeddedResource, вы просто добавляете его в свой .csproj следующим образом:
<ItemGroup>
<EmbeddedResource Include="Data\file.json" />
</ItemGroup>

Теперь посмотрим, как можно прочитать этот файл. При работе со встроенными файлами нам понадобится сборка, в которой мы будем искать встроенные ресурсы. Рассмотрим следующий интерфейс, содержащий методы для чтения встроенных ресурсов тремя различными способами
public interface IEmbeddedResourceQuery
{
// изнутри сборки
Stream? Read<T>(string resource);
// из заданной сборки
Stream? Read(Assembly a, string resource);
// из сборки по имени сборки
Stream? Read(string name, string resource);
}

Для получения потока для чтения ресурса можно использовать метод GetManifestResourceStream сборки. Ещё одна важная деталь — это то, как строится путь для чтения ресурса. Нам нужно указать имя сборки (MyLibrary), а затем использовать запись пути через точку:
Assembly_name.Folder.Filename
Например, для файла file.json в папке Data путь будет:
MyLibrary.Data.file.json

public class EmbeddedResourceQuery
: IEmbeddedResourceQuery
{
public Stream? Read<T>(string resource)
{
var a = typeof(T).Assembly;
return ReadInternal(a, resource);
}

public Stream? Read(
Assembly a, string resource)
{
return ReadInternal(a, resource);
}

public Stream? Read(
string name, string resource)
{
var a = Assembly.Load(name);
return ReadInternal(a, resource);
}

internal static Stream? ReadInternal(
Assembly a, string resource)
{
return assembly
.GetManifestResourceStream(
$"{a.GetName().Name}.{resource}");
}
}

Использование
var q = new EmbeddedResourceQuery();

// изнутри сборки
var s1 = q.Read<MyType>("Data.file.json ");

// из заданной сборки
var a = Assembly.Load("MyLibrary");
var s2 = q.Read(a, "Data.file.json ");

// из сборки по имени сборки
var s3 = q.Read("MyLibrary", "Data.file.json");

Источник: https://josef.codes/using-embedded-files-in-dotnet-core/
👍11
День 1146.
Улучшаем Производительность Сборки в Visual Studio. Начало
Время — ваш самый ценный актив, и медленная сборка занимает первое место в списке убийц продуктивности разработчиков. При медленной сборке теряется не только время на саму сборку, но часто и вы сами отвлекаетесь на другие задачи, такие как проверка почты, кофе, социальные сети… Таким образом, борьба за сокращение времени сборки имеет важное значение.

Измерение
Прежде чем улучшать, нужно сначала измерить. Расширение Visual Studio Build Timer отображает статистику и водопадную диаграмму вашей сборки в Visual Studio. Инструмент доступен в меню View > Other Windows > Build Timer (Вид > Другие окна > Таймер сборки) и позволяет увидеть, какие проекты собираются дольше, а какие быстрее, какие проекты ждут сборки других и т.п.

Фильтры решений
Обычно мы обычно работаем только с несколькими проектами из решения. Поэтому можно вручную выгружать ненужные проекты, чтобы добиться более быстрой компиляции. Процесс выгрузки набора проектов можно значительно улучшить, определив файл фильтра решения (.slnf). Чтобы его создать, просто выгрузите несколько проектов, щёлкните правой кнопкой мыши на решении и выберите в меню Save as Solution Filter (Сохранить как фильтр решения).

VS рассматривает файлы фильтров решений (.slnf) как файлы решений (.sln). Файл фильтра представляет собой текстовый файл, который можно легко редактировать. Загрузка фильтра решения загружает целевые проекты и полностью игнорирует другие: они даже не отображаются как выгруженные. Выгрузка/загрузка проектов в открытом фильтре вызывает подсказку, предлагающую обновить фильтр.

Имейте в виду, что у выгрузки проектов есть и обратная сторона: изменения, сделанные в публичных API ваших проектов не будут отражены в выгруженных клиентских проектах.

Инкрементная сборка
В контексте VS MSBuild проверяет актуальность выходных данных проекта, чтобы определить, нужно ли его компилировать. Эта функция называется Incremental Build и необходима для значительного сокращения количества компилирующихся проектов для ускорения сборки.

Основные причины неактуальности проекта:
- Один из файлов, используемых в качестве входных данных проекта (исходный файл, файл ресурсов…), имеет более новую временную метку, чем временная метка выходного файла проекта (.dll, .pdb, .xml…).
- Проект зависит как минимум от одного устаревшего проекта.

Инкрементальные проверки сборки не могут быть идеальными, особенно когда используются некоторые нетривиальные функции. Например, если в одном из файлов проекта для свойства Copy to Output Directory (Копировать в выходной каталог) установлено значение Copy Always (Копировать всегда), проект никогда не будет считаться актуальным. Такая причина не очевидна. Чтобы это обнаружить перейдите в Options > Projects and Solutions > SDK-Style Projects (Параметры > Проекты и решения > Проекты SDK) измените для параметра Logging Level значение с None на Minimal. Теперь в окне Output при сборке можно заметить строку:
1>FastUpToDate: Item … has CopyToOutputDirectory set to 'Always', not up to date.

Это поможет понять, что заставляет проект перекомпилироваться каждый раз. Чтобы избавиться от этого, просто установите Copy to Output Directory на Copy if Newer (Копировать, если новее).

Чтобы узнать, есть ли у вашего решения такая проблема: сначала выполните Build > Rebuild Solution, а затем Build > Build Solution. Если какие-то проекты перекомпилируются второй раз, исследуйте проблему.

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

Источник:
https://blog.ndepend.com/improve-visual-studio-build-performance/
👍10
День 1147.
Улучшаем Производительность Сборки в Visual Studio. Окончание
Начало

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

2. В окне Options > Projects and Solutions > Build and Run (Параметры > Проекты и решения > Сборка и запуск):
- Убедитесь, что вы используете параллельные сборки.
- Убедитесь, что отмечен флажок Only Build Startup and Dependencies on Run (Собирать только стартовый проект и зависимости при запуске).

3. По умолчанию Visual Studio компилирует каждый проект в отдельный каталог .\bin\Debug и копирует туда все сборки, на которые ссылается проект. Это было настоящим убийцей производительности сборки в старых версиях VS. Надеюсь, это было исправлено. Тем не менее, если на проект P ссылаются N других проектов, существует N+1 файлов сборки P. Мало того, что это трата ресурсов, но также может быть, что версии станут рассинхронизированы, например, из-за того, что некоторые проекты были выгружены в обозревателе решений. Это может привести к неожиданному поведению во время выполнения, например к возникновению MissingMethodException. Поэтому лучше установить, чтобы все проекты решения (кроме тестовых) использовали один и тот же выходной каталог ..\bin\Debug. Таким образом, каждая сборка будет существовать в единственной версии.

Горячая перезагрузка
Благодаря новой функции горячей перезагрузки .NET (ранее известной как Edit and Continue) цикл [написание кода — сборка — запуск — достижение состояния для тестирования — тестирование] сокращается, т.к. шаги [сборка — запуск — достижение состояния для тестирования] могут быть пропущены в многих сценариях редактирования (но не всегда).

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

Большую часть времени модификации исходного кода между двумя сборками представляют собой крошечную часть пересобираемого кода. Можно ожидать, что в будущем конвейер сборки сможет повысить производительность инкрементной сборки за счет внедрения модификаций кода в двоичный файл вместо пересборки всего файла. Но уже в Visual Studio 2022 можно включить горячую перезагрузку, чтобы ускорить выполнение тестов, пропуская дорогостоящие этапы сборки для поддерживаемых типов изменений. Обратите внимание, что эта функция все ещё является экспериментальной и работает только для .NET 6.

Источник: https://blog.ndepend.com/improve-visual-studio-build-performance/
👍2
День 1148.
Как Настроить Git для Улучшения Процесса Разработки
git config — мощная команда. Также вы можете использовать файл конфигурации. Он существует на уровне проекта, где инициализируется Git (/project/.git/config), или в корне (~/.gitconfig). Если конфигурация не указана, Git использует настройки по умолчанию. Рассмотрим некоторые полезные настройки, которые могут улучшить ваш процесс разработки.

1. Выбор редактора по умолчанию
Git по умолчанию открывает редактор vi. Он может быть сложен в использовании. Однако вы можете использовать предпочитаемый вами редактор для написания коммитов. В файл .gitconfig добавьте:
[core]
editor = code --wait
либо используйте команду:
git config --global core.editor "code --wait"

Это откроет редактор VSCode. Настройки для других редакторов можно посмотреть здесь.

2. prune при fetch
Если вы удалили ветку, например, после слияния её с основной, команда prune удалит устаревшие ссылки на удалённые ветки в вашем каталоге .git. Для этого вы можете выполнить
git fetch –prune

Либо задать это поведение по умолчанию в настройках. В файле конфигурации:
[fetch]
prune = true
либо командой:
git config --global fetch.prune true

3. Git-псевдонимы
В файле конфигурации Git вы можете добавить псевдонимы для тех длинных команд, которыми вы постоянно пользуетесь: commit, stash и т.п.
Допустим, вы хотите добавить псевдоним для добавления пустого коммита. В файле конфигурации:
[alias]
empty = git commit --allow-empty
либо командой:
git config --global alias.empty "git commit --allow-empty"

Теперь вы можете использовать такую команду:
git empty "Empty commit"

В псевдонимах вы можете использовать не только команды Git, но и любые другие команды терминала. Git просто выполнит всё, что указано в команде. Для этого добавьте ! в начало команды:
this = !git init && git add . && git commit -m \"Initial commit.\"

Теперь git this инициализирует репозиторий в папке, добавит все файлы под контроль git и выполнит первый коммит.

4. Ветка по умолчанию
При инициализации репозитория (git init) веткой по умолчанию является main (или master). Не обязательно использовать это имя. В файле конфигурации Git вы можете установить ветку по умолчанию при инициализации:
[init]
defaultBranch = default

Источник: https://www.freecodecamp.org/news/git-config-how-to-configure-git-settings/
👍5
День 1149. #Карьера
Чем Больше Ты Знаешь, Тем Больше Знаешь, Что Не Знаешь
На изображении ниже вы можете увидеть, как рост опыта влияет на уверенность. Первоначально ваша уверенность низка, так как вы знаете, что вы неопытны. Однако через некоторое время вы начинаете «что-то понимать» и попадаете в зону комфорта. В зависимости от того, насколько требовательна ваша среда, вы можете оставаться там в течение очень долгого времени, но, если вас подталкивают вперёд, вы, скорее всего, быстро упадёте в «долину отчаяния», когда поймёте, что есть гораздо больше того, чего вы не умеете делать или ещё не освоили. С этой точки, как правило, ваша уверенность растёт по мере увеличения вашего опыта. Это известно как эффект Даннинга-Крюгера.

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

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

Можно расширить это представление, применив известную цитату Дональда Рамсфельда о «неизвестных неизвестных». Чем больше у вас опыта, тем больше вещей вы знаете. Также становится больше вещей, о которых вы знаете, что вы их не знаете. Но, кроме этого, есть множество вещей, о которых вы не знаете, что не знаете их. И несмотря ни на что, всегда будет большое (возможно, бесконечное) количество «неизвестных неизвестных».

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

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

Источник: https://ardalis.com/the-more-you-know-the-more-you-realize-you-dont-know/
👍9
День 1150. #Оффтоп
Сегодня будет полнейший оффтоп. На него меня вдохновил очередной твит одного из коллег программистов. Вопрос в нём был следующий:

Какая область (кроме ИТ) вдохновляет вас больше всего?

Это не обязательно может быть ваше личное хобби, может просто что-то, что вам интересно изучать или узнавать новости.

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

Вот несколько каналов, которые я смотрю.
Mentour Pilot
Практикующий лётчик рассказывает об устройстве самолётов, аэропортов, о том, как составляется расписание, как работают пилоты, а также разбирает некоторые самые известные авиапроисшествия на основе официальных отчётов.

74 Gear
Канал второго пилота Боинга-747. Тематика похожая, но более неформальная. Он разбирает вирусные видео на тему авиации, смешные переговоры пилотов с диспетчерами, а также рассказывает байки из своей (и не только своей) практики.

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

ИЛЬДАР АВТО-ПОДБОР
Ребята рассказывают, как ремонтируют, подбирают, а иногда дарят машины в рамках благотворительного проекта. Интересно, грамотно, с юмором.

Асафьев Стас
Эта, без преувеличения, выдающаяся команда, помимо регулярных новостей авторынка и обзоров автомобилей, выпускает просто потрясающие документалки про историю автомобилизации Японии, Франции или про развитие систем безопасности в автомобилях. Яркая картинка и искромётный юмор. Только осторожно, 18+.

Поделитесь в комментариях, что вас вдохновляет из не-ИТ мира? Не обязательно со ссылками на видео, может это книги, блоги или подкасты. То, что вы изучаете в свободное от программирования время.
👍3
День 1151.
Прекращение Поддержки .NET 5
Поддержка .NET 5.0 прекратится 8 мая 2022 г. После майских обновлений .NET Microsoft больше не будет предоставлять сервисные обновления, включая исправления безопасности или техническую поддержку, для .NET 5.0. Нужно обновить версию .NET до 6.0, чтобы продолжать получать обновления.

.NET 5.0 не является выпуском LTS (долговременной поддержки), поэтому он поддерживается в течение 18 месяцев или 6 месяцев после выпуска следующей версии. Приложения на .NET 5.0 продолжат работать. Тем не менее, прекратится выпуск обновлений безопасности для .NET 5.0, хотя он продолжится для .NET Core 3.1 и .NET 6.0. Это означает, что .NET 5.0 после 8 мая может стать потенциально небезопасной. Кроме того, прекратится техническая поддержка.

Обновление до .NET 6.0
Откройте файл проекта (файл .csproj, .vbproj или .fsproj).
Измените значение целевой платформы с net5.0 на net6.0.
Также посмотрите на критические изменения в версии 6.0.

Обновите среду разработки
На компьютере, который вы используете для разработки, может быть установлена .NET 5.0 — либо автономно, либо вместе с Visual Studio.

Начиная с сервисного обновления Visual Studio 2019 16.11 и 16.9 в июне 2022 г., компонент .NET 5.0 в Visual Studio будет изменён на неподдерживаемый и необязательный. Это означает, что компоненты Visual Studio могут быть установлены без установки .NET 5.0. Обратите внимание, что это не повлияет на существующие установки, и любые ранее установленные компоненты останутся установленными. Хотя вы сможете повторно выбрать этот необязательный компонент в Visual Studio и переустановить его, настоятельно рекомендуется использовать .NET 6.0 с Visual Studio 2022 для создания приложений, работающих в поддерживаемой среде выполнения .NET.

Версии SDK .NET 5.0 будут по-прежнему поддерживаться в VS 16.11 до декабря 2022 года, когда прекратится поддержка .NET Core 3.1, чтобы клиенты .NET Core 3.1 могли продолжать использовать 16.11 для разработки своих приложений. SDK .NET 5.0 не будет использовать среду выполнения .NET 5.0 при запуске сценариев командной строки и не будет поставляться как отдельный пакет SDK.

Источник: https://devblogs.microsoft.com/dotnet/dotnet-5-end-of-support-update/
👍3
День 1152. #ЧтоНовенького
Автосохранение Кода в VS 2022
IDE — это инструмент, который объединяет множество систем, необходимых разработчику для создания приложения. Однако, это всё равно не единственный инструмент в наборе разработчика.

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

Начиная с 17.2 Preview 1 в этом поможет новая функция автосохранения. Она находится в меню Tools > Options > Environment > Documents (Инструменты > Параметры > Cреда > Документы).

Если установлен флажок Automatically save files when Visual Studio is in the background (Автоматически сохранять файлы, когда Visual Studio находится в фоновом режиме), то каждый раз, когда VS теряет фокус (обычно при переключении на другое приложение), VS будет пытаться сохранить все несохранённые документы в IDE: файлы проекта, файлы решения и даже прочие файлы, которые не являются частью проекта или решения. Если по какой-либо причине сохранить файл не удастся (например, файл доступен только для чтения), VS сохранит ваши изменения в редакторе и просто оставит файл «грязным».

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

Стоит отметить, что люди, которые используют функцию Code Cleanup on Save (Очистка кода при сохранении), обнаружат, что автосохранение не запускает очистку кода. Разработчики утилиты решили, что это будет слишком затратно, если будет происходить слишком часто. Очистка кода при сохранении срабатывает только в том случае, если вы явно сохраняете файл через Ctrl+S, либо неявно в процессе сборки проекта.

Источник: https://devblogs.microsoft.com/visualstudio/suffer-from-ctrls-fatigue-we-have-a-feature-for-you/
День 1153.
30 и 31 марта 2022 пройдёт онлайн конференция .NET Beyond.
На ней вы посмотрите, как некоторые из самых умных людей в сообществе .NET используют его для разработки для предприятия — и в масштабе.
Независимо от того, в какой области .NET вы работаете, вы гарантированно научитесь чему-то, чего ещё не знаете.

Вот программа конференции (время московское):
30 марта
18:00 The History of .NET (Richard Campbell)
19:00 Scalability and Security with K8s and Azure Active Directory (Christos Matskas)
20:00 Getting to DDD: Pragmatic or Principled? (Julie Lerman)
21:00 Why F# Works in the Enterprise (Phillip Carter)
22:00 Introducing MongoDB and .NET: SQL is Not the Only Way (Luce Carter)
23:00 Kubernetes Made Easy with VMware Tanzu Application Platform (John Bush)
00:00 Mobile DevOps at Scale (Rodney Littles II)

31 марта
12:00 REST, GraphQL, and gRPC: A Comparison (Poornima Nayar)
13:00 Messaging for .NET Developers (Ian Cooper)
14:00 The Hand That Feeds: How to Misuse Kubernetes (Lewis Denham-Parry)
15:00 From Monolith to Service Orientated and Beyond (Stacy Cashmore)
16:00 ASP.NET Basics for Experts (Jakub Pilimon, Layla Porter)
17:00 Observability for .NET Applications (Hananiel Sarella)
18:00 Simplifying Microservice Security with YARP (Andrew Stakhov)
19:00 Your Enterprise Open Source Journey (Jeff Fritz)

Трансляция на YouTube

Источник: https://tanzu.vmware.com/developer/tv/dotnet-beyond