Go 项目怎么做好分层架构和目录规划

科技   2024-11-06 08:51   北京  

开发项目的时候我们都爱说XX模块,模块一般是跟着项目所服务的业务走的。而项目的分层则没有那么依赖具体的业务类型,靠一些软件设计的方法论和经验在项目搭建初期就能大体确定其结构。

我给大家介绍一下Go项目的分层架构设计,把整个项目的结构按职能进行划分,规划出整个项目的目录结构。


理论讲的再好,跟自己能上手实战还是有点距离,需要大量的结合场景的代码演示才能真正掌握,请扫码订阅专栏,除了能参考专栏学习项目搭建的技能,还能结合大量实战场景的代码演练真正掌握代码分层和整洁开发的精髓。

分层架构

谈到给项目的代码分层,必然少不了对分层架构的回顾。分层架构如下图所示

分层架构的一个重要原则是:每层只能与位于其下方的层发生耦合。我们大多数时候使用的是松散型分层架构,允许上层与任意下层发生耦合。

这里说的耦合可以先理解成包和包之间的引用关系,这样更好理解一些。所以在我们设计项目的结构时,要注意下层的package 一定不能引用上层的package。使用松散型分层架构的目的是让我们的设计能更灵活,必要时出现跨层直接访问的情况也是被允许的。注意哦,不是推荐我们有事儿没事都直接在用户接口层访问DAO查数据哦。

举个例子假如有个旧项目把很多东西都写在了controller里,又假如你是那个接过来要负责它的苦命人,你本来下定决心以后的新代码都好好写不能再这么潦草下去啦,比如说你把把一些新的逻辑放到service里。

但是业务系统一般都是在老需求基础上迭代,新老代码会有调用关系,这时候你却发现原来的逻辑都在controller里,那这时你要不把用到的老逻辑往service放一份,要不你也彻底放弃往controller直接写完事儿啦,你咋选?

项目排期那么紧,我估计换谁都是彻底放弃,就往controller里写吧。所以在项目搭建的开始阶段就确定后分层结构还是很有必要的,后期做需求开发时就可以相对无脑一些按照层次结构往里面套,不同的逻辑写到不同的层里。

上面这个例子是不是很好的体现了大家平时在公司接管项目初期的心理呀,我相信多少人都遇到过这种情况。

好了,回到主题,下面简单说一下分层架构中各个层的职责。

用户接口层:

用户接口层只用于处理用户界面显示和用户的请求响应,针对后端API服务,基本上该层就是负责接受用户请求、验证请求、调用下层拿到结果返回响应,在这里不应该包含核心业务逻辑。

应用层

应用层里面是应用服务,主要负责用例流的任务协调,每个用例流对应一个服务方法(可以理解为API接口),应用服务是领域服务的直接调用者,它主要协调对领域服务的操作,同时像发送基于某个事件的消息通知、发邮件、短信给用户等操作都会写在应用层,这样能让领域服务能专注于核心的业务逻辑。

应用服务还有一个作用是,当一个API的逻辑需要多个领域服务一起协作来完成时,一个清晰的解决方案是通过应用服务来对多个领域服务来进行协调调用。

领域层

领域层是真正写业务逻辑的地方,这个业务逻辑可以理解成本领域的核心业务逻辑,比如怎么通过CRUD完成某件事写在这里,而成功或者失败后向什么地方推送消息通知、调用其他领域服务、请求其他API 这些核心之外的业务逻辑则写在应用层的应用服务里,领域层只关注本领域里的业务逻辑,应用层负责协调调度它们。

基础层

基础层放置我们为项目提供的一些公共、通用的能力:数据的访问和持久化、对接第三方平台能力而封装的库、为项目开发的基础组件等都放在这一层。

注意这里说的层都是概念性的,不是指具体项目中的某个目录或者package。

分层后的目录结构

我们的Go项目,按照分层架构进行规划后,可以用下面这张图表示。图中的逻辑层我是用虚线框住的,代表所有与逻辑相关的应该放在应用和领域层中,它们逻辑侧重点有些不同,上面我们已经说过应用和领域层的区别了,我们在专栏教程里还有更多的实际需求的例子来体现它们之间的区别。

整个项目按分层架构以及各种实际功能的需要,目录结构的规划如下

.
|---api 
|     |---controller  # 控制器
|     |---reply  # 响应对象
|     |---request  # 请求对象
|     |---router  # 路由
|---common  
|     |---app     # 分页和接口响应处理
|     |---enum    # 枚举
|     |---errcode # 项目错误管理
|     |---logger  # 项目的日志门面
|     |---middleware  # 中间件
|     |---util  # 辅助函数
|---config # 配置
|---dal    # 数据访问层
|     |---cache    # 缓存
|     |---dao    # 数据访问对象
|     |---model    # 数据模型对象
|---event
|---library
|---logic    # 逻辑层
|     |---appservice    # 应用服务
|     |---domainservice # 领域服务
|     |---do # 领域对象    
|---resources # 资源目录
|---test # 测试脚本

怎么防止分层"塌陷”

代码有了分层后,如果使用不当一定会导致分层塌陷,最后还是把代码写成一坨,那怎么能尽量减少这在情况出现呢?除了"各个层职责单一"的片汤话外其实是有明确的办法的,老外把这个东西叫做防腐层。

防腐层有很多种,简单和最常用的就是各种数据对象, 他们之间的转化让各个层都能独立的发展,能最大限度避免代码层的塌陷。

项目中设计了四种数据对象:请求对象,数据实体Model对象,领域对象和响应对象

下面这张图展示了一个完整的API请求中客户端与服务的完整交互过程中每种数据对象产生的时段和位置。根据API请求、逻辑的复杂程度我们可以有选择的选择其中几个对象完成接口的请求和响应数据的返回

通过上面四种数据对象,程序的每个分层都可以专注自己的事儿,DAO层、Service层不必考虑接口要返回什么格式,用户接口层也不用怕把一些不该暴露的字段数据给暴露了出去。

请扫码订阅专栏,在专栏的实战开发教程中会专门介绍这些数据对象和防腐层的使用。

另外对接第三方API的代码放在哪个代码层里,在专栏中也有详细的代码分析。

订阅后,可加入专栏配套的实战项目,获得完整实战教程,同时也有专属的读者群,欢迎加入一起学习


专栏分为五大部分 (前三部分26节内容已经更新完成) 主要内容架构如下:


  • 第一部分介绍让框架变得好用的诸多实战技巧,比如通过自定义日志门面让项目日志更简单易用、支持自动记录请求的追踪信息和程序位置信息、通过自定义Error在实现Go error接口的同时支持给给错误添加错误链,方便追溯错误源头。
  • 第二部分:讲解项目分层架构的设计和划分业务模块的方法和标准,让你以后无论遇到什么项目都能按这套标准自己划分出模块和逻辑分层。后面几个部分均是该部分所讲内容的实践。
  • 第三部分:设计实现一个套支持多平台登录,Token泄露检测、同平台多设备登录互踢功能的用户认证体系,这套用户认证体系既可以在你未来开发产品时直接应用
  • 第四部分:商城app C端接口功能的实现,强化分层架构实现的讲解,这里还会讲解用责任链、策略和模版等设计模式去解决订单结算促销、支付方式支付场景等多种多样的实际问题。
  • 第五部分:单元测试、项目Docker镜像、K8s部署和服务保障相关的一些基础内容和注意事项

扫描上方二维码或者访问 https://xiaobot.net/p/golang 即刻订阅

点击阅读原文可跳转至本文的完整版。

网管叨bi叨
分享软件开发和系统架构设计基础、Go 语言和Kubernetes。
 最新文章