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

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1066.
Оглядываясь Назад на C#. Начало

С наступающим!

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

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

90-е были действительно другой эпохой программирования, как технологически, так и культурно. Интернет только начинал развиваться. Колёсико мыши было практически неслыханным делом, а трекболы были еще одним предметом, который нужно чистить и обслуживать. Microsoft были в разгаре судебной тяжбы с Sun по поводу торговых марок Java и J++. Delphi, основанный на Turbo Pascal, был лидером в области быстрой разработки приложений (RAD). Необычный язык программирования JavaScript, который добавлял интерактивность в веб-браузеры, был новинкой. Программистам на COBOL и другим людям, работавшим над ошибкой 2000 года, наряду с HTML-разработчиками, платили как рок-звёздам, а Microsoft спасала Apple от финансового краха.

В середине 2000 года Microsoft объявила о скором выпуске нового языка программирования под названием C#, ничем не напоминающего Visual Basic, их флагманский инструмент RAD, который, возможно, был самым любимым (и самым осуждаемым) языком в то время. Синтаксис VB во всех его формах использовался для большинства инструментов программирования Microsoft. Всё, от VBScript в классическом ASP до автоматизации офиса и инструмента RAD Tool. Хотя это официально не было заявлено, выпуском C# Microsoft недвусмысленно намекнули об изменении своего подхода к разработке ПО и что они не против оставить в прошлом синтаксис BEGIN/END и ON ERROR GOTO, к большому огорчению многих разработчиков.

Да, строго говоря, Microsoft официально не отказывались от Visual Basic. Они создали VB.NET с некоторыми изменениями синтаксиса и согласились «развивать» его параллельно с C#. Хотя в то время официально об этом не говорили, но на его рекламу и продвижение было потрачено гораздо меньше времени и усилий. И многие разработчики считали, что Microsoft твердо намерены перевести разработчиков на C#.

Заглянув в историю 90-х, теперь можно посмотреть на мир, в котором дебютировал C# 1.0. Он вошёл в мир, где продолжались споры о том, действительно ли нужны ещё какие-либо коммерческие языки программирования, и, кроме того, он выглядел чрезвычайно похожим на язык программирования конкурирующей компании… Java. Настолько похож, что даже некоторые недостатки Java были сознательно продублированы, например ковариантность массивов.

В Microsoft решили эту проблему с помощью обобщений. Хотя, в первоначальном выпуске было явно запрещено делать что-то вроде следующего:
public void AddEmployee(List<Employee> employees){}
...
public void AddManager () {
List<Manager> managers = new List<Manager>();

// Изначально это было запрещено, даже при том,
// что Manager – подтип Employee.
AddEmployee(managers);
}

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

Продолжение следует…

Источник:
https://kemiller2002.github.io/c-sharp/2021/12/24/reflection.html
👍11
Моя первая книга по C# от 2003 года.
С новым годом, дорогие подписчики! Бинарную ёлочку вам.
👍17
День 1067.
Оглядываясь Назад на C#. Продолжение
С новым годом! Продолжаем вчерашнюю историю

Наряду с этим у языка C# были «особенности», которые и в то время считались пугающими, а сегодня вообще бы сделали язык непригодным для использования:
1. В C# были только массивы (никаких других коллекций), и во многих случаях их нельзя было расширять. В то время в .NET Framework были вспомогательные функции для этого, но это было совсем не так просто, как, например, вызов List<T>.Add(). Встроенные функции копировали данные в новый массив, поэтому, если вы рассчитывали, что ссылки на исходный массив все ещё работают, вам не повезло. Вы также должны были осознавать компромиссы между временем и количеством памяти и выбирать оптимальный подход. В .NET был список ArrayList, который изначально поддерживал расширение, но только в том случае, если вы соглашались с тем, что все его элементы были типа Object.

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

3. Обнуляемые значимые типы (например, целые числа) не существовали. Это ставило разработчиков перед трудной проблемой определения того, как обрабатывать значения по умолчанию. Вы предполагали, что 0 - значение по умолчанию для целых чисел. Это работало, только если 0 не находился в диапазоне допустимых значений. Тогда приходилось выбирать другое значение, например -1. И это работало, пока кто-то не забывал установить это значение по умолчанию, и вы не тратили часы на поиск того, откуда появляется 0.

