Какое свойство демонстрирует класс или метод, чей код тесно связан с единственной, хорошо определённой задачей?
#Quiz #BestPractices
#Quiz #BestPractices
Anonymous Quiz
25%
Сильная связанность (Tight coupling)
18%
Низкая изменчивость (Low variability)
14%
Слабая связанность (Loose coupling)
43%
Высокая связность (High cohesion)
👎22👍11
День 1947. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Начало
В этой серии рассмотрим, как с максимальной пользой использовать Serilog в приложениях минимальных API ASP.NET Core 8. Серия будет состоять из 3х частей.
1. Настройка
Приложения ASP.NET Core — «всего лишь» консольные приложения. Вы можете настроить Serilog и использовать его вообще без каких-либо особенностей ASP.NET Core. Для «пустого» проекта «минимального API» файл Program.cs будет выглядеть так:
Установим Serilog и консольный приёмник (sink):
В начале Program.cs создадим пайплайн логирования и назначим его статическому свойству Log.Logger:
Теперь при запуске должно появиться сообщение «Starting up» от Serilog, а затем вывод по умолчанию от ASP.NET.
Если приложение не запускается, мы хотим перехватить все возникающие исключения, а также убедиться, что все события буферизованного журнала записаны перед завершением процесса. Добавим try/catch/finally:
Здесь мы можем использовать класс Log для записи собственных структурированных событий журнала.
Возможно, сейчас у вас возникнет соблазн добавить ещё несколько приёмников для журнала. Не торопитесь, обсудим это в следующем разделе.
Продолжение следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Начало
В этой серии рассмотрим, как с максимальной пользой использовать Serilog в приложениях минимальных API ASP.NET Core 8. Серия будет состоять из 3х частей.
1. Настройка
Приложения ASP.NET Core — «всего лишь» консольные приложения. Вы можете настроить Serilog и использовать его вообще без каких-либо особенностей ASP.NET Core. Для «пустого» проекта «минимального API» файл Program.cs будет выглядеть так:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();
Установим Serilog и консольный приёмник (sink):
dotnet add package Serilog
dotnet add package Serilog.Sinks.Console
В начале Program.cs создадим пайплайн логирования и назначим его статическому свойству Log.Logger:
using Serilog;
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.CreateLogger();
Log.Information("Starting up");
// … остальной код минимального API
Теперь при запуске должно появиться сообщение «Starting up» от Serilog, а затем вывод по умолчанию от ASP.NET.
Если приложение не запускается, мы хотим перехватить все возникающие исключения, а также убедиться, что все события буферизованного журнала записаны перед завершением процесса. Добавим try/catch/finally:
using Serilog;
// … пайплайн логирования
try
{
// … код минимального API
return 0;
}
catch (Exception ex)
{
Log.Fatal(ex, "Unhandled exception");
return 1;
}
finally
{
await Log.CloseAndFlushAsync();
}
Здесь мы можем использовать класс Log для записи собственных структурированных событий журнала.
Возможно, сейчас у вас возникнет соблазн добавить ещё несколько приёмников для журнала. Не торопитесь, обсудим это в следующем разделе.
Продолжение следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍5
День 1948. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Продолжение
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
Это очень просто. Установим Serilog.Extensions.Hosting:
И вызовем AddSerilog():
Теперь логи приложения будут писаться в Serilog.
Если вы хотите записывать события в логи, нужно настроить место назначения: путь к файлу или URL сервера логов.
Для примера используем Seq:
Добавим его в пайплайн.
Вариант 1 – в коде, используя переменные среды:
Чтобы установить контейнер Seq, работающий по адресу http://localhost:5341, выполните:
Теперь после запуска приложения, можете перейти по адресу http://localhost:5341 в браузере и увидеть логи приложения.
Этот вариант удобен, т.к. компилятор проверит, предоставлены ли все необходимые параметры, и всё, что не изменяется во время развёртывания, может быть указано в строго типизированном C#. Он также надёжно работает при публикации приложения одним файлом.
Вариант 2 — использовать Serilog.Settings.Configuration для загрузки из appsettings.json.
Конфигурация доступна не сразу, т.е. мы не сможем отслеживать исключения, возникающие на ранних этапах запуска. Совет — не усложнять себе жизнь, упростив Program.cs до чего-то вроде:
appsettings.json будет выглядеть примерно так (Seq можно заменить другим хранилищем):
Подробнее о синтаксисе конфигурации см. здесь.
Для правильной настройки конфигурации JSON может потребоваться немного больше работы, она более хрупкая и требует немного больше тестирования.
Окончание следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Продолжение
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
Это очень просто. Установим Serilog.Extensions.Hosting:
dotnet add package Serilog.Extensions.Hosting
И вызовем AddSerilog():
…
try
{
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSerilog();
…
Теперь логи приложения будут писаться в Serilog.
Если вы хотите записывать события в логи, нужно настроить место назначения: путь к файлу или URL сервера логов.
Для примера используем Seq:
dotnet add package Serilog.Sinks.Seq
Добавим его в пайплайн.
Вариант 1 – в коде, используя переменные среды:
Log.Logger = new LoggerConfiguration()
.WriteTo.Console()
.WriteTo.Seq(
Environment.GetEnvironmentVariable("SEQ_URL")
?? "http://localhost:5341",
apiKey:
Environment.GetEnvironmentVariable("SEQ_API_KEY"))
.CreateLogger();
Чтобы установить контейнер Seq, работающий по адресу http://localhost:5341, выполните:
docker run --rm -it -e ACCEPT_EULA=y -p 5341:80 datalust/seq
Теперь после запуска приложения, можете перейти по адресу http://localhost:5341 в браузере и увидеть логи приложения.
Этот вариант удобен, т.к. компилятор проверит, предоставлены ли все необходимые параметры, и всё, что не изменяется во время развёртывания, может быть указано в строго типизированном C#. Он также надёжно работает при публикации приложения одним файлом.
Вариант 2 — использовать Serilog.Settings.Configuration для загрузки из appsettings.json.
powershell
dotnet add package Serilog.Settings.Configuration
Конфигурация доступна не сразу, т.е. мы не сможем отслеживать исключения, возникающие на ранних этапах запуска. Совет — не усложнять себе жизнь, упростив Program.cs до чего-то вроде:
using Serilog;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddSerilog(lc => lc
.WriteTo.Console()
.ReadFrom.Configuration(builder.Configuration));
var app = builder.Build();
…
appsettings.json будет выглядеть примерно так (Seq можно заменить другим хранилищем):
{
"Serilog": {
"Using": ["Serilog.Sinks.Seq"],
"WriteTo": [
{
"Name": "Seq",
"Args": {
"serverUrl": "http://localhost:5341",
"apiKey": "<API key here>"
}
}
]
},
"AllowedHosts": "*"
}Подробнее о синтаксисе конфигурации см. здесь.
Для правильной настройки конфигурации JSON может потребоваться немного больше работы, она более хрупкая и требует немного больше тестирования.
Окончание следует…
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍16
День 1949. #ЗаметкиНаПолях #BestPractices
Правильное Логирование Минимальных API в Serilog. Окончание
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
3. Запись веб-запросов
Приложение записывает несколько событий в журнал при обработке каждого веб-запроса. Далее рассмотрим, как объединить эту информацию в одно красиво отформатированное событие.
Классический способ сделать это — установить Serilog.AspNetCore и добавить app.UseSerilogRequestLogging() в код запуска вашего веб-приложения сразу после builder.Build(). Но если вы настраиваете всё с нуля, в долгосрочной перспективе вы получите лучший опыт, полагаясь на встроенную поддержку активности (System.Diagnostics.Activity).
Активность - это операция с началом и концом. ASP.NET Core использует активность как обёртку вокруг каждого обрабатываемого веб-запроса. Т.к. активность завершается после выполнения всего промежуточного ПО, она даёт более точную картину продолжительности запроса и конечного кода состояния, чем может предоставить промежуточное ПО UseSerilogRequestLogging(). Также активности участвуют в распределённой трассировке, поэтому вы можете просматривать входящие и исходящие запросы вашего приложения в иерархии, если выбранный вами приёмник это поддерживает.
1) Установим SerilogTracing, поддержку форматирования вывода консоли и интеграцию с ASP.NET Core:
2) В Program.cs, добавим средство форматирования с поддержкой трассировки в приёмник консоли и снизим детализацию некоторых источников журналов Microsoft.AspNetCore.*:
Здесь мы использовали Enrich (хотя это не обязательно), чтобы добавить свойство Application ко всем событиям, поскольку это помогает отслеживать в логах операции среди нескольких сервисов.
3) Сразу после этого настроим прослушиватель, который будет записывать действия ASP.NET Core в конвейер Serilog:
SerilogTracing работает со всеми приёмниками Serilog, но на данный момент только приёмники Seq, SerilogTracing.Sinks.OpenTelemetry и SerilogTracing.Sinks.Zipkin были написаны или изменены для поддержки бэкендов с функциями иерархической трассировки.
Совет: если вы используете приемник без поддержки иерархической трассировки, добавьте
Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
Правильное Логирование Минимальных API в Serilog. Окончание
1. Настройка
2. Связываем ASP.NET Core и ILogger<T>
3. Запись веб-запросов
Приложение записывает несколько событий в журнал при обработке каждого веб-запроса. Далее рассмотрим, как объединить эту информацию в одно красиво отформатированное событие.
Классический способ сделать это — установить Serilog.AspNetCore и добавить app.UseSerilogRequestLogging() в код запуска вашего веб-приложения сразу после builder.Build(). Но если вы настраиваете всё с нуля, в долгосрочной перспективе вы получите лучший опыт, полагаясь на встроенную поддержку активности (System.Diagnostics.Activity).
Активность - это операция с началом и концом. ASP.NET Core использует активность как обёртку вокруг каждого обрабатываемого веб-запроса. Т.к. активность завершается после выполнения всего промежуточного ПО, она даёт более точную картину продолжительности запроса и конечного кода состояния, чем может предоставить промежуточное ПО UseSerilogRequestLogging(). Также активности участвуют в распределённой трассировке, поэтому вы можете просматривать входящие и исходящие запросы вашего приложения в иерархии, если выбранный вами приёмник это поддерживает.
1) Установим SerilogTracing, поддержку форматирования вывода консоли и интеграцию с ASP.NET Core:
dotnet add package SerilogTracing
dotnet add package SerilogTracing.Expressions
dotnet add package SerilogTracing.Instrumentation.AspNetCore
2) В Program.cs, добавим средство форматирования с поддержкой трассировки в приёмник консоли и снизим детализацию некоторых источников журналов Microsoft.AspNetCore.*:
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Override(
"Microsoft.AspNetCore.Hosting",
LogEventLevel.Warning)
.MinimumLevel.Override(
"Microsoft.AspNetCore.Routing",
LogEventLevel.Warning)
.Enrich.WithProperty("Application", "MyApp")
.WriteTo.Console(
Formatters.CreateConsoleTextFormatter(
theme: TemplateTheme.Code))
.WriteTo.Seq(…)
.CreateLogger();
Здесь мы использовали Enrich (хотя это не обязательно), чтобы добавить свойство Application ко всем событиям, поскольку это помогает отслеживать в логах операции среди нескольких сервисов.
3) Сразу после этого настроим прослушиватель, который будет записывать действия ASP.NET Core в конвейер Serilog:
using var listener =
new ActivityListenerConfiguration()
.Instrument.AspNetCoreRequests()
.TraceToSharedLogger();
SerilogTracing работает со всеми приёмниками Serilog, но на данный момент только приёмники Seq, SerilogTracing.Sinks.OpenTelemetry и SerilogTracing.Sinks.Zipkin были написаны или изменены для поддержки бэкендов с функциями иерархической трассировки.
Совет: если вы используете приемник без поддержки иерархической трассировки, добавьте
Enrich.WithSpanTimingMilliseconds(), чтобы добавить свойство Elapsed для событий завершения запроса.Источник: https://nblumhardt.com/2024/04/serilog-net8-0-minimal/
👍5
Все зависимости вашего класса определены как интерфейсы. Конкретные реализации интерфейсов (зависимости) внедряются в ваш класс через конструктор. С какими функциями (свойствами и методами) этих зависимостей может работать ваш класс?
#Quiz #BestPractices
#Quiz #BestPractices
Anonymous Quiz
31%
С функциями, определёнными в любом из интерфейсов, которые реализует внедрённая зависимость
13%
Со всеми функциями конкретного типа внедрённой зависимости
53%
Только с функциями интерфейса зависимости
3%
Только с функциями класса зависимости, но не с функциями, определёнными в интерфейсе
День 2234. #BestPractices
Разбирайте, а не Валидируйте
Во многих приложениях валидация используется для определения того, соответствует ли заданная структура данных или объект определённым требованиям. Однако она не изменяет (не должна изменять) рассматриваемый объект, т.е. любое изменение в дальнейшем может сделать валидацию недействительной. Напротив, разбор (парсинг) менее структурированного объекта и создание из него более структурированного — это односторонняя операция, которая приводит к более полезным структурам данных.
Валидация
Валидация — это метод, действующий в определённый момент времени, который обычно возвращает true или false (или вместе с false - список причин, по которым он вернул false). Обычно он не имеет и не должен иметь никаких побочных эффектов, таких как мутация проверяемого объекта. Если структура данных или объект передаются между процедурами в приложении, то система, скорее всего, не сможет предполагать только на основе типа, что объект остаётся валидным по мере перемещения из одного контекста в другой. Таким образом, вы часто будете сталкиваться с проверкой, происходящей в нескольких точках в приложении даже для одного и того же экземпляра переменной или структуры.
Неизменяемые типы, конечно, помогают и могут быть проверены только один раз, а затем подразумеваться валидными, но только если проверка происходит как часть их построения. То есть типы, которые способны обеспечивать инварианты дизайна как часть их построения и которые являются неизменяемыми, могут считаться в системе валидными везде, где они появляются.
Парсинг
Процесс преобразования менее ограниченных типов в более ограниченные типов (или выдачи исключения, если это невозможно сделать) называется парсингом. Он добавляет дополнительные ограничения и, таким образом, уменьшает общий диапазон возможных значений, которые может представлять результирующий тип. Например:
Входная строка может быть относительно короткой последовательностью цифр (возможно, с префиксом -). Если это что-то другое, это всё ещё валидная строка, но это не валидный int, т.е. Parse() завершится ошибкой с исключением. Если приложению требуется числовое значение для использования в определённых методах или функциях, гораздо лучше преобразовать входную строку в целочисленное значение и затем передать его, чем передавать строку везде и каждый раз проверять, может ли она представлять целое число.
Парсеры и эту практику можно использовать совместно с неизменяемыми объектами. Принимая менее структурированные примитивные данные и разбирая их в объекты-значения, ваше ПО будет менее подвержено ошибкам, и вам придётся отслеживать меньше переменных в своей голове.
DateTime как пример
Представьте, что DateTime не существует, а приложению нужен способ представления значений даты и времени с точностью до секунды. Вы можете передать строку, которую нужно будет разобрать везде, где она используется как значение даты и/или времени. Очевидно, что в идеале вы должны выполнить операцию парсинга один раз, после чего у вас будет нестроковый тип, представляющий значение даты и времени.
Альтернативно, у вас могут быть методы со списками аргументов, такими как (int year, int month, int day, int hour, int minute, int second). Шесть целочисленных значений, каждое с отдельными допустимыми диапазонами. Можно выполнять проверку этих 6 значений в таком методе, прежде чем приступить к его фактической логике. Такая массированная проверка имеет тенденцию загромождать код и скрывать реальную работу, а также часто пропускать проверку некоторых входных данных в некоторых контекстах.
Прелесть типа DateTime в том, что разработчики могут быть уверены, что он всегда валиден. В этом смысл парсинга — создать более ограниченный тип более высокого уровня, который не требует проверки, поскольку он не может быть невалидным. Использование правильных типов вместо одержимости примитивами упростит написание правильных методов.
Источник: https://deviq.com/practices/parse-dont-validate
Разбирайте, а не Валидируйте
Во многих приложениях валидация используется для определения того, соответствует ли заданная структура данных или объект определённым требованиям. Однако она не изменяет (не должна изменять) рассматриваемый объект, т.е. любое изменение в дальнейшем может сделать валидацию недействительной. Напротив, разбор (парсинг) менее структурированного объекта и создание из него более структурированного — это односторонняя операция, которая приводит к более полезным структурам данных.
Валидация
Валидация — это метод, действующий в определённый момент времени, который обычно возвращает true или false (или вместе с false - список причин, по которым он вернул false). Обычно он не имеет и не должен иметь никаких побочных эффектов, таких как мутация проверяемого объекта. Если структура данных или объект передаются между процедурами в приложении, то система, скорее всего, не сможет предполагать только на основе типа, что объект остаётся валидным по мере перемещения из одного контекста в другой. Таким образом, вы часто будете сталкиваться с проверкой, происходящей в нескольких точках в приложении даже для одного и того же экземпляра переменной или структуры.
Неизменяемые типы, конечно, помогают и могут быть проверены только один раз, а затем подразумеваться валидными, но только если проверка происходит как часть их построения. То есть типы, которые способны обеспечивать инварианты дизайна как часть их построения и которые являются неизменяемыми, могут считаться в системе валидными везде, где они появляются.
Парсинг
Процесс преобразования менее ограниченных типов в более ограниченные типов (или выдачи исключения, если это невозможно сделать) называется парсингом. Он добавляет дополнительные ограничения и, таким образом, уменьшает общий диапазон возможных значений, которые может представлять результирующий тип. Например:
int.Parse(string input);
Входная строка может быть относительно короткой последовательностью цифр (возможно, с префиксом -). Если это что-то другое, это всё ещё валидная строка, но это не валидный int, т.е. Parse() завершится ошибкой с исключением. Если приложению требуется числовое значение для использования в определённых методах или функциях, гораздо лучше преобразовать входную строку в целочисленное значение и затем передать его, чем передавать строку везде и каждый раз проверять, может ли она представлять целое число.
Парсеры и эту практику можно использовать совместно с неизменяемыми объектами. Принимая менее структурированные примитивные данные и разбирая их в объекты-значения, ваше ПО будет менее подвержено ошибкам, и вам придётся отслеживать меньше переменных в своей голове.
DateTime как пример
Представьте, что DateTime не существует, а приложению нужен способ представления значений даты и времени с точностью до секунды. Вы можете передать строку, которую нужно будет разобрать везде, где она используется как значение даты и/или времени. Очевидно, что в идеале вы должны выполнить операцию парсинга один раз, после чего у вас будет нестроковый тип, представляющий значение даты и времени.
Альтернативно, у вас могут быть методы со списками аргументов, такими как (int year, int month, int day, int hour, int minute, int second). Шесть целочисленных значений, каждое с отдельными допустимыми диапазонами. Можно выполнять проверку этих 6 значений в таком методе, прежде чем приступить к его фактической логике. Такая массированная проверка имеет тенденцию загромождать код и скрывать реальную работу, а также часто пропускать проверку некоторых входных данных в некоторых контекстах.
Прелесть типа DateTime в том, что разработчики могут быть уверены, что он всегда валиден. В этом смысл парсинга — создать более ограниченный тип более высокого уровня, который не требует проверки, поскольку он не может быть невалидным. Использование правильных типов вместо одержимости примитивами упростит написание правильных методов.
Источник: https://deviq.com/practices/parse-dont-validate
👍21
День 2248. #BestPractices
Мастерство Пулл-Реквестов: как Легко Пройти Обзор Кода. Начало
Как разработчики, мы часто работаем параллельно, создавая ветки для новых функций, исправляя ошибки и внося обновления. Но когда приходит время внести эти изменения в основную кодовую базу, пулл-реквесты (PR) становятся мостом между изолированной разработкой и совместной работой в команде. Каждого разочаровывает, когда PR отклоняют или отправляют на доработку. Легко можно потратить часы на функцию, а потом понять, что твоя реализация не соответствует видению команды. Однако со временем мы узнаём, что эффективные PR касаются не только самого кода. Они и про то, как мы сообщаем о наших изменениях. Рассмотрим, как создавать пулл-реквесты, которые делают процесс обзора более плавным, быстрым и эффективным для всех участников.
1. Начните с информативного заголовка
Первое впечатление имеет значение даже в мире кода. Заголовок пулл-реквеста — это наш шанс немедленно донести суть изменения. Думайте о нём как о заголовке статьи; он должен быть коротким, понятным и информативным. Вместо:
"Обновил код"
"Исправил баг"
"Изменения за вчера"
Используйте более описательные заголовки, например:
feat: Добавил OAuth2 аутентификацию для конечных точек API
fix: Устранил состояния гонки при обработке сеанса пользователя
refactor: Оптимизированы запросы к БД при поиске пользователя
Хорошо составленный заголовок помогает рецензентам понять изменение, не открывая PR. Он задает тон всему процессу обзора кода.
2. Установите контекст (не предполагайте, что все знают проблему)
Прежде чем погрузиться в код, важно предоставить контекст. Не все могут быть знакомы с конкретной проблемой, которую мы решаем, и важно объяснить, почему произошли изменения. Чёткое описание PR упрощает и ускоряет рецензирование. Вот шаблон для хорошо структурированного описания PR:
Это гарантирует, что рецензенты поймут проблему, выбранный подход и то, как проверить решение. PR без контекста может существенно замедлить процесс, поэтому всегда включайте достаточно информации, чтобы команда могла понять ваши изменения.
3. Сохраняйте PR сфокусированным
Нас всех подбивает решить сразу несколько проблем. Но это часто приводит к слишком большим PR, которые могут обескуражить рецензентов. Вместо этого пытайтесь разбить работу на более мелкие, целенаправленные PR. Каждый PR должен решать определённую задачу. Например, если мы создаём систему управления пользователями, можно разбить её на более мелкие задачи:
PR 1: feat: Добавление основной модели и миграции
PR 2: feat: Реализация конечных точек аутентификации
PR 3: feat: Добавление UI управления пользователями
PR 4: feat: Интеграция подтверждения по email
Каждый PR должен быть нацелен на одну фичу или исправление ошибки, что сделает процесс обзора проще для всех. Это ведёт к более быстрым обзорам и меньшему количеству доработок.
Окончание следует…
Источник: https://dev.to/budiwidhiyanto/the-art-of-pull-requests-a-developers-guide-to-smooth-code-reviews-38bk
Мастерство Пулл-Реквестов: как Легко Пройти Обзор Кода. Начало
Как разработчики, мы часто работаем параллельно, создавая ветки для новых функций, исправляя ошибки и внося обновления. Но когда приходит время внести эти изменения в основную кодовую базу, пулл-реквесты (PR) становятся мостом между изолированной разработкой и совместной работой в команде. Каждого разочаровывает, когда PR отклоняют или отправляют на доработку. Легко можно потратить часы на функцию, а потом понять, что твоя реализация не соответствует видению команды. Однако со временем мы узнаём, что эффективные PR касаются не только самого кода. Они и про то, как мы сообщаем о наших изменениях. Рассмотрим, как создавать пулл-реквесты, которые делают процесс обзора более плавным, быстрым и эффективным для всех участников.
1. Начните с информативного заголовка
Первое впечатление имеет значение даже в мире кода. Заголовок пулл-реквеста — это наш шанс немедленно донести суть изменения. Думайте о нём как о заголовке статьи; он должен быть коротким, понятным и информативным. Вместо:
"Обновил код"
"Исправил баг"
"Изменения за вчера"
Используйте более описательные заголовки, например:
feat: Добавил OAuth2 аутентификацию для конечных точек API
fix: Устранил состояния гонки при обработке сеанса пользователя
refactor: Оптимизированы запросы к БД при поиске пользователя
Хорошо составленный заголовок помогает рецензентам понять изменение, не открывая PR. Он задает тон всему процессу обзора кода.
2. Установите контекст (не предполагайте, что все знают проблему)
Прежде чем погрузиться в код, важно предоставить контекст. Не все могут быть знакомы с конкретной проблемой, которую мы решаем, и важно объяснить, почему произошли изменения. Чёткое описание PR упрощает и ускоряет рецензирование. Вот шаблон для хорошо структурированного описания PR:
## Проблема
Текущая система аутентификации пользователей не поддерживает вход через соцсети, что вызывает затруднения при регистрации. Мы наблюдаем 40% отказов на этапе регистрации.
Связанный тикет: AUTH-123
## Решение
Реализована аутентификация OAuth2 с Google:
- Добавлено промежуточное ПО OAuth2 для обработки аутентификации Google
- Создана новая логика сопоставления профилей пользователей
- Реализовано управление сеансами для входа через соцсети
## Технические подробности
- Использует passport-google-oauth20
- Добавлены новые поля: googleId, socialProfile
- Изменена модель пользователя для поддержки нескольких методов аутентификации
## Тестирование
1. Нажмите «Войти через Google»
2. Авторизуйте тестовое приложение
3. Проверьте успешное перенаправление на панель управления
4. Проверьте, содержит ли профиль пользователя данные Google
## Конфигурация
Требуются новые переменные среды:
- GOOGLE_CLIENT_ID
- GOOGLE_CLIENT_SECRET
- OAUTH_CALLBACK_URL
Это гарантирует, что рецензенты поймут проблему, выбранный подход и то, как проверить решение. PR без контекста может существенно замедлить процесс, поэтому всегда включайте достаточно информации, чтобы команда могла понять ваши изменения.
3. Сохраняйте PR сфокусированным
Нас всех подбивает решить сразу несколько проблем. Но это часто приводит к слишком большим PR, которые могут обескуражить рецензентов. Вместо этого пытайтесь разбить работу на более мелкие, целенаправленные PR. Каждый PR должен решать определённую задачу. Например, если мы создаём систему управления пользователями, можно разбить её на более мелкие задачи:
PR 1: feat: Добавление основной модели и миграции
PR 2: feat: Реализация конечных точек аутентификации
PR 3: feat: Добавление UI управления пользователями
PR 4: feat: Интеграция подтверждения по email
Каждый PR должен быть нацелен на одну фичу или исправление ошибки, что сделает процесс обзора проще для всех. Это ведёт к более быстрым обзорам и меньшему количеству доработок.
Окончание следует…
Источник: https://dev.to/budiwidhiyanto/the-art-of-pull-requests-a-developers-guide-to-smooth-code-reviews-38bk
👍18👎2
День 2249. #BestPractices
Мастерство Пулл-Реквестов: как Легко Пройти Обзор Кода. Окончание
Начало
4. Сообщения коммитов: чистота и ясность
Хорошее сообщение коммита не просто объясняет код. Оно помогает всем понять, почему было сделано изменение и как оно вписывается в общую картину.
Хорошее сообщение коммита
- предоставляет контекст: объясняет причину изменения;
- улучшает сотрудничество: будущие разработчики смогут отслеживать историю проекта и легко понимать цель каждого коммита;
- экономит время: уменьшают необходимость в дополнительных вопросах и предотвращают доработки во время процесса проверки;
Примеры плохих сообщений коммитов:
- «Исправлено»
Это расплывчато и не указывает, что исправлено или почему.
Лучше:
fix(auth): устранена ошибка входа пользователя, вызванная истекшими токенами.
- «Обновления»
Не сообщает рецензенту, что было изменено или почему обновление было необходимо.
Лучше:
chore: обновлены зависимости для исправления уязвимостей безопасности
- «Работа в процессе»
Не описывает никаких значимых изменений и предполагает, что код неполный. Также усложняет процесс проверки, так как рецензент не знает, смотрит ли он на готовую функцию или только на черновик.
Лучше:
feat(api): добавлены конечные точки аутентификации пользователя
5. Контрольный список готовности к обзору кода
Перед отправкой PR используйте следующий контрольный список, чтобы убедиться, что всё готово. Контрольный список важен, т.к.:
- Экономит время рецензентов: сводит к минимуму вероятность того, что рецензенты попросят об исправлениях, позволяя им сосредоточиться на логике кода.
- Улучшает согласованность: гарантирует, что все PR соответствуют одному стандарту, что делает процесс обзора более гладким для всех.
- Уменьшает количество повторных проверок: двойная проверка вашего кода и тестов позволяет избежать нескольких раундов обзоров.
Пример контрольного списка:
Распространённые проблемы с PR
1. В PR слишком много изменений
Разбейте задачу на более мелкие, более управляемые PR. Сначала для изменений схемы БД, затем для модификаций API, а затем — для корректировок UI. Это позволит рецензентам сосредоточиться на чём-то одном за раз.
2. Непоследовательные сообщения коммитов
Они затрудняют отслеживание изменений: одни слишком расплывчаты, другие — слишком подробные. Используйте стандартный формат сообщений коммитов и убедитесь, что все его соблюдают. Это сделает историю проекта намного более читаемой и улучшит совместную работу.
Итого
Создание эффективных PR — навык, который улучшается с практикой. Каждый PR — это возможность для обучения. Каждый комментарий, предложение или вопрос в обзоре кода помогает нам расти как разработчикам и улучшать наши методы кодирования.
Цель не просто слить наш код с основной веткой; а создать высококачественную кодовую базу, которую всем будет легко понимать и поддерживать. Уделяя особое внимание нашим PR, мы инвестируем в успех проекта и наш рост как разработчиков.
Источник: https://dev.to/budiwidhiyanto/the-art-of-pull-requests-a-developers-guide-to-smooth-code-reviews-38bk
Мастерство Пулл-Реквестов: как Легко Пройти Обзор Кода. Окончание
Начало
4. Сообщения коммитов: чистота и ясность
Хорошее сообщение коммита не просто объясняет код. Оно помогает всем понять, почему было сделано изменение и как оно вписывается в общую картину.
Хорошее сообщение коммита
- предоставляет контекст: объясняет причину изменения;
- улучшает сотрудничество: будущие разработчики смогут отслеживать историю проекта и легко понимать цель каждого коммита;
- экономит время: уменьшают необходимость в дополнительных вопросах и предотвращают доработки во время процесса проверки;
Примеры плохих сообщений коммитов:
- «Исправлено»
Это расплывчато и не указывает, что исправлено или почему.
Лучше:
fix(auth): устранена ошибка входа пользователя, вызванная истекшими токенами.
- «Обновления»
Не сообщает рецензенту, что было изменено или почему обновление было необходимо.
Лучше:
chore: обновлены зависимости для исправления уязвимостей безопасности
- «Работа в процессе»
Не описывает никаких значимых изменений и предполагает, что код неполный. Также усложняет процесс проверки, так как рецензент не знает, смотрит ли он на готовую функцию или только на черновик.
Лучше:
feat(api): добавлены конечные точки аутентификации пользователя
5. Контрольный список готовности к обзору кода
Перед отправкой PR используйте следующий контрольный список, чтобы убедиться, что всё готово. Контрольный список важен, т.к.:
- Экономит время рецензентов: сводит к минимуму вероятность того, что рецензенты попросят об исправлениях, позволяя им сосредоточиться на логике кода.
- Улучшает согласованность: гарантирует, что все PR соответствуют одному стандарту, что делает процесс обзора более гладким для всех.
- Уменьшает количество повторных проверок: двойная проверка вашего кода и тестов позволяет избежать нескольких раундов обзоров.
Пример контрольного списка:
## Перед коммитом
- [ ] Все тесты проходят
- [ ] Нет предупреждений компилятора
- [ ] Документация обновлена
- [ ] В коммите нет приватных данных
- [ ] Ветка синхронизирована с main
- [ ] Код отвечает стилю кодирования проекта
Распространённые проблемы с PR
1. В PR слишком много изменений
Разбейте задачу на более мелкие, более управляемые PR. Сначала для изменений схемы БД, затем для модификаций API, а затем — для корректировок UI. Это позволит рецензентам сосредоточиться на чём-то одном за раз.
2. Непоследовательные сообщения коммитов
Они затрудняют отслеживание изменений: одни слишком расплывчаты, другие — слишком подробные. Используйте стандартный формат сообщений коммитов и убедитесь, что все его соблюдают. Это сделает историю проекта намного более читаемой и улучшит совместную работу.
Итого
Создание эффективных PR — навык, который улучшается с практикой. Каждый PR — это возможность для обучения. Каждый комментарий, предложение или вопрос в обзоре кода помогает нам расти как разработчикам и улучшать наши методы кодирования.
Цель не просто слить наш код с основной веткой; а создать высококачественную кодовую базу, которую всем будет легко понимать и поддерживать. Уделяя особое внимание нашим PR, мы инвестируем в успех проекта и наш рост как разработчиков.
Источник: https://dev.to/budiwidhiyanto/the-art-of-pull-requests-a-developers-guide-to-smooth-code-reviews-38bk
👍9
День 2346. #BestPractices
Пишем Хорошую Документацию. Начало
Документация часто кажется второстепенной — рутиной, которую откладывают на конец спринта или вообще пропускают. Тем не менее, любой разработчик расскажет, что одно из его самых больших разочарований - продираться через плохую, устаревшую или отсутствующую документацию. Важно не просто иметь документацию, а создать такую, которую разработчики действительно ценят и используют. Это сигнализирует о том, что создатели заботятся о людях, использующих их ПО или API.
1. Знайте свою аудиторию (глубоко)
Прежде чем написать хоть слово, поймите, для кого вы пишете. Опытные или младшие разработчики? Внутренние команды, уже знакомые с экосистемой, или внешние пользователи, впервые сталкивающиеся с продуктом?
- Техническая компетентность: адаптируйте язык и глубину объяснения. Избегайте чрезмерно упрощённых объяснений для экспертов, но не предполагайте глубоких знаний предметной области от новичков.
- Цели: чего они пытаются достичь с помощью вашего ПО/API? Они ищут краткое руководство по началу работы, устранение конкретной ошибки, понимание расширенных концепций или интеграцию с другими системами? Структурируйте документы так, чтобы они отвечали этим конкретным потребностям.
- Контекст: где они обычно ищут информацию? Подойдёт ли интерактивный UI для API или лучше статические справочные страницы?
Поставьте себя на место разработчика. Какая информация вам нужна и как бы вы хотели, чтобы она была представлена?
2. Важна структура: создайте логическую основу
Даже самый точный контент бесполезен, если разработчики не могут его найти. Логическая структура обеспечивает ментальную карту, позволяя пользователям интуитивно ориентироваться.
- Чёткая иерархия: организуйте контент логически, начиная с вводных концепций (Начало работы, Установка) и переходя к конкретике (Справочник API, Руководства, Устранение неполадок). Используйте чёткие заголовки и подзаголовки (H1, H2, H3) последовательно.
- Оглавление: хорошо структурированное, всегда видимое (на боковой панели) оглавление позволяет пользователям видеть общую компоновку и быстро переходить к нужным разделам.
- Функциональность поиска: убедитесь, что поиск эффективно индексирует контент и выделяет ключевые слова в результатах. Разработчики часто знают, что им нужно, но не знают, где это находится.
- Перекрёстные ссылки: делайте ссылки на связанные концепции, руководства и API. Если вы упоминаете конечную точку API в руководстве, давайте прямую ссылку на неё. Это создаёт сеть знаний, а не изолированные хранилища.
- Информационная архитектура: планируйте поток. Рассмотрите возможность использования устоявшихся фреймворков, таких как Diátaxis (концепции, руководства, пояснения, справочные материалы), чтобы гарантировать, что вы систематически охватываете различные потребности в обучении.
3. Содержание: ясность, краткость и примеры
Основа документации — это содержание.
- Ясность: используйте понятный, недвусмысленный язык. Избегайте жаргона, где возможно, или чётко определите понятия при их первом использовании. Предпочитайте активный залог пассивному («Функция возвращает X» вместо «X возвращается функцией»).
- Краткость: разработчики заняты. Переходите к сути. Устраняйте бессмыслицу и ненужные слова. Используйте короткие предложения и абзацы. Маркеры и нумерованные списки отлично подходят для разбиения текста и выделения ключевой информации.
- Точность: неточная документация хуже, чем её отсутствие. Установите процессы проверки и обеспечьте обновление документов вместе с изменениями кода.
- Примеры кода: многочисленные, практичные, копируемые и вставляемые примеры, которые работают из коробки (включая необходимые импорты или настройки). Объясняйте, что делает код и почему он структурирован именно так. Покажите общие случаи использования, пограничные случаи и обработку ошибок. Если ваш API/SDK поддерживает несколько языков, предоставьте примеры на каждом из них.
Продолжение следует…
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
Пишем Хорошую Документацию. Начало
Документация часто кажется второстепенной — рутиной, которую откладывают на конец спринта или вообще пропускают. Тем не менее, любой разработчик расскажет, что одно из его самых больших разочарований - продираться через плохую, устаревшую или отсутствующую документацию. Важно не просто иметь документацию, а создать такую, которую разработчики действительно ценят и используют. Это сигнализирует о том, что создатели заботятся о людях, использующих их ПО или API.
1. Знайте свою аудиторию (глубоко)
Прежде чем написать хоть слово, поймите, для кого вы пишете. Опытные или младшие разработчики? Внутренние команды, уже знакомые с экосистемой, или внешние пользователи, впервые сталкивающиеся с продуктом?
- Техническая компетентность: адаптируйте язык и глубину объяснения. Избегайте чрезмерно упрощённых объяснений для экспертов, но не предполагайте глубоких знаний предметной области от новичков.
- Цели: чего они пытаются достичь с помощью вашего ПО/API? Они ищут краткое руководство по началу работы, устранение конкретной ошибки, понимание расширенных концепций или интеграцию с другими системами? Структурируйте документы так, чтобы они отвечали этим конкретным потребностям.
- Контекст: где они обычно ищут информацию? Подойдёт ли интерактивный UI для API или лучше статические справочные страницы?
Поставьте себя на место разработчика. Какая информация вам нужна и как бы вы хотели, чтобы она была представлена?
2. Важна структура: создайте логическую основу
Даже самый точный контент бесполезен, если разработчики не могут его найти. Логическая структура обеспечивает ментальную карту, позволяя пользователям интуитивно ориентироваться.
- Чёткая иерархия: организуйте контент логически, начиная с вводных концепций (Начало работы, Установка) и переходя к конкретике (Справочник API, Руководства, Устранение неполадок). Используйте чёткие заголовки и подзаголовки (H1, H2, H3) последовательно.
- Оглавление: хорошо структурированное, всегда видимое (на боковой панели) оглавление позволяет пользователям видеть общую компоновку и быстро переходить к нужным разделам.
- Функциональность поиска: убедитесь, что поиск эффективно индексирует контент и выделяет ключевые слова в результатах. Разработчики часто знают, что им нужно, но не знают, где это находится.
- Перекрёстные ссылки: делайте ссылки на связанные концепции, руководства и API. Если вы упоминаете конечную точку API в руководстве, давайте прямую ссылку на неё. Это создаёт сеть знаний, а не изолированные хранилища.
- Информационная архитектура: планируйте поток. Рассмотрите возможность использования устоявшихся фреймворков, таких как Diátaxis (концепции, руководства, пояснения, справочные материалы), чтобы гарантировать, что вы систематически охватываете различные потребности в обучении.
3. Содержание: ясность, краткость и примеры
Основа документации — это содержание.
- Ясность: используйте понятный, недвусмысленный язык. Избегайте жаргона, где возможно, или чётко определите понятия при их первом использовании. Предпочитайте активный залог пассивному («Функция возвращает X» вместо «X возвращается функцией»).
- Краткость: разработчики заняты. Переходите к сути. Устраняйте бессмыслицу и ненужные слова. Используйте короткие предложения и абзацы. Маркеры и нумерованные списки отлично подходят для разбиения текста и выделения ключевой информации.
- Точность: неточная документация хуже, чем её отсутствие. Установите процессы проверки и обеспечьте обновление документов вместе с изменениями кода.
- Примеры кода: многочисленные, практичные, копируемые и вставляемые примеры, которые работают из коробки (включая необходимые импорты или настройки). Объясняйте, что делает код и почему он структурирован именно так. Покажите общие случаи использования, пограничные случаи и обработку ошибок. Если ваш API/SDK поддерживает несколько языков, предоставьте примеры на каждом из них.
Продолжение следует…
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
👍4👎2
День 2347. #BestPractices
Пишем Хорошую Документацию. Продолжение
Начало
4. Сосредоточьтесь на вариантах использования и используйте интеллектуальные инструменты для API
Разработчики не просто хотят знать, что делает конечная точка API; они хотят знать, как использовать её для решения своей проблемы. Создавайте документацию вокруг общих задач и рабочих процессов.
Специализированные фреймворки для API значительно улучшают процесс создания документации. Инструменты, разработанные специально для жизненного цикла API, могут оптимизировать как разработку, так и документирование, обеспечивая согласованность и интерактивность. Например, Apidog интегрирует проектирование API, отладку, тестирование непосредственно с созданием документации.
5. Поддерживайте точность и актуальность
Устаревшая документация подрывает доверие быстрее, чем что-либо ещё. Разработчики полагаются на правильность документов. Если они сталкиваются с несоответствиями, они полностью перестают доверять документации.
- Версионирование: чётко версионируйте документацию вместе с выпусками ПО/API. Позвольте пользователям легко переключаться между версиями.
- Документация-как-Код: относитесь к документации как к коду. Храните её в системе контроля версий (например, Git) вместе с исходным кодом, который она описывает. Это упрощает отслеживание изменений, просмотр обновлений и синхронизацию документов с выпусками кода. Интегрируйте обновления документации в свой конвейер CI/CD.
- Циклы обратной связи: упростите разработчикам возможность сообщать об ошибках или предлагать улучшения (например, кнопка «Предложить изменения», ссылающаяся на GitHub Issues или специальную форму обратной связи). Незамедлительно реагируйте на эти отзывы.
- Регулярные обзоры: запланируйте периодические обзоры документации для проверки точности, ясности и полноты.
6. Визуальная привлекательность и последовательность
Хотя суть является ключевой, представление тоже имеет значение. Красивые документы приятны и легко читаются.
- Чистый дизайн: используйте достаточно свободного пространства, читаемые шрифты и четкую визуальную иерархию. Избегайте загромождённых шаблонов.
- Единообразное форматирование: применяйте единый стиль для блоков кода, заметок, предупреждений, заголовков, ссылок и т. д. По возможности используйте руководство по стилю.
- Подсветка синтаксиса: необходима для примеров кода. Используйте чёткое и правильное выделение для соответствующих языков программирования.
- Наглядные пособия: используйте диаграммы (блок-схемы, диаграммы последовательности, диаграммы архитектуры), снимки экрана или короткие видеоролики, где они могут прояснить сложные концепции более эффективно, чем текст. Убедитесь, что визуальные материалы понятны, маркированы и актуальны.
7. Улучшите интерактивность и поисковую доступность
Выйдите за рамки статического текста:
- Интерактивные элементы: помимо пользовательского интерфейса API (например, Swagger), рассмотрите использование встроенных редакторов кода (например, CodeSandbox) или интерактивных руководств (например, Jupiter Notebooks).
- Расширенный поиск: для больших наборов документации разрешите пользователям фильтровать результаты поиска по категории, версии или разделу API.
- Виджеты "Была ли эта страница полезна?": собирайте быстрые отзывы об эффективности страницы.
Окончание следует…
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
Пишем Хорошую Документацию. Продолжение
Начало
4. Сосредоточьтесь на вариантах использования и используйте интеллектуальные инструменты для API
Разработчики не просто хотят знать, что делает конечная точка API; они хотят знать, как использовать её для решения своей проблемы. Создавайте документацию вокруг общих задач и рабочих процессов.
Специализированные фреймворки для API значительно улучшают процесс создания документации. Инструменты, разработанные специально для жизненного цикла API, могут оптимизировать как разработку, так и документирование, обеспечивая согласованность и интерактивность. Например, Apidog интегрирует проектирование API, отладку, тестирование непосредственно с созданием документации.
5. Поддерживайте точность и актуальность
Устаревшая документация подрывает доверие быстрее, чем что-либо ещё. Разработчики полагаются на правильность документов. Если они сталкиваются с несоответствиями, они полностью перестают доверять документации.
- Версионирование: чётко версионируйте документацию вместе с выпусками ПО/API. Позвольте пользователям легко переключаться между версиями.
- Документация-как-Код: относитесь к документации как к коду. Храните её в системе контроля версий (например, Git) вместе с исходным кодом, который она описывает. Это упрощает отслеживание изменений, просмотр обновлений и синхронизацию документов с выпусками кода. Интегрируйте обновления документации в свой конвейер CI/CD.
- Циклы обратной связи: упростите разработчикам возможность сообщать об ошибках или предлагать улучшения (например, кнопка «Предложить изменения», ссылающаяся на GitHub Issues или специальную форму обратной связи). Незамедлительно реагируйте на эти отзывы.
- Регулярные обзоры: запланируйте периодические обзоры документации для проверки точности, ясности и полноты.
6. Визуальная привлекательность и последовательность
Хотя суть является ключевой, представление тоже имеет значение. Красивые документы приятны и легко читаются.
- Чистый дизайн: используйте достаточно свободного пространства, читаемые шрифты и четкую визуальную иерархию. Избегайте загромождённых шаблонов.
- Единообразное форматирование: применяйте единый стиль для блоков кода, заметок, предупреждений, заголовков, ссылок и т. д. По возможности используйте руководство по стилю.
- Подсветка синтаксиса: необходима для примеров кода. Используйте чёткое и правильное выделение для соответствующих языков программирования.
- Наглядные пособия: используйте диаграммы (блок-схемы, диаграммы последовательности, диаграммы архитектуры), снимки экрана или короткие видеоролики, где они могут прояснить сложные концепции более эффективно, чем текст. Убедитесь, что визуальные материалы понятны, маркированы и актуальны.
7. Улучшите интерактивность и поисковую доступность
Выйдите за рамки статического текста:
- Интерактивные элементы: помимо пользовательского интерфейса API (например, Swagger), рассмотрите использование встроенных редакторов кода (например, CodeSandbox) или интерактивных руководств (например, Jupiter Notebooks).
- Расширенный поиск: для больших наборов документации разрешите пользователям фильтровать результаты поиска по категории, версии или разделу API.
- Виджеты "Была ли эта страница полезна?": собирайте быстрые отзывы об эффективности страницы.
Окончание следует…
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
👍6
День 2348. #BestPractices
Пишем Хорошую Документацию. Окончание
Начало
Продолжение
8. Используйте современные инструменты (вне зависимости от API)
Существует множество инструментов, которые помогут вам эффективно и результативно создавать документацию:
- Генераторы статических сайтов (SSG): такие инструменты, как MkDocs, Docusaurus, Hugo, Jekyll и Sphinx, являются популярным выбором. Они берут простые файлы разметки (например, Markdown) и создают профессионально выглядящие веб-сайты документации, с возможностью поиска. Они часто поставляются с темами, плагинами для поиска, поддержкой управления версиями и хорошо согласуются с подходом «Документация-как-Код».
- Платформы документации: такие сервисы, как Read the Docs, GitBook или Confluence, предлагают решения со встроенными функциями для совместной работы, управления версиями и презентации.
Выбирайте инструменты, которые соответствуют вашему рабочему процессу, размеру команды и техническим требованиям.
9. Используйте ИИ (осторожно)
Искусственный интеллект проникает в документацию. Генератор документации ИИ может стать мощным помощником, но крайне важно понимать его сильные и слабые стороны.
Потенциальные преимущества
- Генерация шаблонов: ИИ может быстро генерировать первоначальные черновики описаний функций/методов на основе комментариев или сигнатур кода (например, блоков
- Саммари: ИИ может обобщать длинные технические объяснения или сложные разделы кода.
- Проверки согласованности: ИИ может помочь выявить несоответствия в терминологии или стиле в больших наборах документации.
- Перевод: сервисы перевода на другие языки совершенствуются, хотя человеческая проверка по-прежнему необходима для технической точности.
Важные предостережения
- Точность не гарантируется: модели ИИ могут галлюцинировать или неправильно интерпретировать контекст кода. Всегда привлекайте эксперта-человека для проверки технической корректности контента, созданного ИИ.
- Отсутствие контекста: ИИ может не понимать более широкий вариант использования, потребности целевой аудитории или причины использования фрагментов кода.
- Общее повествование: текст, сгенерированный ИИ, иногда может быть скучным или не иметь конкретных идей, которые мог бы предоставить эксперт-человек.
Используйте генератор документации ИИ как инструмент для дополнения человеческих усилий, а не для их замены. Он может ускорить составление черновиков и выявить области для улучшения, но критическое мышление, техническая проверка и создание действительно полезных объяснений остаются человеческими задачами.
10. Развивайте культуру документирования
Отличная документация обычно не является продуктом одного человека, работающего в изоляции. Для этого требуются командные усилия и культурный сдвиг:
- Интеграция в рабочий процесс: сделайте документацию частью определения «готово» для новых функций или изменений API. Выделяйте на неё время во время спринтов.
- Поощряйте вклад: сделайте так, чтобы всем разработчикам (а не только преданным писателям) было легко вносить исправления и улучшения. Снизьте барьер для входа (например, простое редактирование Markdown через Git).
- Признавайте и вознаграждайте: признавайте и цените усилия, которые вложены в создание и поддержание высококачественной документации.
- Показывайте пример: если руководители групп и старшие разработчики отдают приоритет документации, другие, скорее всего, последуют их примеру.
Итого
Создание документации, которая понравится разработчикам, — непростая задача, но это чрезвычайно ценная инвестиция. Красивые документы — точные, понятные, хорошо структурированные, простые в навигации и визуально приятные — напрямую влияют на производительность разработчиков, снижают нагрузку на поддержку, улучшают адаптацию и улучшают общее восприятие вашего ПО или платформы.
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
Пишем Хорошую Документацию. Окончание
Начало
Продолжение
8. Используйте современные инструменты (вне зависимости от API)
Существует множество инструментов, которые помогут вам эффективно и результативно создавать документацию:
- Генераторы статических сайтов (SSG): такие инструменты, как MkDocs, Docusaurus, Hugo, Jekyll и Sphinx, являются популярным выбором. Они берут простые файлы разметки (например, Markdown) и создают профессионально выглядящие веб-сайты документации, с возможностью поиска. Они часто поставляются с темами, плагинами для поиска, поддержкой управления версиями и хорошо согласуются с подходом «Документация-как-Код».
- Платформы документации: такие сервисы, как Read the Docs, GitBook или Confluence, предлагают решения со встроенными функциями для совместной работы, управления версиями и презентации.
Выбирайте инструменты, которые соответствуют вашему рабочему процессу, размеру команды и техническим требованиям.
9. Используйте ИИ (осторожно)
Искусственный интеллект проникает в документацию. Генератор документации ИИ может стать мощным помощником, но крайне важно понимать его сильные и слабые стороны.
Потенциальные преимущества
- Генерация шаблонов: ИИ может быстро генерировать первоначальные черновики описаний функций/методов на основе комментариев или сигнатур кода (например, блоков
///summary).- Саммари: ИИ может обобщать длинные технические объяснения или сложные разделы кода.
- Проверки согласованности: ИИ может помочь выявить несоответствия в терминологии или стиле в больших наборах документации.
- Перевод: сервисы перевода на другие языки совершенствуются, хотя человеческая проверка по-прежнему необходима для технической точности.
Важные предостережения
- Точность не гарантируется: модели ИИ могут галлюцинировать или неправильно интерпретировать контекст кода. Всегда привлекайте эксперта-человека для проверки технической корректности контента, созданного ИИ.
- Отсутствие контекста: ИИ может не понимать более широкий вариант использования, потребности целевой аудитории или причины использования фрагментов кода.
- Общее повествование: текст, сгенерированный ИИ, иногда может быть скучным или не иметь конкретных идей, которые мог бы предоставить эксперт-человек.
Используйте генератор документации ИИ как инструмент для дополнения человеческих усилий, а не для их замены. Он может ускорить составление черновиков и выявить области для улучшения, но критическое мышление, техническая проверка и создание действительно полезных объяснений остаются человеческими задачами.
10. Развивайте культуру документирования
Отличная документация обычно не является продуктом одного человека, работающего в изоляции. Для этого требуются командные усилия и культурный сдвиг:
- Интеграция в рабочий процесс: сделайте документацию частью определения «готово» для новых функций или изменений API. Выделяйте на неё время во время спринтов.
- Поощряйте вклад: сделайте так, чтобы всем разработчикам (а не только преданным писателям) было легко вносить исправления и улучшения. Снизьте барьер для входа (например, простое редактирование Markdown через Git).
- Признавайте и вознаграждайте: признавайте и цените усилия, которые вложены в создание и поддержание высококачественной документации.
- Показывайте пример: если руководители групп и старшие разработчики отдают приоритет документации, другие, скорее всего, последуют их примеру.
Итого
Создание документации, которая понравится разработчикам, — непростая задача, но это чрезвычайно ценная инвестиция. Красивые документы — точные, понятные, хорошо структурированные, простые в навигации и визуально приятные — напрямую влияют на производительность разработчиков, снижают нагрузку на поддержку, улучшают адаптацию и улучшают общее восприятие вашего ПО или платформы.
Источник: https://dev.to/therealmrmumba/beyond-code-how-to-create-beautiful-documentation-that-developers-actually-love-best-practices-hc4
👍3
День 2361. #Testing #BestPractices
Лучшие Практики Интеграционного Тестирования с Testcontainers. Начало
Интеграционные тесты с Testcontainers — мощный инструмент, но их поддержка может быстро превратиться в кошмар. Сегодня рассмотрим шаблоны, которые делают тесты Testcontainers надёжными, быстрыми и простыми в поддержке.
Традиционные интеграционные тесты часто используют общие тестовые БД или БД в памяти, которые не соответствуют поведению в рабочей среде. Вам либо приходится сталкиваться с загрязнением тестов между запусками, либо жертвовать реализмом ради скорости.
Testcontainers решает эту проблему, разворачивая настоящие Docker-контейнеры для ваших зависимостей. Тесты выполняются с использованием реальных PostgreSQL, Redis или любого другого сервиса, используемого в рабочей среде. После завершения тестов контейнеры уничтожаются, каждый раз позволяя вам начинать с чистого листа.
Всё происходит через API Docker. Testcontainers управляет всем жизненным циклом: извлечение образов, запуск контейнеров, ожидание готовности и очистка. Тестовому коду нужно лишь знать, как подключиться.
1. Подготовка
Убедитесь, что у вас есть необходимые пакеты:
Пакеты TestContainers существуют для множества сервисов.
2. Создание
Вот так можно создать контейнеры для PostgreSql и Redis:
3. Использование
Чтобы запускать и останавливать контейнеры в тестах, нужно реализовать IAsyncLifetime в вашей WebApplicationFactory:
Это гарантирует готовность контейнеров до запуска тестов и их очистку после них. Т.е. отсутствие остаточного состояния Docker или состояний гонки.
Совет: закрепите версии образов (например, postgres:17), чтобы избежать сюрпризов от изменений версий зависимостей.
4. Передача конфигурации в приложение
Testcontainers назначает динамические порты. Не пишите жёсткие строки подключения в коде. Вместо этого внедряйте значения через WebApplicationFactory.ConfigureWebHost:
Здесь используется метод UseSetting для динамической передачи строк подключения. Это также позволяет избежать состояний гонки или конфликтов с другими тестами, которые могут выполняться параллельно. Это гарантирует, что тесты всегда будут подключаться к правильным портам, независимо от того, что назначает Docker.
Нет необходимости удалять сервисы из коллекции сервисов или настраивать их вручную. Просто задайте строки подключения, и ваше приложение будет использовать их автоматически.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
Лучшие Практики Интеграционного Тестирования с Testcontainers. Начало
Интеграционные тесты с Testcontainers — мощный инструмент, но их поддержка может быстро превратиться в кошмар. Сегодня рассмотрим шаблоны, которые делают тесты Testcontainers надёжными, быстрыми и простыми в поддержке.
Традиционные интеграционные тесты часто используют общие тестовые БД или БД в памяти, которые не соответствуют поведению в рабочей среде. Вам либо приходится сталкиваться с загрязнением тестов между запусками, либо жертвовать реализмом ради скорости.
Testcontainers решает эту проблему, разворачивая настоящие Docker-контейнеры для ваших зависимостей. Тесты выполняются с использованием реальных PostgreSQL, Redis или любого другого сервиса, используемого в рабочей среде. После завершения тестов контейнеры уничтожаются, каждый раз позволяя вам начинать с чистого листа.
Всё происходит через API Docker. Testcontainers управляет всем жизненным циклом: извлечение образов, запуск контейнеров, ожидание готовности и очистка. Тестовому коду нужно лишь знать, как подключиться.
1. Подготовка
Убедитесь, что у вас есть необходимые пакеты:
Install-Package Microsoft.AspNetCore.Mvc.Testing
Install-Package Testcontainers.PostgreSql
Install-Package Testcontainers.Redis
Пакеты TestContainers существуют для множества сервисов.
2. Создание
Вот так можно создать контейнеры для PostgreSql и Redis:
var _pg = new PostgreSqlBuilder()
.WithImage("postgres:17")
.WithDatabase("mydb")
.WithUsername("postgres")
.WithPassword("postgres")
.Build();
var _redis = new RedisBuilder()
.WithImage("redis:latest")
.Build();
3. Использование
Чтобы запускать и останавливать контейнеры в тестах, нужно реализовать IAsyncLifetime в вашей WebApplicationFactory:
public sealed class IntegrationWebAppFactory :
WebApplicationFactory<Program>, IAsyncLifetime
{
public async Task InitializeAsync()
{
await _pg.StartAsync();
await _redis.StartAsync();
// Старт других зависимостей
}
public async Task DisposeAsync()
{
await _pg.StopAsync();
await _redis.StopAsync();
// Остановка других зависимостей
}
}
Это гарантирует готовность контейнеров до запуска тестов и их очистку после них. Т.е. отсутствие остаточного состояния Docker или состояний гонки.
Совет: закрепите версии образов (например, postgres:17), чтобы избежать сюрпризов от изменений версий зависимостей.
4. Передача конфигурации в приложение
Testcontainers назначает динамические порты. Не пишите жёсткие строки подключения в коде. Вместо этого внедряйте значения через WebApplicationFactory.ConfigureWebHost:
protected override void
ConfigureWebHost(IWebHostBuilder bldr)
{
bldr.UseSetting("ConnectionStrings:Database",
_pg.GetConnectionString());
bldr.UseSetting("ConnectionStrings:Redis",
_redis.GetConnectionString());
}
Здесь используется метод UseSetting для динамической передачи строк подключения. Это также позволяет избежать состояний гонки или конфликтов с другими тестами, которые могут выполняться параллельно. Это гарантирует, что тесты всегда будут подключаться к правильным портам, независимо от того, что назначает Docker.
Нет необходимости удалять сервисы из коллекции сервисов или настраивать их вручную. Просто задайте строки подключения, и ваше приложение будет использовать их автоматически.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
👍13
День 2362. #Testing #BestPractices
Лучшие Практики Интеграционного Тестирования с Testcontainers. Окончание
Начало
5. Совместное использование настроек с фикстурами xUnit
Фикстура — это общий контекст для тестов, позволяющий настроить дорогостоящие ресурсы, такие как БД или брокеры сообщений, один раз и использовать их повторно в нескольких тестах. Выбор между фикстурами классов и коллекций влияет как на производительность тестов, так и на изоляцию.
Фикстура класса — один контейнер на каждый тестовый класс.
Используйте, когда тесты изменяют глобальное состояние или когда отладка тестовых взаимодействий становится затруднительной. Применяйте, когда требуется полная изоляция между тестовыми классами (это медленнее, но безопаснее).
Фикстура коллекции — один контейнер, общий для нескольких тестовых классов.
Используйте, когда тесты не изменяют общее состояние или когда вы можете надёжно выполнить очистку между тестами. Т.е. когда тестовые классы не мешают друг другу (это быстрее, но требует дисциплины).
При использовании фикстур коллекций необходимо позаботиться об очистке любого состояния, которое может сохраняться между тестами. Это может включать сброс БД, очистку кэшей или удаление тестовых данных. Если этого не сделать, тесты могут влиять друг на друга, что приведёт к нестабильным результатам.
6. Вспомогательные методы для аутентификации и очистки
Фикстура может предоставлять вспомогательные методы для упрощения написания тестов:
Эти методы могут выполнять настройку аутентификации и очистку БД, чтобы не повторять шаблонный код в каждом тесте.
7. Написание поддерживаемых интеграционных тестов
При правильной настройке инфраструктуры ваши тесты должны быть сосредоточены на бизнес-логике. Сложность контейнеров должна быть скрыта за грамотно спроектированными базовыми классами и вспомогательными методами. В тестах вы не должны заботиться о правильной имитаций Postgres или Redis, а должны тестировать реальное поведение.
Итого
Testcontainers преобразовывает интеграционное тестирование, давая вам уверенность, которую приносит тестирование с реальными зависимостями. Больше не нужно беспокоиться о том, соответствует ли поведение вашей базы в памяти поведению производственной базы, или работать с общими тестовыми средами, которые выходят из строя при запуске тестов кем-то другим.
Начните с простого: выберите один интеграционный тест, который в настоящее время использует моки или БД в памяти, и преобразуйте его для использования Testcontainers. Вы сразу заметите разницу в уверенности, когда тест пройдёт успешно. Затем постепенно расширяйте его, чтобы охватить критически важные бизнес-процессы.
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
Лучшие Практики Интеграционного Тестирования с Testcontainers. Окончание
Начало
5. Совместное использование настроек с фикстурами xUnit
Фикстура — это общий контекст для тестов, позволяющий настроить дорогостоящие ресурсы, такие как БД или брокеры сообщений, один раз и использовать их повторно в нескольких тестах. Выбор между фикстурами классов и коллекций влияет как на производительность тестов, так и на изоляцию.
Фикстура класса — один контейнер на каждый тестовый класс.
Используйте, когда тесты изменяют глобальное состояние или когда отладка тестовых взаимодействий становится затруднительной. Применяйте, когда требуется полная изоляция между тестовыми классами (это медленнее, но безопаснее).
public class AddItemToCartTests :
IClassFixture<IntegrationWebAppFactory>
{
private IntegrationWebAppFactory _factory;
public AddItemToCartTests(
IntegrationWebAppFactory factory)
{
_factory = factory;
}
[Fact]
public async Task ShouldFail_WhenNotEnoughQuantity()
{ … }
}
Фикстура коллекции — один контейнер, общий для нескольких тестовых классов.
Используйте, когда тесты не изменяют общее состояние или когда вы можете надёжно выполнить очистку между тестами. Т.е. когда тестовые классы не мешают друг другу (это быстрее, но требует дисциплины).
[CollectionDefinition(nameof(IntegrationCollection))]
public sealed class IntegrationCollection :
ICollectionFixture<IntegrationWebAppFactory>
{
}
// Применение
[Collection(nameof(IntegrationCollection))]
public class AddItemToCartTests :
IntegrationTestFixture
{
public AddItemToCartTests(
IntegrationWebAppFactory factory)
: base(factory) { }
[Fact]
public async Task Should_Fail_WhenNotEnoughQuantity()
{ … }
}
При использовании фикстур коллекций необходимо позаботиться об очистке любого состояния, которое может сохраняться между тестами. Это может включать сброс БД, очистку кэшей или удаление тестовых данных. Если этого не сделать, тесты могут влиять друг на друга, что приведёт к нестабильным результатам.
6. Вспомогательные методы для аутентификации и очистки
Фикстура может предоставлять вспомогательные методы для упрощения написания тестов:
public async Task<HttpClient>
CreateAuthenticatedClientAsync() { … }
protected async Task CleanupDBAsync() { … }
Эти методы могут выполнять настройку аутентификации и очистку БД, чтобы не повторять шаблонный код в каждом тесте.
7. Написание поддерживаемых интеграционных тестов
При правильной настройке инфраструктуры ваши тесты должны быть сосредоточены на бизнес-логике. Сложность контейнеров должна быть скрыта за грамотно спроектированными базовыми классами и вспомогательными методами. В тестах вы не должны заботиться о правильной имитаций Postgres или Redis, а должны тестировать реальное поведение.
Итого
Testcontainers преобразовывает интеграционное тестирование, давая вам уверенность, которую приносит тестирование с реальными зависимостями. Больше не нужно беспокоиться о том, соответствует ли поведение вашей базы в памяти поведению производственной базы, или работать с общими тестовыми средами, которые выходят из строя при запуске тестов кем-то другим.
Начните с простого: выберите один интеграционный тест, который в настоящее время использует моки или БД в памяти, и преобразуйте его для использования Testcontainers. Вы сразу заметите разницу в уверенности, когда тест пройдёт успешно. Затем постепенно расширяйте его, чтобы охватить критически важные бизнес-процессы.
Источник: https://www.milanjovanovic.tech/blog/testcontainers-best-practices-dotnet-integration-testing
👍5
День 2413. #BestPractices
Сегодня порекомендую вам для воскресного просмотра выступление Скотта Заубера на недавней NDC Conference в Осло "10 Things I Do On Every .NET App" (10 вещей, которые я делаю в каждом .NET приложении)
По мере того, как приложение добавляет всё больше и больше функций, если вы не будете осторожны, оно может быстро превратиться в приложение, над которым никто в команде не хочет работать.
Выступление структурировано как серия коротких докладов на различные темы, которые помогут вам улучшить поддержку ваших .NET-приложений. Разговор пойдёт о библиотеках и передовые практиках, которые помогут в организации кода, валидации, ORM, автоматизированном тестировании, безопасности и многом другом. Вы сможете почерпнуть несколько идей, которые сможете сразу же начать реализовывать, вернувшись к работе над улучшением кодовых баз .NET.
Приятного просмотра.
PS: 20 звёзд, и я разберу все советы на канале😉
Сегодня порекомендую вам для воскресного просмотра выступление Скотта Заубера на недавней NDC Conference в Осло "10 Things I Do On Every .NET App" (10 вещей, которые я делаю в каждом .NET приложении)
По мере того, как приложение добавляет всё больше и больше функций, если вы не будете осторожны, оно может быстро превратиться в приложение, над которым никто в команде не хочет работать.
Выступление структурировано как серия коротких докладов на различные темы, которые помогут вам улучшить поддержку ваших .NET-приложений. Разговор пойдёт о библиотеках и передовые практиках, которые помогут в организации кода, валидации, ORM, автоматизированном тестировании, безопасности и многом другом. Вы сможете почерпнуть несколько идей, которые сможете сразу же начать реализовывать, вернувшись к работе над улучшением кодовых баз .NET.
Приятного просмотра.
31👍27
День 2420. #BestPractices
Вещи, Которые Я Делаю в Каждом Проекте .NET. Начало
Как и обещал, разбираю советы Скотта Заубера из его доклада на NDC Conference. Их много, так что эта серия затянется.
И получается это очень просто. Вы видите метод из тысячи строк, и вы думаете: «Мне нужно добавить ещё 4 строки». Какая разница, 1000 строк или 1004. Но так же думали те, кто его редактировал, когда он был 800, 600 и 200 строк. В конце концов, нужно, поставить точку и сказать: «Так, нам нужно это отрефакторить». Потому что, если не следить за этим, то всё быстро выйдет из-под контроля, и тогда, возможно, придётся делать великое переписывание, которое всё исправит. Все же знают, что переписать с нуля - всегда работает )))
Эта цитата о том, что необходимо фокусироваться на поддерживаемости во многих подобных вещах, потому что единственное, что постоянно в ПО, — это изменения. Технологии, требования, бизнес - всё меняется, и мы не можем это контролировать. Поэтому старайтесь оптимизировать приложение с учётом изменяемости.
1. Структура папок
Если вы создаёте новый проект, выбираете, например, MVC и работаете с традиционным серверным приложением (без Blazor, Angular, React), то каждый раз, когда вам нужно добавить новую функцию, вам приходится перемещаться по множеству папок. Нужно зайти в папку контроллеров, в папку представлений, в папку моделей, в CSS, в JavaScript, и т.п., которые разбросаны по всему приложению. Таким образом, область действия вашей функции как бы разбросана по всему проекту. И если вам когда-нибудь понадобится удалить функцию, придётся найти все эти файлы и удалить их. А если нужно добавить новую функцию, вам нужно знать, как разместить логику во всех этих разных папках.
Решение в том, чтобы создавать папки для функций, что упрощает поддержку и приводит к так называемой высокой связности, которая просто означает, что связанные элементы должны оставаться вместе. Вы создаёте функцию управления профилем пользователя? Создайте для неё папку и добавьте туда всё, что имеет отношение к этому: контроллер, модель представления, само представление и т.п. В React и Blazor – то же самое. Все компоненты – и даже тесты этих компонентов – всё в этой папке.
Подумайте, где вы храните мыло в вашем доме или квартире. Всё вместе в одном шкафу для мыла? Мыло для рук, шампунь, гель для душа, стиральный порошок и т.п. Нет. Вы храните все разные виды мыла там, где вы ими пользуетесь. Мыло для рук у раковины, шампунь и гель для душа в ванной, порошок – рядом со стиральной машиной и т.п. Почему бы не применить ту же концепцию в проекте?
2. Предупреждения
Бывало ли, что вы открывали проект, собирали его и получали сотни или даже тысячи предупреждений? Не очень приятно, правда? Так вот, предупреждений быть не должно! Либо это ошибка, которая меня волнует, и я её исправляю, либо я её игнорирую по какой-то причине, например, знаю, что она не появится. Поэтому включите флажок «Рассматривать предупреждения как ошибки». Это особенно актуально для новых проектов. Сделайте это с самого начала, потому что в противном случае у вас будут копиться самые разные предупреждения, и вы не будет знать, какие из них важны, а какие можно проигнорировать». Поэтому постарайтесь разбираться с ними с самого начала.
В существующем проекте либо создайте отдельную задачу, чтобы разобраться со всеми предупреждениями, либо делайте это по ходу выполнения других задач, когда работаете с кодом, где возникает предупреждение. Если вы абсолютно уверены, что какой-то вид предупреждений можно безболезненно игнорировать, его можно включить в исключения, чтобы этот вид предупреждений не выдавал ошибку при сборке.
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
Вещи, Которые Я Делаю в Каждом Проекте .NET. Начало
Как и обещал, разбираю советы Скотта Заубера из его доклада на NDC Conference. Их много, так что эта серия затянется.
Каждая система стремится к запутанности, медленности и сложности. Поддержание простоты, скорости и лёгкости использования — это битва, в которой приходится бороться каждый день.
— Гильермо Раух
И получается это очень просто. Вы видите метод из тысячи строк, и вы думаете: «Мне нужно добавить ещё 4 строки». Какая разница, 1000 строк или 1004. Но так же думали те, кто его редактировал, когда он был 800, 600 и 200 строк. В конце концов, нужно, поставить точку и сказать: «Так, нам нужно это отрефакторить». Потому что, если не следить за этим, то всё быстро выйдет из-под контроля, и тогда, возможно, придётся делать великое переписывание, которое всё исправит. Все же знают, что переписать с нуля - всегда работает )))
Эта цитата о том, что необходимо фокусироваться на поддерживаемости во многих подобных вещах, потому что единственное, что постоянно в ПО, — это изменения. Технологии, требования, бизнес - всё меняется, и мы не можем это контролировать. Поэтому старайтесь оптимизировать приложение с учётом изменяемости.
1. Структура папок
Если вы создаёте новый проект, выбираете, например, MVC и работаете с традиционным серверным приложением (без Blazor, Angular, React), то каждый раз, когда вам нужно добавить новую функцию, вам приходится перемещаться по множеству папок. Нужно зайти в папку контроллеров, в папку представлений, в папку моделей, в CSS, в JavaScript, и т.п., которые разбросаны по всему приложению. Таким образом, область действия вашей функции как бы разбросана по всему проекту. И если вам когда-нибудь понадобится удалить функцию, придётся найти все эти файлы и удалить их. А если нужно добавить новую функцию, вам нужно знать, как разместить логику во всех этих разных папках.
Решение в том, чтобы создавать папки для функций, что упрощает поддержку и приводит к так называемой высокой связности, которая просто означает, что связанные элементы должны оставаться вместе. Вы создаёте функцию управления профилем пользователя? Создайте для неё папку и добавьте туда всё, что имеет отношение к этому: контроллер, модель представления, само представление и т.п. В React и Blazor – то же самое. Все компоненты – и даже тесты этих компонентов – всё в этой папке.
Подумайте, где вы храните мыло в вашем доме или квартире. Всё вместе в одном шкафу для мыла? Мыло для рук, шампунь, гель для душа, стиральный порошок и т.п. Нет. Вы храните все разные виды мыла там, где вы ими пользуетесь. Мыло для рук у раковины, шампунь и гель для душа в ванной, порошок – рядом со стиральной машиной и т.п. Почему бы не применить ту же концепцию в проекте?
2. Предупреждения
Бывало ли, что вы открывали проект, собирали его и получали сотни или даже тысячи предупреждений? Не очень приятно, правда? Так вот, предупреждений быть не должно! Либо это ошибка, которая меня волнует, и я её исправляю, либо я её игнорирую по какой-то причине, например, знаю, что она не появится. Поэтому включите флажок «Рассматривать предупреждения как ошибки». Это особенно актуально для новых проектов. Сделайте это с самого начала, потому что в противном случае у вас будут копиться самые разные предупреждения, и вы не будет знать, какие из них важны, а какие можно проигнорировать». Поэтому постарайтесь разбираться с ними с самого начала.
В существующем проекте либо создайте отдельную задачу, чтобы разобраться со всеми предупреждениями, либо делайте это по ходу выполнения других задач, когда работаете с кодом, где возникает предупреждение. Если вы абсолютно уверены, что какой-то вид предупреждений можно безболезненно игнорировать, его можно включить в исключения, чтобы этот вид предупреждений не выдавал ошибку при сборке.
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
👍27
День 2421. #BestPractices
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
Начало
3. Логирование
Конкретная библиотека не имеет значения: Serilog, NLog или log4net. Но не используйте их напрямую. Используйте везде ILogger, чтобы единственное место, которое бы знало о конкретной его реализации – был файл program.cs. По возможности используйте структурное логирование. Также помните о том, что каждый журнал должен содержать некоторую ключевую информацию, например, ID пользователя или ID корреляции. Так вы сможете отслеживать как один запрос проходит через разные сервисы, и что там происходит. Иногда полезно включать короткий sha Git-коммита, чтобы если появляется ошибка, и вы её исправляете, вы могли сравнить, получаем ли мы больше исключений в последней версии, чем получали раньше?
Также важно разделять, как вы логируете нужную информацию. Например, в системе управления пользователями нужно регистрировать, кто внёс каждое изменение. Иногда мы думаем: «Есть же логгер, запишем в лог». Скорей всего, это не лучшее место. Рассмотрим о логи, метрики и аудиты.
Логи должны быть ориентированы на разработчиков. Вы не должны их передавать бизнесу. Это исключения с трассировками стека, ответы от внешних API, разные этапы процесса обработки и т.п.
Кроме того, многие путают уровни логирования. Например, сваливают всё в Information. Вы вызываете 3 API и хотите логировать их ответы. Это информация уровня отладки (Debug). А Information – это результат запроса: мы обработали столько-то записей за такое-то время, т.е. одна запись на запрос пользователя.
Используйте предупреждения (Warning) вместо ошибок (Error). Логи уровня предупреждения работают так: если у вас одно предупреждение, это не страшно, но если их много, то что-то не так. Классический пример: пользователь вводит неверный пароль и блокирует свою учётную запись на пять минут. Одно событие – не важно, но если их тысячи за короткий промежуток времени, возможно, происходит что-то не то (например, кто-то пытается проникнуть в систему).
Ошибки (Error) — это необработанные исключения. Многие просто игнорируют ошибки в логах. Не стоит так делать. Нужно выяснить первопричину и определить, волнует ли нас это. Может это предупреждение, а может реальная ошибка в коде. Постарайтесь очистить ошибки из лога, потому что худший человек, которому стоит сообщать о проблемах, — это ваши пользователи.
И, наконец, критический уровень (Critical) используется, когда приложение не может загрузиться. Например, нужно сначала обратиться к БД или к Azure Key Vault, чтобы извлечь секреты. Если это не удаётся, приложение не может работать.
Стоит подумать, как долго хранятся логи. Azure Log Analytics по умолчанию хранит только 30 дней. И если вы пытаетесь сохранить историческую информацию, например: «кто что изменил?», то ваш ответ бизнесу «Мы храним только 30 дней логов» вряд ли будет удовлетворительным. Аналогично, многие системы записывают логи в буфер и потом скидывают на диск. Так что, если отключится питание, последние логи потеряются. Это нормально, если логи используются только как описано выше, и не хранят важной для бизнеса информации.
Метрики делятся на 2 типа:
- уровня приложения: процессор, сеть, память, глубина очереди и т.п.
- бизнес-метрики: сколько размещено заказов, сколько раз нажимали эту кнопку, или сколько просмотрели эту страницу.
Как долго нужно хранить эти данные? Это должен быть разговор с бизнесом.
Аудиты - это регистрация того, кто, когда и что делал в приложении. В таких случаях вообще нельзя использовать логи. Самый простой способ — хранить данные аудита в БД вместе с данными. В одной транзакции вносите и изменение, и запись, кто его сделал.
Поэтому, когда кто-то говорит: «Нам нужно логировать это в следующий раз», - подумайте, какое хранилище данных использовать и на какой срок нужны эти данные.
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
Начало
3. Логирование
Конкретная библиотека не имеет значения: Serilog, NLog или log4net. Но не используйте их напрямую. Используйте везде ILogger, чтобы единственное место, которое бы знало о конкретной его реализации – был файл program.cs. По возможности используйте структурное логирование. Также помните о том, что каждый журнал должен содержать некоторую ключевую информацию, например, ID пользователя или ID корреляции. Так вы сможете отслеживать как один запрос проходит через разные сервисы, и что там происходит. Иногда полезно включать короткий sha Git-коммита, чтобы если появляется ошибка, и вы её исправляете, вы могли сравнить, получаем ли мы больше исключений в последней версии, чем получали раньше?
Также важно разделять, как вы логируете нужную информацию. Например, в системе управления пользователями нужно регистрировать, кто внёс каждое изменение. Иногда мы думаем: «Есть же логгер, запишем в лог». Скорей всего, это не лучшее место. Рассмотрим о логи, метрики и аудиты.
Логи должны быть ориентированы на разработчиков. Вы не должны их передавать бизнесу. Это исключения с трассировками стека, ответы от внешних API, разные этапы процесса обработки и т.п.
Кроме того, многие путают уровни логирования. Например, сваливают всё в Information. Вы вызываете 3 API и хотите логировать их ответы. Это информация уровня отладки (Debug). А Information – это результат запроса: мы обработали столько-то записей за такое-то время, т.е. одна запись на запрос пользователя.
Используйте предупреждения (Warning) вместо ошибок (Error). Логи уровня предупреждения работают так: если у вас одно предупреждение, это не страшно, но если их много, то что-то не так. Классический пример: пользователь вводит неверный пароль и блокирует свою учётную запись на пять минут. Одно событие – не важно, но если их тысячи за короткий промежуток времени, возможно, происходит что-то не то (например, кто-то пытается проникнуть в систему).
Ошибки (Error) — это необработанные исключения. Многие просто игнорируют ошибки в логах. Не стоит так делать. Нужно выяснить первопричину и определить, волнует ли нас это. Может это предупреждение, а может реальная ошибка в коде. Постарайтесь очистить ошибки из лога, потому что худший человек, которому стоит сообщать о проблемах, — это ваши пользователи.
И, наконец, критический уровень (Critical) используется, когда приложение не может загрузиться. Например, нужно сначала обратиться к БД или к Azure Key Vault, чтобы извлечь секреты. Если это не удаётся, приложение не может работать.
Стоит подумать, как долго хранятся логи. Azure Log Analytics по умолчанию хранит только 30 дней. И если вы пытаетесь сохранить историческую информацию, например: «кто что изменил?», то ваш ответ бизнесу «Мы храним только 30 дней логов» вряд ли будет удовлетворительным. Аналогично, многие системы записывают логи в буфер и потом скидывают на диск. Так что, если отключится питание, последние логи потеряются. Это нормально, если логи используются только как описано выше, и не хранят важной для бизнеса информации.
Метрики делятся на 2 типа:
- уровня приложения: процессор, сеть, память, глубина очереди и т.п.
- бизнес-метрики: сколько размещено заказов, сколько раз нажимали эту кнопку, или сколько просмотрели эту страницу.
Как долго нужно хранить эти данные? Это должен быть разговор с бизнесом.
Аудиты - это регистрация того, кто, когда и что делал в приложении. В таких случаях вообще нельзя использовать логи. Самый простой способ — хранить данные аудита в БД вместе с данными. В одной транзакции вносите и изменение, и запись, кто его сделал.
Поэтому, когда кто-то говорит: «Нам нужно логировать это в следующий раз», - подумайте, какое хранилище данных использовать и на какой срок нужны эти данные.
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
👍21
День 2422. #BestPractices
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
1-2
3
4. Задаём авторизацию глобально
Если вы используете, например, контроллеры, вам нужно не забыть добавить атрибут Authorize во всех контроллерах и действиях, которые вы хотите защитить (а это обычно большинство). Либо нужно не забыть наследовать от какого-нибудь базового контроллера, у которого есть этот атрибут. Но проблема в том, что если вы забудете, то этот метод/контроллер полностью открыты для внешнего мира.
Решение этой проблемы — так называемая резервная политика (FallbackPolicy) в ASP.NET Core. Резервная политика работает так: если вы не укажете другую политику, эта будет срабатывать каждый раз. В контейнере DI вы просто добавляете авторизацию и устанавливаете эту резервную политику:
Вы можете создать любую политику, но проще использовать конструктор политик авторизации и запросить аутентифицированного пользователя. Это сработает только в том случае, если вы не укажете ничего другого в контроллере. Если в контроллер или метод контроллера вы добавите атрибут AllowAnonymous, либо атрибут с более строгой политикой, будет использован он. А так вы защищены по умолчанию.
5. Валидация
Наверное, большинство из вас использовали аннотации данных для валидации. Проблема с ними в том, что, если нужно наложить несколько условий на свойство, добавление аннотации для каждого условия быстро становится громоздким и загружает модель. Не говоря уже о случае, когда нам требуется какая-то нестандартная валидация. Кроме того, для них сложно писать автоматизированные тесты.
Fluent Validation позволяет создавать бизнес-правила, которые легко читать даже бизнесу. Их также легко тестировать. Сложные правила создавать тоже просто. Например, в США, вы не можете пользоваться медицинской страховкой родителей после 26 лет. И вот правило для этого:
Вы можете показать это бизнесу, и они поймут эти условия, даже не зная кода.
6. Заголовки сервера
По умолчанию ASP.NET Core в ответ добавляет HTTP-заголовок с именем сервера. Если вы используете Kestrel, это значение будет Kestrel. Зачем он это делает? Скорей всего, в Microsoft просто хотят знать, сколько сайтов используют ASP.NET Core. В .NET Framework было ещё хуже, потому что выдавались и версии MVC и .NET. Но это раскрывает хакерам, что вы используете. Т.е. им не нужно проверять ваш сайт на уязвимости Java или Python, только на уязвимости, специфичные для .NET. Удаление заголовка не избавит вас от атак, но увеличит количество времени, которое атакующий потратит. Если у вас есть публичный веб-сайт, он гарантированно подвергался различным атакам. Удалить заголовок легко, просто добавьте эту строку:
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
1-2
3
4. Задаём авторизацию глобально
Если вы используете, например, контроллеры, вам нужно не забыть добавить атрибут Authorize во всех контроллерах и действиях, которые вы хотите защитить (а это обычно большинство). Либо нужно не забыть наследовать от какого-нибудь базового контроллера, у которого есть этот атрибут. Но проблема в том, что если вы забудете, то этот метод/контроллер полностью открыты для внешнего мира.
Решение этой проблемы — так называемая резервная политика (FallbackPolicy) в ASP.NET Core. Резервная политика работает так: если вы не укажете другую политику, эта будет срабатывать каждый раз. В контейнере DI вы просто добавляете авторизацию и устанавливаете эту резервную политику:
bulder.Services.AddAuthorization(opts =>
{
opts.FallbackPolicy = new
AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
Вы можете создать любую политику, но проще использовать конструктор политик авторизации и запросить аутентифицированного пользователя. Это сработает только в том случае, если вы не укажете ничего другого в контроллере. Если в контроллер или метод контроллера вы добавите атрибут AllowAnonymous, либо атрибут с более строгой политикой, будет использован он. А так вы защищены по умолчанию.
5. Валидация
Наверное, большинство из вас использовали аннотации данных для валидации. Проблема с ними в том, что, если нужно наложить несколько условий на свойство, добавление аннотации для каждого условия быстро становится громоздким и загружает модель. Не говоря уже о случае, когда нам требуется какая-то нестандартная валидация. Кроме того, для них сложно писать автоматизированные тесты.
Fluent Validation позволяет создавать бизнес-правила, которые легко читать даже бизнесу. Их также легко тестировать. Сложные правила создавать тоже просто. Например, в США, вы не можете пользоваться медицинской страховкой родителей после 26 лет. И вот правило для этого:
public class InsuranceValidator
: AbstractValidator<Insurance>
{
public InsuranceValidator()
{
RuleFor(model => model.Age)
.Must(age => age < 26)
.When(model => model.IsDependent)
.WithMessage(“A dependent must be younger than 26”);
}
}
Вы можете показать это бизнесу, и они поймут эти условия, даже не зная кода.
6. Заголовки сервера
По умолчанию ASP.NET Core в ответ добавляет HTTP-заголовок с именем сервера. Если вы используете Kestrel, это значение будет Kestrel. Зачем он это делает? Скорей всего, в Microsoft просто хотят знать, сколько сайтов используют ASP.NET Core. В .NET Framework было ещё хуже, потому что выдавались и версии MVC и .NET. Но это раскрывает хакерам, что вы используете. Т.е. им не нужно проверять ваш сайт на уязвимости Java или Python, только на уязвимости, специфичные для .NET. Удаление заголовка не избавит вас от атак, но увеличит количество времени, которое атакующий потратит. Если у вас есть публичный веб-сайт, он гарантированно подвергался различным атакам. Удалить заголовок легко, просто добавьте эту строку:
builder.WebHost.UseKestrel(opts => opts.AddServerHeader = false);
Продолжение следует…
Источник: https://youtu.be/SvcRvolP2NE
👍25
День 2423. #BestPractices
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
1-2
3
4-6
7. Не внедряйте IOptions
Проблема с параметрами IOptions в том, что вам нужна зависимость от Microsoft.Extensions. И если вы используете IOptions в других проектах ниже по стеку вызовов, придётся добавлять зависимость во все эти проекты. И тестировать параметр типа IOptions может быть непросто. Кроме того, везде приходится использовать .Value вместо просто имени параметра:
Решение - регистрируйте класс IOptions напрямую, так вы получите нужный класс значений в DI контейнере, который уже можно внедрять:
Если вы хотите, чтобы параметры изменялись без перезагрузки приложения, это тоже будет работать. Регистрируете значения как AddScoped и используйте IOptionsSnapshot<T> вместо IOptions<T>.
8. Запахи кода
Во-первых, возьмите за правило располагать «счастливый путь» в конце метода. Если вы смотрите на незнакомый код, как быстро узнать, что происходит, когда всё идёт хорошо? Проще всего – когда нужно всегда смотреть в конец.
Чтобы этого добиться, используйте технику раннего возврата. Вместо нескольких вложенных if-else, просто возвращайте ошибку (или любой другой результат), если что-то идёт не так. Таким образом, в начале метода следуют необходимые проверки, которые завершаются ранним возвратом, если они не проходят, а в конце (если все проверки прошли) – возврат результата, когда всё хорошо:
Это не только позволяет быстро найти «счастливый путь», но и избавляет от избыточной вложенности конструкций if.
И некоторые не жёсткие правила, а просто предупредительные сигналы о запахах кода:
- метод длиннее 20 строк,
- класс длиннее 200 строк,
- использование областей (#region).
Это всё сигналы о том, что метод или класс можно разбить на части.
9. Новые файлы решений
Это относительно новая функция. Технически она всё ещё в стадии превью версии, но сейчас довольно стабильна. Если коротко, новые файлы .slnx – это старый добрый XML, они гораздо короче и понятнее. Обновить файл решения можно, просто перейдя в папку решения и выполнив:
Затем не забудьте удалить старый файл .sln. Он больше не нужен, но утилита его не удаляет.
Окончание следует…
Источник: https://youtu.be/SvcRvolP2NE
Вещи, Которые Я Делаю в Каждом Проекте .NET. Продолжение
1-2
3
4-6
7. Не внедряйте IOptions
Проблема с параметрами IOptions в том, что вам нужна зависимость от Microsoft.Extensions. И если вы используете IOptions в других проектах ниже по стеку вызовов, придётся добавлять зависимость во все эти проекты. И тестировать параметр типа IOptions может быть непросто. Кроме того, везде приходится использовать .Value вместо просто имени параметра:
public class MyController(
IOptions<AppSettings> appSettings)
{
private readonly AppSettings _appSettings =
appSettings.Value;
…
}
Решение - регистрируйте класс IOptions напрямую, так вы получите нужный класс значений в DI контейнере, который уже можно внедрять:
services.Configure<AppSettings>(
Configuration.GetSection("AppSettings"));
services.AddSingleton(s =>
s.GetRequiredService<IOptions<AppSettings>>().Value);
…
public class MyController(AppSettings appSettings)
{
…
}
Если вы хотите, чтобы параметры изменялись без перезагрузки приложения, это тоже будет работать. Регистрируете значения как AddScoped и используйте IOptionsSnapshot<T> вместо IOptions<T>.
8. Запахи кода
Во-первых, возьмите за правило располагать «счастливый путь» в конце метода. Если вы смотрите на незнакомый код, как быстро узнать, что происходит, когда всё идёт хорошо? Проще всего – когда нужно всегда смотреть в конец.
Чтобы этого добиться, используйте технику раннего возврата. Вместо нескольких вложенных if-else, просто возвращайте ошибку (или любой другой результат), если что-то идёт не так. Таким образом, в начале метода следуют необходимые проверки, которые завершаются ранним возвратом, если они не проходят, а в конце (если все проверки прошли) – возврат результата, когда всё хорошо:
public ActionResult SendMessage(Message msg)
{
if(!ModelState.IsValid())
return View(msg);
if(emailSender.Send(msg) != Result.OK)
{
_logger.Log(…);
return LocalRedirect("/message/error");
}
…
return LocalRedirect("/message/success");
}
Это не только позволяет быстро найти «счастливый путь», но и избавляет от избыточной вложенности конструкций if.
И некоторые не жёсткие правила, а просто предупредительные сигналы о запахах кода:
- метод длиннее 20 строк,
- класс длиннее 200 строк,
- использование областей (#region).
Это всё сигналы о том, что метод или класс можно разбить на части.
9. Новые файлы решений
Это относительно новая функция. Технически она всё ещё в стадии превью версии, но сейчас довольно стабильна. Если коротко, новые файлы .slnx – это старый добрый XML, они гораздо короче и понятнее. Обновить файл решения можно, просто перейдя в папку решения и выполнив:
dotnet sln migrate
Затем не забудьте удалить старый файл .sln. Он больше не нужен, но утилита его не удаляет.
Окончание следует…
Источник: https://youtu.be/SvcRvolP2NE
👍21
День 2424. #BestPractices
Вещи, Которые Я Делаю в Каждом Проекте .NET. Окончание
1-2
3
4-6
7-9
10. HTTP-заголовки безопасности
Они сообщают браузеру о необходимости применения дополнительных правил. Это означает, что вы можете предотвратить определённые типы атак, такие как «человек посередине», кликджекинг, кросс-скриптинг и многие другие. Однако будьте осторожны. Можно, например, запретить загрузку JavaScript отовсюду, кроме вашего домена, но если вы при этом используете CDN, то ваше приложение сломается. Есть стратегии по постепенному внедрению HTTP-заголовков в существующее приложение. Если ваше приложение сканируется на безопасность внешними аналитиками, они всегда проверяют это. Есть публичные сайты, вроде securityheaders.com, которые просканируют ваш сайт и сообщат о состоянии дел. Примерно половина веб-сайтов вообще не имеет заголовков безопасности. И только у 10% рейтинг A или A+. У Эндрю Лока есть NuGet-пакет для реализации некоторых заголовков безопасности.
11. Валидация при сборке
Эта функция проверяет, что ваш DI контейнер настроен правильно. Синглтоны зависят только от синглтонов, а не принимают scoped-объекты. Иначе возникает проблема захвата зависимости. ASP.NET Core обнаруживает это, в режиме локальной разработки, но не в других средах. Но вы можете заставить это работать всегда:
12. Автоматизированные тесты
Надеюсь, не нужно объяснять, почему нужно писать тесты? Здесь рассмотрим один нюанс. Слышали выражение «чеховское ружьё»? Если кратко, Чехов писал, что если в главе 1 у вас на стене висит ружьё, то в последующих главах оно должно выстрелить. Иначе нечего его изначально «вешать». То есть, у всего должно быть предназначение. Вот как это касается тестов.
Что здесь не так? Имя, дата рождения и адрес не имеют значения для этого теста. Фамилия — единственное, что мы проверяем. Мы можем вынести ненужные конструкторы в общий код:
Нижний тест более ясно показывает, что мы тестируем.
13. Централизованное управление пакетами
Проблема, которую решает централизованное управление пакетами, в том, что у вас может быть один пакет в нескольких проектах в решении, и может быть раздражающим поддерживать их синхронизацию. В .NET 6 добавили эту функцию, с помощью которой вы можете создать directory.packages.props в корне и определить там пакеты и версии, которые вам нужны, а затем вы удаляете все версии пакетов в файлах .csproj проектов, и все проекты используют одну версию пакета (хотя, её можно переопределить в любом проекте при необходимости).
Источник: https://youtu.be/SvcRvolP2NE
Вещи, Которые Я Делаю в Каждом Проекте .NET. Окончание
1-2
3
4-6
7-9
10. HTTP-заголовки безопасности
Они сообщают браузеру о необходимости применения дополнительных правил. Это означает, что вы можете предотвратить определённые типы атак, такие как «человек посередине», кликджекинг, кросс-скриптинг и многие другие. Однако будьте осторожны. Можно, например, запретить загрузку JavaScript отовсюду, кроме вашего домена, но если вы при этом используете CDN, то ваше приложение сломается. Есть стратегии по постепенному внедрению HTTP-заголовков в существующее приложение. Если ваше приложение сканируется на безопасность внешними аналитиками, они всегда проверяют это. Есть публичные сайты, вроде securityheaders.com, которые просканируют ваш сайт и сообщат о состоянии дел. Примерно половина веб-сайтов вообще не имеет заголовков безопасности. И только у 10% рейтинг A или A+. У Эндрю Лока есть NuGet-пакет для реализации некоторых заголовков безопасности.
11. Валидация при сборке
Эта функция проверяет, что ваш DI контейнер настроен правильно. Синглтоны зависят только от синглтонов, а не принимают scoped-объекты. Иначе возникает проблема захвата зависимости. ASP.NET Core обнаруживает это, в режиме локальной разработки, но не в других средах. Но вы можете заставить это работать всегда:
builder.Host.UseDefaultHostProvider(config =>
{
config.ValidateOnBuild = true;
});
12. Автоматизированные тесты
Надеюсь, не нужно объяснять, почему нужно писать тесты? Здесь рассмотрим один нюанс. Слышали выражение «чеховское ружьё»? Если кратко, Чехов писал, что если в главе 1 у вас на стене висит ружьё, то в последующих главах оно должно выстрелить. Иначе нечего его изначально «вешать». То есть, у всего должно быть предназначение. Вот как это касается тестов.
[Fact]
public void EmptyLastNameValidationTest()
{
var customer = new Customer
{
FirstName = "John",
LastName = "",
Address = "123 1st Street",
Born = new DateOnly(2000, 1, 1)
}
var result = new CustomerValidator()
.Validate(customer);
result.Errors.Should().Contain(
e => e.ErrorMessage == "Last Name is required");
}
Что здесь не так? Имя, дата рождения и адрес не имеют значения для этого теста. Фамилия — единственное, что мы проверяем. Мы можем вынести ненужные конструкторы в общий код:
[Fact]
public void EmptyLastNameValidationTest()
{
_customer.LastName = "";
var result = _customerValidator
.Validate(_customer);
result.Errors.Should().Contain(
e => e.ErrorMessage == "Last Name is required");
}
Нижний тест более ясно показывает, что мы тестируем.
13. Централизованное управление пакетами
Проблема, которую решает централизованное управление пакетами, в том, что у вас может быть один пакет в нескольких проектах в решении, и может быть раздражающим поддерживать их синхронизацию. В .NET 6 добавили эту функцию, с помощью которой вы можете создать directory.packages.props в корне и определить там пакеты и версии, которые вам нужны, а затем вы удаляете все версии пакетов в файлах .csproj проектов, и все проекты используют одну версию пакета (хотя, её можно переопределить в любом проекте при необходимости).
Источник: https://youtu.be/SvcRvolP2NE
👍17