.NET Разработчик
6.51K subscribers
427 photos
2 videos
14 files
2.04K links
Дневник сертифицированного .NET разработчика.

Для связи: @SBenzenko

Поддержать канал:
- https://boosty.to/netdeveloperdiary
- https://patreon.com/user?u=52551826
- https://pay.cloudtips.ru/p/70df3b3b
Download Telegram
День 1367. #TypesAndLanguages
Пару Слов об Оценках и Стори-Пойнтах. Продолжение
Начало

Нам нужны оценки по времени
Нужно ведь планировать работу наперёд.

Да. Поэтому оценивать задачи в стори-пойнтах — плохо. Программисты разные: у них разный опыт, разные навыки, им нравятся разные части разработки ПО. Нельзя просто придумать коэффициент для перевода SP в часы, так как каждый спринт индивидуален и каждый программист индивидуален, поэтому придётся знать эти коэффициенты для каждого человека и уметь предсказывать будущее (поскольку они меняются с каждым спринтом). Из-за этого программисту очень просто объяснить, почему он работал над задачей «слишком долго»: потому, что SP не передают никакой оценки времени (кроме того, что должны укладываться в один спринт).

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

Поскольку программистов редко заботят нетехнические вещи, они хотят избавиться от ответственности. И именно поэтому им нравится оценивать задачи в стори-пойнтах. Не нужно думать о часах, и у них есть очень хорошее объяснение, что дела будут сделаны «когда они будут сделаны». Очевидно, что это мало полезно всем остальным, и хорошие инженеры это понимают. Если вы считаете, что нормально оценивать задачи в SP, то представьте, что сантехник говорит вам, что починка вашей раковины «займет 8 SP». Очевидно, вас это не устроит, вместо этого вы ожидаете оценки по времени. Как ни странно, программисты часто утверждают, что разработка ПО отличается от «реальной жизни», и поэтому они не могут оценивать по времени надолго. Это неправда.

Как это должно выглядеть?
Как только вы разбиваете истории на задачи, вы оцениваете каждую задачу в часах (или днях, или любой другой единице времени). Затем просто выполняете расчёты, чтобы проверить, какие задачи вы можете включить в спринт. И на основе этого определяете, какие пользовательские истории вы обработаете.

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

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

Если вы подсчитаете, что в среднем команда набирает X стори-пойнтов за спринт, то вы можете посмотреть сколько работы вам предстоит сделать, сколько из неё оценено в SP, и достаточно ли вам работы до следующего релиза. Просто умножаете производительность на количество спринтов до релиза. Дело не в том, чтобы быть суперточным, а в том, чтобы понимать, сколько времени это займёт. Если вы видите, что у вас достаточно стори-поинтов, чтобы заполнить работой следующий год, то нет необходимости делать бизнес-анализ с вашим клиентом сейчас, это может подождать до следующего месяца. Может быть и наоборот. Вы думаете, что вам хватит работы на ближайшие 6 месяцев, а по оценке получается только на 5. Делайте выводы.

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

Источники:
-
https://blog.adamfurmanek.pl/2022/06/11/types-and-programming-languages-part-12/
-
https://blog.adamfurmanek.pl/2022/06/18/types-and-programming-languages-part-13/
👍6
День 1368. #TypesAndLanguages
Пару Слов об Оценках и Стори-Пойнтах. Окончание
Начало
Продолжение

Цикл обратной связи
Стори-пойнты используются не только для планирования релизов, но и для относительной оценки вашей работы. Вам нужно сравнивать вещи друг с другом и уметь сказать, какие вещи «большие», а какие «маленькие». Это должны знать все стороны.

Сначала клиент указывает, что нужно сделать. Затем нам нужно провести бизнес-анализ с клиентом, чтобы получить некоторые детали, разбить работу на пользовательские истории. Далее инженеры-программисты должны собраться вместе и оценить работу в стори-пойнтах. Они не должны оценивать точную продолжительность в часах/днях/месяцах. Им нужно только показать, какие задачи «большие», а какие «маленькие».

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

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

Планирование в единицах времени
Если вы используете производительность, чтобы рассчитать, достаточно ли у вас работы на следующие 6 месяцев, то вы эффективно используете стори-пойнты как единицу времени. И в данном случае это нормально, потому что это всего лишь прогноз, а не обязательство, какие пользовательские истории следует выполнить. Может показаться, что мы из Agile вернулись к модели Waterfall. Нет, потому что мы корректируем процесс по ходу дела. В Waterfall мы сначала анализируем работу, потом делаем реализацию, потом тестируем, а потом уже разворачиваем. И всё. При спиральном (инкрементном, agile) подходе мы работаем в терминах релизов: планируем гораздо меньшую часть работы, и поставляем её. Вот в чём разработка ПО немного отличается от строительства домов. Вы переезжаете в новый дом только после завершения строительства. Однако при разработке ПО мы начинаем использовать продукт, даже если он ещё не готов, и делаем это гораздо раньше. В этом суть поэтапной работы: мы не ждём, пока дом будет «готов», мы въезжаем, как только у нас есть одна комната, без окон, без потолка и без входных дверей.

Однако мы не можем быть точны. Годовую работу мы не оценим идеально, мы всегда пропустим дедлайн. Но мы рискуем, потому что можем исправить траекторию на ходу. Все меняется: мы можем потерять техническое преимущество, потерять инвестора, люди могут уйти из компании или попасть под автобус. Есть много вещей, которые могут пойти не так, поэтому просто нужно признать, что мы не будем точны. Но дело не в том, чтобы через год понять, что мы пропустили дедлайн, а в том, чтобы выяснить это заранее и быть «достаточно точными».

