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

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 2230. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 43. Решая вопрос о качестве ПО, вы выбираете: платить немало сейчас или позже, но ещё больше


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

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

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

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍8
Какой перевод слова production (environment) на русский язык вы считаете наиболее удачным (понятным)?
Anonymous Poll
17%
Производственная
7%
Продуктивная
13%
Продуктовая
50%
Продакшен
11%
Рабочая
2%
Другой (напишите в комментариях)
День 2231. #Безопасность
Атрибуты Безопасности Файлов Cookie

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

Существует 3 распространённых атаки с использованием cookie:
1. Атаки с использованием межсайтового скриптинга (XSS) и атаки типа «человек посередине» (MITM) часто используются для кражи файлов cookie.
2. Атаки с использованием межсайтовой подделки запросов (CSRF) используют способ обработки файлов cookie браузерами для выполнения вредоносных действий от имени аутентифицированных пользователей.

Спецификация протокола HTTP содержит несколько механизмов, которые разработчики могут использовать для снижения риска доступа злоумышленников к содержимому cookie с конфиденциальными данными, их повторного использования или подделки. Ниже перечислены атрибуты заголовка HTTP Set-Cookie, которые можно использовать для повышения безопасности файлов cookie.

1. Expire и Max-Age
Определяют срок действия cookie. Expire устанавливает абсолютную дату/время истечения срока действия (формат: weekday, DD-MM-YYYY hh:mm:ss GMT), а атрибут Max-Age - ограничение по времени с момента установки cookie. Если Expire и Max-Age не установлены, браузер обрабатывает cookie как сеансовый и удаляет его при закрытии браузера. Если установлены, сохраняет cookie как постоянный на стороне клиента и удаляет в соответствии со значениями Expire и Max-Age (в зависимости от того, что наступит раньше).

2. Secure
Указывает, что cookie может передаваться только с использованием HTTPS-соединений и никогда не отправляется в открытом виде. Браузер не будет отправлять Secure cookie с запросами HTTP.
Атрибут Secure предназначен для защиты от атак типа «человек посередине» (MITM). Однако он защищает только конфиденциальность файла cookie, а не его целостность. Злоумышленник не получит cookie с сервера через незашифрованное соединение, но всё равно может отправить поддельный cookie на сервер в виде обычного текста.

3. Domain
Объявляет домен, на который будет отправлен cookie (а также все поддомены). Если атрибут Domain не установлен, cookie будет отправлен только на исходный хост (без поддоменов). Поэтому наиболее безопасный способ — не устанавливать атрибут Domain, если это не необходимо.

4. Path
URL-путь, по которому будет отправлен cookie (включая все подпути). По умолчанию - / (все URL-пути на сервере).

5. HttpOnly
Введён для предотвращения атак XSS. Браузер будет отправлять cookie с этим атрибутом только в ответ на HTTP-запросы, т.е. к ним нельзя будет получить доступ из клиентского кода JavaScript. Однако атрибут HttpOnly не защищает cookie от перезаписи. Браузер может хранить только ограниченное количество файлов cookie для домена. Злоумышленник может использовать атаку переполнения хранилища cookie, тем самым удаляя исходный cookie из памяти браузера и добавляя cookie с тем же именем без атрибута HttpOnly.

6. SameSite
Предписывает веб-браузерам отправлять cookie по-разному в зависимости от того, как посетитель взаимодействует с сайтом, установившим cookie. Используется для защиты от атак CSRF. Может иметь одно из следующих значений:
- SameSite=Strict: cookie отправляется только, если вы в данный момент находитесь на сайте, который установил cookie. Если вы переходите с другого сайта (например, из результатов поиска в Google), такой cookie не отправляется с первым запросом.
- SameSite=Lax: файл куки отправляется с GET-запросами верхнего уровня, но не отправляется для встроенного контента (рисунки, CSS, JS).
- SameSite=None: ограничений нет.
Внимание: если атрибут SameSite не установлен, можно ожидать разного поведения браузеров и разных версий одного браузера.

