День 1126. #ЗаметкиНаПолях #AsyncTips
Parallel LINQ
Задача: требуется выполнить параллельную обработку последовательности данных, чтобы сгенерировать другую их последовательность или обобщение этих данных.
Решение
Многие разработчики знакомы с технологией LINQ, позволяющей программировать вычисления с последовательностями, работающей по принципу вытягивания. Parallel LINQ (PLINQ) расширяет эту поддержку LINQ параллельной обработкой.
PLINQ хорошо работает в потоковых сценариях, которые получают последовательность входных значений и производят последовательность выходных значений. Следующий простой пример просто умножает каждый элемент последовательности на 2 (в реальных сценариях выполняются гораздо более серьезные вычисления):
PLINQ предоставляет параллельные версии многих операторов, включая фильтрацию (Where), проекцию (Select) и разные виды агрегирования, такие как Sum, Average и более общую форму Aggregate. В общем случае всё, что можно сделать в обычном LINQ, также можно сделать в параллельном режиме в PLINQ. В результате PLINQ становится отличным кандидатом для обработки существующего кода LINQ, который выиграл бы от выполнения в параллельном режиме.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.
Parallel LINQ
Задача: требуется выполнить параллельную обработку последовательности данных, чтобы сгенерировать другую их последовательность или обобщение этих данных.
Решение
Многие разработчики знакомы с технологией LINQ, позволяющей программировать вычисления с последовательностями, работающей по принципу вытягивания. Parallel LINQ (PLINQ) расширяет эту поддержку LINQ параллельной обработкой.
PLINQ хорошо работает в потоковых сценариях, которые получают последовательность входных значений и производят последовательность выходных значений. Следующий простой пример просто умножает каждый элемент последовательности на 2 (в реальных сценариях выполняются гораздо более серьезные вычисления):
IEnumerable<int> Multiply(Пример может генерировать свои выходные значения в любом порядке; это поведение используется по умолчанию в Parallel LINQ. Также можно потребовать, чтобы сохранялся исходный порядок. В следующем примере обработка ведется параллельно, но с сохранением исходного порядка:
IEnumerable<int> vals)
{
return vals.AsParallel()
.Select(value => value * 2);
}
IEnumerable<int> Multiply(Другое логичное применение Parallel LINQ — агрегирование или обобщение данных в параллельном режиме. В следующем примере выполняется параллельное суммирование:
IEnumerable<int> vals)
{
return vals.AsParallel()
.AsOrdered().Select(value => value * 2);
}
int ParallelSum(IEnumerable<int> values)Класс Parallel хорошо подходит для многих сценариев, но код PLINQ получается более простым при агрегировании или преобразовании одной последовательности в другую. Следует помнить, что класс Parallel ведет себя более корректно с другими процессами в системе, чем PLINQ; этот фактор становится особенно существенным при выполнении параллельной обработки на серверной машине.
{
return values.AsParallel().Sum();
}
PLINQ предоставляет параллельные версии многих операторов, включая фильтрацию (Where), проекцию (Select) и разные виды агрегирования, такие как Sum, Average и более общую форму Aggregate. В общем случае всё, что можно сделать в обычном LINQ, также можно сделать в параллельном режиме в PLINQ. В результате PLINQ становится отличным кандидатом для обработки существующего кода LINQ, который выиграл бы от выполнения в параллельном режиме.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.
День 1127. #DDD
Раскрытие Реализации в Именах Классов
Эта тема возникла в ответ на вопрос о паттерне CQRS, но он в равной степени применима и к другим паттернам. Вопрос:
Почему DatabaseRetryDecorator раскрывает свою структуру и детали реализации в имени класса? Что, если я изменю реализацию и заменю декоратор чем-то другим? Придется ли мне переименовывать его только потому, что я изменил его реализацию?
Просто для контекста, декораторы — это классы, которые позволяют вам вводить сквозную функциональность в вашем приложении.
Вот пример использования декоратора для повторных попыток при обращении к базе данных:
Действительно, почему вы должны называть класс
Здесь есть 2 совета.
1. Никогда не используйте имена паттернов при именовании классов на уровне предметной области (Domain layer). Вы должны использовать только термины из общего языка. Так что, не
2. Допустимо использовать имена паттернов при именовании классов на прикладном уровне (Application layer), потому что прикладной уровень находится за пределами действия общего языка.
Кроме того, имена паттернов помогают лучше понять назначение классов на прикладном уровне, поскольку эти классы не имеют прямой связи с вашей моделью предметной области.
Обратите внимание, что вы всегда должны следовать принципу YAGNI, даже при именовании классов прикладного уровня. Это означает, что вы должны поместить минимальное количество дескрипторов в имена классов.
Самый распространенный пример нарушения YAGNI — вызов репозитория
Источник: https://khorikov.org/posts/2021-08-16-exposing-implementation-details-in-class-names/
Раскрытие Реализации в Именах Классов
Эта тема возникла в ответ на вопрос о паттерне CQRS, но он в равной степени применима и к другим паттернам. Вопрос:
Почему DatabaseRetryDecorator раскрывает свою структуру и детали реализации в имени класса? Что, если я изменю реализацию и заменю декоратор чем-то другим? Придется ли мне переименовывать его только потому, что я изменил его реализацию?
Просто для контекста, декораторы — это классы, которые позволяют вам вводить сквозную функциональность в вашем приложении.
Вот пример использования декоратора для повторных попыток при обращении к базе данных:
[DatabaseRetry]Приведенный выше атрибут
public class EditPersonalInfoCommandHandler :
ICommandHandler<EditPersonalInfoCommand>
{
public Result Handle(EditPersonalInfoCommand command)
{
/* Изменяем данные клиента */
}
}
DatabaseRetryAttribute
соединяет обработчик команд с DatabaseRetryDecorator
. Если обработчик команды выдаёт исключение базы данных, декоратор повторно его запускает (как вариант, через некоторое время). Идея аналогична тому, как промежуточное ПО работает в ASP.NET.Действительно, почему вы должны называть класс
DatabaseRetryDecorator
, а не просто DatabaseRetry
? Тот же аргумент можно применить и к другим классам, например, CustomerRepository
, CustomerFactory
или даже к EditPersonalInfoCommandHandler
. Так ли им нужно указывать на паттерны, которые они реализуют, в своих именах (репозиторий, фабрика и обработчик команд)?Здесь есть 2 совета.
1. Никогда не используйте имена паттернов при именовании классов на уровне предметной области (Domain layer). Вы должны использовать только термины из общего языка. Так что, не
CustomerEntity
или CustomerAggregate
, а просто Customer
.2. Допустимо использовать имена паттернов при именовании классов на прикладном уровне (Application layer), потому что прикладной уровень находится за пределами действия общего языка.
Кроме того, имена паттернов помогают лучше понять назначение классов на прикладном уровне, поскольку эти классы не имеют прямой связи с вашей моделью предметной области.
Обратите внимание, что вы всегда должны следовать принципу YAGNI, даже при именовании классов прикладного уровня. Это означает, что вы должны поместить минимальное количество дескрипторов в имена классов.
Самый распространенный пример нарушения YAGNI — вызов репозитория
CustomerSqlRepository
. Если вы не используете несколько парадигм хранения, таких как SQL и NoSQL, нет необходимости указывать, что ваш репозиторий работает поверх базы данных SQL.Источник: https://khorikov.org/posts/2021-08-16-exposing-implementation-details-in-class-names/
День 1128. #ЧтоНовенького
Новые Функции C#11
Команда .NET уже начала работу над функциями, которые будут включены в C# 11 и .NET 7. Сегодня рассмотрим некоторые из них.
1. Усовершенствования интерполированных строк
В настоящее время поддерживается два типа интерполированных строк:
- Обычная интерполяция:
Они позволят нам сравнивать с массивами и списками, иметь возможность сопоставлять различные элементы или даже включать шаблоны, которые соответствуют нулю или более элементам.
Например, под шаблон
Эта новая функция создана из-за того, что стандартный код проверки параметра на
Если мы применим
Новые Функции C#11
Команда .NET уже начала работу над функциями, которые будут включены в C# 11 и .NET 7. Сегодня рассмотрим некоторые из них.
1. Усовершенствования интерполированных строк
В настоящее время поддерживается два типа интерполированных строк:
- Обычная интерполяция:
$""
- Дословная интерполяция: $@""
Основное отличие состоит в том, что дословно интерполированные строки могут содержать несколько строк, и экранировать нужно только кавычки. В обычных интерполированных строках для новой строки нужно использовать спец символы /r/n
. Теперь в обычных интерполированных строках можно будет использовать что-то вроде:var v =2. Шаблоны списков
$"Результат: { this.Is.Something()
.That.I.Should(
be + able)[
to.Wrap()] }.";
Они позволят нам сравнивать с массивами и списками, иметь возможность сопоставлять различные элементы или даже включать шаблоны, которые соответствуют нулю или более элементам.
Например, под шаблон
[1, 2, .., 10]
подходят все следующие массивы:int[] arr1 = { 1, 2, 10 };3. Проверка параметра на null
int[] arr2 = { 1, 2, 5, 10 };
int[] arr3 = { 1, 2, 5, 6, 7, 8, 9, 10 };
Эта новая функция создана из-за того, что стандартный код проверки параметра на
null
встречается слишком часто:public static void M(string s)Теперь мы сможем использовать сокращённую запись с помощью !!:
{
if (s is null)
throw new ArgumentNullException(nameof(s));
// …
}
public static void M(string s!!)Это также может быть использовано для проверки параметров индексаторов:
{
// …
}
public string this[string key!!]В конструкторах эта функция будет действовать немного по-другому. Проверка параметров конструктора на
{ get { ... } set { ... } }
null
с помощью !!
будет происходить после инициализаторов полей, однако до вызова конструктора базового класса. То есть:public record Base(int len);При передаче
public record Derived(string s!!)
: Base(s.Length);
null
в конструктор Derived
, будет выброшено ArgumentNullException
из класса Derived
, а не NullReferenceException
из класса Base
.Если мы применим
!!
к имени параметра обнуляемого ссылочного типа, компилятор выдаст предупреждение:void WarnCase<T>(Источник: https://dev.to/dotnetsafer/c-11-is-coming-5-features-that-will-blow-your-mind-3o7h
string? name!!,
// CS8995 Nullable type 'string?' is null-checked and will throw if null
// (Обнуляемый тип 'string?' проверяется на null и выбросит исключение при null)
T value1!! // OK
)
День 1129. #ЗаметкиНаПолях
Улучшенная Обработка Исключений с EntityFrameworkCore.Exceptions
При выполнении практически любых действий с Entity Framework, включая обновления, удаления и вставку, если что-то пойдёт не так, вам выдаётся стандартное исключение:
Допустим, мы получили исключение с таким внутренним исключением:
Использование EntityFrameworkCore.Exceptions
Библиотека EntityFrameworkCore.Exceptions чрезвычайно проста в использовании. Чтобы использовать её, всё, что нам нужно сделать, это установить соответствующий NuGet пакет:
Затем добавьте вот эту строку в настройки DB Context:
Источник: https://dotnetcoretutorials.com/2022/01/29/better-exception-handling-with-entityframeworkcore-exceptions/
Улучшенная Обработка Исключений с EntityFrameworkCore.Exceptions
При выполнении практически любых действий с Entity Framework, включая обновления, удаления и вставку, если что-то пойдёт не так, вам выдаётся стандартное исключение:
Microsoft.EntityFrameworkCore.DbUpdateException: ‘An error occurred while saving the entity changes. See the inner exception for details.’ (Возникла ошибка при сохранении изменений сущности. См. детали во внутреннем исключении)
Это может очень раздражать, если вы хотите перехватить конкретное исключение базы данных (например, ожидаете, что могут быть дубликаты уникального ключа) и обработать их отдельно от, например, ошибки подключения. Давайте рассмотрим быстрый пример, чтобы проиллюстрировать, что я имею в виду.Допустим, мы получили исключение с таким внутренним исключением:
SqlException: Cannot insert duplicate key row in object ‘…’ with unique index ‘…’. The duplicate key value is (…).
Если мы хотим обработать его отдельно, нам пришлось бы писать что-то вроде этого:try
{
context.SaveChanges();
} catch(DbUpdateException e) when
(e?.InnerException?.
Message.Contains("Cannot insert duplicate key")
?? false)
{
// …
}
Очень некрасиво, и мало подходит для повторного использования. Если мы захотим использовать такую обработку ещё где-нибудь, нам придётся скопировать всю эту логику.Использование EntityFrameworkCore.Exceptions
Библиотека EntityFrameworkCore.Exceptions чрезвычайно проста в использовании. Чтобы использовать её, всё, что нам нужно сделать, это установить соответствующий NuGet пакет:
Install-Package EntityFrameworkCore.Exceptions.SqlServer
Доступны также версии для Postgres, MySQL, Oracle и Sqlite.Затем добавьте вот эту строку в настройки DB Context:
protected override void OnConfiguring(
DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseExceptionProcessor();
}
Теперь при том же исключении БД вместо стандартного DbUpdateException
мы получим:EntityFramework.Exceptions.Common.UniqueConstraintException: ‘Unique constraint violation’
Таким образом, можно заменить наш код try/catch на следующий:try
{
context.SaveChanges();
} catch (UniqueConstraintException ex)
{
// …
}
Гораздо чище, компактнее и намного более подходит для повторного использования.Источник: https://dotnetcoretutorials.com/2022/01/29/better-exception-handling-with-entityframeworkcore-exceptions/
День 1130. #ЧтоНовенького
Microsoft Выпустили в Превью Инструменты Разработчика Edge для Visual Studio
Это расширение для Visual Studio 2022 позволяет разработчикам просматривать проекты ASP.NET и ASP.NET Core. Оно дополняет аналогичный инструмент для Visual Studio Code, который доступен уже много лет и установлен более 460 000 раз.
Помимо предварительного просмотра вашего веб-приложения, вы можете использовать инструмент Edge Developer Tools для изменения CSS. Изменения будут автоматически применены к вашим исходным файлам.
Как показано в этой анимации, инструмент представляет кнопку предварительного просмотра в нижней левой части редактора, при нажатии на которую создаётся страница и отображается в окне инструмента.
Изменения CSS можно вносить на вкладке Elements и автоматически применять к исходным файлам. Вкладка Network позволяет разработчикам видеть веб-запросы, сделанные при обновлении страницы.
В нынешней превью редакции не хватает некоторых функций, включая поддержку Blazor, которая, как говорят, появится в ближайшее время.
Помимо этого, вот другие известные проблемы:
- Изменения CSS требуют сохранения файла
При изменении CSS обновления не будут применяться по мере ввода, вам нужно будет сохранить файл, чтобы изменения были перенесены в окно предварительного просмотра.
- Сброс прокрутки после внесения изменений CSS в инструментах разработчика Edge
При редактировании CSS с помощью инструментов разработчика Edge, если вы изменяете исходный код файла CSS, который в данный момент открыт в редакторе Visual Studio, редактор открутит файл вверх после внесения изменений в CSS.
- Предупреждение об окончаниях строк
Если вы вносите изменения в файл CSS с помощью инструментов Edge, при следующем открытии этого файла CSS вы можете получить предупреждение о несовместимых окончаниях строк.
Инструмент доступен для Visual Studio 2022 17.1 или более поздней версии.
https://marketplace.visualstudio.com/items?itemName=ms-edgedevtools.VisualStudioEdgeDevTools
Источник: https://visualstudiomagazine.com/articles/2022/03/02/edge-tools-visual-studio.aspx
Microsoft Выпустили в Превью Инструменты Разработчика Edge для Visual Studio
Это расширение для Visual Studio 2022 позволяет разработчикам просматривать проекты ASP.NET и ASP.NET Core. Оно дополняет аналогичный инструмент для Visual Studio Code, который доступен уже много лет и установлен более 460 000 раз.
Помимо предварительного просмотра вашего веб-приложения, вы можете использовать инструмент Edge Developer Tools для изменения CSS. Изменения будут автоматически применены к вашим исходным файлам.
Как показано в этой анимации, инструмент представляет кнопку предварительного просмотра в нижней левой части редактора, при нажатии на которую создаётся страница и отображается в окне инструмента.
Изменения CSS можно вносить на вкладке Elements и автоматически применять к исходным файлам. Вкладка Network позволяет разработчикам видеть веб-запросы, сделанные при обновлении страницы.
В нынешней превью редакции не хватает некоторых функций, включая поддержку Blazor, которая, как говорят, появится в ближайшее время.
Помимо этого, вот другие известные проблемы:
- Изменения CSS требуют сохранения файла
При изменении CSS обновления не будут применяться по мере ввода, вам нужно будет сохранить файл, чтобы изменения были перенесены в окно предварительного просмотра.
- Сброс прокрутки после внесения изменений CSS в инструментах разработчика Edge
При редактировании CSS с помощью инструментов разработчика Edge, если вы изменяете исходный код файла CSS, который в данный момент открыт в редакторе Visual Studio, редактор открутит файл вверх после внесения изменений в CSS.
- Предупреждение об окончаниях строк
Если вы вносите изменения в файл CSS с помощью инструментов Edge, при следующем открытии этого файла CSS вы можете получить предупреждение о несовместимых окончаниях строк.
Инструмент доступен для Visual Studio 2022 17.1 или более поздней версии.
https://marketplace.visualstudio.com/items?itemName=ms-edgedevtools.VisualStudioEdgeDevTools
Источник: https://visualstudiomagazine.com/articles/2022/03/02/edge-tools-visual-studio.aspx
День 1131. #Карьера
Как Быть Продуктивным, Когда Вокруг Столько Отвлекающих Факторов
Мы определённо живем в эпоху постоянного отвлечения внимания. А сейчас ситуация совсем вышла из-под контроля. Неудивительно, что многие из нас чувствуют себя хронически истощёнными. Нужно обрабатывать так много информации и так много вещей, к которым нужно приспособиться. И вдобавок ко всему, большая неопределённость в экономике, здравоохранении и рост стоимости жизни.
Не будем говорить о вещах, которые мы не можем контролировать. Сосредоточимся на единственном, что находится под вашим контролем: вы. Рассмотрим, как адаптировать вашу стратегию продуктивности и как вы можете использовать эти идеи, чтобы улучшить себя.
1. Больше акцента на чётко определённых целях
Мир полон неопределённости и сложности, что может вызывать тревогу. Если вы не знаете, что делать или с чего начать, это зачастую вводит в ступор.
Есть два способа справиться с этим. Отречься от всего и жить как монах. Или поставить чётко определённые цели и усердно работать над ними. Чем более неопределённым и сложным становится мир, тем чётче нужно определять цели. Ваши цели упростят мир и уменьшат неопределённость. Когда нет целей, ты становишься дрейфующим кораблём в море. Ты во власти океана.
В современном мире нужно больше внимания уделять целям. Нужно чётко понимать, к чему стремиться. Нужно работать над целями, не ожидая никакого результата. Это будет продвигать вас вперед, как никакая другая сила, с которой вы когда-либо сталкивались.
2. Постоянство результатов
Когда вы ставите цели, возникает соблазн подумать о ваших желаниях: зарабатывать больше, быть в лучшей форме или путешествовать по красивым местам. Когда мы изо всех сил преследуем одно, мы часто жертвуем другим. Когда мы гонимся за деньгами, это часто происходит за счёт отношений или психического здоровья.
Поскольку жизнь становится всё более конкурентной, возникает соблазн стремиться реализовывать желания. Но погоня за импульсами не приведёт вас к достижению целей. Вместо того, чтобы желать результатов, сосредоточьтесь на постоянстве.
Лучше тренироваться четыре раза в неделю и каждый день ходить на прогулку, чем ежедневно поднимать тяжести, бегать несколько раз в неделю и сгореть через пару недель. Когда вы вынуждены сдаться, потому что больше не можете что-то терпеть ни морально, ни физически, значит, вы не оптимизировали постоянство.
Когда вы сосредотачиваетесь на том, чтобы быть стабильно продуктивным, вы ищете уровень производительности, который подходит именно вам. Это зависит от вашей естественной терпимости к работе и вашего опыта.
3. Меньше потребления контента
Происходит столько всего, что вы просто не можете удержаться от пролистывания ленты новостей. Однако это негативно сказывается на вашем мышлении и продуктивности. Постарайтесь не особо интересоваться новостями. Если произойдёт что-то важное, вы узнаете об этом от семьи или друзей. Это действительно экономит час или два в день. Вместо потребления контента займитесь чем-нибудь активным. Банально говорить что-то вроде: «Проводите больше времени на природе». Но все знают, что это хорошо.
4. Пусть всё, что вы делаете, будет приятным
Не обязательно менять карьеру, чтобы получать больше удовольствия от работы. Можно сделать карьеру и работу более приятной, изменив то, как вы работаете. Вы должны любить то, что делаете. Нужно время, чтобы понять, что вы любите. Не ждите, что сразу же найдёте ответ.
Постановка новых целей — отличный способ для начала. Всё дело в достижении прогресса и выяснении того, какие аспекты этого прогресса вам нравятся. Вы поймёте это, когда начнёте двигаться к цели. Нужно только начать.
Источник: https://dariusforoux.com/productivity-distraction-age/
Как Быть Продуктивным, Когда Вокруг Столько Отвлекающих Факторов
Мы определённо живем в эпоху постоянного отвлечения внимания. А сейчас ситуация совсем вышла из-под контроля. Неудивительно, что многие из нас чувствуют себя хронически истощёнными. Нужно обрабатывать так много информации и так много вещей, к которым нужно приспособиться. И вдобавок ко всему, большая неопределённость в экономике, здравоохранении и рост стоимости жизни.
Не будем говорить о вещах, которые мы не можем контролировать. Сосредоточимся на единственном, что находится под вашим контролем: вы. Рассмотрим, как адаптировать вашу стратегию продуктивности и как вы можете использовать эти идеи, чтобы улучшить себя.
1. Больше акцента на чётко определённых целях
Мир полон неопределённости и сложности, что может вызывать тревогу. Если вы не знаете, что делать или с чего начать, это зачастую вводит в ступор.
Есть два способа справиться с этим. Отречься от всего и жить как монах. Или поставить чётко определённые цели и усердно работать над ними. Чем более неопределённым и сложным становится мир, тем чётче нужно определять цели. Ваши цели упростят мир и уменьшат неопределённость. Когда нет целей, ты становишься дрейфующим кораблём в море. Ты во власти океана.
В современном мире нужно больше внимания уделять целям. Нужно чётко понимать, к чему стремиться. Нужно работать над целями, не ожидая никакого результата. Это будет продвигать вас вперед, как никакая другая сила, с которой вы когда-либо сталкивались.
2. Постоянство результатов
Когда вы ставите цели, возникает соблазн подумать о ваших желаниях: зарабатывать больше, быть в лучшей форме или путешествовать по красивым местам. Когда мы изо всех сил преследуем одно, мы часто жертвуем другим. Когда мы гонимся за деньгами, это часто происходит за счёт отношений или психического здоровья.
Поскольку жизнь становится всё более конкурентной, возникает соблазн стремиться реализовывать желания. Но погоня за импульсами не приведёт вас к достижению целей. Вместо того, чтобы желать результатов, сосредоточьтесь на постоянстве.
Лучше тренироваться четыре раза в неделю и каждый день ходить на прогулку, чем ежедневно поднимать тяжести, бегать несколько раз в неделю и сгореть через пару недель. Когда вы вынуждены сдаться, потому что больше не можете что-то терпеть ни морально, ни физически, значит, вы не оптимизировали постоянство.
Когда вы сосредотачиваетесь на том, чтобы быть стабильно продуктивным, вы ищете уровень производительности, который подходит именно вам. Это зависит от вашей естественной терпимости к работе и вашего опыта.
3. Меньше потребления контента
Происходит столько всего, что вы просто не можете удержаться от пролистывания ленты новостей. Однако это негативно сказывается на вашем мышлении и продуктивности. Постарайтесь не особо интересоваться новостями. Если произойдёт что-то важное, вы узнаете об этом от семьи или друзей. Это действительно экономит час или два в день. Вместо потребления контента займитесь чем-нибудь активным. Банально говорить что-то вроде: «Проводите больше времени на природе». Но все знают, что это хорошо.
4. Пусть всё, что вы делаете, будет приятным
Не обязательно менять карьеру, чтобы получать больше удовольствия от работы. Можно сделать карьеру и работу более приятной, изменив то, как вы работаете. Вы должны любить то, что делаете. Нужно время, чтобы понять, что вы любите. Не ждите, что сразу же найдёте ответ.
Постановка новых целей — отличный способ для начала. Всё дело в достижении прогресса и выяснении того, какие аспекты этого прогресса вам нравятся. Вы поймёте это, когда начнёте двигаться к цели. Нужно только начать.
Источник: https://dariusforoux.com/productivity-distraction-age/
День 1133. #DDD
Коллекции и Одержимость Примитивными Типами. Начало
Одержимость примитивными типами (Primitive Obsession) — это антипаттерн, который заключается в чрезмерном использовании примитивных типов, особенно для моделирования предметной области.
Этот антипаттерн широко известен как в сообществах DDD, так и в сообществах функционального программирования. В DDD вместо этого есть паттерн объекта-значения, а в функциональном программировании существует культура введения типов-оболочек для любого небольшого понятия из вашей предметной области, прежде всего потому, что эти типы-оболочки очень легко создавать в функциональных языках.
Обычно одержимость примитивными типами проявляется в использовании строк, целых чисел и других простых типов. Распространённые примеры:
- Использование строки для представления адресов электронной почты. Специально созданный объект-значение
- Использование
Конечно, не все концепции в вашей предметной области должны быть представлены как объекты-значения, необходимо провести некоторый анализ, чтобы выяснить, стоит ли создавать новый объект-значение. Но недостаточное использование объектов-значений — гораздо более серьёзная проблема, чем чрезмерное их использование.
Но зачем нам вообще нужны объекты-значения?
Дело в инкапсуляции. Она предназначена для защиты данных от перехода в недопустимое состояние. Гораздо сложнее защитить от этого строку, чем специально созданный класс со всеми необходимыми встроенными проверками.
Действительная строка может быть или не быть действительным адресом электронной почты; концепция строки слишком широка и сама по себе не может учитывать правила валидности электронного адреса.
Другими словами, множество строк больше, чем множество e-mail адресов. Чтобы правильно представить концепцию e-mail адреса, нам нужно создать пользовательский класс, который будет соответствовать множеству действительных e-mail адресов.
Помимо инкапсуляции, есть ещё принцип абстракции. Класс
Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/collections-primitive-obsession/
Коллекции и Одержимость Примитивными Типами. Начало
Одержимость примитивными типами (Primitive Obsession) — это антипаттерн, который заключается в чрезмерном использовании примитивных типов, особенно для моделирования предметной области.
Этот антипаттерн широко известен как в сообществах DDD, так и в сообществах функционального программирования. В DDD вместо этого есть паттерн объекта-значения, а в функциональном программировании существует культура введения типов-оболочек для любого небольшого понятия из вашей предметной области, прежде всего потому, что эти типы-оболочки очень легко создавать в функциональных языках.
Обычно одержимость примитивными типами проявляется в использовании строк, целых чисел и других простых типов. Распространённые примеры:
- Использование строки для представления адресов электронной почты. Специально созданный объект-значение
Email
был бы здесь намного лучше.- Использование
double
для моделирования концепции денег вместо введения объекта-значения Money
.Конечно, не все концепции в вашей предметной области должны быть представлены как объекты-значения, необходимо провести некоторый анализ, чтобы выяснить, стоит ли создавать новый объект-значение. Но недостаточное использование объектов-значений — гораздо более серьёзная проблема, чем чрезмерное их использование.
Но зачем нам вообще нужны объекты-значения?
Дело в инкапсуляции. Она предназначена для защиты данных от перехода в недопустимое состояние. Гораздо сложнее защитить от этого строку, чем специально созданный класс со всеми необходимыми встроенными проверками.
Действительная строка может быть или не быть действительным адресом электронной почты; концепция строки слишком широка и сама по себе не может учитывать правила валидности электронного адреса.
Другими словами, множество строк больше, чем множество e-mail адресов. Чтобы правильно представить концепцию e-mail адреса, нам нужно создать пользовательский класс, который будет соответствовать множеству действительных e-mail адресов.
Помимо инкапсуляции, есть ещё принцип абстракции. Класс
Email
абстрагирует все бизнес-правила, связанные с e-mail адресами, так что клиентский код может работать с этими объектами, не обращая внимания на детали реализации, связанные с проверкой e-mail.Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/collections-primitive-obsession/
День 1134. #DDD
Коллекции и Одержимость Примитивными Типами. Окончание
Начало
Пользовательские классы коллекций
А что насчёт коллекций? Допустим, у нас есть следующий класс:
Рассмотрим примеры выше.
1. Коллекция сущностей
Нам нужно, чтобы свойство
2. Пользовательский класс коллекции
Если коллекция не принадлежит никакой другой сущности, то имеет смысл создать для неё отдельный класс. Например, если вам нужно отслеживать всех пользователей, которые в данный момент находятся в сети, лучше всего представить их в виде пользовательского класса:
Итого
Одержимость примитивными типами — это использование примитивных типов для моделирования предметной области.
Вам может понадобиться или не понадобиться отдельный класс для коллекции. Если коллекция представляет собой набор связанных сущностей, присоединённых к родительской сущности, то эта родительская сущность фактически действует как пользовательский класс. Отдельный класс для самой коллекции не нужен.
Если же коллекция является коллекцией корневого уровня, то для неё нужен пользовательский класс (при условии, что помимо самой коллекции необходимы дополнительные функции).
Источник: https://enterprisecraftsmanship.com/posts/collections-primitive-obsession/
Коллекции и Одержимость Примитивными Типами. Окончание
Начало
Пользовательские классы коллекций
А что насчёт коллекций? Допустим, у нас есть следующий класс:
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/
День 1135. #ЗаметкиНаПолях
Избегаем Проблем с DNS в HttpClient
HttpClient позволяет отправлять HTTP-запросы. Подразумевается, что он создаётся однократно и повторно используется на протяжении всего жизненного цикла приложения. HttpClient имеет пул для повторного использования соединений. Если вы отправите несколько запросов на один и тот же хост, они будут повторно использовать одно и то же соединение. Таким образом, приложение экономит доступные ему сокеты. Кроме того, это повышает производительность приложения, избегая рукопожатий TCP и TLS для каждого запроса к одному и тому же хосту.
Сохранение соединений открытыми - хорошо с точки зрения производительности, но вы должны быть осторожны, чтобы не хранить устаревшие соединения. Если срок жизни DNS истёк, хост может изменить свой IP-адрес. В этом случае открытые соединения должны быть закрыты. HttpClient не делает этого автоматически, поскольку ему ничего не известно о сроке жизни DNS.
Когда происходит изменение DNS?
- При сине-зелёном развёртывании (в Azure, когда вы выполняете развёртывание в промежуточном слоте, а затем переключаете рабочий/промежуточный слоты).
- При изменении настроек в диспетчере трафика Azure.
- В случае отказа основного сервера и перехода на бекап и т.п.
Чтобы исправить эту проблему, вы можете указать время ожидания для автоматического закрытия соединения.
-
-
Эти свойства заставляют
По умолчанию простаивающие соединения закрываются через 1 минуту. Однако активные соединения никогда не закрываются. Вы должны явно установить для
Избегаем Проблем с 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;Замечание: Другой способ избежать проблем с изменённым DNS – использовать
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");
}
IHttpClientFactory
:servicesИсточник: https://www.meziantou.net/avoid-dns-issues-with-httpclient-in-dotnet.htm
.AddHttpClient<IMyService, MyService>()
.SetHandlerLifetime(TimeSpan.FromMinutes(1));
День 1136. #ЗаметкиНаПолях #AsyncTips
Модульное тестирование async-методов
Задача: Имеется async-метод, для которого необходимо провести модульное тестирование.
Решение
Многие современные фреймворки модульного тестирования, включая MSTest, NUnit и xUnit, поддерживают методы модульного тестирования async Task. Пример асинхронного модульного теста в MSTest:
Если ваш фреймворк модульного тестирования не поддерживает модульные тесты с
Имитация (mocking) асинхронных зависимостей на первый взгляд кажется немного неуклюжей. Всегда желательно хотя бы проверить, как ваши методы реагируют на синхронный успех (имитация с
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 7.
Модульное тестирование async-методов
Задача: Имеется async-метод, для которого необходимо провести модульное тестирование.
Решение
Многие современные фреймворки модульного тестирования, включая MSTest, NUnit и xUnit, поддерживают методы модульного тестирования async Task. Пример асинхронного модульного теста в MSTest:
[TestMethod]Фреймворк модульного тестирования замечает, что метод возвращает
public async Task MethodAsync_False()
{
var sut = …;
var result = await sut.MethodAsync();
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.
День 1137.
Развёртывайте Чаще
Если вы ещё не практикуете непрерывное развёртывание, скорее всего, ваша команда и компания выиграют от более частых развёртываний.
Развёртывание (deploy) ПО — это процесс переноса его из среды разработки в производственную (или другую) среду. Развёртывание не то же самое, что выпуск (release). В идеале вы должны иметь возможность часто развёртывать ПО, выпуская новые функции для клиентов только тогда, когда это целесообразно с точки зрения бизнеса.
Считаете ли вы развёртывание стрессовым, болезненным и требующим от членов команды внеурочной работы? Что, если бы вы могли избавиться от этого, развёртывая ПО в любое время, но выпуская его только тогда, когда это удобно для вашей команды и/или пользователей?
Ключевым средством разделения развёртывания и выпуска являются флаги (переключатели) функций. Вы можете развернуть код, который ещё не готов, и «скрыть» его за флагом. Как только функция будет готова, и бизнес определит, что пришло время выпустить её, флаг можно переключить, и функция станет активной. И даже этот процесс можно запланировать.
Клиенты, с которыми я работал, развёртывали ПО нерегулярно, примерно раз в 6-8 недель по решению руководства. Поскольку их клиенты приходили в офис к 8 утра, команда должна была начать развёртывание в 3 часа ночи. Процесс почти никогда не проходил по плану: хотя первоначальное развёртывание занимало всего 10-15 минут, остальное время уходило на тестирование, исправление ошибок и повторное развёртывание, чтобы система заработала к 8 утра. А иногда приходилось откатываться и планировать развёртывание на другой день.
Если вы развёртываете редко, вы почти наверняка внедряете изменения, которые были завершены несколько недель или месяцев назад. Если что-то пойдёт не так с этим кодом, разработчик, который его написал, вероятно, уже забыл о нём к этому моменту, а то и вовсе уволился. При более частом развёртывании все вносимые изменения остаются свежими в памяти команды, поэтому выявление и устранение любых проблем становится намного проще.
Для моих клиентов сначала мы собрали метрики о периодичности развёртываний и их успешности. Успешным считалось развёртывание, которое не пришлось откатывать или немедленно исправлять ошибки в нём. Оказалось, что развёртывания, которые выполнялись спустя неделю после предыдущего, почти никогда не были успешными. Тогда как те, что выполнялись спустя день, в большинстве случаев не требовали исправлений.
«Если больно, делай это чаще».
Мы решили выполнять развёртывание чаще. Команде предложение не понравилось. Дни развертывания никому не нравились. Это были дни сильного стресса, бессонницы, которые мешали работе и личной жизни людей. А их просили делать это чаще.
Однако, мы выяснили, что развёртывания после длинного перерыва были высоким стрессом и полной неопределенностью, тогда как те, что выполнялись сразу после, проходили гораздо легче. Это понятно, ведь изменений было немного. Так почему бы не продолжать в том же духе?
Команда решила проводить развёртывания по вторникам и четвергам. Они планировали выполнить 50 развёртываний в год вместо 10, как было раньше. Однако им удалось сделать 100 и более 90% из них были успешными. Больше никому не приходилось выполнять стрессовое развёртывание в 3 часа ночи.
Итого
Процесс доставки ПО является важной частью успеха вашей команды (и компании). Существует множество причин, по которым вы должны предоставлять функционал клиентам раньше и чаще. Проблемы, которые непропорционально возрастают с размером развёртывания, можно контролировать. Стоимость тестирования и исправления ошибок растёт со временем не линейно, а экспоненциально, поэтому, чаще развёртывая, вы сокращаете время, в течение которого могут возникнуть большие проблемы. А с мелкими, которые успевают возникнуть, справиться гораздо легче.
Источник: https://ardalis.com/deploy-more-often/
Автор оригинала: Steve “Ardalis” Smith
Развёртывайте Чаще
Если вы ещё не практикуете непрерывное развёртывание, скорее всего, ваша команда и компания выиграют от более частых развёртываний.
Развёртывание (deploy) ПО — это процесс переноса его из среды разработки в производственную (или другую) среду. Развёртывание не то же самое, что выпуск (release). В идеале вы должны иметь возможность часто развёртывать ПО, выпуская новые функции для клиентов только тогда, когда это целесообразно с точки зрения бизнеса.
Считаете ли вы развёртывание стрессовым, болезненным и требующим от членов команды внеурочной работы? Что, если бы вы могли избавиться от этого, развёртывая ПО в любое время, но выпуская его только тогда, когда это удобно для вашей команды и/или пользователей?
Ключевым средством разделения развёртывания и выпуска являются флаги (переключатели) функций. Вы можете развернуть код, который ещё не готов, и «скрыть» его за флагом. Как только функция будет готова, и бизнес определит, что пришло время выпустить её, флаг можно переключить, и функция станет активной. И даже этот процесс можно запланировать.
Клиенты, с которыми я работал, развёртывали ПО нерегулярно, примерно раз в 6-8 недель по решению руководства. Поскольку их клиенты приходили в офис к 8 утра, команда должна была начать развёртывание в 3 часа ночи. Процесс почти никогда не проходил по плану: хотя первоначальное развёртывание занимало всего 10-15 минут, остальное время уходило на тестирование, исправление ошибок и повторное развёртывание, чтобы система заработала к 8 утра. А иногда приходилось откатываться и планировать развёртывание на другой день.
Если вы развёртываете редко, вы почти наверняка внедряете изменения, которые были завершены несколько недель или месяцев назад. Если что-то пойдёт не так с этим кодом, разработчик, который его написал, вероятно, уже забыл о нём к этому моменту, а то и вовсе уволился. При более частом развёртывании все вносимые изменения остаются свежими в памяти команды, поэтому выявление и устранение любых проблем становится намного проще.
Для моих клиентов сначала мы собрали метрики о периодичности развёртываний и их успешности. Успешным считалось развёртывание, которое не пришлось откатывать или немедленно исправлять ошибки в нём. Оказалось, что развёртывания, которые выполнялись спустя неделю после предыдущего, почти никогда не были успешными. Тогда как те, что выполнялись спустя день, в большинстве случаев не требовали исправлений.
«Если больно, делай это чаще».
Мы решили выполнять развёртывание чаще. Команде предложение не понравилось. Дни развертывания никому не нравились. Это были дни сильного стресса, бессонницы, которые мешали работе и личной жизни людей. А их просили делать это чаще.
Однако, мы выяснили, что развёртывания после длинного перерыва были высоким стрессом и полной неопределенностью, тогда как те, что выполнялись сразу после, проходили гораздо легче. Это понятно, ведь изменений было немного. Так почему бы не продолжать в том же духе?
Команда решила проводить развёртывания по вторникам и четвергам. Они планировали выполнить 50 развёртываний в год вместо 10, как было раньше. Однако им удалось сделать 100 и более 90% из них были успешными. Больше никому не приходилось выполнять стрессовое развёртывание в 3 часа ночи.
Итого
Процесс доставки ПО является важной частью успеха вашей команды (и компании). Существует множество причин, по которым вы должны предоставлять функционал клиентам раньше и чаще. Проблемы, которые непропорционально возрастают с размером развёртывания, можно контролировать. Стоимость тестирования и исправления ошибок растёт со временем не линейно, а экспоненциально, поэтому, чаще развёртывая, вы сокращаете время, в течение которого могут возникнуть большие проблемы. А с мелкими, которые успевают возникнуть, справиться гораздо легче.
Источник: https://ardalis.com/deploy-more-often/
Автор оригинала: Steve “Ardalis” Smith
День 1139. #ЗаметкиНаПолях
Выполнение Кода Перед Main
Вообще, я не любитель подобных извращений. Но чисто ради лулзов иногда интересно узнать, что так можно.
Согласно документации, «Метод Main — это точка входа в приложение C#. При запуске приложения метод Main вызывается первым.» На самом деле метод
1. Статический конструктор
Статический конструктор используется для инициализации любых статических данных или для выполнения определённого действия, которое необходимо выполнить только один раз. Он вызывается автоматически перед созданием первого экземпляра или обращением к любым статическим элементам. Поэтому статический конструктор вызовется перед методом Main.
Инициализаторы модулей позволяют библиотекам выполнять однократную инициализацию при загрузке без необходимости явного вызова пользователем чего-либо. Когда среда выполнения загружает модуль (DLL), она вызывает методы инициализации модуля перед выполнением любого кода из этого модуля.
Переменная среды
Выполнение Кода Перед Main
Вообще, я не любитель подобных извращений. Но чисто ради лулзов иногда интересно узнать, что так можно.
Согласно документации, «Метод Main — это точка входа в приложение C#. При запуске приложения метод Main вызывается первым.» На самом деле метод
Main
может быть не первым методом сборки, который будет выполняться при запуске приложения. Существуют различные методы, которые могут выполняться перед методом Main
.1. Статический конструктор
Статический конструктор используется для инициализации любых статических данных или для выполнения определённого действия, которое необходимо выполнить только один раз. Он вызывается автоматически перед созданием первого экземпляра или обращением к любым статическим элементам. Поэтому статический конструктор вызовется перед методом Main.
class Program2. Инициализаторы модулей
{
static Program() =>
Console.WriteLine("Program.cctor");
static void Main() =>
Console.WriteLine("Hello, World!");
}
Инициализаторы модулей позволяют библиотекам выполнять однократную инициализацию при загрузке без необходимости явного вызова пользователем чего-либо. Когда среда выполнения загружает модуль (DLL), она вызывает методы инициализации модуля перед выполнением любого кода из этого модуля.
using System.Runtime.CompilerServices;3. Стартап хуки
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");
}
Переменная среды
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Источник: https://www.meziantou.net/executing-code-before-main-in-dotnet.htm
Module Init 1
Module Init 2
StartupHook.cctor
Startup hook
program.cctor
Hello, World!
День 1140. #CodeReview
Про обзоры кода на канале было уже много постов. Найти их можно по тегу в заголовке. А сегодня, пока ютуб окончательно не заблокировали, порекомендую вам очередное видео от Дейва Пламера «The Secret Society of Code Reviewers at Microsoft»
В видео он рассказывает о том, зачем нужны обзоры кода, как они проходили в Майкрософт на заре систем контроля версий, 5 советов, как проводить обзоры кода, и 5 советов, чего не надо делать при обзорах кода.
PS: из-за скорости речи и некоторого акцента автора, понять его иногда довольно трудно. Можете поставить скорость 0,75 и включить субтитры.
Про обзоры кода на канале было уже много постов. Найти их можно по тегу в заголовке. А сегодня, пока ютуб окончательно не заблокировали, порекомендую вам очередное видео от Дейва Пламера «The Secret Society of Code Reviewers at Microsoft»
В видео он рассказывает о том, зачем нужны обзоры кода, как они проходили в Майкрософт на заре систем контроля версий, 5 советов, как проводить обзоры кода, и 5 советов, чего не надо делать при обзорах кода.
PS: из-за скорости речи и некоторого акцента автора, понять его иногда довольно трудно. Можете поставить скорость 0,75 и включить субтитры.
День 1141. #ЗаметкиНаПолях
Совместное Использование Кода Между ASP.NET и ASP.NET Core
Перенос существующего кода в ASP.NET Core часто кажется серьёзным шагом. Однако уже сегодня можно внести небольшие изменения, которые упростят переход на ASP.NET Core завтра.
Первым шагом является создание нового проекта ASP.NET Core Web App (Model-View-Controller). Этот шаблон добавит поддержку контроллеров и сопоставит маршрут по умолчанию для контроллеров в файле
Контроллеры
Многие команды хотят, чтобы новый веб-сайт работал так же, как текущий. Если вы исправляете ошибку в проекте, важно, чтобы это исправление отображалось на обоих сайтах. Один из самых простых способов обеспечить это — предоставить общий доступ к одному и тому же файлу в обоих проектах. К счастью, ASP.NET Core использует новые файлы проектов в стиле SDK. Это означает, что файл csproj легко открыть и внести некоторые изменения. Нужно создать
Модели
Для этого подойдут те же советы, что и при совместном использовании контроллеров. Также директивы препроцессора можно использовать для атрибутов:
Опять же можно использовать csproj для совместного использования файлов, таких как
Пошаговые инструкции по переносу на примере проекта MvcMusicStore приведены здесь. Там также описано, как можно запускать ASP.NET и ASP.NET Core из одного и того же пула приложений IIS для постепенной миграции вашего веб-приложения по одному контроллеру за раз.
Источник: https://devblogs.microsoft.com/dotnet/sharing-code-between-aspnet-and-aspnetcore/
Совместное Использование Кода Между 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>Теперь проект ASP.NET Core больше не компилируется. В ASP.NET Core класс Controller использует не System.Web.Mvc, а Microsoft.AspNetCore.Mvc. Это можно исправить с помощью директив препроцессора:
<Compile
Include="..HomeController.cs"
LinkBase="Controllers" />
</ItemGroup>
#if NETАналогичный код можно добавить и в других нужных местах, чтобы заставить оба проекта компилироваться. Кроме того, можно создать частичные классы и выделить крупные блоки кода в новые методы, различающиеся в разных проектах, а затем, используя csproj, включать в проект только нужные файлы.
using Microsoft.AspNetCore.Mvc;
#else
using System.Web.Mvc;
#endif
Модели
Для этого подойдут те же советы, что и при совместном использовании контроллеров. Также директивы препроцессора можно использовать для атрибутов:
#if !NETПредставления
[Bind(Exclude="Id")]
#endif
public partial class Order
{
[ScaffoldColumn(false)]
#if NET
[BindNever]
#endif
public int Id { get; set; }
…
Опять же можно использовать csproj для совместного использования файлов, таких как
_Layout.cshtml
. Внутри представления вы можете продолжать использовать директивы препроцессора:@{Аналогично можно совместно использовать статический контент (CSS, JavaScript и изображения). Также обновите все NuGet-пакеты и ваши собственные библиотеки под использование netstandard, чтобы они могли совместно использоваться в обоих проектах.
#if NET
<text>
@await
Component.InvokeAsync("CartSummary")
</text>
#else
@Html.RenderAction(
"CartSummary",
"ShoppingCart");
#endif
}
Пошаговые инструкции по переносу на примере проекта MvcMusicStore приведены здесь. Там также описано, как можно запускать ASP.NET и ASP.NET Core из одного и того же пула приложений IIS для постепенной миграции вашего веб-приложения по одному контроллеру за раз.
Источник: https://devblogs.microsoft.com/dotnet/sharing-code-between-aspnet-and-aspnetcore/
День 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/
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/
День 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
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
День 1144. #ЗаметкиНаПолях #AsyncTips
Неизменяемые стеки и очереди
Задача
Вам нужна коллекция — стек или очередь, которая изменяется не очень часто и к которой можно безопасно обращаться из нескольких потоков. Например, очередь для представления последовательности выполняемых операций, а стек — для представления последовательности операций отмены.
Решение
Неизменяемые стеки и очереди из пространства имён
Неизменяемый стек
Неизменяемая очередь
- Экземпляр неизменяемой коллекции никогда не изменяется.
- Экземпляр неизменяемой коллекции потокобезопасен по своей природе, но ссылка на него потокобезопасной не является. Переменная, ссылающаяся на неизменяемую коллекцию, нуждается в такой же синхронизационной защите, как и любая другая переменная.
- При вызове изменяющего метода для неизменяемой коллекции возвращается новая измененная коллекция.
Неизменяемые коллекции могут использоваться и в однопоточных приложениях, например для функционального кода, а также при необходимости хранить большое количество снимков коллекции, которые должны по возможности совместно использовать одну память.
Неизменяемые коллекции идеально подходят для хранения общего состояния. С другой стороны, в качестве коммуникационного канала они работают не так хорошо. В частности, неизменяемые очереди не следует использовать для передачи данных между потоками; очереди «производитель/потребитель» подходят для этой цели намного лучше.
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 9.
Неизменяемые стеки и очереди
Задача
Вам нужна коллекция — стек или очередь, которая изменяется не очень часто и к которой можно безопасно обращаться из нескольких потоков. Например, очередь для представления последовательности выполняемых операций, а стек — для представления последовательности операций отмены.
Решение
Неизменяемые стеки и очереди из пространства имён
System.Collections.Immutable
по поведению очень близки к стандартным коллекциям Stack<T>
и Queue<T>
и обладают практически такой же временной сложностью. Впрочем, в простых сценариях с частым обновлением стандартные стеки и очереди работают быстрее.Неизменяемый стек
var stack = ImmutableStack<int>.Empty;В этом примере многократно перезаписывается локальная переменная stack. Неизменяемые коллекции возвращают обновлённую коллекцию, а ссылка на исходную остаётся без изменений. Это означает, что, если имеется ссылка на экземпляр неизменяемой коллекции, она никогда не изменится:
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
var stack = ImmutableStack<int>.Empty;Во внутренней реализации два стека совместно используют память, выделенную для хранения элемента 13. Такая реализация весьма эффективна, к тому же она позволяет легко создавать снимки текущего состояния. Каждый экземпляр неизменяемой коллекции потокобезопасен по своей природе.
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);
Неизменяемая очередь
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.
День 1145. #ЗаметкиНаПолях
Использование Встроенных Файлов в dotnet core
Мы хотим прочитать файл JSON с диска. Мы не хотим полагаться на абсолютные пути к файлам, параметрам среды, копировать файлы в выходной каталог и т.п. Файл JSON выглядит следующим образом:
Использование Встроенных Файлов в 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();Источник: https://josef.codes/using-embedded-files-in-dotnet-core/
// изнутри сборки
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");