关于路由层及逻辑层框架设计的思考
关于路由层及逻辑层框架设计的思考
背景
当前服务端的设计逻辑按照三层主体架构方式实现:路由层-逻辑层-数据层,在路由层和逻辑层数据交互方式和代码冗余性方面与团队人员出现了分歧,引发了一些思考。
「架构简介」
- 路由层:路由层承担参数校验,身份验证及解析,路由实体返回功能,有对 gin.context 操作权限;
- 逻辑层:实现主体复杂业务逻辑,构建路由返回实体,无 gin.context 和数据库连接的操作权限;
- 数据层:实现底层数据获取,操作数据库,根据封装性和实用性操作部分简单业务逻辑,有数据库连接的操作权限;
- 逻辑层和数据库层应提供 interface 以实现目录功能,所有对外暴露的函数及功能均应在 interface 中体现,并在 interface 中尽可能的提供具体的参数及返回类型。
「问题详述」
- 当前路由层重复代码过多,应该精简;
- 本次引入错误码相关封装,当前设计要求路由层对逻辑层返回的解析优先级为 error > code > res(业务实体)。
「思考」
- 路由层代码可以封装精简,但应该只在路由层实现,不应该对其他层级或模块要求配合实现;
- 有一些关于 error 的看法需要重新被提出和讨论以建立共识,之后再确定方案和着手修改。
「关于 error 的看法」
- error 作为 golang 通用的错误类型,是应该被广泛兼容的;
- 即使是同一个服务,不同模块(即这里讨论的层级)也是不同的业务单元,承载不同的业务功能,模块与模块之间的必须要有有关错误信息的同步方式(从服务拆分,服务间不应该互相信任,单元测试及代码规范要求等方面能找到一些印证),而且这种方式应该是全局统一的;
- 从代码的安全性和可靠性角度,应该认为任何一个代码单元都可以产生 error,而任何一个产生的 error 都应该立即被处理且只能被处理一次(立即处理,不能遗漏,也不能重复处理), 因为任何带着 error 信息继续运行的代码都是很危险的,一旦出错,所需要的排查错误的工作会变得非常复杂。即对于任何代码单元,都应该遵守的规范是能处理的错误就立即处理,并将原错误清除,对于不能处理的错误,则向外抛出,等待外部解决。
「关于错误码的看法」
- 错误码可以由解析 error 产生,也可以由业务逻辑直接产生;
- 由 error 产生的错误码应该认为是已经对 error 进行了处理,此时 error 应该置为 nil。
「个人想法总结」
- 优化方式一:
- 路由层代码需要进一步优化,尽量去除重复代码;
- 逻辑层的返回模式中 error 不应该被去除,且路由层应维持 error > code > res 的处理逻辑(按照 error 看法3和错误码看法2的思想,error 和 code 不应该存在可以同时出现的情况),逻辑层的返回封装可以维持原样。
- 优化方式二:
所有 error 定义为 interface 类型 并将错误码当错 error 返回 则当前框架可以自适应至目前输出且携带 message,该方法后续可通过引入范式限制类型替换掉 interface(缺点:返回类型不明确会有一定理解困难)- 优化方式三:
错误码直接当做 error 返回,由框架适配处理 error 再次转换为错误码(缺点:该种框架仍需较长时间开发)
结论: 使用优化方式一,需跟开发者明确 err 只要存在 http 状态码为500 ,err 不存在,才使用开发者自定义的返回(包括业务错误码)