См. также Cookie и Управление Сессиями

Источник: https://www.invicti.com/learn/cookie-security-flags/
👍16
День 2232. #ЧтоНовенького
Новые Функции Отладки в Visual Studio 17.13

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

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

2. Улучшенные редактируемые выражения в визуализаторе IEnumerable
Визуализатор IEnumerable теперь имеет встроенный чат GitHub Copilot, позволяющий уточнять редактируемые выражения с помощью естественного языка. Нажмите на кнопку Continue in Chat (Продолжить в Чате), сообщите Copilot, что вы хотели бы изменить, и получите сгенерированный ИИ запрос LINQ, включая подсветку синтаксиса для облегчения чтения. См. картинку 2.

3. Многопроцессный анализ использования CPU
Инструмент использования CPU в профилировщике Visual Studio теперь поддерживает многопроцессный анализ, при этом графики производительности отображаются разными цветами для каждого процесса. Графики отображаются в виде диаграмм с перекрывающимися областями. Вы также можете фильтровать процессы с помощью раскрывающегося списка в левом верхнем углу. См. картинку 3.
Это позволяет легко филировать и изолировать использование CPU по процессам в одном сеансе, упрощая отладку производительности многопроцессных приложений.

4. Помощь в поиске проблем перед коммитом в Git
Новая функция (в VS 17.14 preview 1) на базе GitHub Copilot представляет ревью изменений кода перед коммитом. Это может помочь выявить проблемы с производительностью и безопасностью на ранней стадии, гарантируя вам более высокое качество кодовой базы.
Чтобы использовать эту функцию, убедитесь, что ваша подписка GitHub Copilot активна и включена в Visual Studio. Включите необходимые флаги функций: Tools > Options > Preview Features > Pull Request Add Comment (Инструменты > Параметры > Функции предварительной версии > Комментарии к пул-реквестам) и Tools > Options > GitHub > Copilot > Source Control Integration > Enable Git preview features (Инструменты > Параметры > GitHub > Copilot > Интеграция с системой управления исходным кодом > Включить превью функции для Git). Тогда в окне Git Changes в заголовке изменений вы увидите значок чата. При нажатии на него GitHub Copilot проведёт обзор ваших локальных изменений и представит предложения. См. картинку 4.
Как и со всеми функциями на базе ИИ, вам нужно будет просмотреть предложения Copilot на точность, что можно сделать прямо в файле кода. Вы можете перемещаться между комментариями или сворачивать их, используя кнопки в заголовке комментария.

Источники:
-
https://devblogs.microsoft.com/visualstudio/new-debugging-and-profiling-features-in-visual-studio-v17-13/
-
https://devblogs.microsoft.com/visualstudio/catch-issues-before-you-commit-to-git/
👍11👎2
День 2233. #ЗаметкиНаПолях
Перебираем Элементы ConcurrentDictionary
Существует несколько способов итерации по ConcurrentDictionary<TKey, TValue> в .NET. Вы можете использовать цикл foreach или свойства Keys и Values. Оба метода дают разные результаты, и вам следует выбрать тот, который лучше всего соответствует вашим потребностям.

1. Использование цикла foreach
Цикл foreach лениво выполняет итерацию по парам ключ-значение в ConcurrentDictionary. Это означает, что цикл будет извлекать следующую пару ключ-значение только тогда, когда это необходимо. Кроме того, он перечисляет «живые» данные. Т.е., если вы добавите элемент во время итерации по словарю, цикл foreach может вернуть его*.
* Из документации: Перечислитель, возвращаемый из словаря, можно безопасно использовать одновременно с чтением и записью в словарь, однако он не представляет моментальный снимок словаря. Содержимое, представленное через перечислитель, может содержать изменения, внесенные в словарь после вызова GetEnumerator.


Ещё один интересный момент заключается в том, что перечисление не блокирует словарь, поэтому не влияет на производительность.
var dict = new ConcurrentDictionary<int, string>();

