.NET Разработчик
6.5K 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
День семьсот шестьдесят шестой. #ЧтоНовенького
Что нового в Visual Studio 2019 v16.10 Preview 1
В Microsoft объявили о долгосрочной поддержке релиза Visual Studio 2019 версии 16.9, а также о выходе первой предварительной версии 16.10. О новых функциях версии 16.9 я уже писал здесь и здесь, поэтому сегодня о 16.10, где есть пара интересных новинок.

1. Удаление неиспользуемых ссылок
Добавлена возможность удалить из проекта неиспользуемые ссылки на проекты и пакеты NuGet. Это можно сделать из контекстного меню проекта «Удалить Неиспользуемые Ссылки» (Remove Unused References). По умолчанию эта возможность отключена, но её можно включить в меню Инструменты > Параметры > Текстовый редактор > C# > Дополнительно (Tools > Options > Text Editor > C# > Advanced). Отметьте команду «Удалить неиспользуемые ссылки» (Remove Unused References). После выбора этого пункта контекстного меню откроется диалоговое окно, где вы сможете просмотреть все ссылки, которые будут удалены, и отметить те, которые вы хотите сохранить. См. рис. 1 ниже.

2. Упрощение выражений LINQ
Эти подсказки рефакторинга предложат вам, например, удалить лишний вызов метода .Where(), чтобы повысить производительность и читаемость. Подсказка появляется, если поместить курсор на выражение LINQ и нажать Ctrl+. См. рис. 2 ниже.

3. Новые варианты автозавершения
IntelliSense теперь будет предлагать среди вариантов завершения значения enum, когда тип известен, даже если вы не вводите название самого перечисления. Просто начните вводить название значения, и оно появится в подсказке. См. рис. 3 ниже.

Также в меню Инструменты > Параметры > Текстовый редактор > Дополнительно (Tools > Options > Text Editor > Advanced) можно настроить режим автозавершения только по Tab, автоматически (по точке, скобке и т.п.) или по последнему сохранённому значению.

Кроме того, новая команда «Умный Перевод Строки» (Smart Break Line) автоматически вставит фигурные скобки и поставит курсор между ними при нажатии Shift+Enter после объявления названия типа, метода, свойства, события и т.п. Повторное нажатие Shift+Enter уберёт скобки и добавит точку с запятой в конце строки.

4. Настройки стилей кодирования для пустых строк
Вы можете настроить обработку пустых строк в файле EditorConfig или в меню Инструменты > Параметры > Текстовый редактор> C# > Стиль кода > Параметры новых строк (Tools > Options > Text Editor > C# > Code Style > New line preferences). Например, вы можете настроить, допустимы ли несколько пустых строк подряд, допустим ли код сразу после закрывающей фигурной скобки блока и т.п. Для каждого параметра можно настроить, будет ли он исправляться при рефакторинге или выдавать предложение, предупреждение или ошибку. См. рис. 4 ниже.

Установить Visual Studio 2019 v16.10 Preview 1

Источник: https://devblogs.microsoft.com/visualstudio/vs2019-v16-9-and-v16-10-preview-1/
День семьсот шестьдесят седьмой. #Оффтоп #ЗадачиНаСобеседовании
Давненько у нас не было задач.

Допустим, вы ищете квартиру. Для простоты представим улицу в виде одномерного массива кварталов. Пусть у нас будет только одна улица в городе, идеально прямая, а расстояния между кварталами одинаковы и равны 1.
В каждом квартале есть подходящая вам квартира. Кроме того, в кварталах случайным образом расположены важные для вас объекты: магазин, тренажёрный зал, школа для ребёнка и т.п. Допустим, что они одинаково для вас важны. Идеальная для вас квартира находится квартале с наименьшим расстоянием до самого дальнего важного объекта. Обратите внимание: не с минимальной суммой расстояний до всех объектов, а с минимальным наибольшим расстоянием! Задача – найти такой квартал.