4. Хотя технически это не совсем проблема C#, концепция файла .ini была заменена конфигурацией в виде XML, который разработчики до этого никогда не видели и не понимали, как использовать. Хотя сейчас это звучит довольно глупо, простая конфигурация в виде «ключ=значение» была заменена гораздо более многословным синтаксисом.

С другой стороны, в Microsoft предприняли несколько смелых шагов, невиданных в языках в то время, чтобы помочь программистам в их повседневной работе. Хотя C#, возможно, и не изобрёл с нуля эти концепции, он пропагандировал их, просто мягко побуждая разработчиков работать более продуктивно и устраняя распространённые ошибки, что и сделало его популярным.

Один из примеров – запрет «проваливаться» в следующий case:
switch number
{
case 0:
DoSomething();
// Нельзя опускать оператор break
case 1:
DoSomethingElse();
break;
...
}
Хотя некоторым это ограничение кажется смешным, оно экономит бесчисленные часы отладки, когда break был случайно пропущен.

Точно так же C# убрал необходимость в «синтаксисе Йоды» if (42 == answer), когда константа ставится в левую часть оператора сравнения, просто чтобы не путать сравнение с присваиванием if (answer = 42).
Также запрещены выражения вроде if(42), а требуется явное if(42 > 0), потому что первое сбивает с толку людей, не понимающих, почему, например, в JavaScript if(-1) оценивается как true.

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

Источник:
https://kemiller2002.github.io/c-sharp/2021/12/24/reflection.html
👍4👎2
Фото из истории создания обобщений в .NET в исследовательской лаборатории Microsoft Cambridge в феврале 1999 года в St Georges House, Кембридж, Великобритания. Обсуждения на доске между Don Syme, Cedric Fournet, Nick Benton и Simon Peyton Jones.
👍25
День 1068.
Оглядываясь Назад на C#. Окончание
Начало
Продолжение

Примерно в 2005 году в Microsoft сделали амбициозный шаг и представили концепцию обобщений. Их реализация в C# существенно изменила ландшафт языка и среды выполнения, предоставив более сильный функционал по сравнению с реализацией в Java, появившейся годом ранее. C++, Python, Rust, Swift и Go теперь тоже поддерживают обобщения, и без них будущее C# определённо было бы под вопросом. Сейчас нельзя и представить C# без обобщений и их преемников, и они также рассматривались как важный шаг в преодолении разрыва между чисто академическими языками и языками, используемыми в коммерческих целях.

В том же году легендарный C++ программист Херб Саттер написал свою культовую статью «Бесплатный обед закончился», в которой он предсказал крах систем, строго полагавшихся на то, что скорость процессоров будет постоянно увеличиваться, позволяя программам работать быстрее без дополнительных оптимизаций. В Microsoft осознали, что любой вид асинхронного программирования, существовавший в то время, был трудным почти для всех разработчиков. C# получил модель async/await в 2011 году в предварительной версии и официально в 2012 году. (Хотя Microsoft ещё в 2010 году добавили Task Parallel Library для решения схожих задач). Трудно сказать, откуда другие языки черпали вдохновение, но несколько языков последовали за C# и также добавили этот шаблон:
- Python в 2015,
- Typescript в 2015,
- JavaScript в 2017,
- Rust в 2019,
- C++ в 2020,
- Swift в 2021.

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

Оглядываясь назад, более чем 20 лет спустя, C# действительно сохранил свой костяк с момента возникновения, но некоторые аспекты также полностью изменились по мере того, как менялись мнения о теории программирования. Ещё в 90-х функциональное программирование считалось в основном академическим занятием, но сегодня стало очень популярным. Изначально C# позиционировал себя как объектно-ориентированный язык, но с годами изменился, чтобы быть в первую очередь объектно-ориентированным языком, но с дополнениями, поддерживающими функциональный характер разработки. Некоторые задаются вопросом, движется ли он по тому же пути, что и PERL, который кажется хаотичным набором огромного количества способов выполнить одну и ту же задачу, но в то же время без адаптации к реалиям язык обречён на то, чтобы быть забытым, как и многие его предшественники.