foreach (var pair in dict)
{
Console.WriteLine($"{pair.Key}: {pair.Value}");
}


2. Использование свойств Keys и Values
Свойства Keys и Values возвращают снимок ключей и значений в словаре. Это означает, что коллекция, возвращаемая этими свойствами, является копией ключей и значений на момент вызова. Таким образом, если вы добавляете элемент во время итерации по словарю, свойства Keys и Values не вернут его. Кроме того, свойства Keys и Values блокируют словарь на время создания снимка. Это может повлиять на производительность, если словарь большой:
var dict = new ConcurrentDictionary<int, string>();

foreach (var key in dict.Keys)
{
Console.WriteLine($"Key: {key}");
}


Источник: https://www.meziantou.net/how-to-iterate-on-a-concurrentdictionary-foreach-vs-keys-values.htm
👍37
День 2234. #BestPractices
Разбирайте, а не Валидируйте

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

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

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

Парсинг
Процесс преобразования менее ограниченных типов в более ограниченные типов (или выдачи исключения, если это невозможно сделать) называется парсингом. Он добавляет дополнительные ограничения и, таким образом, уменьшает общий диапазон возможных значений, которые может представлять результирующий тип. Например:
int.Parse(string input);


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

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

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

Альтернативно, у вас могут быть методы со списками аргументов, такими как (int year, int month, int day, int hour, int minute, int second). Шесть целочисленных значений, каждое с отдельными допустимыми диапазонами. Можно выполнять проверку этих 6 значений в таком методе, прежде чем приступить к его фактической логике. Такая массированная проверка имеет тенденцию загромождать код и скрывать реальную работу, а также часто пропускать проверку некоторых входных данных в некоторых контекстах.

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

Источник: https://deviq.com/practices/parse-dont-validate
👍21
День 2235. #Карьера
Ежедневная Практика Лучше Учёбы по Выходным
В мире разработки ПО постоянно появляются новые фреймворки, языки и инструменты, и велик соблазн изучить новинку за выходные или на курсе, чтобы поддерживать знания актуальными. Но секрет освоения разработки ПО не в марафонских учебных сессиях. Всё гораздо проще: дело в постоянстве.

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

Напротив, ежедневная практика — даже всего 30 минут — создаёт устойчивую привычку и накопление знаний.

Правило 1% улучшения
Концепция, популяризированная Джеймсом Клиром в его книге «Атомные привычки». Небольшие, постепенные улучшения накапливаются со временем. Если вы улучшаетесь всего на 1% каждый день, то к концу года вы станете в 37 раз лучше.

Применительно к разработке это означает:
- Написание небольшого фрагмента кода каждый день.
- Решение одной проблемы кодирования ежедневно.
- Обзор новой концепции или отладка небольшой проблемы.

Почему это работает
1. Развивается «мышечная память» для кодирования
Как спортсменам, программным инженерам нужна регулярная практика, чтобы отточить свои навыки. Ежедневное написание кода помогает усвоить синтаксис, шаблоны и лучшие практики, делая вас быстрее и эффективнее.

2. Улучшаются навыки решения проблем
Решение проблем лежит в основе разработки ПО. Ежедневная практика подвергает вас различным испытаниям, помогая разработать набор стратегий и методов. Со временем вы обнаружите, что легче справляетесь со сложными проблемами.

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

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

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

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

3. Обзор и рефакторинг кода
Уделяйте несколько минут каждый день обзору собственного кода или проектов с открытым кодом. Ищите способы улучшить читаемость, эффективность или структуру.

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

5. Отслеживайте прогресс
Используйте журнал или приложение для отслеживания своей ежедневной деятельности по кодированию. Размышления о своём прогрессе укрепляют привычку и поддерживают мотивацию.

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

Источник: https://dev.to/jps27cse/the-role-of-consistency-in-software-engineering-why-daily-practice-beats-weekend-learning-36b9
👍32
День 2236. #УрокиРазработки
Уроки 50 Лет Разработки ПО

