.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
День 1920. #УрокиРазработки
Уроки 50 Лет Разработки ПО


Урок 7. Запись знаний дешевле, чем повторное их обретение
Приходилось ли вам исследовать существующие системы, чтобы выяснить, как их изменить? А кто из вас записывал всё, что узнал, для дальнейшего использования?

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

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

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍16
День 1921. #ЗаметкиНаПолях
Не Изменяйте Строки Подключения Вручную
Вам когда-нибудь приходилось изменять строку подключения в коде? Вы использовали регулярное выражение или другие манипуляции со строкой? Есть способ лучше.

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

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

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

Лучше использовать построитель строки подключения. Это классы, которые наследуют от базового System.Data.Common.DbConnectionStringBuilder. Например, System.Data.SqlClient.SqlConnectionStringBuilder используется для подключения к Microsoft SQL Server, но есть версии и для других СУБД.

Сначала нам нужен доступ к значению строки подключения (она должна поступать из системы конфигурации приложения):
var connStr = "Data Source=myServerAddress;Initial Catalog=db_1;User Id=my_user;Password=Pa55w0rd!;";

Это значение может быть использовано как аргумент конструктора построителя строк:
var builder = 
new SqlConnectionStringBuilder(connStr);

Мы можем изменять любые значения в строке подключения. Здесь обновим имя БД или исходный каталог:
builder.InitialCatalog = "new_db";

Теперь можно получить доступ к обновлённой строке подключения и использовать её:
var newConnStr = builder.ConnectionString;

Обновлённое значение будет:
Data Source=myServerAddress;Initial Catalog=new_db_name;User ID=my_user;Password=Pa55w0rd!

Как видите, изменился только исходный каталог. Остальная структура осталась прежней.

Источник: https://adamstorr.co.uk/blog/stop-using-regex-for-updating-connection-strings/
👍20
День 1922. #юмор
👍24👎1
День 1923. #ЗаметкиНаПолях
Отображаем Математические Формулы в HTML

Это довольно редкий случай (в зависимости от вашего домена), но иногда бывает нужно вывести на экран математическую формулу (и порой довольно сложную). На протяжении многих лет существовали различные рекомендации и спецификации W3C для языка математической разметки. MathML разработан как универсальная спецификация для математической записи во многих различных областях: браузеры, офисные пакеты, программы чтения EPUB, генераторы на основе LaTeX и т.п.

Самый ранний язык математической разметки (MathML) 1 был рекомендован в 1998 году и даже был включен в Mozilla 1.0. С тех пор появились ещё две версии MathML, причем второе издание MathML 3.0 было утверждено в качестве стандарта ISO в 2015 году.

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

MathML Core — это попытка создать минимальную версию MathML, хорошо совместимую с современной веб-платформой с упором на тестируемость и совместимость. MathML 3 содержал 195 элементов; MathML Core ориентирован на около 30!

Язык представляет собой набор HTML элементов, заключённый в общего родителя – элемент <math>. Например, вот так будет выглядеть дробь «x в квадрате, делённое на 3» (к сожалению, Телеграм пока не поддерживает MathML 😊):
<!-- родительский элемент -->
<math>
<!-- дробь: 1й дочерний элемент – числитель, 2й - знаменатель -->
<mfrac>
<!-- Число (1й дочерний) в степени (2й) -->
<msup>
<!-- mi - идентификатор (переменная или функция) -->
<mi>x</mi>
<!-- mn – числовая константа -->
<mn>2</mn>
</msup>
<mrow>
<mn>3</mn>
</mrow>
</mfrac>
</math>

Поскольку это HTML-элементы, они позволяют включать в себя и другие HTML-элементы, например, поля для ввода (если вы, например, создаёте форму для теста по математике), а также позволяют использовать CSS для стилизации.

