将外部错误映射到 golang 中的域错误

我有一个称为ComputeService实现特定域逻辑的服务类型。服务本身取决于调用的接口的实现,Computer该接口具有方法Computer.Compute(args...) (value, error)。如图所示,Compute它本身可能会返回某些错误。


ComputeService需要使用正确的域错误代码从一组域错误中发送适当的错误,以便可以完成翻译,并且客户端也可以适当地处理错误。


我的问题是,Computer实现应该将它们的失败包装在域错误中还是应该ComputeService这样做。如果ComputeService是这样做的人,那么它将必须知道Computer接口的不同实现返回的不同错误,在我看来这打破了抽象。两种方式如下所示:


package arithmetic

type Computer struct {

}

func (ac Computer) Compute(args ....) (value, error) {

     // errors is a domain-errors package defined in compute service project

     return errors.NewDivideByZero()

}

或者


package compute

type Service struct {

}

func (svc Service) Process(args...) error {

    computer := findComputerImplementation(args...)

    val, err := computer.Compute(args...)

    if err != nil {

       if err == arith.ErrDivideByZero {

          // converting an arithmetic computer implementation 

          // specific error to domain error

          return errors.NewDivideByZero()

       } else if err == algebra.ErrInvalidCoEfficient {

          // converting an algebraic computer implementation 

          // specific error to domain error

          return errors.NewBadInput()

       }

       // some new implementation was used and we have no idea

       // what errors it could be returning. so we have to send

       // a internal server error equivalent here

       return errors.NewInternalError()

    }


}


Qyouu
浏览 68回答 2
2回答

千巷猫影

的实现者Computer应该用域错误来响应,因为它们是最接近操作的错误并且最能确定错误是什么。就像你说的,拥有这种逻辑打破 ComputeService了抽象。如果您需要将代码从特定Computer错误映射到域错误,请创建将主要逻辑与该错误包装代码分开的包装器结构。要保留内部错误上下文,只需将原始错误嵌入到域错误中并创建IsSpecificDomainError帮助程序。type MyDomainError struct {    Err error}func NewMyDomainErr(err error) error {    return &MyDomainError{err}}func IsMyDomainError(e error) bool {    _, ok := err.(*MyDomainError)    return ok}

波斯汪

要保留内部错误上下文,只需将原始错误嵌入到域错误中我想我们都同意这strings.Contains(err.Error(), "not found")是脆弱的代码。我希望我们也同意我们更愿意看到像errors.Is(err, os.ErrNotExist).但要点是,在许多情况下,包的未来发展必须避免调用者依赖特定的错误结果来满足errors.Is(err, os.ErrNotExist),即使这是导致今天结果的根本原因。这就像查看未导出的字段或比较错误文本 - 这是一个可能会改变的细节。虽然strings.Contains看起来很脆弱,但errors.Is看起来并不脆弱,也不应被视为脆弱。如果我们要避免它变得脆弱,那么我们需要为包提供一种方法来报告详细信息,而无需让客户对其进行测试。这种方式是无法解包的错误。err.As():var pe *os.PathErrorif errors.As(err, &pe) {     use(pe)}%在:func inner() error { return errors.New("inner error") }func outer() error { return fmt.Errorf("outer error: %w", inner()) }fmt.Fprintf("%+v", outer())// outer error://     /path/to/file.go:123//   - inner error://     /path/to/file.go:122Go 1.13 的当前状态:只是说明我认为团队提供的折衷解决方案:fmt.Errorf目前被广泛用于包装错误并返回一个新的(不透明的)错误(因为您无法访问底层错误)。' %w' 现在可用于显式选择返回可解包的错误。errors 被设计为没有依赖关系的基础包,因此每个包都可以依赖它。团队同意在存在广泛分歧的领域下注,并希望发布足够多的内容(errors.Is,errors.As,对大多数人包装错误的方式的扩展),以便人们可以实现目标。泛型还没有出现,我们不知道它什么时候会出现:关于泛型的激烈讨论将使这个关于“错误 2 值”的问题看起来像儿戏。errors.Is并且errors.As干净简洁,足以长时间舒适。大多数有争议的事情都被推迟到 1.14。Wrapf不能存在错误,因为它是一个基础包。Wrapf意味着团队必须决定在nil传递错误时会发生什么:下注。Wrap 可能会与正在考虑的本地化、国际化等想法发生冲突。ErrorFormatter并且ErrorPrinter还没有得到更深入的使用并且有疣。平底船。
打开App,查看更多内容
随时随地看视频慕课网APP