Урок 44. Высокое качество естественным образом ведет к повышению продуктивности. Начало

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

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

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

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

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

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

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

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

Урок 44. Высокое качество естественным образом ведет к повышению продуктивности. Окончание

Начало

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍6
День 2236. #ЧтоНовенького #NET10
System.Linq.Async Стал Частью .NET 10

IAsyncEnumerable — интерфейс, который был представлен во времена netcoreapp3.1. Хотя он и похож на IEnumerable (пусть и асинхронный), он никогда не имел таких возможностей, как его синхронный аналог. До .NET 10. Теперь у нас есть некоторое соответствие функций между ними.

Что такое IAsyncEnumerable?
Представьте, что у вас есть коллекция чего-то. В IEnumerable<T> это может быть Enumerable.Range(0, 10_000), что сгенерирует 10000 элементов. Но что, если генерация каждого элемента асинхронна?
Task<IEnumerable<T>> нам поможет? Не совсем. Придётся сначала ждать генерации всех элементов, а потом их обрабатывать.
А как насчет IEnumerable<Task<T>>? Семантика намекает, что у нас есть коллекция, в которой каждый элемент должен быть ожидаем. Но вам придётся заботиться о каждом элементе самостоятельно. Т.е. метод возвращает перечисление из задач, а вам решать, как обрабатывать эти задачи. Вот тут и поможет IAsyncEnumerable. По сути он похож на IEnumerable<Task<T>>, но упрощает обработку результатов. См. подробнее про асинхронные коллекции.

AsyncEnumerable
AsyncEnumerable, как и его синхронная версия Enumerable, определяет все полезные расширения (вроде Select, Where и т. д.) для типа IAsyncEnumerable. Поэтому вы можете написать такой код:
IAsyncEnumerable<MyObject> items = GetItems();

var filtered = await items
.Where(x => x.IsEnabled)
.ToListAsync(cancellationToken: token);

Или:
var avg = await items
.Select(s => s.SomeNumber)
.AverageAsync(cancellationToken);

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

System.Linq.Async
Этот API не новый, а взят отсюда. API доступен через NuGet-пакет System.Linq.Async. Хотя пакет по-прежнему действует для всего ниже .NET 10, нет смысла использовать его начиная с 10й версии. Поэтому пакет можно полностью удалить. API, судя по всему, идентичен. Если у вас этот пакет используется в качестве транзитивной зависимости, можно исключить библиотеку вот так:
<PackageReference Include="System.Linq.Async" Version="6.0.1">
<ExcludeAssets>all</ExcludeAssets>
</PackageReference>


Источник: https://steven-giesel.com/blogPost/e40aaedc-9e56-491f-9fe5-3bb0b162ae94/systemlinqasync-is-part-of-net-10-linq-for-iasyncenumerable
👍25
День 2239. #Книги
«Kubernetes для разработчиков» (Деннис У. — СПб.: Питер, 2025).

Прочитал подаренную издательством «Питер» книгу про Kubernetes.

Могу сказать, что это прекрасное пособие для тех, кто хочет ознакомиться с технологией. При этом книга подойдёт даже совсем новичкам, потому что начинается с самых основ контейнеризации, создания «Hello World» в докере, постепенно увеличивая сложность. Добавляется простенький веб-сервис, разворачивается в кубере, добавляются реплики, сервисы, проверки жизнеспособности, автомасштабирование, балансировщики, и т.д., и т.п. При этом всё с подробными разборами примеров. Я лично не выполнял все примеры (тем более, что они на Python – хотя это нисколько не мешает, код не сложный). Но для закрепления материала, конечно, полезнее будет всё потыкать на практике.