Источник: https://kemiller2002.github.io/c-sharp/2021/12/24/reflection.html
👍7
День 1069. #Книги
Вдохновившись этой серией постов, решил-таки полностью прочитать книгу дядюшки Боба «Идеальный программист». И должен вам сказать, прошла она у меня на ура. Прекрасное ненапряжное чтение для метро, автобуса по дороге на работу (или где вы там ещё книжки читаете).
Книга про карьеру разработчика. Приводятся советы относительно различных жизненных ситуаций, с которыми вы можете столкнуться на работе. Всё это приправлено байками из жизни самого Роберта Мартина.
Конечно, не обошлось без присущего дядюшке Бобу идеализма, и кое-где он перегибает палку в плане категоричности суждений. Но в целом книга понравилась, советую.

PS: Накидайте в комментарии похожего околопрограммистского «лёгкого чтива». Я ещё читал «Мифический человеко-месяц» Фредерика Брукса (но она уже порядком устарела) и «Кодеры за работой» Питера Сейбела. Последняя представляет собой серию интервью с известными программистами от создателя ЖЖ Брэда Фицпатрика до самого Дональда Кнута. Хотя написана довольно сухо.
👍1
День 1070. #юмор
Лайк, если было такое)))
👍41
День 1071. #NET6
Не Делайте Этого В .NET 6, Делайте Вот Так. Начало
В C# 10 появилось много хороших вещей: улучшения производительности, горячая перезагрузка, минимальные API и многое другое. Большинство разговоров идёт про важные функции. А что насчёт более мелких улучшений, который всё же помогают сделать ваш ежедневный опыт разработки более продуктивным? Многие из них могут помочь убрать шаблонный код и ускорить достижение цели.

1. Не разбивайте большие коллекции вручную, используйте новый API LINQ
При работе с большими коллекциями иногда нужно разбивать их на более мелкие порции (страницы). Чаще всего это приводит к серии вызовов методов Take и Skip, либо к созданию метода расширения, вроде этого популярного ответа со Stack Overflow:
static class LinqExtensions
{
public static IEnumerable<IEnumerable<T>> Split<T>(
this IEnumerable<T> list, int parts)
{
int i = 0;
var splits =
from item in list
group item by i++ % parts into part
select part.AsEnumerable();
return splits;
}
}

Не делайте так. Вместо этого используйте новый метод Chunk:
int pageSize = 10;
IEnumerable<Employee[]> employeeChunk = employees.Chunk(pageSize);

2. Если вам нужна только дата, не используйте DateTime, используйте DateOnly
Если вам нужно работать с датой и временем в .NET, вы обычно используете DateTime, TimeSpan или DateTimeOffset. Что, если вам нужно работать только с датами и нужен только год, месяц или день? В .NET 6 вы можете использовать новую структуру DateOnly (также можно использовать TimeOnly). Вот стандартный код, который вы могли использовать раньше:
var someDateTime = new DateTime(2021, 11, 09);
// 09.11.2021 12:00:00 AM
var justTheDate = someDateTime.ToShortDateString();
// "09.11.2021"

Не делайте так. Вместо этого используйте структуру DateOnly:
var someDateTime = new DateOnly(2021, 11, 09);
// 09.11.2021

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

3. Не пишите кучу кода для логирования HTTP-запросов, используйте новое промежуточное ПО
До .NET 6 регистрировать HTTP-запросы было не сложно, но немного многословно. Один из способов - создать своё промежуточное ПО, где логировать запрос и передавать его дальше по конвейеру.

Не делайте так. Вместо этого используйте новое промежуточное ПО .NET 6 HTTP Logging:
public void Configure(
IApplicationBuilder app,
IWebHostEnvironment env)
{
app.UseHttpLogging();
// ...
}
Логирование можно настроить по вашему усмотрению:
public void ConfigureServices(
IServiceCollection services)
{
services.AddHttpLogging(log =>
{
log.LoggingFields = HttpLoggingFields.All;
log.RequestHeaders.Add("X-Request-Header");
log.ResponseHeaders.Add("X-Response-Header");
log.RequestBodyLogLimit = 4096;
log.ResponseBodyLogLimit = 4096;
});
}
Надо следить за тем, что вы пишете в лог, и как часто, но всё же это серьёзное упрощение процедуры.

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

