guides/go.md
2023-12-27 10:38:34 +08:00

196 lines
6.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 规范目录
[命名](#命名)
[包名package](#包名package)
[变量](#变量)
[常量](#常量)
[接口](#接口)
[结构体](#结构体)
[方法](#方法)
[注释](#注释)
[数据库设计](#数据库设计)
[API设计风格](#api设计风格)
## 命名
文件和目录命名一律采用小写,不用驼峰式,尽量见名思义,看见文件名就可以知道这个文件下的大概内容。尽量和标准库不要冲突。
其中测试文件以_test.go结尾除测试文件外命名`不出现下划线`。
例子:
stringutil.go stringutil_test.go
## 包名package
包名用全小写,使用短命名,尽量和标准库不要冲突。
包名统一使用单数形式。
## 变量
变量命名一般采用驼峰式当遇到特有名词缩写或简称如DNS的时候特有名词根据是否私有全部大写或小写, `不使用下划线`
例子:
apiClient、URLString
## 常量
同变量规则,力求语义表达完整清楚,不要嫌名字长。
如果模块复杂为避免混淆可按功能统一定义在package下的一个文件中。
## 接口
单个函数的接口名以 er 为后缀
type Reader interface {
Read(p []byte) (n int, err error)
}
两个函数的接口名综合两个函数名,如:
type WriteFlusher interface {
Write([]byte) (int, error)
Flush() error
}
三个以上函数的接口名类似于结构体名,如:
type Car interface {
Start()
Stop()
Drive()
}
## 结构体
结构体名应该是名词或名词短语,`不使用下划线`如Account,Book避免使用Manager这样的。
如果该数据结构需要序列化如json 则首字母大写, 包括里面的字段。
## 方法
方法名应该是动词或动词短语,采用驼峰式, `不使用下划线`。将功能及必要的参数体现在名字中, 不要嫌长, 如updateByIdgetUserInfo.
如果是结构体方法,那么 Receiver 的名称使用缩写,一般使用结构体名的首字母或前两个字母(小写)作为 Receiver 的名称。 如:
func (f foo) method() {
...
}
func (re *Receiver) method() {
...
}
对于结构体方法中Receiver命名应该统一 要么都使用值, 要么都用指针。
## 注释
每个包都应该有一个包注释,位于 package 之前。如果同一个包有多个文件,只需要在一个文件中编写即可;如果你想在每个文件中的头部加上注释,需要在版权注释和 Package前面加一个空行否则版权注释会作为Package的注释。如
// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package net
每个以大写字母开头(即可以导出)的方法应该有注释,且以该函数名开头。如:
// Get 会响应对应路由转发过来的 get 请求
func (c *Controller) Get() {
...
}
大写字母开头的方法以为着是可供调用的公共方法,如果你的方法想只在本包内掉用,请以小写字母开发。如:
func (c *Controller) curl() {
...
}
注释应该用一个完整的句子,注释的第一个单词应该是要注释的指示符,以便在 godoc 中容易查找。
注释应该以一个句点 . 结束
## 数据库设计
* 表名统一采用单数形式如user_info
* 字段名统一采用驼峰式如小写加下划线如user_id
* 数据表设计时索引名称要加上表名(或缩写,索引名称也尽量避免过长)前缀idx/uni后缀,索引名不能重复,postgresql数据库时索引名全局唯一
* 每个表必须要有主键不然goctl生成的模型文件会报错
* 每个表必须带上created_at、updated_at和deleted_at字段方便生成仓库文件 软删除可以在仓库创建时选择是否使用
* 数据库关键字不能用作字段名, 如desc asc 等 pg select 带关键字字段时会报错
## API设计风格
以go-zero框架开发为例:
* `接口请求参数和返回结果统一下划线分隔`, 请求参数结构体以Req结尾 返回结果结构体以Res结尾
* 代码目录和文件名称全部小写 `不加下划线` (模型和repository生成文件除外)
* app下创建应用api文件统一放在apifile目录 以main.api为主文件
* 数据库表名全部改成单数(方便生成工具使用)
* 接口查询和更新Req参数结构非必传(optional)字段用指针,为统一方便记忆全部请求参数都使用指针类型,
这样logic获取请求参数都是指针 (因为指针结构体请求时不传该参会为nil类型使copier复制时就会跳过修改此字段) eg
```
UpdateAppInstanceReq {
AppKey *string `path:"appKey"`
UserId *int64 `json:"userId,optional"`
Name *string `json:"name,optional"`
Logo *string `json:"logo,optional"`
}
```
* GET请求参数使用参数的flag要写成form传递 用json传递会导致参数无法获取到
```
QueryDeviceReq {
Page *uint64 `form:"page,optional,default=1"`
PageSize *uint64 `form:"page_size,optional,default=20"`
GroupId *int64 `form:"group_id,optional"`
IotProductKey *string `form:"iot_product_key,optional"`
Keyword *string `form:"keyword,optional"`
}
```
* Api创建和删除非必要不在logic return 内容, 200响应即成功,eg:
```
@handler Create
post / (CreateReq)
@handler Delete
delete /:id (IdPathReq)
```
* ##### Api定义尽量保持一致(动作+资源)
* 查询 => QueryXXX
* 创建 => CreateXXX
* 编辑 => UpdateXXX
* 删除 => DeleteXXX
* 详情 => DetailXXX
其他:
* 上传 => UploadXXX
* 触发 => TriggerXXX
* ##### 请求参数结构体命名为handler后方法名+Req
* ##### 返回结果结构体命名为handler后方法名+Res
```
示例:
service smartenergy {
@doc "查询触发器"
@handler QueryTrigger
get / (QueryTriggerReq) returns (QueryTriggerRes)
@doc "创建触发器"
@handler CreateTrigger
post / (CreateTriggerReq) returns (TriggerRes)
@doc "编辑触发器"
@handler UpdateTrigger
put /:id (UpdateTriggerReq)
@doc "触发器详情"
@handler DetailTrigger
get /:id (TriggerIdReq)
@doc "删除触发器"
@handler DeleteTrigger
delete /:id (TriggerIdReq)
}
```
* 尽量避免修改handler 因为修改api文件重新生成不会生成已有handler 无修改过handler方便直接删除目录重新生成