Ещё хотел бы отметить качество перевода. Поскольку я сам участвовал в переводах книг, то обращаю на это внимание. Так вот, здесь перевод один из лучших, которые я встречал. Это, конечно, вопрос вкуса, но на мой взгляд соблюли хороший баланс между переводом терминов на русский язык, которые можно легко перевести (nodes – узлы, deployment – развёртывание и т.п.), при этом оставив то, что сложно переводится, как есть (поды или Stateful-приложения), не уходя в излишнюю «литературность» перевода. Сервисы названы сервисами, а не службами! Единственное, что немножко «резануло глаз» - это «продуктивная среда» (отсюда и недавний опрос), но к этому быстро привыкаешь. Так что спасибо научному редактору перевода, Алексею Патрину (кстати, C#-разработчику), за работу.

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

Ещё раз спасибо за подарок издательству «Питер». Присылайте что-нибудь ещё 😊
👍46
День 2240. #юмор
Навеяло недавним 10х ускорением компилятора Typescript.
👍32
День 2241. #ЗаметкиНаПолях
Выполнение Очистки в BackgroundService
Есть что-то немного странное в шаблоне Worker Service в .NET.

Создадим новый проект Worker Service с помощью:
dotnet new worker -n MyWorker

Класс Worker использует BackgroundService в качестве базового класса. Worker имеет метод ExecuteAsync(…), который вызывается при запуске сервиса и принимает CancellationToken. В ExecuteAsync(…) есть цикл while, который проверяет, отменён ли CancellationToken. Если да, цикл завершается, и всё, что находится за пределами цикла, должно быть выполнено. В цикле есть вызов Task.Delay(1000, stopToken), который задерживается на 1 секунду и также принимает токен отмены.

Если Worker делает мало работы, задержка во время каждой итерации цикла велика по сравнению со временем, которое занимает фактическая работа. И отмена, скорее всего, произойдет во время периода задержки. Если CancellationToken отменяется во время задержки, Task.Delay(…) должен выбросить TaskCanceledException.

Но этого не происходит. Метод ExecuteAsync(…) прекращает работу, но исключение не выбрасывается. Код за пределами цикла while не выполняется. Это означает, что любой код очистки, который я хочу запустить при отмене BackgroundService, скорее всего, не будет выполнен, т.к. отмена обычно происходит во время задержки. Это странно.

Если запустить аналогичное консольное приложение, Task.Delay(…) выбросит TaskCanceledException, и мы получим исключение.
var cts = new CancellationTokenSource(3000);
var stopToken = cts.Token;

int count = 0;
while (!stopToken.IsCancellationRequested)
{
Console.WriteLine($"{++count} - {DateTime.Now:HH:mm:ss}");
await Task.Delay(1000, stopToken);
}

Console.WriteLine("Exiting");

Получим:
1 - 01:23:45
2 - 01:23:46
3 - 01:23:47
Unhandled exception. System.Threading.Tasks.TaskCanceledException: A task was canceled.

Но фоновый процесс не выбрасывает исключения!

Решение
Обернём Task.Delay(1000, stopsToken) в try…catch, перехватывая TaskCanceledException:
protected override async Task 
ExecuteAsync(CancellationToken stopToken)
{
while (!stopToken.IsCancellationRequested)
{
Console.WriteLine($"До: {DateTime.Now:HH:mm:ss}");
try
{
await Task.Delay(1000, stopToken);
}
catch (TaskCanceledException)
{
Console.WriteLine($"Отмена в Task.Delay.");
break;
}
Console.WriteLine($"После: {DateTime.Now:HH:mm:ss}");
}
Console.WriteLine("Очистка");
}

Если вы используете Task.Delay(1000) без токена отмены, код дождётся окончания задержки, прежде чем выходить из while, но любой код после выполнится.

Также можно попробовать:
await Task.Delay(1000, stopToken)
.ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
// или
await Task.Delay(1000, stopToken)
.ContinueWith(t => { return t.Exception == default;});

Они тоже не прервут работу и выполнят код после задержки.

Источник: https://nodogmablog.bryanhogan.net/2025/02/doing-some-cleanup-in-a-canceled-background-service/
👍8👎1
День 2242. #Карьера
Собеседования и Рынок .NET в РФ
Походил я тут ради интереса в последнее время по собеседованиям. Уже выкладывал задачу на код ревью от Озона. Сегодня хочу порассуждать о собеседованиях и в принципе о состоянии найма в ИТ.

В предыдущий раз я собеседовался аж в 2021 году. Хочу отметить, что если тогда все по классике спрашивали Рихтера, async-await и ленивое выполнение в LINQ, то сейчас этого очень мало. Почти везде (а я был на 4х техсобесах в разных компаниях), жёстко гоняют по «кабанчику». Распределённые системы, очереди сообщений, репликации и точки отказа. Надо, конечно, как советуют многие, ходить для профилактики на собеседования хотя бы раз в полгода-год, а то упускаешь, что сегодня в тренде. «Кабанчика» пришлось перечитать, т.к. многое оттуда забыл.

Ещё хотелось бы отметить довольно странную работу HR отделов компаний (исключая крупные, вроде Т-банка, Озона или Контура). 60% на присланное резюме просто не реагируют никак (хотя оно отправлялось напрямую по указанному в вакансии контакту), либо ограничиваются «я передам резюме руководству и вернусь с обратной связью». Дальше, как в меме: «С обратной связью, конечно, никто возвращаться не собирался». Они просто пропадают. Неужели сложно коротко ответить, типа «Вы нам не подходите». Не понимаю.

Из остальных 40% интересно, что некоторые HR умудряются так пропадать даже после созвона. Остальные всё-таки отвечают, и удавалось продолжить диалог и получить либо отказ, либо согласие общаться дальше. В большинстве случаев проходит 3 этапа собеседований:
- знакомство с HR (30 минут – час),
- техническое собеседование (1,5-2,5 часа),
- общение с командой/техлидом об условиях работы (1,5-2 часа).

В этом плане хотел бы отметить работу отдела найма в Контуре. После того, как я отправил резюме, HR довольно быстро ответила и прислала список вопросов для первого знакомства: почему ищу работу? какие ожидания по ЗП? чего жду от нового места? какой есть опыт с тем и с этим? был ли опыт управления командой? и т.п.
Я ответил на вопросы, и буквально в течение 10 минут HR вернулась с фидбеком. Для сравнения, иногда диалоги с HR других компаний шли по 1 сообщению в 1-2 дня. Приходилось перечитывать переписку, чтоб вспомнить, кто это и из какой компании. В общем, HR Контура ответила, что ЗП определят по итогам тех. интервью. Но, т.к. у меня не было такого и такого опыта, спросила, соглашусь ли я на ЗП на 10% меньше? Но сразу же упомянула, что в компании до двух раз в год пересматривают зарплаты, и в случае удачного старта можно выйти на желаемый уровень довольно быстро. А также перечислила другие преимущества работы в компании. Т.е. не просто отказала из-за завышенных требований, не заявила, что «можем дать только столько-то», а дала мотивированное объяснение. По-моему, прекрасный ответ.

Далее был созвон с HR (другой), поболтали о компании и о моём опыте. Кстати, совет. Будьте готовы ответить на вопросы типа «Что вы считаете своими большими достижениями в карьере?» и «Какие у вас были провалы?». Понятно, что и то, и другое, случается у каждого, но, чтоб не было неожиданностью, и чтоб не ляпнуть от волнения что-нибудь ненужное, стоит подготовить ответы заранее.

Техническое интервью тоже вполне достойное. Сначала дали код на обзор. Но тут, в отличие от Озона, не было очевидных ляпов в коде. Упор сделали на алгоритмы, оценку сложности и возможные улучшения. Разбирали, кстати, самописную реализацию StringBuilder. А после тоже погоняли по моему опыту, по «кабанчику» и попросили нарисовать и объяснить архитектуру небольшого сервиса: куда поместить сервис, какой будет API, где и как хранить данные, что, когда, куда будет передаваться. После этого также вернулись с подробным фидбеком: в чём были сильные стороны, где есть «зоны роста», причём с перечнем литературы, которую надо почитать (да, «кабанчик» там тоже был).

В общем, Контур оставил прекрасное впечатление в плане работы с кандидатами. Всем бы так.

Пишите в комментарии ваши истории о поиске работы.

Автору лучшей истории пришлю книгу по Kubernetes (мне из "Питера" случайно вторую прислали, разрешили подарить).
👍52👎2
День 2243. #ЗаметкиНаПолях
Статические Лямбда-Функции не Являются Статическими Методами
Начиная с C# 9.0, вы можете использовать модификатор static в лямбда-функциях. Например, вы можете написать следующий код:
enumerable.Select(static x => x * 2);

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

Если вы посмотрите на сгенерированный код, вы увидите, что лямбда-функция не является статическим методом. Это метод экземпляра.
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static Func<int, int> <>9__0_0;

// This method is not static
internal int <<Main>$>b__0_0(int i)
{
return i + 1;
}
}


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

