.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
День 2130. #Оффтоп
Почему Разработчики Любят Чистый Код, но Ненавидят Писать Документацию? Окончание

Начало

Является ли документация, созданная ИИ, хорошим решением?
Существует несколько различных способов, которыми разработчик или команда разработчиков могут подойти к этой проблеме. В этом видео показано, как GitHub CoPilot работает как предиктивный движок, принимая подсказку от разработчика, а затем расширяя мысль и добавляя соответствующие детали.

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

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

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

Возможно, самое важное, что эта синергия между GenAI и разработчиками-людьми не устраняет человеческий надзор. Разработчики сохраняют контроль над результатом, направляя ИИ и проверяя точность вывода, что гарантирует соответствие конечного продукта их намерениям.

Лучшие практики для документации в Agile среде
Важно рассматривать эти инструменты как инструменты для внедрения новых лучших практик, которыми по-прежнему управляют люди, а не как роботов, которые выполняют всю работу самостоятельно.

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

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

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

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

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

Источник: https://stackoverflow.blog/2024/11/11/developers-hate-documentation-ai-generated-toil-work/
👍4
День 2131. #ЧтоНовенького
Отладка Тестов с Помощью GitHub Copilot
Новая функция Visual Studio 2022, работающая на основе GitHub Copilot, предлагает кнопку Debug with Copilot (Отладка с Copilot) в обозревателе тестов.

Отладка неудачных модульных тестов часто может быть утомительным и разочаровывающим процессом. Разработчики тратят много времени на выявление основной причины сбоя и выяснение шагов по её устранению. Этот трудоемкий процесс может задержать сроки разработки и снизить производительность. Visual Studio 2022 с GitHub Copilot предлагает инновационное решение для оптимизации этого процесса.

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

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

Источник: https://devblogs.microsoft.com/visualstudio/transform-your-debugging-experience-with-github-copilot/
👍4
День 2132. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 34. Мы слишком часто принимаем желаемое за действительное


Реальность часто далека от идеала, который мы себе представляем; люди иногда хотят верить, что всё не так, как есть на самом деле. Это может проявляться по-разному, но сегодня рассмотрим веру, связанную с самообманом или необоснованным оптимизмом. В одних случаях это попытка убежать от реальности. В других — принятие желаемого за действительное.

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

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

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

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

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

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

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

Случается ли подобное в вашей организации? Если да, то каковы последствия? Можете ли вы как-то повлиять на это?

Надежда на то, что мир не такой, какой есть на самом деле, может быть утешительной, но неконструктивной. Иногда мы не в восторге от реальности, но она — всё, что у нас есть, и мы должны с этим жить.

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 4.
👍5
День 2133. #ЗаметкиНаПолях
Пример Реализации Паттерна Цепочка Обязанностей

Паттерн «Цепочка Обязанностей» —позволяет создавать цепочку объектов для обработки запроса или выполнения задачи. Рассмотрим, как реализовать его в .NET на практическом примере.

Допустим, у нас есть ряд правил скидок для приложения электронной коммерции. В зависимости от клиента мы хотим применять различные проценты скидок к его заказам:
— VIP - 20%,
— постоянный клиент - 10%,
— новый клиент - 5%.
— иначе не применять скидку.

Изначально мы можем обрабатывать эту логику с помощью ряда операторов if:
public decimal CalculateDiscount(
Customer customer,
decimal orderTotal)
{
if (customer.IsVIP)
return orderTotal * 0.8m;

if (customer.IsRegular)
return orderTotal * 0.9m;

if (customer.IsNew)
return orderTotal * 0.95m;

return orderTotal;
}


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

1. Создадим абстрактный класс обработчика DiscountHandler, который определяет общий интерфейс для всех обработчиков скидок:
public abstract class DiscountHandler
{
protected DiscountHandler _next;

public DiscountHandler SetNextHandler(
DiscountHandler next)
{
_next = next;
return next;
}

public abstract decimal CalculateDiscount(
Customer customer, decimal orderTotal);
}


2. Реализуем конкретные обработчики скидок, производные от DiscountHandler. Каждый обработчик будет отвечать за определённое правило и решать, применять ли скидку или передавать запрос следующему обработчику:
public class VIPDiscountHandler
: DiscountHandler
{
public override decimal
CalculateDiscount(
Customer customer,
decimal orderTotal)
{
if (customer.IsVIP)
return orderTotal * 0.8m;

return _next?
.CalculateDiscount(customer, orderTotal)
?? orderTotal;
}
}

Остальные реализуем аналогично.

3. Создадим цепочку связанных обработчиков:
var vipHandler = new VIPDiscountHandler();

vipHandler
.SetNextHandler(new RegularDiscountHandler())
.SetNextHandler(new NewCustomerDiscountHandler())
.SetNextHandler(new NoDiscountHandler());

Наконец, вызовем цепочку, обратившись к методу CalculateDiscount первого обработчика:
decimal discountAmount = vipHandler
.CalculateDiscount(customer, orderTotal);


Плюсы
1. Гибкость
Позволяет динамически изменять или расширять цепочку (добавлять или удалять обработчики), не затрагивая другие части кода.
2. Слабая связанность
Каждому обработчику нужно знать только о своем непосредственном преемнике, что минимизирует зависимости.
3. Единая ответственность
Отделяет классы, которые вызывают операции, от классов, которые выполняют операции.