Источник:
https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/
👍29
День 1072. #NET6
Не Делайте Этого В .NET 6, Делайте Вот Так. Окончание
Начало

4. Не используйте костыли для обработки исключений в Blazor Server, используйте компонент ErrorBoundary
Что происходит при возникновении необработанного исключения в Blazor Server? Оно считается фатальным, поскольку «цепь остается в неопределённом состоянии, что может привести к проблемам со стабильностью или безопасностью в Blazor Server». В результате вам может потребоваться разбрасывать повсюду блоки try/catch в качестве превентивной меры или инкапсулировать логику в JavaScript, поскольку код C# после необработанного исключения не будет выполнен.

Не делайте так. Вместо этого используйте новый компонент ErrorBoundary. Это не глобальный обработчик исключений, но он поможет справиться с непредсказуемым поведением, особенно с компонентами, которые вы не контролируете.
<div class="main">
<div class="content px-4">
<ErrorBoundary>
@Body
</ErrorBoundary>
</div>
</div>
Конечно, можно не перехватывать все исключения:
<tbody>
@foreach (var emp in Employees)
{
<ErrorBoundary @key="@emp">
<ChildContent>
<tr>
<td>@emp.Id</td>
<td>@emp.FirstName</td>
<td>@emp.LastName</td>
</tr>
</ChildContent>
<ErrorContent>
Не удалось отобразить #@emp.Id.
</ErrorContent>
</ErrorBoundary>
}
</tbody>

5. Не используйте подробный логгинг в Server.Kestrel, используйте новые подкатегории
Если я хочу включить подробный логгинг для Kestrel, раньше нужно было использовать Microsoft.AspNetCore.Server.Kestrel. Это всё ещё существует, но есть и новые подкатегории, которые упрощают жизнь. В дополнение к Server.Kestrel теперь есть Kestrel.BadRequests, Kestrel.Connections, Kestrel.Http2 и Kestrel.Http3. Допустим, вы хотите регистрировать только неверные запросы:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Server.Kestrel": "Debug"
}
}
}

Не делайте так. Делайте вот так:
{
"Logging": {
"LogLevel": {
"Microsoft.AspNetCore.Server.Kestrel.BadRequests": "Debug"
}
}
}

6. Не теряйтесь в скобках, используйте пространства имён уровня файлов
В C# 10 представлены пространства имён уровня файлов. Вот обычное объявление класса в C# до версии 10:
namespace SuperheroApp.Models
{
public class Superhero
{
public string? FirstName { get; set; }
public string? LastName { get; set; }
}
}

Теперь можно убрать скобки в пространстве имён, а также получить все преимущества неизменяемости, использовав записи:
namespace SuperheroApp.Models;

public record Superhero(string? FirstName, string? LastName);

Кстати, о скобках. В C# 10 также введены новые шаблоны свойств. В выражении switch вместо
var tax = sales switch
{
{ Address: { State: "AZ" } } => 1.03M,
{ Address: { State: "FL" } } => 1.07M,
{ Address: { State: "CA" } } => 1.12M
_ => 0
};
можно использовать более ясный формат:
var tax = sales switch
{
{ Address.State: "AZ" } => 1.03M,
{ Address.State: "FL" } => 1.07M,
{ Address.State: "CA" } => 1.12M
_ => 0
};

Источник: https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/
👍10
День 1073. #Testing
Исправлять ли Ошибки в Приватных Методах, Если Они Компенсируют Друг Друга?
Недавно наткнулся на интересное обсуждение. Нужно ли исправлять ошибки, которые компенсируют друг друга и в итоге приводят к правильному поведению?

Допустим, у нас есть такой код:
public void PerformAction()
{
Step1();
Step2();
}
private void Step1()
{ ... }
private void Step2()
{ ... }