Источник: https://www.meziantou.net/static-lambda-functions-are-not-static-methods.htm
👍25
День 2244. #УрокиРазработки
Уроки 50 Лет Разработки ПО

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

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

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

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

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

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

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

Источник: Карл Вигерс “Жемчужины Разработки”. СПб.: Питер, 2024. Глава 6.
👍13👎1
День 2245. #ЧтоНовенького
Новые Функции Visual Studio 17.14

Очередная порция интересных новинок в новой версии Visual Studio.

1. Генерация саммари с помощью ИИ
Если в настройках включена автоматическая генерация саммари, вы можете просто ввести ///, и Copilot автоматически заполнит описание метода и параметров на основе содержимого метода. Вы можете принять эти предложения с помощью Tab, как и обычные автодополнения кода Copilot. См. картинку 1.

Чтобы включить эту функцию, перейдите в Tools > Options > Text Editor > C# > Advanced (Инструменты > Параметры > Текстовый Редактор > C# > Дополнительно) и в блоке Comments (Комментарии) отметьте Generate XML documentation comments for /// (Генерировать комментарии XML документации для ///).

2. Поиск Функций IDE с помощью GitHub Copilot
VS упрощает доступ к чату GitHub Copilot из поиска функций (Ctrl+Q). Теперь нажатие кнопки Ask Copilot (Спросить Copilot) отправит запрос в чат GitHub Copilot, и вы получите подробный ответ.