Минусы
1. Запрос может остаться необработанным
Если ни один из обработчиков в цепочке не может обработать запрос, он может остаться необработанным, что приведет к неожиданному поведению. Важно иметь обработчик по умолчанию или способ обработки таких сценариев.
2. Потенциальное влияние на производительность
Если цепочка становится очень длинной, это может привести к накладным расходам производительности из-за обхода нескольких обработчиков.

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

Источник: https://thecodeman.net/posts/chain-responsibility-pattern
👍19👎1
День 2134. #ЧтоНовенького
Значительное Ускорение Восстановления NuGet-Пакетов в .NET 9

В .NET 9 добавлен новый сопоставитель зависимостей NuGet, созданный для значительного повышения производительности. Если вы боролись с медленным восстановлением пакетов в сложных сборках, это решение, которого вы ждали.

Внутри Microsoft большой репозиторий содержит тысячи проектов на .NET Core. Это непростая задача, в настоящее время более 2500 отдельных проектов перенесены и оптимизированы для современных стандартов. Восстановление NuGet-пакетов занимало более 30 минут, что приводило к значительным задержкам в сотнях сборок каждый день. Эти задержки быстро накапливались, что приводило к потере времени и разочарованию разработчиков.

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

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

Результаты
Новый подход дал впечатляющие результаты. Исходный граф зависимостей, который создал бы 1,6 миллиона узлов для сложного проекта, был сокращён до всего 1200 узлов. Благодаря меньшему количеству узлов для обработки время восстановления значительно сократилось: до всего 2 минут.

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

Источник: https://devblogs.microsoft.com/dotnet/dotnet-9-nuget-resolver/
👍21
День 2135. #ЗаметкиНаПолях
Избегаем Null в Строках при Отправке Форм
ASP.NET Core
Если перенести решение с ASP.NET Framework на ASP.NET Core 8, можно внезапно столкнуться с ошибкой 500. Ошибка происходит из-за исключения NullReferenceException. Рассмотрим метод действия:
[HttpPost("/")]
public ActionResult Index(
[FromForm] MyForm myForm)
{
if(myForm.Input1.Length > 0)
{
// Что-то делаем…
}
return Ok();
}
public class MyForm
{
public string Input1 { get; init; }
}

