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

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1874. #ЗаметкиНаПолях
Структура Данных Куча и Очередь с Приоритетом в .NET. Начало

В .NET термин «куча» обычно используется при обсуждении управления памятью. Но сегодня мы рассмотрим, что такое структура данных куча, чем она полезна и как используется в типе PriorityQueue в .NET.

Куча — это структура данных, которая обычно представляется в виде дерева и удовлетворяет следующим правилам:
- Минимальная куча — для каждого узла в дереве значение узла меньше (или равно) значений его дочерних элементов.
- Максимальная куча — для каждого узла в дереве значение узла больше (или равно) значений его дочерних элементов.
На рисунке ниже показана визуализация минимальной кучи, включая некоторые термины. Куча на рисунке - двоичная, (каждый узел имеет до два дочерних). Также говорят, что арность кучи 2.

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

Кучи обычно реализуются как массивы, в которых каждый элемент представляет узел кучи. Позиция определяет связь между узлами, как показано на рисунке ниже. Здесь:
- Элемент с индексом 0 - корневой. В минимальной куче это минимальное значение в куче.
- Элементы 1 и 2 - дочерние корневого.
- 3 и 4 - дочерние элемента 1, 5 и 6 — дочерние элемента 2 и т. д.

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

В качестве примера рассмотрим тип PriorityQueue, появившийся в .NET 6:
// добавляем элементы с разным приоритетом
var q = new PriorityQueue<string, int>([
("A", 15), ("B", 7), ("C", 23), ("D", 2), ("E", 22)
]);

// выбираем элементы в порядке приоритета
while (q.TryDequeue(out var elem, out var priority))
Console.WriteLine($"{elem}: {priority}");

// Вывод
// D: 2
// B: 7
// A: 15
// E: 22
// C: 23

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

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

Источник:
https://andrewlock.net/an-introduction-to-the-heap-data-structure-and-dotnets-priority-queue/
👍11
День 1875. #ЗаметкиНаПолях
Структура Данных Куча и Очередь с Приоритетом в .NET. Окончание

Начало

Согласно документации, тип PriorityQueue в .NET использует «четвертичную минимальную кучу на основе массива». Т.е. каждый узел в куче имеет 4 дочерних элемента.

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

PriorityQueue в .NET имеет множество методов, типичных для реализации очереди с приоритетом:
// создание с одновременным «упорядочиванием» в кучу
var queue = new PriorityQueue<string, int>([
("A", 15), ("B", 7), ("C", 23), ("D", 2), ("E", 22)
]);

// Поиск минимального элемента без извлечения
string peek = queue.Peek(); // "D"

// Извлечение минимального элемента
// Это приводит к удалению корня, поэтому
// куча должна быть «пересортирована»
string dequeue = queue.Dequeue(); // "D"

// Добавление элемента с приоритетом
// Скорее всего приводит к «пересортировке»
queue.Enqueue(element: "F", priority: 42);

// Добавление нескольких элементов
queue.EnqueueRange([("G", 3), ("H", 13)]);

// Одновременное извлечение и добавление нового элемента
// Т.к. для каждой операции требуется «пересортировка», это более эффективно, чем последовательный вызов Dequeue() и Enqueue()
string deque1 =
queue.DequeueEnqueue("I", 19); // "G"


// И наоборот
string deque2 =
queue.EnqueueDequeue("J", 31); // "H"


PriorityQueue имеет несколько других вспомогательных методов для контроля ее работы:
// Выдаёт элементы, не учитывая приоритет, позволяя их перечислить
var unordered = queue.UnorderedItems;

// Количество элементов
var count = queue.Count;

// Очистка очереди
queue.Clear();

// Позволяет задать компаратор для приоритета. По умолчанию это минимальная куча, следующий код создаёт максимальную кучу
var inverse = Comparer<int>
.Create((a, b) => 0 - a.CompareTo(b));
var maxQueue =
new PriorityQueue<string, int>(inverse);

// Уменьшает ёмкость массива, лежащего в основе кучи,
// если новая ёмкость меньше 90% от текущей
queue.TrimExcess();


Источник: https://andrewlock.net/an-introduction-to-the-heap-data-structure-and-dotnets-priority-queue/
👍4
День 1876. #Курсы
Изучаем ИИ в .NET 8 с помощью Новых Руководств
Если вы думали о том, чтобы внедрить в свои .NET-приложения искусственный интеллект и большие языковые модели (LLM), сейчас самое время. Microsoft предлагают новые краткие руководства, которые помогут вам.

Недавно выпущены несколько кратких руководств с практическими примерами приложений, которые вы можете использовать с большими языковыми моделями от OpenAI (скоро появятся и другие модели):
- Саммари текста
- Построение приложения чата
- Анализ данных в ИИ-чате
- Azure функция с ИИ
- Генерация изображений