Кварталы даны в виде массива словарей (не пугайтесь, это для наглядности, и чтобы не создавать кучи сущностей 😊). В словаре ключ – строковое название объекта, и логическое значение есть он в квартале или нет. Например, вот так:
[
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
То есть, в первом квартале нет тренажёрного зала и школы, но есть магазин. Во втором есть только тренажёрный зал. В третьем – зал и магазин. И т.д.

Таким образом, в первом квартале дальше всего идти до школы - 4. А победителем получается квартал №4. Хотя там ничего нет, но из него до всех объектов расстояние 1.

Для простоты допустим, что кварталов всегда больше одного, и во всех кварталах заданы все нужные вам объекты (которых в принципе может быть сколько угодно). А при равенстве результатов можно выдать первый.

На этот раз у меня для вас есть даже шаблон проекта с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinder
Всё, что вам надо сделать – реализовать метод Find(), принимающий массив кварталов и возвращающий индекс идеального квартала.

Вопросы и предложения оставляйте в комментариях. Через пару дней выложу решение с объяснением.
День семьсот шестьдесят восьмой. #ЗаметкиНаПолях
Обнуляемый null
Рассмотрим следующий код:
public class Person {
public string FirstName { get; }
public string LastName { get; } = null!;
public string? MiddleName {get; } = null;

public Person (string first,
string last, string? middle) {
FirstName = first;
LastName = last;
MiddleName = middle;
}
}

Что значит null! ?
Раньше оператор ! означал отрицание в логических выражениях. Но начиная с C#8 в языке допустимо использование обнуляемых ссылочных типов. Поэтому оператор ! приобрёл другое значение и стал называться null-снисходительным (null-forgiving).

Свойство MiddleName обнуляемое (string?), т.к. у человека может не быть отчества. Тогда:
Console.WriteLine(person.MiddleName.Length);
выдаст предупреждение, что MiddleName может быть null, а
Console.WriteLine(person.MiddleName!.Length);
не выдаст предупреждения из-за null-снисходительного оператора.

Таким образом программист сообщает компилятору, что он уверен, что здесь значение переменной не будет null.

Можно рассматривать операторы ? и ! как приведение типов
? = из необнуляемого в обнуляемый
! = из обнуляемого в необнуляемый

Например:
string? x;
? делает из необнуляемого string обнуляемый тип, поэтому можно использовать x = null.

string y;
Здесь y = null приводит к предупреждению компилятора, из-за присваивания null необнуляемому типу. Аналогично y = x приведёт к предупреждению, т.к. x может быть null. Однако y = x! не вызовет предупреждения, т.к. мы «гарантируем», что x не null.

ВНИМАНИЕ: оператор ! отключает только проверку компилятора на уровне системы типов. Во время выполнения значение может быть null. Поэтому использование null-снисходительного оператора может быть признаком плохого дизайна системы, поскольку он сводит на нет все усилия проверки на null-безопасность, которую выполняет компилятор.

Использование оператора ! может создать очень трудные для поиска ошибки. Если у вас есть свойство, помеченное как необнуляемое, предполагается, что его можно использовать безопасно. Но во время выполнения вы можете неожиданно столкнуться с исключением NullReferenceException, поскольку значение фактически стало null из-за обхода проверок компилятора с помощью оператора !.

Зачем тогда он нужен?
Существуют допустимые варианты использования, в которых использование является целесообразным:
- В некоторых (редких) случаях компилятор не может определить, что обнуляемое значение на самом деле не может быть null.
- Для упрощения миграции старого кода, не использовавшего обнуляемые ссылочные типы.
- В некоторых случаях вас просто не волнует, что что-то будет null.
- В тестах для проверки поведения кода при получении null.

Так что же такое null! ?
null! сообщает компилятору, что null не допускает значения null. Странно, правда? Но это то же самое, что и x! из примера выше. Литерал null допускает значение null по определению. Но, как мы узнали, обнуляемость любого типа можно переопределить с помощью оператора !.

Систему типов не волнует фактическое значении переменной во время выполнения. Её заботит только тип переменной времени компиляции. И в исходном примере свойство LastName (null!) не допускает значения null, что допустимо для системы типов.

Источник: https://stackoverflow.com/questions/54724304/what-does-null-statement-mean
День семьсот шестьдесят девятый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
79. Используйте Анализаторы Кода
Ценность тестирования - вот что вбивают в головы разработчикам ПО с ранних этапов их пути в программировании. В последние годы рост модульного тестирования, разработки, основанной на тестировании, и agile методов свидетельствует о всплеске интереса к максимальному использованию тестирования на всех этапах цикла разработки. Однако тестирование - это лишь один из многих инструментов, которые можно использовать для улучшения качества кода.

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

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

Более сложные инструменты, такие как Splint для C, Pylint для Python или анализаторы Roslyn для .NET настраиваются. То есть вы можете выбрать, какие ошибки и предупреждения будет выдавать инструмент, с помощью файла конфигурации, в командной строке или в вашей IDE. В некоторых случаях можно писать аннотации для анализатора прямо в коде.

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

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Sarah Mount
День семьсот семидесятый. #Оффтоп #ЗадачиНаСобеседовании
Ответ на задачу про поиск квартиры.

Создадим двумерный массив для хранения расстояний. В строках будут кварталы, в столбцах объекты. При этом, если объект присутствует в квартале, отметим соответствующее расстояние как 0, если нет, для начала отметим его недостижимо большим значением, например, 999999 (ниже буду использовать *). Таким образом, для примера из задачи:
[
{{"gym",false},{"school",false},{"store",true}},
{{"gym",true },{"school",false},{"store",false}},
{{"gym",true },{"school",false},{"store",true}},
{{"gym",false },{"school",false},{"store",false}},
{{"gym",false },{"school",true},{"store",true}}
]
Первый квартал будет
1: * * 0

Теперь проходим вдоль массива кварталов. Если соответствующий объект есть, заполняем ячейку нулём, в противном случае заполняем её значением на 1 больше, чем в предыдущем квартале. Например, во втором квартале объект "store" будет иметь значение 1. Большие значения нас пока не интересуют, там будет значение <очень много>+1 (оставим их как *). Тогда второй квартал будет:
2: 0 * 1
И так далее:
3: 0 * 0
4: 1 * 1
5: 2 0 0

Теперь проходим массив кварталов обратно. На этом этапе:
1. Задаём значение расстояния как минимальное между существующим значением и значением на 1 больше, чем в предыдущем квартале. То есть, если, проходя в одну сторону, мы получили расстояние до объекта в 3 квартала, но он находится в следующем квартале, то, проходя в обратную сторону, мы зададим минимальное расстояние между 3 и 1 – 1. Аналогичным образом мы заменим все большие значение, обозначенные *.
2. Кроме того, рассчитав все расстояния в квартале, считаем максимальное из них.

5: 2 0 0 (макс: 2)
4: 1 1 1 (макс: 1)
3: 0 2 0 (макс: 2)
2: 0 3 1 (макс: 3)
1: 1 4 0 (макс: 4)

И, наконец, из максимальных значений выбираем наименьшее – 1 в 4м квартале.

Таким образом, нам нужно дважды пройти массив кварталов, в каждом перебрать все объекты. Если количество кварталов взять за M, количество объектов – за N, то сложность решения по времени O(2*M*N), сложность по памяти – O(M*(N+1)).

Код решения с тестами: https://github.com/sbzenenko/NetDeveloper/tree/main/ApartmentFinderSolution

PS: есть ещё нахождение максимума по N и минимума по M, которые сами по себе добавляют O(logM) и O(logN) по времени, но их можно находить параллельно с обратным прохождением массива.

Источник: https://youtu.be/rw4s4M3hFfs
День семьсот семьдесят первый. #ЧтоНовенького
Что Нового в EF Core 6 Preview 1
Ниже описаны некоторые из основных нововведений в предварительной версии EF Core 6.

1. Атрибут Unicode
Строковое свойство теперь можно сопоставить со столбцом, не поддерживающим Юникод:
[Unicode(false)]
public string Isbn { get; set; }
Поскольку номер ISBN не может содержать не-юникод символы, атрибут сообщит СУБД, что можно использовать не-юникод строку. Например, в SQL Server будет использован varchar вместо nvarchar.

2. Атрибут Precision
Теперь можно задать точность поля базы данных, указав количество цифр всего и после запятой, не используя непосредственно тип данных, поддерживаемый СУБД:
[Precision(precision: 10, scale: 2)]
public decimal Price { get; set; }

3. Атрибут EntityTypeConfiguration
Атрибут позволяет определять класс конфигурации сущности, позволяя вынести конфигурацию в отдельный класс, а не помещать её всю в OnModelCreating.
[EntityTypeConfiguration(typeof(BookConfiguration))]
public class Book {…}

При этом класс конфигурации должен реализовывать IEntityTypeConfiguration<T>:
public class BookConfiguration : 
IEntityTypeConfiguration<Book> {…}
ПРИМЕЧАНИЕ. Типы, помеченные атрибутом EntityTypeConfiguration не будут автоматически обнаруживаться в сборке. Типы сущностей должны быть явно добавлены в контекст EF.

4. EF.Functions.Random
EF.Functions.Random соответствует функции СУБД, возвращающей псевдо-случайное число от 0 до 1. Реализации уже готовы для SQL Server, SQLite, и Cosmos.

5. Проверка на null обязательных полей в in-memory базе
In-memory база данных теперь будет выбрасывать исключение при попытке сохранить null в свойстве, помеченном, как обязательное (например, атрибутом Required).
Эта проверка может быть отключена при необходимости:
….UseInMemoryDatabase("…")
.EnableNullabilityCheck(false);

Источник: https://devblogs.microsoft.com/dotnet/announcing-entity-framework-core-6-0-preview-1/
День семьсот семьдесят второй. #ЗаметкиНаПолях
Автоматическая Жадная Загрузка Навигационных Свойств в EF Core
Обычно при загрузке навигационных свойств в EF Core вы вынуждены использовать метод Include, чтобы указать, какие навигационные свойства нужно вернуть в запрос. Это очень хорошая практика явно указывать, какие данные вам на самом деле нужны.

Например, допустим, что у нас есть есть два класса: контакт и его email адреса.
class Contact {
public int Id { get; set; }
public string Name { get; set; }
public ICollection ContactEmails { get; set; }
}
class ContactEmail {
public int ContactId { get; set; }
public Contact Contact { get; set; }
public string Email { get; set; }
}

При использовании подхода Code First это навигационное свойство будет без проблем обработано на основе соглашений. При запросе контактов, если бы мы хотим сразу получить и ContactEmails, нам пришлось бы написать что-то вроде этого:
_context.Contact.Include(x => x.ContactEmails)
.FirstOrDefault(x => x.Id == myContactId);
Это называется жадной загрузкой, потому что мы с сразу загружаем email адреса контактов, например, чтобы вернуть их пользователю или использовать где-нибудь еще в нашем коде.

Но что, если мы уверены, что каждый раз, когда мы загружаем контакты, нам сразу нужны их email адреса? Мы уверены, что никогда не будем использовать контакты без email адресов. Часто это характерно для навигационных свойств один-к-одному. Но даже в этом примере, возможно, везде, где мы показываем контакт, нам также нужно показать и его email’ы, поскольку они являются неотъемлемой частью модели.

Настройка AutoInclude
До EF Core 5 у вас действительно не было выбора, кроме как постоянно использовать Include. Однако сейчас ситуация поменялась, появилась функция AutoInclude:
builder.Navigation(x => x.ContactEmails).AutoInclude();

Строитель навигации используется довольно редко, поэтому не все знают о его возможностях. И стоит упомянуть, что AutoInclude() нельзя использовать на конфигурациях вроде HasOne() или HasMany(), он должен быть настроен обособленно, как в примере выше.

Вот и всё. Теперь каждый раз при получении данных Contacts их свойство ContactEmails будет заполнено без использования Include.

Игнорирование AutoInclude
Конечно, бывают случаи, когда вы настроили AutoInclude, а затем вам нужно написать запрос, не включающий навигационное свойство. К счастью, для этого есть хорошее расширение IQueryable:
_context.Contact.IgnoreAutoIncludes()
.FirstOrDefault(x => x.Id == myContactId);
Так мы можем отписаться от получения навигационного свойства, и не запрашивать из базы больше данных, чем нам нужно.

Источник: https://dotnetcoretutorials.com/2021/03/07/eager-load-navigation-properties-by-default-in-ef-core/
День семьсот семьдесят третий. #ЧтоНовенького
Прекращение Поддержки .NET Core 2.1
Поддержка .NET Core 2.1 будет прекращена 21 августа 2021 года. После этой даты Microsoft прекратит обновления (включая исправления безопасности) и поддержку этой версии. Необходимо обновить вашу версию .NET Core до поддерживаемой (.NET Core 3.1 или .NET 5.0) до этой даты.

Когда поддержка .NET Core 2.1 прекратится, приложения, использующие эту версию, продолжат работу. При этом обновления безопасности для .NET Core 2.1 начиная с сентября 2021 года выпускаться не будут, в отличие от .NET Core 3.1 и .NET 5.0. То есть .NET Core 2.1 может стать потенциально небезопасной средой.

Обновление приложений
Если ваше приложение использует NET Core 2.1, Microsoft настоятельно рекомендует перенести его на поддерживаемую версию - .NET 3.1 или более позднюю, которые можно скачать с веб-сайта .NET.

Обновление до .NET Core 3.1
Откройте файл проекта (файл *.csproj, *.vbproj или *.fsproj).
Измените значение целевой платформы с netcoreapp2.1 на netcoreapp3.1. Целевая платформа определяется элементом <TargetFramework> или <TargetFrameworks>.
Например, измените
<TargetFramework>netcoreapp2.1</TargetFramework>
На
<TargetFramework>netcoreapp3.1</TargetFramework>.

Проверить установленные на компьютере версии .NET можно, выполнив команду:
dotnet --list-runtimes

Если вы используете Visual Studio 2017 15.9, то у вас также может быть установлен .NET Core 2.1 в качестве обязательного компонента (см. рисунок ниже). Начиная с обновления 15.9.34 в марте 2021 года, компонент .NET Core 2.1 в Visual Studio будет изменен с обязательного на рекомендуемый. Когда поддержка .NET Core 2.1 прекратится, Visual Studio 2017 15.9 будет обновлена и .NET Core 2.1 станет необязательным. То есть различные рабочие нагрузки (Workload) в Visual Studio можно будет установить без установки .NET Core 2.1. При этом существующие установки не будут затронуты. Рабочие нагрузки и компоненты останутся установленными до тех пор, пока не будут явно удалены в установщике Visual Studio. Хотя у вас сохранится возможность установить компонент .NET Core 2.1, настоятельно рекомендуется использовать .NET Core 3.1 или .NET 5.0 с Visual Studio 2019 для создания приложений.

Источник: https://devblogs.microsoft.com/dotnet/net-core-2-1-will-reach-end-of-support-on-august-21-2021/
День семьсот семьдесят четвёртый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
80. Проверяйте Требуемое, а не Случайное Поведение
Распространённая проблема тестирования - предположение, что реализация делает именно то, на что вы хотите проверить. На первый взгляд, это скорее хорошо, чем плохо. Однако проблема становится очевидной, если перефразировать это предложение: распространённая ошибка при тестировании заключается в привязке тестов к особенностям реализации, когда эти особенности являются случайными и не имеют отношения к желаемой функциональности.

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

Например, для метода CompareTo(object obj) интерфейса IComparable, требования к результату заключаются в том, что:
- он отрицательный, если экземпляр класса стоит по порядку раньше, чем объект, переданный в аргументе метода,
- он положительный, если экземпляр класса стоит позже,
- он равен нулю если объекты считаются равными.
Этот стиль сравнения используется во многих API, включая компаратор для функций сортировки. И хотя конкретные значения –1 и +1 обычно используются в реализациях для обозначения отрицательного и положительного результатов, соответственно, программисты часто ошибочно предполагают, что эти значения и представляют фактическое требование, и, следовательно, пишут тесты, которые публично подтверждают это предположение.

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

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

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

Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Kelvin Henney
День семьсот семьдесят пятый. #ЧтоНовенького
Новое Динамическое Инструментальное Профилирование для .NET
С выпуском Visual Studio версии 16.9 инструменты профилирования в Visual Studio стали ещё лучше. Новый инструмент динамического инструментального профилирования показывает точное количество вызовов ваших функций и работает быстрее, чем его предшественники. Он также поддерживает инструментарий .NET Core без использования файлов PDB.

Вы можете получить доступ к инструменту динамического профилирования, запустив профилировщик производительности для проекта .NET в Visual Studio (Debug > Performance Profiler или Alt+F2). В открывшейся вкладке отметьте флажок рядом с блоком Instrumentation. См. видео.

В профилировании существует два метода сбора данных: instrumentation (инструментальный) и sampling (метод выборки). В инструментальном профилировании каждый вызов функции в вашем приложении аннотируется, поэтому при вызове метод добавляется в трассировку вместе с информацией о вызывающем коде. При методе выборки текущий стек выполнения извлекается из ЦП в определённые интервалы времени, а затем каждый такой «кадр» добавляется к трассировке.

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

Новый сценарий динамического инструментального профилирования даёт ещё несколько преимуществ.

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

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

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

Источник: https://devblogs.microsoft.com/visualstudio/new-dynamic-instrumentation-profiling/
День семьсот семьдесят шестой.
Будни программиста
Сегодня будет не совсем про программирование. Сегодня история личной боли (или тупости, вам решать). Я уже писал в нашем чате пару дней назад, что винда предложила под угрозой прекращения поддержки обновиться до версии 20H2. Что в этой версии такого революционного, я так и не понял. Но в выходные потратил 3,5 часа на обновление домашнего ноута. Наивный я думал, что вечером в понедельник быстренько обновлю новенький рабочий ноут, а потом подготовлю статью для канала.

Собственно обновление то действительно прошло быстрее (около часа), зато потом началось сплошное веселье. То, что перестало работать гнездо для наушников (к которому у меня перманентно подключены колонки) или что исчезла панель быстрого доступа слева в проводнике – это мелочи, на которые я даже не обращаю внимания. Старый добрый Майкрософт в своём репертуаре. Это я быстро восстановил.

Гораздо больше радости доставил отвалившийся Microsoft Loopback Adapter, к которому были подключены 2 виртуальные машины VirtualBox (машина для разработки и машина чисто с оракловской базой). Они через этот адаптер ноута по VirtualBox Bridged Adapter были связаны друг с другом.
- Не беда, - подумал я, - сейчас переустановлю Loopback адаптер, и всё ок.
- А вот хрен там, - ответила винда.

Для начала сам Loopback адаптер стал показывать «Undefined network». Я в принципе редко в него лазил, и не представлял, что он должен в нормальном состоянии показывать. Всё-таки, он тестовый, может неопределённая сеть для него – это нормально. Однако машины наотрез отказывались соединяться хоть с чем-нибудь, поэтому пришлось гуглить. Нашёл вот такое решение. Оооо… ручная правка реестра, как я по ней скучал!

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

После трёх часов тыкания в разные настройки машин, хоста и VirtualBox, ближе к 10 вечера, решил написать начальнику (благо, у него в штатах день только начинался). У него ровно те же виртуалки и почти такой же рабочий ноут. Скопировали все его настройки до запятой – нифига. Стали пробовать пинговать по IPv6 – нифига. Тут, кстати, стоит оговориться, что ораклу для подключения нужна сеть 10.x.x.x, поэтому все адаптеры были настроены на статические IPv4 и отдельную подсеть только для этих двух виртуалок. У виртуалки для разработки есть отдельное подключение для интернета, оракловой виртуалке интернет не нужен, поэтому у неё только одно подключение по мосту к другой виртуалке.

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

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

Вот теперь вопрос, ибо мне самому интересно. Это я настолько туп (хотя, повторюсь, не сисадмин совсем)? Может вы сразу поняли, в чём было дело?

Напомню вкратце:
Рабочий ноут, в нём 2 виртуалки VirtualBox, соединённые по Bridged Adapter между собой, используя Microsoft Loopback Adapter ноута. До обновления винды на ноуте всё работало, потом перестало. Соединения в виртуалках настроены на статические IP в сети 10.x.x.x. Одна виртуалка с базой данных видит вторую, но не видит ноут. Вторая видит ноут, но не видит виртуалку с базой (а именно это соединение и требуется).

UPD: Видимо, всё же я тупой, т.к. в комментариях уже через 15 минут предложили правильный вариант. Да, чудил файрвол в оракловой виртуалке. Каким-то макаром после всех манипуляций с Loopback адаптером на ноуте, сеть в оракловой виртуалке из приватной стала публичной. А для публичных сетей файрвол блокировал все попытки внешних подключений. Вот, кстати, вдруг кому пригодится, как изменить тип сети обратно на приватную.
День семьсот семьдесят седьмой. #юмор
Да, очень похоже на правду.
А ещё вдогонку вам на сегодня свежее видео от ExtremeCode на смежную тему)))
День семьсот семьдесят восьмой. #DeveloperPath
Новости проекта «Путь Разработчика»
О проекте