Как быть достаточно точным?
История показывает, что оценки экспертов не бывают точны. Мы можем ограничить незавершённую работу, уменьшить скрытую работу, автоматизировать рутинную работу, чтобы улучшить процесс и получить более надёжные оценки. Можем использовать метод Монте-Карло, находить критические пути и моделировать различные сценарии. Но мы также можем просто переоценить наши планы и предположить, что 30% из них не будут реализованы в течение года. Всё это приемлемо, если вы знаете, насколько вы неточны.

Источник: https://blog.adamfurmanek.pl/2022/06/18/types-and-programming-languages-part-13/
День 1369.
Поговорили с Игорем Лабутиным о переводе книги «Entity Framework Core в действии». Как шёл процесс перевода, сложно ли это, зачем всё это надо и нужны ли вообще в наше время книги по технологиям.

Разговор вошёл в 59й выпуск подкаста RadioDotNet от 28 октября 2022 года.
Конкретно наш разговор на 01:26:00.
👍15
День 1370. #ЗаметкиНаПолях #AsyncTips
Блокировки и команда lock

Задача
Имеются общие данные. Требуется обеспечить безопасное чтение и запись этих данных из нескольких потоков.

Решение
Лучшее решение в такой ситуации — использование команды блокировки lock. Если поток входит в блок lock, то все остальные потоки не смогут войти в этот блок, пока блокировка не будет снята:
class MyClass
{
// Блокировка защищает поле _value.
private readonly object _mutex = new object();
private int _value;
public void Increment()
{
lock (_mutex)
{
_value = _value + 1;
}
}
}

В .NET существует несколько механизмов блокировки: Monitor, Spin, Lock и ReaderWriterLockSlim. В большинстве приложений эти типы блокировок практически никогда не должны использоваться напрямую. В частности, разработчики часто используют ReaderWriterLockSlim, даже когда такая сложность не является необходимой. Базовая команда lock нормально справляется с 99% случаев.

При использовании блокировок следует руководствоваться четырьмя важными рекомендациями:

1. Ограничьте видимость блокировки.
Объект, используемый в команде lock, должен быть приватным полем, которое никогда не должно быть доступным извне класса. Обычно есть не более одного поля блокировки на тип; если у вас их несколько, рассмотрите возможность рефакторинга этого типа на несколько типов. Блокировка может устанавливаться по любому ссылочному типу, но рекомендуется создавать отдельное поле специально для команды lock, как в примере выше. Если вы устанавливаете блокировку по другому экземпляру, убедитесь в том, что он является приватным для вашего класса; он не должен передаваться в конструкторе или возвращаться из get-метода свойства. Никогда не используйте lock(this) или lock с любым экземпляром Type или string; это может привести к взаимоблокировкам, доступным из другого кода.

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

3. Сократите до минимума объем кода, защищённого блокировкой.
Один из аспектов, на которые следует обращать внимание, — блокирующие вызовы при удержании блокировок. В идеале их быть вообще не должно.

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

Источник: Стивен Клири “Конкурентность в C#”. 2-е межд. изд. — СПб.: Питер, 2020. Глава 12.
👍17
Программа конференции DotNext 2022 Autumn полностью готова!

Конференция пройдет:
🌐 3–4 ноября онлайн
👥 20 ноября офлайн, в Москве

Вас ждут 26 докладов от спикеров из Альфа-Банка, Dodo Engineering, Тинькофф, Контура и других компаний.

Вот несколько примеров докладов:
✔️ Андрей Акиньшин, «Поговорим об описательной статистике перформанс-распределений»
✔️ Дмитрий Сошников, «Как научить вашего ребенка программировать (и не только)»
✔️ Вагиф Абилов, «Распределенный трейсинг OpenTelemetry вместо логирования всего подряд»

Участников ждут тематические дискуссии с другими участниками, интервью с экспертами, доклады от партнеров и много других активностей.

Промокод netdeveloper2022JRGpc дает скидку от 20% на билеты из категории «Для частных лиц».

Подробности и билеты на сайте — dotnext.ru
День 1371. #ЗаметкиНаПолях
Записи с Выражениями и Вычисляемыми Свойствами
Учитывая краткость записей и даже игнорируя другие их характеристики, когда нужен неизменяемый тип, проще всего использовать запись. Однако стоит помнить об их характеристиках, чтобы не получить неожиданные результаты.

Рассмотрим следующую запись:
public record SomeRecord(string Val)
{
public string CalcVal { get; } =
Val + " *calculated*";
}

Мы используем первичный конструктор для объявления и инициализации свойства Val, но у нас также есть другое свойство CalcVal, которое вычисляется с использованием Val. Вроде просто. Но что если мы используем with для создания другой записи:
var x = new SomeRecord("42");
var y = x with {Val = "69"};
Console.WriteLine(x);
Console.WriteLine(y);

Вот что получилось:
SomeRecord { Val = 42, CalcVal = 42 *calculated* }
SomeRecord { Val = 69, CalcVal = 42 *calculated* }


CalcVal во второй записи по-прежнему имеет то же значение, что и в первой. Это имеет смысл, так как при использовании выражения with запись клонируется, а новые значения получают только свойства, указанные в скобках.

Простой способ исправить это — использовать вычисляемое свойство:
public record SomeRecord(string Val)
{
public string CalcVal => Val + " *calculated*";
}

