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

Which should we choose between Effect and Either as a return type of our business services?

随着箭头 1 的到来。1.x 我们得到了新的 Effect class。

到目前为止,我的业务 classes 返回了 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) })

    }

有了新的 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)
        }
    }

在测试中,模拟更改自:

    @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())

到...

    @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 })

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

如果 Either 适合您的用例,则没有理由重构为 Effect

The question is, what's the best approach to model our business services, the new Effect class or Either, and why?

遗憾的是,在软件中,没有 1-fit-all 的答案,但对于建模业务服务,我通常会推荐 EitherEffect<E, A> 在语义上等同于 suspend EffectScope<E>.() -> A,运行 的结果即 lambda 可以是 Either<E, A>.

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

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

suspend fun operation(): Either<E, A> =
  operation.toEither()

因此,如果您只需要对操作的 结果 建模,则需要使用 Either<E, A>。如果你需要传递一个 lambda/operation 然后使用 Effect 可以使用。

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

实现的

您可以在 either { } 的 Arrow 实现中看到。

suspend fun <E, A> either(block: suspend EffectScope<E>.() -> A): Either<E, A> =
  effect(block).toEither()