Каждое из них по шагам знакомит вас с кодом, необходимым для выполнения этой темы, с использованием Azure OpenAI SDK. Скоро мы также будут добавлены версии этих примеров с использованием Semantic Kernel SDK.

Если ChatGPT, LLM, модели и OpenAI — это новые для вас термины или вы только начинаете работать в этой области, вот несколько дополнительных ресурсов, которые вы можете использовать, чтобы помочь изучить основные концепции:
- Get started with OpenAI in .NET – Об использовании OpenAI в .NET.
- Get started with OpenAI Completions with .NET – Введение в завершения с помощью OpenAI: ответы, генерируемые такой моделью, как GPT.
- Level up your GPT game with prompt engineering – Введение в запросы к ИИ, как их усовершенствовать и получать более релевантные результаты.
- Get started with ChatGPT in .NET - Описывает, что такое ChatGPT, а также основные понятия, такие как роли и история чата.
- Плейлист видео: Generative AI with .NET for Beginners

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

Источник: https://devblogs.microsoft.com/dotnet/get-started-with-dotnet-ai-quickstarts/
День 1877. #ЧтоНовенького
Garnet — Быстрое Хранилище Кэша с Открытым Кодом

Исследователи Microsoft уже почти десять лет работают над механизмами хранения данных для поддержки быстрого развития интерактивных веб-приложений и сервисов. Новая система хранения кэша Garnet, которая предлагает ряд преимуществ по сравнению с другими хранилищами кэша, была развернута в нескольких сервисах в Microsoft, например, в платформе Windows & Web Experiences, Azure Resource Manager и Azure Resource Graph, а также теперь доступна для загрузки.

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

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

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

Garnet
В Microsoft Research работу над базой данных «ключ-значение» начали в 2016 году, тогда она называлась FASTER. С 2021 года, основываясь на требованиях сценариев использования, в Microsoft начали создавать новое удаленное хранилище кэша со всеми необходимыми функциями – Garnet.

Преимущества
1. Использует популярный протокол RESP, что позволяет использовать Garnet из немодифицированных клиентов Redis, доступных сегодня в большинстве языков программирования.
2. Предлагает гораздо лучшую масштабируемость и пропускную способность благодаря множеству клиентских подключений и небольшим пакетам, что приводит к экономии затрат для крупных приложений и сервисов.
3. Меньшие задержки на 99-м и 99,9-м процентилях, что имеет решающее значение для реальных сценариев.
4. Кроссплатформенный, расширяемый и современный. Cпроектирован таким образом, чтобы под него можно было легко разрабатывать ПО без ущерба для производительности. Благодаря использованию .NET, обеспечивает высочайшую производительность как в Linux, так и в Windows.

Возможности
1. Широкий спектр API, включая необработанные строки, аналитические и объектные операции, описанные ранее.
2. Режим кластера с сегментированием, репликацией и динамической миграцией ключей.
3. Транзакции RESP на стороне клиента и хранимые процедуры на стороне сервера на C#, что позволяет пользователям определять собственные операции как с необработанными строками, так и с новыми типами объектов.

Производительность
Судя по тестам в созданной Microsoft (sic!) утилите Resp.benchmark, Garnet превосходит конкурентов по производительности. Подробности можно найти здесь.

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

Источник: https://www.microsoft.com/en-us/research/blog/introducing-garnet-an-open-source-next-generation-faster-cache-store-for-accelerating-applications-and-services/
👍16
День 1878. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 1. Если вы неверно определили требования, неважно, как хорошо вы выполните остальную часть работы
IT-отдел взялся за создание новой информационной системы для своей компании. Разработчики считали, что прекрасно понимают требования и без опроса пользователей. Однако реакция пользователей на готовую систему была: «А если серьезно, где наше приложение?» Они категорически забраковали систему. Отказ от взаимодействия с пользователями, которое помогает убедиться в правильном понимании требований, был серьёзным упущением. Разработчики в итоге переделали систему, на этот раз внимательно прислушиваясь к пользователям. Это был дорогой урок о важности участия клиента в составлении требований.

Требования — это фундамент для всей последующей работы над проектом. Многочисленные исследования показали, что эффективная разработка и своевременное информирование о требованиях являются решающими факторами успеха любого проекта. И наоборот, неадекватное ви́дение проекта, неполные и неточные требования, а также меняющиеся требования и цели проекта — частые причины неудачи. При отсутствии качественной проработки требований заинтересованные стороны могут удивиться тому, что предлагает команда разработчиков. Такие программные сюрпризы часто оказываются неприятными.