Наивно полагал, что новости проекта буду писать каждую неделю. Но немножко задержался (почти на 4 месяца). Однако за это время проект не только не умер, но и вполне себе развивался.

1. UI проект заменён на Blazor. Никаких больше node модулей! Всё собирается и запускается гораздо быстрее.
2. Основная часть API допилена и работает (можно потестить через Swagger UI).
3. Сергей Трофимов @trofimov_serhii разрабатывает Identity в отдельном проекте.
4. Проект «выложен» на Azure, и сайт даже можно открыть здесь https://developerpath.azurewebsites.net Правда, ничего полезного вы там всё равно не увидите)))

С выкладыванием возникла проблема. Поскольку опыта в развёртывании у меня примерно никакого, я пошёл самым простым путём. В Deployment Center можно было просто привязать репозиторий GitHub, и Azure через GitHub Actions как-то автоматом мог сайт развернуть. Оказалось, что не всё так просто. Решение вроде как даже скомпилировалось в dll-ки и выложилось. Но по ссылке показывается только стандартная страница. В общем, срочно нужен девопс помочь правильно «развернуться».

Однако задачи найдутся для самых разных специалистов. Если кто-то хочет поковыряться в .NET 5, C#9, Blazor, паттерне CQRS, или даже веб-дизайне, милости просим.