Единственная проблема в том, что писать элементы MathML некрасиво и довольно утомительно. Одной из самых популярных альтернатив является MathJax, который включает в себя целый движок отображения на JavaScript. Если вы разместите сценарий MathJax на своей странице, он просканирует HTML-код и заменит блоки с математическими выражениями эквивалентом в MathML. MathJax использует выражения TeX/LaTeX (внутри блоков $$..$$), которые гораздо короче и проще для понимания, чем MathML. Например, вот формула корней квадратного уравнения:
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$


AsciiMath идёт ещё дальше, и позволяет писать более понятные выражения, как если бы мы писали их на одном из языков программирования. Например, вот та же формула корней квадратного уравнения в AsciiMath:
`x = (-b-sqrt(b^2-4ac))/(2a)`

MathJax поддерживает и формат AsciiMath.

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

Источник: https://andrewlock.net/rendering-math-in-html-mathml-mathml-core-and-asciimath/
👍12
День 1924. #Книги
Пособие по Основам Разработки
Тут в одном из чатов выложили преинтересную ссылку. В Майкрософт создали целое пособие по разработке и выложили его для всеобщего обозрения.

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

Здесь есть множество полезных статей, шпаргалок и чек-листов, например:
- Структура спринта: как подготовить проект и команду, какая работа делается на каждом этапе спринта.
- Чек-лист основ разработки: настроена ли система управления версиями, настроено ли тестирование и CI/CD, согласованы ли обзоры кода, учтена ли безопасность, настроен ли мониторинг системы
- Документация по Agile
- Документация по видам автоматизированного тестирования
- Советы и инструменты для проведения обзоров кода
- и многое, многое другое.

В общем, настоятельно советую к прочтению и себе отложил в закладки.
👍28
День 1925. #ЗаметкиНаПолях
Полезные функции EF Core 8. Начало
Рассмотрим набор функций Entity Framework Core 8, которые могут быть полезны многим.

1. Поддержка сопоставления коллекций примитивов
Коллекция примитивов - это набор значений примитивного типа для провайдера БД (обычно это числа и строки, перечисления). Раньше этого можно было достичь с помощью специального кода, а теперь это доступно прямо из коробки. Например, теперь можно легко сопоставить свойство:
public List<string> Tags { get; }

с его конфигурацией
builder.Property(o => o.Tags);

Тогда для следующей таблицы:
CREATE TABLE "Tweets" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Tweets" PRIMARY KEY AUTOINCREMENT,
"Name" TEXT NOT NULL,
"Tags" TEXT NOT NULL
);

EF сохранит коллекцию значений в (в данном случае) одной строке и распарсит их обратно в список объектов, которые вы ожидаете при запросе из БД, что довольно удобно. Это также будет работать для таких типов, как uint, bool, DateOnly, DateTime, Uri.
Uri? Да, функция будет работать и для типов, для которых в EF есть встроенные преобразователи!

2. Сложные типы
Говоря о типах объектов, которые хранятся и сопоставляются с реляционными БД с помощью Entity Framework, можно грубо выделить 3 категории:
- Типы с одним значением: int, string, Guid, DateTime, и т.п.
- Структурированные объекты, однозначно определённые с помощью ключа (сущности).
- Структурированные объекты, не определяемые ключом (типы-значения).

Начиная с EF Core 8 появился хороший способ сопоставления третьей категории объектов. Рассмотрим простой пример модели:
public class Price
{
public decimal Amount { get; set; }
public string Currency { get; set; }
}

public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public Price Price { get; set; }
}

Конфигурация для сущности Product может выглядеть так:
public void Configure(EntityTypeBuilder<Product> b)
{
b.ToTable("Products");
b.HasKey(p => p.Id);

b.ComplexProperty(p => p.Price);
}

Мы получим примерно такую таблицу:
CREATE TABLE "Products" (
"Id" INTEGER NOT NULL CONSTRAINT "PK_Products" PRIMARY KEY AUTOINCREMENT,
"Name" TEXT NOT NULL,
"Price_Amount" TEXT NOT NULL,
"Price_Currency" INTEGER NOT NULL
);

Как видим, EF Core автоматически объединит свойства сложного объекта в соответствующее количество столбцов.

Примечание. В настоящее время невозможно сопоставить сложные типы с другой таблицей.

