前言
今天我们讲一下在不使用微服务的情况下,如何使用GO的workspace(中文应该是叫工作区)配合私有库来重构多端非微服务项目。
前提
现在有一个项目,代码分成了商户端biz和管理端admin。分别提交到不同的git代码库中。两个项目连接的数据库是同一个。整个项目没有微服务化。
问题
但现在商户端和管理端有很多业务逻辑很类似。比如查看商户余额,可能商户端和管理端都需要调用一个接口叫 balance.Get(merchantId int),粗暴的做法是把这个方法在biz和admin两个git仓库里都写一份。
随着代码量增加,这个balance.Get接口将会不断迭代。这时候需要把两边的代码同步修改一份。
唔,闻到代码的臭味了。
方案
微服务
一种方法是把biz和admin项目重构为微服务项目,新增一个balance的微服务,biz和admin通过RPC调用来获得数据。此后balance内部业务更新只需要关注自身即可。
但这个方法需要对biz和admin项目进行微服务改造,项目时间上不允许。暂时不使用此方法
私有库
可以将balance的业务方法封装进另一个service私有库,然后使用私有库的方法进行开发。在biz和admin的go.mod文件中设置好replace后,再调用service库中的方法。此后service库即可以独立迭代。不需要在biz/admin中反复修改。
但这个方法的问题在于go.mod文件中的replace中需要指定开发者的本地路径,而在多人开发的情况下,这个本地路径每人不同,提交上去后会污染其它开发者的开发环境。不是最佳解决方案。
workspace方案
在GO 1.18中引入了workspace,可以将不同目录的项目编排在一起。
把biz和admin放在同一个目录下,创建service项目,创建go.work文件。
workspaceDir
├── biz
│ ├── .git
│ ├── go.mod // biz项目
│ └── main.go
├── admin
│ ├── .git
│ ├── go.mod // admin项目
│ └── main.go
├── service
│ ├── .git
│ ├── go.mod // service项目
│ └── main.go
├── go.work // 工作区
go.work文件内容如下
go 1.18
use (
./biz
./admin
./service
)
在工作区目录下执行go work sync之后,此时在 biz和admin中就可以方便地调用service包里的方法了。
比如在biz项目中可以直接使用如下的use
use "service/sdk/balance"
main() {
balance.Get(1)
}
workspace的方案已经避免了前个方案在go.mod中使用 replace 导致污染的问题。并且各端都可以独立提交git仓库。
workspace + 私有库
如果再优化一点,将service库当作内部独立库提交到私有库中。那么最终的调用方式会是这样的:
use "git.mydomain.com/team/service/sdk/balance"
main() {
balance.Get(1)
}
当 service 进入相对稳定状态时,就可以这么干了。这样万一有新的仓库不需要加入workspace的时候,就可以直接使用私有库。
后记
这样拆分后代码比较干净,也相对好维护,团队切换成本低。未来如果需要切换成微服务的话也有基础。
希望大家好运。