Как реализовать календарный сервис с разными вариантами реализации
Что проверяют
Умеете ли вы спрятать изменчивую часть за абстракцией и подключить нужную реализацию без if по всему коду. Фраза «разные варианты реализации» обычно означает: сегодня события лежат в своей базе, завтра их надо брать из внешнего календаря по CalDAV или Exchange. Следом спросят, как выбирать реализацию в рантайме и как это тестировать.
Как отвечать
Начните с контракта, а не с контроллера:
- интерфейс:
ICalendarServiceс методами вродеGetEventsAsync(from, to, ct),CreateAsync,CancelAsync. Все асинхронные, сCancellationToken, наружу отдаются доменные модели, а не сущности EF; - реализации:
DbCalendarServiceповерх EF Core,ExternalCalendarServiceповерх HTTP-клиента,InMemoryCalendarServiceдля тестов. Вызывающий код про них не знает; - выбор реализации: регистрация в DI по конфигурации, фабрика или стратегия. С .NET 8 есть keyed services:
AddKeyedScoped<ICalendarService, DbCalendarService>("db")и параметр с[FromKeyedServices("db")]. Если выбор зависит от пользователя, нужна фабрика, которая по настройке аккаунта отдаёт нужную реализацию; - сквозная логика: кеширование, ретраи и логирование оформляются декоратором над тем же интерфейсом, а не копируются в каждую реализацию.
Затем покажите, что знаете предметную область. Время храните как DateTimeOffset в UTC плюс идентификатор часового пояса события, иначе встреча «каждый понедельник в 10:00» съедет при переходе на летнее время. Повторяющиеся события описываются правилом RRULE из RFC 5545, а не тысячей копий в таблице, для поясов и повторов удобна NodaTime. Текущее время берите из TimeProvider, тогда тест на напоминания не ждёт реальных минут.
Где спотыкаются
Пишут контроллер со статическим List<Event>, как в учебных примерах. Такой список не потокобезопасен, теряется при перезапуске и не переживает второй экземпляр сервиса.
Делают интерфейс под одну реализацию: методы возвращают IQueryable или сущности EF, и внешний календарь под такой контракт уже не подключить.
Хранят локальное время в DateTime без зоны. Ошибки всплывают у пользователей из других часовых поясов и в дни перевода часов там, где он есть.