Проект всё также на Azure DevOps:
https://dev.azure.com/sbenzenko/DeveloperPath/
Он открытый, поэтому посмотреть, почитать можно и без регистрации. Авторизованные через аккаунт Microsoft или GitHub могут оставлять комментарии или добавиться в команду. Если вы ещё не в команде, пишите в личку или в комментарии свой e-mail, я вас приглашу.

Я добавил «парочку» тасок, которые можно посмотреть здесь. Все они делятся на:
- Epic (с короной) - глобальные задачи.
- Task (с жёлтой галочкой) – простые задачи на разработку.
- Issue (с зелёной планшеткой) – по задумке должны быть чем-то средним между Epic и Task. Пока особо не используются, считайте их теми же, что Task.

Задачи Epic представляют глобальные направления в разработке проекта: Архитектура, API, UI, Развёртывание, Документация, Тесты и т.п. Они «содержат» в себе задачи Task и Issue. Поэтому, кому интересно поучаствовать, можете присмотреть задачу по душе из тех, что в статусе «To Do» и взять её на себя.

Задачи помечены тегами по направлениям:
- Architecture – разработка проектов и модулей,
- Development – разработка отдельных фич,
- Design – разработка пользовательского интерфейса,
- Deployment – всё, что связано с развёртыванием,
- Bug – исправление ошибок или недоделок,
- Testing – все вопросы тестирования,
- Documentation – создание документации (как описание проекта, так и заметки по особенностям установки или работы).

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