Когда?
Нереально иметь полный набор требований перед началом реализации. Всегда будут появляться новые идеи, изменения и исправления, которые вы должны учитывать в своих планах развития. Но для любой части системы, которую вы создаёте, необходимо иметь как можно более полные и правильные требования. Либо планируйте доработку после окончания реализации. В проектах, практикующих Agile, предусмотрен дополнительный этап проверки требований. Чем дальше первоначальные требования от того, что действительно нужно клиентам, тем больше доработок понадобится. Учитывая, что всегда можно что-то добавить, вы никогда не сможете идеально выполнить требования. Но оговорённый объём разработки требует, чтобы вы сделали всё правильно, иначе успеха не видать.

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

Как?
Ничто не заменит постоянного взаимодействия с клиентами. Нельзя просто провести встречу в самом начале, а затем сказать клиентам: «Мы позвоним вам, когда закончим». В идеале команда должна быть на связи с представителями клиентов на протяжении всего времени разработки проекта. У разработчиков будет много вопросов и моментов, требующих уточнения.

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍13
День 1879. #Оффтоп
Сегодня порекомендую вам очередное виде с ютуба, а также канал ThePrimeTime. Честно говоря, не смог найти подробной информации об авторе. Знаю только, что он работает в Netflix. Стек у него не .NET, но и в своих видео он мало касается какой-то определённой технологии, больше рассуждает об общих проблемах разработки.

Одно из последних его видео, которое мне понравилось, на самом деле, реакция на видео с канала Awesome (тоже про разработку). Видео называется The Harsh Reality of Good Software (Жёсткая Реальность Хорошего ПО).

В двух словах. Всем плевать, сколько вы потратили времени на ПО, какой красивый и хорошо структурированный у вас код и т.д., и т.п. Программе достаточно сломаться 1 раз у конечного пользователя – и ваше ПО оценивается как говно. Несмотря на всё это, нам надо создавать хорошее ПО. И прочие рассуждения на тему чистого и читаемого кода.

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

Наслаждайтесь (потребуются навыки английского, либо автосубтитры)
https://youtu.be/NiljDyzAOcI

PS: не знал про американские горки в Excel. Это великолепно!!!
👍18
День 1880. #ЧтоНовенького
.NET Smart Components

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

.NET Smart Components находятся на этапе эксперимента и пока доступны для страниц Blazor, MVC и Razor с .NET 6 и более поздних версий. Также планируется предоставить компоненты для других инфраструктур .NET, таких как .NET MAUI, WPF и Windows Forms.

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

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

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

Примеры
Демонстрацию работы .NET Smart Components можно посмотреть в этом видео. А попробовать их в Blazor или MVC/RazorPages, используя примеры приложений смарт-компонентов .NET на GitHub.
Для работы .NET Smart Components потребуется развернуть серверную часть Azure OpenAI, и добавить в файл конфигурации в корне решения ключ API, имя развертывания и URL конечной точки.

Добавление в существующее приложение
Чтобы добавить .NET Smart Components в существующие приложения Blazor, MVC или Razor Pages, посмотрите эти руководства:
- Начало работы с .NET Smart Components в Blazor
- Начало работы с .NET Smart Components в MVC или страницах Razor.

Обратная связь и поддержка
.NET Smart Components в настоящее время являются экспериментальными и официально не поддерживаются. В Microsoft хотят знать ваше мнение, полезны ли они и как их улучшить.

Источник: https://devblogs.microsoft.com/dotnet/introducing-dotnet-smart-components/
👍7
День 1881. #ЗаметкиНаПолях
Массовая Вставка в C# и EF Core. Начало

Независимо от того, создаёте ли вы платформу анализа данных, переносите устаревшую систему или привлекаете новых пользователей, вероятно, наступит момент, когда вам потребуется вставить огромный объём данных в БД. Традиционные методы слишком медленные. Поэтому необходимо понимание методов быстрой массовой вставки в C#. Сегодня рассмотрим несколько вариантов.

Примечание: Мы не будем рассматривать некоторые крайние варианты, вроде ручной генерации SQL запросов или использования параметров, возвращающих табличные значения (Table-Valued parameters).

Допустим, нам нужно вставить множество экземпляров класса User в соответствующую таблицу БД.

1. Простой (плохой) пример EF Core
Для сравнения рассмотрим простейший (плохой) вариант, где пользователи добавляются по одному:
using var ctx = new AppDbContext();
foreach (var u in GetUsers())
{
ctx.Users.Add(u);
await ctx.SaveChangesAsync();
}

Результаты ужасные (как и ожидалось из-за множества запросов в БД):
  100 пользователей - 20 мс,