Вроде ничего странного, правда? Только обработку ошибок убрали для краткости. А вот код, который отправлял форму:
const formData = new URLSearchParams();
formData.append('Input1', '');
fetch('/', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: formData.toString()
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch((error) => {
console.error('Error:', error);
});

Здесь важно то, что Input1 установлен в пустую строку ''. Но при отправке пустой строки ASP.NET Core не устанавливает соответствующее свойство в пустую строку. Вместо этого он устанавливает его в значение null.

Это можно исправить несколькими способами.

Для конкретной конечной точки
Использовать атрибут DisplayFormat:
public class MyForm
{
[DisplayFormat(ConvertEmptyStringToNull = false)]
public string Input1 { get; init; }
}


Глобально
Написать реализацию IDisplayMetadataProvider, которая устанавливает ConvertEmptyStringToNull в false для всех строковых свойств:
public class EmptyStringDisplayMetadataProvider :
IDisplayMetadataProvider
{
public void CreateDisplayMetadata(
DisplayMetadataProviderContext context)
{
if (context.Key.ModelType == typeof(string))
context.DisplayMetadata
.ConvertEmptyStringToNull = false;
}
}

Использование:
// …
builder.Services.Configure<MvcOptions>(opts =>
{
opts.ModelMetadataDetailsProviders
.Add(new EmptyStringDisplayMetadataProvider());
});
// …


Источник: https://josef.codes/dont-let-asp-net-core-set-empty-strings-to-null-when-posting-forms/
👍21
День 2136. #Оффтоп
async2 — Завершение Эксперимента с Асинхронностью в .NET. Начало

Команда .NET работала над новым экспериментом под названием async2, который представляет собой новую реализацию шаблона async/await, разработанную для большей эффективности и гибкости, чем текущая реализация. Он начался с зелёных потоков и закончился экспериментом, который перемещает async и await в среду выполнения. Рассмотрим путь async2 и то, чем закончился эксперимент.

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

В настоящее время для потоков и в некоторой степени для async/await создаётся новый стек. Вы можете легко увидеть это в IDE, при отладке (см. картинку).

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

Отказ от зелёных потоков
Ключевые проблемы, которые привели к отказу от эксперимента с зелеными потоками, были следующими:
1. Сложное взаимодействие между зелёными потоками и существующей моделью асинхронности;
2. Взаимодействие с нативным кодом было сложным и медленнее, чем при использовании обычных потоков;
3. Проблемы совместимости с мерами безопасности, такими как теневые стеки;
4. Неопределённость относительно того, можно ли сделать зелёные потоки быстрее, чем async в важных сценариях, учитывая усилия, необходимые для улучшения.

Это привело к выводу, что зелёные потоки — неверный путь для среды выполнения .NET, и породило эксперимент async2.

async2
Очевидно, это просто кодовое имя. Целью эксперимента было переместить async и await в среду выполнения. Главной мотивацией этого было сделать async более эффективным и гибким. Поскольку async уже используется как идентификатор в C#, команда решила использовать async2 в качестве кодового имени для эксперимента. Если эта штука когда-нибудь попадёт в среду выполнения, она будет называться async — то есть это будет замена текущей реализации async. В следующем посте разберём, что же это такое.

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

Источник:
https://steven-giesel.com/blogPost/59752c38-9c99-4641-9853-9cfa97bb2d29/async2-the-net-runtime-async-experiment-concludes
👍25
День 2137. #Оффтоп
async2 — Завершение Эксперимента с Асинхронностью в .NET. Окончание

Начало

async — функция компилятора
Текущая реализация async и await — это функция компилятора. Компилятор генерирует конечный автомат для async -метода. Среда выполнения ничего не знает об async и await. Нет никаких следов ключевого слова async в IL или в JIT-скомпилированном коде. И вот с этого начался эксперимент, подробно описанный здесь.

async — функция среды выполнения
Целью эксперимента было переместить async и await в среду выполнения. Это позволило бы среде выполнения иметь больше контроля над самим шаблоном. При этом также была бы другая семантика.

async2 не сохраняет и не восстанавливает контекст синхронизации и контекст исполнения на границах функций, вместо этого позволяя вызывающим методам наблюдать изменения. С ExecutionContext это изменяет поведение AsyncLocal.

Сегодня AsyncLocal используется для хранения данных, которые передаются с логическим контекстом вызова. Они копируются в новый контекст. Тем не менее, если функция глубоко в стеке вызовов изменяет значение AsyncLocal, вызывающий метод не увидит обновлённое значение, его увидят только методы ниже по логическому асинхронному потоку. Например:
await new AsyncLocalTest().Outer();

public class AsyncLocalTest
{
private readonly AsyncLocal<string>
_al = new();

public async Task Outer()
{
_al.Value = "Out";
Console.WriteLine($"Outer: {_al.Value}");
await Inner();
Console.WriteLine($"Outer: {_al.Value}");
}

private async Task Inner()
{
_al.Value = "In";
Console.WriteLine($"Inner: {_al.Value}");
await Task.Yield();
Console.WriteLine($"Inner: {_al.Value}");
}
}

Вывод:
Outer: Out
Inner: In
Inner: In
Outer: Out

В async2 изменения не «откатываются», что приводит к другому выводу:
Outer: Out
Inner: In
Inner: In
Outer: In


Сравнение с текущей реализацией
Команда обнаружила, что подход с помещением асинхронности в JIT может дать наилучшие результаты в целом. Вот основные отличия:
1. Производительность
Async обычно медленнее, чем async2, особенно для глубоких стеков вызовов, где async2 имеет производительность, сопоставимую с синхронным кодом в сценариях без приостановки исполнения.
2. Обработка исключений
В async медленно и неэффективно, вызывает паузы GC и влияет на отзывчивость приложений. В async2 улучшена.
3. Ограничение глубины стека
Присутствует в async, что может вызвать проблемы для глубоких стеков вызовов. Нет явных ограничений в async2.
4. Потребление памяти
В async обычно ниже, особенно в сценариях с большим количеством приостановленных задач. В async2 более высокое потребление памяти из-за захвата целых стековых кадров и регистров, но все ещё приемлемо по сравнению с другими факторами, такими как время паузы.

Полный документ здесь.

Что дальше?
Пока это всего лишь эксперимент, который может привести к замене async через несколько лет. Да, может пройти некоторое время, прежде чем это будет выпущено. А для переходной фазы должен быть interop для async <-> async2. В любом случае - очень хорошая отправная точка. Ждём async2, как юнионов.

Источник: https://steven-giesel.com/blogPost/59752c38-9c99-4641-9853-9cfa97bb2d29/async2-the-net-runtime-async-experiment-concludes
👍20
День 2138. #УрокиРазработки
Уроки 50 Лет Разработки ПО


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

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

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

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

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

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

В своей книге Software Teamwork Джим Броссо рекомендует каждой команде выработать свой контракт. Контракт должен отражать специфику конкретной команды, но быть связан с другими командами и компанией в целом. Он может содержать заявления, подобные этим:
- Для принятия решений на основе консенсуса мы проводим дебаты, уважая при этом мнения друг друга.
- Мы вовремя приходим на встречи и другие мероприятия и соблюдаем повестку дня.
- Члены команды должны стремиться завершить к установленным срокам все задачи, которые взяли на себя.
- Мы можем расходиться во мнениях внутри команды, но вовне представляем единую позицию.
- Мы приветствуем различные точки зрения, чтобы максимизировать коллективное творчество.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
👍10
День 2139. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Командная работа. Окончание

Начало

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

IT — необычная техническая дисциплина, поскольку привлекает людей с широким спектром знаний, характеристик и взглядов и выигрывает от их присутствия. Группа разработчиков, состоящая из экспертов в области технологий, только выиграет от присутствия в ней нетехнических специалистов с сильными коммуникативными навыками и знанием предметной области.

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

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

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

2. Попробуйте перечислить предпринимаемые руководителями или членами команды модели поведения и действия, которые усиливают внимание к культуре, ориентированной на качество.

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

4. Насколько хорошо вы понимаете культуру компании? Соответствует ли культура вашей команды культуре компании? Если нет, то что можно сделать, чтобы уменьшить разрыв?

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
👍8
День 2140. #МоиИнструменты
Создаём и Тестируем Устойчивые Приложения в .NET с Помощью Dev Proxy
При создании приложений, подключающихся к API, мы обычно фокусируемся на том, чтобы приложение работало. Но что, если API работает медленно, возвращает ошибки или становится недоступным? Сложно смоделировать, как ваше приложение будет справляться с этими сценариями, если вы не контролируете API, с которыми вы интегрируетесь.

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

Dev Proxy — это симулятор API, который позволяет моделировать различное поведение API, не изменяя ни одной строки кода вашего приложения. Вы можете моделировать ошибки, задержки, ограничение скорости и многое другое. И всё это время ваше приложение думает, что оно подключено к настоящему API.

Dev Proxy — это веб-прокси, который вы запускаете локально на своей машине разработки. Перед запуском вы настраиваете его для отслеживания запросов на определённые URL. Затем определяете, как он должен обрабатывать эти запросы: возвращать предопределённый ответ, выдавать ошибку, задерживать ответ или имитировать ограничение скорости или другие поведения? Когда вы запускаете Dev Proxy, он регистрируется как ваш системный прокси и перехватывает все запросы, которые соответствуют настроенным вами URL. Затем он применяет определённые вами поведения. Ваше приложение не знает, что оно не общается с реальным API. Оно просто получает ответы. Это отличный способ проверить, как ваше приложение обрабатывает различные поведения API.

По умолчанию Dev Proxy имитирует ошибку в ответ на запрос с вероятностью 50%. Если запрос не возвращает ошибку, Dev Proxy передаёт его реальному API.

Как улучшить устойчивость приложения для обработки сценария с ошибкой API? Во-первых, мы должны рассмотреть возможность перехвата исключения API и отображения его в удобном для пользователя виде. Это поможет обрабатывать как ошибки API, так и, например, ограничения частоты запросов (ошибка 429 Too Many Requests). Мы также должны рассмотреть возможность обработки ошибки 429 отлично от остальных ошибок, чтобы гарантировать, что приложение корректно сделает паузу и даст API время на восстановление.

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

Подробный пример работы с Dev Proxy рассмотрен в этом видео.

Источник: https://devblogs.microsoft.com/dotnet/build-test-resilient-apps-dotnet-dev-proxy/
👍10
День 2141. #ЧтоНовенького
Обновите Проекты Windows Forms для Повышения Безопасности
Каждый выпуск .NET представляет множество новых функций и исправлений ошибок, которые повышают как производительность, так и безопасность. Чтобы воспользоваться этими преимуществами, разработчики как сервисных, так и настольных приложений должны обновить свои приложения до последних версий .NET. Последнее обновление повысит безопасность опыта разработки WinForms в Visual Studio и мотивирует разработчиков WinForms обновлять свои приложения для повышения безопасности. Также это означает, что больше не будут поддерживаться проектирование форм в проектах, ориентированных на старые, неподдерживаемые версии .NET. Т.е. разработчикам также необходимо будет обновить свои проекты до поддерживаемых сред выполнения .NET, чтобы создавать формы в Visual Studio.

Обновление WinForms Designer и ваших приложений до новых версий .NET не только повышает безопасность, но и улучшает надёжность и производительность во время разработки за счет использования улучшений, доступных в новых версиях .NET и связанных NuGet-пакетах. Настоятельно рекомендуется обновлять ваши приложения до последних версий .NET.

Начиная с выпуска VS 17.12 Preview 3, WinForms Designer будет автоматически проверять целевую версию .NET вашего проекта. Если она ниже минимальной поддерживаемой версии, вы получите уведомление. Эта функция будет держать вас в курсе совместимости вашего проекта, обеспечивая лёгкий доступ к списку версий .NET и статусу их поддержки.

Будущая поддержка WinForms Designer в отношении сред выполнения .NET
Каждый раз, когда поддержка LTS выпуска .NET будет заканчиваться, Visual Studio будет обновлять минимальную поддерживаемую версию утилиты дизайна форм до этой версии LTS. Например, поддержка .NET 6 прекратилась в ноябре 2024 года, следующий выпуск Visual Studio, 17.13, обновит дизайнер форм, чтобы в качестве минимальной поддерживаемой версии была указана .NET 6. Следовательно, проекты, ориентированные на версии .NET ниже 6, такие как .NET Core 3.1 и .NET 5, больше не будут загружаться в дизайнере. Поэтому настоятельно рекомендуется обновить приложение до последней версии .NET, чтобы сохранить совместимость с Visual Studio 17.13 или более новыми версиями. Для миграции можно использовать дизайнер в Visual Studio 17.12.

Важное примечание: эти изменения повлияют только на работу дизайнера форм WinForms во время проектирования. Во время выполнения все версии .NET продолжат работать так же, как и сейчас.

Источник: https://devblogs.microsoft.com/visualstudio/upgrade-your-windows-forms-net-projects-to-the-latest-net-version-for-enhanced-security/
День 2142. #ЗаметкиНаПолях
Пакеты NuGet: Риски Безопасности и Лучшие Практики. Начало

NuGet-пакеты предлагают удобный способ обмена кодом, но многие разработчики загружают их, не просматривая содержимое или не проверяя обновления при выпуске новых версий.

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

Рассмотрим, что может пойти не так.

Что может сделать NuGet-пакет?
1. props и targets в MSBuild
NuGet-пакет может содержать файлы MSBuild, которые автоматически импортируются при сборке проекта. Эти файлы могут изменить процесс сборки вашего приложения. Может быть запущен target, выполняющий команды, или динамический код C#. Также может изменяться код вашего приложения перед его сборкой.
Вы можете проверить содержимое файлов в папках build, buildMultitargeting и buildTransitive NuGet-пакета.

2. Анализаторы и генераторы исходного кода Roslyn
NuGet-пакеты могут содержать анализаторы Roslyn. Они выполняются во время проектирования в IDE и во время сборки и могут делать всё, что угодно на вашем компьютере. Хотя анализаторы предназначены для анализа кода, на самом деле они работают внутри процесса компиляции и могут делать всё (песочницы нет): писать файлы, обновлять двоичные файлы после компиляции и т.д.
Генераторы исходного кода Roslyn очень похожи на анализаторы, поэтому к ним применяются те же проблемы безопасности. Они также могут добавлять или обновлять код вашего приложения при его сборке.
Обратите внимание, что вы можете запретить загрузку анализаторов из пакета, используя свойства IncludeAssets или ExcludeAssets в файле .csproj. Например, вы можете использовать следующий код, чтобы загрузить только библиотеки из пакета:
<PackageReference Include="Some.Package" Version="3.2.1">
<IncludeAssets>compile</IncludeAssets>
</PackageReference>

См. подробнее об управлении ресурсами зависимостей.

3. Библиотеки
Вы уверены, что DLL в NuGet-пакете — те, которые вам нужны? Даже если код находится на GitHub, вы уверены, что DLL собраны из этого кода? Вы можете проверить содержимое DLL, декомпилировав его. Если символы (PDB) предоставлены и содержат правильную информацию, вы можете автоматически проверить, что код построен из предоставленного исходного кода.

4. Выполнение кода при установке/удалении пакета
NuGet-пакеты могут содержать скрипты PowerShell, которые выполняются при установке или удалении пакета. Обратите внимание, что эти скрипты выполняются только для проектов, которые не используют <PackageReference>. Поэтому для большинства современных проектов это не проблема.
Перед установкой пакета обязательно проверьте содержимое пакета. Вы можете сделать это, загрузив пакет и распаковав его. Обязательно проверьте следующие файлы:
tools/init.ps1
tools/install.ps1
tools/uninstall.ps1


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

Источник:
https://meziantou.net/nuget-packages-security-risks-and-best-practices.htm
👍14
День 2143. #ЗаметкиНаПолях
Пакеты NuGet: Риски Безопасности и Передовой Опыт. Окончание

Начало

Другие векторы атаки
1. Тайпсквоттинг
Злоумышленник может создать пакет с именем похожим на популярный пакет. Например, Newtonsoft.Json можно заменить на Newtomsoft.Json или Newtomsoft-Json. Это называется тайпсквоттинг (атака через опечатки). Обязательно проверьте имя пакета перед его установкой.
Обратите внимание, что nuget.org позволяет резервировать префикс для предотвращения такого рода атак. Например, Newtonsoft – единственный автор, кто может создать пакет с префиксом Newtonsoft. Все его пакеты имеют галочку, указывающую на то, что они из зарезервированного префикса.

2. Тот же пакет, что и приватный пакет
Если у вас есть пакет, опубликованный во внутреннем канале, таком как Azure Packages, с тем же именем, что и у публичного пакета, публичный пакет можно использовать вместо приватного. Это проблема безопасности, поскольку вы не знаете содержимое публичного пакета. Вы можете использовать сопоставление источников пакетов, чтобы предотвратить эту проблему.

3. Удалённый пакет
Даже если вы проверили пакет и установили его, вы можете быть не в безопасности. На nuget.org вы не можете удалить пакет. Вы можете только пометить его как исключённый из списка (unlisted). Unlisted-пакет не отображается на веб-сайте или при разрешении графа пакетов. Но когда пакет обновляется, вы автоматически получаете новую версию. Это означает, что ваше приложение может использовать новую версию пакета, которую вы не проверили.
Чтобы предотвратить эту проблему, вы можете использовать файл блокировки (Lock-файл). Он содержит точную версию используемых вами пакетов. При восстановлении пакетов вы получаете точную версию, которую использовали ранее.

Лучшие практики
1. Проверяйте содержимое NuGet-пакета перед его установкой с помощью такого инструмента, как NuGet Package Explorer.
2. Используйте файл блокировки, чтобы предотвратить использование версии пакета, отличной от проверенной.
3. Используйте сопоставление источников пакетов, если ваш источник отличается от nuget.org.
4. Используйте IncludedAssets или ExcludedAssets для управления ресурсами, загруженными из пакета.
5. Проверяйте использование зарезервированного префикса, чтобы предотвратить тайпсквоттинг из-за опечаток

Итого
NuGet-пакет может:
- Выполнять код на вашем компьютере с разрешениями текущего пользователя.
- Выполнять код на CI-машинах с разрешениями пользователя CI.
- Изменять код вашего приложения и потенциально добавлять вредоносный код. Так он может выполнять код на ваших производственных компьютерах.
- Большинство пакетов безопасны, но вы не знаете, что может произойти в будущем. Взлом аккаунта NuGet или GitHub — это не редкость. Поэтому обязательно проверяйте содержимое пакетов, которые вы устанавливаете или обновляете.

И последнее, но не менее важное: другие менеджеры пакетов имеют похожие проблемы. Будьте бдительны при использовании любого пакета!

Источник: https://meziantou.net/nuget-packages-security-risks-and-best-practices.htm
👍14
День 2144. #Оффтоп
Развлекаемся с ValueTuple

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

Тип ValueTuple — это приятный синтаксический сахар. Если у вас есть следующий код, даже если вы назвали элементы кортежа:
(var one, var two) = MyFunc();
Console.WriteLine(one + two);

(int ANumber, int AnotherNumber)
MyFunc() => (1,2);

Это будет преобразовано компилятором в:
[CompilerGenerated]
internal class Program
{
private static void <Main>$(string[] args)
{
ValueTuple<int, int> valueTuple = <<Main>$>g__MyFunc|0_0();
int item = valueTuple.Item1;
int item2 = valueTuple.Item2;
Console.WriteLine(item + item2);
}

[CompilerGenerated]
[return: TupleElementNames(new string[] { "ANumber", "AnotherNumber" })]
internal static ValueTuple<int, int> <<Main>$>g__MyFunc|0_0()
{
return new ValueTuple<int, int>(1, 2);
}
}


Итак, компилятор генерирует список элементов, пронумерованных от 1 до любого количества элементов, которые у вас есть. Но происходит что-то интересное, если вы добавляете больше 7 элементов:
var (a,b,c,d,e,f,g,h) = MyFunc();
Console.WriteLine(a+b+c+d+e+f+g+h);

(int a, int b, int c, int d, int e, int f, int g, int h) MyFunc()
=> (1,2,3,4,5,6,7,8);

Это преобразовывается компилятором в:
ValueTuple<int, int, int, int, int, int, int, ValueTuple<int>> valueTuple = <<Main>$>g__MyFunc|0_0();
int item = valueTuple.Item1;
int item2 = valueTuple.Item2;
int item3 = valueTuple.Item3;
int item4 = valueTuple.Item4;
int item5 = valueTuple.Item5;
int item6 = valueTuple.Item6;
int item7 = valueTuple.Item7;
int item8 = valueTuple.Rest.Item1;

Console.WriteLine(item + item2 + item3 + item4 + item5 + item6 + item7 + item8);

После 7го элемента компилятор генерирует новое свойство Rest для хранения… ну, остального. Поэтому, если мы немного посходим с ума:
(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j,  int k, int l, int m, int n, int o, int p, int q, int r, int s, int t, int u, int v, int w, int x, int y, int z, int aa, int bb, int cc, int dd, int ee, int ff, int gg, int hh, int ii, int jj, int kk, int ll, int mm, int nn, int oo, int pp, int qq, int rr, int ss, int tt, int uu, int vv, int ww, int xx) MyFunc()
{
return (1, 2, 3, 4, 5, 6, 7, 8, 9, 10,
11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29, 30,
31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50);
}

И используем это так:
var (a,b,c,…,xx) = MyFunc();

То мы получим что-то вроде valueTuple.Rest.Rest.Rest.Rest.Item1.

Если хотите поиграть с этим, заходите на sharblap.io.

Источник: https://steven-giesel.com/blogPost/0a3db64c-e514-45fc-a1a1-2b79cc42f797/having-fun-with-valuetuple
👍22👎1
День 2145. #Карьера
Метрика Улучшения

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

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

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

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

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

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

Одной из метрик оценки качества программиста, которую можно использовать, является «Улучшение» (Betterment). Может ли программист определять области для улучшения и делает ли он их лучше без подсказок?

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

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

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

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

Группа D: превышают ожидания
Эта группа последовательно действовала, чтобы очистить ленту и улучшить систему, обеспечивая бесперебойную работу для всех, даже когда это не было их работой или напрямую не влияло на них.

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

Источник: https://angiejones.tech/the-betterment-metric/
👍12
День 2146. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 35. От передачи знаний выигрывают все

Знания не похожи на материальные предметы. Если у меня есть 3 штуки чего-то, и я дам вам 1, то у меня останется 2. Я должен потерять часть, чтобы вы что-то приобрели. Но со знаниями дело обстоит иначе: если я передам вам часть своих знаний, то не потеряю их. Я могу поделиться ими с другими людьми, как и вы. Этот расширяющийся круг знаний приносит пользу всем.

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

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

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

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

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

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

1. Технические беседы
Можно обсуждать прочитанные книги или статьи с коллегами за обедом. Это способствует формированию общего понимания материала и общего словарного запаса.

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 5.
10👍12
День 2147. #ЧтоНовенького
Новинки Visual Studio 17.12

В новой версии Visual Studio 2022 (17.12) представлено несколько интересных новинок.

1. Уведомление о переименовании файла
Часто возникает путаница в том, как работает Git при переименовании файлов. Git не хранит никакой информации для отслеживания переименований. Даже когда вы запускаете операцию git mv, это всего лишь сокращение для выполнения git rm, а затем git add для файла. Иногда Git запускает обнаружение переименования и может отображать удаление+добавление как переименование, но под капотом он использует эвристику, основанную на сходстве двух файлов, чтобы назвать это переименованием — и иногда он ошибается!
Когда вы переименовываете файл в Solution Explorer и смотрите на список изменённых файлов, это отображается как удаление+добавление. После того как вы сделаете Stage изменений, Git запустит обнаружение переименования, и вы сможете увидеть, как он заменит удаление+добавление на переименование в разделе Stage. Чтобы напоминать вам об этом, и добавлено новое уведомление.

2. Постоянная ссылка на код
Если вам нужно поделиться фрагментом кода с коллегами, вы знаете, как сложно сохранить контекст. С новой функцией Copy Git Permalink (Копировать Постоянную Ссылку на Git) вы теперь можете создать постоянную ссылку непосредственно из VS на удалённый репозиторий. Просто выберите нужный код, щёлкните правой кнопкой мыши и выберите Git > Copy Permalink. Ваш коллега сможет открыть ссылку, которой вы поделились, чтобы перейти к этой строке кода в интернет. Функция поддерживает репозитории Azure DevOps и GitHub (требуется вход в систему).

3. Подсказка о возвращаемых значениях
Вы когда-нибудь создавали временные переменные, только чтобы проверить возвращаемые значения функций? Эта новая функция позволит просматривать возвращаемые значения непосредственно в коде.
Раньше можно было посмотреть возвращаемые значения в окнах Autos или Locals. Они появляются после выхода из функции и возврата вызывающей стороне. Новая функция показывает эту информацию до выхода из функции и непосредственно в редакторе. Когда вы достигаете точки останова или проходите по коду, VS 2022 автоматически отображает значение, которое будет возвращено, в строке рядом с закрывающей скобкой метода.
Чтобы подробнее изучить возвращаемые значения, наведите указатель мыши это него и щёлкните значок Ask Copilot (Спросить Copilot) на подсказке по данным. Откроется новое окно чата Copilot, отладчик соберёт соответствующий контекст и передаст его Copilot для анализа. Copilot объяснит, почему вы видите это значение, предоставит информацию о потенциальных проблемах и даже сможет предложить исправления кода.

4. Неблокирующая очистка кода
Традиционный процесс Code Cleanup в VS может занимать некоторое время и заблокировать всю IDE, что делало его нецелесообразным для запуска при каждом сохранении. Теперь, когда вы сохраняете свою работу, Code Cleanup может работать в фоновом режиме, не прерывая ваш рабочий процесс. Больше не нужно ждать завершения очистки, прежде чем возобновить работу. Если вам нужно внести изменения, то, когда редактор обнаруживает пользовательский ввод, процесс очистки останавливается. Сохранитесь ещё раз, чтобы перезапустить очистку обновленного кода.
Включить очистку кода при сохранении можно в меню Tools > Options > Text Editor > Code Cleanup (Инструменты > Опции > Текстовый Редактор > Очистка Кода).

Источники:
-
https://devblogs.microsoft.com/visualstudio/boost-your-git-confidence-with-the-new-file-rename-notification/
-
https://devblogs.microsoft.com/visualstudio/introducing-the-copy-git-permalink-feature-in-visual-studio-17-12/
-
https://devblogs.microsoft.com/visualstudio/how-inline-return-values-simplify-debugging-in-visual-studio-2022/
-
https://devblogs.microsoft.com/visualstudio/keep-working-with-non-blocking-code-cleanup/
👍10
День 2148. #ЗаметкиНаПолях
Гибридный Кэш в
ASP.NET Core 9. Начало
В .NET 9 представлен гибридный кэш (HybridCache), механизм кэширования, который сочетает скорость кэширования в памяти с масштабируемостью распределённого кэширования. Я уже писал о новинке тут. Теперь рассмотрим его подробнее.

Что это?
HybridCache — это абстрактный класс с реализацией по умолчанию, который обрабатывает большинство аспектов сохранения в кэш и извлечения из кэша. HybridCache также включает в себя некоторые важные функции, относящиеся к процессу кэширования:
- Двухуровневое кэширование (L1/L2)
Использует быстрый кэш в памяти (L1) для быстрого извлечения данных и распределённый кэш (L2) для согласованности данных в нескольких экземплярах приложения.
- Защита от паники в кэше
Предотвращает панику в кэше при нескольких параллельных запросах, гарантируя, что только один запрос извлекает данные, а другие ждут, что снижает ненужную нагрузку.
- Инвалидация на основе тегов
Позволяет группировать записи кэша тегами, что обеспечивает эффективное удаление связанных элементов кэша одновременно.
- Настраиваемая сериализация
Позволяет настраивать методы сериализации данных, поддерживая различные форматы, такие как JSON, Protobuf или XML, в соответствии с потребностями конкретного приложения.

Добавляем гибридный кэш в .NET 9
1. Установим NuGet-пакет
dotnet add package Microsoft.Extensions.Caching.Hybrid


2. Зарегистрируем сервис
builder.Services.AddHybridCache(opts =>
{
opts.MaximumPayloadBytes = 1024 * 1024; // 1 MB
opts.MaximumKeyLength = 512;
opts.DefaultEntryOptions = new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(30),
LocalCacheExpiration = TimeSpan.FromMinutes(30)
};
});