По всем вопросам добро пожаловать в комментaрии сюда, либо в проект на Azure DevOps.
День семьсот семьдесят девятый. #ЗаметкиНаПолях #SQL
Выражение WITH и Сложные Запросы
В разработке ПО обычной практикой является инкапсуляция инструкций в небольшие и легко понятные единицы - функции или методы. В SQL мы оперируем не инструкциями, а запросами. Чтобы сделать запросы многоразовыми, в SQL-92 были введены представления (view). После создания представление получает имя в схеме базы данных, чтобы другие запросы могли использовать его как таблицу. В SQL-99 добавлено предложение WITH для определения «представлений в области действия оператора». Они не хранятся в схеме базы данных, а живут только в рамках текущего запроса. Это позволяет улучшить структуру запроса, не загрязняя глобальное пространство имен. Предложение WITH также известно как общее табличное выражение (CTE).

Синтаксис
WITH query1 (column1, …) AS
(SELECT … FROM table …)
SELECT * FROM query1;

WITH не является самостоятельной командой, за ним должен следовать SELECT. Запрос SELECT (и содержащиеся в нем подзапросы) могут ссылаться в своём блоке FROM на определённое в предложении WITH имя подзапроса.

Одно предложение WITH может определять несколько имён подзапросов, разделяя их запятыми. Каждый из этих подзапросов может ссылаться на ранее определённые имена подзапросов:
WITH 
query1 AS (SELECT …),
query2 AS (SELECT … FROM query1 …)
SELECT …