1000 – 260 мс,
10000 – 8,86 с.

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

2. Добавление всех и сохранение в EF Core
Можно поправить пример выше, сначала добавив все записи в контекст, а затем 1 раз вызвав SaveChanges().

foreach (var u in GetUsers())
context.Users.Add(u);
await ctx.SaveChangesAsync();

Результаты:
    100 - 2 мс,
1000 - 18 мс,
10000 - 203 мс,
100000 - 2,13 с,
1000000 - 21,56 с.


3. AddRange в EF Core
Мы можем добавить в контекст сразу всю коллекцию, используя метод AddRange:

ctx.Users.AddRange(GetUsers());
await context.SaveChangesAsync();

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

4. EF Core Bulk Extensions
Библиотеку EF Core Bulk Extensions можно использовать для повышения производительности. Кстати, она позволяет делать не только массовую вставку. Библиотека с открытым кодом, но платная для коммерческого использования. Для нашего варианта подойдёт метод BulkInsertAsync:

await context.BulkInsertAsync(GetUsers());

Результаты впечатляющие:
    100 - 1.9 мс,
1000 - 8 мс,
10000 - 76 мс,
100000 - 742 мс,
1000000 - 8,3 с.


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

Источник:
https://www.milanjovanovic.tech/blog/fast-sql-bulk-inserts-with-csharp-and-ef-core
👍22
День 1882. #ЗаметкиНаПолях
Массовые Вставки в C# и EF Core. Окончание

Начало

5. Dapper
Dapper — это простой преобразователь SQL в объекты .NET. Он позволяет нам легко вставить коллекцию объектов в БД:
using var conn = new SqlConnection(connString);
conn.Open();

var sql = @"
INSERT INTO Users (FirstName, LastName, Email, …)
VALUES (@FirstName, @LastName, @Email, …);";

await conn.ExecuteAsync(sql, GetUsers());

Результаты:
    100 пользователей - 10 мс
1000 - 113 мс,
10000 - 1,02 с,
100000 - 10,9 с,
1000000 - 109,065 с.


6. SQL Bulk Copy
Наконец, для SQL Server мы можем попробовать использовать SqlBulkCopy. Эта реализация немного сложнее. Во-первых, нужно создать объект DataTable, содержащий объекты, которые мы хотим вставить:
DataTable GetUsersDataTable()
{
var dt = new DataTable();
dt.Columns.Add(nameof(User.FirstName),
typeof(string));
dt.Columns.Add(nameof(User.LastName),
typeof(string));
dt.Columns.Add(nameof(User.Email),
typeof(string));


foreach (var u in GetUsers())
dt.Rows.Add(
u.FirstName, u.LastName, u.Email, …);

return dt;
}

Теперь настроим SqlBulkCopy для выполнения вставки:
using var bc = new SqlBulkCopy(ConnString);

bc.DestinationTableName = "dbo.Users";
bc.ColumnMappings.Add(
nameof(User.FirstName), "FirstName");
bc.ColumnMappings.Add(
nameof(User.LastName), "LastName");
bc.ColumnMappings.Add(
nameof(User.Email), "Email");

await bc.WriteToServerAsync(GetUsersDataTable());

Производительность невероятно высока:
    100 – 1,7 мс,
1000 - 7 мс,
10000 - 68 мс,
100000 - 646 мс,
1000000 - 7,34 с.


Итого
SqlBulkCopy работает быстрее всех, однако EF Core Bulk Extensions обеспечивают фантастическую производительность, сохраняя при этом простоту использования, которой славится Entity Framework Core. Поэтому выбор зависит от требований вашего проекта:
- Главное – производительность? SqlBulkCopy или EF Core Bulk Extensions.
- Не хочется платить и нужна простота разработки? Грамотное использование EF Core всё равно даёт неплохие результаты.

Источник: https://www.milanjovanovic.tech/blog/fast-sql-bulk-inserts-with-csharp-and-ef-core
👍16
День 1883. #МоиИнструменты
Назначенные Задания с NCronJob
Hangfire/Quartz или фоновый сервис? А может что-то среднее? Если вам не нужен полноценный планировщик заданий с множеством настроек, но нужно нечто большее, чем просто BackgroundService, рассмотрите NCronJob.

Что это?
Простой и удобный планировщик заданий, работающий поверх IHostedService в .NET. Предоставляет два способа планирования заданий:
- Мгновенные задания — запуск задания прямо сейчас,
- Задания Cron — планирование задания, используя выражение cron.

Идея в том, чтобы иметь простой и лёгкий способ планирования заданий либо повторяющихся через нотацию cron, либо одноразовых (запускаемых с помощью мгновенных заданий). Библиотека построена на основе IHostedService и поэтому идеально подходит для приложений ASP.NET.