Cвойства HybridCacheOptions позволяют настраивать ограничения, применяемые ко всем записям кэша:
- MaximumPayloadBytes — максимальный размер записи кэша. Значение по умолчанию — 1 МБ.
- MaximumKeyLength — максимальная длина ключа. Значение по умолчанию — 1024 символа.
Попытки сохранить значения, превышающие эти размеры, записываются в лог, но значение не сохраняется в кэше.
- DefaultEntryOptions – настраивает время хранения элементов в кэше: Expiration – общее время хранения элемента, LocalCacheExpiration – время хранения элемента в кэше L1.

3. Настроим распределённый кэш (не обязательно)
Например, используем Redis:
builder.Services
.AddStackExchangeRedisCache(opts =>
{
opts.Configuration = "connectionString";
});

Это делать не обязательно, т.к. HybridCache может работать и как кэш только в памяти.

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

Источник:
https://thecodeman.net/posts/hybrid-cache-in-aspnet-core
👍22
День 2149. #ЗаметкиНаПолях
Гибридный Кэш в
ASP.NET Core 9. Окончание
Начало

Используем HybridCache
Допустим, у нас есть API, предоставляющий информацию о продукте. Часто используемые данные будут кэшироваться для повышения производительности:
1. L1 (в памяти) - для обслуживания быстрых чтений из локального кэша.
2. L2 (Redis) - для обеспечения согласованности данных в распределённых экземплярах.
public class ProductService(
HybridCache cache)
{
public async Task<List<Product>>
GetProductsByCategoryAsync(
string category,
CancellationToken ct = default)
{
var key = $"products:category:{category}";

return await cache.GetOrCreateAsync(
key,
async token =>
await FetchFromDB(category, token),
ct
);
}
}