Это решает проблему и может быть допустимым решением в целом. Однако каждый раз, когда мы вызываем CalcVal значение будет вычисляться заново. В зависимости от того, как используется свойство, это может быть, а может и не быть проблемой, поскольку мы всегда повторяем одну и ту же логику и создаем новые объекты для возврата значения.

Источник: https://blog.codingmilitia.com/2022/09/01/beware-of-records-with-expressions-and-calculated-properties/
👍10
День 1372. #DevOps
Принципы, Реализации и Культура DevOps. Начало
Когда организации начинают использовать DevOps для разработки приложений, многие понимают DevOps только как часть инфраструктуры развёртывания и выбирают подмножество DevOps, вместо того чтобы понять культуру и технологические изменения, необходимые для успеха. Организации должны сначала определить, какой подход «Ops» лучше всего им подходит и интегрировать его в свои рабочие процессы. При этом они будут лучше координировать группы разработки и поддержки относительно общих целей и протоколов.

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

Вариации DevOps
1. DevOps: улучшение технических процессов и культуры
DevOps — это общий термин для операций, которые сочетают концепции Agile-разработки с ИТ-операциями и ускоряют разработку и развёртывание приложений в облачных средах. Хотя существуют разные поджанры DevOps, каждый поджанр представляет собой отдельное приложение методологии DevOps, направленное на то, чтобы сделать разработку более гибкой, стабильной и эффективной. Поскольку DevOps значительно сокращает жизненный цикл разработки, этот оптимизированный подход к разработке приложений довольно популярен.

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

3. NoOps: сокращение внутренних команд для операций
NoOps — это возвышенный взгляд на DevOps. Ощущение, что он настолько автоматизирован, что не требует отдельных специалистов внутри компании, а это означает, что ручное вмешательство в процессы не требуется. NoOps отличается от DevOps тем, что меньше внимания уделяется Agile и управлению процессами. Этот процесс предполагает, что разработчикам не нужно знать, как использовать автоматизированные инструменты, и использует методы непрерывной интеграции, позволяющие разработчикам сосредоточиться только на разработке приложений.

Хотя NoOps ускоряет процессы развёртывания, сам по себе он не подразумевает открытого общения между командами и менеджмента команд. Успешное внедрение NoOps возможно только в том случае, если команда разработчиков небольшая, но сильная и способна справиться с разработкой и поддержкой.

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

Метод GitOps также может похвастаться тем, что он поддерживается одними из самых инновационных облачных сервисов на рынке, что позволяет автоматизировать процесс создания обновления, тестирования на наличие ошибок, проверки кода и отправки обновления в производство. Поскольку Git — единственный источник достоверной информации о GitOps, крайне важно эффективно защитить репозиторий Git, чтобы избежать ненужных коммитов или пулл-реквестов.

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

Источник:
https://devops.com/devops-principles-implementations-and-culture/
👍13
День 1373. #DevOps
Принципы, Реализации и Культура DevOps. Окончание
Начало

5. CloudOps: реализация облачных функций
CloudOps пытается получить больше преимуществ от облачных функций, предлагаемых современными провайдерами. Поскольку CloudOps фокусируется на распределённой разработке и развёртывании, отсутствует единая точка отказа, что делает всю облачную среду более надёжной. Кроме того, некоторые части рабочего процесса в этом типе операций могут проходить без сохранения состояния, что делает его экономически эффективным, поскольку организации платят только за те ресурсы, которые они фактически используют. Несмотря на то, что CloudOps может быть эффективным с точки зрения времени и затрат, чрезвычайно важна правильная настройка конфигурации, чтобы этот подход был рабочим, что может означать дополнительные сложности при настройке конвейеров CI/CD.

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

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

7. ITOps: автоматизация конвейеров управления ИТ
ИТ в общих чертах определяется как управление системами, обслуживающими конечных пользователей или сотрудников. Эти системы необходимы для ведения основного бизнеса. Принципиальная разница в том, что разработки тут практически нет. Если вашему бизнесу не требуется команда инженеров-программистов, и вы можете работать исключительно с готовыми приложениями, тогда ITOps для вас.

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

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

Источник: https://devops.com/devops-principles-implementations-and-culture/
👍5
День 1374.
Нерабочий день в РФ, пятница. Самое время повысить квалификацию. И команда конференции DotNext дарит вам эту возможность. Community Day - бесплатный билет на второй день online-конференции DotNext 2022 Autumn.

Послушать и пообщаться будет с кем. В программе (везде время московское):

15:00 - 16:00. Доклад Олега Сафонова (Тинькофф) «Пишем код, когда пишем код: source generator'ы»

15:00 - 16:00. Доклад Андрея Цветцих (Тинькофф) «Zero-downtime deployment и базы данных»

15:55 - 16:35. Интервью с Вадимом Мартыновым (Контур)

16:30 - 17:30. Доклад Романа Просина (Райффайзенбанк) «SkillsFlow: разработка системы управления навыками и компетенциями»

16:30 - 17:30. Дискуссия на тему «Объединяем .NET-разработчиков: как запустить и развить гильдии в компании» с участием Дмитрия Радченко (Почтатех), Дениса Фомина (Контур), Максима Смирнова (Альфа-Банк), Анны Морозовой (Dodo Engineering) и Алексея Мерсона (Тинькофф)

16:30 - 17:30. Доклад Гурия Самарина (Инжиниринговый дивизион Госкорпорации «Росатом») «Тестируем код, взаимодействующий с базой данных»