Особенности, отличающие NCronJob от BackgroundService:
- 2 вида заданий,
- передача параметров заданиям (как cron, так и мгновенным),
- (Скоро) Уведомления о завершении работы.

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

Как использовать?
Библиотека доступна в виде NuGet-пакета:
dotnet add package LinkDotNet.NCronJob

Для начала определим задание:
public class PrintHelloWorld : IJob
{
private ILogger<PrintHelloWorld> logger;

public PrintHelloWorld(
ILogger<PrintHelloWorld> logger)
{
this.logger = logger;
}

public Task RunAsync(
JobExecutionContext context,
CancellationToken ct = default)
{
logger.LogInformation(
"Parameter: {Parameter}", context.Parameter);

return Task.CompletedTask;
}
}

Как видите, поддерживаются параметры. Это справедливо как для заданий, запускаемых через cron, так и для мгновенных заданий. Теперь зарегистрируем сервис:
builder.Services.AddNCronJob();
builder.Services
.AddCronJob<PrintHelloWorld>(opt =>
{
// Каждую минуту
opt.CronExpression = "* * * * *";
// необязательный параметр
opt.Parameter = "Hello Parameter";
});

Готово!

Вы также можете запускать мгновенные задания откуда угодно:
public class MyService
{
private IInstantJobRegistry jobReg;

public MyService(IInstantJobRegistry jobReg)
=> this.jobReg = jobReg;

public void MyMethod()
=> jobReg.AddInstantJob<MyJob>(
"Необязательный параметр");
}


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

Источник: https://steven-giesel.com/blogPost/f58777b8-e10b-4023-845b-9f5ad3b7e48f/ncronjob-scheduling-made-easy
👍21
День 1884. #ЗаметкиНаПолях
Генерация Спецификации OpenAPI при Сборке Проекта
ASP.NET
Спецификация OpenAPI — мощный инструмент для описания и документирования API. Это стандарт, который позволяет вам определить структуру вашего API, включая конечные точки, модели запросов и ответов, а также требования безопасности. Спецификация OpenAPI — это файл JSON или YAML, который можно использовать для создания документации, клиентских библиотек и серверных заглушек.

Большинство разработчиков .NET генерируют спецификацию из кода. Библиотека Swashbuckle.AspNetCore — популярный выбор для создания спецификации OpenAPI на основе проектов веб-API ASP.NET Core. Вы можете легко добавить страницу для доступа к спецификации. Однако сложно проверить содержание спецификации, чтобы убедиться, что спецификация пригодна для использования потребителями. Один из способов улучшить это — сделать спецификацию частью вашего кода, чтобы вы могли просматривать ее во время проверок кода.

Microsoft предоставляет пакет NuGet Microsoft.Extensions.ApiDescription.Server, который позволяет генерировать спецификацию OpenAPI из кода во время сборки проекта.
Сначала создадим новый проект веб-API и добавим пакет Microsoft.Extensions.ApiDescription.Server:
dotnet new webapi --framework net8.0
dotnet add package Microsoft.Extensions.ApiDescription.Server

Теперь можно добавить следующие свойства в файл .csproj проекта, чтобы настроить генерацию спецификации OpenAPI:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>

<OpenApiDocumentsDirectory>
$(MSBuildProjectDirectory)
</OpenApiDocumentsDirectory>
<OpenApiGenerateDocuments>true</OpenApiGenerateDocuments>
<OpenApiGenerateDocumentsOnBuild>
true
</OpenApiGenerateDocumentsOnBuild>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.OpenApi" Version="8.0.3" />
<PackageReference Include="Microsoft.Extensions.ApiDescription.Server" Version="8.0.3">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.4.0" />
</ItemGroup>
</Project>

Теперь при сборке проекта спецификация будет сгенерирована в корне проекта в файле <ИмяПроекта>.json.

Источник: https://www.meziantou.net/generate-openapi-specification-at-build-time-from-the-code-in-asp-net-core.htm
👍15
День 1885. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 2. Основной результат разработки требований — общее видение и понимание
Материальным результатом разработки требований является документ в некой хранимой форме. Обычно это письменный документ, часто называемый спецификацией требований к ПО или бизнес-требованиями. Как вариант, требования можно оформить в виде карточек, стикеров на доске, диаграмм, приёмочных тестов или комбинации всего этого.

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

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

Часто трудно определить, одинаково ли понимают несколько человек нечто столь сложное, как проект по разработке ПО. Эти различия могут привести к тому, что участники будут стремиться к противоположным целям.
Изложение концепции (заявление о видении - Vision statement) определяет общую стратегическую цель, к достижению которой должны стремиться все участники проекта. Оно помогает достичь общего понимания и непротиворечивых ожиданий.

