作为我们业务服务的 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 的答案,但对于建模业务服务,我通常会推荐 Either
。
Effect<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
可以使用。
您可以考虑 Effect
比 Either
更低级别的实现,因为所有计算块,例如 either { }
、option { }
、ior { }
、result { }
,等现在都是通过effect
.
实现的
您可以在 either { }
的 Arrow 实现中看到。
suspend fun <E, A> either(block: suspend EffectScope<E>.() -> A): Either<E, A> =
effect(block).toEither()
随着箭头 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 的答案,但对于建模业务服务,我通常会推荐 Either
。
Effect<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
可以使用。
您可以考虑 Effect
比 Either
更低级别的实现,因为所有计算块,例如 either { }
、option { }
、ior { }
、result { }
,等现在都是通过effect
.
您可以在 either { }
的 Arrow 实现中看到。
suspend fun <E, A> either(block: suspend EffectScope<E>.() -> A): Either<E, A> =
effect(block).toEither()