上一期我分享了为什么要升级小A的后端以及框架选择,今天我会分享数据库应用和项目结构(project structure)。
数据库
小A目前使用的是市面上使用最广的关系型数据库MySQL,这两年MySQL有江河日下的趋势,感觉PostgreSQL是一个更好的选择。我大概知道PostgresSQL对JSON支持更好,数据同步比较容易。不过最终我还是决定继续使用MySQL,因为阿里云RDS提供Serverless MySQL,这对我等穷人太友好了,又省下几百块!
数据库后面还会提到。
项目结构(project structure)
这是一个网上讨论量极大的一个话题,没有绝对的对错,也不存在一种比另一种更好的情况,主要还是看项目本身。每个人的命名方式也不同,所以在此我只分享我认为是最好的。
首先引用一下Clean Architecture图
https://blog.cleancoder.com/uncle-bob/2012/08/13/the-clean-architecture.html基本概念就是自己干自己的事,不是自己的事不干。依赖程度尤里而外递增,Entities不要知道任何外层。(职场上亦是如此。。。)
小A后端的文件夹们cmd 是程序入口,go项目入口一定是main.go
entity和enum两个组成了Clean Architecture图里的Entities,属于整个程序的最里一层,基本是数据库的映射。enum类我习惯加type后缀。
domain entitiesfeature相当于Clean Architecture图里的Use Cases,是全部的商业逻辑。我习惯加query(读操作)和 command(写操作)后缀。每一个文件只做一件事。
use cases每一个query/command都含有Validate和Handle两个function。Validate会返回exception。它们都属于request-validator interface。
validate和handlemiddleware用来在数据到达controller之前做检查。
middlewarevalidate-json-request-middleware 和 validate-query-request-middleware 通过generic调用query/command的Validate功能,这样就不需要重复在controller里做Validate了。很难想象在golang支持generic前要做这些得多麻烦。
validateJsonRequest middlewarecontroller,middleware,exception,dto就是Clean Architecture图里的第三层
controller因为有middleware,controller里面只需要获取信息然后handle
controller内部dto又名Data Transfer Object,用来向外输出从数据库获取的entity,避免敏感信息泄露。有些人会把query/command也归于dto,然后在写一堆handler文件,我觉得太麻烦了,handler直接写在query/command里面了,所以在我这里query/command不算dto。
data transfer objectexception用来返回各种错误,主要有inputException(用户输入错误)和系统错误(数据库错误等)。input-exceptions用来存放多个input-exception。
exceptionrepository是全部的数据库操作,属于Clean Architecture图最外一层。我先定义了interfaces,然后用dependency injection倒入实际操作
repository其中unit-of-work是全部repository的合集,可以用来做transaction操作
unit-of-workservice也属于Clean Architecture图最外一层,包含各种外部服务,也是用了dependency injection
service到这里大概的结构就解释完了。一些外部框架包括
1. gin web框架
2. gorm 数据库orm
3. zap logger
4. sentry记载崩溃
关于数据库我想再说一点
我以前会把每一个http请求都包在一个数据库transaction里面,现在看是没必要的。只有在多个table写入或更改数据的情况才需要transaction以保证数据一致,所以我把gorm的SkipDefaultTransaction设为true。
本来我想加入读写分离机制,可以通过两个repository,一个master,一个readonly连接两个数据库地址做到;也可以通过微服务+消息列队做到。我看小A短期不会有这方面的需求,最终没有加入。
这期写这么多有一个原因是我在学习编程时总觉得网上能找到的资料虽然很多,但大部分都是互相抄袭,很多时候都没有一个真正在线运营的项目的解析。还有很多概念在ASP.NET里很常见却在go里被忽略了,比如dto,dependency injection等。
如果有同学需要代码可以留言给我。
下一期我想讲代码部署。
网友评论