Как это работает
1. Метод проверяет, существует ли key в HybridCache. Если да, возвращаются кэшированные данные (из L1, если доступно; в противном случае из L2).
2. Если данные отсутствуют в кэшах L1 и L2, вызывается делегат (FetchFromDB) для извлечения данных из базы данных.
3. После извлечения данных они сохраняются в кэшах L1 и L2 с указанными политиками истечения срока действия (HybridCacheEntryOptions - их можно задать для всех элементов при регистрации кэша, либо в перегруженной версии GetOrCreateAsync).
4. Метод возвращает список продуктов либо из кэша, либо после извлечения из базы данных.

Удаление данных из кэша
Можно использовать метод RemoveAsync:
public async Task RemoveFromCache(
string category,
CancellationToken ct = default)
{
var key = $"products:category:{category}";
await cache.RemoveAsync(key, ct);
}

Запись удаляется из кэшей L1 и L2. Если ключ не существует, метод не делает ничего.

Добавление элементов с тегами
При сохранении записей в кэше вы можете назначать теги для их логической группировки. Для этого используется перегрузка GetOrCreateAsync:
// …
return await cache.GetOrCreateAsync(
key,
async token =>
await FetchFromDB(category, token),
new HybridCacheEntryOptions
{
Expiration = TimeSpan.FromMinutes(10),
LocalCacheExpiration = TimeSpan.FromMinutes(5),
Tags = new List<string> { $"category:{category}" }
},
ct
);

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