Допустим, что и Step1, и Step2 содержат ошибки в своей реализации, но общее поведение метода PerformAction является правильным, потому что по чистой случайности ошибки в двух приватных методах взаимно компенсируются.

Как следует тестировать этот метод? Общее мнение, что вам следует тестировать только публичные методы. Приватные методы следует тестировать косвенно, через публичные методы, которые их используют.

Другими словами, PerformAction - единственный метод, который здесь следует тестировать. Step1 и Step2 вообще не должны рассматриваться.

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

В нашем примере метод PerformAction - это наблюдаемое поведение, а Step1 и Step2 - детали реализации. Поэтому единственное, что имеет значение, - это поведение PerformAction.

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

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

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

Однако, если бы эти методы не были приватными, всё было бы по-другому. Теперь, когда эти методы являются частью общедоступного API, они также становятся частью наблюдаемого поведения и, следовательно, должны быть протестированы и исправлены. Но до тех пор ошибки в приватных методах - не проблема.

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

Но это «исправление» будет рефакторингом, а не исправлением ошибки: здесь вы меняете детали реализации; наблюдаемое поведение остаётся неизменным.

Источник: https://enterprisecraftsmanship.com/
Автор Оригинала: Владимир Хориков
👍8
День 1074. #ЗаметкиНаПолях #AsyncTips
Параллельное агрегирование

Задача:
требуется агрегировать результаты (суммирование значений или вычисление среднего) при завершении параллельной операции.

Решение
Для поддержки агрегирования класс Parallel использует концепцию локальных значений — переменных, существующих локально внутри параллельного цикла. Это означает, что тело цикла может просто обратиться к значению напрямую, без необходимости синхронизации. Когда цикл готов к агрегированию всех своих локальных результатов, он делает это с помощью делегата localFinally. Следует отметить, что делегату localFinally нужно синхронизировать доступ к переменной для хранения результата. Пример параллельного суммирования:
int ParallelSum(IEnumerable<int> values)
{
int result = 0;
Parallel.ForEach(source: values,
localInit: () => 0,
body: (item, state, localValue) =>
localValue + item,
localFinally: localValue =>
Interlocked.Add(ref result, localValue)
);
return result;
}

В Parallel LINQ реализована более понятная поддержка агрегирования, чем в классе Parallel:
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Sum();
}

На самом деле в PLINQ реализована встроенная поддержка многих распространённых операторов (например, Sum). Также предусмотрена обобщённая поддержка агрегирования с оператором Aggregate:
int ParallelSum(IEnumerable<int> values)
{
return values.AsParallel().Aggregate(
seed: 0,
func: (sum, item) => sum + item
);
}

Если вы уже используете класс Parallel, следует использовать его поддержку агрегирования. В остальных случаях поддержка в PLINQ, как правило, более выразительна, а код получается короче.

UPD: Обновил пример ParallelSum примером из документации с использованием Interlocked.Add вместо lock.

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 4.
В дополнение к предыдущему посту.
Вот именно поэтому нужно читать источники в оригинале. Там может ошибиться только автор, но хотя бы нет ошибок переводчика. И хотя в целом перевод Клири более менее качественный, вот вам пример, разворачивающий смысл на 180 градусов. Сам 3 раза прочитал текст, потом код, потом опять текст. Не сходилось. Хорошо, что под рукой был оригинал.
👍15
День 1075. #ЧтоНовенького
В C #10 появился новый атрибут CallerArgumentExpression. Он позволяет записывать выражение, переданное в качестве параметра, в виде строки (см. рисунок). Как и другие атрибуты CompilerServices, он применяется к необязательному параметру.

Кстати, его использует новый метод
ArgumentNullException.ThrowIfNull(nullArg);
в .NET без явной передачи имени.

Если раньше нам нужно было писать что-то подобное:
public bool DoSomething(string id, string name)
{
if (id is null)
throw new ArgumentNullException(nameof(id));
if (name is null)
throw new ArgumentNullException(nameof(id));
// ...
}

Теперь новый метод позволяет писать более чистый код:
public bool DoSomething(string id, string name)
{
ArgumentNullException.ThrowIfNull(id);
ArgumentNullException.ThrowIfNull(name);
// ...
}