17:25 - 18:05. Интервью с Дмитрием Таболичем (IT_ONE)

18:00 - 19:00. Дискуссия на тему «Best practices для разработки Application Layer» с участием Андрея Парамонова (Dodo Engineering),
Андрея и Дениса Цветцих (Тинькофф, DevBrothers), Максима Аршинова (Хайтек Груп)

18:00 - 19:00. Доклад Романа Неволина (Sytac) «Пишем приложения, которые не ломаются в продакшене»

18:00 - 19:00. Доклад Андрея Акиньшина «Поговорим об описательной статистике перформанс-распределений»

Регистрируйтесь на Community Day по ссылке https://dotnext.ru/registration/personal/
👍4
День 1375. #ЗаметкиНаПолях #Юмор
Творим Дичь в C#. Часть 1
В этой короткой серии постов рассмотрим разные странные и зачастую бесполезные вещи, которые можно делать в C#.

Начнём с foreach для всего
Мы хотим выполнить foreach по целому числу, чтобы получить все его цифры:
foreach (var i in 435972)
{
Console.WriteLine(i);
}

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

Видите ли, foreach не требует от типа реализации интерфейса вроде IEnumerable или IEnumerator. Компилятору нужен всего лишь метод GetEnumerator, возвращающий объект итератора (подробнее про паттерн Итератор), в котором есть свойство Current и метод MoveNext. Давайте добавим его:
public static class Extensions
{
public static IntEnumerator
GetEnumerator(this int i) => new(i);
}

public struct IntEnumerator
{
private readonly List<int> list;
private int idx = -1;

public IntEnumerator(int num)
{
list = new List<int>();
while(num > 0)
{
list.Add(num % 10);
num /= 10;
}
list.Reverse();
}

public int Current => list[idx];

public bool MoveNext()
{
idx++;
return list.Count > idx;
}
}

Ничего сложного. Мы «добавляем» в тип int метод GetEnumerator, который возвращает IntEnumerator. IntEnumerator выполняет требования для цикла foreach. Этот итератор просто помещает отдельные цифры целого числа в список и возвращает их одну за другой по требованию.

В результате наш код скомпилируется и выведет:
4
3
5
9
7
2

Источник: https://steven-giesel.com/blogPost/5360d1c3-89f6-4a08-9ee3-6ddbe1b44236
👍28
День 1376.
Остановим Овер-Инжиниринг ПО
Можем ли мы, как разработчики приложений, перестать овер-инжинерить ПО? Все мы когда-либо это делали. Вот некоторые из ловушек, в которые мы попадаемся, что приводит к овер-инжинирингу.

1. «Что, если»
Мы делаем предположения о предметной области. Проблема в том, что мы не подтверждаем их, а они могут быть неверными. Мы обнаруживаем пограничный случай, который, нам кажется, нужно решить в коде. На самом деле это происходит настолько редко, что бизнесу не нужно это автоматизировать. Об этом проще уведомить и исправить вручную. Подтвердите предположения и поговорите с бизнесом! Не пишите сложный код, когда в этом нет необходимости.

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

3. Изобретение велосипедов
Вам случалось работать над системой, где был свой кастомный фреймворк, ORM и т.п.? Скорее всего да. Он было документирован? Скорее всего нет. Обычно доморощенный фреймворк много лет назад написал кто-то, кто больше не работает в компании, а теперь застряли с ним вы. Мы любим технологии, но всё, что вы добавляете, — это сложность.
Хорошим примером является написание собственной библиотеки обмена сообщениями вместо RabbitMQ/AWS SQS/Azure ServiceBus. Люди часто делают это, не осознавая всей сложности, которую нужно реализовать. Вместо этого используйте проверенную на практике библиотеку. Купите готовое, а не усложняйте систему.

4. Недостаток изначального проектирования
Недостаточное понимание предметной области приводит к созданию чрезмерно сложной системы. Это вариант игры «что, если». «Что, если нам нужно сделать X» или «Что, если X изменится, давайте добавим Y». Вам это не понадобится.
Не обязательно надолго садиться за проектирование. Исследуйте предметную область, особенно в проекте с нуля, используя что-то простое, например, Event storming. Нужно понять рабочие процессы и различные точки зрения разных людей в бизнесе.

5. DRY без границ
Отличным примером того, что DRY ушёл не туда, является то, что вещи становятся слишком абстрактными, пытаясь приспособиться под различные варианты использования, что в итоге приводит к огромной сложности.
Например, Службы сущностей (Entity Services). ProductService в системе склада, который содержит всю информацию о продукте: название, цена, стоимость, количество в наличии и т.д.
Проблема в том, понятие продукта на складе существует в нескольких разных контекстах. Отдел продаж волнует цена продажи, закупку волнует стоимость, доставку - количество в наличии. Не существует единой сущности продукта, каждый контекст будет иметь свою концепцию, раскрывающую функциональные возможности и данные, которые имеют к ней отношение.

6. Чрезмерная абстракция
Кажется типичным желание абстрагироваться от сторонней зависимости, библиотеки или инструмента. На первый взгляд это имеет смысл, и вы создаете свою абстракцию, чтобы код вашего приложения зависел от неё, а не от сторонней утилиты. И если вам когда-нибудь понадобится изменить её, то не придётся менять весь код приложения. Звучит разумно?
Однако всё сводится к связанности и управлению ей. Смысл абстракции в том, чтобы упростить базовые концепции, наиболее подходящие для вашего варианта использования. Создание абстракции ограничит вашу способность использовать все возможности, которые зависимость может предложить. Управляйте связанностью! Вертикальные слои и фокус на функционале. Группировка функций по функционалу позволит сузить фокус и принимать локальные решения о том, какие зависимости требуются для каждого функционала.