Вот примерный шаблон заявления о видении:
Для
[целевые клиенты]
Которые
[изложение бизнес-потребностей или возможностей]
Предполагается создать
[название продукта или проекта]
Являющийся
[тип продукта или проекта]
Позволяющий
[основные возможности продукта; основные преимущества, которые он обеспечит; веская причина покупки продукта или реализации проекта]
В отличие от
[текущей реальности или альтернативных продуктов]
Наш продукт
[краткое изложение основных преимуществ этого продукта по сравнению с текущей реальностью или товарами конкурентов]


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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍12
День 1886. #Здоровье
10 Упражнений, Чтобы Предотвратить Боли в Спине
Давно ничего не писал на тему здоровья. Многие из нас из-за сидячей работы сталкиваются с болью в спине. И не просто периодической скованностью, а с постоянной ноющей болью, которая возникает из-за долгих сеансов программирования. Вот 10 важных упражнений, которые помогут её избежать.

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

2. Сведение лопаток
Что делать: сядьте/встаньте прямо. Представьте, что держите карандаш между лопатками и сведите их. Удерживайте 10 секунд, отпустите и повторите.
Преимущества: Упражнение нацелено непосредственно на мышцы вокруг лопаток. Улучшает осанку, уменьшает напряжение в верхней части спины и плечах, а также может помочь облегчить боль в шее за счет укрепления мышц, поддерживающих верхнюю часть позвоночника.

3. Растяжка программиста
Что делать: переплетите пальцы, вытяните их от груди, затем поднимите над головой. Слегка наклоните из стороны в сторону.
Преимущества: Эта растяжка предназначена для воздействия на области, наиболее страдающие от длительного сидения и использования клавиатуры. Вытягивание рук и наклоны из стороны в сторону усиливают растяжение верхней части тела, обеспечивая облегчение и улучшая гибкость. Увеличивает приток крови к рукам и плечам, растягивает напряженные мышцы вокруг груди и плеч и помогает предотвратить возникновение повторяющихся травм от перенапряжения.

4. Отжимания на столе стоя
Что делать: встаньте спиной к столу, положив руки на край, и медленно опустите тело, затем снова поднимитесь.
Преимущества: Использование стола для отжиманий помогает задействовать трицепсы, плечи и даже грудные мышцы. Это упражнение требует минимума движений, но развивает силу верхней части тела, которая поддерживает осанку. Укрепление этих мышц означает, что ваш позвоночник получит больше поддержки, что потенциально уменьшит боль в спине.

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

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

Источник:
https://learnhub.top/10-essential-exercises-for-programmers-to-prevent-back-pain/
👍26
День 1887. #Здоровье
10 Упражнений, Чтобы Предотвратить Боли в Спине. Окончание
Начало

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

7. Прогулки
Что делать: каждый час совершайте 5-минутную прогулку. Будь то дома или в офисе.
Преимущества: улучшает кровообращение и предотвращает скованность, возникающую при длительном сидении. Улучшает общее состояние сердечно-сосудистой системы, повышает уровень энергии и даже может повысить креативность и способность решать проблемы, давая вашему мозгу отдохнуть от экрана.

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

9. Кошка-корова
Что делать: встаньте на четвереньки. Выгните спину вверх, прижав подбородок к груди (кошка), затем опустите спину вниз, задрав голову вверх (корова).
Преимущества: мягкое плавное движение, которое растягивает позвоночник и помогает придать гибкость всей спине и снять напряжение в пояснице. Это также отличное средство от стресса и помогает сосредоточиться.

10. Растяжка кобры
Что делать: лягте на живот, ладони прижмите к груди. Отожмитесь от пола, подняв только грудь, выгибая спину и задирая голову вверх.
Преимущества: укрепляет позвоночник и раскрывает грудь и плечи, противодействуя наклону вперед. Улучшает силу и гибкость позвоночника, уменьшает напряжение в пояснице и может помочь облегчить дискомфорт, связанный с осанкой. Это также полезно для улучшения дыхания и снижения стресса.

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

Источник: https://learnhub.top/10-essential-exercises-for-programmers-to-prevent-back-pain/
👍10
День 1888. #ProjectManagement
Что Такое SLI, SLO и SLA
При проектировании архитектуры ПО мы должны учитывать как функциональные, так и нефункциональные требования. Сегодня разберём SLO, SLA и SLI и как они влияют на жизненный цикл ПО.

