写点什么

GoFrame V2 真香,我是 Get 到了高内聚低耦合的点,你呢?

作者:王中阳Go
  • 2022-11-19
    北京
  • 本文字数:4670 字

    阅读完需:约 15 分钟

GoFrame V2真香,我是Get到了高内聚低耦合的点,你呢?

让开发者更好的做到“模块内部高内聚,模块之间松耦合”,是我认为 GoFrame V2 设计的精髓。

前言

用 GoFrame 开发商业项目已经很长时间,发现 GoFrame 的版本更新比较快,社区也非常的活跃。


因为历史原因,我之前一直用 V1.16 版本做商业项目的开发,虽然个人有比较强的意愿升级到 V2。


但是考虑到项目稳定性及开发成本等等原因,商业项目并未升级。这可能也是很多小伙伴面临的问题。

受到鼓励

正好前段时间,分享了自己的开源项目【Go WEB进阶实战】基于GoFrame搭建的电商前后台API系统受到了大家的关注和支持,也得到了 GoFrame 作者的点赞转发。


更重要的是:收到了社区里很多小伙伴的优化建议,其中最好的就是建议我使用 V2 版本,因为提供了很多新特性,可以更好的实现需求,稳定且高效。

决定升级

所以,我决定把我开源的项目从 V1.16.x 版本,升级到最新的 V2.2.0 版本,踩一下升级的坑,享受一下升级后的快乐。欢迎小伙伴们加入到我的开源项目中:电商前后台系统API,已经开发了 100 多个接口,包括电商项目的常用功能。


因为内容比较长且硬核,所以我决定分两篇文章分享:


  1. 这篇文章重点:介绍 GoFrame V2 的新特性,和 V1 相比有哪些优势?最大的变化是什么?

  2. 第二篇文章会分享一下:我从 V1 升级到 V2 的踩坑之旅,相信对很多小伙伴都有帮助。


这个经历实属不易,希望小伙伴们可以点赞、关注、转发一波。

适合看的人群

  1. 掌握 Go 基础后,想用成熟框架开发项目的伙伴,建议读完我的文章之后,直接使用 GoFrame 最新的 V2 版本实战开发

  2. 目前在用 V1 版本,有意愿但是没有大量精力学习 V2 新特性的伙伴,担心升级问题太高不敢贸然升级的伙伴们。

  3. 想提高自己学习新知识效率的小伙伴,欢迎复刻我的这种实践方式。

站在开发者的角度

不管你是哪种人群,都建议花时间仔细阅读官方文档,尤其是 框架介绍这部分。


区别于官方文档,这篇文章会结合我自己的经验,站在框架使用者的角度,帮大家更快更好的理解 Goframe V2 版的设计思路,基于 V2 版本如何更好的进行商业项目的开发。

踩的坑

在我升级版本的过程中发现:一定要先了解清楚 V2 的新特性,然后再从 V1 升级到 V2,否则升级到一半会出现无从下手的问题:


  1. 因为通过 V2 版本的 CLI 工具生成的 dao、model,和 V1 版本是不一致的:废弃了 gmvc 模块等,也引入了新的模块。

  2. V2 版本支持gf gen service的方式生成 service 层,统一我们接口逻辑的实现方式,引入了 logic 层和 service 层的概念


下面我就结合自己的升级经历,分享给大家学习 GoFrame V2 必知必会的知识点:

必知必会

  1. 项目工程结构发生了变化,且需要按照 V2 的标准来,因为 gf 工具生成代码的目录结构发生了改变,更重要的:V2 官方建议的目录结构也是我们践行"高内聚低耦合"比较好的工程目录结构。

  2. gf gen dao除了会像 V1 一样生成 dao 层和 model 层,还会另外生成 do 层和 entity 层

  3. V2 版本的目录结构实践了业务模型和数据模型解耦的思想(也是我认为非常赞的地方)

  4. V2 相比于 V1 会出现方法或者模块的情况,比如废弃了 gmvc 耦合模块,未来不再进一步支持。但是也为我们提供了更好的实现方式。


5.V2 有点编写“微服务”的意思了,需要服务注册:controller 调用一个或多个 service 实现具体的业务逻辑;但是复杂的业务逻辑又不是在 service 中实现的,为了解耦,V2 版本引入了 logic 目录,用于编写和复用复杂的业务逻辑。在 logic 中注册服务,在 service 中通过接口方式规范 logic 层要实现的方法。

重中之重

下面再介绍一下我花了很长时间才消化的知识点:

dao 代码生成(很重要)

gf gen dao


在业务项目中,官方推荐使用 dao/do/entity 的方式操作数据库,这些文件都是通过开发工具自动生成的,由开发工具统一维护。


区别于 V1 版本,V2 版本引入了 do 的概念,为什么这么设计?