Источник: https://codeopinion.com/stop-over-engineering-software/
👍9
День 1377. #Книги
Сегодня немного отойду в сторону от дотнета. Но фуллстекам, как я, возможно, пригодится.

Закончил читать книгу «Оптимизация запросов в PostgreSQL» (Домбровская Г., Новиков Б., Бейликова А. — М.: ДМК Пресс, 2022).

Хотя она и про PostgreSQL, вполне будет полезна и работающим с другими БД, и просто разработчикам приложений для понимания сути работы базы данных. Почему что-то медленно и как это ускорить, почему не работает индекс, а когда он, наоборот, вреден. А работающие с PostgreSQL (или переходящие на PostgreSQL с других СУБД, как я) тем более найдут много интересного. Для меня, например, стало откровением, что часто динамический SQL в PostgreSQL выполняется быстрее, чем обычный параметризованный запрос. А всё дело в том, что оптимизации применяются после добавления всех параметров. Таким образом Postgres строит разные планы выполнения в зависимости от полученных параметров. К примеру, когда запрашиваются данные за последний год (относительно много строк таблицы), или за предыдущий день (относительно мало). Параметризованный запрос в этом случае будет иметь один план выполнения для обоих случаев. А динамический – разные, и запрос «за день» будет выполняться гораздо быстрее.

Хотя, конечно, книга не без минусов. Главным из которых можно выделить слабое знание авторами современных ORM-систем, и пассажи вроде «большинство ORM по умолчанию откладывают загрузку, поэтому для получения дочерних элементов сначала выдаётся один запрос в базу данных для родительской записи, а затем по одному запросу для каждой дочерней записи». Правда, оговорюсь, что они тестировали на Hibernate. Возможно, в Java так и происходит.

Чтобы от этого избавиться, целая глава посвящена авторской системе NORM (No-ORM), где в базе создаются DTO типы, которые возвращаются через функции в виде JSON, а потом десериализуются в приложении. Авторы утверждают, что это позволяет ускорить получение данных в 10-50 раз (в это я ещё могу поверить). А также, что это упрощает разработку. Вот это уже очень спорно, учитывая, что на каждый запрос нужно создать иерархию типов в базе, а также функцию со сложным SQL-запросом по извлечению этой иерархии. В общем, я не пробовал и не измерял, но решение кажется довольно спорным. Хотя то, что в сложных случаях чистый SQL будет намного быстрее ORM, – это, конечно, правда.

Как бы то ни было, в целом книга очень полезная, рекомендую к прочтению.
👍23
День 1378.
.NET Conf 2022. Начало
Вот опять ноябрь, а это значит, выпуск новой версии .NET и посвящённая этому .NET Conf 2022.

https://www.dotnetconf.net/

Вот краткое расписание первого дня по московскому времени (подробное расписание тут). Конференция разбита на тематические блоки (Web, Cloud, Client, General, Blazor, GitHub и т.п.), все доклады по 30 минут.

8 ноября
19:00-20:00 Keynote: Welcome to .NET 7

Web
20:00-20:30 State of ASP.NET Core (Daniel Roth)
20:30-21:00 What's new for Blazor in .NET 7 (Steve Sanderson)
21:00-21:30 Making the Most of Minimal APIs in .NET 7 (Safia Abdalla, Stephen Halter)
21:30-22:00 Building modern high-performance services with ASP.NET Core and .NET 7 (Sebastien Ros)

Cloud
22:00-22:30 State of Azure + .NET (Scott Hunter)
22:30-23:00 The Whirlwind Tour of Building .NET Apps in Azure (Matt Soucoup)
23:00- 23:30 Building Serverless Applications with .NET 7 and Azure functions (Melony Qin, Fabio Cavalcante)
23:30-00:00 Azure Container Apps with .NET (Mike Morton, Anthony Chu)

9 ноября
Client
00:00-00:30 State of .NET MAUI (David Ortinau, Maddy Montaquila)
00:30-01:00 What's new in .NET MAUI and Desktop Apps (Shane Neuville)
01:00-01:30 Performance Improvements in .NET MAUI (Jonathan Peppers)
01:30-02:00 Create native desktop & mobile apps using web skills in Blazor Hybrid (Eilon Lipton, James Montemagno)

.NET Developer Stories
02:00-02:30 .NET at Stack Overflow (Roberta Arcoverde)
02:30-03:00 Using .NET to build the .NET website (Maira Wenzel, Jon Galloway)
03:00-03:30 Microsoft Teams Backend Services - Powered by .NET (Marwa El-Dafrawy)
03:30-04:00 How Halo, Dynamics 365, and Mesh scale to millions with Orleans and you can too! (Brady Gaster, Reuben Bond)

General
04:00-05:30 .NET Conf CodeParty 2022 (Jeffrey T. Fritz)
👍13
День 1379.
.NET Conf 2022. Продолжение

Трансляция

Второй и третий дни конференции идут без перерыва. Вот краткое расписание второго дня по московскому времени (подробное расписание тут).

9 ноября
Deeper .NET
19:00-19:30 What's New in C# 11 (Mads Torgersen, Dustin Campbell)
19:30-20:00 Performance Improvements in .NET 7 (Stephen Toub)
20:00-20:30 Let's design a new C# language feature! (Jared Parsons)
20:30-21:00 .NET Architects Panel (David Fowler, Mikayla Hutchinson, Damian Edwards)

