这是我参与「第三届青训营 -后端场」笔记创作活动的第 7 篇笔记
使用 Go 语言开发的哲学
-
Go 语言从诞生之初就将效率和简单作为自己的主要目标,而使用 Go 语言开发,你只需要关注功能实现的逻辑,在开发的实际过程中进行补充就可以了。事实上,最好的做法就是围绕自己的逻辑,缺啥补啥。
-
举个例子,你需要使用 Gin 写一个 Web 的后端,首先,你想到,你需要处理客户端传来的请求,那么你就可以通过
gin.Default()拿取一个gin.Engine来处理,在这里你并不需要考虑其中的日志和崩溃恢复策略,是否重写日志和 Recovery 是之后需要考虑的事情。 -
接下来,你想到,对于不同的路由需要有不同的处理器(controller)来处理,这些路由可以分为不同的组,比如
/user/login,/user/register和/info/:id,这个时候,你通过gin.Group和GET/POST来快速地建立路由,但是你突然发现,你并没有可用的 controller,没关系,再建个包塞进去就好了。 -
假设你在项目的根目录里新建了一个文件夹 controller/ 这里面放着
controller包 (或者你觉得这个包名有点长,不如直接叫做ctrl。没问题!包名和文件夹名不是强制相同的,你想怎么取就怎么取,怎么实用怎么来!) -
现在你的项目目录里有个
main.go、一个文件夹 controller/ ,里面放着一个ctrl包(除去go.mod、go.sum。或者你的项目是个使用了 go workspace 的项目,不过这都无所谓,先假设当前的项目是基于单个 go module 开发的),包里可能根据不同的服务写了不同名称的.go文件,文件里写了一些 controller -
好的,现在你有了 controller,路由的处理也写好了,但是看着膨胀起来的
main.go,多少觉得不够优雅……简单!抽取成一个函数,把*gin.Engine当做参数,来处理路由。或许还可以放到一个叫做router.go的文件中,而这个文件可以直接放在main包中!于是乎,你的main.go变成了这样:
package main
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
route(r)
}
どのような優雅さ!
下面的是 router.go
package main
import (
"l-gin/controller"
"github.com/gin-gonic/gin"
)
func route(r *gin.Engine) {
userGroup := r.Group("/user")
{
// 查看给定用户的信息
userGroup.GET("/info/:id", controller.Info)
// 用户登录
userGroup.POST("/login", controller.Login)
// 用户注册
userGroup.POST("/register", controller.Register)
// 关注操作
userGroup.POST("/follow", controller.Follow)
// ...
}
}
- 好了,到现在为止,路由已经建好了,那么我们就可以启动服务器了:
r.Run("127.0.0.1:80")
-
等等等等,其他的东西呢?没事,我们慢慢来
-
让我们从拿“用户登录”这个功能来开刀,首先,登录需要向服务器发送一些数据,我们需要将前端发送过来的数据包装一下,简单来说就是通过结构体简单封装一下。封装的过程很简单,这里就不展开了。
-
好,现在我们得到了一个封装好的结构体,它就写在
controller/user.go中。但是,我们不只有这一个服务,请求也不可能只有这一个类型,所以,我们可以再提取出来一个 req/ 里面放个叫做req的包,这个包放着我的用于封装请求的结构体
-
这里把 req 单独抽出来不止方便统一管理,同时也有另外一个好处,接着看下去你就知道了
-
一般我们会将处理前端发来的数据的逻辑封装在 service 层(假设包名为
srv),而有时,我们会想直接把 controller 层封装好的结构体(或者结构体的指针,一般传指针是比较理想的)直接传到 service 层。也就是说,我们的 controller 调用了 service 层的函数,如果我们不将 req 抽取出来,那么 service 层想要使用 controller 层封装好的结构体,就只能 import controller 层的包! -
看出来了吗?!我们将业务逻辑提取到 service 层,又想直接使用 controller 层封装的结构体,所以
srv导入了ctrl,而在ctrl包,我们又导入了srv,循环依赖了,而这是 Go 不允许的! -
所以,在可以且合理的范围内,进行适当地抽取,不只是让你的代码变得清晰,也会避免一些不必要的麻烦。
-
好了,到目前为止,使用 Go 语言进行开发的哲学应该说的
比较明白了,之后就是在实践中活用,读万卷书,行万里路(bushi)