在这里我只说结论,文章最后会附上官方链接:


  1. dao 层用于数据访问,这是一层抽象对象,用于和底层数据库交互,仅包含最基础的 CURD 方法

  2. model 层是结构模型,是数据结构管理模块,管理数据实体对象,以及输入与输出数据结构定义。

  3. 2.1 model 中的 do 是领域对象,用于 dao 数据操作中业务模型与实例模型转换,由工具维护,用户不能修改。

  4. 2.2 model 中的 entity 是数据模型,数据模型是模型与数据集合的一对一关系,由工具维护,用户不能修改。


后面我会带着大家用实例讲解

服务接口生成(更重要)

gf gen service


服务接口是非常重要的知识点,也是我认为在 cli 工具支持方面和 V1 版本最大的区别:


为了降低业务项目内部模块间的耦合,框架将模块间的依赖抽象为了接口,由 internal/service 包维护。internal/service 可以由开发者自定义维护接口,也可以通过 internal/logic 业务封装的代码按照一定规则自动生成接口代码文件。

实践出真知

看 10 遍文档,都不如一次动手实践。建议大家和我一起操练起来,欢迎复刻:

我的思路是这样:

  1. 下载官方的示例项目,学习一下官方是怎么写的。

  2. 给自己提需求,参考官方的实现方式,实现自己的业务场景。

  3. 我会带着大家实现经典的电商场景:添加和查询商品信息。

1. 下载运行官方示例的 GitHub

官方示例GitHub


1.1 下载部署好项目之后,启动:非常顺滑的就启动成功了:



1.2 请求接口,验证试一下 DB 是否连接正常。



1.3 查询数据库,也是有值的。



验证环境无误,下面开始带着大家参考官方示例实现自己的需求,进而更好的理解 V2 版本新特性和工程实践。

2. 基于 V2 编写商品管理

我们按照官方建议的工程方式去实践,看看会不会踩坑:


2.1 创建 goods 表如下:



2.2 通过 gf gen dao 生成 dao 和 model


初次尝试,失败,原因是没有修改 hack 目录下的 config.yaml 配置文件。



**注意:和 V1 不同,官方说 hack 目录的作用是工具脚本,存放项目开发工具、脚本等内容。例如,CLI 工具的配置,各种 shell/bat 脚本等文件。所以我们就不要像 V1 一样把 cli 工具的配置文件也写到 manifest/config 目录中了。**


2.3 搞定,成功生成。



小技巧,如果我们不指定 tables,则生成所有表对应的数据。我是比较喜欢这么操作:因为能避免自己改了多个 tables,但是在配置文件中漏写了某个 tables 导致意料之外的问题。

下面开始正式撸代码了:

我会先按照大家容易理解的方式进行编写,文章最后我会分享实践经验:按照什么顺序编写各个模块的代码是比较科学的。


2.4 首先我们实现 api 层,定义请求和响应的结构体



2.5 我们在 cmd 中注册 Goods 相关的路由



2.6 我们发现注册路由时,controller.Goods 飘红,原因是我们还没有编写这个方法。


我们参考示例代码去编写 controller 层:


我们发现右侧的示例项目,方法内部调用了 service 中的方法,但是我们目前还没有定义 service,怎么办?



我们先点击示例项目中的 user.go,查看一下 service 中都定义了什么:



经过查阅文档得知:


我们需要通过编写 logic 层实现业务逻辑,通过配置 goland 插件,自动生成 service 代码。


这要是官方建议我们的最佳实践:


2.7 导入官方提供的 xml 文件(只需要配置一次)


xml文件地址


强烈建议大家这么操作,经过这个配置在我们编写 logic 层代码的时候,service 能自动生成接口定义文件。


当然也可以不配置,只是每一次在开发/更新完成 logic 业务模块后,都需要手动执行一下 gf gen service 命令。太麻烦了!!!



2.8 我们参考右侧的示例 编写商品 goods 的 logic 代码,处理业务逻辑:



2.9 经测试我发现:在编写 logic 逻辑后,就自动在 service 层生成了对应的 goods 文件和方法,非常方便。



2.10 我们再继续写添加商品逻辑和查看商品逻辑


我们发现:在 logic 层编写完添加商品逻辑后,在右侧的 service 层自动生成了代码。



2.11 细心的同学可能发现了 service 层的 RegisterGoods 方法,这是干嘛用的呢?



答案是:我们要在 service 层生成 RegisterXX()方法后,在对应的业务模块中加上接口的实现注入。



小提示:该方法每个业务模块加一次即可。


建议大家在编写完第一个 logic 方法后(或者说 service 层生成了 RegisterXX 方法后):


  1. 就在 logic 层的 init 函数中实现服务的注册;

  2. 然后去查看 logic.go 文件是否添加了相关的依赖,没有的话也可以手动添加一下;


要成良好的编码习惯,少出 bug。


2.12 我们查看 logic 目录下的 logic.go 文件,发现已经自动添加了我们本次编写的 goods 相关的 import:


这个文件的作用是:将接口的具体实现,在程序启动时执行注册。



好了,logic 和 service 到此结束,我们已经完成了业务逻辑的编写。