Пример выше может привести к проблемам из-за изменяемости объекта Price. Если продукт имеет две цены (например, розничную и оптовую), которым мы изначально назначили один и тот же экземпляр Price, при изменении значения одной цены результирующий оператор SQL фактически изменит обе. Эту проблему можно легко обойти, сделав базовую сущность Price неизменяемой (или записью). Вот тестовый пример этого поведения.

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

Источник:
https://dateo-software.de/blog/entity-framework-8
👍11
День 1926. #ЗаметкиНаПолях
Полезные функции EF Core 8. Окончание

Начало

3. Столбцы JSON
Сопоставление столбцов JSON уже было частью EF Core 7, поэтому оно не совсем новое, но есть некоторые улучшения. Предположим, мы создаём некий код авторизации с настраиваемыми ролями и политиками:
public class Role
{
public int Id { get; set; }
public string Name { get; set; }
public IList<CustomPolicy>
Policies { get; set; };
}

public class CustomPolicy
{
public string Key { get; set; }
public bool Value { get; set; }
}

Чтобы сопоставить эти сущности с одной таблицей, а Policies - с одним столбцом, конфигурация будет такой:
public void Configure(EntityTypeBuilder<Role> b)
{
b.ToTable("Roles");
b.HasKey(o => o.Id);

b.OwnsMany(o => o.Policies, x =>
{
x.Property(p => p.Key);
x.Property(p => p.Value);
x.ToJson();
});
}

При создании таблицы свойство Policies будет текстовым столбцом, содержащим JSON. Это было и в EF Core 7. В 8й версии поддерживаются запросы с использованием индексов массивов JSON, трансляция запросов к коллекциям JSON, содержащим сложные типы, запросы и обновления отдельных полей JSON. Также JSON колонки доступны в SQLite.

4. Контрольные значения
Контрольное значение заставляет EF Core проверять заданное значение вместо значения по умолчанию типа для свойства, которое необходимо установить. Предположим, что мы моделируем сущность ToDoItem:
public class ToDoItem
{
public int Id { get; set; }
public string Name { get; set; }
public int Priority { get; set; }
}

По бизнес-правилам приоритет по умолчанию должен быть 100:
public void Configure(EntityTypeBuilder<ToDoItem> b)
{
b.ToTable("ToDoItems");
b.HasKey(o => o.Id);

b.Property(o => o.Priority)
.HasDefaultValueSql(100);
}

Т.к. свойство Priority не обнуляемое, а значение по умолчанию для int равно 0, у нас не будет возможности сохранить экземпляр ToDoItem со значением 0. EF Core идентифицировал бы 0 как значение по умолчанию, предположил, что свойство не установлено, и установил бы его в 100.

Если сделать свойство обнуляемым, то по умолчанию оно будет null. Но это заставит нас учитывать в коде, что Priority может null. В EF Core 8 можно настроить контрольное значение, т.е. значение, которое сообщает EF Core, что вместо него нужно вставить в БД значение по умолчанию:

b.Property(o => o.Priority)
.HasSentinel(-1)
.HasDefaultValueSql(100);

Здесь мы проверяем контрольное значение -1 (которое не используется в бизнес-логике), поэтому сохранение экземпляра с приоритетом 0 фактически становится возможным без костылей в реальной модели объекта.

Источник: https://dateo-software.de/blog/entity-framework-8
👍17
Какое свойство демонстрирует класс или метод, чей код тесно связан с единственной, хорошо определённой задачей?
#Quiz #BestPractices
Anonymous Quiz
25%
Сильная связанность (Tight coupling)
18%
Низкая изменчивость (Low variability)
14%
Слабая связанность (Loose coupling)
43%
Высокая связность (High cohesion)
👎22👍11
День 1927. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 8. Главное требование к разработке — налаженное и эффективное общение
Разработка ПО связана как с вычислениями, так и с общением. А разработка требований полностью основана на общении. Члены команды, которые отвечают за соблюдение требований (чаще их называют бизнес-аналитиками), находятся в центре сети общения. Они координируют обмен знаниями о требованиях между всеми участниками проекта. Бизнес-аналитик должен сообщать всем участникам информацию о требованиях, приоритетах, состоянии и изменениях.

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

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

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

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

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

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

