fan*_*f42 2 functional-programming scala io-monad bifunctor zio
ZIO
( https://zio.dev/ ) 是一个 Scala 框架,其核心是数据ZIO[R, E, A]
结构,其站点提供了以下三个参数的信息:
齐奥
的
ZIO[R, E, A]
数据类型有三种类型的参数:
R
- 环境类型。该效果需要类型为 的环境R
。如果该类型参数为Any
,则表示效果没有要求,因为您可以使用任何值(例如,单位值()
)运行效果。E
- 故障类型。如果值为 type ,则效果可能会失败E
。一些应用程序将使用Throwable
. 如果此类型参数为Nothing
,则表示效果不会失败,因为没有 Nothing 类型的值。A
- 成功类型。使用 type 值可能会成功A
。如果此类型参数为Unit
,则表示该效果不会产生有用的信息,如果是Nothing
,则表示该效果将永远运行(或直到失败)。
很容易得到什么A
是:它是函数在名义情况下返回的值,即我们为函数编码的原因。
R
是一种依赖注入 - 一个有趣的话题,但我们可以ZIO
通过始终将其设置为Any
(并且实际上IO[E, A] = ZIO[Any, E, A]
在 lib 中有一个别名)来忽略它以使用它。
因此,它仍然E
是用于错误的类型(著名的错误通道)。我粗略地认为这IO[E, A]
是一种Either[E, A]
,但处理效果(这很棒)。
我的问题是:为什么我应该在我的应用程序中到处使用错误通道,我如何决定错误通道中应该包含什么?
1/ 为什么用错误通道影响管理?
作为开发人员,您最困难的任务之一是确定什么是错误,什么不是您的应用程序 - 或者更准确地说,发现故障模式:什么是名义路径(即该代码的目标),什么是预期的应用程序稍后可以通过某种方式处理的错误,以及应用程序无法处理的意外错误。这个问题没有明确的答案,这取决于应用程序和上下文,因此需要由您作为开发人员来决定。
但最困难的任务是构建一个遵守承诺的应用程序(你的承诺,因为你选择了什么是错误和什么是名义路径),这并不奇怪,因此用户、管理员和开发人员 - 包括未来的你两周 - 了解代码在大多数情况下的作用,而无需猜测并让代理适应该行为,包括响应错误。
这很难,您需要一个系统的过程来处理所有可能的情况,而无需进行。
IO
bi-monad 中的错误通道(因此ZIO
)可以帮助您完成该任务:IO
monad 帮助您跟踪效果,这是大多数错误的来源,并且错误通道明确可能的错误情况是什么,等等如果可以,申请的某些部分有代理机构来处理它们。您将能够以纯粹、一致、可组合的方式管理您的效果,并使用显式故障模式。此外,在的情况下ZIO
,你可以easely导入像遗留Java非纯代码extremelly容易:
val pure = ZIO.effect(someJavaCodeThrowingException)
Run Code Online (Sandbox Code Playgroud)
2/ 我如何选择什么是错误?
因此,错误通道提供了一种将what if?
问题的答案编码给未来开发该代码的开发人员的方法。“如果数据库宕机了怎么办?” “有一个DatabaseConnectionError
”。但是what if
对于您的用例,对于当前应用程序级别,所有这些都不相同。“如果没有找到用户怎么办?” - 啊,它可能是低级“存储库”级别的完全预期的答案(例如未找到任何内容的“查找”),也可能是其他级别的错误(例如当您在此过程中时)验证用户,它真的应该在那里)。在第一种情况下,您可能不会使用错误通道:这是标称路径,有时您找不到东西。在第二种情况下,您可能会使用错误通道 ( UserNotFoundError
)。
正如我们所说,错误通道中的错误通常what if
是您可能希望在应用程序中处理的问题,而不是在该功能级别。第一个例子DatabaseConnectionError
可能是在应用程序中捕获更高,并导致用户消息如“请再试一次”和发送给系统管理员的通知电子邮件(“快速,看看,如果这里有问题”)。将UserNotFoundError
可能会被作为管理在登录表单用户的错误信息,类似“坏的登录名或密码,请重试或与该进程收回资格证书”。
所以这些情况(名义和预期错误)是容易的部分。但是有一些what if
问题是您的应用程序,无论级别如何,都不知道如何回答。“如果我尝试分配该对象时遇到内存异常怎么办?” 我没有任何线索,实际上,即使我有线索,这也超出了我想为该应用程序处理的范围。所以这些错误不会进入错误通道。我们称它们为失败,当它们发生时我们将应用程序崩溃,因为应用程序现在很可能处于未知、危险的僵尸状态。
同样,该选择(标称路径/错误通道/故障)是您的选择:两个应用程序可以做出不同的选择。例如,一次性数据处理应用程序然后丢弃它可能会将所有非标称路径视为故障。有一个开发人员可以实时捕获案例并决定它是否重要(请参阅:Shell、Python 和任何大量使用该策略的脚本 - 好吧,有时即使没有开发人员来捕获错误:)。在幽灵的另一端,美国宇航局开发人员把所有东西都放在错误通道(+)中,甚至内存损坏。因为这是一个预期的错误,所以应用程序需要知道如何处理并继续。
(+)注意:AFAIK他们不使用zio(目前),但是关于什么是错误的决策过程是相同的,即使在C中也是如此。
为了更进一步,我 (@fanf42) 在Scala.io会议上发表了演讲。演讲“应用程序中的系统错误管理”在此处提供法语版本 。是的,法语,我知道 - 但这里有英文版的幻灯片!您可以 ping 我(请参阅幻灯片末尾附近的联系信息)。