内容不少,大家可以上划再看一遍这部分内容,消化吸收一下。


2.13 咱们回过头来,继续编写 controller 层的代码:


我们参考官方提供的 controller/user.go 实现了我们自己的 controller/goods.go 的添加商品方法:



2.14 到这里,我们已经完成了新需求的编写,启动服务查看一下效果:



很 OK,已经看到了对应的接口。

编码完毕,测试一下:

我们请求接口,添加数据看一下:



在数据库中也查看到数据:插入成功,流程走通!


反思回顾

按照上面这个流程走下来,虽然整体跑通了。我个人感觉还是比较混乱的。


我又花了比较长的时间消化吸收了官方文档的工程实践,结合我自己的经验。


我们再来梳理一下 V2 项目的编写流程,我的建议是这样的


  1. 设计表结构

  2. 使用 gf gen dao 生成对应的 dao/do/model

  3. 编写 api 层:定义业务侧数据结构,提供对外接口的输入/输出数据结构

  4. 编写 model 层:定义数据侧数据结构,提供对内的数据处理的输入/输出数据结构

  5. 编写 logic 层,自动生成 service 层代码。(通过配置 goland File Watcher 自动生成,也可以通过 gf gen service 手动执行脚本生成,建议前者)

  6. 在 service 层代码生成 RegisterXX()方法后,在对应的 logic 模块注册服务(每个模块只需要写一次)

  7. 编写 controller 层,接收/解析用户输入的参数,调用 service 层的服务。

  8. 注册路由,对外暴露接口,比如这个项目是编写 cmd.go 文件。

  9. 在 main.go 中 加入一行 _ "project-name/internal/logic" (只需写一次)

  10. 在 main.go 中加入一行 _ "github.com/gogf/gf/contrib/drivers/mysql/v2" (如果你使用的是 mysql;只需写一次)


我按照上面这个步骤,编写了查询商品逻辑,整体还是非常顺滑的:




小伙伴们也动手实践吧:


GitHub 地址:https://github.com/wangzhongyang007/gf-demo-user

带着问题学习

我在编写商品管理需求的时候有些疑惑:


为什么要定义两遍数据结构呢?在 api 层定义了一遍,在 model 层又定义了一遍,我写了两遍重复的结构体,意义何在呀?



我静下心来想想,这个设计还真的深得我心,我结合之前的项目经历一下就 get 到了 GoFrame 团队的点:

之前遇到的问题

我们之前在在开发商品中心统一入库是就遇到了难以维护的问题,原因就是业务逻辑和数据处理逻辑耦合在一起。


随着业务的复杂度越来越高,项目维护成本越来越高,甚至达到了难以维护的程度。

我们是如何解决的呢?

答案和 GoFrame 的数据模型和业务模型解耦,底层思想是一样的:


我们把复杂的逻辑进行了拆分:定义了业务模块和数据处理模块。


业务模块:只处理接收的参数,并不需要关心如何入库和取值,按照数据模块的要求,处理好前端传入的数据,统一结构体传递给数据模块。


数据模块:不需要关心业务模块的具体实现,定义了统一的入参标准,要求业务模块按照自己的要求,统一传入数据;数据模块考虑的重点是如何高效的批量插入数据,如何高效的按需取值,并不需要关心多变的业务侧需求。

升华一下

经过对冗余模块的拆解,梳理清楚了数据模型和业务模型的边界,我们不仅解决了之前项目难以维护的问题,还提高了灵活对接客户需求的能力。


结合自己的项目经历和这次实践 V2 版本的经历,所以我说:让开发者更好的做到“模块内部高内聚,模块之间松耦合”,是我认为 GoFrame V2 设计的精髓。


好了,这篇文章就到这里,升级之旅实属不易,欢迎大家点赞、评论、转发。


第二篇《基于 GoFrame 的商业项目从 V1.16 升级到 V2.2.0 的踩坑之旅》在编写中,欢迎大家在评论区分享自己的升级经验。

一起学习,升级打怪

欢迎和我们一起学 Go,坚持打卡,互相监督。


可以通过下面「作者栏」的信息联系我加群,一起学习。

发布于: 2022-11-19阅读数: 35
用户头像

王中阳Go

关注

靠敲代码在北京买房的程序员 2022-10-09 加入

公众号:程序员升级打怪之旅👍微信:wangzhongyang1993👍InfoQ优质创作者👍掘金签约作者👍B站&掘金&CSDN&思否等全平台账号:王中阳Go

评论 (2 条评论)

发布
用户头像
欢迎和我们一起学 Go,坚持打卡,互相监督。
2022-11-21 09:50 · 陕西
回复
用户头像
让开发者更好的做到“模块内部高内聚,模块之间松耦合”,是我认为GoFrame V2设计的精髓。
2022-11-19 22:44 · 北京
回复
没有更多了
GoFrame V2真香,我是Get到了高内聚低耦合的点,你呢?_Go_王中阳Go_InfoQ写作社区