Чтобы удалить все элементы, имеющие определённый тэг, используется метод RemoveByTagAsync:
public async Task InvalidateByTag(
string tag,
CancellationToken ct = default
)
{
await _cache.RemoveByTagAsync(tag, ct);
}


Источник: https://thecodeman.net/posts/hybrid-cache-in-aspnet-core
👍13
День 2150. #ЧтоНовенького #NET10
Заглядываем в .NET 10
9я версия .NET вышла всего месяц назад, а уже появляются предложения того, что может появиться через год в юбилейной 10й версии.

1. «Левое объединение» в LINQ
В LINQ есть оператор Join, который чаще всего в SQL преобразуется во что-то вроде INNER JOIN. В LINQ нет встроенного оператора для LEFT JOIN, но вы можете достичь того же результата, используя комбинацию GroupJoin, SelectMany и DefaultIfEmpty:
var query =
_dbctx.Table1
.GroupJoin(
_dbctx.Table2,
t1 => t1.T2Id,
t2 => t2.Id,
(t1, t2) => new { t1, t2 }
)
.SelectMany(
t => t.t2.DefaultIfEmpty(),
(t, t2) => new { t1 = @t.t1, t2 }
);

Имейте в виду, если вы хотите объединить несколько столбцов, они должны иметь одинаковые имена и типы данных.