Существует множество стандартных обозначений для анализа диаграмм и моделей, в том числе:
- структурированный анализ;
- IDEF0;
- унифицированный язык моделирования (Unified Modeling Language, UML);
- язык моделирования требований (Requirements Modeling Language, RML).

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍1
День 1928. #МоиИнструменты
Обновляем Устаревшие Пакеты в .NET

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

1. Диспетчер пакетов в IDE
В Visual Studio или Rider легко узнать, доступны ли новые версии пакетов, используемых вашим проектом, с помощью диспетчера пакетов NuGet.
В Visual Studio откройте «Tools > NuGet Package Manager > Manage NuGet Packages for Solution…» (Инструменты > Менеджер NuGet-Пакетов > Управлять NuGet-Пакетами в Решении…). На вкладке «Updates» (Обновления) выберите все обновления и нажмите «Обновить». Либо вы можете обновить их по одному. Кроме того, вкладка Consolidate (Консолидация) покажет пакеты, которые установлены в разных версиях в проектах решения и позволит привести все установленные пакеты к одной версии.
В Rider откройте «View > Tool Windows > NuGet» (Вид > Окна Инструментов > NuGet). Чтобы обновить установленные пакеты, нажмите «Upgrade Packages in Solution» (Обновить пакеты в решении) на панели инструментов окна NuGet, а затем выберите, какие пакеты следует обновить. Либо вы можете выбрать один из установленных пакетов в левой части окна NuGet, выбрать нужную версию в правой части, а затем обновить версию пакета в конкретных проектах.

2. Глобальная утилита dotnet-outdated
Это утилита командной строки с открытым исходным кодом. Для начала нужно её установить, выполнив следующую команду:
dotnet tool install --global dotnet-outdated-tool

Теперь вызовите её, выполнив команду в папке проекта или решения:
dotnet-outdated

Утилита выдаст список всех доступных обновлений, выделенных цветом:
- зеленым – патчи и исправления ошибок (обратно совместимо),
- желтым – обновления минорных версий (обратно совместимо, добавлены новые функции),
- красным – обновления мажорных версий (возможны ломающие изменения).
Чтобы обновить все устаревшие пакеты, выполните команду:
dotnet-outdated –upgrade


3. Через команду dotnet
Также можно использовать утилиты командной строки dotnet напрямую. Чтобы получить список устаревших пакетов, выполните следующую команду:
dotnet list package --outdated

Чтобы обновить устаревший пакет, нужно выполнить команду:
dotnet add package PACKAGENAME

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

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

Источник: https://bartwullems.blogspot.com/2024/05/net-core-view-outdated-packages.html?m=1
👍18
День 1929. #Карьера
Наибольшее Влияние на Качество Кода

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

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

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

Избегайте режима аврала!

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

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

Аврал – это провал в управлении проектом.

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

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

Источник: https://bartwullems.blogspot.com/2024/05/the-biggest-effect-on-code-quality.html
👍19
День 1930. #ЗаметкиНаПолях
Организуем Минимальные API в
ASP.NET Core
Часто говорят, что нельзя использовать минимальные API для «реальных» приложений. Скорее всего, причина в том, что большинство примеров очень просты и не показывают, как организовать код так, чтобы это имело смысл для более крупного приложения.

Проблема в том, что в ASP.NET все примеры заканчиваются некоторыми конечными точками в Program.cs со встроенным кодом (как показано ниже), и на самом деле это не то, каким вы хотите видеть код в более крупном приложении:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.MapGet("/todos", async (TodoDb db) =>
await db.Todos.ToListAsync());
app.MapGet("/todos/{id}",
async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());

app.Run();

Здесь мы используем пример из руководства Microsoft. Итак, рассмотрим, как организовать код в что-то более удобочитаемое.