Источник: https://twitter.com/Nick_Craver/status/1476929172249448459
👍13
День 1076. #NuGet
10 Лучших NuGet Пакетов для Повышения Продуктивности в 2022. Начало
Сегодня мы рассмотрим лучшие NuGet пакеты для повышения продуктивности разработчиков на C#.

1. RestSharp
RestSharp — самая популярная клиентская библиотека HTTP для .NET. Используя эту библиотеку, разработчики C# могут легко вызывать удалённые ресурсы по HTTP. Кроме того она заботится о сериализации тела запроса в JSON или XML и десериализации ответа.
Пакет RestSharp поддерживает:
- синхронные и асинхронные запросы,
- сериализацию и десериализацию,
- различные методы HTTP-запросов (GET, POST, PUT и DELETE),
- разнообразные способы аутентификации.
Всего загрузок: 111,1 млн.

2. Json.NET
Json.NET — это бесплатная библиотека с открытым исходным кодом для .NET, которую скачали более миллиарда раз. Её ключевые особенности включают в себя:
- Сериализацию и десериализацию любого объекта .NET в JSON и текста JSON в объект .NET.
- Преобразование между XML и JSON.
- Создание, анализ, запросы и изменение JSON, используя объекты JObject, JArray и JValue.
- Запросы к JSON с синтаксисом, подобным XPath.
- Высокую производительность.
Всего загрузок: 1,6 млрд.

3. Serilog
Логи — это записи действий, исключений, информации и предупреждений. Ведение журнала — важный фактор в разработке приложений, который помогает разработчикам легко обнаруживать и устранять проблемы. Serilog — это платформа логирования, используемая в .NET. Он записывает пользовательские свойства и данные в формате JSON.
В отличие от других инструментов ведения журналов, Serilog предоставляет структурированные журналы, которые позволяют производить поиск по записанным данным. Он также позволяет разработчикам легко записывать данные о событиях в консоль, в файлы и во все типы систем хранения.
Всего загрузок: 365,1 млн.

4. NUnit
Тестирование играет важную роль в разработке программного обеспечения для обеспечения корректности кода. NUnit — это платформа модульного тестирования с открытым исходным кодом для всех языков .NET, включая C#. С помощью NUnit вы можете легко тестировать большие приложения, разбивая их на небольшие модули. Это помогает нам находить проблемы прямо во время разработки.
Всего загрузок: 153,1 млн.

5. Insight.Database
Insight.Database — это микро-ORM для .NET, который преобразует объекты C# в записи базы данных и наоборот. Это набор методов расширения, упрощающих работу с базами данных в приложении C#.
Основные функции Insight.Database включают в себя:
- Автоматическое открытие/закрытие соединений с базой данных.
- Простое выполнение хранимых процедур.
- Поддержку нескольких наборов результатов.
Всего загрузок: 691,0 тыс.

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

Источник:
https://www.syncfusion.com/blogs/post/10-best-c-nuget-packages-to-improve-your-productivity-in-2022.aspx/amp
👍5
*Утащу. На этот раз у Немчинского*

Вы достигли целей, поставленных на 2021 год?
Anonymous Poll
16%
Да
40%
Частично
14%
Нет
30%
Не пишу себе целей на год
👍2
День 1077. #NuGet
10 Лучших NuGet Пакетов для Повышения Продуктивности в 2022. Продолжение
Начало

6. FluentValidation
FluentValidation — это библиотека .NET для построения строго типизированных правил валидации. Она использует Fluent-интерфейс и лямбда-выражения для создания правил. Правила валидации помогают поддерживать чистоту кода домена, выделяя код проверки в отдельный блок.
FluentValidation имеет множество встроенных правил, таких как проверка на null, на пустую строку, максимальную и минимальную длину и т.п. Библиотека также поддерживает пользовательские валидаторы, настраиваемые сообщения валидации на основе имён свойств, предоставляет локализованные сообщения, асинхронные проверки и т.д.
Всего загрузок: 118,7 млн.

