我们应该在 Effect 和 Either 之间选择哪一个作为我们业务服务的返回类型?

cod*_*ent 8 kotlin arrow-kt

随着 Arrow 1.1.x 的到来,我们获得了新的Effect类。

到目前为止,我的业务类返回 Either 来模拟返回错误或值的效果,例如:

    @Service
    class CreateDepartmentUseCaseImpl(
        private val createDepartmentsDrivenPort: CreateDepartmentsDrivenPort,
        private val getDepartmentByCodeDrivenPort: GetDepartmentByCodeDrivenPort
    ) : CreateDepartmentUseCase {
        override suspend fun execute(param: Department): Either<DomainError, Department> =
            Either.conditionally(getDepartmentByCodeDrivenPort.get(param.code) == null,
                { DepartmentAlreadyExistsError(param.code.value) },
                { createDepartmentsDrivenPort.create(param) })

    }
Run Code Online (Sandbox Code Playgroud)

在新版本中Effect,这可以重构为:

    @Service
    class CreateDepartmentUseCaseImpl(
        private val createDepartmentsDrivenPort: CreateDepartmentsDrivenPort,
        private val getDepartmentByCodeDrivenPort: GetDepartmentByCodeDrivenPort
    ) : CreateDepartmentUseCase {
        override suspend fun execute(param: Department): Effect<DomainError, Department> = effect {
            ensure(getDepartmentByCodeDrivenPort.get(param.code) == null) { DepartmentAlreadyExistsError(param.code.value) }
            createDepartmentsDrivenPort.create(param)
        }
    }
Run Code Online (Sandbox Code Playgroud)

在测试中,模拟更改为:

    @Test
    fun `should create department`() = runTest {
        val dep = createValidDepartment()
        val createDepartmentRequest = CreateDepartmentRequest(dep.code.value, dep.name.value, dep.description.value)
        `when`(createDepartmentsUseCase.execute(dep)).thenReturn(dep.right())
Run Code Online (Sandbox Code Playgroud)

到...

    @Test
    fun `should create department`() = runTest {
        val dep: Department = createValidDepartment()
        val createDepartmentRequest = CreateDepartmentRequest(dep.code.value, dep.name.value, dep.description.value)
        `when`(createDepartmentsUseCase.execute(dep)).thenReturn(effect { dep })
Run Code Online (Sandbox Code Playgroud)

问题是,对我们的业务服务(新Effect类 或 )进行建模的最佳方法是什么Either?为什么?

nom*_*Rev 10

没有理由重构Effect是否Either适合您的用例。

问题是,对我们的业务服务进行建模的最佳方法是什么,是新的 Effect 类还是 Either,为什么?

遗憾的是,就像在软件中一样,没有一劳永逸的答案,但我通常会推荐对业务服务进行建模EitherEffect<E, A>在语义上等价于suspend EffectScope<E>.() -> A,并且运行该 lambda 的结果可以是Either<E, A>

这也是为什么我们可以分配Effect给 a val,并且在返回时Either我们需要调用需要 的 suspend lambda suspend fun

val operation: Effect<E, A> =
  effect { ... }

suspend fun operation(): Either<E, A> =
  operation.toEither()
Run Code Online (Sandbox Code Playgroud)

因此,如果您只需要对操作结果Either<E, A>进行建模,那么就需要使用。如果您需要传递 lambda/操作,则Effect可以使用 using 。

您可以考虑Effect比 更低级别的实现Either,因为所有计算块(例如either { }option { }ior { }result { }等)现在都通过 实现effect

您可以在 的 Arrow 实现中看到这一点either { }

suspend fun <E, A> either(block: suspend EffectScope<E>.() -> A): Either<E, A> =
  effect(block).toEither()
Run Code Online (Sandbox Code Playgroud)

  • 我也一直好奇这个问题。感谢 OP 和@nomisRev。 (2认同)