Этот инструмент интерпретирует семантическое значение вашего запроса, учитывает вашу версию Visual Studio и даёт точные ответы. Например, ввод «prettify file» в традиционном поиске может не найти опцию «format document». Однако Copilot понимает намерение вашего запроса и может подсказать правильную настройку со всей необходимой информацией. См. картинку 2.

3. Улучшения Обзоров Кода в Пул-Реквестах
Просмотр комментариев к пул-реквестам уже был добавлен в VS некоторое время назад. Теперь вы сможете добавлять комментарии непосредственно в IDE прямо в нужном месте кода.

Чтобы использовать эту функцию комментирования, убедитесь, что вы включили флаги функции: Tools > Options > Preview Features > Pull Request Comments (Инструменты > Опции > Предварительный Просмотр Функций > Комментарии к Пул-реквестам) и Tools > Options > Preview Features > Pull Request Add Comment (Инструменты > Опции > Предварительный Просмотр Функций > Добавление Комментариев к Пул-реквестам).

После этого выберите любую ветку с активным пул-реквестом и нажмите Show Comments in Files (Показывать комментарии в файлах) в окне Git Changes, чтобы активировать комментарии к пул-реквесту в редакторе. Тогда в редакторе кода слева от каждой строки будет появляться значок Add comment (Добавить комментарий) или значок комментария в месте, где он был оставлен.

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

Подробности в этом видео.

Источники:
-
https://devblogs.microsoft.com/visualstudio/introducing-automatic-documentation-comment-generation-in-visual-studio/
-
https://devblogs.microsoft.com/visualstudio/find-the-ide-features-you-need-with-github-copilot-and-search/
-
https://devblogs.microsoft.com/visualstudio/enhance-pull-request-reviews-with-in-depth-feedback/
👍11