День восемьсот сорок четвёртый. #PerformanceTips
5 Способов Повысить Производительность Кода C# Бесплатно
5. Материализуйте запросы LINQ один раз
При написании запросов LINQ с использованием интерфейсов
Вот пример с материализованным запросом:
5 Способов Повысить Производительность Кода C# Бесплатно
5. Материализуйте запросы LINQ один раз
При написании запросов LINQ с использованием интерфейсов
IEnumerable
или IQueryable
разработчики могут материализовать запрос (вызвать ToList
, ToArray
или аналогичные методы) или не делать этого, что позволяет лениво работать с коллекциями. Но иногда возникает необходимость перебрать одну и ту же коллекцию несколько раз. Если запрос не был материализован, повторный перебор коллекции повлияет на производительность.public void NotMaterializedQueryTest()В этом примере запрос
{
var elements = Enumerable.Range(0, 50000000);
var filtered =
elements.Where(e => e % 100000 == 0);
foreach (var e in filtered)
{
…
}
foreach (var e in filtered)
{
…
}
foreach (var e in filtered)
{
…
}
}
Where
не материализуется. Вызов метода Where
просто возвращает объект, реализующий интерфейс IEnumerable
. Методы GetEnumerator
и MoveNext
будут вызываться только при итерации по коллекции в цикле foreach
.Вот пример с материализованным запросом:
public void MaterializedQueryTest()Второй метод из-за материализации запроса с помощью
{
var elements = Enumerable.Range(0, 50000000);
var filtered =
elements.Where(e => e % 100000 == 0).ToList();
//остальной код такой же
}
ToList
будет работать в 3 раза быстрее первого.| Method | Mean |Источник: https://levelup.gitconnected.com/5-ways-to-improve-the-performance-of-c-code-for-free-c89188eba5da
|------------------------- |-----------:|
| NotMaterializedQueryTest | 1,299.6 ms |
| MaterializedQueryTest | 495.5 ms |
День восемьсот сорок пятый. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Продолжение 25-27
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
Продолжение 21-24
25. Что такое интернирование строк?
Интернирование строк - это метод, позволяющий не дублировать экземпляры строк с одинаковым значением, известным во время компиляции. Таким образом, каждый раз, когда вы используете строковый литерал вроде
Дедупликация динамически создаваемых строк (со значением, неизвестным во время компиляции) не использует пул, потому что накладные расходы на проверку того, существует ли уже строка с заданным значением, вероятно, сократят преимущество от невыделения новой строки. В настоящее время открыт вопрос о дедупликации строк в фоновом режиме, но она пока не реализована.
Существует потокобезопасный API, с помощью которого вы можете получить доступ к пулу строк, чтобы проверить, интернирована ли строка с заданным значением (
26. Какие аллокации происходят в следующем методе:
Каждая лямбда также выделяет экземпляр
Примечание: статические лямбда-функции – нововведение в C#9.
27. Приводит ли ToString() на структуре к боксингу?
Окончание следует…
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Продолжение 25-27
Начало 1-4
Продолжение 5-8
Продолжение 9-12
Продолжение 13-16
Продолжение 17-20
Продолжение 21-24
25. Что такое интернирование строк?
Интернирование строк - это метод, позволяющий не дублировать экземпляры строк с одинаковым значением, известным во время компиляции. Таким образом, каждый раз, когда вы используете строковый литерал вроде
"Hello world!"
в разных местах вашего кода C# (в одном проекте/сборке) компилятор распознает это и будет рассматривать как одну «интернированную строку». Такие интернированные строки - это обычные строки, размещённые в управляемой куче. Единственное отличие состоит в том, что JIT знает о них, поэтому при компиляции IL кода, ссылающегося на них, он будет повторно использовать уже выделенную строку вместо создания новой с тем же значением. «Пул Интернированных Строк» (String Intern Pool) - это пул для обработки адресов/экземпляров этих строк, а не какое-либо выделенное пространство для них.Дедупликация динамически создаваемых строк (со значением, неизвестным во время компиляции) не использует пул, потому что накладные расходы на проверку того, существует ли уже строка с заданным значением, вероятно, сократят преимущество от невыделения новой строки. В настоящее время открыт вопрос о дедупликации строк в фоновом режиме, но она пока не реализована.
Существует потокобезопасный API, с помощью которого вы можете получить доступ к пулу строк, чтобы проверить, интернирована ли строка с заданным значением (
string.IsInterned
) или принудительно интернировать её (string.Intern
).26. Какие аллокации происходят в следующем методе:
IEnumerable Processing(List input) =>LINQ - это очень удобный высокоуровневый способ написания декларативного кода. Однако он не оптимизирован для высокопроизводительных горячих путей в вашем коде. Многие операции что-то выделяют в куче, как и в этом случае. Каждый раз, когда вы используете
input
.Where(static x => x > 0)
.Select(static x => x * x);
Where
или Select
, выделяется специальный класс-итератор. Он может комбинироваться с другими. В нашем случае сначала выделяется WhereListIterator
(из-за вызова Where
), а затем он объединяется в WhereSelectListIterator
(из-за вызова Select
). Оба экземпляра занимают 152 байта, что явно не так много, если рассматривать один вызов. Но если он используется в горячем пути и вызывается тысячи или миллионы раз, и вы получите мегабайты мусора только из-за этой единственной строчки кода.Каждая лямбда также выделяет экземпляр
Func
, но обычно они оптимизируются с помощью кеширования. То есть, хотя первый вызов действительно выделит два экземпляра Func
для представления лямбда-выражений в методах Where
и Select
, они будут повторно использоваться в последующих вызовах.Примечание: статические лямбда-функции – нововведение в C#9.
27. Приводит ли ToString() на структуре к боксингу?
ToString()
у структур имеет реализацию по умолчанию и вызывает боксинг структуры (размещение её в управляемой куче). Если вы хотите избежать ненужного боксинга, вам необходимо переопределить метод ToString()
.Окончание следует…
Источник: https://dotnetmemoryexpert.com
День восемьсот сорок шестой. #ЗаметкиНаПолях
Отмена Операции при Отмене HTTP Запроса
Я уже много раз писал про скоординированную отмену, например, здесь и здесь. И даже про улучшения, которые ожидаются в .NET6. Однако, я, к своему удивлению, упустил момент, что Kestrel может перехватывать событие отмены запроса со стороны пользователя, и передавать отмену операции методу действия контроллера.
Таким образом, можно просто передать
В своём коде вы можете использовать два способа:
- булево свойство
- метод
Необработанные исключения в методах контроллера – это, конечно, плохая идея. Чтобы не засорять код контроллеров их обработкой, можно использовать фильтр исключений, например, такой:
Также имейте в виду, что пользователь, отменивший запрос, конечно, не увидит никакого сообщения или кода ответа от сервера, поэтому какой именно код ответа будет использован, не играет роли, хотя формально существует код 499 Client Closed Request.
Стоит отметить ещё одну интересную особенность токена отмены. Swagger «понимает» смысл передачи его в метод действия контроллера, поэтому он не включает его в общедоступные параметры метода. Таким образом, в сгенерированной документации API у вас не будет лишних параметров конечных точек.
Конечно, токен отмены в методах действия контроллеров стоит добавлять с умом. Например, вы вряд ли хотите, чтобы транзакция по изменению сущности в базе поддерживала отмену посреди операции. Таким образом, наиболее безопасно использовать токен отмены в операциях без побочных эффектов, вроде получения данных от API.
Источники:
- https://www.youtube.com/watch?v=b5dyPJ3zyRg
- https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/
Отмена Операции при Отмене HTTP Запроса
Я уже много раз писал про скоординированную отмену, например, здесь и здесь. И даже про улучшения, которые ожидаются в .NET6. Однако, я, к своему удивлению, упустил момент, что Kestrel может перехватывать событие отмены запроса со стороны пользователя, и передавать отмену операции методу действия контроллера.
Таким образом, можно просто передать
CancellationToken
в метод контроллера, который запускает длительную операцию:public MyController {Entity Framework и ADO, а также, например,
public async Task<IActionResult>
DoSomethingAsync(CancellationToken token)
{
…
}
}
HttpClient
, принимают токен отмены, и в случае отмены операции выбрасывают TaskCanceledException
. В методе действия контроллера вы можете перехватить и обработать это исключение.В своём коде вы можете использовать два способа:
- булево свойство
IsCancellationRequested
, которое вы можете проверять вручную в цикле или между вызовами длительных операций,- метод
ThrowIfCancellationRequested()
, выбрасывающий исключение OperationCanceledException
, которое вы впоследствии можете обработать.Необработанные исключения в методах контроллера – это, конечно, плохая идея. Чтобы не засорять код контроллеров их обработкой, можно использовать фильтр исключений, например, такой:
public class OperationCanceledExceptionFilter :Обратите внимание, что мы перехватываем исключение
ExceptionFilterAttribute
{
public OperationCanceledExceptionFilter()
{}
public override void OnException(ExceptionContext context)
{
if(context.Exception is OperationCanceledException)
{
context.ExceptionHandled = true;
context.Result = new StatusCodeResult(400);
}
}
}
OperationCanceledException
. TaskCanceledException
является его потомком, поэтому также будет перехвачено.Также имейте в виду, что пользователь, отменивший запрос, конечно, не увидит никакого сообщения или кода ответа от сервера, поэтому какой именно код ответа будет использован, не играет роли, хотя формально существует код 499 Client Closed Request.
Стоит отметить ещё одну интересную особенность токена отмены. Swagger «понимает» смысл передачи его в метод действия контроллера, поэтому он не включает его в общедоступные параметры метода. Таким образом, в сгенерированной документации API у вас не будет лишних параметров конечных точек.
Конечно, токен отмены в методах действия контроллеров стоит добавлять с умом. Например, вы вряд ли хотите, чтобы транзакция по изменению сущности в базе поддерживала отмену посреди операции. Таким образом, наиболее безопасно использовать токен отмены в операциях без побочных эффектов, вроде получения данных от API.
Источники:
- https://www.youtube.com/watch?v=b5dyPJ3zyRg
- https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/
День восемьсот сорок седьмой. #ЗаметкиНаПолях #GC
Топ Вопросов о Памяти в .NET. Окончание 28-32
Предыдущие вопросы: 1-4, 5-8, 9-12, 13-16, 17-20, 21-24, 25-27
28. Что такое хвост распределения задержек (tail latency)?
Хвост распределения задержек - это небольшой процент ответов системы с наибольшим временем отклика. Обычно, рассматривая производительность, например, веб-приложения, нас интересует «среднее время отклика». Оно сообщает нам, каково время отклика для среднестатистического пользователя. Это может быть важным, но также и вводящим в заблуждение. Особенно, если распределение времени отклика является мультимодальным, т.е. когда существуют различные группы времён отклика (например, большинство - очень быстрые, но есть и другая группа очень медленных). Поэтому лучше измерять производительность, наблюдая гистограмму времени отклика, а также следить за хвостом распределения задержек.
Оптимизация хвоста распределения задержек важна, потому что даже если наше приложение работает достаточно хорошо, всё равно будут те несколько процентов пользователей, которые наблюдают действительно медленные ответы. Они могут разочароваться в нашем приложении и больше к нему не возвращаться.
В контексте GC хвост распределения задержек может возникать из-за случайных, но очень длинных пауз на сборку мусора.
29. В чём особенность метода Dispose?
Метод
30. Можно ли добиться детерминированных пауз на сборку мусора?
Короткий ответ - нет. Мы можем повлиять на время паузы: всё, что снижает нагрузку на память (например, уменьшение количества аллокаций), скорее всего уменьшит время пауз. Некоторые настройки GC тоже могут влиять на них. Но нет гарантии, что время паузы будет детерминированным (например, всегда меньше X миллисекунд). На рынке есть другие сборщики мусора, особенно в мире JVM, которые предоставляют такие гарантии. В .NET их пока нет.
31. Где можно настроить режим GC: серверный или рабочей станции?
Мы можем изменить режим GC только перед запуском приложения, но не во время его выполнения. Для этой цели можно использовать как файл конфигурации, так и переменные среды. Выбор между конкурентным (фоновым) и неконкурентным режимами сборки мусора не зависит от того, работает ли текущий сборщик мусора в режиме рабочей станцией или сервера.
32. Можем ли мы заменить сборщик мусора в .NET?
Да, можем! Начиная с .NET Core 2.0, GC и среда выполнения были разделены. С помощью переменной среды
Источник: https://dotnetmemoryexpert.com
Топ Вопросов о Памяти в .NET. Окончание 28-32
Предыдущие вопросы: 1-4, 5-8, 9-12, 13-16, 17-20, 21-24, 25-27
28. Что такое хвост распределения задержек (tail latency)?
Хвост распределения задержек - это небольшой процент ответов системы с наибольшим временем отклика. Обычно, рассматривая производительность, например, веб-приложения, нас интересует «среднее время отклика». Оно сообщает нам, каково время отклика для среднестатистического пользователя. Это может быть важным, но также и вводящим в заблуждение. Особенно, если распределение времени отклика является мультимодальным, т.е. когда существуют различные группы времён отклика (например, большинство - очень быстрые, но есть и другая группа очень медленных). Поэтому лучше измерять производительность, наблюдая гистограмму времени отклика, а также следить за хвостом распределения задержек.
Оптимизация хвоста распределения задержек важна, потому что даже если наше приложение работает достаточно хорошо, всё равно будут те несколько процентов пользователей, которые наблюдают действительно медленные ответы. Они могут разочароваться в нашем приложении и больше к нему не возвращаться.
В контексте GC хвост распределения задержек может возникать из-за случайных, но очень длинных пауз на сборку мусора.
29. В чём особенность метода Dispose?
Метод
Dispose
- это контракт, представленный интерфейсом IDisposable
. Реализуя его, мы явно говорим: «экземпляры этого типа владеют некоторыми ресурсами, которые требуют явной очистки путём вызова метода Dispose». Вот и всё! Что делает метод Dispose, полностью зависит от конкретного случая. Важно помнить, что он не имеет ничего общего с GC и управляемой памятью. Это просто метод, который нужно вызвать. Мы можем вызвать его неявно через using
и проверить, вызывается ли он, с помощью анализаторов кода. Вызов его ни о чём не сообщает сборщику мусора и не «освобождает память» после объекта. Такой объект, как и любой другой объект .NET, будет обработан сборщиком мусора, когда сборщик мусора обнаружит, что он больше не используется.30. Можно ли добиться детерминированных пауз на сборку мусора?
Короткий ответ - нет. Мы можем повлиять на время паузы: всё, что снижает нагрузку на память (например, уменьшение количества аллокаций), скорее всего уменьшит время пауз. Некоторые настройки GC тоже могут влиять на них. Но нет гарантии, что время паузы будет детерминированным (например, всегда меньше X миллисекунд). На рынке есть другие сборщики мусора, особенно в мире JVM, которые предоставляют такие гарантии. В .NET их пока нет.
31. Где можно настроить режим GC: серверный или рабочей станции?
Мы можем изменить режим GC только перед запуском приложения, но не во время его выполнения. Для этой цели можно использовать как файл конфигурации, так и переменные среды. Выбор между конкурентным (фоновым) и неконкурентным режимами сборки мусора не зависит от того, работает ли текущий сборщик мусора в режиме рабочей станцией или сервера.
32. Можем ли мы заменить сборщик мусора в .NET?
Да, можем! Начиная с .NET Core 2.0, GC и среда выполнения были разделены. С помощью переменной среды
COMPlus_GCName
вы можете указать динамическую библиотеку, которая реализует ваш собственный сборщик мусора, и она будет использоваться средой выполнения .NET Core или .NET 5 вместо библиотеки по умолчанию. Однако есть одна проблема: на рынке нет готовых пользовательских сборщиков мусора.Источник: https://dotnetmemoryexpert.com
День восемьсот сорок восьмой. #BestPractices #CICD
Индикатор Покрытия Кода
Многие используют непрерывную интеграцию или какой-либо конвейер сборки с помощью Azure DevOps, GitHub Actions или другого сервера сборки. Практически любой из конвейеров позволяет вам запускать тесты как часть процесса и откатывать сборку, если тесты терпят неудачу. Некоторые шаги сборки могут анализировать общее покрытие кода (процент от общего количества строк кода в вашем приложении, которые покрыты тестами), и вы можете выбрать откат сборки, если процент упадёт ниже определённого порога. Это один из индикаторов качества сборки, в данном случае индикатором покрытия тестами.
Важно понимать и убедить руководство в том, что индикатор покрытия тестами - это запаздывающий индикатор.
Суть процесса непрерывной интеграции заключается в сокращении циклов обратной связи. И когда процесс обнаруживает ошибку или неудавшийся тест, он хорошо служит этой цели. Однако, если ваше текущее покрытие кода составляет 85%, а порог качества - 80%, могут произойти несколько ошибочных коммитов, которые уменьшат покрытие (путем удаления тестов или добавления тонны непроверенного кода). Но, возможно, это просто снизит покрытие до 81%. Затем происходят ещё несколько коммитов, которые в принципе нормальные. Но через пару недель - БАМ! – покрытие снижается ниже лимита после вполне безобидного коммита. Настоящий виновник - более ранние коммиты, которые в реальности серьёзно снизили покрытие, но ещё проходили под лимит. А вы обнаружили проблему намного позже.
Если вы собираетесь использовать индикаторы покрытия кода в процессе непрерывной интеграции, то помните, что, в случае унаследованного (существующего) кода, вы должны установить ОЧЕНЬ низкий лимит, а затем увеличивать его каждую неделю или две по мере увеличения покрытия кода. Если вы пишете новое программное обеспечение с относительно высоким стандартом покрытия кода, вам всё равно следует подумать о том, чтобы порог был выше, чем требуют стандарты компании, но всё же чуть ниже текущего покрытия, чтобы всё, что вызывает серьезное падение показателя, было обнаружено на раннем этапе. Возможно, стоит установить более высокий порог в среде разработки, и сделать его чуть ниже для более поздних этапов развёртывания. Если вы отнесётесь к этому серьезно, это может помочь вам быстрее определить, какие изменения в кодовой базе несут ответственность за негативное влияние на покрытие кода.
Источник: https://ardalis.com/tips
Индикатор Покрытия Кода
Многие используют непрерывную интеграцию или какой-либо конвейер сборки с помощью Azure DevOps, GitHub Actions или другого сервера сборки. Практически любой из конвейеров позволяет вам запускать тесты как часть процесса и откатывать сборку, если тесты терпят неудачу. Некоторые шаги сборки могут анализировать общее покрытие кода (процент от общего количества строк кода в вашем приложении, которые покрыты тестами), и вы можете выбрать откат сборки, если процент упадёт ниже определённого порога. Это один из индикаторов качества сборки, в данном случае индикатором покрытия тестами.
Важно понимать и убедить руководство в том, что индикатор покрытия тестами - это запаздывающий индикатор.
Суть процесса непрерывной интеграции заключается в сокращении циклов обратной связи. И когда процесс обнаруживает ошибку или неудавшийся тест, он хорошо служит этой цели. Однако, если ваше текущее покрытие кода составляет 85%, а порог качества - 80%, могут произойти несколько ошибочных коммитов, которые уменьшат покрытие (путем удаления тестов или добавления тонны непроверенного кода). Но, возможно, это просто снизит покрытие до 81%. Затем происходят ещё несколько коммитов, которые в принципе нормальные. Но через пару недель - БАМ! – покрытие снижается ниже лимита после вполне безобидного коммита. Настоящий виновник - более ранние коммиты, которые в реальности серьёзно снизили покрытие, но ещё проходили под лимит. А вы обнаружили проблему намного позже.
Если вы собираетесь использовать индикаторы покрытия кода в процессе непрерывной интеграции, то помните, что, в случае унаследованного (существующего) кода, вы должны установить ОЧЕНЬ низкий лимит, а затем увеличивать его каждую неделю или две по мере увеличения покрытия кода. Если вы пишете новое программное обеспечение с относительно высоким стандартом покрытия кода, вам всё равно следует подумать о том, чтобы порог был выше, чем требуют стандарты компании, но всё же чуть ниже текущего покрытия, чтобы всё, что вызывает серьезное падение показателя, было обнаружено на раннем этапе. Возможно, стоит установить более высокий порог в среде разработки, и сделать его чуть ниже для более поздних этапов развёртывания. Если вы отнесётесь к этому серьезно, это может помочь вам быстрее определить, какие изменения в кодовой базе несут ответственность за негативное влияние на покрытие кода.
Источник: https://ardalis.com/tips
День восемьсот сорок девятый. #ЗаметкиНаПолях
Стек или Куча
Тема про сборщик мусора и паттерн Disposable пару дней назад вызвала бурную дискуссию у нас в чате. Сегодня предложу вам не менее острую: ссылочные типы и типы значений, и где они хранятся. Короткий (и неправильный) ответ: ссылочные - в куче, а типы значений - в стеке.
Типы значений в .NET – это bool, byte, sbyte, char, decimal, double, float, int, uint, nint, nuint, long, ulong, short, ushort, struct, enum и кортежи. Все остальные типы ссылочные.
На самом деле, всё немного сложнее. Типы значений могут храниться в куче в некоторых случаях. Вот краткий список правил хранения экземпляров типа значения:
1. переменная в методе – в стеке,
2. параметр метода – в стеке,
3. поле класса – в куче,
4. элемент коллекции – в куче,
5. поле структуры – там, где хранится структура,
6. тип ref struct и его члены – всегда в стеке.
Подробнее в новом видео от Nick Chapsas по ссылке ниже. Кроме того, Ник наглядно показывает, где хранится переменная в том или ином случае, а также, что такое упаковка, и почему она происходит при интерполяции строк.
Источник: https://www.youtube.com/watch?v=jONSIhMST9E
Стек или Куча
Тема про сборщик мусора и паттерн Disposable пару дней назад вызвала бурную дискуссию у нас в чате. Сегодня предложу вам не менее острую: ссылочные типы и типы значений, и где они хранятся. Короткий (и неправильный) ответ: ссылочные - в куче, а типы значений - в стеке.
Типы значений в .NET – это bool, byte, sbyte, char, decimal, double, float, int, uint, nint, nuint, long, ulong, short, ushort, struct, enum и кортежи. Все остальные типы ссылочные.
На самом деле, всё немного сложнее. Типы значений могут храниться в куче в некоторых случаях. Вот краткий список правил хранения экземпляров типа значения:
1. переменная в методе – в стеке,
2. параметр метода – в стеке,
3. поле класса – в куче,
4. элемент коллекции – в куче,
5. поле структуры – там, где хранится структура,
6. тип ref struct и его члены – всегда в стеке.
Подробнее в новом видео от Nick Chapsas по ссылке ниже. Кроме того, Ник наглядно показывает, где хранится переменная в том или ином случае, а также, что такое упаковка, и почему она происходит при интерполяции строк.
Источник: https://www.youtube.com/watch?v=jONSIhMST9E
День восемьсот пятидесятый. #Юмор
Доброй субботы, дорогие подписчики. Сегодня вашему вниманию прекрасное видео «День разработчика ПО на удалёнке». Мне очень понравилось)))
Доброй субботы, дорогие подписчики. Сегодня вашему вниманию прекрасное видео «День разработчика ПО на удалёнке». Мне очень понравилось)))
YouTube
a day in the life of an engineer working from home
Check out my new vlog channel: https://www.youtube.com/channel/UCmMGlb7mGXYVthrXYSwlQhw
Follow my newsletter: https://jomakaze.substack.com/
Music by Joy Ngiaw:
https://www.joyngiaw.com/
https://www.instagram.com/joyngiaw/
📱 SOCIAL MEDIA
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀…
Follow my newsletter: https://jomakaze.substack.com/
Music by Joy Ngiaw:
https://www.joyngiaw.com/
https://www.instagram.com/joyngiaw/
📱 SOCIAL MEDIA
▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀▀…
День восемьсот пятьдесят первый. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
86. Одна Голова Хорошо, а Две (Зачастую) Лучше
Программирование требует много обдумывания и сосредоточенности, а глубокие мысли требуют уединения. Таков стереотип программиста.
Этот подход «одинокого волка» к программированию уступил место более коллективному подходу, который, я бы сказал, улучшает качество, продуктивность и удовлетворённость работой программистов. Такой подход побуждает разработчиков более тесно сотрудничать друг с другом, а также с не разработчиками: бизнес-аналитиками, системными аналитиками, специалистами по обеспечению качества и пользователями.
Что это значит для разработчиков? Быть опытным технологом уже недостаточно. Вы должны научиться эффективно работать с другими.
Сотрудничество - это не только вопросы и ответы или сидение на собраниях. Речь идет о том, чтобы работать с кем-то в паре, обмениваться опытом и совместно решать проблемы.
Я большой поклонник парного программирования. Можно назвать это «экстремальным сотрудничеством». Когда я работаю в паре, мои навыки как разработчика растут. Если я слабее своего партнёра в какой-то области или технологии, я учусь на его или её опыте. Когда я становлюсь сильнее в каком-то аспекте, я глубже понимаю, что я знаю и чего не знаю, когда мне приходится объяснять это партнёру. Мы неизменно добавляем что-то в общую копилку и учимся друг у друга.
При объединении в пары каждый из нас привносит свой опыт программирования - как предметный, так и технический - в решение поставленной задачи и может привнести уникальное понимание и опыт в эффективное и действенное написание программного обеспечения. Даже в случаях огромной разницы в умениях или технических знаниях более опытный участник неизменно учится чему-то у другого - возможно, новому сочетанию клавиш, новому инструменту или библиотеке. Для менее опытных членов пары это отличный способ догнать команду.
Парное программирование популярно, но не только среди сторонников гибкой разработки программного обеспечения. Скептики объединения в пары, задают вопрос: «Почему я должен платить двум программистам, чтобы они выполняли работу одного?» Вы действительно не должны. Однако объединение в пары повышает качество, понимание предметной области, технологий и методов (например, трюков IDE) и снижает последствия «риска лотереи» (когда один из ваших опытных разработчиков выигрывает в лотерею и увольняется на следующий день).
Какова долгосрочная ценность изучения нового сочетания клавиш? Как измерить общее улучшение качества продукта в результате объединения в пары? Как измерить вклад вашего партнёра, который не позволил вам пойти по тупиковому пути к решению сложной проблемы? В одном исследовании говорится об увеличении эффективности и скорости на 40%*. Какова ценность снижения последствий «риска лотереи»? Большинство из этих преимуществ трудно измерить.
Кто с кем должен составлять пары? Если вы новичок в команде, важно найти опытного члена команды. Не менее важно найти человека, у которого есть хорошие навыки межличностного общения и коучинга. Если у вас нет большого опыта в предметной области, объединитесь с членом команды, который является экспертом в данной предметной области.
Если вы не уверены, экспериментируйте: сотрудничайте с коллегами. Решите интересную и трудную проблему. Посмотрите, каково это. Попробуйте несколько раз.
*“The Case for Collaborative Programming”, J. T. Nosek - Communications of the ACM, 1998
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Adrian Wible
97 Вещей, Которые Должен Знать Каждый Программист
86. Одна Голова Хорошо, а Две (Зачастую) Лучше
Программирование требует много обдумывания и сосредоточенности, а глубокие мысли требуют уединения. Таков стереотип программиста.
Этот подход «одинокого волка» к программированию уступил место более коллективному подходу, который, я бы сказал, улучшает качество, продуктивность и удовлетворённость работой программистов. Такой подход побуждает разработчиков более тесно сотрудничать друг с другом, а также с не разработчиками: бизнес-аналитиками, системными аналитиками, специалистами по обеспечению качества и пользователями.
Что это значит для разработчиков? Быть опытным технологом уже недостаточно. Вы должны научиться эффективно работать с другими.
Сотрудничество - это не только вопросы и ответы или сидение на собраниях. Речь идет о том, чтобы работать с кем-то в паре, обмениваться опытом и совместно решать проблемы.
Я большой поклонник парного программирования. Можно назвать это «экстремальным сотрудничеством». Когда я работаю в паре, мои навыки как разработчика растут. Если я слабее своего партнёра в какой-то области или технологии, я учусь на его или её опыте. Когда я становлюсь сильнее в каком-то аспекте, я глубже понимаю, что я знаю и чего не знаю, когда мне приходится объяснять это партнёру. Мы неизменно добавляем что-то в общую копилку и учимся друг у друга.
При объединении в пары каждый из нас привносит свой опыт программирования - как предметный, так и технический - в решение поставленной задачи и может привнести уникальное понимание и опыт в эффективное и действенное написание программного обеспечения. Даже в случаях огромной разницы в умениях или технических знаниях более опытный участник неизменно учится чему-то у другого - возможно, новому сочетанию клавиш, новому инструменту или библиотеке. Для менее опытных членов пары это отличный способ догнать команду.
Парное программирование популярно, но не только среди сторонников гибкой разработки программного обеспечения. Скептики объединения в пары, задают вопрос: «Почему я должен платить двум программистам, чтобы они выполняли работу одного?» Вы действительно не должны. Однако объединение в пары повышает качество, понимание предметной области, технологий и методов (например, трюков IDE) и снижает последствия «риска лотереи» (когда один из ваших опытных разработчиков выигрывает в лотерею и увольняется на следующий день).
Какова долгосрочная ценность изучения нового сочетания клавиш? Как измерить общее улучшение качества продукта в результате объединения в пары? Как измерить вклад вашего партнёра, который не позволил вам пойти по тупиковому пути к решению сложной проблемы? В одном исследовании говорится об увеличении эффективности и скорости на 40%*. Какова ценность снижения последствий «риска лотереи»? Большинство из этих преимуществ трудно измерить.
Кто с кем должен составлять пары? Если вы новичок в команде, важно найти опытного члена команды. Не менее важно найти человека, у которого есть хорошие навыки межличностного общения и коучинга. Если у вас нет большого опыта в предметной области, объединитесь с членом команды, который является экспертом в данной предметной области.
Если вы не уверены, экспериментируйте: сотрудничайте с коллегами. Решите интересную и трудную проблему. Посмотрите, каково это. Попробуйте несколько раз.
*“The Case for Collaborative Programming”, J. T. Nosek - Communications of the ACM, 1998
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Adrian Wible
День восемьсот пятьдесят второй.
Новые Бесплатные Расширения для VS 2019. Начало 1-4
Пока мы ждём выхода новой Visual Studio 2022, большая часть .NET разработчиков используют VS 2019. Сегодня рассмотрим полезные бесплатные расширения для студии. Замечу, что под «новыми» здесь понимаются не только недавно вышедшие, но и недавно обновлённые инструменты.
1. Unit Test Boilerplate Generator от RandomEngy - это бесплатный инструмент со средней оценкой 4,8 из 5. Он поможет создать шаблон модульного теста для класса C#, с mock-объектами для всех зависимостей. Наряду с двумя режимами внедрения зависимостей и поддержкой инфраструктуры тестирования VS, он поддерживает NUnit и xUnit, а для mock-объектов поддерживаются: FakeItEasy, JustMock, Moq + AutoMoq, NSubstitute, Rhino Mocks и
SimpleStubs.
2. Fine Code Coverage от Fortune Ngwenya было скачано почти 18 тысяч раз, получив почти идеальную оценку 4,9. Оно помогает разработчикам визуализировать покрытие кода модульными тестами в .NET Core (.NET 5) и даже в старой .NET Framework. В частности, функция визуализации позволяет программистам:
- Помечать код, для которого есть тесты и для которого их нет
- Помечать тестирующий код
- Получать отчёты о покрытии кода тестами
- Получить отчёт о проблемах на горячих путях
Расширение последний раз было обновлено в конце марта, а последний коммит в репозитории проекта недельной давности, то есть автор старается поддерживать его в актуальном состоянии.
3. Run Coverlet Report от Chris Dexter - еще одна утилита для упрощения демонстрации покрытия кода, цель которой - бесплатно дублировать функциональность Visual Studio Enterprise (прости, Microsoft). Run Coverlet Report основан на превосходных инструментах Coverlet и Report Generator, которые позволяют собирать результаты покрытия кода из модульных тестов. Это расширение запускает оба этих инструмента, а затем отображает файл отчёта в Visual Studio, а также использует вывод Coverlet для подсветки синтаксиса. Coverlet, поддерживаемый .NET Foundation, - это проект с открытым исходным кодом, обеспечивающий кроссплатформенную систему анализа покрытия кода для C#. Report Generator преобразует отчёты о покрытии кода, созданные Visual Studio и многими другими инструментами, в удобочитаемые отчёты в различных форматах. Ещё один инструмент с идеальными 5 из 5.
4. Debug Attach Manager от Viktor Karpach делает одно дело, но делает его хорошо: помогает присоединить отладчик Visual Studio к пулам веб-приложений, службам Windows и другим процессам. Фактически, вы можете искать процессы (например, относящиеся к пулу приложений IIS), а затем присоединяться к ним, автоматически сохраняя выбранные процессы между перезапусками Visual Studio. Вы также можете подключаться к нескольким процессам одновременно. Кстати, расширение работает с версиями VS, начиная аж с 2013, если вдруг у кого ещё остались такие.
Окончание следует …
Источник: https://visualstudiomagazine.com/articles/2021/05/07/testing-tools.aspx
Новые Бесплатные Расширения для VS 2019. Начало 1-4
Пока мы ждём выхода новой Visual Studio 2022, большая часть .NET разработчиков используют VS 2019. Сегодня рассмотрим полезные бесплатные расширения для студии. Замечу, что под «новыми» здесь понимаются не только недавно вышедшие, но и недавно обновлённые инструменты.
1. Unit Test Boilerplate Generator от RandomEngy - это бесплатный инструмент со средней оценкой 4,8 из 5. Он поможет создать шаблон модульного теста для класса C#, с mock-объектами для всех зависимостей. Наряду с двумя режимами внедрения зависимостей и поддержкой инфраструктуры тестирования VS, он поддерживает NUnit и xUnit, а для mock-объектов поддерживаются: FakeItEasy, JustMock, Moq + AutoMoq, NSubstitute, Rhino Mocks и
SimpleStubs.
2. Fine Code Coverage от Fortune Ngwenya было скачано почти 18 тысяч раз, получив почти идеальную оценку 4,9. Оно помогает разработчикам визуализировать покрытие кода модульными тестами в .NET Core (.NET 5) и даже в старой .NET Framework. В частности, функция визуализации позволяет программистам:
- Помечать код, для которого есть тесты и для которого их нет
- Помечать тестирующий код
- Получать отчёты о покрытии кода тестами
- Получить отчёт о проблемах на горячих путях
Расширение последний раз было обновлено в конце марта, а последний коммит в репозитории проекта недельной давности, то есть автор старается поддерживать его в актуальном состоянии.
3. Run Coverlet Report от Chris Dexter - еще одна утилита для упрощения демонстрации покрытия кода, цель которой - бесплатно дублировать функциональность Visual Studio Enterprise (прости, Microsoft). Run Coverlet Report основан на превосходных инструментах Coverlet и Report Generator, которые позволяют собирать результаты покрытия кода из модульных тестов. Это расширение запускает оба этих инструмента, а затем отображает файл отчёта в Visual Studio, а также использует вывод Coverlet для подсветки синтаксиса. Coverlet, поддерживаемый .NET Foundation, - это проект с открытым исходным кодом, обеспечивающий кроссплатформенную систему анализа покрытия кода для C#. Report Generator преобразует отчёты о покрытии кода, созданные Visual Studio и многими другими инструментами, в удобочитаемые отчёты в различных форматах. Ещё один инструмент с идеальными 5 из 5.
4. Debug Attach Manager от Viktor Karpach делает одно дело, но делает его хорошо: помогает присоединить отладчик Visual Studio к пулам веб-приложений, службам Windows и другим процессам. Фактически, вы можете искать процессы (например, относящиеся к пулу приложений IIS), а затем присоединяться к ним, автоматически сохраняя выбранные процессы между перезапусками Visual Studio. Вы также можете подключаться к нескольким процессам одновременно. Кстати, расширение работает с версиями VS, начиная аж с 2013, если вдруг у кого ещё остались такие.
Окончание следует …
Источник: https://visualstudiomagazine.com/articles/2021/05/07/testing-tools.aspx
День восемьсот пятьдесят третий.
Новые Бесплатные Расширения для VS 2019. Окончание 5-9
Начало 1-4
5. SpecFlow представляет собой комплексное предложение профессионального уровня, в котором есть ссылки на документацию, инструкции по началу работы, часто задаваемые вопросы и политика конфиденциальности. При этом оно по-прежнему бесплатное, и имеет впечатляющие 4,9 из 5. SpecFlow помогает группам разработчиков .NET определять, управлять и выполнять автоматизированные приёмочные тесты в виде удобочитаемых бизнес-ориентированных спецификаций. SpecFlow поддерживает концепции разработки Behavior Driven Development (BDD) и Acceptance Test Driven Development (ATDD). Про BDD и SpecFlow, кстати, есть видео у Nick Chapsas.
6. Azure DevOps Test Connector от MadeUpExtensions работает с вышеупомянутым SpecFlow, поддерживая создание тестов Specflow Scenario Outline. Он позволяет программистам использовать атрибуты для связи с тестовыми классами и файлами функций SpecFlow с планами/наборами тестов и кейсами Azure DevOps. Это позволяет инженеру по автоматизации тестирования быстро синхронизировать свои последние изменения в Visual Studio с Azure DevOps, экономя время за счёт автоматического создания и связывания планов тестирования, наборов тестов (как статических, так и основанных на требованиях).
7. «Обожаю работать со сложными регулярными выражениями» – любят говорить… примерно никто из программистов. Хотя, может, это только мой личный опыт, наверняка есть любители. Поэтому, если нечто подобное:
для вас как два пальца…, можете пропустить этот пункт. Для всех остальных Regex Editor от Георгия Лосенкова может помочь. Это ещё один нишевый инструмент, который:
- Помогает редактировать и тестировать регулярные выражения.
- Тестировать основные методы класса Regex: Match, Replace, Split.
- Генерировать образцы кода (C# и VB), используя введённые вами данные.
- Рассматривать входные данные как несколько выборок (по одной выборке в строке)
- Подсвечивать шаблоны, найденные группы и замещающие строки
Короче, это regex101.com внутри вашей студии. На данный момент он был установлен более 8 тысяч раз и имеет идеальные 5 из 5.
8. Telerik Testing Framework от известного производителя множества профессиональных платных инструментов .NET. Но это бесплатная среда для веб-тестирования, разработанная, чтобы помочь вам автоматизировать приложения HTML5, AJAX, Silverlight (помните?) и WPF. Среди достоинств инструмента богатый API, поддержка LINQ, абстракция браузера и другие.
9. Недавно было обновлено популярное расширение SonarLint от SonarSource. Оно использует Roslyn, чтобы помочь пользователям находить и исправлять ошибки и проблемы в файлах C#, VB.Net, C, C++ и JavaScript. В связи с ростом количества правил, которые теперь исчисляются сотнями, оно использует сопоставление с образцом и анализ потока данных для облегчения алгоритмов глубокого анализа кода. Оно даже помогает решить любые обнаруженные проблемы. Есть возможность подключения к серверу SonarQube или SonarCloud для совместного использования наборов правил, получения уведомлений о событиях и т.п.
Источник: https://visualstudiomagazine.com/articles/2021/05/07/testing-tools.aspx
Новые Бесплатные Расширения для VS 2019. Окончание 5-9
Начало 1-4
5. SpecFlow представляет собой комплексное предложение профессионального уровня, в котором есть ссылки на документацию, инструкции по началу работы, часто задаваемые вопросы и политика конфиденциальности. При этом оно по-прежнему бесплатное, и имеет впечатляющие 4,9 из 5. SpecFlow помогает группам разработчиков .NET определять, управлять и выполнять автоматизированные приёмочные тесты в виде удобочитаемых бизнес-ориентированных спецификаций. SpecFlow поддерживает концепции разработки Behavior Driven Development (BDD) и Acceptance Test Driven Development (ATDD). Про BDD и SpecFlow, кстати, есть видео у Nick Chapsas.
6. Azure DevOps Test Connector от MadeUpExtensions работает с вышеупомянутым SpecFlow, поддерживая создание тестов Specflow Scenario Outline. Он позволяет программистам использовать атрибуты для связи с тестовыми классами и файлами функций SpecFlow с планами/наборами тестов и кейсами Azure DevOps. Это позволяет инженеру по автоматизации тестирования быстро синхронизировать свои последние изменения в Visual Studio с Azure DevOps, экономя время за счёт автоматического создания и связывания планов тестирования, наборов тестов (как статических, так и основанных на требованиях).
7. «Обожаю работать со сложными регулярными выражениями» – любят говорить… примерно никто из программистов. Хотя, может, это только мой личный опыт, наверняка есть любители. Поэтому, если нечто подобное:
([^e]|e([^s]|s([^\.]|\.([^c]|c([^o]|o([^m]|m([^p]|p([^\.]|\.([^o]|o([^ +s]|s([^\.]|\.([^l]|l([^i]|i([^n]|n([^u]|u[^x])))))))))))))))
для вас как два пальца…, можете пропустить этот пункт. Для всех остальных Regex Editor от Георгия Лосенкова может помочь. Это ещё один нишевый инструмент, который:
- Помогает редактировать и тестировать регулярные выражения.
- Тестировать основные методы класса Regex: Match, Replace, Split.
- Генерировать образцы кода (C# и VB), используя введённые вами данные.
- Рассматривать входные данные как несколько выборок (по одной выборке в строке)
- Подсвечивать шаблоны, найденные группы и замещающие строки
Короче, это regex101.com внутри вашей студии. На данный момент он был установлен более 8 тысяч раз и имеет идеальные 5 из 5.
8. Telerik Testing Framework от известного производителя множества профессиональных платных инструментов .NET. Но это бесплатная среда для веб-тестирования, разработанная, чтобы помочь вам автоматизировать приложения HTML5, AJAX, Silverlight (помните?) и WPF. Среди достоинств инструмента богатый API, поддержка LINQ, абстракция браузера и другие.
9. Недавно было обновлено популярное расширение SonarLint от SonarSource. Оно использует Roslyn, чтобы помочь пользователям находить и исправлять ошибки и проблемы в файлах C#, VB.Net, C, C++ и JavaScript. В связи с ростом количества правил, которые теперь исчисляются сотнями, оно использует сопоставление с образцом и анализ потока данных для облегчения алгоритмов глубокого анализа кода. Оно даже помогает решить любые обнаруженные проблемы. Есть возможность подключения к серверу SonarQube или SonarCloud для совместного использования наборов правил, получения уведомлений о событиях и т.п.
Источник: https://visualstudiomagazine.com/articles/2021/05/07/testing-tools.aspx
День восемьсот пятьдесят четвёртый. #ЗаметкиНаПолях
Валидация Email и URL в .NET
Существует множество совершенно безумных способов проверки email в .NET. Недавно я наткнулся на войну между двумя разработчиками в пул-реквесте. Война велась вокруг «идеального» регулярного выражения для проверки email.
Посмотрите на этот ответ на Stack Overflow. Регулярное выражение в ответе приведено следующее:
Логика валидации довольно проста:
1. Значение – строка?
2. Есть ли в строке символ
3. Находится ли символ
Всё. Регулярное выражение не требуется!
Это идеальный валидатор? Конечно, нет, и, если он используется в списке рассылки, то письма будут отправляться на адреса, которые не совсем соответствуют спецификации RFC. Однако, такой валидации достаточно, чтобы поймать 99,99% ошибок. Тем более, что, например, при создании учётной записи вы, скорее всего, дополнительно «проверите» email, отправив на него письмо с подтверждением регистрации.
Аналогичный атрибут
Так что в следующий раз, когда люди будут спорить об идеальном регулярном выражении для проверки email или url, рассмотрите вариант вообще не использовать регулярное выражение.
Источник: https://dotnetcoretutorials.com/2021/05/16/validating-an-email-in-a-net-api
Валидация Email и URL в .NET
Существует множество совершенно безумных способов проверки email в .NET. Недавно я наткнулся на войну между двумя разработчиками в пул-реквесте. Война велась вокруг «идеального» регулярного выражения для проверки email.
[email protected]
, что может быть проще? Посмотрите на этот ответ на Stack Overflow. Регулярное выражение в ответе приведено следующее:
(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])Другой пример можно взять из валидации email в Angular. Тут также используется регулярное выражение:
^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$Немного другой, но всё равно гигантский шаблон. Итак, учитывая эти параметры (и, вероятно, многие другие), какое же выражение нам выбрать для валидации нашей модели?
public class CreateAccountViewModelНа самом деле, ни то, ни другое. В .NET Core (и в .NET Framework) есть встроенный валидатор email:
{
[RegularExpression("SoMeCrAzYReGeX")]
public string Email { get; set; }
}
[EmailAddress]Красиво и просто, без лишних сложностей. Но тогда возникает вопрос, какое регулярное выражение использует .NET? Вообще-то тут в принципе не используется регулярное выражение!
public string Email { get; set; }
Логика валидации довольно проста:
1. Значение – строка?
2. Есть ли в строке символ
@
?3. Находится ли символ
@
в любой позиции, кроме первой или последней?Всё. Регулярное выражение не требуется!
Это идеальный валидатор? Конечно, нет, и, если он используется в списке рассылки, то письма будут отправляться на адреса, которые не совсем соответствуют спецификации RFC. Однако, такой валидации достаточно, чтобы поймать 99,99% ошибок. Тем более, что, например, при создании учётной записи вы, скорее всего, дополнительно «проверите» email, отправив на него письмо с подтверждением регистрации.
Аналогичный атрибут
[Url]
для валидации URL, просто проверяет, начинается ли строка с https://
, https://
или ftp://
.Так что в следующий раз, когда люди будут спорить об идеальном регулярном выражении для проверки email или url, рассмотрите вариант вообще не использовать регулярное выражение.
Источник: https://dotnetcoretutorials.com/2021/05/16/validating-an-email-in-a-net-api
День восемьсот пятьдесят пятый. #Оффтоп #КакСтатьСеньором
После некоторого перерыва продолжу серию #КакСтатьСеньором с простыми, но полезными советами.
Написание Кода
1. Legacy-код и следующий разработчик
Вы когда-нибудь смотрели на код и чувствовали, что тут что-то не так? Зачем они так сделали? В этом нет никакого смысла. Я имел счастье работать с устаревшей кодовой базой. С комментариями типа
То же относится к вам. Подумайте о следующем человеке, который прочитает ваш код. Код покажется ему странным? Обзор кода частично решает эту проблему. Это привело меня к идее контекста: осознавать контекст, в котором работает команда.
Если я забуду код, вернусь к нему позже и не смогу воссоздать контекст, в котором был написан код, я подумаю: «Какой дебил это написал? Тут нет никакого смысла… Ой, это же я написал». И здесь на помощь приходит документация и комментарии.
2. Документация и комментарии
Документация – головная боль для большинства команд разработчиков. Не только комментарии, но и описание процессов, связанных с кодом. Но они помогают сохранять контекст и делиться знаниями. Основная ценность программного обеспечения - это не созданный код, а знания, накопленные людьми, которые его создали.
У нас есть конечная точка клиентского API, которую, казалось, никто никогда не использовал. Просто удалим её? В конце концов, это технический долг. А что, если раз в год 10 человек отправляют свои отчёты на эту конечную точку? Как это проверить? Если документации нет, то никак. Мы удалили эту конечную точку. Через несколько месяцев наступило то самое время года. Пользователи не смогли отправить 10 важных отчетов, потому что конечной точки больше не существовала. Люди, знавшие продукт, давно покинули команду. Конечно, теперь в коде есть комментарии, объясняющие, для чего предназначена эта конечная точка.
3. Атомарные коммиты
Если вам придётся откатить ваши изменения (а вам рано или поздно придётся это сделать), что случится с приложением? Атомарен ли ваш коммит? То есть, переводит ли он приложение из одного стабильного состояния в другое (например, проект компилируется и до ваших изменений, и после)?
4. Уверенность в удалении плохого кода
Поначалу мне было очень неловко удалять плохой или устаревший код. Я считал священным то, что когда-то было написано, тем более не мной. Я размышлял так: «Когда это писали, они явно хотели этим что-то сказать». Это традиции и культура против рационального мышления. Отчасти такие мысли подкрепляются случаями, вроде удаления той конечной точки.
Я пытался во что бы то ни стало сохранить код, придумывая костыли для обхода, тогда как сеньор безропотно бы его удалил. Удаляйте. Блок if, который никогда не выполнится, функцию, которую не нужно вызывать. В противном случае вы просто увеличите сложность кода и технический долг. Следующему человеку будет ещё труднее понять, что тут происходит.
Правило: есть код, которого вы не понимаете, и код, который никогда будет достигнут. Удалите код, который не достигается, и будьте осторожны с кодом, который вы не понимаете.
5. Обзоры кода
Обзоры кода великолепны для обучения. Это внешний цикл обратной связи о том, как вы пишете код и как его пишут другие. В чем разница? Один способ лучше другого? Я задавал себе этот вопрос на каждом обзоре: «Почему они сделали это именно так?». Когда я не мог найти подходящего ответа, я приходил поговорить с коллегами.
По прошествии первого месяца я начал замечать ошибки в коде моих коллег (а они замечали мои). Рецензирование стало для меня намного интереснее. Это была игра, которую я с нетерпением ждал. Игра, которая улучшит моё восприятие кода.
Правило: не одобряйте код, пока не поймёте, как он работает.
Источник: https://neilkakkar.com/things-I-learnt-from-a-senior-dev.html
Автор оригинала – Neil Kakkar
После некоторого перерыва продолжу серию #КакСтатьСеньором с простыми, но полезными советами.
Написание Кода
1. Legacy-код и следующий разработчик
Вы когда-нибудь смотрели на код и чувствовали, что тут что-то не так? Зачем они так сделали? В этом нет никакого смысла. Я имел счастье работать с устаревшей кодовой базой. С комментариями типа
//Раскомментировать этот код, когда прояснится ситуация с МухамедомЧто это? Кто такой Мухамед?
То же относится к вам. Подумайте о следующем человеке, который прочитает ваш код. Код покажется ему странным? Обзор кода частично решает эту проблему. Это привело меня к идее контекста: осознавать контекст, в котором работает команда.
Если я забуду код, вернусь к нему позже и не смогу воссоздать контекст, в котором был написан код, я подумаю: «Какой дебил это написал? Тут нет никакого смысла… Ой, это же я написал». И здесь на помощь приходит документация и комментарии.
2. Документация и комментарии
Документация – головная боль для большинства команд разработчиков. Не только комментарии, но и описание процессов, связанных с кодом. Но они помогают сохранять контекст и делиться знаниями. Основная ценность программного обеспечения - это не созданный код, а знания, накопленные людьми, которые его создали.
У нас есть конечная точка клиентского API, которую, казалось, никто никогда не использовал. Просто удалим её? В конце концов, это технический долг. А что, если раз в год 10 человек отправляют свои отчёты на эту конечную точку? Как это проверить? Если документации нет, то никак. Мы удалили эту конечную точку. Через несколько месяцев наступило то самое время года. Пользователи не смогли отправить 10 важных отчетов, потому что конечной точки больше не существовала. Люди, знавшие продукт, давно покинули команду. Конечно, теперь в коде есть комментарии, объясняющие, для чего предназначена эта конечная точка.
3. Атомарные коммиты
Если вам придётся откатить ваши изменения (а вам рано или поздно придётся это сделать), что случится с приложением? Атомарен ли ваш коммит? То есть, переводит ли он приложение из одного стабильного состояния в другое (например, проект компилируется и до ваших изменений, и после)?
4. Уверенность в удалении плохого кода
Поначалу мне было очень неловко удалять плохой или устаревший код. Я считал священным то, что когда-то было написано, тем более не мной. Я размышлял так: «Когда это писали, они явно хотели этим что-то сказать». Это традиции и культура против рационального мышления. Отчасти такие мысли подкрепляются случаями, вроде удаления той конечной точки.
Я пытался во что бы то ни стало сохранить код, придумывая костыли для обхода, тогда как сеньор безропотно бы его удалил. Удаляйте. Блок if, который никогда не выполнится, функцию, которую не нужно вызывать. В противном случае вы просто увеличите сложность кода и технический долг. Следующему человеку будет ещё труднее понять, что тут происходит.
Правило: есть код, которого вы не понимаете, и код, который никогда будет достигнут. Удалите код, который не достигается, и будьте осторожны с кодом, который вы не понимаете.
5. Обзоры кода
Обзоры кода великолепны для обучения. Это внешний цикл обратной связи о том, как вы пишете код и как его пишут другие. В чем разница? Один способ лучше другого? Я задавал себе этот вопрос на каждом обзоре: «Почему они сделали это именно так?». Когда я не мог найти подходящего ответа, я приходил поговорить с коллегами.
По прошествии первого месяца я начал замечать ошибки в коде моих коллег (а они замечали мои). Рецензирование стало для меня намного интереснее. Это была игра, которую я с нетерпением ждал. Игра, которая улучшит моё восприятие кода.
Правило: не одобряйте код, пока не поймёте, как он работает.
Источник: https://neilkakkar.com/things-I-learnt-from-a-senior-dev.html
Автор оригинала – Neil Kakkar
День восемьсот пятьдесят шестой. #юмор
Доброй летней пятницы, дорогие подписчики.
Доброй летней пятницы, дорогие подписчики.
День восемьсот пятьдесят седьмой. #ЗаметкиНаПолях
Настройка Производительности в EF Core
Сегодня посоветую вам видео из серии EF Core Community Standup, посвящённое настройке производительности в Entity Framework. Для знающих SQL, вроде меня, советы могут показаться довольно очевидными, хотя интересно было узнать, что оптимизации можно делать не в SQL, а прямо в LINQ запросе к EF.
Для примера взято приложение книжного магазина. Есть основная сущность Books. Сущности Authors (авторы) и Tags (теги), которые относятся к Books как многие-ко-многим, а сущность Reviews (отзывы и оценки) – один-ко-многим.
Нам для отображения доступных книг нужно выбрать данные книги (название, цена, год публикации), авторов и теги для каждой книги, а также количество отзывов и среднюю оценку.
Очевидным вариантом запроса будет что-то вроде:
1. Добавить метод
2. Не загружать ненужные данные. Используйте проекцию в методе
4. По возможности выполнять вычисления на стороне БД. Например, для количества отзывов и средней оценки (заметьте, что требуется приведение к обнуляемому типу и тип зависит от конкретной СУБД):
Чтобы не загромождать запрос, все эти изменения можно разместить в методе расширения
В видео по ссылке ниже весь процесс оптимизации производительности описан более подробно и наглядно.
Источники:
- Видео https://youtu.be/VgNFFEqwZPU
- Текст https://www.thereformedprogrammer.net/five-levels-of-performance-tuning-for-an-ef-core-query/
Настройка Производительности в EF Core
Сегодня посоветую вам видео из серии EF Core Community Standup, посвящённое настройке производительности в Entity Framework. Для знающих SQL, вроде меня, советы могут показаться довольно очевидными, хотя интересно было узнать, что оптимизации можно делать не в SQL, а прямо в LINQ запросе к EF.
Для примера взято приложение книжного магазина. Есть основная сущность Books. Сущности Authors (авторы) и Tags (теги), которые относятся к Books как многие-ко-многим, а сущность Reviews (отзывы и оценки) – один-ко-многим.
Нам для отображения доступных книг нужно выбрать данные книги (название, цена, год публикации), авторов и теги для каждой книги, а также количество отзывов и среднюю оценку.
Очевидным вариантом запроса будет что-то вроде:
var books = context.BooksКак можно улучшить этот запрос:
.Include(book => book.AuthorsLink
.OrderBy(bookAuthor => bookAuthor.Order))
.ThenInclude(bookAuthor => bookAuthor.Author)
.Include(book => book.Reviews)
.Include(book => book.Tags)
.ToList();
1. Добавить метод
AsNoTracking()
для всех запросов, не предполагающих изменения данных.2. Не загружать ненужные данные. Используйте проекцию в методе
Select
для выбора только нужных полей:Books.Select(p => new BookListDto {3. Не включать зависимости, а выбирать только то, что надо из них. Например, нам нужны только имена авторов через запятую:
Title = p.Title,
Price = p.Price,
Published = p.Published,
…
AuthorsOrdered = string.Join(", ",
p.AuthorsLink.OrderBy(q => q.Order)
.Select(q => q.Author.Name)),
…
String.Join
будет выполняться на клиенте, но можно использовать пользовательские функции SQL (User-Defined Functions).4. По возможности выполнять вычисления на стороне БД. Например, для количества отзывов и средней оценки (заметьте, что требуется приведение к обнуляемому типу и тип зависит от конкретной СУБД):
ReviewsCount = p.Reviews.Count(),5. В конфигурации сущностей EF добавить индексы для каждого свойства сущности, по которому планируется производить сортировку или фильтрацию.
ReviewsAverageVotes =
p.Reviews.Select(y =>
(double?)y.NumStars).Average(),
…
Чтобы не загромождать запрос, все эти изменения можно разместить в методе расширения
MapBookToDto(this IQueryable<Book> books)
, таким образом сам запрос будет выглядеть примерно так:var booksQuery = _context.BooksЕсли эти советы всё равно не дают достаточной производительности, можно, например, денормализовать БД и включить столбцы с рассчитанными значениями количества отзывов и средней оценкой в таблицу Books. А при добавлении/удалении отзыва пересчитывать эти значения.
.AsNoTracking()
.MapBookToDto()
. …
В видео по ссылке ниже весь процесс оптимизации производительности описан более подробно и наглядно.
Источники:
- Видео https://youtu.be/VgNFFEqwZPU
- Текст https://www.thereformedprogrammer.net/five-levels-of-performance-tuning-for-an-ef-core-query/
День восемьсот пятьдесят восьмой. #Оффтоп #97Вещей
97 Вещей, Которые Должен Знать Каждый Программист
87. Две Ошибки Могут «Исправить» Друг Друга (и Это Трудно Обнаружить)
Код никогда не лжёт, но может сам себе противоречить. Иногда такие противоречия могут заставить схватиться за голову и воскликнуть: «Как это вообще может работать?»
В своём интервью главный разработчик ПО лунного модуля Аполлона-11 Аллан Клумпп рассказал, что ПО управления двигателями, содержало ошибку, которая должна была сделать посадочный модуль нестабильным. Однако эта ошибка компенсировалась другой, и ПО использовалось как для посадки на Луну, так и для Аполлона-11, прежде чем была обнаружена или исправлена.
Рассмотрим функцию, возвращающую статус завершения задачи. Представьте, что она возвращает
Или, например приложение, которое сериализует и сохраняет своё состояние для дальнейшего чтения и использования. Представьте, что одно из свойств неправильно названо как
Когда два дефекта в коде создают одну видимую ошибку, стандартный подход к исправлению ошибок может потерпеть неудачу. Разработчик получает отчёт об ошибке, находит дефект, исправляет его и повторно тестирует. Однако неисправность всё равно проявляется, потому что работает второй дефект. В итоге первое исправление удаляется и код анализируется дальше, пока не будет обнаружен второй дефект. Он исправляется, но из-за отмены исправления первого дефекта ошибка всё ещё проявляется, поэтому и второе исправление откатывается. Процесс повторяется, но теперь разработчик отклонил два возможных исправления, и пытается найти третий дефект, которого в реальности не существует…
Взаимодействие между двумя дефектами кода, которые проявляются как одна видимая ошибка, не только затрудняет решение проблемы, но и ведёт разработчиков в тупик, в котором, при благоприятном исходе, они могут обнаружить, что они пробовали правильные решения на раннем этапе.
Это происходит не только в коде: проблема также существует в документации и требованиях. И она может вирусно распространяться из одного места в другое. Ошибка в коде может компенсировать ошибку в документации.
Это также может распространяться на людей: пользователи узнают, что когда приложение говорит: «Налево», - это означает «Направо», поэтому они корректируют своё поведение соответствующим образом. Они даже передают этот опыт новым пользователям: «Помните, когда в приложении говорится «нажмите стрелку влево», это на самом деле означает «стрелку вправо». Исправьте ошибку - и пользователям потребуется переобучение.
Одиночные ошибки можно легко обнаружить и легко исправить. Труднее решить проблемы со множеством причин, требующие множественных изменений. Отчасти это связано с тем, что простые проблемы так легко решаются, что люди склонны решать их относительно быстро, а более сложные проблемы откладывают на потом.
Не существует простых советов, как устранять недостатки, возникающие из-за множественных проблем. Необходимо осознавать вероятность такого случая, ясно мыслить и быть готовым рассмотреть все возможные варианты.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly
97 Вещей, Которые Должен Знать Каждый Программист
87. Две Ошибки Могут «Исправить» Друг Друга (и Это Трудно Обнаружить)
Код никогда не лжёт, но может сам себе противоречить. Иногда такие противоречия могут заставить схватиться за голову и воскликнуть: «Как это вообще может работать?»
В своём интервью главный разработчик ПО лунного модуля Аполлона-11 Аллан Клумпп рассказал, что ПО управления двигателями, содержало ошибку, которая должна была сделать посадочный модуль нестабильным. Однако эта ошибка компенсировалась другой, и ПО использовалось как для посадки на Луну, так и для Аполлона-11, прежде чем была обнаружена или исправлена.
Рассмотрим функцию, возвращающую статус завершения задачи. Представьте, что она возвращает
false
, когда должна возвращать true
. Теперь представьте, что вызывающая функция не проверяет возвращаемое значение. Всё работает нормально, пока однажды кто-нибудь не заметит упущенную проверку и не добавит её.Или, например приложение, которое сериализует и сохраняет своё состояние для дальнейшего чтения и использования. Представьте, что одно из свойств неправильно названо как
TimeToLive
, вместо TimeToDie
, как указано в документации. Все выглядит нормально, пока код сериализации и код десериализации содержат одну и ту же ошибку. Но исправьте это в одном месте или добавьте новое приложение, читающее те же данные, и симметрия нарушится, как и работа кода.Когда два дефекта в коде создают одну видимую ошибку, стандартный подход к исправлению ошибок может потерпеть неудачу. Разработчик получает отчёт об ошибке, находит дефект, исправляет его и повторно тестирует. Однако неисправность всё равно проявляется, потому что работает второй дефект. В итоге первое исправление удаляется и код анализируется дальше, пока не будет обнаружен второй дефект. Он исправляется, но из-за отмены исправления первого дефекта ошибка всё ещё проявляется, поэтому и второе исправление откатывается. Процесс повторяется, но теперь разработчик отклонил два возможных исправления, и пытается найти третий дефект, которого в реальности не существует…
Взаимодействие между двумя дефектами кода, которые проявляются как одна видимая ошибка, не только затрудняет решение проблемы, но и ведёт разработчиков в тупик, в котором, при благоприятном исходе, они могут обнаружить, что они пробовали правильные решения на раннем этапе.
Это происходит не только в коде: проблема также существует в документации и требованиях. И она может вирусно распространяться из одного места в другое. Ошибка в коде может компенсировать ошибку в документации.
Это также может распространяться на людей: пользователи узнают, что когда приложение говорит: «Налево», - это означает «Направо», поэтому они корректируют своё поведение соответствующим образом. Они даже передают этот опыт новым пользователям: «Помните, когда в приложении говорится «нажмите стрелку влево», это на самом деле означает «стрелку вправо». Исправьте ошибку - и пользователям потребуется переобучение.
Одиночные ошибки можно легко обнаружить и легко исправить. Труднее решить проблемы со множеством причин, требующие множественных изменений. Отчасти это связано с тем, что простые проблемы так легко решаются, что люди склонны решать их относительно быстро, а более сложные проблемы откладывают на потом.
Не существует простых советов, как устранять недостатки, возникающие из-за множественных проблем. Необходимо осознавать вероятность такого случая, ясно мыслить и быть готовым рассмотреть все возможные варианты.
Источник: https://www.oreilly.com/library/view/97-things-every/9780596809515/
Автор оригинала – Allan Kelly
День восемьсот пятьдесят девятый. #ЧтоНовенького
.NET 6: Улучшения коллекций. Начало
1. Ёмкость списка, стека и очереди
Перед добавлением большого количества элементов в
Заметным исключением из этой группы является
Это не единственный недостаток
2. Изменяемые структуры и словари
Хотя и редко, разработчикам иногда приходится работать с изменяемыми структурами. Это может вызывать трудности, потому что легко случайно скопировать изменяемую структуру, в результате чего два значения больше не будут синхронизироваться.
Чтобы решить эту проблему, приходилось намеренно копировать структуру, вносить изменения, а затем копировать её обратно в исходное место. Для небольших конструкций это неплохо, но для больших может быть дорого. А так как производительность – чаще всего первопричина использования изменяемых структур, использование этого метода контрпродуктивно.
Чтобы избежать этих ненужных копий, изменяемые структуры обычно хранились в массивах. В отличие от свойства-индексатора в
В C# 7 были введены ссылочные возвращаемые значения (ref return). Это позволило индексаторам возвращать ссылку на объект, а не копию.
Чтобы предложить те же возможности для словарей, была создана новая функция под названием
1. Это не метод расширения. Разработчики опасались, что его будет слишком легко использовать неправильно, поэтому они намеренно сделали так, чтобы его было сложно найти. (Функцию
2. Существует внутренний метод
3. После вызова
Окончание следует…
Источник: https://www.infoq.com/news/2021/06/Net6-Collections/
.NET 6: Улучшения коллекций. Начало
1. Ёмкость списка, стека и очереди
Перед добавлением большого количества элементов в
Dictionary
или HashSet
полезно вызвать EnsureCapacity
с ожидаемым размером коллекции. Это позволяет коллекции выполнить одну операцию изменения размера заранее, избегая необходимости делать это несколько раз. Метод EnsureCapacity
был добавлен в классы List<T>
, Stack<T>
и Queue<T>
, также для повышения производительности.Заметным исключением из этой группы является
Collection<T>
. В отличие от других коллекций, Collection<T>
может при желании обернуть другую коллекцию, которая не обязательно предоставляет метод EnsureCapacity
. Её потомок, ObservableCollection<T>
, также не может предоставить метод EnsureCapacity
.Это не единственный недостаток
Collection<T>
и ObservableCollection<T>
. Отсутствие метода AddRange
давно раздражало разработчиков. А также им не хватает высокопроизводительного IEnumerator
на основе структур, который предлагает List<T>
.2. Изменяемые структуры и словари
Хотя и редко, разработчикам иногда приходится работать с изменяемыми структурами. Это может вызывать трудности, потому что легко случайно скопировать изменяемую структуру, в результате чего два значения больше не будут синхронизироваться.
Чтобы решить эту проблему, приходилось намеренно копировать структуру, вносить изменения, а затем копировать её обратно в исходное место. Для небольших конструкций это неплохо, но для больших может быть дорого. А так как производительность – чаще всего первопричина использования изменяемых структур, использование этого метода контрпродуктивно.
Чтобы избежать этих ненужных копий, изменяемые структуры обычно хранились в массивах. В отличие от свойства-индексатора в
List<T>
, доступ к элементам массива осуществляется напрямую.В C# 7 были введены ссылочные возвращаемые значения (ref return). Это позволило индексаторам возвращать ссылку на объект, а не копию.
public ref int this[int index] {Этот метод используется структурой
get { return ref _internalArray[index]; }
}
Span<T>
, начиная с .NET Core 2.1. Начиная с .NET 5, метод CollectionsMarshal.AsSpan
позволяет легко получить span-обёртку коллекции.Чтобы предложить те же возможности для словарей, была создана новая функция под названием
CollectionsMarshal.GetValueRefOrNullRef
. Есть несколько интересных фактов об этой функции:1. Это не метод расширения. Разработчики опасались, что его будет слишком легко использовать неправильно, поэтому они намеренно сделали так, чтобы его было сложно найти. (Функцию
AsSpan
также потенциально небезопасно использовать, поскольку размеры коллекции не могут быть изменены, пока существует Span<T>
.)2. Существует внутренний метод
Dictionary<TKey, TValue>.FindValue
. Он и используется в GetValueRefOrNullRef
:public static ref TValueFindValue сам по себе использует некоторые методы, которые не распространены в программировании на C#, вроде
GetValueRefOrNullRef<TKey, TValue>
(Dictionary<TKey, TValue> dictionary, TKey key)
where TKey : notnull
=> ref dictionary.FindValue(key);
goto
, включая обратные переходы.3. После вызова
GetValueRefOrNullRef
нужно использовать CompilerServices.Unsafe.IsNullRef
, чтобы проверить, является ли результат ссылкой на фактическое значение или на null
. Это связано с тем, что в C# нет синтаксиса для проверки того, является ли ссылка на структуру нулевой.Окончание следует…
Источник: https://www.infoq.com/news/2021/06/Net6-Collections/
День восемьсот шестидесятый. #ЧтоНовенького
.NET 6: Улучшения коллекций. Окончание
3. Улучшения сериализации для словарей
В то время как сериализация списочных коллекций довольно проста, коллекции, для которых требуется компонент хеширования, такие как
Поскольку подавляющее большинство этих проблем связано со строковыми ключами, было решено добавить два новых метода в
Однако это не полное решение. Поскольку ни XML, ни JSON не позволяют связывать свойства с коллекциями, сериализаторам всё равно нужно будет определять собственный способ хранения информации.
4. Очередь с приоритетом
Новый класс
Для
Чтобы гарантировать, что приоритет не может быть изменён, он хранится в очереди отдельно от объекта:
Ещё вопрос: разрешить ли перечисление очереди. На первый взгляд он может показаться странным. Почему бы не использовать
Первая проблема - это подразумеваемый контракт для
Можно сделать перечислитель неразрушающим, но в этом есть свои проблемы. Внутренне приоритетная очередь не обязательно упорядочена. Это означает, что перечислитель должен будет отслеживать, какие элементы он уже видел. Если по какой-то причине вам понадобится запустить несколько перечислений одновременно, каждый, по идее должен был бы получить полную копию очереди.
Таким образом, было решено, что класс
Если вы действительно хотите использовать
.NET 6: Улучшения коллекций. Окончание
3. Улучшения сериализации для словарей
В то время как сериализация списочных коллекций довольно проста, коллекции, для которых требуется компонент хеширования, такие как
Dictionary
и HashSet
, создают дополнительные проблемы. Одна из таких проблем - необходимость сериализации не только содержимого, но и используемого алгоритма сравнения. Чтобы десериализатор знал, должен ли он создавать коллекцию с порядковым компаратором, зависящим от языка и региональных параметров и чувствительным или нечувствительным к регистру.Поскольку подавляющее большинство этих проблем связано со строковыми ключами, было решено добавить два новых метода в
StringComparer
:public static bool IsWellKnownOrdinalComparer(Проверяя результат этих функций, сериализатор может собрать необходимую информацию для последующей десериализации. Хотя методы не охватывают всех сценариев, редко можно встретить настолько специализарованный компаратор, не основанный на известной культуре.
IEqualityComparer<string?>? comparer,
out bool ignoreCase);
public static bool IsWellKnownCultureAwareComparer(
IEqualityComparer<string?>? comparer,
[NotNullWhen(true)] out CompareInfo? compareInfo,
out CompareOptions compareOptions);
Однако это не полное решение. Поскольку ни XML, ни JSON не позволяют связывать свойства с коллекциями, сериализаторам всё равно нужно будет определять собственный способ хранения информации.
4. Очередь с приоритетом
Новый класс
PriorityQueue
разработан для сценариев, когда разработчику нужна очередь, в которой элементы помещаются в список на основе значения приоритета. Это можно реализовать несколькими способами, многие из которых зависят от вопроса: «Можно ли изменять приоритет элемента?».Для
PriorityQueue
было решено не допускать изменения приоритета. Создатели определили, что фиксированное значение приоритета приведёт к 2-3-кратному улучшению производительности.Чтобы гарантировать, что приоритет не может быть изменён, он хранится в очереди отдельно от объекта:
public void Enqueue(TElement element, TPriority priority);Следующий вопрос - стабильность. Если вы добавляете в очередь два элемента с одинаковым приоритетом, и они гарантированно извлекаются из очереди в том же порядке, то очередь считается стабильной. В .NET решили не предоставлять стабильную очередь, опять же во имя быстродействия.
Ещё вопрос: разрешить ли перечисление очереди. На первый взгляд он может показаться странным. Почему бы не использовать
foreach
для очереди?Первая проблема - это подразумеваемый контракт для
IEnumerable
. Большинство разработчиков предполагают, что вы можете дважды перечислить одну и ту же коллекцию и оба раза получить одинаковый результат. Это предположение встроено в общие шаблоны, где не всегда очевидно, что перечисление вообще происходит. Например, вызов метода Count()
может перечислить элементы, что приведёт к опустошению очереди. Что означает, что вызванный после этого foreach
увидит пустую очередь.Можно сделать перечислитель неразрушающим, но в этом есть свои проблемы. Внутренне приоритетная очередь не обязательно упорядочена. Это означает, что перечислитель должен будет отслеживать, какие элементы он уже видел. Если по какой-то причине вам понадобится запустить несколько перечислений одновременно, каждый, по идее должен был бы получить полную копию очереди.
Таким образом, было решено, что класс
PriorityQueue
не будет реализовывать IEnumerable<T>
. Это, в свою очередь, означает, что он также не может реализовать ICollection<T>
или другие подобные интерфейсы.Если вы действительно хотите использовать
PriorityQueue
в foreach
, можно добавить метод расширения:public static IEnumerable<TElement>Источник: https://www.infoq.com/news/2021/06/Net6-Collections/
GetDequeuingEnumerator<TElement, TPriority>(
this PriorityQueue<TElement, TPriority> queue)
{
while (queue.TryDequeue(out var item))
yield return item;
}
День восемьсот шестьдесят первый.
5 Инструментов для Обнаружения и Устранения Уязвимостей в Безопасности
Сканирование зависимостей
Своевременное обновление зависимостей - один из самых лёгких способов предотвращения уязвимостей в вашем коде.
1. Dependabot
Эта утилита GitHub имеет простой и понятный рабочий процесс: автоматически создаёт пулл реквесты для новых версий зависимостей и предупреждает об уязвимостях в зависимостях.
Dependabot позволяет настраивать частоту обновлений, метки, рецензентов и сообщения для коммитов, а также позволяет исключить зависимости, которые могут иметь критические изменения и конфликты при слиянии.
Включить обновления зависимостей можно в вашем репозитории на Github. Зайдите в Настройки > Безопасность и Анализ (Settings > Security & Analysis) и включите Обновления безопасности Dependabot (Dependabot security updates).
2. Renovate
Как и Dependabot, Renovate - это приложение GitHub, которое отслеживает ваши зависимости и открывает пул реквесты при появлении обновлений.
Главное преимущество Renovate в том, что он чрезвычайно настраиваемый. Он поддерживает обновления по расписанию, а также автоматическое слияние на основе правил, установленных в конфигурации.
Renovate также позволяет группировать обновления зависимостей в один пул реквест, а не создавать отдельные, что может значительно снизить трудозатраты для команды.
Анализаторы кода
3. Snyk
Synk - платный продукт, но в личных проектах его можно использовать бесплатно. Это, по сути, набор продуктов для поиска и устранения уязвимостей в ваших зависимостях, коде и контейнерах.
Snyk использует семантический анализ для обнаружения ошибок безопасности и производительности. И в создаваемом им отчете для каждой уязвимости вы получите классификатор серьёзности, подробное объяснение проблемы, анализ исправления и способы предотвращения ошибки в будущем.
4. GitGuardian
GitGuardian - это, по сути, сервис для автоматического обнаружения и исправления секретной информации в вашем коде. Он интегрируется с Github и работает как с общедоступными, так и с частными репозиториями. GitGuarding также может быть интегрирован с рабочим процессом CI/CD для получения обратной связи по каждому коммиту. Еще одна важная функция - это интеграция со Slack/Discord, PagerDuty, которая позволяет разработчикам оставаться в курсе предупреждений системы безопасности.
5. Webhint
Webhint - это настраиваемый инструмент линтинга с открытым исходным кодом, который помогает улучшить доступность вашего сайта, скорость, кроссбраузерность, безопасность и т.д.
Источник: https://dev.to/opinionatedpie/5-developer-tools-for-detecting-and-fixing-security-vulnerabilities-h1j
5 Инструментов для Обнаружения и Устранения Уязвимостей в Безопасности
Сканирование зависимостей
Своевременное обновление зависимостей - один из самых лёгких способов предотвращения уязвимостей в вашем коде.
1. Dependabot
Эта утилита GitHub имеет простой и понятный рабочий процесс: автоматически создаёт пулл реквесты для новых версий зависимостей и предупреждает об уязвимостях в зависимостях.
Dependabot позволяет настраивать частоту обновлений, метки, рецензентов и сообщения для коммитов, а также позволяет исключить зависимости, которые могут иметь критические изменения и конфликты при слиянии.
Включить обновления зависимостей можно в вашем репозитории на Github. Зайдите в Настройки > Безопасность и Анализ (Settings > Security & Analysis) и включите Обновления безопасности Dependabot (Dependabot security updates).
2. Renovate
Как и Dependabot, Renovate - это приложение GitHub, которое отслеживает ваши зависимости и открывает пул реквесты при появлении обновлений.
Главное преимущество Renovate в том, что он чрезвычайно настраиваемый. Он поддерживает обновления по расписанию, а также автоматическое слияние на основе правил, установленных в конфигурации.
Renovate также позволяет группировать обновления зависимостей в один пул реквест, а не создавать отдельные, что может значительно снизить трудозатраты для команды.
Анализаторы кода
3. Snyk
Synk - платный продукт, но в личных проектах его можно использовать бесплатно. Это, по сути, набор продуктов для поиска и устранения уязвимостей в ваших зависимостях, коде и контейнерах.
Snyk использует семантический анализ для обнаружения ошибок безопасности и производительности. И в создаваемом им отчете для каждой уязвимости вы получите классификатор серьёзности, подробное объяснение проблемы, анализ исправления и способы предотвращения ошибки в будущем.
4. GitGuardian
GitGuardian - это, по сути, сервис для автоматического обнаружения и исправления секретной информации в вашем коде. Он интегрируется с Github и работает как с общедоступными, так и с частными репозиториями. GitGuarding также может быть интегрирован с рабочим процессом CI/CD для получения обратной связи по каждому коммиту. Еще одна важная функция - это интеграция со Slack/Discord, PagerDuty, которая позволяет разработчикам оставаться в курсе предупреждений системы безопасности.
5. Webhint
Webhint - это настраиваемый инструмент линтинга с открытым исходным кодом, который помогает улучшить доступность вашего сайта, скорость, кроссбраузерность, безопасность и т.д.
Источник: https://dev.to/opinionatedpie/5-developer-tools-for-detecting-and-fixing-security-vulnerabilities-h1j
День восемьсот шестьдесят второй. #Оффтоп #КакСтатьСеньором
Тестирование
Я настолько полюбил тестирование, что мне неловко писать код без тестов.
Если ваше приложение выполняет всего одну задачу (как школьная лабораторная работа), то ручное тестирование ещё приемлемо. Раньше я так и делал. А что, если приложение выполняет сотню различных действий? Я не хочу тратить полчаса на тестирование всего функционала, а иногда и забывать, что мне нужно проверить.
Я думаю о тестировании как о документировании. Это документация, подтверждающая мои предположения о коде. Тесты говорят мне, что я ожидаю от работы кода, и сообщают мне обо всех случаях, когда что-то идёт не так.
Итак, когда я пишу тесты, я:
1. Демонстрирую, как использовать класс/функцию/систему, которую я тестирую.
2. Демонстрирую всё, что может пойти не так.
3. В большинстве случаев тестирую поведение (публичный API), а не реализацию.
Всё, что я пропустил в п. 2, – это источники ошибок. Поэтому, всякий раз, когда я обнаруживаю ошибку, я убеждаюсь, что исправление кода имеет соответствующий тест, чтобы задокументировать: «вот ещё один способ, как что-то может пойти не так».
Просто написание этих тестов не улучшает качество моего кода, в отличие от написания самого кода. Но понимание, которое я получаю от чтения тестов, помогает мне писать лучший код.
Но это не единственный вид тестирования.
Есть машины, на которых вы разрабатываете (источник всех мемов «Оно работает на моей машине!»). Есть машины, на которых вы тестируете (зачастую, это те же машины для разработки). И наконец, есть машины, на которых вы развёртываете приложение. Если существует несоответствие среды между тестовой и производственной машинами, у вас будут проблемы.
У нас есть локальная разработка, например, в докере на машине разработчика. Есть среда разработки, где установлен набор библиотек (и инструментов разработки). Туда мы устанавливаем код, который мы пишем, и там же проводим все тесты с другими зависимыми системами. Затем идёт среда бета (staging), которая в точности совпадает с производственной средой. Наконец, производственная среда, состоящая из машин, на которых выполняется код и обслуживает реальных клиентов.
Идея состоит в том, чтобы попытаться выявить ошибки, которые не удалось бы выявить при модульном и системном тестировании. Например, несоответствие API запрашивающей и отвечающей системы.
Думаю, всё было бы по-другому в личном проекте или в небольшой компании. Не у всех есть ресурсы для создания собственной инфраструктуры. Однако эта идея актуальна для облачных провайдеров, таких как AWS и Azure.
Вы можете настроить отдельные кластеры для разработки и производственной среды. AWS ECS использует для развёртывания образы докеров, поэтому в разных средах всё относительно единообразно. Сложность - это интеграция с другими облачными сервисами: вызывать нужную конечную точку из правильной среды.
Источник: https://neilkakkar.com/things-I-learnt-from-a-senior-dev.html
Автор оригинала – Neil Kakkar
Тестирование
Я настолько полюбил тестирование, что мне неловко писать код без тестов.
Если ваше приложение выполняет всего одну задачу (как школьная лабораторная работа), то ручное тестирование ещё приемлемо. Раньше я так и делал. А что, если приложение выполняет сотню различных действий? Я не хочу тратить полчаса на тестирование всего функционала, а иногда и забывать, что мне нужно проверить.
Я думаю о тестировании как о документировании. Это документация, подтверждающая мои предположения о коде. Тесты говорят мне, что я ожидаю от работы кода, и сообщают мне обо всех случаях, когда что-то идёт не так.
Итак, когда я пишу тесты, я:
1. Демонстрирую, как использовать класс/функцию/систему, которую я тестирую.
2. Демонстрирую всё, что может пойти не так.
3. В большинстве случаев тестирую поведение (публичный API), а не реализацию.
Всё, что я пропустил в п. 2, – это источники ошибок. Поэтому, всякий раз, когда я обнаруживаю ошибку, я убеждаюсь, что исправление кода имеет соответствующий тест, чтобы задокументировать: «вот ещё один способ, как что-то может пойти не так».
Просто написание этих тестов не улучшает качество моего кода, в отличие от написания самого кода. Но понимание, которое я получаю от чтения тестов, помогает мне писать лучший код.
Но это не единственный вид тестирования.
Есть машины, на которых вы разрабатываете (источник всех мемов «Оно работает на моей машине!»). Есть машины, на которых вы тестируете (зачастую, это те же машины для разработки). И наконец, есть машины, на которых вы развёртываете приложение. Если существует несоответствие среды между тестовой и производственной машинами, у вас будут проблемы.
У нас есть локальная разработка, например, в докере на машине разработчика. Есть среда разработки, где установлен набор библиотек (и инструментов разработки). Туда мы устанавливаем код, который мы пишем, и там же проводим все тесты с другими зависимыми системами. Затем идёт среда бета (staging), которая в точности совпадает с производственной средой. Наконец, производственная среда, состоящая из машин, на которых выполняется код и обслуживает реальных клиентов.
Идея состоит в том, чтобы попытаться выявить ошибки, которые не удалось бы выявить при модульном и системном тестировании. Например, несоответствие API запрашивающей и отвечающей системы.
Думаю, всё было бы по-другому в личном проекте или в небольшой компании. Не у всех есть ресурсы для создания собственной инфраструктуры. Однако эта идея актуальна для облачных провайдеров, таких как AWS и Azure.
Вы можете настроить отдельные кластеры для разработки и производственной среды. AWS ECS использует для развёртывания образы докеров, поэтому в разных средах всё относительно единообразно. Сложность - это интеграция с другими облачными сервисами: вызывать нужную конечную точку из правильной среды.
Источник: https://neilkakkar.com/things-I-learnt-from-a-senior-dev.html
Автор оригинала – Neil Kakkar
День восемьсот шестьдесят третий. #ЗаметкиНаПолях
Почему ASP.NET Приложение Такое Медленное? 10 Проблем с Производительностью и Их Решения
Проблемы с производительностью сервера могут возникать по разным причинам. Проблемы с памятью, медленные запросы к базе данных и слишком мало машин - вот лишь некоторые из них. В этой серии постов расскажу о 10 типах проблем, которые могут снижать производительность вашего сервера.
1. Медленные вызовы базы данных
Быстрое взаимодействие БД, вероятно, самое важное условие для хорошей производительности. По крайней мере, в большинстве приложений. К сожалению, есть много вещей, которые могут пойти не так, и даже невинно выглядящие реализации могут вызывать проблемы. Вот некоторые проблемы, которые могут приводить к медленным запросам к БД и снижать производительность вашего приложения:
- Плохой дизайн схемы
- Плохая стратегия индексации и выполнение действий в приложении, а не в БД (см. производительность в EF Core).
- БД находится далеко от сервера.
Лучше всего разместить БД географически близко к вашим серверам, оптимально в том же центре обработки данных.
- Использование БД способом, для которого она не была создана.
Не все базы данных одинаковы. Некоторые из них идеально подходят для хранения пар «ключ-значение», другие - для транзакций, третьи по-прежнему идеально подходят для хранения журналов. Используйте лучшую БД для ваших нужд. Например, документоориентированная БД, вроде MongoDB, плохо справляется с операциями JOIN, и их использование может снизить производительность. Но она отлично подходит для хранения документов с большим количеством данных. Таким образом, одним из решений может быть дублирование информации между документами вместо использования
- У БД недостаточно ресурсов.
Хотя очевидным решением будет масштабирование ваших серверов, не забывайте, что и базы данных должны масштабироваться. Например, в Azure SQL Server вам нужно будет следить за DTU (единицами транзакций базы данных). В других БД вам нужно следить за хранилищем, оперативной памятью, сетью и процессором. И не всегда система ясно предупреждает, когда вы приближаетесь к пределу. Всё просто начинает замедляться, и вы задаётесь вопросом, что, чёрт возьми, происходит.
- Неэффективные запросы всегда возможны. Если вы используете Entity Framework, сгенерированный SQL не всегда оптимален.
- Требуется каждый раз восстанавливать соединение. Если ваши соединения с БД не объединены в пул должным образом, возможно, соединение пересоздаётся для каждого запроса.
- Рассмотрите хранимые процедуры, когда сложный запрос занимает много времени.
- Плохая стратегия сегментирования.
Позаботьтесь о том, чтобы сгруппировать связанные данные в одном сегменте, иначе вы рискуете запрашивать несколько сегментов в одном запросе.
Самая сложная часть решения этих проблем - это изначально их идентифицировать. Есть много инструментов, чтобы увидеть, как ваши запросы работают в производственной среде. Обычно сама база данных может отображать отчёты о медленных запросах, проблемах с масштабированием, достижение сетью своих пределов и т.д. Решения вроде Application Insights очень хорошо это показывают. Также довольно просто добавить время выполнения запроса в журналы и автоматизировать отчёты на их основе.
Продолжение следует…
Источник: https://michaelscodingspot.com/slow-asp-net-server/
Почему ASP.NET Приложение Такое Медленное? 10 Проблем с Производительностью и Их Решения
Проблемы с производительностью сервера могут возникать по разным причинам. Проблемы с памятью, медленные запросы к базе данных и слишком мало машин - вот лишь некоторые из них. В этой серии постов расскажу о 10 типах проблем, которые могут снижать производительность вашего сервера.
1. Медленные вызовы базы данных
Быстрое взаимодействие БД, вероятно, самое важное условие для хорошей производительности. По крайней мере, в большинстве приложений. К сожалению, есть много вещей, которые могут пойти не так, и даже невинно выглядящие реализации могут вызывать проблемы. Вот некоторые проблемы, которые могут приводить к медленным запросам к БД и снижать производительность вашего приложения:
- Плохой дизайн схемы
- Плохая стратегия индексации и выполнение действий в приложении, а не в БД (см. производительность в EF Core).
- БД находится далеко от сервера.
Лучше всего разместить БД географически близко к вашим серверам, оптимально в том же центре обработки данных.
- Использование БД способом, для которого она не была создана.
Не все базы данных одинаковы. Некоторые из них идеально подходят для хранения пар «ключ-значение», другие - для транзакций, третьи по-прежнему идеально подходят для хранения журналов. Используйте лучшую БД для ваших нужд. Например, документоориентированная БД, вроде MongoDB, плохо справляется с операциями JOIN, и их использование может снизить производительность. Но она отлично подходит для хранения документов с большим количеством данных. Таким образом, одним из решений может быть дублирование информации между документами вместо использования
JOIN
.- У БД недостаточно ресурсов.
Хотя очевидным решением будет масштабирование ваших серверов, не забывайте, что и базы данных должны масштабироваться. Например, в Azure SQL Server вам нужно будет следить за DTU (единицами транзакций базы данных). В других БД вам нужно следить за хранилищем, оперативной памятью, сетью и процессором. И не всегда система ясно предупреждает, когда вы приближаетесь к пределу. Всё просто начинает замедляться, и вы задаётесь вопросом, что, чёрт возьми, происходит.
- Неэффективные запросы всегда возможны. Если вы используете Entity Framework, сгенерированный SQL не всегда оптимален.
- Требуется каждый раз восстанавливать соединение. Если ваши соединения с БД не объединены в пул должным образом, возможно, соединение пересоздаётся для каждого запроса.
- Рассмотрите хранимые процедуры, когда сложный запрос занимает много времени.
- Плохая стратегия сегментирования.
Позаботьтесь о том, чтобы сгруппировать связанные данные в одном сегменте, иначе вы рискуете запрашивать несколько сегментов в одном запросе.
Самая сложная часть решения этих проблем - это изначально их идентифицировать. Есть много инструментов, чтобы увидеть, как ваши запросы работают в производственной среде. Обычно сама база данных может отображать отчёты о медленных запросах, проблемах с масштабированием, достижение сетью своих пределов и т.д. Решения вроде Application Insights очень хорошо это показывают. Также довольно просто добавить время выполнения запроса в журналы и автоматизировать отчёты на их основе.
Продолжение следует…
Источник: https://michaelscodingspot.com/slow-asp-net-server/