1. Используем методы расширения для организации конечных точек
В папке Endpoints или Todos (если вы используете чистую архитектуру) создадим файл TodoEndpoints.cs:
public static class TodoEndpoints
{
public static void
RegisterTodoEndpoints(this WebApplication app)
{
app.MapGet("/todos", async (TodoDb db) =>
await db.Todos.ToListAsync());

app.MapGet("/todos/{id}",
async (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? Results.Ok(todo)
: Results.NotFound());

}
}

Это сразу сделает файл Program.cs намного чище:

var app = builder.Build();

app.RegisterTodosEndpoints();
app.Run();

Также мы можем разделить группы конечных точек по файлам.

2. Используем TypedResults вместо Results
TypedResults позволит нам не использовать атрибут или метод Produces для описания типа возвращаемого значения для OpenAPI/Swagger. Тип будет выведен из типа возвращаемого значения:
app.MapGet("/todos/{id}", 
async Task<Results<Ok<Todo>, NotFound>> (int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound());


3. Отделим функциональность от регистрации
Лямбда–выражение из метода конечной точки можно вынести в отдельный метод, что улучшит читаемость и тестируемость:
app.MapGet("/todos/{id}", GetById);

static async Task<Results<Ok<Todo>, NotFound>>
GetById(int id, TodoDb db) =>
await db.Todos.FindAsync(id)
is Todo todo
? TypedResults.Ok(todo)
: TypedResults.NotFound();

Тогда регистрация TodoEndpoints будет выглядеть так:
app.MapGet("/todos", GetAll);
app.MapGet("/todos/{id}", GetById);

// методы

Теперь в тестах методы можно вызывать напрямую, а не через API.

4. Группируем
Конечные точки можно сгруппировать, чтобы избежать повторения кода:
var todos = app.MapGroup("/todos");

todos.MapGet("/", GetAll);
todos.MapGet("/{id}", GetById);

Также к группе можно применять общие политики, тэги и т.п.
var todos = app.MapGroup("/todos")
.RequireAuthorization()
.WithTags("Todos");

Источник: https://www.tessferrandez.com/blog/2023/10/31/organizing-minimal-apis.html
👍43👎1
День 1931. #TipsAndTricks
Обновляем Сертификат для localhost в .NET Core

Многие команды не используют https на машинах разработчиков, поскольку не хотят возиться с сертификатами. Хорошей новостью является то, что добавить или обновить сертификат локального хоста в случае истечения срока при использовании Kestrel очень просто. Для управления самоподписанным сертификатом можно использовать встроенную команду dotnet dev-certs.

При необходимости сначала можно удалить существующий сертификат:
dotnet dev-certs https --clean

Вывод:
Cleaning HTTPS development certificates from the machine. A prompt might get displayed to confirm the removal of some of the certificates.
HTTPS development certificates successfully removed from the machine.

(Очистка сертификатов разработки HTTPS с компьютера. Может появиться запрос на подтверждение удаления некоторых сертификатов.
Сертификаты разработки HTTPS успешно удалены с компьютера.)


Теперь сгенерируем новый самоподписанный сертификат, и сразу добавим его в доверенные:
dotnet dev-certs https --trust

Вывод:
Trusting the HTTPS development certificate was requested. A confirmation prompt will be displayed if the certificate was not previously trusted. Click yes on the prompt to trust the certificate.
Successfully created and trusted a new HTTPS certificate.

(Было запрошено доверие к сертификату разработки HTTPS. Если сертификат ранее не был доверенным, отобразится запрос на подтверждение. Нажмите «Да» в запросе, чтобы доверять сертификату.
Успешно создан новый доверенный сертификат HTTPS.)

Наконец, следующая команда проверяет существующие сертификаты:
dotnet dev-certs https --check

Output:
A valid certificate was found: 189E61FFAD59C21110E9AD13A009B984EE5E8D5D - CN=localhost - Valid from 2024-04-22 13:11:50Z to 2025-04-22 13:11:50Z - IsHttpsDevelopmentCertificate: true - IsExportable: true

Run the command with both --check and --trust options to ensure that the certificate is not only valid but also trusted.

(Был найден действительный сертификат: 189E61FFAD59C21110E9AD13A009B984EE5E8D5D - CN=localhost - действителен с 22 апреля 2024 г., 13:11:50Z по 22 апреля 2025 г., 13:11:50Z - IsHttpsDevelopmentCertificate: true - IsExportable: true

Запустите команду с параметрами --check и --trust, чтобы убедиться, что сертификат не только действителен, но и добавлен в доверенные.)


Источник: https://bartwullems.blogspot.com/2024/05/net-core-renew-localhost-certificate.html
👍51
День 1933.
Microsoft Build 2024

Microsoft Build 2024 уже не за горами. Независимо от того, являетесь ли вы опытным разработчиком или только начинаете свой путь, каждый найдёт сессию для себя.

Мероприятие пройдёт как офлайн в Сиэтле, так и онлайн, и онлайн доступ бесплатный.

Вот некоторые из докладов, которые я отметил для себя (на самом деле их гораздо больше - вот полное расписание):
21 мая
21:30 мск - Developer’s Guide to Customizing Microsoft Copilot

22 мая
00:30 мск - Developer experience improvements in Windows
23:00 мск - Demystify Cloud-Native Development with .NET Aspire

23 мая
00:30 мск - .NET Aspire development on any OS with the Visual Studio family
04:00 мск - What’s new in GitHub Copilot and Visual Studio
18:30 мск - What’s New in C# 13
23:45 мск - Leverage Azure Testing Services to build high quality applications

Также есть набор предварительно записанных выступлений, которые можно посмотреть в любое время:
- What's New with WinForms in .NET 9?
- Enhancing .NET MAUI: Quality, Performance, and Interoperability in .NET 9
- Diagnostic techniques for .NET running on Linux and within containers
- .NET API development end-to-end
- EF Core 9: Evolving Data Access in .NET
- How to Quickly Build a .NET Desktop Dashboard
- May the forms be with you: a new hope with Blazor Hybrid on WinForms

Зарегистрироваться на Microsoft Build 2024 можно здесь.
👍2👎2
День 1933. #ЗаметкиНаПолях
Избегаем Конфликтов при Локальном Тестировании Шаблонов Проектов

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

Для использования шаблона проекта dotnet используются команды dotnet install и dotnet new, чтобы создать новый проект на основе локального шаблона. Однако dotnet install может конфликтовать с предыдущей установкой шаблона, опубликованного как пакет NuGet. Рассмотрим, как избежать этого конфликта и как протестировать шаблон локально.

В dotnet есть несколько скрытых аргументов, которые можно использовать для отладки шаблона. Аргумент --debug:custom-hive позволяет указать произвольное расположение кэша шаблонов. Это полезно, если вы хотите протестировать свой шаблон, не затрагивая глобальный кэш шаблонов:
dotnet install /путь/к/шаблону --debug:custom-hive /temp/hive

Теперь можно создать новый проект на основе установленного шаблона, передав в качестве параметра путь к вашему локальному кэшу:
dotnet new my_template --debug:custom-hive /temp/hive

Можно создавать столько локальных кэшей, сколько необходимо для создания изолированных сред для тестирования ваших шаблонов.

Источник: https://www.meziantou.net/how-to-avoid-conflicts-when-testing-your-dotnet-templates-locally.htm
👍3
День 1934. #ЗаметкиНаПолях #Frontend
ASP.NET Unobtrusive Validation. Группируем Сообщения об Ошибках
Сегодня пост из личного опыта. Немного легаси и немного «попрограммируем» на HTML+CSS 😊
Не знаю, как дела обстоят в UI фреймворках, таких, как React или Vue, т.к. не знаком с ними, но мы в компании до сих пор используем старый добрый HTML и jQuery. В том числе для валидации форм используется встроенная в ASP.NET jQuery Unobtrusive Validation. Она позволяет проверять формы на клиенте без написания логики валидации на JS. То есть в модели используются стандартные атрибуты Data Annotations.
Например, для модели:
public class MyModel
{
[Required]
public string Name { get; set; }
}

И формы
<form method="post">
Email: <input asp-for="Name" /> <br />
<span asp-validation-for="Name"></span>

</form>

Будет сгенерирован следующий HTML код:
<form method="post">
Name: <input name="Name" id="Name" type="text" value=""
data-val-required="The Name field is required."
data-val="true"><br>
<span class="field-validation-valid" data-valmsg-replace="true"
data-valmsg-for="Name"></span>

</form>

И эта форма автоматически будет проверяться средствами JS согласно этим атрибутам на клиенте без отправки формы на сервер. В случае непрошедшей валидации в элемент <span> будет добавляться соответствующее сообщение об ошибке, а его класс сменится с field-validation-valid на field-validation-error. Можно сделать так, что все ошибки формы будут выдаваться в одном месте (validation summary), либо для каждого поля в отдельности (как в этом случае).

Конечно, если требуется нестандартная валидация, можно как написать свой атрибут валидации, так и добавить в JS валидатор для него.

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

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

В общем то, решение довольно простое. Размещаем оба поля и оба валидатора для них:
<form method="post">
Expires:
<select asp-for="Month" asp-items="Model.Months"></select> /
<select asp-for="Year" asp-items="Model.Years"></select>
<div class="val-msg-group">
<span asp-validation-for="Month"></span>
<span asp-validation-for="Year"></span>
</div>

</form>

В этом случае, если оба поля будут пустыми, будут выведены оба сообщения об ошибке, по одному для каждого. Это решается просто сокрытием второго сообщения средствами CSS:
.val-msg-group .field-validation-error ~ .field-validation-error {
display: none;
}

Здесь мы внутри блока val-msg-group скрываем всех потомков, за которыми следует элемент с тем же классом field-validation-error. То есть, первое сообщение об ошибке будет показано (для какого бы поля оно ни было), а остальные будут спрятаны. См. видео ниже.

В общем, думаю, что приём будет полезен и в других UI фреймворках, работающих по подобному принципу.
👍5👎1
День 1935. #УрокиРазработки
Уроки 50 Лет Разработки ПО

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

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

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

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

Аудитория: Спонсор, отдел маркетинга, клиенты
Вопросы:
- Позволит ли решение, основанное на требованиях, достичь целей, поставленных клиентами?
- Понятны ли риски и последствия для бизнеса, связанные с каждым требованием?

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

Руководитель проекта:
- Сможет ли команда разработать решение с учетом имеющихся ресурсов и в рамках существующих ограничений?
- Позволяет ли описание каждого требования оценить его сложность и влияние на проект?

Бизнес-аналитик, владелец продукта, продакт-менеджер:
- Каждое ли требование представляет ценность для клиента?
- Являются ли требования чёткими и однозначными?
- Отсутствуют ли конфликты между требованиями?

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

Тестировщик:
- Можно ли протестировать выполнение каждого требования?

Другие заинтересованные стороны:
- Соответствуют ли требования всем ожиданиям и ограничениям, накладываемым моей точкой зрения?

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

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

Урок 9. Качество требований каждый определяет по-своему. Окончание

Начало

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

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

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

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

4. Достижимость
Разработчики смогут реализовать решение для удовлетворения данного требования в рамках известных технических, временных и ресурсных ограничений.

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

6. Приоритетность
Требования классифицируются по их относительной важности и своевременности включения в продукт.

7. Отслеживаемость
Каждому требованию присваивается уникальный идентификатор, чтобы его можно было связать с источником и далее с проектами, кодом, тестами и любыми другими элементами, созданными для удовлетворения этого требования. Знание источника дает дополнительный контекст и показывает, к кому можно обратиться за разъяснениями.

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

9. Достоверность
Существует некий объективный, однозначный и эффективный способ определить, удовлетворяет ли решение требованиям. Наиболее распространённый способ проверить достоверность — тестирование, поэтому некоторые называют эту характеристику тестируемостью.

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 2.
👍3