Тайптеги для зависимостей в ZIO
В DI-фреймворке под названием ZIO можно автовайрить зависимости с помощью расширения zio-magic, который ещё и встроят в версию 2.0. Код выглядит примерно так:
ZLayer.fromMagic[Env](
UsersRepository.live,
ClientsRepository.live,
RegistrationService.live
)
А дальше макрос на этапе компиляции выстроит граф зависимостей по входящим
типам слоёв. Но частенько в приложении бывают классы, принимающие зависимости
одного и того же типа. Допустим, grpc-клиенты к микросервисам BillingClient
и
NotificatorClient
принимают в зависимости GrpcConfig
. Содержимое этих
конфигов очевидно разное, но на уровне типов этого не видно, поэтому нельзя
понять, какой экземляр конфига к кому относится. Можно решить это ручным
вайрингом:
ZLayer.fromMagic[Env](
Grpc.live,
Config.loadLayer[GrpcConfig]("billing") ++ ZLayer.environment[Has[Grpc]] >>> BillingClient.live,
Config.loadLayer[GrpcConfig]("notificator") ++ ZLayer.environment[Has[Grpc]] >>> NotificatorClient.live
)
Но мне это не нравится, потому что приходится внедрять куски ручного построения графа зависимостей в плоский список слоёв.
Так как вайринг происходит во время компиляции, различать зависимости нужно на уровне типов. Сразу пришла идея использовать тайп-теги: пометить слой зависимости каким-то тегом, и такой же тип затребовать в слое-получателе. Собственно, после некоторого пердолинга с компилятором было написано такое вот поделие: https://gist.github.com/poslegm/f252994a15453457e64d6498249928f3.
И с ним можно писать уже так:
ZLayer.fromMagic[Env](
Grpc.live,
Config.loadLayer[GrpcConfig]("billing").tagged[BillingClient.Service],
Config.loadLayer[GrpcConfig]("notificator").tagged[NotificatorClient.Service],
BillingClient.live.requireTagged[GrpcConfig, BillingClient.Service, Has[Grpc]],
NotificatorClient.live.requireTagged[GrpcConfig, NotificatorClient.Service, Has[Grpc]]
)
К сожалению не получилось придумать реализацию requireTagged
, в которой не
надо явно указывать компилятору тип “остатка” требуемых слоёв, кроме
протегированного. Зато теперь все зависимости укладываются в один плоский
список, а zio-magic ругнётся, если не будет протегированной зависимости к
какому-то слою.