День 1768. #Карьера
Пишем Код, как Сеньор
Самое неприятное для разработчика — усердно поработать над какой-то функцией и через некоторое время обнаружить, что кто-то не понял ваш код и переписал его. Кроме того, это одна из самых больших трат времени во многих проектах - переписывание кода, который уже работает, просто чтобы удовлетворить чьи-то предпочтения. Вот несколько привычек, которые позволят вам писать код, как сеньор.
1. Завершите работу, прежде чем двигаться дальше.
Часто вы можете оказаться в ситуации, когда время поджимает, работа на 90% готова, и возникает желание отложить оставшееся на потом. Но так вы накапливаете для себя технический долг. Возможно, только вы об этом знаете, но рано или поздно другие тоже узнают. Лучше честно сказать, что вы ещё не закончили. Если руководство разочаровано, пусть лучше они знают реальное состояние проекта вместо того, чтобы ваша ложь выяснилась на более поздних этапах. Кто-то другой будет просматривать ваш код в будущем. И вас будут оценивать, глядя на ваш код. Лучше убедиться, что вы действительно закончили работу – это одна из главных отличительных черт сеньора.
2. Соблюдайте стандарты кодирования.
Сегодня большинство IDE могут форматировать код (например, editorconfig для Visual Studio). Если в вашей IDE этого нет, найдите утилиту или плагин. Ничто не разочаровывает больше в кодовой базе, чем обнаружить разные стили написания кода в разных местах. Имеет смысл создать стандарт для команды, либо использовать какой-то готовый, и договориться его придерживаться.
3. Дисциплинированно документируйте шаблоны.
Многие команды, начиная проект, договариваются о наборе шаблонов/библиотек и приступают к работе. Не полагайтесь на самодокументирующийся код, а потратьте время на фактическую документацию шаблонов и решений, которые вы приняли в проекте. Тогда, если вы при обзоре кода обнаружите, что разработчик использует другой шаблон, у вас не будет дебатов на тему, нужен он или нет, - вы сможете сослаться на документ. Также, если вы используете шаблон, который уже является частью фреймворка или языка, добавьте ссылку на документацию, где объясняется, как его использовать, чтобы остальные не гуглили, а имели именно тот пример, который использовали вы. Если вы собираетесь добавить новый шаблон, сначала обсудите это с командой. Возможно, кто-то раньше его уже рассматривал, и отказался от него по каким-то причинам. Не останавливайтесь на устном обсуждении. Задокументируйте цель шаблона, когда его использовать, а когда нет, и несколько примеров кода его применения в распространённых сценариях.
4. Не создавайте тикет для рефакторинга.
Всё, что вы добавляете, как тикет, который может видеть руководство, может быть исключено из спринта. Качество кода — это то, за что мы, разработчики, отвечаем. Как профессионалы мы должны защищать наш проект от неверных решений руководства. Если требуется рефакторинг, не останавливайте другую работу, чтобы его провести. Договоритесь с командой о том, как распределить его по всей команде и провести поэтапно. Это действительно ценный навык. Каждый раз при реализации новой функции добавьте какое-то время, чтобы создать её, используя новый шаблон, а также провести рефакторинг одной-двух других функций.
5. Планируйте непредвиденные обстоятельства.
Когда вас просят оценить время, необходимое на работу, добавьте время на неожиданности. Иногда, когда вы пишете реализацию функции, может выясниться какой-то нюанс, и чтобы соответствовать требованиям, нужно изменить шаблон или добавить новую документацию. Худшее в этой ситуации —вернуться к менеджеру проекта и сказать, что вам нужно больше времени. Это почти гарантирует, что в будущем менеджер будет контролировать каждый ваш шаг. Поэтому всегда выделяйте себе дополнительное время не только на неожиданности, но и для написания документации.
Источник: https://youtu.be/oJbfMBROEO0
Пишем Код, как Сеньор
Самое неприятное для разработчика — усердно поработать над какой-то функцией и через некоторое время обнаружить, что кто-то не понял ваш код и переписал его. Кроме того, это одна из самых больших трат времени во многих проектах - переписывание кода, который уже работает, просто чтобы удовлетворить чьи-то предпочтения. Вот несколько привычек, которые позволят вам писать код, как сеньор.
1. Завершите работу, прежде чем двигаться дальше.
Часто вы можете оказаться в ситуации, когда время поджимает, работа на 90% готова, и возникает желание отложить оставшееся на потом. Но так вы накапливаете для себя технический долг. Возможно, только вы об этом знаете, но рано или поздно другие тоже узнают. Лучше честно сказать, что вы ещё не закончили. Если руководство разочаровано, пусть лучше они знают реальное состояние проекта вместо того, чтобы ваша ложь выяснилась на более поздних этапах. Кто-то другой будет просматривать ваш код в будущем. И вас будут оценивать, глядя на ваш код. Лучше убедиться, что вы действительно закончили работу – это одна из главных отличительных черт сеньора.
2. Соблюдайте стандарты кодирования.
Сегодня большинство IDE могут форматировать код (например, editorconfig для Visual Studio). Если в вашей IDE этого нет, найдите утилиту или плагин. Ничто не разочаровывает больше в кодовой базе, чем обнаружить разные стили написания кода в разных местах. Имеет смысл создать стандарт для команды, либо использовать какой-то готовый, и договориться его придерживаться.
3. Дисциплинированно документируйте шаблоны.
Многие команды, начиная проект, договариваются о наборе шаблонов/библиотек и приступают к работе. Не полагайтесь на самодокументирующийся код, а потратьте время на фактическую документацию шаблонов и решений, которые вы приняли в проекте. Тогда, если вы при обзоре кода обнаружите, что разработчик использует другой шаблон, у вас не будет дебатов на тему, нужен он или нет, - вы сможете сослаться на документ. Также, если вы используете шаблон, который уже является частью фреймворка или языка, добавьте ссылку на документацию, где объясняется, как его использовать, чтобы остальные не гуглили, а имели именно тот пример, который использовали вы. Если вы собираетесь добавить новый шаблон, сначала обсудите это с командой. Возможно, кто-то раньше его уже рассматривал, и отказался от него по каким-то причинам. Не останавливайтесь на устном обсуждении. Задокументируйте цель шаблона, когда его использовать, а когда нет, и несколько примеров кода его применения в распространённых сценариях.
4. Не создавайте тикет для рефакторинга.
Всё, что вы добавляете, как тикет, который может видеть руководство, может быть исключено из спринта. Качество кода — это то, за что мы, разработчики, отвечаем. Как профессионалы мы должны защищать наш проект от неверных решений руководства. Если требуется рефакторинг, не останавливайте другую работу, чтобы его провести. Договоритесь с командой о том, как распределить его по всей команде и провести поэтапно. Это действительно ценный навык. Каждый раз при реализации новой функции добавьте какое-то время, чтобы создать её, используя новый шаблон, а также провести рефакторинг одной-двух других функций.
5. Планируйте непредвиденные обстоятельства.
Когда вас просят оценить время, необходимое на работу, добавьте время на неожиданности. Иногда, когда вы пишете реализацию функции, может выясниться какой-то нюанс, и чтобы соответствовать требованиям, нужно изменить шаблон или добавить новую документацию. Худшее в этой ситуации —вернуться к менеджеру проекта и сказать, что вам нужно больше времени. Это почти гарантирует, что в будущем менеджер будет контролировать каждый ваш шаг. Поэтому всегда выделяйте себе дополнительное время не только на неожиданности, но и для написания документации.
Источник: https://youtu.be/oJbfMBROEO0
👍15👎1
День 1769. #ЗаметкиНаПолях
Используем Перехватчики в EF Core
Перехватчики в EF Core позволяют перехватывать, изменять или подавлять операции EF Core.
Перехватчики регистрируются для каждого экземпляра DbContext при настройке контекста. Каждый перехватчик реализует интерфейс IInterceptor. Несколько распространённых производных интерфейсов включают
- IDbCommandInterceptor,
- IDbConnectionInterceptor,
- IDbTransactionInterceptor,
- ISaveChangesInterceptor.
Не обязательно реализовывать эти интерфейсы напрямую. Лучше использовать конкретные реализации и переопределить необходимые методы. Рассмотрим вариант использования перехватчиков с помощью самого распространённого перехватчика SaveChangesInterceptor, который добавляет поведение при сохранении изменений в базе данных.
Добавление записей аудита
Записи аудита изменений сущностей - ценная функция в некоторых приложениях. Вы записываете дополнительную информацию аудита каждый раз, когда объект создаётся или изменяется. Также это могут быть значения «до» и «после», в зависимости от ваших требований.
Например, создадим интерфейс IAuditable с датами создания и изменения объекта:
Добавим UpdateInterceptor для записи значений аудита. Он использует ChangeTracker для поиска всех экземпляров IAuditable и устанавливает соответствующее значение свойства. Здесь мы используем метод SavingChangesAsync, который запускается до того, как изменения будут сохранены в БД.
Эту реализацию можно легко расширить, включив в неё, например, информацию о текущем пользователе.
Зарегистрировать перехватчик можно следующим образом:
Источник: https://www.milanjovanovic.tech/blog/how-to-use-ef-core-interceptors
Используем Перехватчики в EF Core
Перехватчики в EF Core позволяют перехватывать, изменять или подавлять операции EF Core.
Перехватчики регистрируются для каждого экземпляра DbContext при настройке контекста. Каждый перехватчик реализует интерфейс IInterceptor. Несколько распространённых производных интерфейсов включают
- IDbCommandInterceptor,
- IDbConnectionInterceptor,
- IDbTransactionInterceptor,
- ISaveChangesInterceptor.
Не обязательно реализовывать эти интерфейсы напрямую. Лучше использовать конкретные реализации и переопределить необходимые методы. Рассмотрим вариант использования перехватчиков с помощью самого распространённого перехватчика SaveChangesInterceptor, который добавляет поведение при сохранении изменений в базе данных.
Добавление записей аудита
Записи аудита изменений сущностей - ценная функция в некоторых приложениях. Вы записываете дополнительную информацию аудита каждый раз, когда объект создаётся или изменяется. Также это могут быть значения «до» и «после», в зависимости от ваших требований.
Например, создадим интерфейс IAuditable с датами создания и изменения объекта:
public interface IAuditable
{
DateTime Created { get; }
DateTime? Modified { get; }
}
Добавим UpdateInterceptor для записи значений аудита. Он использует ChangeTracker для поиска всех экземпляров IAuditable и устанавливает соответствующее значение свойства. Здесь мы используем метод SavingChangesAsync, который запускается до того, как изменения будут сохранены в БД.
internal sealed class UpdateInterceptor
: SaveChangesInterceptor
{
public override
ValueTask<InterceptionResult<int>>
SavingChangesAsync(
DbContextEventData e,
InterceptionResult<int> result,
CancellationToken ct = default)
{
if (e.Context is not null)
UpdateEntities(e.Context);
return base
.SavingChangesAsync(e, result, ct);
}
private static void
UpdateEntities(DbContext ctx)
{
var now = DateTime.UtcNow;
var entities = ctx
.ChangeTracker
.Entries<IAuditable>()
.ToList();
foreach (var e in entities)
{
if (e.State == EntityState.Added)
e.Property(
nameof(IAuditable.Created)) = now;
if (e.State == EntityState.Modified)
e.Property(
nameof(IAuditable.Modified)) = now;
}
}
}
Эту реализацию можно легко расширить, включив в неё, например, информацию о текущем пользователе.
Зарегистрировать перехватчик можно следующим образом:
services.AddSingleton<UpdateInterceptor>();
services.AddDbContext<
IApplicationDbContext,
AppDbContext>(
(sp, opts) => opts
.UseSqlServer(connString)
.AddInterceptors(
sp.GetRequiredService<UpdateInterceptor>());
Источник: https://www.milanjovanovic.tech/blog/how-to-use-ef-core-interceptors
👍18
День 1770. #ЗаметкиНаПолях #AsyncAwaitFAQ
ConfigureAwait в .NET 8. Начало
Мы привыкли использовать ConfigureAwait(false), чтобы предотвратить захват контекста. Изначально его рекомендовали использовать везде, но со временем рекомендация поменялась на «используйте его в коде библиотек, но не в коде приложения». Это довольно простое правило. Недавно (в частности, из-за того, что SynchronizationContext был удалён из ASP.NET Core), многие решили вовсе отказаться от ConfigurationAwait(false), даже в коде библиотек.
Есть несколько распространенных заблуждений относительно ConfigureAwait(false):
1. Это не лучший способ избежать взаимоблокировок. Это не его цель. Чтобы избежать взаимоблокировок, необходимо убедиться, что весь асинхронный код использует ConfigureAwait(false), включая код в библиотеках и среде выполнения. Да и просто это не очень удобное в обслуживании решение.
2. ConfigureAwait настраивает ожидание, а не задачу. Например, функция ConfigureAwait(false) в
ничего не делает. Аналогично, ожидание в
по-прежнему продолжает использовать захваченный контекст, полностью игнорируя ConfigureAwait(false).
3. ConfigureAwait(false) не означает «запустить остальную часть этого метода в потоке из пула потоков» или «запустить остальную часть этого метода в другом потоке». Он работает только в том случае, если await передаёт управление, а затем возобновляет асинхронный метод. В частности, await не передаст управление, когда задача уже завершена, ConfigureAwait не будет иметь никакого эффекта, поскольку ожидание продолжится синхронно.
Теперь посмотрим, что изменилось в ConfigureAwait в .NET 8.
Ничто из существующего поведения не изменилось. Поведение по умолчанию то же, и ConfigurationAwait(false) имеет то же поведение. Добавлена новая перегрузка.
ConfigureAwait(ConfigureAwaitOptions)
ConfigurationAwaitOptions — это новый тип, который предоставляет все возможные способы настройки ожидаемых объектов:
Во-первых, это битовый флаг, т.е. может использоваться любая комбинация этих опций.
Во-вторых, пока это доступно только в Task и Task<T>, по крайней мере, для .NET 8. В ValueTask/ValueTask<T> это пока не добавлено.
Далее рассмотрим каждую из опций.
Окончание следует…
Источник: https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html
ConfigureAwait в .NET 8. Начало
Мы привыкли использовать ConfigureAwait(false), чтобы предотвратить захват контекста. Изначально его рекомендовали использовать везде, но со временем рекомендация поменялась на «используйте его в коде библиотек, но не в коде приложения». Это довольно простое правило. Недавно (в частности, из-за того, что SynchronizationContext был удалён из ASP.NET Core), многие решили вовсе отказаться от ConfigurationAwait(false), даже в коде библиотек.
Есть несколько распространенных заблуждений относительно ConfigureAwait(false):
1. Это не лучший способ избежать взаимоблокировок. Это не его цель. Чтобы избежать взаимоблокировок, необходимо убедиться, что весь асинхронный код использует ConfigureAwait(false), включая код в библиотеках и среде выполнения. Да и просто это не очень удобное в обслуживании решение.
2. ConfigureAwait настраивает ожидание, а не задачу. Например, функция ConfigureAwait(false) в
SomethingAsync().ConfigureAwait(false).GetAwaiter().GetResult()
ничего не делает. Аналогично, ожидание в
var task = SomethingAsync();
task.ConfigureAwait(false);
await task;
по-прежнему продолжает использовать захваченный контекст, полностью игнорируя ConfigureAwait(false).
3. ConfigureAwait(false) не означает «запустить остальную часть этого метода в потоке из пула потоков» или «запустить остальную часть этого метода в другом потоке». Он работает только в том случае, если await передаёт управление, а затем возобновляет асинхронный метод. В частности, await не передаст управление, когда задача уже завершена, ConfigureAwait не будет иметь никакого эффекта, поскольку ожидание продолжится синхронно.
Теперь посмотрим, что изменилось в ConfigureAwait в .NET 8.
Ничто из существующего поведения не изменилось. Поведение по умолчанию то же, и ConfigurationAwait(false) имеет то же поведение. Добавлена новая перегрузка.
ConfigureAwait(ConfigureAwaitOptions)
ConfigurationAwaitOptions — это новый тип, который предоставляет все возможные способы настройки ожидаемых объектов:
[Flags]
public enum ConfigureAwaitOptions
{
None = 0x0,
ContinueOnCapturedContext = 0x1,
SuppressThrowing = 0x2,
ForceYielding = 0x4,
}
Во-первых, это битовый флаг, т.е. может использоваться любая комбинация этих опций.
Во-вторых, пока это доступно только в Task и Task<T>, по крайней мере, для .NET 8. В ValueTask/ValueTask<T> это пока не добавлено.
Далее рассмотрим каждую из опций.
Окончание следует…
Источник: https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html
👍12👎2
День 1771. #ЗаметкиНаПолях #AsyncAwaitFAQ
ConfigureAwait в .NET 8. Окончание
Начало
None и ContinueOnCapturedContext
Эти опции очевидны, с небольшим замечанием.
ContinueOnCapturedContext — то же самое, что true, т.е. ожидание захватит контекст и возобновит выполнение асинхронного метода в этом контексте.
None — то же самое, что false, т.е. ожидание не будет захватывать контекст.
Замечание. По умолчанию контекст НЕ захватывается. Если явно не добавить ContinueOnCapturedContext, контекст не будет захвачен.
Поведение по умолчанию не изменилось: отсутствие ConfigureAwait аналогично true или ContinueOnCapturedContext. Но при использовании других опций ConfigureAwaitOptions, для захвата контекста нужно будет добавлять флаг ContinueOnCapturedContext (см. ниже).
SuppressThrowing
Этот флаг подавляет исключения, которые в противном случае могли бы возникнуть при ожидании задачи. В нормальных условиях await отслеживает исключения в задачах, повторно выбрасывая их в момент ожидания. Обычно это именно то поведение, которое вам нужно, но бывают ситуации, когда вы просто хотите дождаться завершения задачи и вас не волнует, завершится ли она успешно или с исключением. SuppressThrowing позволяет дождаться завершения задачи, не наблюдая за её результатом.
Это скорее всего будет полезно при отмене задач. Иногда нужно вызвать отмену задачи, дождаться её, а затем выполнить другую задачу вместо отменённой. Тогда отменяемую задачу можно ожидать с SuppressThrowing, и метод продолжит работу после завершения задачи, независимо от того, была ли она успешной, отменённой или вызвала исключение.
Замечание: эта семантика не работает для Task<T>, поскольку в этом случае ожидание должно возвращать значение типа T. Неясно, какое значение будет уместно вернуть в случае игнорируемого исключения, поэтому текущее поведение заключается в выдаче исключения ArgumentOutOfRangeException во время выполнения. Было добавлено новое предупреждение:
CA2261: The ConfigureAwaitOptions.SuppressThrowing is only supported with the non-generic Task (ConfigureAwaitOptions.SuppressThrowing поддерживается только с необобщённым Task).
Это предупреждение лучше сделать ошибкой, поскольку во время выполнения оно всегда будет давать сбой.
ForceYielding
ForceYielding – флаг, который может быть полезен в очень редких случаях, но в этих случаях он будет очень удобен. Он похож на Task.Yield. Yield возвращает специальную ожидаемую задачу, которая всегда утверждает, что она не завершена, но немедленно планирует продолжение. Обычно await проверяет, завершена ли ожидаемая задача и, если да, продолжает синхронно. ForceYielding предотвращает такое синхронное поведение, заставляя ожидание вести себя асинхронно. Это может быть полезно, например, при модульном тестировании.
Обратите внимание, что сам по себе флаг ForceYielding также подразумевает отказ от продолжения работы с захваченным контекстом, поэтому это то же самое, что сказать «запланировать остальную часть этого метода для выполнения в пуле потоков» или «переключиться на поток из пула потоков».
Task.Yield возобновит работу в захваченном контексте, поэтому это не то же самое, что ForceYielding. Task.Yield аналогично комбинации флагов
Конечно, реальная ценность ForceYielding в том, что его можно применить к любой задаче. Раньше приходилось либо добавлять отдельный
Источник: https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html
ConfigureAwait в .NET 8. Окончание
Начало
None и ContinueOnCapturedContext
Эти опции очевидны, с небольшим замечанием.
ContinueOnCapturedContext — то же самое, что true, т.е. ожидание захватит контекст и возобновит выполнение асинхронного метода в этом контексте.
None — то же самое, что false, т.е. ожидание не будет захватывать контекст.
Замечание. По умолчанию контекст НЕ захватывается. Если явно не добавить ContinueOnCapturedContext, контекст не будет захвачен.
Поведение по умолчанию не изменилось: отсутствие ConfigureAwait аналогично true или ContinueOnCapturedContext. Но при использовании других опций ConfigureAwaitOptions, для захвата контекста нужно будет добавлять флаг ContinueOnCapturedContext (см. ниже).
SuppressThrowing
Этот флаг подавляет исключения, которые в противном случае могли бы возникнуть при ожидании задачи. В нормальных условиях await отслеживает исключения в задачах, повторно выбрасывая их в момент ожидания. Обычно это именно то поведение, которое вам нужно, но бывают ситуации, когда вы просто хотите дождаться завершения задачи и вас не волнует, завершится ли она успешно или с исключением. SuppressThrowing позволяет дождаться завершения задачи, не наблюдая за её результатом.
Это скорее всего будет полезно при отмене задач. Иногда нужно вызвать отмену задачи, дождаться её, а затем выполнить другую задачу вместо отменённой. Тогда отменяемую задачу можно ожидать с SuppressThrowing, и метод продолжит работу после завершения задачи, независимо от того, была ли она успешной, отменённой или вызвала исключение.
Замечание: эта семантика не работает для Task<T>, поскольку в этом случае ожидание должно возвращать значение типа T. Неясно, какое значение будет уместно вернуть в случае игнорируемого исключения, поэтому текущее поведение заключается в выдаче исключения ArgumentOutOfRangeException во время выполнения. Было добавлено новое предупреждение:
CA2261: The ConfigureAwaitOptions.SuppressThrowing is only supported with the non-generic Task (ConfigureAwaitOptions.SuppressThrowing поддерживается только с необобщённым Task).
Это предупреждение лучше сделать ошибкой, поскольку во время выполнения оно всегда будет давать сбой.
ForceYielding
ForceYielding – флаг, который может быть полезен в очень редких случаях, но в этих случаях он будет очень удобен. Он похож на Task.Yield. Yield возвращает специальную ожидаемую задачу, которая всегда утверждает, что она не завершена, но немедленно планирует продолжение. Обычно await проверяет, завершена ли ожидаемая задача и, если да, продолжает синхронно. ForceYielding предотвращает такое синхронное поведение, заставляя ожидание вести себя асинхронно. Это может быть полезно, например, при модульном тестировании.
Обратите внимание, что сам по себе флаг ForceYielding также подразумевает отказ от продолжения работы с захваченным контекстом, поэтому это то же самое, что сказать «запланировать остальную часть этого метода для выполнения в пуле потоков» или «переключиться на поток из пула потоков».
Task.Yield возобновит работу в захваченном контексте, поэтому это не то же самое, что ForceYielding. Task.Yield аналогично комбинации флагов
ForceYielding | ContinueOnCapturedContext
.Конечно, реальная ценность ForceYielding в том, что его можно применить к любой задаче. Раньше приходилось либо добавлять отдельный
await Task.Yield();
либо создавать собственный ожидаемый объект. Теперь в этом больше нет необходимости, поскольку ForceYielding можно применять к любой задаче. Источник: https://blog.stephencleary.com/2023/11/configureawait-in-net-8.html
👍9
День 1772. #ЗаметкиНаПолях #PatternMatching
Шпаргалка по Сопоставлению по Шаблону в C#
Сопоставление по шаблону — это функция, используемая для проверки выражений на соответствие некоторым условиям с одновременной проверкой их типов. Исторически оно было отличительной чертой функционального программирования, и уже существует в других популярных языках, таких как Scala, Rust, Python, Haskell, Prolog и многих других. Сопоставление по шаблону было представлено в C# 7, и с тех пор получало множество обновлений в последующих версиях.
Помните, что его можно применять только в выражениях is или switch.
С# 7
Шаблон типа
Проверка типа выражения
Шаблон объявления
Проверка типа + присвоение переменной при успехе.
Шаблон константы
Проверка на константное значение: int, float, char, string, bool, enum, const, null.
Шаблон null
Проверка ссылочного или обнуляемого типа на null
Шаблон var
Подобно шаблону типа, шаблон var сопоставляет шаблон, проверяет на null и присваивает значение переменной. Тип var объявляется на основе типа времени компиляции соответствующего выражения.
Продолжение следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
Шпаргалка по Сопоставлению по Шаблону в C#
Сопоставление по шаблону — это функция, используемая для проверки выражений на соответствие некоторым условиям с одновременной проверкой их типов. Исторически оно было отличительной чертой функционального программирования, и уже существует в других популярных языках, таких как Scala, Rust, Python, Haskell, Prolog и многих других. Сопоставление по шаблону было представлено в C# 7, и с тех пор получало множество обновлений в последующих версиях.
Помните, что его можно применять только в выражениях is или switch.
С# 7
Шаблон типа
Проверка типа выражения
public bool IsFood(object product)
=> product is Food;
Шаблон объявления
Проверка типа + присвоение переменной при успехе.
public bool IsFridgeFood(object product)
=> product is Food food &&
RequiresFridge(food.StorageTemp);
Шаблон константы
Проверка на константное значение: int, float, char, string, bool, enum, const, null.
public bool IsFresh(Food food)
=> food?.Category?.ID is (int)Category.Fresh;
Шаблон null
Проверка ссылочного или обнуляемого типа на null
public bool DoesNotExist(Food food)
=> food is null;
Шаблон var
Подобно шаблону типа, шаблон var сопоставляет шаблон, проверяет на null и присваивает значение переменной. Тип var объявляется на основе типа времени компиляции соответствующего выражения.
public bool RequiresFridge(Food food)
=> GetStorageRequirement(food) is var req &&
req is StorageRequirement.Freezer;
Продолжение следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
👍11
День 1773. #ЗаметкиНаПолях #PatternMatching
Шпаргалка по Сопоставлению по Шаблону в C#. Продолжение
C# 7
С# 8
Шаблон свойства
Вы можете включать в шаблон элементы объекта вместо переменных, для соответствия заданным условиям. Его можно легко использовать с другими типами шаблонов для создания гибких и мощных логических выражений.
Использование вложенных свойств было доступно в 8 и 9 версиях языка, но его реализация не была самым чистым решением или самым лаконичным синтаксисом.
Шаблон отказа
Оператор отказа (discard) _ в шаблоне соответствует всему, включая значение null. Его использование проявляется в новых выражениях switch, чтобы соответствовать выбору по умолчанию. В примере ниже, если вид хранения продуктов не указан или не соответствует ни одному варианту, будет выдано исключение:
Позиционный шаблон
В основном используется со структурами, использует деконструктор для сопоставления шаблона в соответствии с позицией значений в деконструкторе. В примере ниже Price – структура со значением и валютой. Здесь используется шаблон отказа, чтобы игнорировать валюту, когда цена 0.
Шаблон кортежа
Особый вариант позиционного шаблона, позволяющий проверять несколько свойств класса в одном выражении.
Продолжение следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
Шпаргалка по Сопоставлению по Шаблону в C#. Продолжение
C# 7
С# 8
Шаблон свойства
Вы можете включать в шаблон элементы объекта вместо переменных, для соответствия заданным условиям. Его можно легко использовать с другими типами шаблонов для создания гибких и мощных логических выражений.
public bool IsOrganic(Food food)
{
return food is
{
NoGMO: true,
NoFertilizers: true,
NoPesticides: true
};
}
Использование вложенных свойств было доступно в 8 и 9 версиях языка, но его реализация не была самым чистым решением или самым лаконичным синтаксисом.
Шаблон отказа
Оператор отказа (discard) _ в шаблоне соответствует всему, включая значение null. Его использование проявляется в новых выражениях switch, чтобы соответствовать выбору по умолчанию. В примере ниже, если вид хранения продуктов не указан или не соответствует ни одному варианту, будет выдано исключение:
public int GetStorageTemp(
StorageRequirement req)
=> req switch
{
StorageRequirement.Freezer => -18,
StorageRequirement.Fridge => 4,
StorageRequirement.RoomTemp => 25,
_ => throw new
InvalidStorageRequirementException()
};
Позиционный шаблон
В основном используется со структурами, использует деконструктор для сопоставления шаблона в соответствии с позицией значений в деконструкторе. В примере ниже Price – структура со значением и валютой. Здесь используется шаблон отказа, чтобы игнорировать валюту, когда цена 0.
public bool IsFree(Food food)
=> food.Price is (0, _);
Шаблон кортежа
Особый вариант позиционного шаблона, позволяющий проверять несколько свойств класса в одном выражении.
public string GetDescription(Food food)
=> (food.NonGMO, food.Category.ID) switch
{
(true, (int)Category.Fresh)
=> "Non-GMO Fresh Product",
(true, (int)Category.Dairy)
=> "Non-GMO Dairy",
(false, (int)Category.Meats)
=> "GMO Meat!",
(_, _) => "Invalid Food Group"
};
Продолжение следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
👍15
День 1774. #ЗаметкиНаПолях #PatternMatching
Шпаргалка по Сопоставлению по Шаблону в C#. Продолжение
С# 7
С# 8
C# 9
«Расширенный» шаблон типа
Позволяет выполнять проверку типов в выражениях switch.
Логический шаблон
Представляет собой совокупность отрицания (not), конъюнкции (and) и дизъюнкции (or). Вместе они называются комбинаторами шаблонов. Они используются для объединения шаблонов и применения к ним логических условий.
Шаблон отношения
Позволяет применять реляционные операторы > < >= <= для сопоставления шаблонов с константами или перечислениями.
Шаблон отрицания null
Проверяет выражение на ненулевое значение
Скобки в шаблоне
Круглые скобки в шаблоне используются для управления порядком выполнения и группировки логических выражений. Их можно использовать в любом типе шаблона, но в основном это связано с использованием комбинаторов шаблонов.
Окончание следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
Шпаргалка по Сопоставлению по Шаблону в C#. Продолжение
С# 7
С# 8
C# 9
«Расширенный» шаблон типа
Позволяет выполнять проверку типов в выражениях switch.
public string CheckValueType(object value)
=> value switch
{
int => "integer",
decimal => "decimal",
double => "double",
_ => "not a number"
};
Логический шаблон
Представляет собой совокупность отрицания (not), конъюнкции (and) и дизъюнкции (or). Вместе они называются комбинаторами шаблонов. Они используются для объединения шаблонов и применения к ним логических условий.
public bool RequiresFrige(Category cat)
=> cat is Category.Dairy or Category.Meats;
Шаблон отношения
Позволяет применять реляционные операторы > < >= <= для сопоставления шаблонов с константами или перечислениями.
public StorageRequirement
GetStorageRequirement(Food food)
=> food.StorageTemp switch
{
<= -18 => StorageRequirement.Freezer,
>= 2 and < 6 => StorageRequirement.Frige,
> 6 and < 30 => StorageRequirement.RoomTemp,
_ => throw new
InvalidStorageRequirementException(
food.StorageTemperature)
};
Шаблон отрицания null
Проверяет выражение на ненулевое значение
public bool Exists(Blog blog)
=> blog is not null;
Скобки в шаблоне
Круглые скобки в шаблоне используются для управления порядком выполнения и группировки логических выражений. Их можно использовать в любом типе шаблона, но в основном это связано с использованием комбинаторов шаблонов.
public bool RequiresFridge(int storageTemp)
=> storageTemp is > 1 and (< 6);
Окончание следует…
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
👍17
День 1775. #ЗаметкиНаПолях #PatternMatching
Шпаргалка по Сопоставлению по Шаблону в C#. Окончание
С# 7
С# 8
C# 9
C# 10
Расширенный шаблон свойств
В C# 10 была решена проблема соответствия синтаксиса вложенных свойств. С появлением расширенного шаблона свойств синтаксис использования вложенных свойств при сопоставлении с шаблоном стал понятным и кратким.
C# 11
Шаблон списка
Позволяет сопоставить список или массив с набором последовательных элементов. Вы можете комбинировать его с шаблонами отказа, комбинаторами шаблонов, диапазонами, переменными и типом назначения, чтобы создать очень гибкое и мощное сопоставление по шаблону списка.
См. подробнее про шаблоны списков.
Итого
С добавлением функций сопоставления по шаблону C# добавил замечательные возможности функционального программирования, которые десятилетиями использовались во множестве языков. Конечно, всегда нужно проявлять осторожность, чтобы не злоупотреблять сопоставлением по шаблону.
Если вы работаете над большим проектом с другими членами команды, помните, что не все знают о некоторых или всех функциях сопоставления по шаблону, поэтому не стоит сразу вводить слишком много.
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
Шпаргалка по Сопоставлению по Шаблону в C#. Окончание
С# 7
С# 8
C# 9
C# 10
Расширенный шаблон свойств
В C# 10 была решена проблема соответствия синтаксиса вложенных свойств. С появлением расширенного шаблона свойств синтаксис использования вложенных свойств при сопоставлении с шаблоном стал понятным и кратким.
public bool RequiresFridge(Food food)
=> food is
{
Category.ID: (int)Category.Dairy or
(int)Category.Meats
};
C# 11
Шаблон списка
Позволяет сопоставить список или массив с набором последовательных элементов. Вы можете комбинировать его с шаблонами отказа, комбинаторами шаблонов, диапазонами, переменными и типом назначения, чтобы создать очень гибкое и мощное сопоставление по шаблону списка.
public (int?, int?) FindOneAndFour()
{
int[] numbers = { 1, 2, 3, 4, 5 };
// Совпадает, если
// - 2й элемент любой
// - 3й больше или равен 3
// - 5й равен 5
if (numbers is
[var one, _, >= 3, int four, 5])
{
return (one, four);
}
return (null, null);
}
См. подробнее про шаблоны списков.
Итого
С добавлением функций сопоставления по шаблону C# добавил замечательные возможности функционального программирования, которые десятилетиями использовались во множестве языков. Конечно, всегда нужно проявлять осторожность, чтобы не злоупотреблять сопоставлением по шаблону.
Если вы работаете над большим проектом с другими членами команды, помните, что не все знают о некоторых или всех функциях сопоставления по шаблону, поэтому не стоит сразу вводить слишком много.
Источник: https://codingsonata.com/your-quick-guide-to-pattern-matching-in-c/
👍16
День 1777. #ЗаметкиНаПолях
Где Имеет Смысл Применять Первичные Конструкторы
Первичные конструкторы классов появились в C# 12. Один из первых вопросов, который может возникнуть: как они работают и какова область их применения?
Во-первых, параметры первичных конструкторов ведут себя как параметры метода или обычного конструктора. Т.е. к этому параметру можно получить доступ и изменить его, как и любой другой параметр, из любого места внутри класса. Например:
После того, как вы вызовете метод Format(), все ссылки на name будут использовать изменённую версию name, поскольку параметр изменяемый. Т.е., если вы собираетесь использовать первичные конструкторы для внедрения зависимостей, любой оператор внутри принимающего класса может изменить значение параметра. По сути, вы не можете доверять тому, что значение параметра соответствует тому, что было передано.
Валидация
Как правило, рекомендуется проверять аргументы конструктора. Типичное место проверки входных данных — конструктор с использованием защитных предложений.
Примечание: я не нашёл, как можно проверять собственно параметры первичного конструктора. Поэтому подозреваю, что это придётся делать при каждом использовании, например:
Если вы знаете другой способ (исключая сторонние библиотеки), пожалуйста, напишите в комментариях.
Внедрение зависимостей
Вы можете использовать первичные конструкторы для зависимостей, как и обычный конструктор:
В небольшом простом классе сервиса может быть приемлемо использовать аргументы первичного конструктора. Однако это быстро может перерасти в проблему.
Во-первых, как упоминалось выше, параметры первичных конструкторов изменяемы. То есть любой метод может изменить их, и тогда полагаться на их значение будет нельзя. Вы не можете пометить их как только для чтения. Пока для этого недостаточно поддержки на уровне языка.
Во-вторых, по мере роста объёма кода класса становится неочевидно, откуда берутся параметры класса. Они называются как закрытые поля полями (с префиксом _), но ими не являются. Если вы попытаетесь получить к ним доступ через this, это не сработает.
DTO
Конечно, это будет работать. Но вам всё равно захочется назначить их свойствам. Однако в этом случае проще использовать запись, которая даст и неизменяемость, и переопределённый ToString, и прочие преимущества.
Итого
Учитывая текущую реализацию первичных конструкторов классов C#:
- Используйте аргументы первичного конструктора только для инициализации полей и свойств. Избегайте доступа к ним где-либо ещё (за исключением, возможно, тривиальных реализаций классов).
- Учитывая, что это параметры, их лучше называть, как и обычные параметры с помощью camelCase, без префикса
- До тех пор, пока не будут доступны дополнительные ограничения для параметров первичного конструктора, они представляют собой ружьё, которым разработчики могут отстрелить себе …, если не будут осторожны. Обязательно включите TreatWarningsAsErrors, чтобы отслеживать любые случаи, когда вы ссылаетесь на параметры уровня класса, помимо инициализации (особенно предупреждение CS9124).
Источник: https://blog.nimblepros.com/blogs/where-csharp-primary-constructors-make-sense/
Где Имеет Смысл Применять Первичные Конструкторы
Первичные конструкторы классов появились в C# 12. Один из первых вопросов, который может возникнуть: как они работают и какова область их применения?
Во-первых, параметры первичных конструкторов ведут себя как параметры метода или обычного конструктора. Т.е. к этому параметру можно получить доступ и изменить его, как и любой другой параметр, из любого места внутри класса. Например:
public class Customer(string name)
{
// выдаст предупреждение компилятора
public string Name { get; } = name;
public string FullName => name;
public void Format() => name = name.ToUpper();
}
var c = new Customer("steve");
c.Format();
Console.WriteLine(c.Name); // steve
Console.WriteLine(c.FullName); // STEVE
После того, как вы вызовете метод Format(), все ссылки на name будут использовать изменённую версию name, поскольку параметр изменяемый. Т.е., если вы собираетесь использовать первичные конструкторы для внедрения зависимостей, любой оператор внутри принимающего класса может изменить значение параметра. По сути, вы не можете доверять тому, что значение параметра соответствует тому, что было передано.
Валидация
Как правило, рекомендуется проверять аргументы конструктора. Типичное место проверки входных данных — конструктор с использованием защитных предложений.
Примечание: я не нашёл, как можно проверять собственно параметры первичного конструктора. Поэтому подозреваю, что это придётся делать при каждом использовании, например:
public class Customer(string name)
{
public string Name
{
get
{
ArgumentException
.ThrowIfNullOrEmpty(nameof(name));
return name;
}
}
}
Если вы знаете другой способ (исключая сторонние библиотеки), пожалуйста, напишите в комментариях.
Внедрение зависимостей
Вы можете использовать первичные конструкторы для зависимостей, как и обычный конструктор:
public class MyService(
IMyRepo _repo,
ILogger<MyService> _logger)
{
…
}
В небольшом простом классе сервиса может быть приемлемо использовать аргументы первичного конструктора. Однако это быстро может перерасти в проблему.
Во-первых, как упоминалось выше, параметры первичных конструкторов изменяемы. То есть любой метод может изменить их, и тогда полагаться на их значение будет нельзя. Вы не можете пометить их как только для чтения. Пока для этого недостаточно поддержки на уровне языка.
Во-вторых, по мере роста объёма кода класса становится неочевидно, откуда берутся параметры класса. Они называются как закрытые поля полями (с префиксом _), но ими не являются. Если вы попытаетесь получить к ним доступ через this, это не сработает.
DTO
Конечно, это будет работать. Но вам всё равно захочется назначить их свойствам. Однако в этом случае проще использовать запись, которая даст и неизменяемость, и переопределённый ToString, и прочие преимущества.
Итого
Учитывая текущую реализацию первичных конструкторов классов C#:
- Используйте аргументы первичного конструктора только для инициализации полей и свойств. Избегайте доступа к ним где-либо ещё (за исключением, возможно, тривиальных реализаций классов).
- Учитывая, что это параметры, их лучше называть, как и обычные параметры с помощью camelCase, без префикса
_
.- До тех пор, пока не будут доступны дополнительные ограничения для параметров первичного конструктора, они представляют собой ружьё, которым разработчики могут отстрелить себе …, если не будут осторожны. Обязательно включите TreatWarningsAsErrors, чтобы отслеживать любые случаи, когда вы ссылаетесь на параметры уровня класса, помимо инициализации (особенно предупреждение CS9124).
Источник: https://blog.nimblepros.com/blogs/where-csharp-primary-constructors-make-sense/
👍14
День 1778. #ЧтоНовенького
Новый Способ Логирования в .NET 8
В последней версии .NET представлен новый, более гибкий и усовершенствованный, способ ведения журнала – атрибут LoggerMessageAttribute.
Вот старый способ:
В .NET 8 атрибут
Чтобы генераторы исходного кода работали, мы должны определить класс как частичный. Генератор кода сгенерирует недостающую часть класса. Получается меньше кода, что приятнее читать. Вы также можете сэкономить драгоценные ресурсы и немного производительности, хотя в 99% случаев это не имеет значения. Но хорошо, что это бесплатно.
Подробнее об атрибуте
Источник: https://steven-giesel.com/blogPost/1add3827-4233-4e31-9ce9-bcc34d64e76f
Новый Способ Логирования в .NET 8
В последней версии .NET представлен новый, более гибкий и усовершенствованный, способ ведения журнала – атрибут LoggerMessageAttribute.
Вот старый способ:
public class MyRepo
{
public async Task Delete(
IEnumerable<string> ids)
{
for (var i = 0; i < totalBatches; i++)
{
…
_logger.LogDebug(
"Deleted Batch {BatchNumber} - {TotalDeleted} elements.",
i+1, (i+1)*batchSize);
}
}
}
В .NET 8 атрибут
LoggerMessageAttribute
получил некоторые расширения, которые помогут вам сделать то же самое с помощью генераторов исходного кода:public partial class MyRepo
{
public async ValueTask DeleteBulkAsync(IEnumerable<string> ids)
{
for (var i = 0; i < totalBatches; i++)
{
…
LogDelete(i+1, (i+1)*batchSize);
}
}
[LoggerMessage(LogLevel.Debug,
"Deleted Batch {BatchNumber} - {TotalDeleted} elements")]
private partial void LogDelete(
int batchNumber, int totalDeleted);
}
Чтобы генераторы исходного кода работали, мы должны определить класс как частичный. Генератор кода сгенерирует недостающую часть класса. Получается меньше кода, что приятнее читать. Вы также можете сэкономить драгоценные ресурсы и немного производительности, хотя в 99% случаев это не имеет значения. Но хорошо, что это бесплатно.
Подробнее об атрибуте
LoggerMessageAttribute
можно почитать в официальном анонсе .NET 8 превью 6.Источник: https://steven-giesel.com/blogPost/1add3827-4233-4e31-9ce9-bcc34d64e76f
👍15👎1
День 1779. #ЗаметкиНаПолях
Сравниваем Алгоритмы Ограничения Обработки Запросов. Начало
Всегда следует устанавливать ограничение на количество входящих запросов. Иначе система может оказаться уязвимой для злоумышленников. Рассмотрим 4 основных алгоритма ограничения обработки запросов.
Ограничение обработки запросов (Rate Limiting) — это способ запретить клиентам слишком часто обращаться к системе.
Преимущества:
1. Защищает систему от DoS атак
Если злоумышленник попытается повлиять на систему, вызывая API так часто, что вся система выйдет из строя, ограничение поможет уменьшить количество выполняемых операций.
2. Добавляет уровень безопасности, предотвращающий атаки грубой силой.
Если злоумышленник попытается получить доступ к системе, перепробовав все возможные пароли, политика ограничения обработки запросов не позволит ему выполнить слишком много попыток.
3. Защищает медленно работающую часть системы.
Если часть системы не может быстро обработать запрос, клиент может добавить политику повтора запроса. Так он может перегрузить и без того плохо работающий компонент, что сделает его совершенно неспособным обрабатывать любые запросы.
Чтобы клиенты знали, что их запросы не обрабатываются из-за слишком частых попыток, нужно использовать код ответа HTTP: 429 Too Many Requests. Так клиенты могут реализовать логику повторных попыток, учитывая это. Ответ также должен включать HTTP-заголовок Retry-After, чтобы сообщить клиенту, как долго ждать перед выполнением следующего запроса.
Теперь рассмотрим стратегии ограничения количества запросов.
1. Фиксированное окно
Ограничивает количество запросов, разрешённых в течение данного временного окна. Временные рамки определяются сервером и одинаковы для всех клиентов.
Допустим, мы можем принимать 100 запросов в минуту. По прошествии минуты, сможем принять ещё 100. Можно выбрать два типа ограничения:
- на уровне пользователя позволяет каждому пользователю выполнять, в нашем примере, 100 запросов в минуту,
- на уровне сервера означает, что сервер способен обрабатывать всего 100 запросов в минуту от всех клиентов.
Алгоритм прост в реализации, но имеет некоторые недостатки:
1) Может допускать всплески запросов в начале или в конце каждого окна, что может перегрузить систему.
2) Предположим, что многие запросы переводятся на следующую минуту. В этом случае вы в итоге добавляете всё больше запросов в начало следующей минуты, вызывая всплеск запросов, которые система может быть не в состоянии обработать.
2. Скользящее окно
Делит время на фиксированные интервалы, и каждый интервал начинается с первого запроса клиента. Если окно составляет 100 запросов в минуту, то:
- Клиент А делает первый запрос в 09:00:05 и может обратиться к системе 100 раз до 09:01:05.
- Клиент B - первый запрос в 09:00:38 - 100 запросов до 09:01:38.
Так оба клиента могут обращаться к системе по 100 раз в минуту, но их временные окна не зависят друг от друга и могут пересекаться.
Этот алгоритм более справедлив, чем алгоритм фиксированного окна, поскольку рассматривает историю запросов каждого клиента независимо. Однако теперь необходимо хранить информацию о количестве запросов и времени окна для каждого клиента, что более сложно и ресурсоемко.
Окончание следует…
Источник: https://www.code4it.dev/architecture-notes/rate-limiting-algorithms/
Сравниваем Алгоритмы Ограничения Обработки Запросов. Начало
Всегда следует устанавливать ограничение на количество входящих запросов. Иначе система может оказаться уязвимой для злоумышленников. Рассмотрим 4 основных алгоритма ограничения обработки запросов.
Ограничение обработки запросов (Rate Limiting) — это способ запретить клиентам слишком часто обращаться к системе.
Преимущества:
1. Защищает систему от DoS атак
Если злоумышленник попытается повлиять на систему, вызывая API так часто, что вся система выйдет из строя, ограничение поможет уменьшить количество выполняемых операций.
2. Добавляет уровень безопасности, предотвращающий атаки грубой силой.
Если злоумышленник попытается получить доступ к системе, перепробовав все возможные пароли, политика ограничения обработки запросов не позволит ему выполнить слишком много попыток.
3. Защищает медленно работающую часть системы.
Если часть системы не может быстро обработать запрос, клиент может добавить политику повтора запроса. Так он может перегрузить и без того плохо работающий компонент, что сделает его совершенно неспособным обрабатывать любые запросы.
Чтобы клиенты знали, что их запросы не обрабатываются из-за слишком частых попыток, нужно использовать код ответа HTTP: 429 Too Many Requests. Так клиенты могут реализовать логику повторных попыток, учитывая это. Ответ также должен включать HTTP-заголовок Retry-After, чтобы сообщить клиенту, как долго ждать перед выполнением следующего запроса.
Теперь рассмотрим стратегии ограничения количества запросов.
1. Фиксированное окно
Ограничивает количество запросов, разрешённых в течение данного временного окна. Временные рамки определяются сервером и одинаковы для всех клиентов.
Допустим, мы можем принимать 100 запросов в минуту. По прошествии минуты, сможем принять ещё 100. Можно выбрать два типа ограничения:
- на уровне пользователя позволяет каждому пользователю выполнять, в нашем примере, 100 запросов в минуту,
- на уровне сервера означает, что сервер способен обрабатывать всего 100 запросов в минуту от всех клиентов.
Алгоритм прост в реализации, но имеет некоторые недостатки:
1) Может допускать всплески запросов в начале или в конце каждого окна, что может перегрузить систему.
2) Предположим, что многие запросы переводятся на следующую минуту. В этом случае вы в итоге добавляете всё больше запросов в начало следующей минуты, вызывая всплеск запросов, которые система может быть не в состоянии обработать.
2. Скользящее окно
Делит время на фиксированные интервалы, и каждый интервал начинается с первого запроса клиента. Если окно составляет 100 запросов в минуту, то:
- Клиент А делает первый запрос в 09:00:05 и может обратиться к системе 100 раз до 09:01:05.
- Клиент B - первый запрос в 09:00:38 - 100 запросов до 09:01:38.
Так оба клиента могут обращаться к системе по 100 раз в минуту, но их временные окна не зависят друг от друга и могут пересекаться.
Этот алгоритм более справедлив, чем алгоритм фиксированного окна, поскольку рассматривает историю запросов каждого клиента независимо. Однако теперь необходимо хранить информацию о количестве запросов и времени окна для каждого клиента, что более сложно и ресурсоемко.
Окончание следует…
Источник: https://www.code4it.dev/architecture-notes/rate-limiting-algorithms/
👍13
День 1780. #ЗаметкиНаПолях
Сравниваем Алгоритмы Ограничения Обработки Запросов. Окончание
Начало
3. Дырявое ведро
Представьте себе ведро с отверстием в дне. Ведро наполняется водой (что символизирует поступающие запросы) с разной скоростью, но вода постоянно вытекает из отверстия. Если ведро уже заполнено и добавляется дополнительная вода, она выливается, что означает отказ от дополнительных запросов.
Этот алгоритм обеспечивает постоянство потока запросов и уменьшает перегрузку. Если запросы добавляются быстрее, чем могут быть обработаны, лишние запросы отбрасываются.
Алгоритм может быть реализован с использованием очереди FIFO (First In, First Out). В очереди хранится список запросов, и фиксированное количество запросов извлекается из очереди с постоянной скоростью, а затем обрабатывается.
Например: каждый запрос заполняет одну ячейку в ведре, и одна ячейка извлекается через постоянные промежутки времени. Если размер ведра 100 запросов, а скорость утечки — 5 запросов в секунду, то, если будет поступать более 5 запросов в секунду, ведро заполнится, а входящие запросы будут блокироваться до тех пор, пока не освободится место.
4. Корзина токенов
Аналогичен алгоритму дырявого ведра, но вместо заполнения слотов запросами он потребляет токены из корзины. Каждому клиенту выделяется определённое количество токенов, которые он может использовать. Он может использовать их все сразу или постепенно.
В корзине теперь есть минимальное (ноль) и максимальное количество доступных токенов. При поступлении запроса система извлекает соответствующее количество токенов из корзины. При этом токены добавляются с постоянной скоростью. Например, в корзину, вместимостью 100 токенов, система может добавлять 5 токенов каждые 10 секунд. Как только корзина достигнет предела, система отбрасывает лишние токены (а не запросы).
Одно из отличий от «дырявого ведра» в том, что «корзина токенов» допускает пакетные запросы, тогда как «дырявое ведро» поддерживает только обработку запросов с постоянной скоростью.
Итого
Здесь лишь поверхностно рассмотрены четыре основных алгоритма ограничения обработки запросов. На картинке ниже они изображены схематически. Каждый из алгоритмов в реальности намного сложнее. Однако знание того, что они существуют и решают различные проблемы, может помочь выбрать тот, который подходит для ваших приложений.
См. также «Промежуточное ПО для ограничений в .NET 7»
Источник: https://www.code4it.dev/architecture-notes/rate-limiting-algorithms/
Сравниваем Алгоритмы Ограничения Обработки Запросов. Окончание
Начало
3. Дырявое ведро
Представьте себе ведро с отверстием в дне. Ведро наполняется водой (что символизирует поступающие запросы) с разной скоростью, но вода постоянно вытекает из отверстия. Если ведро уже заполнено и добавляется дополнительная вода, она выливается, что означает отказ от дополнительных запросов.
Этот алгоритм обеспечивает постоянство потока запросов и уменьшает перегрузку. Если запросы добавляются быстрее, чем могут быть обработаны, лишние запросы отбрасываются.
Алгоритм может быть реализован с использованием очереди FIFO (First In, First Out). В очереди хранится список запросов, и фиксированное количество запросов извлекается из очереди с постоянной скоростью, а затем обрабатывается.
Например: каждый запрос заполняет одну ячейку в ведре, и одна ячейка извлекается через постоянные промежутки времени. Если размер ведра 100 запросов, а скорость утечки — 5 запросов в секунду, то, если будет поступать более 5 запросов в секунду, ведро заполнится, а входящие запросы будут блокироваться до тех пор, пока не освободится место.
4. Корзина токенов
Аналогичен алгоритму дырявого ведра, но вместо заполнения слотов запросами он потребляет токены из корзины. Каждому клиенту выделяется определённое количество токенов, которые он может использовать. Он может использовать их все сразу или постепенно.
В корзине теперь есть минимальное (ноль) и максимальное количество доступных токенов. При поступлении запроса система извлекает соответствующее количество токенов из корзины. При этом токены добавляются с постоянной скоростью. Например, в корзину, вместимостью 100 токенов, система может добавлять 5 токенов каждые 10 секунд. Как только корзина достигнет предела, система отбрасывает лишние токены (а не запросы).
Одно из отличий от «дырявого ведра» в том, что «корзина токенов» допускает пакетные запросы, тогда как «дырявое ведро» поддерживает только обработку запросов с постоянной скоростью.
Итого
Здесь лишь поверхностно рассмотрены четыре основных алгоритма ограничения обработки запросов. На картинке ниже они изображены схематически. Каждый из алгоритмов в реальности намного сложнее. Однако знание того, что они существуют и решают различные проблемы, может помочь выбрать тот, который подходит для ваших приложений.
См. также «Промежуточное ПО для ограничений в .NET 7»
Источник: https://www.code4it.dev/architecture-notes/rate-limiting-algorithms/
👍4
День 1781. #ЗаметкиНаПолях
Доброго зимнего субботнего утра всем. Не желаете ли немного Кавки на завтрак?)))
Да, вот такой у меня сегодня юмор. И нет, я не опечатался в фамилии. Я говорю о Ернеи Кавке, разработчике из Словении. Не так давно он выступил на конференции NDC Oslo с докладом «Common mistakes in EF Core», который я сегодня и хочу вам предложить посмотреть.
Для опытных разработчиков, давно работающих с Entity Framework, он, конечно, не откроет Америки. Ошибки, которые он рассматривает, довольно хорошо известны. Однако, если вам не давал покоя вопрос, насколько же хуже может быть, например, использование IEnumerable вместо IQueriable, то Ерней заморочился с тестами и покажет это наглядно.
В общем, приятногоаппетита просмотра.
Доброго зимнего субботнего утра всем. Не желаете ли немного Кавки на завтрак?)))
Да, вот такой у меня сегодня юмор. И нет, я не опечатался в фамилии. Я говорю о Ернеи Кавке, разработчике из Словении. Не так давно он выступил на конференции NDC Oslo с докладом «Common mistakes in EF Core», который я сегодня и хочу вам предложить посмотреть.
Для опытных разработчиков, давно работающих с Entity Framework, он, конечно, не откроет Америки. Ошибки, которые он рассматривает, довольно хорошо известны. Однако, если вам не давал покоя вопрос, насколько же хуже может быть, например, использование IEnumerable вместо IQueriable, то Ерней заморочился с тестами и покажет это наглядно.
В общем, приятного
YouTube
Common mistakes in EF Core - Jernej Kavka - NDC Oslo 2023
When JK worked with many different clients and projects, he frequently heard "EF Core is slow" or "We should do this in raw SQL" only to realize they haven't used EF Core correctly.
JK will show you how to improve your EF Core statements as well as how various…
JK will show you how to improve your EF Core statements as well as how various…
👍13
День 1782. #ЧтоНовенького
Помечаем Экспериментальные API Атрибутом Experimental
При написании библиотек и фреймворков, которые используют другие, иногда нужно сообщить клиентам, что данный API по-прежнему считается «экспериментальным». Например, предоставить другим возможность работать с частью кода, оставив для себя возможность что-то ломать. В C# 12 это можно сделать с помощью ExperimentalAttribute.
Например, в JetBrains Space SDK есть метод MapSpaceAttachmentProxy, который пока является экспериментальной функцией:
Сборка проекта, использующего этот метод, по умолчанию завершается неудачей с ошибкой “Error SPC101: ‘MapSpaceAttachmentProxy(…)’ is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.” (Ошибка SPC101: 'MapSpaceAttachmentProxy(…)' предназначен только для ознакомительных целей и может быть изменён или удалён в будущих обновлениях. Подавите эту диагностику, чтобы продолжить.)
Также с помощью свойства UrlFormat в атрибут можно добавить URL, где люди смогут найти дополнительную информацию об API. Здесь заместитель {0} MSBuild заменит диагностическим идентификатором:
Вы можете подавить диагностику экспериментальных атрибутов в файле проекта, добавив свойство <NoWarn>:
Либо с помощью директивы pragma в коде:
Что делать в старых версиях языка?
Как вариант, можно использовать атрибут Obsolete. Хотя он по умолчанию отображается только как предупреждение, но, по крайней мере, это будет видно в журнале сборки. Начиная с .NET6, вы также можете добавить к атрибуту диагностический идентификатор, давая людям возможность подавить сообщение, если они согласны использовать этот экспериментальный API:
Источник: https://blog.maartenballiauw.be/post/2023/11/08/opt-in-to-experimental-apis-using-csharp-12-experimentalattribute.html
Помечаем Экспериментальные API Атрибутом Experimental
При написании библиотек и фреймворков, которые используют другие, иногда нужно сообщить клиентам, что данный API по-прежнему считается «экспериментальным». Например, предоставить другим возможность работать с частью кода, оставив для себя возможность что-то ломать. В C# 12 это можно сделать с помощью ExperimentalAttribute.
Например, в JetBrains Space SDK есть метод MapSpaceAttachmentProxy, который пока является экспериментальной функцией:
using System.Diagnostics.CodeAnalysis;
public static class SpaceMapAttachmentProxyExtensions
{
[Experimental("SPC101")]
public static IEndpointConventionBuilder
MapSpaceAttachmentProxy(
this IEndpointRouteBuilder endpoints,
string path)
{
//…
}
}
Сборка проекта, использующего этот метод, по умолчанию завершается неудачей с ошибкой “Error SPC101: ‘MapSpaceAttachmentProxy(…)’ is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to proceed.” (Ошибка SPC101: 'MapSpaceAttachmentProxy(…)' предназначен только для ознакомительных целей и может быть изменён или удалён в будущих обновлениях. Подавите эту диагностику, чтобы продолжить.)
Также с помощью свойства UrlFormat в атрибут можно добавить URL, где люди смогут найти дополнительную информацию об API. Здесь заместитель {0} MSBuild заменит диагностическим идентификатором:
[Experimental("SPC101", UrlFormat = "https://www.example.com/diagnostics/{0}.html")]
Вы можете подавить диагностику экспериментальных атрибутов в файле проекта, добавив свойство <NoWarn>:
<Project Sdk="Microsoft.NET.Sdk.Web">
<!-- ... -->
<PropertyGroup>
<NoWarn>SPC101</NoWarn>
</PropertyGroup>
</Project>
Либо с помощью директивы pragma в коде:
#pragma warning disable SPC001
Что делать в старых версиях языка?
Как вариант, можно использовать атрибут Obsolete. Хотя он по умолчанию отображается только как предупреждение, но, по крайней мере, это будет видно в журнале сборки. Начиная с .NET6, вы также можете добавить к атрибуту диагностический идентификатор, давая людям возможность подавить сообщение, если они согласны использовать этот экспериментальный API:
[Obsolete("'MapSpaceAttachmentProxy(...)' is for evaluation purposes only and is subject to change or removal in future updates. Suppress this diagnostic to remove this warning.", DiagnosticId = "SPC101")]
Источник: https://blog.maartenballiauw.be/post/2023/11/08/opt-in-to-experimental-apis-using-csharp-12-experimentalattribute.html
👍11
День 1783. #ЗаметкиНаПолях
Лучшие Практики Логирования с Serilog. Начало
Serilog — это библиотека структурированного логирования для .NET. Она поддерживает множество мест хранения логов, которые называются приёмники данных (sink): от консоли и файлов до управляемых служб ведения журналов, таких как Application Insights. Рассмотрим лучшие практические советы при использовании Serilog.
1. Используйте систему конфигурации
Настроить Serilog в ASP.NET Core можно двумя способами:
1) Fluent API
Позволяет настраивать Serilog в коде. Недостатком является жёстко закодированная конфигурация. Любые изменения требуют развёртывания новой версии.
2) Система конфигурации
Требует установки библиотеки Serilog.Settings.Configuration. После этого добавьте следующий код:
Ниже настраивается запись логов в консоль, а также в блоке Enrich дополнительная информация для записи в лог:
2. Используйте логирование запросов
Библиотека Serilog.AspNetCore позволяет добавить логирование для конвейера запросов ASP.NET Core. Она добавляет внутренние операции ASP.NET в те же логи, что и события вашего приложения. Для этого надо вызвать метод:
SourceContext для этого типа логов — Serilog.AspNetCore.RequestLoggingMiddleware. Вот пример вывода:
3. Используйте Seq для локальной разработки
Seq — это автономный сервер поиска, анализа и оповещений, созданный для структурированных логов. Его можно бесплатно использовать для локальной разработки. Он предлагает расширенные возможности поиска и фильтрации структурированных логов. Экземпляр Seq можно развернуть в контейнере Docker:
Также в настройках Serilog нужно будет добавить запись логов в Seq. Тогда в панели управления сервера Seq вы сможете анализировать логи.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/5-serilog-best-practices-for-better-structured-logging
Лучшие Практики Логирования с Serilog. Начало
Serilog — это библиотека структурированного логирования для .NET. Она поддерживает множество мест хранения логов, которые называются приёмники данных (sink): от консоли и файлов до управляемых служб ведения журналов, таких как Application Insights. Рассмотрим лучшие практические советы при использовании Serilog.
1. Используйте систему конфигурации
Настроить Serilog в ASP.NET Core можно двумя способами:
1) Fluent API
Позволяет настраивать Serilog в коде. Недостатком является жёстко закодированная конфигурация. Любые изменения требуют развёртывания новой версии.
2) Система конфигурации
Требует установки библиотеки Serilog.Settings.Configuration. После этого добавьте следующий код:
builder.Host.UseSerilog((context, сonfig) =>
сonfig.ReadFrom.Configuration(context.Configuration));
Ниже настраивается запись логов в консоль, а также в блоке Enrich дополнительная информация для записи в лог:
{
"Serilog": {
"Using": ["Serilog.Sinks.Console"],
"MinimiumLevel": {
"Default": "Information",
"Override": {
"Micrsoft": "Information"
}
},
"WriteTo": [
{ "Name": "Console" }
],
"Enrich": [
"FromLogContext",
"WithMachineName",
"WithThreadId"
]
}
}
2. Используйте логирование запросов
Библиотека Serilog.AspNetCore позволяет добавить логирование для конвейера запросов ASP.NET Core. Она добавляет внутренние операции ASP.NET в те же логи, что и события вашего приложения. Для этого надо вызвать метод:
app.UseSerilogRequestLogging();
SourceContext для этого типа логов — Serilog.AspNetCore.RequestLoggingMiddleware. Вот пример вывода:
{
"@t": "2023-12-16T00:00:00.0000000Z",
"@mt": "HTTP {RequestMethod} {RequestPath} responded {StatusCode} in {Elapsed:0.0000} ms",
"@m": "HTTP POST /api/users responded 409 in 24.7928 ms",
"@i": "37aa1435",
"@r": ["24.7928"],
"@tr": "61a449a8606fdb64e88d6c64b7b7354e",
"@sp": "163ed90674cb12f6",
"ConnectionId": "0HMVSP0L8FVEN",
"CorrelationId": "0HMVSP0L8FVEN:0000000B",
"Elapsed": 24.792778,
"RequestId": "0HMVSP0L8FVEN:0000000B",
"RequestMethod": "POST",
"RequestPath": "/api/users",
"SourceContext": "Serilog.AspNetCore.RequestLoggingMiddleware",
"StatusCode": 409
}
3. Используйте Seq для локальной разработки
Seq — это автономный сервер поиска, анализа и оповещений, созданный для структурированных логов. Его можно бесплатно использовать для локальной разработки. Он предлагает расширенные возможности поиска и фильтрации структурированных логов. Экземпляр Seq можно развернуть в контейнере Docker:
version: '3.4'
services:
seq:
image: datalust/seq:latest
container_name: seq
environment:
- ACCEPT_EULA=Y
ports:
- 5341:5341
- 8081:80
Также в настройках Serilog нужно будет добавить запись логов в Seq. Тогда в панели управления сервера Seq вы сможете анализировать логи.
Окончание следует…
Источник: https://www.milanjovanovic.tech/blog/5-serilog-best-practices-for-better-structured-logging
👍20
День 1784. #ЗаметкиНаПолях
Лучшие Практики Логирования с Serilog. Окончание
Начало
4. Обогатите логи с помощью CorrelationId
Свойство CorrelationId помогает отслеживать логи, относящиеся к одному и тому же запросу. Это также работает в нескольких приложениях. Для этого необходимо передать CorrelationId через HTTP-заголовок, например, X-Correlation-Id. В примере ниже создадим промежуточное ПО для добавления CorrelationId:
Затем добавим промежуточное ПО в конвейер. Обратите внимание, что порядок регистрации важен. Если вам нужен CorrelationId во всех логах, нужно зарегистрировать его в начале:
5. Логируйте важные события приложений
К важным событиям можно отнести информацию о текущем запросе, ошибках, сбоях, неожиданных значениях, точках ветвления и т. д. Одни предпочитают использовать шаблон Result для обработки сбоев приложения. Поэтому понадобится специальное промежуточное ПО для логирования результатов обработки запросов. Другие используют исключения для достижения той же функциональности. Использование исключений для управления потоком — плохая практика. Но все же не забудьте добавить глобальный обработчик для необработанных исключений.
Итого
Все структурированные логи имеют одну и ту же структуру. Это облегчает фильтрацию и поиск конкретной информации в них. Также они предоставляют больше контекста и подробную информацию об ошибках приложений, облегчают выявление и устранение проблем.
Вы можете использовать LogContext в Serilog, чтобы обогатить ваши логи значением CorrelationId, что позволит легко отслеживать все записи, относящиеся к одному запросу.
Когда вы настроите структурированное ведение журнала, вам понадобится искать и анализировать свои журналы. Seq — отличный инструмент для этого, который можно бесплатно использовать для локальной разработки.
Источник: https://www.milanjovanovic.tech/blog/5-serilog-best-practices-for-better-structured-logging
Лучшие Практики Логирования с Serilog. Окончание
Начало
4. Обогатите логи с помощью CorrelationId
Свойство CorrelationId помогает отслеживать логи, относящиеся к одному и тому же запросу. Это также работает в нескольких приложениях. Для этого необходимо передать CorrelationId через HTTP-заголовок, например, X-Correlation-Id. В примере ниже создадим промежуточное ПО для добавления CorrelationId:
public class RequestLoggingMiddleware
{
private const string HEADER = "X-Correlation-Id";
private RequestDelegate _next;
public RequestLoggingMiddleware(
RequestDelegate next)
{
_next = next;
}
public Task Invoke(HttpContext ctx)
{
var cId = GetCorrelationId(ctx);
using (LogContext.PushProperty(
"CorrelationId", cId))
{
return _next.Invoke(ctx);
}
}
private static string GetCorrelationId(
HttpContext ctx)
{
ctx.Request.Headers.TryGetValue(
HEADER, out StringValues cId);
return cId.FirstOrDefault() ?? ctx.TraceIdentifier;
}
}
Затем добавим промежуточное ПО в конвейер. Обратите внимание, что порядок регистрации важен. Если вам нужен CorrelationId во всех логах, нужно зарегистрировать его в начале:
app.UseMiddleware<RequestContextLoggingMiddleware>();
5. Логируйте важные события приложений
К важным событиям можно отнести информацию о текущем запросе, ошибках, сбоях, неожиданных значениях, точках ветвления и т. д. Одни предпочитают использовать шаблон Result для обработки сбоев приложения. Поэтому понадобится специальное промежуточное ПО для логирования результатов обработки запросов. Другие используют исключения для достижения той же функциональности. Использование исключений для управления потоком — плохая практика. Но все же не забудьте добавить глобальный обработчик для необработанных исключений.
Итого
Все структурированные логи имеют одну и ту же структуру. Это облегчает фильтрацию и поиск конкретной информации в них. Также они предоставляют больше контекста и подробную информацию об ошибках приложений, облегчают выявление и устранение проблем.
Вы можете использовать LogContext в Serilog, чтобы обогатить ваши логи значением CorrelationId, что позволит легко отслеживать все записи, относящиеся к одному запросу.
Когда вы настроите структурированное ведение журнала, вам понадобится искать и анализировать свои журналы. Seq — отличный инструмент для этого, который можно бесплатно использовать для локальной разработки.
Источник: https://www.milanjovanovic.tech/blog/5-serilog-best-practices-for-better-structured-logging
👍15
День 1785. #ЗаметкиНаПолях
Разбираем Native AOT в .NET
Сегодня разберём подробно, что такое AOT-компиляция в .NET.
Ahead-of-Time (AOT) компиляция в .NET представляет собой компиляцию кода C# в нативный код на целевом компьютере.
Традиционная компиляция в .NET включает два этапа:
1) Компиляция C# создаёт файлы DLL, содержащие код на промежуточном языке (IL). Такая DLL называется .NET-сборкой.
2) При выполнении программы среда исполнения .NET (CLR) загружает .NET-сборки. Подсистема CLR (Just-In-Time компилятор) отвечает за компиляцию IL-кода метода при первом его вызове в нативный код, выполняемый непосредственно процессором.
С другой стороны, Native AOT компиляция состоит из одного шага: компиляции исходного кода C# в нативный код машины. Это включает преобразование кода C# в код IL, а затем в нативный код, но это детали реализации.
Преимущества
1) Производительность.
Native AOT значительно сокращает время запуска и повышает общую производительность приложения. Отсутствие накладных расходов на JIT-компиляцию во время выполнения приводит к более быстрому выполнению кода.
2) Упрощённое развертывание.
AOT часто приводит к созданию автономных исполняемых файлов с минимальным или нулевым количеством зависимостей. Это упрощает процессы развёртывания, исключая необходимость установки компонентов среды выполнения.
3) Меньший размер приложения.
Удаляя ненужный код, AOT может значительно уменьшить размер приложения. Это не только экономит место, но и оптимизирует использование памяти, что особенно важно в средах с ограниченными ресурсами, таких как мобильные устройства или устройства IoT.
4) Защита исходного кода.
AOT-компиляция преобразует исходный код в оптимизированный машинный код, который более запутан и сложен для расшифровки, чем IL-код, который можно легко декомпилировать в исходный код C#. Это повышает безопасность чувствительных алгоритмов и бизнес-логики.
Недостатки
1) Компиляция для конкретной платформы
AOT создаёт нативный код для конкретной платформы, адаптированный к конкретной архитектуре или операционной системе. Полученный исполняемый файл не будет работать на другой платформе.
2) Нет поддержки кросс-ОС компиляции.
Например, в Windows нельзя создать версию для Linux и наоборот.
3) Частичная поддержка рефлексии.
Рефлексия опирается на динамическую генерацию кода и обнаружение типов во время выполнения, что противоречит природе предварительной компиляции статического кода при AOT. Хотя до некоторой степени рефлексия всё же работает.
4) Требуются зависимости, совместимые с AOT.
Необходимо, чтобы все зависимости, используемые в проекте, были AOT-совместимыми.
5) Увеличенное время сборки.
Генерация нативного кода может значительно увеличить время сборки, особенно для более крупных проектов или приложений с обширной базой кода.
6) Для разработки требуются инструменты C++ разработки.
AOT может компилироваться только с установленными инструментами для C++ разработки, которые могут занимать до 7Гб на диске.
Поддержка Native AOT .NET 8
Поддерживаются:
- Промежуточное ПО
- Минимальные API
- gRPC
- HTTP-Сервер Kestrel
- Авторизация
- Аутентификация через JWT
- CORS
- Проверки работоспособности
- Кэширование вывода и ответа
- Декомпрессия запроса
- Сжатие ответа
- Статические файлы
- Веб-сокеты
- ADO.NET
- PostgreSQL
- Dapper
- SQLite
Не поддерживаются:
- ASP.NET Core MVC
- WebAPI
- SignalR
- Blazor Server
- Razor Pages
- Сессии
- Spa
- Entity Framework Core
Итого
В .NET 8 Native AOT уже достаточно развит и может использоваться в производстве. Мы, безусловно, можем надеяться, что Microsoft продолжит улучшать поддержку AOT.
Источник: https://blog.ndepend.com/net-native-aot-explained/
Разбираем Native AOT в .NET
Сегодня разберём подробно, что такое AOT-компиляция в .NET.
Ahead-of-Time (AOT) компиляция в .NET представляет собой компиляцию кода C# в нативный код на целевом компьютере.
Традиционная компиляция в .NET включает два этапа:
1) Компиляция C# создаёт файлы DLL, содержащие код на промежуточном языке (IL). Такая DLL называется .NET-сборкой.
2) При выполнении программы среда исполнения .NET (CLR) загружает .NET-сборки. Подсистема CLR (Just-In-Time компилятор) отвечает за компиляцию IL-кода метода при первом его вызове в нативный код, выполняемый непосредственно процессором.
С другой стороны, Native AOT компиляция состоит из одного шага: компиляции исходного кода C# в нативный код машины. Это включает преобразование кода C# в код IL, а затем в нативный код, но это детали реализации.
Преимущества
1) Производительность.
Native AOT значительно сокращает время запуска и повышает общую производительность приложения. Отсутствие накладных расходов на JIT-компиляцию во время выполнения приводит к более быстрому выполнению кода.
2) Упрощённое развертывание.
AOT часто приводит к созданию автономных исполняемых файлов с минимальным или нулевым количеством зависимостей. Это упрощает процессы развёртывания, исключая необходимость установки компонентов среды выполнения.
3) Меньший размер приложения.
Удаляя ненужный код, AOT может значительно уменьшить размер приложения. Это не только экономит место, но и оптимизирует использование памяти, что особенно важно в средах с ограниченными ресурсами, таких как мобильные устройства или устройства IoT.
4) Защита исходного кода.
AOT-компиляция преобразует исходный код в оптимизированный машинный код, который более запутан и сложен для расшифровки, чем IL-код, который можно легко декомпилировать в исходный код C#. Это повышает безопасность чувствительных алгоритмов и бизнес-логики.
Недостатки
1) Компиляция для конкретной платформы
AOT создаёт нативный код для конкретной платформы, адаптированный к конкретной архитектуре или операционной системе. Полученный исполняемый файл не будет работать на другой платформе.
2) Нет поддержки кросс-ОС компиляции.
Например, в Windows нельзя создать версию для Linux и наоборот.
3) Частичная поддержка рефлексии.
Рефлексия опирается на динамическую генерацию кода и обнаружение типов во время выполнения, что противоречит природе предварительной компиляции статического кода при AOT. Хотя до некоторой степени рефлексия всё же работает.
4) Требуются зависимости, совместимые с AOT.
Необходимо, чтобы все зависимости, используемые в проекте, были AOT-совместимыми.
5) Увеличенное время сборки.
Генерация нативного кода может значительно увеличить время сборки, особенно для более крупных проектов или приложений с обширной базой кода.
6) Для разработки требуются инструменты C++ разработки.
AOT может компилироваться только с установленными инструментами для C++ разработки, которые могут занимать до 7Гб на диске.
Поддержка Native AOT .NET 8
Поддерживаются:
- Промежуточное ПО
- Минимальные API
- gRPC
- HTTP-Сервер Kestrel
- Авторизация
- Аутентификация через JWT
- CORS
- Проверки работоспособности
- Кэширование вывода и ответа
- Декомпрессия запроса
- Сжатие ответа
- Статические файлы
- Веб-сокеты
- ADO.NET
- PostgreSQL
- Dapper
- SQLite
Не поддерживаются:
- ASP.NET Core MVC
- WebAPI
- SignalR
- Blazor Server
- Razor Pages
- Сессии
- Spa
- Entity Framework Core
Итого
В .NET 8 Native AOT уже достаточно развит и может использоваться в производстве. Мы, безусловно, можем надеяться, что Microsoft продолжит улучшать поддержку AOT.
Источник: https://blog.ndepend.com/net-native-aot-explained/
👍16
День 1786. #Карьера
12 Качеств Сеньора, Которыми Должны Овладеть Джуны. Начало
Самый быстрый способ достичь вершины в любой области — изучать людей, которые уже находятся на вершине… И делать то, что они делают, а вы — нет. Если вы зарабатываете на жизнь написанием кода, вам стоит обратить внимание на навыки, привычки и отличительные черты старших разработчиков.
1. Внимание
Сосредоточиться означает сказать «нет» одним вещам, чтобы заняться другими. В идеале — говорить «да» тому, что позволяет вам прогрессировать, а остальному – «нет». Для многих разработчиков это сложно, потому что это противоречит нашему естественному инстинкту. Признайте, что вы не можете сделать всё и что не у всех равные возможности.
Вы не можете изучить все новинки, посетить все конференции или прочитать все статьи. Ваше время ограничено. Как и ваша энергия.
Как ни странно, чем лучше вы сможете выбирать важные вещи, тем быстрее вы будете прогрессировать. Старшие разработчики говорят больше «нет», чем «да». Они заканчивают больше проектов и осваивают фреймворк, с которым уже работают, прежде чем изучать новый.
Поэтому первое качество, которое нужно развить - сосредоточенность.
2. Мышление второго порядка
Отличительная черта джуна – мышление «давайте сделаем это, а там посмотрим». Они склонны сначала писать код, а потом думать. Это может быть хорошим подходом в начале, но, когда вы работаете над промышленным ПО, некоторые технические решения вы не сможете изменить, или это будет слишком сложно.
Старшие разработчики знают, что, если вы влюбитесь в фреймворки и библиотеки, которые знаете лучше всего, вы начнёте принимать неверные технические решения. Сеньоры дважды думают о последствиях своего выбора и о возможных недостатках, которые может иметь их решение.
Учёт обстоятельств второго порядка сделает вас гораздо лучшим разработчиком. Это также поможет вам во время технических собеседований.
3. Прагматизм
Когда джуны читают книгу о лучших практиках, они сразу же пытаются применить их к каждой строке кода, следуя им неукоснительно. Если вы не можете принимать технические решения самостоятельно, гораздо проще придерживаться заранее определённых правил. Но разработка ПО — это не религия.
Старшие разработчики знают, как сбалансировать лучшие практики и время выхода на рынок. Когда следует использовать костыли, а когда нет. Костыль приведёт к появлению ошибок и технического долга. Постоянное соблюдение правил при изменении контекста вашего кода приведёт к неверным решениям. Нужен баланс. Будьте готовы пересматривать свои технические решения в зависимости от обстоятельств.
4. Состоятельность
Из-за неуверенности в себе младшие разработчики постоянно пытаются доказать другим свою состоятельность. То же самое и со старшими разработчиками, которые не уверены в своей ценности и навыках. Они основывают свою уверенность на подтверждении, которое получают от других. Это проигрышная стратегия - пытаться показать, насколько много вы знаете, в технических дискуссиях, обсуждая других или доделывая работу поздно вечером или на выходных. Такое поведение создаёт токсичную командную среду и приводит к неприятным последствиям.
Есть два способа справиться с этим:
1) Прекратить ожидать признания извне. Правда в том, что вам не нужно никому доказывать свою правоту. Только себе.
2) Примириться с негативными голосами в вашей голове. Вы можете быть своим худшим критиком. Перфекционизм, страх неудачи и ошибочное представление о том, кто такой «настоящий» разработчик, разрушают вашу самооценку. Вот почему, как бы усердно вы ни работали, вы всегда будете чувствовать, что терпите неудачу.
Сосредоточьтесь на овладении своим ремеслом, а остальное приложится. Вы мгновенно станете более уверенными в себе и своих силах. И перестанете пытаться доказать свою правоту незнакомцам.
Продолжение следует…
Источник: https://dev.to/dragosnedelcu/12-senior-developer-traits-junior-developers-need-to-master-285m
12 Качеств Сеньора, Которыми Должны Овладеть Джуны. Начало
Самый быстрый способ достичь вершины в любой области — изучать людей, которые уже находятся на вершине… И делать то, что они делают, а вы — нет. Если вы зарабатываете на жизнь написанием кода, вам стоит обратить внимание на навыки, привычки и отличительные черты старших разработчиков.
1. Внимание
Сосредоточиться означает сказать «нет» одним вещам, чтобы заняться другими. В идеале — говорить «да» тому, что позволяет вам прогрессировать, а остальному – «нет». Для многих разработчиков это сложно, потому что это противоречит нашему естественному инстинкту. Признайте, что вы не можете сделать всё и что не у всех равные возможности.
Вы не можете изучить все новинки, посетить все конференции или прочитать все статьи. Ваше время ограничено. Как и ваша энергия.
Как ни странно, чем лучше вы сможете выбирать важные вещи, тем быстрее вы будете прогрессировать. Старшие разработчики говорят больше «нет», чем «да». Они заканчивают больше проектов и осваивают фреймворк, с которым уже работают, прежде чем изучать новый.
Поэтому первое качество, которое нужно развить - сосредоточенность.
2. Мышление второго порядка
Отличительная черта джуна – мышление «давайте сделаем это, а там посмотрим». Они склонны сначала писать код, а потом думать. Это может быть хорошим подходом в начале, но, когда вы работаете над промышленным ПО, некоторые технические решения вы не сможете изменить, или это будет слишком сложно.
Старшие разработчики знают, что, если вы влюбитесь в фреймворки и библиотеки, которые знаете лучше всего, вы начнёте принимать неверные технические решения. Сеньоры дважды думают о последствиях своего выбора и о возможных недостатках, которые может иметь их решение.
Учёт обстоятельств второго порядка сделает вас гораздо лучшим разработчиком. Это также поможет вам во время технических собеседований.
3. Прагматизм
Когда джуны читают книгу о лучших практиках, они сразу же пытаются применить их к каждой строке кода, следуя им неукоснительно. Если вы не можете принимать технические решения самостоятельно, гораздо проще придерживаться заранее определённых правил. Но разработка ПО — это не религия.
Старшие разработчики знают, как сбалансировать лучшие практики и время выхода на рынок. Когда следует использовать костыли, а когда нет. Костыль приведёт к появлению ошибок и технического долга. Постоянное соблюдение правил при изменении контекста вашего кода приведёт к неверным решениям. Нужен баланс. Будьте готовы пересматривать свои технические решения в зависимости от обстоятельств.
4. Состоятельность
Из-за неуверенности в себе младшие разработчики постоянно пытаются доказать другим свою состоятельность. То же самое и со старшими разработчиками, которые не уверены в своей ценности и навыках. Они основывают свою уверенность на подтверждении, которое получают от других. Это проигрышная стратегия - пытаться показать, насколько много вы знаете, в технических дискуссиях, обсуждая других или доделывая работу поздно вечером или на выходных. Такое поведение создаёт токсичную командную среду и приводит к неприятным последствиям.
Есть два способа справиться с этим:
1) Прекратить ожидать признания извне. Правда в том, что вам не нужно никому доказывать свою правоту. Только себе.
2) Примириться с негативными голосами в вашей голове. Вы можете быть своим худшим критиком. Перфекционизм, страх неудачи и ошибочное представление о том, кто такой «настоящий» разработчик, разрушают вашу самооценку. Вот почему, как бы усердно вы ни работали, вы всегда будете чувствовать, что терпите неудачу.
Сосредоточьтесь на овладении своим ремеслом, а остальное приложится. Вы мгновенно станете более уверенными в себе и своих силах. И перестанете пытаться доказать свою правоту незнакомцам.
Продолжение следует…
Источник: https://dev.to/dragosnedelcu/12-senior-developer-traits-junior-developers-need-to-master-285m
👍29
День 1787. #Карьера
12 Качеств Сеньора, Которыми Должны Овладеть Джуны. Продолжение
Начало
5. Знание основ
Знание фреймворков или библиотек не делает вас сеньором. Это всего лишь верхушка айсберга. Такие темы, как отладка или оптимизация производительности, являются для большинства разработчиков игрой в угадайку. Они не привыкли копаться в глубинах библиотек и инструментов, с которыми работают. Чтобы стать старшим разработчиком, вы должны понимать не только «Что», но и «Почему». Старший разработчик сможет не только создать приложение на фреймворке, но он также понимает, почему он выбрал этот фреймворк, и как он устроен. Хорошая новость заключается в том, что как только вы освоите основы, ваш уровень в целом повысится.
6. Поставка под ключ
Компании избегают нанимать джунов, потому что им нужно много внешней помощи, чтобы добиться цели. Внешняя помощь означает, что вам придётся беспокоить старшего разработчика, чтобы выполнить ваши задачи.
Старшие разработчики выполняют работу «под ключ». Дайте им список требований, а со всем остальным они разберутся. Это не значит, что они волки-одиночки, обычно они отлично умеют работать в команде. И это не означает, что они знают каждую часть жизненного цикла разработки. Но они понимают все основные этапы и могут внести свой вклад в каждый из них (фронтенд, бэкенд, развёртывание).
7. Ментальные модели
Сеньоры могут понимать более сложные кодовые базы и требования. Они могут понять обстоятельства второго порядка. Как изменения в кодовой базе повлияют на производительность, затраты и даже на команду. И это не потому, что они запоминают каждую деталь реализации, а потому что абстрагируют сложность кода в ментальные модели.
Они это делают, изучая фреймворки и библиотеки и лежащие в их основе паттерны проектирования. Паттернов невероятное множество, поэтому лучший способ начать — это выбрать любую среду, с которой вы работаете, и попытаться выйти за рамки кода.
Начните спрашивать себя, почему создатели фреймворка построили его таким образом? Построен он на новых концепциях или это просто реализация старых принципов (что обычно и происходит)? Так вы построите свои ментальные модели разработки и сможете справляться с более сложными задачами.
8. Коммуникация
Сеньоры могут хорошо вести технические дискуссии и влиять на людей вокруг них: бизнес, менеджеров продукта или коллег-разработчиков, - сеньоры знают, как направить их в правильном направлении. Они делают это, используя сочетание настойчивости, технических знаний и коммуникативных навыков.
Также они могут устанавливать чёткие границы. Не соглашаться, не проявляя эмоций, постоять за себя (и других) во время митингов, агрессивно договориться о своей зарплате.
Если коллега во время проверки кода начнёт обвинять других, сеньор знает, как его остановить. Если руководство пытается вмешиваться в работу и заниматься микроменеджментом, сеньор знает, как прекратить это, не повредив отношениям. Не существует пошагового руководства, как таким стать, поможет только практика. Первый шаг — перестать все время говорить «Да». И начать добиваться своего на переговорах о зарплате.
9. Долгосрочное мышление
Джун думает про «сейчас». Он изменяет фрагмент кода, не задумываясь о его правильном рефакторинге, или просто игнорирует тестирование и производительность. Так же джуны думают о своей карьере: слишком часто меняют работу, сжигая мосты, не совершенствуются, если работа стабильна и т.п.
Хорошие вещи требуют времени. Старшие разработчики знают это и соответствующим образом корректируют своё мышление. Если вы решили, что ваша карьера будет связана с разработкой ПО в ближайшие хотя бы 10 лет, инвестируйте в свои навыки, потому что эти инвестиции окупятся. Инвестируйте в коммуникации, потому что никто не знает, когда то или иное знакомство сможет вам пригодиться.
Окончание следует…
Источник: https://dev.to/dragosnedelcu/12-senior-developer-traits-junior-developers-need-to-master-285m
12 Качеств Сеньора, Которыми Должны Овладеть Джуны. Продолжение
Начало
5. Знание основ
Знание фреймворков или библиотек не делает вас сеньором. Это всего лишь верхушка айсберга. Такие темы, как отладка или оптимизация производительности, являются для большинства разработчиков игрой в угадайку. Они не привыкли копаться в глубинах библиотек и инструментов, с которыми работают. Чтобы стать старшим разработчиком, вы должны понимать не только «Что», но и «Почему». Старший разработчик сможет не только создать приложение на фреймворке, но он также понимает, почему он выбрал этот фреймворк, и как он устроен. Хорошая новость заключается в том, что как только вы освоите основы, ваш уровень в целом повысится.
6. Поставка под ключ
Компании избегают нанимать джунов, потому что им нужно много внешней помощи, чтобы добиться цели. Внешняя помощь означает, что вам придётся беспокоить старшего разработчика, чтобы выполнить ваши задачи.
Старшие разработчики выполняют работу «под ключ». Дайте им список требований, а со всем остальным они разберутся. Это не значит, что они волки-одиночки, обычно они отлично умеют работать в команде. И это не означает, что они знают каждую часть жизненного цикла разработки. Но они понимают все основные этапы и могут внести свой вклад в каждый из них (фронтенд, бэкенд, развёртывание).
7. Ментальные модели
Сеньоры могут понимать более сложные кодовые базы и требования. Они могут понять обстоятельства второго порядка. Как изменения в кодовой базе повлияют на производительность, затраты и даже на команду. И это не потому, что они запоминают каждую деталь реализации, а потому что абстрагируют сложность кода в ментальные модели.
Они это делают, изучая фреймворки и библиотеки и лежащие в их основе паттерны проектирования. Паттернов невероятное множество, поэтому лучший способ начать — это выбрать любую среду, с которой вы работаете, и попытаться выйти за рамки кода.
Начните спрашивать себя, почему создатели фреймворка построили его таким образом? Построен он на новых концепциях или это просто реализация старых принципов (что обычно и происходит)? Так вы построите свои ментальные модели разработки и сможете справляться с более сложными задачами.
8. Коммуникация
Сеньоры могут хорошо вести технические дискуссии и влиять на людей вокруг них: бизнес, менеджеров продукта или коллег-разработчиков, - сеньоры знают, как направить их в правильном направлении. Они делают это, используя сочетание настойчивости, технических знаний и коммуникативных навыков.
Также они могут устанавливать чёткие границы. Не соглашаться, не проявляя эмоций, постоять за себя (и других) во время митингов, агрессивно договориться о своей зарплате.
Если коллега во время проверки кода начнёт обвинять других, сеньор знает, как его остановить. Если руководство пытается вмешиваться в работу и заниматься микроменеджментом, сеньор знает, как прекратить это, не повредив отношениям. Не существует пошагового руководства, как таким стать, поможет только практика. Первый шаг — перестать все время говорить «Да». И начать добиваться своего на переговорах о зарплате.
9. Долгосрочное мышление
Джун думает про «сейчас». Он изменяет фрагмент кода, не задумываясь о его правильном рефакторинге, или просто игнорирует тестирование и производительность. Так же джуны думают о своей карьере: слишком часто меняют работу, сжигая мосты, не совершенствуются, если работа стабильна и т.п.
Хорошие вещи требуют времени. Старшие разработчики знают это и соответствующим образом корректируют своё мышление. Если вы решили, что ваша карьера будет связана с разработкой ПО в ближайшие хотя бы 10 лет, инвестируйте в свои навыки, потому что эти инвестиции окупятся. Инвестируйте в коммуникации, потому что никто не знает, когда то или иное знакомство сможет вам пригодиться.
Окончание следует…
Источник: https://dev.to/dragosnedelcu/12-senior-developer-traits-junior-developers-need-to-master-285m
👍20