Не Внедряйте Сторонние Зависимости. Используйте Декораторы. Окончание
Начало
Продолжение
Причины для снижения связанности
Почему важно отделить код приложения от Polly?
1. Во-первых, Polly — это просто пример любой сторонней зависимости. Сторонний компонент меняется со временем и часто независимо от вашей базовой платформы. Возможно, вам придется иметь дело с критическими изменениями или исправлениями безопасности в неподходящее время. Организация, которая поддерживает компонент, может прекратить работу. Это происходит как с коммерческими организациями, так и с разработчиками открытого кода, хотя и по разным причинам.
2. Если ваш временной горизонт составляет от пяти до десяти лет, вы будете удивлены, насколько всё изменится. Вы можете возразить, что никто не проектирует программные системы с такой долгосрочной перспективой, но я думаю, что, если вы спросите бизнес, он наверняка ожидает, что система прослужит долго.
3. Предположим, что мы не хотим зависеть от какого-то случайного компонента с открытым кодом, но ведь зависимость от Polly безопасна, правда? В долгосрочной перспективе - нет. Пять лет назад была такая же ситуация с Newtonsoft.Json, но затем Microsoft сделали свою System.Text.Json. Теперь есть две конкурирующие библиотеки JSON, и Microsoft использует свою во фреймворках и библиотеках, которые они выпускают.
Решение отделить код приложения от стороннего компонента в итоге является вопросом управления рисками. Вам решать, делать ли ставку. Вы платите авансом в виде расходов ресурсов на рефакторинг или откладываете его, надеясь, что он никогда не понадобится. В случае с отделением стоимость изменений довольно низкая, зато есть и другие преимущества. Как уже упоминалось, модульное тестирование становится проще.
Конфигурация
Поскольку Polly живёт только в корне композиции, вам также нужно будет определить ResiliencePipeline там. Вы можете написать код, который создает пайплайн, где угодно, но было бы естественно сделать его функцией создания в классе ResilientService:
public static ResiliencePipeline CreatePipeline()
{
return new ResiliencePipelineBuilder()
.AddRetry(new RetryStrategyOptions
{
MaxRetryAttempts = 4
})
.AddTimeout(TimeSpan.FromSeconds(1))
.Build();
}
Это всего лишь пример, и, возможно, это не то, что вы хотели бы сделать. Возможно, вы предпочитаете, чтобы некоторые из этих значений были определены в файле конфигурации. Однако, если вы используете этот вариант, вы можете взять возвращаемое значение этого метода и внедрить его в конструктор ResilientService.
Итого
Сквозные проблемы, такие как кэширование, ведение журнала, безопасность или, в данном случае, отказоустойчивость, обычно лучше всего решаются с помощью паттерна Декоратор. Мы рассмотрели пример его использования для отделения проблемы отказоустойчивости от потребителя сервиса, который должен быть отказоустойчивым.
Polly является одним из лучших пакетов .NET с открытым кодом, поэтому здесь не наброс на Polly. Это просто пример того, как размещать полезные зависимости в вашей кодовой базе, чтобы убедиться, что они как можно меньше влияют на код приложения.
Источник: https://blog.ploeh.dk/2024/09/02/keeping-cross-cutting-concerns-out-of-application-code/