Blazor
21:00-21:30 .NET ❤️’s WebAssembly in .NET 7 (Daniel Roth)
21:30-22:00 Build an Audio Browser app with Blazor (Steve Sanderson)
22:00-22:30 Testing Blazor Applications with Playwright (Debbie O'Brien, Max Schmitt)

GitHub
22:30-23:00 GitHub Universe + .NET Conf Epic Crossover (Scott Hanselman)
23:00-23:30 Microsoft Dev Box and Azure Deployment Environments for .NET Developers (Anthony Cangialosi)

Power Platform / Teams
23:30-00:00 Boost your .NET productivity with Low Code Tools (Karuana Gatimu, Heather Newman)

10 ноября
00:00-00:30 Rapidly create a front-end for your web APIs with Microsoft Power Apps (Julia Kasper)
00:30-01:00 Building Microsoft Teams Bots with .NET & the Teams Toolkit (Ayca Bas, John Miller)

Windows
01:00-01:30 Building Windows apps with WinUI 3 with .NET (Nick Randolph)
01:30-02:00 Accelerate your WinUI 3 app with the Windows Community Toolkit (Michael Hawker)
02:00-02:30 Modernize your WPF and Windows Forms application with Blazor (Michele Aponte)

Modernization
02:30-03:00 Upgrading from .NET Framework to .NET 7 (Mike Rousos, Taylor Southwick, Olia Gavrysh)
03:00-03:30 Using CoreWCF to unblock modernization of WCF apps (Sam Spencer, Matt Connew)
03:30-04:00 High-performance services with gRPC: What's new in .NET 7 (James Newton-King)

General
04:00-04:30 Upgrading Xamarin apps to .NET MAUI (Sweekriti Satpathy)
04:30-05:00 CSS Techniques for Blazor Developers (Ed Charbeneau)
05:00-05:30 Accepting Payments with Stripe Checkout (Cecil Phillip)
05:30-06:00 The Power of Polyglot Notebooks (Claudia Regio)
06:00-06:30 Slaying Zombie ‘No Repro’ Crashes with Infer# (Matthew Jin, Xin Shi, Xiaoyu Liu, Jason Shaver)
06:30-07:00 .NET Interop Improvements in .NET 7 (Jeremy Koritzinsky)
07:00-07:30 Visual Studio Code for C# Developers (Tim Corey)
07:30-08:00 Migrate Your Legacy ASP.NET Projects to ASP.NET Core Incrementally with YARP (Jonathan "J." Tower)
08:00-08:30 MVVM is easier than ever before with Source Generators, .NET 7, and the MVVM Toolkit (Sergio Pedri)
08:30-09:00 Deep Learning in .NET (Kinfey Lo)
09:00-09:30 T4 goodness with Entity Framework Core 7 (Erik Ejlskov Jensen)
09:30-10:00 Build More Predictable Event-Driven System with CloudEvents, .NET and Azure (Justin Yoo)
10:00-10:30 From RESTful HTTP API to gRPC (Irina Scurtu)
10:00-11:00 Human-readable Razor views with ASP.NET 7 Tag Helpers (Dino Esposito)
👍8
День 1380.
.NET Conf 2022. Окончание

https://youtu.be/ET3wMMEt76I

Краткое расписание заключительного дня по московскому времени (подробное расписание тут):

10 ноября

General
11:00-11:30 Tips and tricks on platform-code implementation in .NET MAUI (Luis Beltran)
11:30-12:00 Aloha .NET MAUI Community Toolkit (Gerald Versluis)
12:00-12:30 Pushing C# to new places with NativeAOT (Kevin Gosse)
12:30-13:00 Authorization in a Distributed / Microservice System (Halil İbrahim Kalkan)
13:00-13:30 Down the Oregon Trail with Functional C# (Simon Painter)
13:30-14:00 .NET 7, Docker, K8S and Azure DevOps (Vahid Farahmandian)
14:00-14:30 Leverage the power of the GPU, DX12 and D2D1 with ease using ComputeSharp (Sergio Pedri)
14:30-15:00 Using Durable Azure Functions in .NET 7 (Niels Filter)
15:00-15:30 Performance tricks I learned from contributing to the Azure .NET SDK (Daniel Marbach)
15:30-16:00 Building a .NET SDK library with Open API and NSwag (Laura Rodriguez)
16:00-16:30 WatchDog: What's New in Open-source Logging (Israel Ulelu, Kelechi Onyekwere)
16:30-17:00 Dynamically adding functionality to ASP.NET Core (Chris Klug)
17:00-17:30 ASP.NET Basics for Experts (Layla Porter)
17:30-18:00 .NET Configuration In Depth (Chris Ayers)
18:00-18:30 Networking in .NET 7.0 (Karel Zikmund)
18:30-19:00 Creating Business Applications Using Azure Maps (Michael Washington)

Linux
19:00-19:30 Building .NET apps on WSL (Scott Hanselman)
19:30-20:00 Using .NET with Chiseled Ubuntu Containers (Richard Lander, Valentin Viennot)
20:00-20:30 .NET GUI Applications for Embedded Linux Using Containers (Matheus Castello)

Data
20:30-21:00 Leveling up data: Upgrade from EF6 to EF7 and blast off! (Arthur Vickers, Shay Rojansky)
21:00-21:30 Navigating Graphs in Azure Cosmos DB using Gremlin.Net (Sarah Dutkiewicz)
21:30-22:00 Event Sourcing with Marten and Postgresql (Jeremy Miller)

ML/AI
22:00-22:30 Announcing ML.NET 2.0 (Luis Quintanilla)
22:30-23:00 Machine learning models with ONNX and .NET (Henk Boelman, Beatriz Stollnitz)

General
23:00-23:30 Lessons learnt using DevContainers and the Azure Developer Cli to code apps anywhere, anytime. (Rory Preddy)
23:30-00:00 Clean Architecture with ASP.NET Core 7 (Steve Smith)

11 ноября
00:00-00:30 .NET 7 on App Service (Byron Tardif, Gaurav Seth)
00:30-01:00 Azure Static Web Apps with Blazor and .NET (Melissa Houghton)
01:00-01:30 Building Accessible Apps with .NET MAUI (Rachel Kang)
01:30-02:00 Performance benefits of .NET 7 for Web Applications (Jérôme Laban)
02:00-02:30 Making Technology More Accessible with .NET and AI (Alex Dunn)

Games
02:30-03:00 Build games with C# and Visual Studio (Jb Evain)
03:00-04:00 The future of .NET in real time 3D applications using Unity (Josh Peterson)
👍4
День 1381. #ЗаметкиНаПолях #Юмор
Творим Дичь в C#. Часть 2
В этой короткой серии постов рассмотрим разные странные и зачастую бесполезные вещи, которые можно делать в C#.

Ожидаем всё
Вы не устали писать конструкции вроде
await Task.Delay(10);

Очень много текста и всё равно единица измерения непонятна. Что если можно было бы сделать следующее:
// Подождем 2 секунды через TimeSpan
await TimeSpan.FromSeconds(2);

Да, вы правильно поняли, мы хотим дождаться объекта TimeSpan. И сделать это просто. Снова используем методы расширения. Всё, что мы говорили про foreach, применимо и к await. Он основан на шаблоне. Если у нас есть TaskAwaiter для определённого типа, мы можем ожидать этот тип. Есть хорошая статья от Microsoft, в которой Стивен Тауб рассматривает тему подробнее.

Как бы то ни было, нам нужно написать только один небольшой метод расширения, чтобы эта конструкция работала:
public static class Extensions
{
public static TaskAwaiter
GetAwaiter(this TimeSpan ts)
{
return Task.Delay(ts).GetAwaiter();
}
}

Вот и всё! У нас есть неявное преобразование из TimeSpan в TaskAwaiter, что позволяет нам ожидать TimeSpan. Но зачем останавливаться на этом? Мы можем пойти дальше в сторону fluent-интерфейсов и сделать что-нибудь вроде этого:
await 2.Seconds();

Красиво и выразительно. Единственное, что нам нужно сделать здесь, это добавить к имеющемуся выше методу, метод расширения для int, возвращающий TimeSpan:
public static class Extensions
{

public static TimeSpan Seconds(this int i)
=> TimeSpan.FromSeconds(i);
}

Таким образом, наш int становится неявным TimeSpan, который можно ожидать, потому что компилятор видит TaskAwaiter. Выглядит гораздо более читаемо, чем await Task.Delay.

Источник: https://steven-giesel.com/blogPost/5360d1c3-89f6-4a08-9ee3-6ddbe1b44236
👍23👎3
День 1382. #ЧтоНовенького
GitHub Codespaces Доступен Бесплатно для Всех Пользователей GitHub
Все пользователи GitHub могут бесплатно использовать размёщенные на GitHub среды разработки до 60 часов в месяц.

Codespace — это среда разработки, размещённая в облаке. Вы можете настроить свой проект для GitHub Codespaces, добавив файлы конфигурации (известные как контейнеры разработки) в свой репозиторий. Контейнеры разработки создают повторяемую конфигурацию среды разработки для всех пользователей вашего проекта.

Каждый кодспейс работает на виртуальной машине, размещённой на GitHub. Вы можете выбрать тип машины, которую хотите использовать, в зависимости от необходимых вам ресурсов. Доступны различные типы машин, начиная с 2-ядерного процессора, 4 ГБ ОЗУ и 32 ГБ памяти.

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

GitHub Codespaces теперь общедоступен для пользователей планов GitHub Free и GitHub Pro. Пользователям GitHub Free будет выделено до 60 часов бесплатного использования Codespaces в месяц, а пользователям плана GitHub Pro — 90 часов.

Кроме того добавлен ряд новых возможностей:
- Публично доступны в бета-версии IDE JetBrains, включая IntelliJ и PyCharm. Разработчики могут загрузить JetBrains Gateway и установить плагин GitHub Codespaces из JetBrains Marketplace. Редактор Visual Studio Code поддерживается в Codespaces со старта.
- Публично доступны в бета-версии JupyterLab Notebooks.
- Codespaces на GPU доступны в ограниченной бета-версии, предоставляя разработчикам возможность запуска моделей машинного обучения.
- Доступны шаблоны для запуска новых проектов на основе популярных платформ приложений. Правда, .NET шаблонов в списке нет.
- Для организаций добавлен REST API для управления и администрирования кодспейсов.

Источник: https://www.infoworld.com/article/3679948/github-codespaces-freely-available-to-all-github-users.html
👍7
День 1383. #Оффтоп
Сегодня порекомендую вам очередное видео с просторов ютуба.

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

В видео от канала Computerphile, доктор Джулиан Онионс рассказывает про протокол NTP (Network Time Protocol), с помощью которого компьютеры синхронизируют время между собой.

https://www.youtube.com/watch?v=BAo5C2qbLq8
👍5
День 1384. #ЗаметкиНаПолях #Microservices
Снижаем Проблемы от «Шумного Соседа» в Многопользовательском ПО
В многопользовательской системе множество клиентов совместно используют одни и те же вычислительные ресурсы. Это может привести к проблемам, если один клиент загрузит систему таким объёмом работы, что другие обнаружат снижение производительности. Иногда это называют проблемой «шумного соседа», по аналогии многоквартирным домом, где шумный сосед негативно влияет на жизнь других жильцов. Рассмотрим некоторые приёмы, позволяющие снизить ущерб от «шумного соседа».

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

2. API ограничений (Rate-limiting)
Мы можем отклонить некоторые вызовы для определённого клиента, разрешив при этом вызовы от других. Например, можно возвращать код ответа HTTP 429 Too Many Requests с заголовком Retry-After, сообщающим клиенту, когда можно будет повторить попытку.
Реализация ограничений для каждого клиента не всегда тривиальна. Нужно определить, что действительно один клиент монополизировал вычислительные ресурсы. Одним из подходов могут быть квоты, когда каждый клиент получает определённое количество разрешённых операций за период времени, прежде чем его вызовы попадут под ограничение.
.NET 7 включает промежуточное ПО ограничений (см. этот пост пункт 4 https://t.iss.one/NetDeveloperDiary/1487), значительно упрощающее эту задачу.
Недостатком этого подхода является то, что вы фактически лишаете клиентов возможности выполнять операции, что не очень удобно для них.

3. Приоритизация очередей
Альтернативой может быть приём запросов и использование очереди для их асинхронной обработки. Сообщения помещаются в очередь, а обработчик сообщений будет работать с отставанием, в итоге навёрстывая его, когда нагрузка спадёт. Но что, если один клиент добавит миллионы сообщений?
Один из вариантов решения — очередь для каждого клиента. Сообщения из разных очередей можно обрабатывать по очереди или параллельно, гарантируя, что каждый клиент получит равные шансы на обработку своего "первого" сообщения. Но если клиентов много, накладные расходы на одновременное обслуживание множества очередей сами по себе могут быть дорогостоящими и ресурсоёмкими.
Другой подход - «очереди с приоритетом». После определённого порога, каждое следующее сообщение от шумного клиента помещается в очередь с «низким приоритетом» и обрабатывается после обработки всех сообщений из основной очереди.

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

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

Источник: https://markheath.net/post/noisy-neighbour-multi-tenancy
👍7
День 1385. #ЗаметкиНаПолях #TipsAndTricks
Современные Приёмы в C#. Часть 1
Странно Повторяющийся Обобщённый Паттерн
Название предложено Стивеном Клири по аналогии со «Странно повторяющимся шаблоном» из C++.

Смысл паттерна в том, что интерфейс (или базовый тип) принимает в качестве параметра типа собственный производный тип:
interface IExample<TDerived> 
{ … }
class MyExample : IExample<MyExample>
{ … }

Если интерфейс (или базовый тип) хочет использовать полноценный производный тип в качестве параметра метода или возвращаемого значения, то он может сам определить эти методы, не возлагая никакой ответственности на производный тип. Вот пример из .NET BCL:
public interface IEquatable<T>
{
bool Equals(T? other);
}

Использование:
sealed class MyEquatable : 
IEquatable<MyEquatable>
{
public bool Equals(MyEquatable? other)
{ … }
}

MyEquatable.Equals реализует IEquatable<T>.Equals со строго типизированным аргументом MyEquatable. Без использования паттерна пришлось бы использовать IEquatable (принимая object) и терялась бы безопасность типов и эффективность.

Интерфейс (или базовый тип) также может использовать себя в качестве ограничения обобщения. Иногда это полезно, особенно для базовых типов:
abstract class MyBase<TDerived>
where TDerived : MyBase<TDerived>
{
// Методы могут использовать (TDerived)this
// Полезно при возврате TDerived
public virtual TDerived Get()
=> (TDerived)this;
}

class Derived : MyBase<Derived>
{
// Неявно имеет реализацию
// public Derived Get(), т.к. метод
// базового класса правильно определяет
// тип возвращаемого значения.
// Но может и переопределить его
}

Например, это полезно в Fluent API. В более общем случае ограничение обобщения необходимо в любой из этих ситуаций:
- Базовый тип должен рассматривать экземпляр MyBase<TDerived> (например, this) как производный тип (т. е. (TDerived)this). Это также может возникнуть при передаче this другим методам.
- Базовый тип должен обрабатывать TDerived как MyBase<TDerived>, например, вызывая приватные базовые методы для экземпляра типа TDerived, отличного от this. В этом случае явное приведение не требуется.

Подобно обычным методам интерфейса, Curiously Recurring Generic Pattern может при необходимости повысить безопасность типов методов интерфейса по умолчанию. Это похоже на использование паттерна с базовым типом, за исключением того, что интерфейсы не могут иметь состояния. Иными словами, это позволяет использовать строго типизированные трейты, но не подходит для миксинов.

Как и другие паттерны кода, этот тоже можно использовать не по назначению. Наиболее распространённое неправильное использование – его чрезмерное применение. Кроме того, этот паттерн имеет усложняет код. Здесь нужно найти компромисс между добавляемой ценностью и усложнением поддержки кодовой базы.

Источник: https://blog.stephencleary.com/2022/09/modern-csharp-techniques-1-curiously-recurring-generic-pattern.html
👍14