1. Индикатор уровня обслуживания (Service Level Indicator - SLI)
Измеримая мера некоторого аспекта уровня предоставляемого обслуживания: процент времени безотказной работы, время ответа или частота сообщений об ошибках. SLI используются для объективного измерения производительности сервиса и для проверки SLO.

Как отслеживать?
- Тщательно определите проверяемые метрики. Например «ошибки HTTP» - недостаточно чётко. Какие именно? 404, 401 и 500 — обозначают ошибки, но их появление может как указывать, так и не указывать на ошибки в системе.
- Определите функции для проверки качества релизов, чтобы гарантировать, что новый релиз не ухудшит существующие значения SLI.

2. Целевой уровень обслуживания (Service Level Objective - SLO)
Целевой уровень обслуживания между поставщиком услуг и конечным пользователем, который измеряется конкретными показателями. Если SLI —фактическое значение измерения, SLO — конечная цель, которую необходимо достичь для этого SLI. SLO - желаемая цель для некоторых показателей (обычно производительности и надёжности), которых стремится достичь сервис. Вы можете указать значение SLO для каждой метрики, которая важна для вас и ваших клиентов. Например:
- 99% запросов к веб-сервису должны иметь задержку менее 300 мс;
- 99,9% запросов к определённой конечной точке должны иметь задержку менее 100 мс;
- 99,9% запросов должны возвращать успешный код состояния.
SLO являются конкретными, подробными и измеримыми. Например, заявление: «Запросы, как правило, должны быть быстрыми» - слишком расплывчато, и его невозможно измерить.

Как отслеживать?
- Создайте информационную панель для измерения каждого из определённых вами SLO.
- Отправляйте оповещения, если значение достигает порога.
- Спроектируйте архитектуру с учётом значений SLO: например, если необходимо обеспечить низкую задержку для запросов, можно спроектировать асинхронную связь между сервисами или решить развернуть приложение близко к местоположению пользователей.

3. Соглашение об уровне обслуживания (Service Level Agreement - SLA)
Официальное соглашение между поставщиком услуг и клиентом. В отличие от SLO, SLA имеют юридическую силу и предусматривают последствия несоблюдения. Если продукт не соответствует SLA, это может вести к штрафам, неустойкам и т.п. Примером SLA является скорость реагирования техподдержки, например, закрывать открытую клиентом заявку в течение 24 часов.

Взаимодействие между SLO, SLA и SLI существенно влияет на решения по архитектуре ПО:
- SLO и SLI помогают архитекторам определить показатели надёжности и производительности, которым должна соответствовать система. Это влияет на выбор технологий и шаблонов, позволяющих достичь этих показателей. Микросервис или монолит? С# или Rust? Локально или в облаке?
- Для соблюдения требований SLO системе может потребоваться обрабатывать большое количество запросов в секунду, что требует масштабируемых архитектур, таких как микросервисы или бессерверные вычисления.
- Необходимость соблюдения SLA может привести к внедрению механизмов резервирования и аварийного переключения для обеспечения высокой доступности и минимизации времени простоя.
- SLI требуют надёжных систем мониторинга и оповещения для отслеживания производительности услуги в режиме реального времени и уведомления, когда SLO подвергаются риску нарушения.
- Необходимость удовлетворять SLO может влиять на распределение ресурсов, что приводит к принятию решений о балансировке нагрузки, сегментировании базы данных или использовании сетей доставки контента (CDN).
- Штрафы, связанные с SLA, могут повлиять на стоимость, побуждая архитектуру быть более экономичной, при этом соответствуя уровням обслуживания.

Источник: https://www.code4it.dev/architecture-notes/sli-vs-slo-vs-sla/
👍13
День 1889. #ЗаметкиНаПолях
Проверка Схемы Json в .NET
Часто бывает полезно проверять документы JSON на соответствие схеме. Схема JSON — это словарь, который можно использовать для аннотирования и проверки документов JSON. Например, вы можете проверить документ JSON, полученный от REST API, или файл конфигурации, написанный пользователем. Сегодня посмотрим, как проверить данные JSON на соответствие схеме в .NET.

Совет. В PowerShell, вы можете использовать командлет Test-Json для проверки данных JSON на соответствие схеме JSON.

.NET не поддерживает проверку схемы JSON «из коробки». Однако существует несколько сторонних библиотек, которые можно использовать для проверки данных JSON на соответствие схеме. Здесь мы используем библиотеку JsonSchema.Net https://www.nuget.org/packages/JsonSchema.Net.

Создадим проект:
dotnet new console
dotnet add package JsonSchema.Net

Следующий код показывает, как проверить данные JSON на соответствие схеме:
using System.Text.Json.Nodes;
using Json.Schema;