7. Noda Time
Работа с датой, временем и часовыми поясами в .NET очень болезненна. Noda Time заполняет пробел в операциях с датой и временем в .NET и тем самым упрощает жизнь. Пакет предоставляет различные API для обработки UTC, местного времени и часовых поясов. Также предоставляется функционал для простого преобразования местного времени в UTC и обратно, что позволяет избежать серьёзных ошибок, которые могут допустить разработчики, реализуя эту логику самостоятельно.
Всего загрузок: 46,2 млн.

8. FluentEmail
FluentEmail — это библиотека .NET с открытым исходным кодом, которая позволяет внедрить функции отправки электронной почты в ваше приложение .NET за 10 минут. Помимо основных параметров электронного письма, пакет позволяет вложить файл, отправлять почту асинхронно, а также использовать Razor для разработки шаблонов писем и отправлять письма с помощью SendGrid, MailGun, SMTP и т. д.
Всего загрузок: 1,8 млн.

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

10. LazyCache
Кэширование — отличный способ повысить производительность приложения. LazyCache использует формат GetOrAdd для кэширования, когда вы запрашиваете элемент из кэша, предоставляя при этом функциональность для его добавления, если элемент отсутствует.
LazyCache отлично подходит для кэширования вызовов базы данных, процедур построения сложных графов объектов и вызовов веб-сервисов, которые нужно временно сохранить для повышения производительности. Пакет позволяет кэшировать элементы в течение большего или меньшего времени, но по умолчанию он сохраняет кэшированные элементы до 20 минут.
Ключевые особенности LazyCache:
- Потокобезопасен и готов для использования в параллельном коде.
- Совместим с асинхронным кодом: доступна ленивая однократная оценка асинхронных делегатов с использованием метода GetOrAddAsync().
Всего загрузок: 7,3 млн.

Источник:
https://www.syncfusion.com/blogs/post/10-best-c-nuget-packages-to-improve-your-productivity-in-2022.aspx/amp
👍16
День 1078.
Избегайте Ненужных Программных Абстракций. Начало
Разработчики ПО любят абстракции. Абстракции — ключ к эффективной разработке. Проблема возникает, когда абстракции вводятся преждевременно, т.е. до того, как они решают реальную нетеоретическую проблему. Добавление абстракций всегда происходит за счёт роста сложности и, если с ними переборщить, начинает замедлять скорость разработки и способность понимать кодовую базу.

Все проблемы в информатике можно решить с помощью ещё одного уровня абстракции… За исключением проблемы слишком большого количества уровней абстракции.
— Батлер Лэмпсон

Мы рассмотрим, как отказ от лишних абстракций может привести к гораздо более чистой кодовой базе со значительно сниженной сложностью, а также повышенной читаемостью и удобством сопровождения. Обсуждаемые вопросы основаны на таких принципах, как «Делай Проще, Тупица» (KISS) и «Вам Этого не Понадобится» (YAGNI), что означает использование абстракции только тогда, когда это даёт значительную и реальную пользу. Давайте рассмотрим некоторые конкретные случаи преждевременных абстракций, которые часто встречаются на практике.

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

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

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

Когда же разделять обязанности? Распространённый случай — когда логику нужно использовать более, чем в одном месте. Если один и тот же HTTP-вызов или запрос к базе требуется в нескольких местах, дублирование логики снижает удобство сопровождения. Тогда будет хорошей идеей перенести код в общий и многократно используемый компонент. Главное не делать этого до того, как это потребуется. Другой допустимый случай — когда логика очень сложна и негативно влияет на читаемость окружающего кода. Если часть логики занимает 300 строк, это как раз тот случай. Но выделение всего нескольких строк в отдельный класс, скорее всего, только ухудшит читаемость и затруднит навигацию по коду. Помните, что разделение обязанностей всегда усложняет структуру кода.

Продолжение следует…

Источник:
https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/
👍8
День 1079.
Избегайте Ненужных Программных Абстракций. Продолжение
Начало

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

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

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

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

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

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

Преждевременная оптимизация — корень всех зол
— Дональд Кнут

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

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

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

Источник: https://www.daveabrock.com/2021/12/08/do-this-not-that-the-net-6-edition/
👍1