День 1322. #ЧтоНовенького
Cборки в .NET 7 Обрезаются по Умолчанию
Все сборки в консольных приложениях в .NET 7 теперь обрезаются (trimmed) по умолчанию. Это изменение влияет только на приложения, опубликованные с параметром
Ранее обрезались только сборки с параметром
Начиная с .NET 7, по умолчанию обрезаются все сборки в приложении. Приложения, которые ранее могли работать с PublishTrimmed, могут не работать в .NET 7. Однако затронуты будут только приложения с предупреждениями о тримминге. Если ваше приложение ране не выдавало предупреждений о тримминге, изменение поведения не должно вызвать каких-либо неблагоприятных последствий и, скорее всего, лишь уменьшит размер приложения.
Если в вашем приложении были предупреждения о тримминге, вы можете увидеть изменения в поведении или исключения. Например, приложение, использующее Newtonsoft.Json или System.Text.Json без генерации исходного кода для сериализации и десериализации типов в пользовательском проекте, могло функционировать до изменения, поскольку типы в проекте полностью сохранялись. Выдавалось лишь одно или несколько предупреждений о тримминге (коды предупреждений ILxxxx). Теперь типы в пользовательском проекте обрезаются, и сериализация может завершиться ошибкой или привести к непредвиденным результатам.
Причина изменения
Это изменение помогает уменьшить размер приложения без явного согласия пользователей и соответствует ожиданиям пользователей, что всё приложение будет обрезаться, если не указано иное.
Рекомендованное действие
Лучшее решение — устранить все предупреждения о тримминге. Сведения об устранении предупреждений в ваших библиотеках можно посмотреть в разделе документации «Общие сведения о предупреждениях об обрезке».
В отношении сторонних библиотек, обратитесь к автору, чтобы попросить устранить предупреждения, или выберите другую библиотеку, которая уже поддерживает тримминг. Например, вместо Newtonsoft.Json можно переключиться на System.Text.Json с генерацией исходного кода.
Чтобы вернуться к предыдущему поведению, задайте для свойства TrimMode значение partial, которое было поведением по умолчанию до .NET 7:
Cборки в .NET 7 Обрезаются по Умолчанию
Все сборки в консольных приложениях в .NET 7 теперь обрезаются (trimmed) по умолчанию. Это изменение влияет только на приложения, опубликованные с параметром
PublishTrimmed=true
, и нарушит работу только тех приложений, для которых ранее выдавались предупреждения при тримминге. Это также влияет только на простые приложения .NET, которые не используют Windows Desktop, Android, iOS, WASM или ASP.NET SDK.Ранее обрезались только сборки с параметром
<IsTrimmable>true</IsTrimmable>
в файле проекта библиотеки.Начиная с .NET 7, по умолчанию обрезаются все сборки в приложении. Приложения, которые ранее могли работать с PublishTrimmed, могут не работать в .NET 7. Однако затронуты будут только приложения с предупреждениями о тримминге. Если ваше приложение ране не выдавало предупреждений о тримминге, изменение поведения не должно вызвать каких-либо неблагоприятных последствий и, скорее всего, лишь уменьшит размер приложения.
Если в вашем приложении были предупреждения о тримминге, вы можете увидеть изменения в поведении или исключения. Например, приложение, использующее Newtonsoft.Json или System.Text.Json без генерации исходного кода для сериализации и десериализации типов в пользовательском проекте, могло функционировать до изменения, поскольку типы в проекте полностью сохранялись. Выдавалось лишь одно или несколько предупреждений о тримминге (коды предупреждений ILxxxx). Теперь типы в пользовательском проекте обрезаются, и сериализация может завершиться ошибкой или привести к непредвиденным результатам.
Причина изменения
Это изменение помогает уменьшить размер приложения без явного согласия пользователей и соответствует ожиданиям пользователей, что всё приложение будет обрезаться, если не указано иное.
Рекомендованное действие
Лучшее решение — устранить все предупреждения о тримминге. Сведения об устранении предупреждений в ваших библиотеках можно посмотреть в разделе документации «Общие сведения о предупреждениях об обрезке».
В отношении сторонних библиотек, обратитесь к автору, чтобы попросить устранить предупреждения, или выберите другую библиотеку, которая уже поддерживает тримминг. Например, вместо Newtonsoft.Json можно переключиться на System.Text.Json с генерацией исходного кода.
Чтобы вернуться к предыдущему поведению, задайте для свойства TrimMode значение partial, которое было поведением по умолчанию до .NET 7:
<TrimMode>partial</TrimMode>Поведение по умолчанию в .NET 7+:
<TrimMode>full</TrimMode>Источник: https://docs.microsoft.com/en-us/dotnet/core/compatibility/deployment/7.0/trim-all-assemblies
👍7
День 1323. #Книги
По совету из здешнего чата прочитал книгу «Мой продуктивный год» (Крис Бэйли — М.: Альпина Паблишер, 2022).
«У многих людей списки дел настолько длинные, что невозможно переделать их все за имеющееся время. Первое, к чему прибегают в такой ситуации, чтобы высвободить время и успеть больше, - начинают заказывать еду в офис, накачиваются кофеином, забрасывают занятия спортом, работают до ночи и экономят на сне. Все эти жертвы способны ненадолго поддёрнуть продуктивность вверх, но в долгосрочной перспективе их влияние на продуктивность негативно.»
Автор в течение года пробовал на себе все возможные методы повышения продуктивности. В 26 главах книги он рассматривает каждый из методов, который действительно сработал для него. В итоге получается набор полезных советов, которые позволят сконцентрировано работать, выполнять задачи, которыми не хочется заниматься, и бороться с прокрастинацией.
Читается на одном дыхании и очень мотивирует. Некоторые из практик пробую применять.
По совету из здешнего чата прочитал книгу «Мой продуктивный год» (Крис Бэйли — М.: Альпина Паблишер, 2022).
«У многих людей списки дел настолько длинные, что невозможно переделать их все за имеющееся время. Первое, к чему прибегают в такой ситуации, чтобы высвободить время и успеть больше, - начинают заказывать еду в офис, накачиваются кофеином, забрасывают занятия спортом, работают до ночи и экономят на сне. Все эти жертвы способны ненадолго поддёрнуть продуктивность вверх, но в долгосрочной перспективе их влияние на продуктивность негативно.»
Автор в течение года пробовал на себе все возможные методы повышения продуктивности. В 26 главах книги он рассматривает каждый из методов, который действительно сработал для него. В итоге получается набор полезных советов, которые позволят сконцентрировано работать, выполнять задачи, которыми не хочется заниматься, и бороться с прокрастинацией.
Читается на одном дыхании и очень мотивирует. Некоторые из практик пробую применять.
👍22
День 1324. #ЗаметкиНаПолях
Как Получить Базовый URL в ASP.NET Core
Обычно это не нужно. По крайней мере, не из кода самого приложения. Однако существует ряд причин, по которым это всё ещё может быть актуально, например, если вы хотите сгенерировать и вывести абсолютный URL-адрес в контроллере MVC или на странице Razor.
Допустим, у нас есть адрес страницы:
https://example.com/path/document/?id=42
URL состоит из схемы (https), имени хоста (example.com), пути (path/document/), и строки запроса (id=42). Базовый адрес представляет собой комбинацию схемы, порта и имени хоста:
https://example.com
Номер порта можно не указывать, если веб-сервер прослушивает порт 443 для HTTPS или порт 80 для HTTP-запросов.
Насколько мне известно, в ASP.NET Core нет встроенных способов получить базовый URL, но запрос предоставляет достаточно информации, чтобы собрать его вручную:
Теперь для получения базового URL-адреса требуется всего одна строка:
Как Получить Базовый URL в ASP.NET Core
Обычно это не нужно. По крайней мере, не из кода самого приложения. Однако существует ряд причин, по которым это всё ещё может быть актуально, например, если вы хотите сгенерировать и вывести абсолютный URL-адрес в контроллере MVC или на странице Razor.
Допустим, у нас есть адрес страницы:
https://example.com/path/document/?id=42
URL состоит из схемы (https), имени хоста (example.com), пути (path/document/), и строки запроса (id=42). Базовый адрес представляет собой комбинацию схемы, порта и имени хоста:
https://example.com
Номер порта можно не указывать, если веб-сервер прослушивает порт 443 для HTTPS или порт 80 для HTTP-запросов.
Насколько мне известно, в ASP.NET Core нет встроенных способов получить базовый URL, но запрос предоставляет достаточно информации, чтобы собрать его вручную:
public IActionResult Index()Этот пример обычно предлагается на StackOverflow. Есть некоторые недостатки в использовании такой интерполяции строк. Очевидным является часть порта, которую мы в большинстве случаев не хотим включать. К счастью, в .NET есть встроенный класс для создания URL-адресов с именем UriBuilder. Немного отрефакторим код и включим его в метод расширения HttpRequest:
{
var base = $"{Request.Scheme}://{Request.Host}:{Request.Host.Port ?? 80}";
return View();
}
public static class HttpRequestExtensionsВ этом примере мы используем класс UriBuilder для добавления схемы и имени хоста, а порт добавляем только в том случае, если он есть в запросе. Значение -1 (как ни странно) не указывает на отсутствие порта в UriBuilder. Оператор if позволяет избежать отображения номера порта в базовом URL, используется порт по умолчанию для схемы. Т.е., если схема https и порт 443, нам просто нужен https://example.com, а не https://example.com:443.
{
public static string? BaseUrl(
this HttpRequest req)
{
if (req == null) return null;
var uriBuilder = new UriBuilder(
req.Scheme,
req.Host.Host,
req.Host.Port ?? -1);
if (uriBuilder.Uri.IsDefaultPort)
uriBuilder.Port = -1;
return uriBuilder.Uri.AbsoluteUri;
}
}
Теперь для получения базового URL-адреса требуется всего одна строка:
Request.BaseUrl();В Razor Pages у нас не будет доступа к HTTP-запросу, как в MVC. Здесь требуется внедрить HttpContextAccessor в файл Program.cs (Startup.cs):
var builder = WebApplication.CreateBuilder(args);После этого можно внедрить IHttpContextAccessor на страницу Razor:
builder.Services.AddHttpContextAccessor();
// ...
var app = builder.Build();
// ...
{Источник: https://blog.elmah.io/how-to-get-base-url-in-asp-net-core/
private readonly IHttpContextAccessor hCA;
public IndexModel(IHttpContextAccessor hCA)
{
this.hCA = hCA;
}
public void OnGet()
{
var baseUrl =
hCA.HttpContext?.Request.BaseUrl();
// ...
}
}
👍8
День 1325. #Оффтоп
Открытый Код и Случайные Инновации
Чем более открыта система для новых контрибуторов, тем больше шансов, что случайная встреча принесёт пользу всем участникам.
В конце 1970-х годов в разработке технологий доминировала горстка крупных компаний из Бостона, которые всё финансировали и привлекали в основном талантливых инженеров из Массачусетского технологического института.
В Кремниевой долине в 1990-х люди часто меняли работу и пользовались преимуществом растущего количества неформальных связей, созданных инженерами, бизнес-лидерами и венчурными капиталистами. Вместо культуры секретности была культура нетворкинга. Если бы вы были в Долине в 1990-х, вы могли бы почувствовать вокруг себя гул амбиций и технического голода. Каждая случайная встреча между игроками в индустрии ПО могла стать искрой, которая изменит то, как работает целая отрасль.
Сейчас, когда мы живем в 2020-х годах, произошло ещё одно важное событие, стимулирующее инновации, — это ПО с открытым исходным кодом. По мере того, как открытый код становился всё более популярным в 21 веке, темпы развития отрасли стремительно росли. В частности, это было обусловлено фреймворками ПО с открытым кодом, такими как LAMP или .NET Core, средами разработки и инновациями в базах данных, развитием CMS, поиска и других основных вычислительных функций. Разработка продвинулась «вверх по стеку», так что новым приложениям не нужно изобретать велосипед.
Это также привело к резкому росту экономической активности. Доступность децентрализованных инструментов разработки, таких как GIT, также экспоненциально расширила возможности технических работников по созданию неформальных сетей и совместной работе по всему миру. Не случайно в 2000-е почти все компании стали производителями ПО — от финансов до здравоохранения и образования. ПО управляет нашим миром, и ПО с открытым кодом является правилом, а не исключением в разработке.
Многие попадают в разработку ПО почти случайно. Услышав о программировании от знакомых, попробовав что-то написать самостоятельно или по статье или видеоуроку в сети. Эти случайности могли произойти только потому, что люди делятся своими знаниями, в основном неструктурированным образом. Этот неформальный обмен, который теперь может выходить за пределы географических, политических и бизнес-блоков, — вот что заставляет мир изобретать. Теперь мы наблюдаем ещё один сдвиг — к постгеографическому миру разработки программного обеспечения, великому «перераспределению» возможностей между городами и поселками, далекими от традиционных технологических центров.
Что читатель должен извлечь из этого поста? Что карьера зависит не только от случайности, но и от страстного намерения? Что местоположение может быть судьбоносным, но нельзя предсказать, где произойдет следующий прорыв?
Самый важный урок о случайных инновациях заключается в том, что они не являются транзакционными. На протяжении многих лет бизнес воспринимал использование открытого исходного кода как глупость, пустую трату времени и знаний, и как предоставление услуги бесплатно. Это потому, что они думали в стиле Бостонских компаний 1970-х, а не в стиле Кремниевой долины.
Обмен бизнес-информацией является услугой. Но случайные инновации требуют от нас отдавать, не получая, верить, что мы получим выгоду или просто смириться, с тем, что мы не получим непосредственной выгоды. Если вы поделитесь знаниями, кто-то воспользуется ими, но всё равно поделитесь. Независимо от того, делитесь ли вы открытым исходным кодом или своими знаниями иным образом, этот обмен ценен сам по себе. И он двигает всю отрасль вперёд.
Источник: https://stackoverflow.blog/2022/08/24/open-source-and-accidental-innovation/
Открытый Код и Случайные Инновации
Чем более открыта система для новых контрибуторов, тем больше шансов, что случайная встреча принесёт пользу всем участникам.
В конце 1970-х годов в разработке технологий доминировала горстка крупных компаний из Бостона, которые всё финансировали и привлекали в основном талантливых инженеров из Массачусетского технологического института.
В Кремниевой долине в 1990-х люди часто меняли работу и пользовались преимуществом растущего количества неформальных связей, созданных инженерами, бизнес-лидерами и венчурными капиталистами. Вместо культуры секретности была культура нетворкинга. Если бы вы были в Долине в 1990-х, вы могли бы почувствовать вокруг себя гул амбиций и технического голода. Каждая случайная встреча между игроками в индустрии ПО могла стать искрой, которая изменит то, как работает целая отрасль.
Сейчас, когда мы живем в 2020-х годах, произошло ещё одно важное событие, стимулирующее инновации, — это ПО с открытым исходным кодом. По мере того, как открытый код становился всё более популярным в 21 веке, темпы развития отрасли стремительно росли. В частности, это было обусловлено фреймворками ПО с открытым кодом, такими как LAMP или .NET Core, средами разработки и инновациями в базах данных, развитием CMS, поиска и других основных вычислительных функций. Разработка продвинулась «вверх по стеку», так что новым приложениям не нужно изобретать велосипед.
Это также привело к резкому росту экономической активности. Доступность децентрализованных инструментов разработки, таких как GIT, также экспоненциально расширила возможности технических работников по созданию неформальных сетей и совместной работе по всему миру. Не случайно в 2000-е почти все компании стали производителями ПО — от финансов до здравоохранения и образования. ПО управляет нашим миром, и ПО с открытым кодом является правилом, а не исключением в разработке.
Многие попадают в разработку ПО почти случайно. Услышав о программировании от знакомых, попробовав что-то написать самостоятельно или по статье или видеоуроку в сети. Эти случайности могли произойти только потому, что люди делятся своими знаниями, в основном неструктурированным образом. Этот неформальный обмен, который теперь может выходить за пределы географических, политических и бизнес-блоков, — вот что заставляет мир изобретать. Теперь мы наблюдаем ещё один сдвиг — к постгеографическому миру разработки программного обеспечения, великому «перераспределению» возможностей между городами и поселками, далекими от традиционных технологических центров.
Что читатель должен извлечь из этого поста? Что карьера зависит не только от случайности, но и от страстного намерения? Что местоположение может быть судьбоносным, но нельзя предсказать, где произойдет следующий прорыв?
Самый важный урок о случайных инновациях заключается в том, что они не являются транзакционными. На протяжении многих лет бизнес воспринимал использование открытого исходного кода как глупость, пустую трату времени и знаний, и как предоставление услуги бесплатно. Это потому, что они думали в стиле Бостонских компаний 1970-х, а не в стиле Кремниевой долины.
Обмен бизнес-информацией является услугой. Но случайные инновации требуют от нас отдавать, не получая, верить, что мы получим выгоду или просто смириться, с тем, что мы не получим непосредственной выгоды. Если вы поделитесь знаниями, кто-то воспользуется ими, но всё равно поделитесь. Независимо от того, делитесь ли вы открытым исходным кодом или своими знаниями иным образом, этот обмен ценен сам по себе. И он двигает всю отрасль вперёд.
Источник: https://stackoverflow.blog/2022/08/24/open-source-and-accidental-innovation/
👍11
День 1326. #CodeReview
Советы по Улучшению Обзоров Кода на GitHub
У большинства компаний и команд есть специальные стандарты, определяющие, как должен выглядеть обзор и сколько согласований вам нужно, прежде чем слить код в основную ветку. У GitHub есть специальные инструменты для поддержки обзоров кода в своих средах.
1. Защищённые ветки
Защитите основную ветку от случайных изменений. Push чего-либо непосредственно в основную ветку не должен быть возможным. К счастью, GitHub предлагает отличный механизм для защиты веток. Вы можете создать специальные правила, определив, например, что для слияния кода с основной веткой требуется пул-реквест и одобрение хотя бы одного рецензента.
Как это настроить?
- В репозитории на GitHub перейдите на вкладку Settings (Настройки).
- В меню слева нажмите Branches (Ветки).
- В разделе Branch protection rules (Правила защиты веток) нажмите Add rule (Добавить правило).
- Введите имя ветки или регулярное выражение для шаблона имени.
- Выберите один из пунктов, из списка правил и сохраните изменения.
2. Метки
Метки — это дополнительные, легко распознаваемые фрагменты информации, видимые в списках пул-реквестов. Вы можете использовать их, например, чтобы различать внутренние и внешние изменения, запросы на слияние, связанные с конкретными функциями вашего приложения, типом изменений или размером. Использование меток значительно упрощает управление слияниями.
Как создать новую метку?
- В репозитории на GitHub перейдите в раздел Pull Requests.
- Щёлкните на кнопку Labels (Метки) рядом с полем фильтра.
- Нажмите зелёную кнопку New label (Новая метка).
- Заполните все поля в форме и нажмите кнопку Create label (Создать метку).
- Теперь вы можете назначить её любому из ваших новых или существующих мерж-реквестов в форме создания пул-реквеста.
3. Автоматические проверки
Многие вещи, такие как синтаксис или выполнение тестов, могут выполняться автоматически. Вы можете использовать Jenkins/Github Actions/CircleCI или любой другой инструмент по вашему выбору, чтобы запускать автоматические тесты при каждом создании пул-реквеста. Добавьте правило для отказа в слиянии до тех пор, пока не будут пройдены все необходимые проверки. В один прекрасный день это может спасти ваш производственный код! Добавьте также способ лёгкого повторного запуска этих тестов вручную . Например, отправка специального сообщения в комментарии на GitHub. Это очень полезно при отладке.
4. Шаблон сообщения пул-реквеста с контрольным списком
Каждый запрос на слияние должен иметь хороший, короткий и говорящий сам за себя заголовок и некоторое описание, возможно ссылку на задачу в баг-трекере. Кроме того, некоторые вещи нельзя протестировать вручную, например, доступность или выполнение бизнес-требований. Со временем становится всё труднее помнить все те вещи, которые нужно указать в сообщении мерж-реквеста вам, как автору, и вещи, которые нужно проверить вам, как рецензенту. Вы можете легко решить эти проблемы, используя шаблоны для мерж-реквестов. Это черновик сообщения с контрольным списком вещей, которые нужно проверить вручную, когда вы создаёте запрос на слияние, и этого достаточно, чтобы заполнить форму необходимой информацией и отметить все пункты в контрольном списке как выполненные.
Как добавить шаблон?
- Откройте свой репозиторий в своем любимом редакторе кода.
- Добавьте файл pull_request_template.md в корень вашего репозитория или папку docs, расположенную в корне.
- Поместите свой шаблон внутрь файла (вы можете использовать синтаксис markdown для создания заголовков, контрольных списков и т. д.).
- Слейте изменения с основной веткой.
- Если вы хотите иметь более 1 шаблона сообщения, создайте каталог PULL_REQUEST_TEMPLATE (также в корне или в папке docs) и храните там файлы markdown. В этом случае пользователь сможет выбрать один из шаблонов, используя раскрывающееся меню во время создания запроса на слияние.
Источник: https://dev.to/this-is-learning/5-tips-to-improve-your-code-reviews-on-github-gja
Советы по Улучшению Обзоров Кода на GitHub
У большинства компаний и команд есть специальные стандарты, определяющие, как должен выглядеть обзор и сколько согласований вам нужно, прежде чем слить код в основную ветку. У GitHub есть специальные инструменты для поддержки обзоров кода в своих средах.
1. Защищённые ветки
Защитите основную ветку от случайных изменений. Push чего-либо непосредственно в основную ветку не должен быть возможным. К счастью, GitHub предлагает отличный механизм для защиты веток. Вы можете создать специальные правила, определив, например, что для слияния кода с основной веткой требуется пул-реквест и одобрение хотя бы одного рецензента.
Как это настроить?
- В репозитории на GitHub перейдите на вкладку Settings (Настройки).
- В меню слева нажмите Branches (Ветки).
- В разделе Branch protection rules (Правила защиты веток) нажмите Add rule (Добавить правило).
- Введите имя ветки или регулярное выражение для шаблона имени.
- Выберите один из пунктов, из списка правил и сохраните изменения.
2. Метки
Метки — это дополнительные, легко распознаваемые фрагменты информации, видимые в списках пул-реквестов. Вы можете использовать их, например, чтобы различать внутренние и внешние изменения, запросы на слияние, связанные с конкретными функциями вашего приложения, типом изменений или размером. Использование меток значительно упрощает управление слияниями.
Как создать новую метку?
- В репозитории на GitHub перейдите в раздел Pull Requests.
- Щёлкните на кнопку Labels (Метки) рядом с полем фильтра.
- Нажмите зелёную кнопку New label (Новая метка).
- Заполните все поля в форме и нажмите кнопку Create label (Создать метку).
- Теперь вы можете назначить её любому из ваших новых или существующих мерж-реквестов в форме создания пул-реквеста.
3. Автоматические проверки
Многие вещи, такие как синтаксис или выполнение тестов, могут выполняться автоматически. Вы можете использовать Jenkins/Github Actions/CircleCI или любой другой инструмент по вашему выбору, чтобы запускать автоматические тесты при каждом создании пул-реквеста. Добавьте правило для отказа в слиянии до тех пор, пока не будут пройдены все необходимые проверки. В один прекрасный день это может спасти ваш производственный код! Добавьте также способ лёгкого повторного запуска этих тестов вручную . Например, отправка специального сообщения в комментарии на GitHub. Это очень полезно при отладке.
4. Шаблон сообщения пул-реквеста с контрольным списком
Каждый запрос на слияние должен иметь хороший, короткий и говорящий сам за себя заголовок и некоторое описание, возможно ссылку на задачу в баг-трекере. Кроме того, некоторые вещи нельзя протестировать вручную, например, доступность или выполнение бизнес-требований. Со временем становится всё труднее помнить все те вещи, которые нужно указать в сообщении мерж-реквеста вам, как автору, и вещи, которые нужно проверить вам, как рецензенту. Вы можете легко решить эти проблемы, используя шаблоны для мерж-реквестов. Это черновик сообщения с контрольным списком вещей, которые нужно проверить вручную, когда вы создаёте запрос на слияние, и этого достаточно, чтобы заполнить форму необходимой информацией и отметить все пункты в контрольном списке как выполненные.
Как добавить шаблон?
- Откройте свой репозиторий в своем любимом редакторе кода.
- Добавьте файл pull_request_template.md в корень вашего репозитория или папку docs, расположенную в корне.
- Поместите свой шаблон внутрь файла (вы можете использовать синтаксис markdown для создания заголовков, контрольных списков и т. д.).
- Слейте изменения с основной веткой.
- Если вы хотите иметь более 1 шаблона сообщения, создайте каталог PULL_REQUEST_TEMPLATE (также в корне или в папке docs) и храните там файлы markdown. В этом случае пользователь сможет выбрать один из шаблонов, используя раскрывающееся меню во время создания запроса на слияние.
Источник: https://dev.to/this-is-learning/5-tips-to-improve-your-code-reviews-on-github-gja
👍6
День 1327. #ЧтоНовенького
.NET 7 SDK Поддерживает Создание Контейнерных Приложений
25 августа Microsoft объявили, что .NET 7 SDK будет включать поддержку создания контейнерных приложений в рамках процесса публикации сборки, минуя необходимость в явной фазе сборки Docker.
Обоснованием этого решения было упрощение стандартного кода Docker и снижение когнитивной нагрузки на разработчиков, что позволило создавать контейнерные приложения в .NET быстрее, чем раньше. Разработчики могут использовать сгенерированные контейнеры в локальной разработке или использовать их для создания образов в рамках конвейера CI/CD.
Чет Хаск, продукт-менеджер .NET SDK, объясняет, что для создания этой функции им пришлось добавить поддержку обработки файлов TAR непосредственно в .NET. Это позволило изменять и обновлять файлы образов Docker, которые упакованы как файлы TAR в соответствии со спецификацией Open Container Initiative, во время обычного процесса сборки .NET. Вся информация, необходимая для создания образа контейнера приложения .NET, уже имеется в момент сборки, а в пакет SDK для .NET был добавлен процесс сборки образа контейнера, написанный на C#.
Образ Docker может иметь множество параметров конфигурации. В процессе сборки образа .NET SDK эти конфигурации отображаются как свойства на уровне проекта. Например, проект ASP.NET Core имеет базовый образ контейнера по умолчанию из реестра контейнеров Azure. Если вы хотите заменить его на другой базовый образ, вам придётся изменить свойство
Основное ограничение заключается в том, что команды Dockerfile RUN не поддерживаются. По словам Хаска, нет возможности выполнять команды RUN с помощью .NET SDK. Команды Dockerfile RUN позволяют создавать промежуточные образы, запуская команды операционной системы в создаваемом образе, обычно для установки инструмента или изменения конфигурации системы. В качестве обходного пути Microsoft предлагает создать образ, использующий команды RUN, с помощью Docker, а затем указать этот образ в качестве базового при создании контейнеров в .NET SDK.
Чтобы попробовать эту новую функцию в .NET 7, вам необходимо установить Docker на вашем компьютере для разработки, по крайней мере, на данном этапе. Зависимость от Docker связана с тем, что SDK по-прежнему полагается на него для аутентификации в реестрах контейнеров. Также Docker по-прежнему необходим для запуска сгенерированного образа контейнера.
На данный момент эта функция поддерживается только для образов Linux. В Microsoft заявляют, что образы Windows и проверка подлинности реестра контейнеров будут готовы до выпуска .NET 7 наряду с другими возможностями настройки образов.
Источник: https://www.infoq.com/news/2022/09/dotnet-sdk-container-support/
.NET 7 SDK Поддерживает Создание Контейнерных Приложений
25 августа Microsoft объявили, что .NET 7 SDK будет включать поддержку создания контейнерных приложений в рамках процесса публикации сборки, минуя необходимость в явной фазе сборки Docker.
Обоснованием этого решения было упрощение стандартного кода Docker и снижение когнитивной нагрузки на разработчиков, что позволило создавать контейнерные приложения в .NET быстрее, чем раньше. Разработчики могут использовать сгенерированные контейнеры в локальной разработке или использовать их для создания образов в рамках конвейера CI/CD.
Чет Хаск, продукт-менеджер .NET SDK, объясняет, что для создания этой функции им пришлось добавить поддержку обработки файлов TAR непосредственно в .NET. Это позволило изменять и обновлять файлы образов Docker, которые упакованы как файлы TAR в соответствии со спецификацией Open Container Initiative, во время обычного процесса сборки .NET. Вся информация, необходимая для создания образа контейнера приложения .NET, уже имеется в момент сборки, а в пакет SDK для .NET был добавлен процесс сборки образа контейнера, написанный на C#.
Образ Docker может иметь множество параметров конфигурации. В процессе сборки образа .NET SDK эти конфигурации отображаются как свойства на уровне проекта. Например, проект ASP.NET Core имеет базовый образ контейнера по умолчанию из реестра контейнеров Azure. Если вы хотите заменить его на другой базовый образ, вам придётся изменить свойство
ContainerBaseImage
в файле проекта и выбрать для него новый образ. Процесс сборки также примет имя сборки проекта в качестве имени образа, которое также можно переопределить с помощью свойства проекта ContainerImageName
.Основное ограничение заключается в том, что команды Dockerfile RUN не поддерживаются. По словам Хаска, нет возможности выполнять команды RUN с помощью .NET SDK. Команды Dockerfile RUN позволяют создавать промежуточные образы, запуская команды операционной системы в создаваемом образе, обычно для установки инструмента или изменения конфигурации системы. В качестве обходного пути Microsoft предлагает создать образ, использующий команды RUN, с помощью Docker, а затем указать этот образ в качестве базового при создании контейнеров в .NET SDK.
Чтобы попробовать эту новую функцию в .NET 7, вам необходимо установить Docker на вашем компьютере для разработки, по крайней мере, на данном этапе. Зависимость от Docker связана с тем, что SDK по-прежнему полагается на него для аутентификации в реестрах контейнеров. Также Docker по-прежнему необходим для запуска сгенерированного образа контейнера.
На данный момент эта функция поддерживается только для образов Linux. В Microsoft заявляют, что образы Windows и проверка подлинности реестра контейнеров будут готовы до выпуска .NET 7 наряду с другими возможностями настройки образов.
Источник: https://www.infoq.com/news/2022/09/dotnet-sdk-container-support/
👍13
День 1328. #ЗаметкиНаПолях #AsyncTips
Асинхронное Создание Объектов: Фабрики
Задача: вы создаёте тип, который требует выполнения некоторой асинхронной работы в конструкторе.
Решение
Конструкторы не могут объявляться с async; кроме того, они не могут содержать ключевое слово await. Конечно, использование await в конструкторе могло бы быть полезным, но это привело бы к существенному изменению языка C#.
Одна из возможностей — использовать конструктор в паре с инициализирующим async-методом, чтобы тип использовался следующим образом:
Вот более качественное решение, которое основано на применении паттерна асинхронного фабричного метода:
Экземпляр может создаваться следующим образом:
К сожалению, в некоторых сценариях этот способ не работает — в частности, когда в коде используется провайдер внедрения зависимостей. Ни одна заметная библиотека внедрения зависимостей или инверсии управления не работает с async-кодом. Если вы окажетесь в одной из таких ситуаций, существует пара альтернатив, которые также стоит рассмотреть.
Если создаваемый экземпляр в действительности является общим ресурсом, можно использовать ленивую инициализацию. В противном случае можно воспользоваться паттерном асинхронной инициализации, который рассмотрим позже.
Пример того, как поступать не следует:
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 11.
Асинхронное Создание Объектов: Фабрики
Задача: вы создаёте тип, который требует выполнения некоторой асинхронной работы в конструкторе.
Решение
Конструкторы не могут объявляться с async; кроме того, они не могут содержать ключевое слово await. Конечно, использование await в конструкторе могло бы быть полезным, но это привело бы к существенному изменению языка C#.
Одна из возможностей — использовать конструктор в паре с инициализирующим async-методом, чтобы тип использовался следующим образом:
var instance = new MyAsyncClass();У такого подхода есть недостатки. Разработчик может забыть вызвать метод
await instance.InitAsync();
InitAsync
, а экземпляр не может использоваться сразу же после выполнения конструктора.Вот более качественное решение, которое основано на применении паттерна асинхронного фабричного метода:
class AsyncClassКонструктор и метод
{
private AsyncClass()
{
}
private async Task<AsyncClass> InitAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1));
return this;
}
public static Task<AsyncClass> CreateAsync()
{
var result = new AsyncClass();
return result.InitAsync();
}
}
InitAsync
объявлены приватными, чтобы они не могли использоваться в вызывающем коде; экземпляры могут создаваться только одним способом — статическим фабричным методом CreateAsync
. Вызывающий код не может обратиться к экземпляру до того, как инициализация будет завершена.Экземпляр может создаваться следующим образом:
var instance = await AsyncClass.CreateAsync();Главное преимущество этого паттерна заключается в том, что вызывающий код никак не сможет получить неинициализированный экземпляр
AsyncClass
.К сожалению, в некоторых сценариях этот способ не работает — в частности, когда в коде используется провайдер внедрения зависимостей. Ни одна заметная библиотека внедрения зависимостей или инверсии управления не работает с async-кодом. Если вы окажетесь в одной из таких ситуаций, существует пара альтернатив, которые также стоит рассмотреть.
Если создаваемый экземпляр в действительности является общим ресурсом, можно использовать ленивую инициализацию. В противном случае можно воспользоваться паттерном асинхронной инициализации, который рассмотрим позже.
Пример того, как поступать не следует:
class AsyncClassНа первый взгляд решение может показаться разумным: вы получаете обычный конструктор, который запускает асинхронную операцию; при этом у него есть ряд недостатков, обусловленных использованием async void. Первая проблема заключается в том, что при завершении конструктора экземпляр всё ещё продолжает асинхронно инициализироваться, и не существует очевидного способа определить, когда завершится асинхронная инициализация. Вторая проблема связана с обработкой ошибок: любые исключения, выданные из InitAsync, не могут быть перехвачены секциями catch, окружающими вызов конструктора объекта.
{
public AsyncClass()
{
InitAsync();
}
// ПЛОХОЙ КОД!!
private async void InitAsync()
{
await Task.Delay(TimeSpan.FromSeconds(1));
}
}
Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 11.
👍12
День 1329. #CodeReview
Допрашиваем Незнакомый Код. Начало
Читаемый код — это хорошо, но не весь код будет читаемым. Популярное утверждение о коде, что его читают в десять раз чаще, чем пишут. Точных цифр нет, но скорее реальное соотношение ближе к 100:1. И чем больше срок службы продукта, тем оно выше. Книги и пособия обычно фокусируются на написании кода, но чтение кода — это отдельный навык.
Новичкам часто кажется, что, если не тратить большую часть времени на добавление нового кода в проект, они не работают продуктивно. На самом деле, первые 80-95% времени должны быть потрачены на чтение кода и других форм документации. Иногда это даже 100%: в процессе изучения кода вы можете узнать, что эта функция уже существует, просто о ней забыли или это принесёт больше вреда, чем пользы.
Рассмотрим наиболее практичные тактики чтения кода и полезные инструменты, которые нужно иметь и сочетать их в зависимости от ситуации.
1. Изучите IDE и установите полезные плагины
Ваша IDE — бесценный инструмент для понимания кода. Однако стоит потратить время, чтобы найти полезные плагины, которые облегчат чтение и понимание кода. Ищите следующие функции:
- Подсветку синтаксиса: ключевые слова, имена классов/методов/полей/переменных,… скобки.
- Автоформатирование
- Статический анализ
- Контекстная навигация: позволит быстро перейти к определению, просмотреть реализации и просмотреть использования класса или метода.
- Рефакторинг: автоматизирует частые рефакторинги, такие как извлечение логики в метод, изменение параметров метода или переименование переменной.
- Подсказки по коду: тип, параметры, документация о классе/методе/поле, при наведении курсора.
- Средство запуска тестов.
- Отладчик.
- Интеграция с системой контроля версий: помимо очевидного, предоставляет информацию об авторе и дате последнего редактирования каждой строки кода.
Вы можете (а иногда, возможно, придётся) читать код без этих инструментов. Но они упрощают проверку ваших предположений и сбор контекста, и вы с большей вероятностью будете принимать правильные решения и меньше гадать.
2. Прочитайте код как минимум дважды
Одного прочтения почти никогда не бывает достаточно, чтобы полностью понять, что делает фрагмент кода. Дважды - это самый минимум.
При первом чтении постарайтесь получить общую картину, просматривая и создавая схему в уме (или на бумаге). Ваша цель — общее представление о том, что делает код. Если под рукой есть резиновая уточка, - самое время поговорить с ней. Объясните общую цель кода. Если какие-то части будет сложно объяснить, это привлечёт к ним внимание.
Второе чтение больше касается деталей. Убедитесь, что вы понимаете каждую строку или хотя бы имеете теорию об этом. Обратите особое внимание на внешние эффекты. Какие методы вызываются? Обновляется ли общее состояние? Какие значения возвращаются? Потратьте время на изучение каждого метода, чтобы понять всю логику, даже если она находится за пределами изучаемого кода. Перейдите к другим методам, посмотрите документацию библиотечных методов, проверьте, что значит каждый фрагмент, вызывающий сомнения. Когда вы закончите, у вас будут теории о возможном поведении, пограничных случаях и условиях отказа в коде. Могут быть части, которые вы не понимаете, но они почти всегда следуют простым правилам, которые можно нагуглить или узнать у товарища по команде.
Третье прочтение полезно, если код содержит сложную логику. Выберите простые значения для любых параметров или переменных и представьте, что они проходят через код сверху вниз. Просчитайте результаты каждой строки.
На самом деле, каждое чтение может включать в себя несколько проходов и несколько походов в Google и на Stack Overflow. Совершенно нормально читать кусок кода десять или более раз, прежде чем вы действительно его поймёте. Может помочь длительный перерыв после первых нескольких прочтений, особенно если вы имеете дело с новыми для вас понятиями.
Продолжение следует…
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
Допрашиваем Незнакомый Код. Начало
Читаемый код — это хорошо, но не весь код будет читаемым. Популярное утверждение о коде, что его читают в десять раз чаще, чем пишут. Точных цифр нет, но скорее реальное соотношение ближе к 100:1. И чем больше срок службы продукта, тем оно выше. Книги и пособия обычно фокусируются на написании кода, но чтение кода — это отдельный навык.
Новичкам часто кажется, что, если не тратить большую часть времени на добавление нового кода в проект, они не работают продуктивно. На самом деле, первые 80-95% времени должны быть потрачены на чтение кода и других форм документации. Иногда это даже 100%: в процессе изучения кода вы можете узнать, что эта функция уже существует, просто о ней забыли или это принесёт больше вреда, чем пользы.
Рассмотрим наиболее практичные тактики чтения кода и полезные инструменты, которые нужно иметь и сочетать их в зависимости от ситуации.
1. Изучите IDE и установите полезные плагины
Ваша IDE — бесценный инструмент для понимания кода. Однако стоит потратить время, чтобы найти полезные плагины, которые облегчат чтение и понимание кода. Ищите следующие функции:
- Подсветку синтаксиса: ключевые слова, имена классов/методов/полей/переменных,… скобки.
- Автоформатирование
- Статический анализ
- Контекстная навигация: позволит быстро перейти к определению, просмотреть реализации и просмотреть использования класса или метода.
- Рефакторинг: автоматизирует частые рефакторинги, такие как извлечение логики в метод, изменение параметров метода или переименование переменной.
- Подсказки по коду: тип, параметры, документация о классе/методе/поле, при наведении курсора.
- Средство запуска тестов.
- Отладчик.
- Интеграция с системой контроля версий: помимо очевидного, предоставляет информацию об авторе и дате последнего редактирования каждой строки кода.
Вы можете (а иногда, возможно, придётся) читать код без этих инструментов. Но они упрощают проверку ваших предположений и сбор контекста, и вы с большей вероятностью будете принимать правильные решения и меньше гадать.
2. Прочитайте код как минимум дважды
Одного прочтения почти никогда не бывает достаточно, чтобы полностью понять, что делает фрагмент кода. Дважды - это самый минимум.
При первом чтении постарайтесь получить общую картину, просматривая и создавая схему в уме (или на бумаге). Ваша цель — общее представление о том, что делает код. Если под рукой есть резиновая уточка, - самое время поговорить с ней. Объясните общую цель кода. Если какие-то части будет сложно объяснить, это привлечёт к ним внимание.
Второе чтение больше касается деталей. Убедитесь, что вы понимаете каждую строку или хотя бы имеете теорию об этом. Обратите особое внимание на внешние эффекты. Какие методы вызываются? Обновляется ли общее состояние? Какие значения возвращаются? Потратьте время на изучение каждого метода, чтобы понять всю логику, даже если она находится за пределами изучаемого кода. Перейдите к другим методам, посмотрите документацию библиотечных методов, проверьте, что значит каждый фрагмент, вызывающий сомнения. Когда вы закончите, у вас будут теории о возможном поведении, пограничных случаях и условиях отказа в коде. Могут быть части, которые вы не понимаете, но они почти всегда следуют простым правилам, которые можно нагуглить или узнать у товарища по команде.
Третье прочтение полезно, если код содержит сложную логику. Выберите простые значения для любых параметров или переменных и представьте, что они проходят через код сверху вниз. Просчитайте результаты каждой строки.
На самом деле, каждое чтение может включать в себя несколько проходов и несколько походов в Google и на Stack Overflow. Совершенно нормально читать кусок кода десять или более раз, прежде чем вы действительно его поймёте. Может помочь длительный перерыв после первых нескольких прочтений, особенно если вы имеете дело с новыми для вас понятиями.
Продолжение следует…
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
👍9
День 1330. #CodeReview
Допрашиваем Незнакомый Код. Продолжение
Начало
3. Рефакторинг имён локальных переменных и методов
Иногда часть кода настолько расплывчата или вводит в заблуждение, что её трудно осмыслить. Один практически безрисковый способ — переименовать локальные переменные и приватные методы, чтобы более точно описать, что они делают. Эти изменения не повлияют ни на что за пределами файла, с которым вы работаете, и не вызовут ошибок, если вы будете осторожны, чтобы избежать конфликтов имен. Если возможно, используйте инструменты рефакторинга IDE, а не поиск и замену текста.
Возможно, стоит внести и другие улучшения (например, предложенные статическим анализатором кода), но даже переименование нескольких плохо названных идентификаторов поможет понять код, не меняя его логики и не задумываясь обо всех его частях одновременно. Сами решайте, фиксировать ли эти изменения. Улучшение читабельности кода будет приносить пользу всей команде снова и снова, даже если оно не добавляет и не изменяет функциональность.
4. Посмотрите, как используется код
Большая часть кода используется другим кодом. Понимание ситуации, в которой код используется, может быть ценным контекстом для выяснения того, что он делает.
В идеале IDE покажет все места, где используется метод. Если такой функции нет, можно попробовать переименовать метод во что-нибудь нелепое. Ошибки компиляции сообщат, где использовался метод. Не забудьте изменить имя обратно. Если ваш язык интерпретируемый, придётся использовать текстовый поиск по имени метода и копаться в результатах.
5. Поищите похожий код
Иногда код трудно понять, даже если все идентификаторы правильно названы и варианты использования знакомы. Иногда для конкретной операции нет идиомы. В худшем случае рассматриваемый код либо уникален для кодовой базы, либо нет очевидной фразы, которую вы могли бы погуглить, чтобы узнать больше.
Хорошая новость в том, что по-настоящему уникальный код встречается редко в долгоживущих кодовых базах, особенно на уровне одного выражения или строки кода. Если вы потратите несколько минут на поиск похожего кода в проекте, вы можете найти что-то, что поможет разгадать загадку.
Полнотекстовый поиск — самая простая версия. Если вы хотите сузить результаты, поищите с помощью регулярного выражения. Также стоит потратить время на изучение некоторых продвинутых методов. Многие программисты предпочитают инструменты командной строки Unix, такие как grep и awk, или, в Windows, рукописные сценарии PowerShell.
Цель в том, чтобы сузить поиск до нескольких файлов, которые, скорее всего, будут отражать изучаемый вами процесс. Это позволит взглянуть на код с другой стороны и, возможно, лучше его понять.
6. Запустите модульные тесты
В идеальном мире тесты — всё, что вам нужно, чтобы понять поведение любого участка кода. Большинство кодовых баз не соответствуют этому идеалу. Тем не менее, рекомендуется проверить наличие тестов, выполняющих код, который вы изучаете. По крайней мере, они будут описывать входные и выходные данные.
Если тестов нет или они недостаточно полны, это вторая возможность внести некоторые положительные изменения. Напишите тест или два, чтобы ответить на вопросы, которые у вас остались о коде. Вы можете зафиксировать их, повысив стабильность кодовой базы и сделав её более самодокументируемой для всех, кто с ней сталкивается. И не нужно беспокоиться о том, что добавление теста как-то нарушит существующую функциональность.
Для написания тестов требуется время, но они гораздо более эффективны, чем прогон кода в воображении. Они являются фактическим доказательством того, что код работает определённым образом. И если вам в итоге потребуется изменить код, тесты дадут вам уверенность, что вы его не сломаете.
Окончание следует …
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
Допрашиваем Незнакомый Код. Продолжение
Начало
3. Рефакторинг имён локальных переменных и методов
Иногда часть кода настолько расплывчата или вводит в заблуждение, что её трудно осмыслить. Один практически безрисковый способ — переименовать локальные переменные и приватные методы, чтобы более точно описать, что они делают. Эти изменения не повлияют ни на что за пределами файла, с которым вы работаете, и не вызовут ошибок, если вы будете осторожны, чтобы избежать конфликтов имен. Если возможно, используйте инструменты рефакторинга IDE, а не поиск и замену текста.
Возможно, стоит внести и другие улучшения (например, предложенные статическим анализатором кода), но даже переименование нескольких плохо названных идентификаторов поможет понять код, не меняя его логики и не задумываясь обо всех его частях одновременно. Сами решайте, фиксировать ли эти изменения. Улучшение читабельности кода будет приносить пользу всей команде снова и снова, даже если оно не добавляет и не изменяет функциональность.
4. Посмотрите, как используется код
Большая часть кода используется другим кодом. Понимание ситуации, в которой код используется, может быть ценным контекстом для выяснения того, что он делает.
В идеале IDE покажет все места, где используется метод. Если такой функции нет, можно попробовать переименовать метод во что-нибудь нелепое. Ошибки компиляции сообщат, где использовался метод. Не забудьте изменить имя обратно. Если ваш язык интерпретируемый, придётся использовать текстовый поиск по имени метода и копаться в результатах.
5. Поищите похожий код
Иногда код трудно понять, даже если все идентификаторы правильно названы и варианты использования знакомы. Иногда для конкретной операции нет идиомы. В худшем случае рассматриваемый код либо уникален для кодовой базы, либо нет очевидной фразы, которую вы могли бы погуглить, чтобы узнать больше.
Хорошая новость в том, что по-настоящему уникальный код встречается редко в долгоживущих кодовых базах, особенно на уровне одного выражения или строки кода. Если вы потратите несколько минут на поиск похожего кода в проекте, вы можете найти что-то, что поможет разгадать загадку.
Полнотекстовый поиск — самая простая версия. Если вы хотите сузить результаты, поищите с помощью регулярного выражения. Также стоит потратить время на изучение некоторых продвинутых методов. Многие программисты предпочитают инструменты командной строки Unix, такие как grep и awk, или, в Windows, рукописные сценарии PowerShell.
Цель в том, чтобы сузить поиск до нескольких файлов, которые, скорее всего, будут отражать изучаемый вами процесс. Это позволит взглянуть на код с другой стороны и, возможно, лучше его понять.
6. Запустите модульные тесты
В идеальном мире тесты — всё, что вам нужно, чтобы понять поведение любого участка кода. Большинство кодовых баз не соответствуют этому идеалу. Тем не менее, рекомендуется проверить наличие тестов, выполняющих код, который вы изучаете. По крайней мере, они будут описывать входные и выходные данные.
Если тестов нет или они недостаточно полны, это вторая возможность внести некоторые положительные изменения. Напишите тест или два, чтобы ответить на вопросы, которые у вас остались о коде. Вы можете зафиксировать их, повысив стабильность кодовой базы и сделав её более самодокументируемой для всех, кто с ней сталкивается. И не нужно беспокоиться о том, что добавление теста как-то нарушит существующую функциональность.
Для написания тестов требуется время, но они гораздо более эффективны, чем прогон кода в воображении. Они являются фактическим доказательством того, что код работает определённым образом. И если вам в итоге потребуется изменить код, тесты дадут вам уверенность, что вы его не сломаете.
Окончание следует …
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
👍3
День 1331. #CodeReview
Допрашиваем Незнакомый Код. Окончание
Начало
Продолжение
7. Используйте отладчик
Выполните код по шагам в отладчике. Если вы знаете, какие действия пользователя запускают код, установите точку останова в начале кода, запустите программу в обычном режиме, взаимодействуя с ее интерфейсом, чтобы запустить код. Это дольше, чем запустить отладку в тесте, но так вы используете более реалистичные данные, которые могут помочь вам заметить такие вещи, как нулевые ссылки и пограничные случаи.
Отладка может быть менее полезной для кода, который выполняется десятки или сотни раз, например, для вложенных циклов. В этом случае вы можете добавить переменные, которые собирают данные на каждой итерации, чтобы просмотреть их позже. Многие IDE также позволяют устанавливать условные точки останова, чтобы можно было приостановить выполнение итерации, отвечающей определенным требованиям.
8. Поиск в базе знаний
Если ваша команда использует базу знаний, такую как Stack Overflow for Teams, Confluence или GitHub-вики, вы уже должны иметь довольно хорошее представление о том, какие термины или понятия можно использовать для поиска соответствующей документации. Имейте в виду, что документация не должна быть вашим единственным источником правды. Она начинает устаревать в момент публикации, и единственное, на что вы можете полностью положиться, чтобы узнать, как ведёт себя часть кода, — это сам код. Тем не менее, даже устаревшая документация может дать достаточно исходной информации и контекста, чтобы помочь вам избежать ошибочных выводов.
Документация может объяснить скорее не «как», а «почему» код работает так, а не иначе. Иногда вы понимаете, что делает фрагмент кода, но что-то в нем кажется неправильным. Прежде чем изменить его, вы должны приложить все усилия, чтобы понять, чем руководствовался первоначальный программист.
9. Используйте аннотацию контроля версий (git blame)
Последний способ собрать контекст — отследить исходного автора, коммит и тикет, связанный с этим кодом.
В любой системе контроля версий есть инструмент, который раскрывает автора и коммит для любой строки кода в кодовой базе. В Git это команда git blame. Так вы сможете найти исходный запрос, который включал код, и возможно, ссылку на исходный тикет, в котором содержится описание функции или ошибки. Возможно, придется просмотреть историю изменений файла, чтобы найти коммит, в котором было сделано нужное изменение.
Так вы сможете найти автора, рецензентов пул-реквеста, всех, кто комментировал тикет или ещё каким-либо образом имел отношение к изменению. Если вы до сих пор не поговорили с коллегами о возникшем у вас затруднении, теперь самое время.
Итого
Контекст и понимание, которые вы получили в ходе этих шагов, вероятно, будут ценны в будущем. Прежде чем двигаться дальше, рассмотрите возможность рефакторинга кода для ясности, создайте новую документацию или даже просто отправьте email с вашими выводами. Каждый раз, когда вы инвестируете в это, вы будете получать дивиденды, поскольку вы и ваша команда будете взаимодействовать с кодом в будущем.
Способность эффективно читать код — это секретное оружие, которое ускорит прохождение вами технического собеседования и сделает вас незаменимым членом любой команды. Программисты, умеющие писать код, ценны, но программисты, умеющие читать код, возможно, ещё более ценны. Когда в продакшене есть ошибка или нужно срочно создать фичу, первым и самым важным шагом является понимание. Умение читать код поможет вам в этом.
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
Допрашиваем Незнакомый Код. Окончание
Начало
Продолжение
7. Используйте отладчик
Выполните код по шагам в отладчике. Если вы знаете, какие действия пользователя запускают код, установите точку останова в начале кода, запустите программу в обычном режиме, взаимодействуя с ее интерфейсом, чтобы запустить код. Это дольше, чем запустить отладку в тесте, но так вы используете более реалистичные данные, которые могут помочь вам заметить такие вещи, как нулевые ссылки и пограничные случаи.
Отладка может быть менее полезной для кода, который выполняется десятки или сотни раз, например, для вложенных циклов. В этом случае вы можете добавить переменные, которые собирают данные на каждой итерации, чтобы просмотреть их позже. Многие IDE также позволяют устанавливать условные точки останова, чтобы можно было приостановить выполнение итерации, отвечающей определенным требованиям.
8. Поиск в базе знаний
Если ваша команда использует базу знаний, такую как Stack Overflow for Teams, Confluence или GitHub-вики, вы уже должны иметь довольно хорошее представление о том, какие термины или понятия можно использовать для поиска соответствующей документации. Имейте в виду, что документация не должна быть вашим единственным источником правды. Она начинает устаревать в момент публикации, и единственное, на что вы можете полностью положиться, чтобы узнать, как ведёт себя часть кода, — это сам код. Тем не менее, даже устаревшая документация может дать достаточно исходной информации и контекста, чтобы помочь вам избежать ошибочных выводов.
Документация может объяснить скорее не «как», а «почему» код работает так, а не иначе. Иногда вы понимаете, что делает фрагмент кода, но что-то в нем кажется неправильным. Прежде чем изменить его, вы должны приложить все усилия, чтобы понять, чем руководствовался первоначальный программист.
9. Используйте аннотацию контроля версий (git blame)
Последний способ собрать контекст — отследить исходного автора, коммит и тикет, связанный с этим кодом.
В любой системе контроля версий есть инструмент, который раскрывает автора и коммит для любой строки кода в кодовой базе. В Git это команда git blame. Так вы сможете найти исходный запрос, который включал код, и возможно, ссылку на исходный тикет, в котором содержится описание функции или ошибки. Возможно, придется просмотреть историю изменений файла, чтобы найти коммит, в котором было сделано нужное изменение.
Так вы сможете найти автора, рецензентов пул-реквеста, всех, кто комментировал тикет или ещё каким-либо образом имел отношение к изменению. Если вы до сих пор не поговорили с коллегами о возникшем у вас затруднении, теперь самое время.
Итого
Контекст и понимание, которые вы получили в ходе этих шагов, вероятно, будут ценны в будущем. Прежде чем двигаться дальше, рассмотрите возможность рефакторинга кода для ясности, создайте новую документацию или даже просто отправьте email с вашими выводами. Каждый раз, когда вы инвестируете в это, вы будете получать дивиденды, поскольку вы и ваша команда будете взаимодействовать с кодом в будущем.
Способность эффективно читать код — это секретное оружие, которое ускорит прохождение вами технического собеседования и сделает вас незаменимым членом любой команды. Программисты, умеющие писать код, ценны, но программисты, умеющие читать код, возможно, ещё более ценны. Когда в продакшене есть ошибка или нужно срочно создать фичу, первым и самым важным шагом является понимание. Умение читать код поможет вам в этом.
Источник: https://stackoverflow.blog/2022/08/15/how-to-interrogate-unfamiliar-code/
👍10
День 1332. #ЗаметкиНаПолях #DDD
Всегда Валидная Модель Домена
Инвариант — это условие, которое всегда должно выполняться. Например, треугольник имеет 3 стороны. Условие
Другое важное свойство инвариантов состоит в том, что они определяют класс предметной области: благодаря им этот класс является тем, чем он является. Следовательно, вы не можете нарушить эти инварианты. Если вы это сделаете, доменный класс просто перестанет быть тем, что вы от него ожидаете, а станет чем-то другим. Например, если вы добавите четвёртую сторону к треугольнику, он станет четырёхугольником.
Наличие инвариантов — это то, что требует введения правил валидации. Без таких инвариантов, как
Таким образом, разница между валидацией и инвариантами — это просто вопрос точки зрения. Одни и те же бизнес-правила рассматриваются как инварианты моделью предметной области и как правила валидации сервисами приложений.
Это различие приводит к различному обращению с нарушениями этих бизнес-правил. Нарушение инварианта в модели предметной области — это исключительная ситуация, и на неё следует генерировать исключение и полностью останавливать текущую операцию (принцип отказоустойчивости).
С другой стороны, нет ничего исключительного в том, что внешний ввод неверен. Для этого и нужны прикладные сервисы: они разделяют (фильтруют) правильные и неправильные запросы. Вы не должны генерировать исключения в таких случаях и вместо этого должны использовать класс Result со статусом операции.
Можно предположить, что разница между валидациями и инвариантами в том, что валидации могут меняться в зависимости от бизнес-правил. Например, треугольник имеет 2 инварианта:
- ровно 3 стороны,
- каждая сторона больше нуля.
Но в нашей модели предметной области есть ещё условие:
- каждая сторона долна быть больше 10 см.
Это правило валидации (в отличие от инвариантов) можно изменить или удалить из нашей модели предметной области.
Действительно, интуитивно эти два условия не кажутся одинаковыми: наличие 3 сторон и требование, чтобы все стороны были больше 10 см. Одно условие необходимо для треугольников, а другое явно нет. Но это только потому, что мы привносим наш реальный опыт в область моделирования предметной области.
Какова цель моделирования предметной области? Максимально приблизиться к физическому миру? Сделать модель максимально реалистичной?
Нет.
Цель в том, чтобы построить модель, полезную для нашей конкретной проблемы. Не для всех возможных областей проблем и определённо не для какой-то сферической проблемы в вакууме. Для нашей конкретной.
Следовательно, если нашему приложению необходимо, чтобы все треугольники имели стороны больше 10 см, если работа с треугольниками меньших размеров не помогает нам достичь наших целей, то эти меньшие треугольники могут просто не существовать для целей нашего приложения. Т.е., если концепция бесполезна для модели, вы вообще не должны включать её в модель.
Да, треугольники со сторонами меньше 10 см могут существовать в других доменах, но в нашем конкретном их нет. Так же, как и четырёхугольники, пятиугольники и другие фигуры (при условии, что наше приложение работает только с треугольниками). Поэтому между этими условиями наличия ровно 3 сторон и всех сторон больше 10 см нет разницы. Оба являются инвариантами, составляющими понятие треугольника в нашем конкретном приложении.
Конечно, требования могут измениться, и условие 10 см может превратиться в 5 или 20 (или даже стать настраиваемым), но это регулярный процесс уточнения, когда вы лучше понимаете домен по мере продвижения проекта. Это не означает, что исходное условие не было инвариантом. Было. Так же, как новое является инвариантом сейчас.
Источник: https://khorikov.org/posts/2022-06-06-validation-vs-invariants/
Всегда Валидная Модель Домена
Инвариант — это условие, которое всегда должно выполняться. Например, треугольник имеет 3 стороны. Условие
edges.Count == 3
по своей сути верно для всех треугольников.Другое важное свойство инвариантов состоит в том, что они определяют класс предметной области: благодаря им этот класс является тем, чем он является. Следовательно, вы не можете нарушить эти инварианты. Если вы это сделаете, доменный класс просто перестанет быть тем, что вы от него ожидаете, а станет чем-то другим. Например, если вы добавите четвёртую сторону к треугольнику, он станет четырёхугольником.
Наличие инвариантов — это то, что требует введения правил валидации. Без таких инвариантов, как
edges.Count == 3
, вам не нужно было бы проверять входные данные от внешних клиентов.Таким образом, разница между валидацией и инвариантами — это просто вопрос точки зрения. Одни и те же бизнес-правила рассматриваются как инварианты моделью предметной области и как правила валидации сервисами приложений.
Это различие приводит к различному обращению с нарушениями этих бизнес-правил. Нарушение инварианта в модели предметной области — это исключительная ситуация, и на неё следует генерировать исключение и полностью останавливать текущую операцию (принцип отказоустойчивости).
С другой стороны, нет ничего исключительного в том, что внешний ввод неверен. Для этого и нужны прикладные сервисы: они разделяют (фильтруют) правильные и неправильные запросы. Вы не должны генерировать исключения в таких случаях и вместо этого должны использовать класс Result со статусом операции.
Можно предположить, что разница между валидациями и инвариантами в том, что валидации могут меняться в зависимости от бизнес-правил. Например, треугольник имеет 2 инварианта:
- ровно 3 стороны,
- каждая сторона больше нуля.
Но в нашей модели предметной области есть ещё условие:
- каждая сторона долна быть больше 10 см.
Это правило валидации (в отличие от инвариантов) можно изменить или удалить из нашей модели предметной области.
Действительно, интуитивно эти два условия не кажутся одинаковыми: наличие 3 сторон и требование, чтобы все стороны были больше 10 см. Одно условие необходимо для треугольников, а другое явно нет. Но это только потому, что мы привносим наш реальный опыт в область моделирования предметной области.
Какова цель моделирования предметной области? Максимально приблизиться к физическому миру? Сделать модель максимально реалистичной?
Нет.
Цель в том, чтобы построить модель, полезную для нашей конкретной проблемы. Не для всех возможных областей проблем и определённо не для какой-то сферической проблемы в вакууме. Для нашей конкретной.
Следовательно, если нашему приложению необходимо, чтобы все треугольники имели стороны больше 10 см, если работа с треугольниками меньших размеров не помогает нам достичь наших целей, то эти меньшие треугольники могут просто не существовать для целей нашего приложения. Т.е., если концепция бесполезна для модели, вы вообще не должны включать её в модель.
Да, треугольники со сторонами меньше 10 см могут существовать в других доменах, но в нашем конкретном их нет. Так же, как и четырёхугольники, пятиугольники и другие фигуры (при условии, что наше приложение работает только с треугольниками). Поэтому между этими условиями наличия ровно 3 сторон и всех сторон больше 10 см нет разницы. Оба являются инвариантами, составляющими понятие треугольника в нашем конкретном приложении.
Конечно, требования могут измениться, и условие 10 см может превратиться в 5 или 20 (или даже стать настраиваемым), но это регулярный процесс уточнения, когда вы лучше понимаете домен по мере продвижения проекта. Это не означает, что исходное условие не было инвариантом. Было. Так же, как новое является инвариантом сейчас.
Источник: https://khorikov.org/posts/2022-06-06-validation-vs-invariants/
👍9
This media is not supported in your browser
VIEW IN TELEGRAM
День 1333. #ЧтоНовенького
Улучшения Табличного Визуализатора Данных в VS 2022
Табличный визуализатор данных (DataTable visualizer) появился в версии 17.3 preview 3 для IEnumerable, а начиная с версии 17.4 preview 2 позволяет также просматривать содержимое объектов DataTable, DataSet, DataView или DataViewManager. Вызывается он по щелчку на увеличительное стекло в отладчике (см. видео).
Поддерживается
- Фильтрация данных по строке фильтра.
- Сортировка по возрастанию или убыванию.
- Экспорт данных в формат Excel (xlsx) или CSV. Также работает с отсортированным и отфильтрованным представлением.
- Тема основного окна Visual Studio.
Источник: https://devblogs.microsoft.com/visualstudio/datatable-visualizer-improvements/
Улучшения Табличного Визуализатора Данных в VS 2022
Табличный визуализатор данных (DataTable visualizer) появился в версии 17.3 preview 3 для IEnumerable, а начиная с версии 17.4 preview 2 позволяет также просматривать содержимое объектов DataTable, DataSet, DataView или DataViewManager. Вызывается он по щелчку на увеличительное стекло в отладчике (см. видео).
Поддерживается
- Фильтрация данных по строке фильтра.
- Сортировка по возрастанию или убыванию.
- Экспорт данных в формат Excel (xlsx) или CSV. Также работает с отсортированным и отфильтрованным представлением.
- Тема основного окна Visual Studio.
Источник: https://devblogs.microsoft.com/visualstudio/datatable-visualizer-improvements/
День 1334. #ЧтоНовенького
Атрибут StringSyntax
Visual Studio ещё с версии 2019 поддерживала подсветку синтаксиса в регулярных выражениях или подсказки при форматировании даты. Исторически это был жёстко закодированный список методов, где было известно, что строковые аргументы в действительности будут регулярными выражениями или форматом даты. Однако это решение не масштабировалось. Существует много API, принимающих строки, которые должны соответствовать определенному синтаксису, например, JSON, XML, формат даты, Guid и т.п.
В .NET 7 представлен новый атрибут
Строковые параметры, свойства и поля во всех основных библиотеках .NET теперь помечены атрибутами, чтобы обозначить, являются ли они регулярными выражениями, JSON, XML, строками составного формата, URL, строками числового формата и так далее.
Подробнее об этом в недавнем видео от Ника Чапсаса https://youtu.be/Y2YOaqSAJAQ
Источник: https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#stringsyntaxattribute-regex
Атрибут StringSyntax
Visual Studio ещё с версии 2019 поддерживала подсветку синтаксиса в регулярных выражениях или подсказки при форматировании даты. Исторически это был жёстко закодированный список методов, где было известно, что строковые аргументы в действительности будут регулярными выражениями или форматом даты. Однако это решение не масштабировалось. Существует много API, принимающих строки, которые должны соответствовать определенному синтаксису, например, JSON, XML, формат даты, Guid и т.п.
В .NET 7 представлен новый атрибут
StringSyntax
, который используется в .NET 7 для более чем 350 параметров типа string
, string[]
и ReadOnlySpan<char>
, свойств и полей, чтобы обозначить для клиента, какой синтаксис ожидается для передачи или установки. Теперь любой метод, который хочет указать, что строковый параметр, принимает регулярное выражение, добавить атрибут на параметр:void MyMethod(Visual Studio 2022 обеспечит ту же проверку синтаксиса, подсветку синтаксиса и IntelliSense, что и для всех других методов, связанных с Regex.
[StringSyntax(StringSyntaxAttribute.Regex)]
string input)
Строковые параметры, свойства и поля во всех основных библиотеках .NET теперь помечены атрибутами, чтобы обозначить, являются ли они регулярными выражениями, JSON, XML, строками составного формата, URL, строками числового формата и так далее.
Подробнее об этом в недавнем видео от Ника Чапсаса https://youtu.be/Y2YOaqSAJAQ
Источник: https://devblogs.microsoft.com/dotnet/regular-expression-improvements-in-dotnet-7/#stringsyntaxattribute-regex
👍8
День 1335. #ЗаметкиНаПолях
Разработка API для Людей.
Часть 1. Идентификаторы Объектов
Про выбор идентификатора между целым числом и GUID, я уже писал ранее. Сегодня посмотрим, как делать ID более удобочитаемыми для людей.
Вот, например, ID в платёжной системе Stripe:
Полиморфный поиск
При создании
Это сработало бы, но усложняет API без дополнительной выгоды. Вместо того, чтобы иметь
Предотвращение человеческой ошибки
Есть и другие менее очевидные преимущества, одно из которых — простота работы с идентификаторами, когда вы можете определить их тип по первым нескольким символам. Например, на сервере Stripe Discord используется функция Discord AutoMod, чтобы автоматически помечать и блокировать сообщения, содержащие живой секретный ключ API Stripe, который начинается с
Говоря о ключах API, префиксы live и test — это встроенный уровень защиты, который защищает вас от их смешивания. Те, кто особенно заботится о безопасности, могут настроить проверки, чтобы убедиться, что вы используете ключ только для соответствующей среды:
Разработка API для Людей.
Часть 1. Идентификаторы Объектов
Про выбор идентификатора между целым числом и GUID, я уже писал ранее. Сегодня посмотрим, как делать ID более удобочитаемыми для людей.
Вот, например, ID в платёжной системе Stripe:
pi_3LKQhvGUcADgqoEM3bh6pslEЭтот формат более понятен для человека:
pi_3LKQhvGUcADgqoEM3bh6pslEНичего не зная об идентификаторе, мы можем сразу же понять, что здесь мы говорим об объекте PaymentIntent, благодаря префиксу
└─┘└──────────────────────┘
└─ Префикс └─ Случайные символы
pi_
. Когда вы создаёте PaymentIntent через API, вы фактически создаёте или ссылаетесь на несколько других объектов, включая Customer (cus_
), PaymentMethod (pm_
) и Charge (ch_
). С помощью префиксов вы можете сразу различить все эти разные объекты:var pi =Это помогает сотрудникам Stripe так же, как и разработчикам, интегрирующимся со Stripe. Например, вот фрагмент кода, который нужно отладить:
Stripe.PaymentIntents.Create(@"{
Amount = 1000,
Currency = 'usd',
Customer = 'cus_MJA953cFzEuO1z',
PaymentMethod = 'pm_1LaXpKGUcADgqo'
}");
var pi =Код пытается получить
Stripe.PaymentIntents.Retrieve(
id: id,
stripeAccount: "cus_1KrJdMGUcADgqoEM"
);
PaymentIntent
из подключённой учетной записи, однако, даже не глядя на код, вы можете сразу заметить ошибку: вместо идентификатора учетной записи (acct_
) используется идентификатор клиента (cus_
). Без префиксов это было бы намного сложнее отлаживать.Полиморфный поиск
При создании
PaymentIntent
вы можете дополнительно указать параметр paymentMethod
, чтобы указать, какой тип платежного инструмента вы хотите использовать. Вы можете указать здесь идентификатор источника (src_
) или карты (card_
) вместо идентификатора PaymentMethod (pm_
):var pi =Без префиксов не было бы возможности узнать, какой объект представляет идентификатор, т.е. мы не знаем, из какой таблицы запрашивать данные объекта. Одним из способов может быть требование дополнительного параметра типа.
Stripe.PaymentIntents.Create(@"{
Amount = 1000,
Currency = 'usd',
Customer = 'cus_MJA953cFzEuO1z',
// Здесь может быть
// PaymentMethod, Card или Source ID
PaymentMethod = 'card_1LaRQ7GUcA'
}");
Это сработало бы, но усложняет API без дополнительной выгоды. Вместо того, чтобы иметь
PaymentMethod
в виде простой строки, теперь это хэш идентификатора. Всякий раз, когда вы используете идентификатор, вам нужно знать, какой тип объекта он представляет, что делает объединение этих двух типов информации в одном источнике гораздо лучшим решением, чем требование дополнительных параметров типа.Предотвращение человеческой ошибки
Есть и другие менее очевидные преимущества, одно из которых — простота работы с идентификаторами, когда вы можете определить их тип по первым нескольким символам. Например, на сервере Stripe Discord используется функция Discord AutoMod, чтобы автоматически помечать и блокировать сообщения, содержащие живой секретный ключ API Stripe, который начинается с
sk_live_
. Утечка такого конфиденциального ключа может иметь серьёзные последствия для бизнеса. Поскольку ключи начинаются с sk_live_
, написать регулярное выражение для фильтрации случайных утечек несложно.Говоря о ключах API, префиксы live и test — это встроенный уровень защиты, который защищает вас от их смешивания. Те, кто особенно заботится о безопасности, могут настроить проверки, чтобы убедиться, что вы используете ключ только для соответствующей среды:
if (!app.Environment.IsDevelopment())Источник: https://dev.to/stripe/designing-apis-for-humans-object-ids-3o5a
{
if (Regex.IsMatch("sk_live", "<API_KEY>"))
throw new Exception("Live key detected! Aborting!");
}
👍6
День 1336. #ЗаметкиНаПолях #DesignPrinciples
OCP Против YAGNI. Начало
В этой серии постов рассмотрим противоречия между принципом Open/Closed и принципом «Вам это не понадобится».
OCP
Принцип Open/Closed гласит, что:
«Программные сущности (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации.»
В настоящее время существует две интерпретации этого определения:
1. Дядюшка Боб Мартин говорит о предотвращении волновых эффектов. Когда вы изменяете часть кода, вам не нужно вносить изменения во всю базу кода, чтобы приспособиться к этой модификации. В идеале вы должны иметь возможность добавлять новые функции, ничего не меняя в существующем коде.
Обычно это реализуется с помощью полиморфизма. Например, следующий пример нарушает версию OCP Мартина:
2. Бертран Мейер же говорит об обратной совместимости.
Когда есть несколько взаимозависимых модулей, вы не можете просто изменить свой модуль, когда хотите, вам нужно учитывать его клиентов.
Например, для библиотеки с открытым методом
Ещё один важный момент: версия OCP Мейера имеет смысл только в контексте нескольких команд разработчиков, когда каждый модуль разрабатывается разными командами. Если вы являетесь и автором, и «клиентом» кода, нет необходимости придерживаться таких сложных схем.
Итак, две разновидности OCP, несмотря на то что имеют одно и то же имя, различаются по основному назначению. Код со switch, приведённый ранее, нарушает интерпретацию OCP Мартина, но не противоречит интерпретации Мейера. Интерпретация Мартина шире. Она направлена на сокращение количества изменений в целом, возможность расширить поведение ПО с небольшим изменением исходного кода или без него. Интерпретация Мейера направлена только на сокращение критических изменений: изменений, которые могут вызвать проблемы при совместной работе нескольких команд.
Продолжение следует…
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
OCP Против YAGNI. Начало
В этой серии постов рассмотрим противоречия между принципом Open/Closed и принципом «Вам это не понадобится».
OCP
Принцип Open/Closed гласит, что:
«Программные сущности (классы, модули, функции и т. д.) должны быть открыты для расширения, но закрыты для модификации.»
В настоящее время существует две интерпретации этого определения:
1. Дядюшка Боб Мартин говорит о предотвращении волновых эффектов. Когда вы изменяете часть кода, вам не нужно вносить изменения во всю базу кода, чтобы приспособиться к этой модификации. В идеале вы должны иметь возможность добавлять новые функции, ничего не меняя в существующем коде.
Обычно это реализуется с помощью полиморфизма. Например, следующий пример нарушает версию OCP Мартина:
public void Draw(Shape shape)Здесь, чтобы ввести новую форму, вам нужно будет изменить метод
{
switch (shape.Type)
{
case ShapeType.Circle:
DrawCircle(shape);
break;
case ShapeType.Square:
DrawSquare(shape);
break;
default:
throw new
ArgumentOutOfRangeException();
}
}
Draw
. Чтобы исправить это, вы можете создать абстрактный класс Shape
, а затем перенести логику рисования в подклассы:public abstract class ShapeТеперь, если нужно добавить новую фигуру, вы просто создаете подкласс и переопределяете метод Draw. Так вы закрыли класс Shape и открыли точку расширения в нём.
{
public abstract void Draw();
}
public class Circle : Shape
{
public override void Draw()
{ … }
}
2. Бертран Мейер же говорит об обратной совместимости.
Когда есть несколько взаимозависимых модулей, вы не можете просто изменить свой модуль, когда хотите, вам нужно учитывать его клиентов.
Например, для библиотеки с открытым методом
CreateCustomer(string email)вы не можете просто добавить новый обязательный параметр:
CreateCustomer(string email, string accountNumber)Это будет критическим изменением для клиентского кода, который уже привязан к исходной версии метода. Это можно делать во время разработки, но не после публикации. Если нужно внести изменение после публикации, вы создаёте новый модуль (версию модуля). Однако вы по-прежнему можете изменять реализацию, если она не меняет API. Вся тема управления версиями веб-API — это, по сути, принцип OCP Мейера.
Ещё один важный момент: версия OCP Мейера имеет смысл только в контексте нескольких команд разработчиков, когда каждый модуль разрабатывается разными командами. Если вы являетесь и автором, и «клиентом» кода, нет необходимости придерживаться таких сложных схем.
Итак, две разновидности OCP, несмотря на то что имеют одно и то же имя, различаются по основному назначению. Код со switch, приведённый ранее, нарушает интерпретацию OCP Мартина, но не противоречит интерпретации Мейера. Интерпретация Мартина шире. Она направлена на сокращение количества изменений в целом, возможность расширить поведение ПО с небольшим изменением исходного кода или без него. Интерпретация Мейера направлена только на сокращение критических изменений: изменений, которые могут вызвать проблемы при совместной работе нескольких команд.
Продолжение следует…
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
👍19
День 1337. #ЗаметкиНаПолях #DesignPrinciples
OCP Против YAGNI. Продолжение
Начало
YAGNI
“You ain’t gonna need it” (Вам это не понадобится) означает, что вы не должны тратить время на функциональность, которая сейчас не нужна. Вам не следует разрабатывать эту функциональность, а также изменять существующий код с учетом её появления в будущем. Два основных момента, которые объясняют, почему это хорошая идея:
1. Требования бизнеса постоянно меняются. Если вы тратите время на функцию, которая не нужна бизнес-людям в данный конкретный момент, вы крадёте время у тех функций, которые им нужны прямо сейчас. Более того, когда им наконец-то понадобится разработанный функционал, их взгляд на него, скорее всего, изменится, и вам всё равно придётся вносить в него коррективы. Такая деятельность расточительна и приводит к чистым убыткам, поскольку было бы выгоднее просто реализовать функцию с нуля, когда в ней возникнет реальная потребность.
2. Ваш код — это не актив, а пассив. Предпочтительно иметь меньше кода, а не больше, так как любой дополнительный код увеличивает стоимость обслуживания. Внедрение кода «на всякий случай», без непосредственной необходимости, увеличивает общую стоимость владения всей кодовой базой. Помните, что вам нужно будет провести рефакторинг этой дополнительной части, уберечь её от ошибок, покрыть тестами и так далее. Желательно отложить внедрение нового функционала на как можно более поздний этап вашего проекта.
Бывают ситуации, когда YAGNI неприменим.
Например, вы проектируете функциональность, которую трудно изменить в будущем. Это ориентированные на клиента API, сторонние библиотеки, фундаментальные архитектурные решения, пользовательские интерфейсы (их может быть трудно изменить, поскольку пользователи неохотно принимают новый внешний вид). В таких ситуациях стоит потратить некоторое время, чтобы попытаться предсказать, как будущие функции будут сочетаться с решениями, которые вы принимаете сейчас. Например, заранее продумать систему управления версиями веб-API, потому что после публикации API изменить её будет невозможно. Аналогично, публичный метод или класс в общедоступной библиотеке должен оставаться там для обратной совместимости, даже если вы решите, что он больше не нужен. Менять такие вещи сложно.
Другими словами, если решение, которое вы собираетесь принять, станет святой заповедью, YAGNI не применяется. В этом случае вам необходимо учитывать возможные будущие потребности.
Однако желательно принимать как можно меньше таких решений. По крайней мере, постарайтесь отложить их на более поздний этап. Таким образом, вы сможете собрать больше информации о реальных потребностях бизнеса. Кроме того, имейте в виду, что большинство решений, которые вы принимаете, не относятся к потребностям бизнеса, и их можно довольно легко изменить. YAGNI применим к большей части кода, который мы пишем изо дня в день.
Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
OCP Против YAGNI. Продолжение
Начало
YAGNI
“You ain’t gonna need it” (Вам это не понадобится) означает, что вы не должны тратить время на функциональность, которая сейчас не нужна. Вам не следует разрабатывать эту функциональность, а также изменять существующий код с учетом её появления в будущем. Два основных момента, которые объясняют, почему это хорошая идея:
1. Требования бизнеса постоянно меняются. Если вы тратите время на функцию, которая не нужна бизнес-людям в данный конкретный момент, вы крадёте время у тех функций, которые им нужны прямо сейчас. Более того, когда им наконец-то понадобится разработанный функционал, их взгляд на него, скорее всего, изменится, и вам всё равно придётся вносить в него коррективы. Такая деятельность расточительна и приводит к чистым убыткам, поскольку было бы выгоднее просто реализовать функцию с нуля, когда в ней возникнет реальная потребность.
2. Ваш код — это не актив, а пассив. Предпочтительно иметь меньше кода, а не больше, так как любой дополнительный код увеличивает стоимость обслуживания. Внедрение кода «на всякий случай», без непосредственной необходимости, увеличивает общую стоимость владения всей кодовой базой. Помните, что вам нужно будет провести рефакторинг этой дополнительной части, уберечь её от ошибок, покрыть тестами и так далее. Желательно отложить внедрение нового функционала на как можно более поздний этап вашего проекта.
Бывают ситуации, когда YAGNI неприменим.
Например, вы проектируете функциональность, которую трудно изменить в будущем. Это ориентированные на клиента API, сторонние библиотеки, фундаментальные архитектурные решения, пользовательские интерфейсы (их может быть трудно изменить, поскольку пользователи неохотно принимают новый внешний вид). В таких ситуациях стоит потратить некоторое время, чтобы попытаться предсказать, как будущие функции будут сочетаться с решениями, которые вы принимаете сейчас. Например, заранее продумать систему управления версиями веб-API, потому что после публикации API изменить её будет невозможно. Аналогично, публичный метод или класс в общедоступной библиотеке должен оставаться там для обратной совместимости, даже если вы решите, что он больше не нужен. Менять такие вещи сложно.
Другими словами, если решение, которое вы собираетесь принять, станет святой заповедью, YAGNI не применяется. В этом случае вам необходимо учитывать возможные будущие потребности.
Однако желательно принимать как можно меньше таких решений. По крайней мере, постарайтесь отложить их на более поздний этап. Таким образом, вы сможете собрать больше информации о реальных потребностях бизнеса. Кроме того, имейте в виду, что большинство решений, которые вы принимаете, не относятся к потребностям бизнеса, и их можно довольно легко изменить. YAGNI применим к большей части кода, который мы пишем изо дня в день.
Окончание следует…
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
👍10
День 1338. #ЗаметкиНаПолях #DesignPrinciples
OCP Против YAGNI. Окончание
Начало
Продолжение
Обратите внимание, что YAGNI не только про добавление неиспользуемых функций «на будущее», но и про запрет изменения существующих функций для учёта возможных изменений в будущем. И в этом заключается противоречие. Этот «учёт возможных изменений в будущем» — именно то, что предлагает версия OCP Боба Мартина.
Вернёмся к коду метода Draw, использующего switch, из первой части. С одной стороны, у нас есть YAGNI, который говорит, что с этим оператором switch всё в порядке, если полученный код прост, его легко понять и поддерживать. С другой стороны, у нас есть OCP Боба Мартина, в котором говорится, что нам нужно иметь возможность расширять его без изменения имеющегося кода, то есть без изменения самого оператора switch.
Что выбрать?
Обратите внимание, что мы говорим о противоречии между YAGNI и версии OCP Боба Мартина, а не о версии Бертрана Мейера. Это потому, что YAGNI не противоречит последней, они в принципе говорят о разных вещах.
Что касается версии Боба Мартина, то её можно рассматривать с двух разных точек зрения.
1. Когда вы являетесь и автором, и «клиентом» кода, который пишете, YAGNI имеет приоритет над OCP. Потому что YAGNI, наряду с KISS, является самым важным принципом в разработке ПО. Следование ему должно быть первоочередной задачей любого программного проекта. Зачем преждевременно закладывать точки расширения в свой код, если это приведет к чрезмерному усложнению? Действительно ли рефакторинг switch в иерархию классов стоит усилий и дополнительных затрат на обслуживание? Конечно нет. Гораздо лучше закладывать точки расширения постфактум, когда уже есть полная картина и когда вы видите, что оператор switch стал слишком раздутым. В этом случае вы можете отрефакторить код и извлечь иерархию классов. Но не раньше, чем потребность в этом станет очевидной.
2. Когда нужно опубликовать свой код для внешнего использования.
В данном случае YAGNI неприменим, поскольку стоимость изменения уже реализованного функционала слишком высока. Вы не можете просто отрефакторить свой код, потому что вы не единственный его потребитель. В такой ситуации вам необходимо определить потенциальные точки вариаций и создать вокруг них интерфейс, который позволит потребителям расширять ваши классы, а не изменять их. В примере с методом Draw, если он открыт для клиентов, и вы хотите предоставить средства для его расширения, лучше заранее реализовать его в базовом классе Shape и позволить вашим потребителям создавать собственные формы.
Версия OCP Боба Мартина имеет гораздо больше смысла, если поместить её в контекст точки зрения Бертрана Мейера. Точки расширения стоит закладывать только тогда, когда вам придётся публиковать свой код для внешнего использования в том или ином виде. В любом другом случае придерживайтесь YAGNI и не вводите дополнительную гибкость без реальной необходимости.
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
OCP Против YAGNI. Окончание
Начало
Продолжение
Обратите внимание, что YAGNI не только про добавление неиспользуемых функций «на будущее», но и про запрет изменения существующих функций для учёта возможных изменений в будущем. И в этом заключается противоречие. Этот «учёт возможных изменений в будущем» — именно то, что предлагает версия OCP Боба Мартина.
Вернёмся к коду метода Draw, использующего switch, из первой части. С одной стороны, у нас есть YAGNI, который говорит, что с этим оператором switch всё в порядке, если полученный код прост, его легко понять и поддерживать. С другой стороны, у нас есть OCP Боба Мартина, в котором говорится, что нам нужно иметь возможность расширять его без изменения имеющегося кода, то есть без изменения самого оператора switch.
Что выбрать?
Обратите внимание, что мы говорим о противоречии между YAGNI и версии OCP Боба Мартина, а не о версии Бертрана Мейера. Это потому, что YAGNI не противоречит последней, они в принципе говорят о разных вещах.
Что касается версии Боба Мартина, то её можно рассматривать с двух разных точек зрения.
1. Когда вы являетесь и автором, и «клиентом» кода, который пишете, YAGNI имеет приоритет над OCP. Потому что YAGNI, наряду с KISS, является самым важным принципом в разработке ПО. Следование ему должно быть первоочередной задачей любого программного проекта. Зачем преждевременно закладывать точки расширения в свой код, если это приведет к чрезмерному усложнению? Действительно ли рефакторинг switch в иерархию классов стоит усилий и дополнительных затрат на обслуживание? Конечно нет. Гораздо лучше закладывать точки расширения постфактум, когда уже есть полная картина и когда вы видите, что оператор switch стал слишком раздутым. В этом случае вы можете отрефакторить код и извлечь иерархию классов. Но не раньше, чем потребность в этом станет очевидной.
2. Когда нужно опубликовать свой код для внешнего использования.
В данном случае YAGNI неприменим, поскольку стоимость изменения уже реализованного функционала слишком высока. Вы не можете просто отрефакторить свой код, потому что вы не единственный его потребитель. В такой ситуации вам необходимо определить потенциальные точки вариаций и создать вокруг них интерфейс, который позволит потребителям расширять ваши классы, а не изменять их. В примере с методом Draw, если он открыт для клиентов, и вы хотите предоставить средства для его расширения, лучше заранее реализовать его в базовом классе Shape и позволить вашим потребителям создавать собственные формы.
Версия OCP Боба Мартина имеет гораздо больше смысла, если поместить её в контекст точки зрения Бертрана Мейера. Точки расширения стоит закладывать только тогда, когда вам придётся публиковать свой код для внешнего использования в том или ином виде. В любом другом случае придерживайтесь YAGNI и не вводите дополнительную гибкость без реальной необходимости.
Источник: https://enterprisecraftsmanship.com/posts/ocp-vs-yagni/
👍13
День 1339. #ЗаметкиНаПолях
Пустые Переменные в Лямбдах
В твиттере задали интересный вопрос:
Имеет ли смысл использование пустой переменной (дискарда) `_` в выражении типа?
— Layla #WomenOfDotNet (@LaylaCodesIt)
Короткий ответ: да. Но кому нужны простые ответы? Пустые переменные появились в C# недавно. А это значит, что не всё так просто, как кажется.
В C# есть несколько мест, где мы используем
Зачем это нужно?
Иногда мы вынуждены принимать аргументы, которые не будем использовать. Неиспользуемые параметры выглядят так, как будто это может быть ошибкой:
Поэтому принято соглашение об использовании
Использование
Всё становится ещё интереснее, когда
Источник: https://endjin.com/blog/2022/09/csharp-lambda-discards
Пустые Переменные в Лямбдах
В твиттере задали интересный вопрос:
Имеет ли смысл использование пустой переменной (дискарда) `_` в выражении типа?
( _ , args) =>{…}Я ожидаю параметр, но не буду с ним ничего делать.
— Layla #WomenOfDotNet (@LaylaCodesIt)
Короткий ответ: да. Но кому нужны простые ответы? Пустые переменные появились в C# недавно. А это значит, что не всё так просто, как кажется.
В C# есть несколько мест, где мы используем
_
как пустую переменную. В примере ниже _
технически не является ей:Func<int, int, int> f = (_, x) => 2 * x;Лямбда здесь имеет два параметра, первый называется
_
, а второй называется x. C# принимает _
в качестве идентификатора в соответствии с правилами языка. Даже Visual Studio при наведении курсора на _
показывает подсказку «(parameter) int _». Мы можем продемонстрировать это, используя оба параметра:Func<int, int, int> f2 = (_, x) => _ * x;Следующий код не работал в C#8, но C#9 позволяет так писать:
Func<int, int, int> f3 = (_, _) => 42;Здесь символы подчеркивания действительно являются пустыми переменными. (Правило состоит в том, что если лямбда имеет несколько параметров с именем
_
, то все они отбрасываются). A Visual Studio при наведении курсора на _ показывает подсказку «(discard) int _». Однако это работает только для лямбда-выражений.Зачем это нужно?
Иногда мы вынуждены принимать аргументы, которые не будем использовать. Неиспользуемые параметры выглядят так, как будто это может быть ошибкой:
void ShowNumber(int i)Анализатор кода не выдаёт даже предупреждения, а выдаёт только сообщение IDE0060 уровня Message о неиспользуемой переменной. Однако читателю этого кода неочевидно, есть ли ошибка в коде метода или так и задумано. При этом, если вы фанат чистых сборок — без предупреждений и сообщений анализатора, — тогда изменения кода, приводящие к появлению новых сообщений, немедленно привлекут ваше внимание.
{
Console.WriteLine(42);
}
Поэтому принято соглашение об использовании
_
в качестве имени параметра, который бы намеренно игнорировался. Если вы измените предыдущий пример, переименовав параметр i
в _
, вы увидите, что компилятор перестанет выдавать сообщение IDE0060, поскольку он знает об этом соглашении:void ShowNumber(int _)Но, если у вас есть два параметра, которые вы хотите игнорировать:
void ShowNumber(int _, int _)это вызовет ошибку компиляции CS0100 из-за дублирующего имени параметра
_
, т.к. пустые переменные можно использовать только в лямбдах.Использование
_
- это просто соглашение. Это валидное имя для параметра, поэтому у нас не может быть двух параметров с именами _
по той же причине, по которой мы не можем иметь два параметра с именем i
.Всё становится ещё интереснее, когда
_
используется в качестве имени локальной переменной. Например, что, по-вашему, выведет код с картинки ниже в C#9+?Источник: https://endjin.com/blog/2022/09/csharp-lambda-discards
👍5
Что выведет код с картинки выше?
Anonymous Quiz
24%
Ошибку в строке 2
41%
Ошибку в строке 3
11%
23
2%
29
7%
63
15%
69
👍3