//пример схемы
var schema = """
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/product.schema.json",
"title": "Product",
"description": "A product from Acme's catalog",
"type": "object",
"properties": {
"productName": {
"description": "Name of the product",
"type": "string"
},
"price": {
"description": "The price of the product",
"type": "number",
"exclusiveMinimum": 0
}
},
"required": [ "productName", "price" ]
}
""";

// полученные данные
var json = """
{
"productName": "test",
"price": -1
}
""";

// Проверка
var jsonSchema = JsonSchema.FromText(schema);
var result = jsonSchema
.Evaluate(JsonNode.Parse(json));

if (!result.IsValid)
{
Console.WriteLine("Invalid document");
if (result.HasErrors)
{
foreach (var error in result.Errors)
Console.WriteLine(error.Key + ": " + error.Value);
}
}

Источник:
https://www.meziantou.net/json-schema-validation-in-dotnet.htm
👍13
День 1890. #ЧтоНовенького
В C# 13 Разрешат ref и unsafe в Итераторах и Асинхронном Коде

Сейчас вы не можете написать так:
async Task MyMethodAsync()
{
await AnAsyncMethod();
ref int x = ref GetRef();
DoSomething(ref x);
await AnohterAsnycMethod();
}

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

То же самое относится и к ссылочным структурам, таким как Span<T> или ReadOnlySpan<T>. Вы не можете использовать их в итераторах (yield) или асинхронных методах. Предложение позволит писать так:
async Task MyMethodAsync()
{
var result = await AnAsyncMethod();
var span = result.AsSpan();
DoSomething(span);
await AnohterAsnycMethod();
}


Подробности предложения здесь.

Источник: https://steven-giesel.com/blogPost/0d4216e5-4445-48c4-8d9c-3ff5aa1bfdc3/c-13-allow-ref-and-unsafe-in-iterators-and-async
👍8
День 1891. #ЗаметкиНаПолях
Используем localStorage в Современных Приложениях. Начало

API localStorage позволяет разработчикам хранить пары ключ-значение в браузере пользователя. Сегодня рассмотрим различные аспекты API localStorage, преимущества, ограничения и альтернативные варианты.

Что это?
API localStorage — встроенная функция браузеров, позволяющая веб-разработчикам постоянно хранить небольшие объёмы данных в формате «ключ-значение» на устройстве пользователя. Данные остаются доступными даже после того, как пользователь закрывает браузер или уходит со страницы. Это удобный способ поддерживать состояние и сохранять пользовательские настройки, не полагаясь на хранилище на стороне сервера.
// Сохранение
localStorage.setItem('username', 'john_doe');

// Извлечение
let user = localStorage.getItem('username');

// Удаление
localStorage.removeItem('username');

// Очистка
localStorage.clear();

Хранение сложных данных возможно с помощью сериализации JSON (JSON.stringify и JSON.parse):
let user = {
name: 'Alice',
age: 42,
email: '[email protected]'
};

localStorage.setItem('user',
JSON.stringify(user));

let storedUser =
JSON.parse(localStorage.getItem('user'));


Ограничения
1. Неасинхронный API. Любые операции в localStorage потенциально могут заблокировать основной поток.
2. Ограниченная структура данных. Простое хранилище ключ-значение делает localStorage непригодным для хранения сложных структур данных или управления связями между элементами данных.
3. Накладные расходы. Хранение JSON требует сериализации, потенциально замедляя операции до 10 раз.
4. Отсутствие индексации. Нет возможности индексирования, что затрудняет эффективный поиск или перебор данных на основе определённых критериев.
5. Блокировка вкладок. Операции localStorage на одной вкладке могут повлиять на производительность других вкладок, монополизируя ресурсы ЦП.
6. Ограничение хранилища. Обычно около 5 МБ для каждого источника localStorage.

Причины использовать
API localStorage в JavaScript работает на удивление быстро по сравнению с альтернативными решениями. Он превосходно справляется с хранением небольших данных. Доступ к данным localStorage и их изменение требуют минимальных затрат.

Когда не использовать
1. Данные извлекаются через запросы по критериям.
localStorage не предоставляет таких возможностей. Сложный поиск данных может привести к неэффективному коду и снижению производительности.
2. Большие документы JSON.
Важно оценить размер данных и рассмотреть более надёжные решения для обработки значительных наборов данных.
3. Множество операций чтения/записи.
Чрезмерное количество операций чтения и записи в localStorage может привести к снижению производительности.
4. Нет необходимости в постоянном хранении данных.
Если приложению не нужно хранить данные между сеансами, лучше использовать структуры данных в памяти, такие как Map или Set. Они обеспечивают скорость и эффективность обработки временных данных.

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

Источник:
https://rxdb.info/articles/localstorage.html
👍13