Теперь появилось предложение добавить оператор LeftJoin в .NET 10. Тогда запрос выше будет выглядеть так:
var query = _dbctx.Table1
.LeftJoin(
_dbctx.Table2,
t1 => t1.T2Id,
t2 => t2.Id,
(t1, t2) => new { t1, t2 }
);

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

2. Неблокирующий старт фоновых сервисов
Небольшое изменение в способе запуска BackgroundService в .NET 10. Вы могли заметить, что запуск фонового сервиса блокирует запуск приложения до тех пор, пока не будет запущен сервис. Это происходит из-за того, что метод StartAsync вызывается синхронно в реализации IHostedService. Вы можете использовать следующий трюк, чтобы обойти это:
public class MyService : BackgroundService
{
private IHostApplicationLifetime _lt;

public MyService(IHostApplicationLifetime lt)
{
_lt = lt;
}

protected override async Task
ExecuteAsync(CancellationToken ct)
{
await Task.Yield();
// Вся работа здесь
}
}

Или обернуть всё в Task.Run. Но это не очень хорошо и нелегко обнаружить. В .NET 10 это поведение будет заменено на реально асинхронное, и приложение не будет блокироваться при запуске.

3. Новый компаратор строк
Представьте, что вы хотите отсортировать следующие две строки: Windows 10 и Windows 7. Если рассматривать их исключительно как строки, Windows 10 будет идти перед Windows 7, потому что символ 1 идет перед 7. Но есть контексты, в которых вам нужно рассматривать некоторую часть строки как число и сортировать строки соответствующим образом. Вот тут и пригодится новый StringComparer. Он позволит вам сортировать строки как числа, поэтому Windows 10 будет идти после Windows 7.
var list = new List<string> { "Windows 10", "Windows 7" };
list.Sort(StringComparer.NumericOrdering);

Другой пример, упомянутый в предложении, - сортировка IP адресов.

Источники:
-
https://steven-giesel.com/blogPost/82ebfd51-23c0-44b7-9602-628d1aba5f3c/linq-might-get-a-left-join-operator-in-net-10
-
https://steven-giesel.com/blogPost/3a8c29a3-750a-40f0-aa43-c236b855813e/some-news-about-net-10-backgroundservices-and-new-string-comparer
👍29