ВАЖНО! Имена подзапросов, определённые в предложении WITH скрывают таблицы или представления с тем же именем.

СУБД
Базовая функциональность предложения WITH доступна во всех современных СУБД.

Производительность
- Большинство баз данных обрабатывают WITH-запросы так же, как и представления: они заменяют ссылку на запрос его определением и оптимизируют общий запрос.
*PostgreSQL до версии 12 оптимизировала каждый подзапрос и главный запрос независимо друг от друга.
- Если WITH-запрос упоминается несколько раз, некоторые базы данных кешируют его результат, чтобы предотвратить двойное выполнение.

Полезные расширения
1. WITH как префикс DML запроса (PostgreSQL, SQL Server, SQLite)
Некоторые СУБД позволяют использовать WITH не только с запросами SELECT, но и с запросами на манипуляцию с данными (INSERT, UPDATE, DELETE).

2. WITH как цель DML (SQL Server)
SQL Server также позволяет использовать WITH-запрос как цель DML запроса, то есть создавать обновляемые представления.

3. Функции в WITH (Oracle)
Oracle, начиная с версии 12cR1 позволяет определять функции и процедуры в предложении WITH.

4. DML в WITH (PostgreSQL)
Начиная с версии 9.1 PostgreSQL поддерживает использование DML запросов внутри предложения WITH. А при использовании выражения RETURNING, предложение WITH возвращает данные в основной запрос. Таким образом, например, можно сделать запрос к только что вставленным в таблицу записям:
WITH added AS (
INSERT INTO table1 …
RETURNING *
)
SELECT * FROM added;

Источник: https://modern-sql.com/feature/with
День семьсот восьмидесятый. #Оффтоп #ЗадачиНаСобеседовании
Доброй субботы, дорогие друзья. Новая задачка вам на выходной день. На этот раз никаких Big O, никаких сложных алгоритмов и оптимизаций. Просто на смекалку.

Задача максимально короткая:
С помощью генератора случайных чисел, выдающего значения от 0 до 1, вычислите число пи.

Внезапно?)))

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