后端开发规范指南学习

摘要:项目的开发规范,包括代码规范、Git 工作流、团队协作等方面的最佳实践学习,搬运(部分)来自:https://github.com/flipped-aurora/gin-vue-admin

后端开发规范指南

📝 Go 代码规范

命名规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// 包名:小写,简短,有意义
package user
package system

// 常量:大写,下划线分隔
const (
MAX_RETRY_COUNT = 3
DEFAULT_TIMEOUT = 30
API_VERSION = "v1"
)

// 变量:驼峰命名
var (
userService *UserService
configFilePath string
isDebugMode bool
)

// 函数:大写开头(公开),小写开头(私有)
func GetUserList() []User {}
func createUser() error {}

// 结构体:大写开头,驼峰命名
type UserService struct {
db *gorm.DB
redis *redis.Client
}

// 接口:以 -er 结尾或描述性名称
type UserRepository interface {
Create(user *User) error
GetByID(id uint) (*User, error)
}

type Validator interface {
Validate() error
}

注释规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
// Package user 提供用户管理相关功能
// 包括用户的增删改查、权限验证等操作
package user

// UserService 用户服务,负责处理用户相关的业务逻辑
type UserService struct {
db *gorm.DB
redis *redis.Client
}

// NewUserService 创建用户服务实例
// 参数:
// db: 数据库连接
// redis: Redis连接
// 返回:
// *UserService: 用户服务实例
func NewUserService(db *gorm.DB, redis *redis.Client) *UserService {
return &UserService{
db: db,
redis: redis,
}
}

// GetUserByID 根据用户ID获取用户信息
// 该方法会先从缓存中查找,如果缓存中不存在则从数据库查询
// 参数:
// id: 用户ID
// 返回:
// *User: 用户信息,如果用户不存在则返回nil
// error: 错误信息
func (s *UserService) GetUserByID(id uint) (*User, error) {
// 实现逻辑...
}

错误处理规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// 自定义错误类型
type UserError struct {
Code int `json:"code"`
Message string `json:"message"`
Data string `json:"data,omitempty"`
}

func (e *UserError) Error() string {
return e.Message
}

// 错误常量定义
var (
ErrUserNotFound = &UserError{Code: 1001, Message: "用户不存在"}
ErrUserExists = &UserError{Code: 1002, Message: "用户已存在"}
ErrInvalidPassword = &UserError{Code: 1003, Message: "密码格式不正确"}
ErrPermissionDenied = &UserError{Code: 1004, Message: "权限不足"}
)

// 错误处理示例
func (s *UserService) CreateUser(user *User) error {
// 验证用户是否已存在
exists, err := s.userExists(user.Username)
if err != nil {
return fmt.Errorf("检查用户是否存在失败: %w", err)
}
if exists {
return ErrUserExists
}

// 验证密码强度
if err := s.validatePassword(user.Password); err != nil {
return fmt.Errorf("密码验证失败: %w", err)
}

// 创建用户
if err := s.db.Create(user).Error; err != nil {
return fmt.Errorf("创建用户失败: %w", err)
}

return nil
}

结构体标签规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
type User struct {
ID uint `json:"id" gorm:"primarykey;comment:用户ID"`
Username string `json:"username" gorm:"uniqueIndex;size:64;not null;comment:用户名" validate:"required,min=3,max=64"`
Password string `json:"-" gorm:"size:255;not null;comment:密码" validate:"required,min=8"`
Email string `json:"email" gorm:"uniqueIndex;size:128;comment:邮箱" validate:"email"`
Phone string `json:"phone" gorm:"size:20;comment:手机号" validate:"phone"`
Status int `json:"status" gorm:"default:1;comment:状态(1:启用 0:禁用)"`
CreatedAt time.Time `json:"createdAt" gorm:"comment:创建时间"`
UpdatedAt time.Time `json:"updatedAt" gorm:"comment:更新时间"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index;comment:删除时间"`
}

// TableName 指定表名
func (User) TableName() string {
return "sys_users"
}

🔄 Git 工作流

1. 分支管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 主要分支
main/master # 主分支,用于生产环境
develop # 开发分支,用于集成开发

# 功能分支
feature/user-management # 功能开发分支
feature/api-optimization # 功能开发分支

# 修复分支
hotfix/login-bug # 紧急修复分支
bugfix/user-validation # 普通修复分支

# 发布分支
release/v1.2.0 # 发布准备分支

2. 提交规范

提交信息格式

1
2
3
4
5
<type>(<scope>): <subject>

<body>

<footer>

类型说明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 功能相关
feat: 新功能
fix: 修复bug
perf: 性能优化

# 代码相关
refactor: 重构代码
style: 代码格式调整

# 文档和测试
docs: 文档更新
test: 测试相关

# 构建和配置
build: 构建系统或依赖更新
ci: CI配置更新
chore: 其他杂项

# 版本相关
revert: 回滚提交

提交示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 新功能
git commit -m "feat(user): 添加用户批量导入功能

- 支持Excel文件导入
- 添加数据验证
- 支持导入进度显示

Closes #123"

# 修复bug
git commit -m "fix(auth): 修复JWT token过期时间计算错误

修复了token过期时间计算不准确的问题,
现在使用UTC时间进行计算。

Fixes #456"

# 重构
git commit -m "refactor(api): 重构用户API响应结构

BREAKING CHANGE: 用户API响应格式发生变化
- 将user_info改为userInfo
- 添加了权限信息字段"

3. 分支操作流程

功能开发流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
# 1. 从develop分支创建功能分支
git checkout develop
git pull origin develop
git checkout -b feature/user-management

# 2. 开发功能
# ... 编写代码 ...

# 3. 提交代码
git add .
git commit -m "feat(user): 添加用户管理功能"

# 4. 推送到远程
git push origin feature/user-management

# 5. 创建Pull Request
# 在GitHub/GitLab上创建PR,请求合并到develop分支

# 6. 代码审查通过后合并
# 删除功能分支
git checkout develop
git pull origin develop
git branch -d feature/user-management
git push origin --delete feature/user-management

紧急修复流程

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 1. 从main分支创建hotfix分支
git checkout main
git pull origin main
git checkout -b hotfix/login-bug

# 2. 修复问题
# ... 修复代码 ...

# 3. 提交修复
git add .
git commit -m "fix(auth): 修复登录验证失败问题"

# 4. 合并到main和develop
git checkout main
git merge hotfix/login-bug
git push origin main

git checkout develop
git merge hotfix/login-bug
git push origin develop

# 5. 删除hotfix分支
git branch -d hotfix/login-bug
git push origin --delete hotfix/login-bug

# 6. 创建版本标签
git tag -a v1.1.1 -m "修复登录验证问题"
git push origin v1.1.1

👥 团队协作

1. 代码审查

Pull Request 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
## 变更描述

简要描述本次变更的内容和目的。

## 变更类型

- [ ] 新功能
- [ ] Bug修复
- [ ] 性能优化
- [ ] 重构
- [ ] 文档更新
- [ ] 测试相关

## 测试

- [ ] 单元测试通过
- [ ] 集成测试通过
- [ ] 手动测试通过
- [ ] 性能测试通过(如适用)

## 检查清单

- [ ] 代码符合项目规范
- [ ] 添加了必要的注释
- [ ] 更新了相关文档
- [ ] 没有引入新的安全风险
- [ ] 向后兼容(或已标记为破坏性变更)

## 相关Issue

Closes #123
Related to #456

## 截图(如适用)

<!-- 添加截图或GIF来展示变更效果 -->

## 额外说明

<!-- 任何需要审查者注意的特殊说明 -->

代码审查要点

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
### 功能性审查
- [ ] 功能是否按需求实现
- [ ] 边界条件是否处理
- [ ] 错误处理是否完善
- [ ] 性能是否可接受

### 代码质量审查
- [ ] 代码结构是否清晰
- [ ] 命名是否规范
- [ ] 注释是否充分
- [ ] 是否有代码重复

### 安全性审查
- [ ] 输入验证是否充分
- [ ] 权限控制是否正确
- [ ] 敏感信息是否保护
- [ ] SQL注入等安全问题

### 测试审查
- [ ] 测试覆盖率是否足够
- [ ] 测试用例是否合理
- [ ] 集成测试是否通过

2. 项目管理

Issue 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
## Bug报告

### 环境信息
- 操作系统:
- 浏览器:
- 项目版本:

### 问题描述

简要描述遇到的问题。

### 复现步骤

1. 打开页面
2. 点击按钮
3. 查看结果

### 期望行为

描述期望的正确行为。

### 实际行为

描述实际发生的行为。

### 截图

如果适用,添加截图来帮助解释问题。

### 额外信息

添加任何其他有助于解决问题的信息。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
## 功能需求

### 需求描述

详细描述新功能的需求。

### 用户故事

作为 [用户角色],我希望 [功能描述],以便 [价值/目的]。

### 验收标准

- [ ] 标准1
- [ ] 标准2
- [ ] 标准3

### 设计稿

<!-- 如果有设计稿,请添加链接或图片 -->

### 技术要求

- 前端技术栈:
- 后端技术栈:
- 数据库变更:

### 优先级

- [ ] 高
- [ ] 中
- [ ] 低

3. 文档规范

README 模板

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
# 项目名称

简要描述项目的目的和功能。

## 功能特性

- 功能1
- 功能2
- 功能3

## 技术栈

### 后端
- Go 1.19+
- Gin
- GORM
- Redis
- MySQL

### 前端
- Vue 3
- Element Plus
- Vite
- Pinia

## 快速开始

### 环境要求

- Go 1.19+
- Node.js 16+
- MySQL 8.0+
- Redis 6.0+

### 安装步骤

1. 克隆项目
```bash
git clone https://github.com/your-org/project-name.git
cd project-name
  1. 后端设置
1
2
3
4
5
cd server
go mod download
cp config.yaml.example config.yaml
# 修改配置文件
go run main.go
  1. 前端设置
1
2
3
cd web
npm install
npm run dev

部署

Docker 部署

1
docker-compose up -d

手动部署

详细的部署步骤…

贡献指南

  1. Fork 项目
  2. 创建功能分支
  3. 提交变更
  4. 推送到分支
  5. 创建 Pull Request

许可证

本项目采用 Apache License 2.0 开源许可证

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

#### API 文档规范

```markdown
# API 文档

## 基础信息

- 基础URL: `http://localhost:8888`
- 版本: v1
- 认证方式: JWT Token

## 通用响应格式

```json
{
"code": 0,
"data": {},
"msg": "success"
}

用户管理

获取用户列表

请求

1
2
3
4
5
6
7
8
9
POST /user/getUserList
Content-Type: application/json
Authorization: Bearer <token>

{
"page": 1,
"pageSize": 10,
"keyword": ""
}

响应

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"code": 0,
"data": {
"list": [
{
"id": 1,
"username": "admin",
"email": "admin@example.com",
"createdAt": "2023-01-01T00:00:00Z"
}
],
"total": 1,
"page": 1,
"pageSize": 10
},
"msg": "success"
}

错误响应

错误码 说明
1001 用户不存在
1002 权限不足
1003 参数错误
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

## 🔧 开发工具配置

### 1. VS Code 配置

#### settings.json

```json
{
"go.formatTool": "goimports",
"go.lintTool": "golangci-lint",
"go.testFlags": ["-v"],
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": true
},
"eslint.validate": [
"javascript",
"javascriptreact",
"vue"
],
"vetur.format.defaultFormatter.html": "prettier",
"vetur.format.defaultFormatter.js": "prettier",
"vetur.format.defaultFormatter.css": "prettier"
}

推荐扩展

1
2
3
4
5
6
7
8
9
10
11
{
"recommendations": [
"golang.go",
"vue.volar",
"esbenp.prettier-vscode",
"dbaeumer.vscode-eslint",
"bradlc.vscode-tailwindcss",
"ms-vscode.vscode-json",
"redhat.vscode-yaml"
]
}

2. Git Hooks

pre-commit

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#!/bin/sh
# .git/hooks/pre-commit

echo "Running pre-commit checks..."

# 检查Go代码格式
if ! gofmt -l . | grep -q '^$'; then
echo "Go code is not formatted. Please run 'gofmt -w .'"
exit 1
fi

# 运行Go测试
if ! go test ./...; then
echo "Go tests failed"
exit 1
fi

# 检查前端代码格式
cd web
if ! npm run lint; then
echo "Frontend linting failed"
exit 1
fi

echo "Pre-commit checks passed!"

commit-msg

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
# .git/hooks/commit-msg

commit_regex='^(feat|fix|docs|style|refactor|test|chore|perf|ci|build|revert)(\(.+\))?: .{1,50}'

if ! grep -qE "$commit_regex" "$1"; then
echo "Invalid commit message format!"
echo "Format: <type>(<scope>): <subject>"
echo "Example: feat(user): add user registration"
exit 1
fi

3. 代码质量工具

.golangci.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
linters-settings:
govet:
check-shadowing: true
golint:
min-confidence: 0
gocyclo:
min-complexity: 15
maligned:
suggest-new: true
dupl:
threshold: 100
goconst:
min-len: 2
min-occurrences: 2
misspell:
locale: US
lll:
line-length: 140
goimports:
local-prefixes: github.com/flipped-aurora/gin-vue-admin

linters:
enable:
- bodyclose
- deadcode
- depguard
- dogsled
- dupl
- errcheck
- gochecknoinits
- goconst
- gocyclo
- gofmt
- goimports
- golint
- gosec
- gosimple
- govet
- ineffassign
- interfacer
- lll
- misspell
- nakedret
- scopelint
- staticcheck
- structcheck
- stylecheck
- typecheck
- unconvert
- unparam
- unused
- varcheck
- whitespace

run:
timeout: 5m

.eslintrc.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
module.exports = {
root: true,
env: {
node: true,
browser: true,
es2021: true
},
extends: [
'plugin:vue/vue3-essential',
'@vue/standard'
],
parserOptions: {
ecmaVersion: 2021,
sourceType: 'module'
},
rules: {
'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off',
'vue/multi-word-component-names': 'off',
'space-before-function-paren': ['error', 'never'],
'comma-dangle': ['error', 'never']
}
}

📊 质量保证

1. 测试规范

单元测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// user_service_test.go
package service

import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
)

func TestUserService_CreateUser(t *testing.T) {
// 准备测试数据
user := &User{
Username: "testuser",
Email: "test@example.com",
Password: "password123",
}

// 创建mock
mockDB := new(MockDB)
mockDB.On("Create", mock.AnythingOfType("*User")).Return(nil)

// 创建服务实例
service := NewUserService(mockDB, nil)

// 执行测试
err := service.CreateUser(user)

// 断言结果
assert.NoError(t, err)
mockDB.AssertExpectations(t)
}

func TestUserService_CreateUser_UserExists(t *testing.T) {
user := &User{
Username: "existinguser",
Email: "existing@example.com",
Password: "password123",
}

mockDB := new(MockDB)
mockDB.On("First", mock.AnythingOfType("*User"), mock.Anything).Return(nil)

service := NewUserService(mockDB, nil)

err := service.CreateUser(user)

assert.Error(t, err)
assert.Equal(t, ErrUserExists, err)
}

集成测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// integration_test.go
package test

import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"testing"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
)

func TestUserAPI_CreateUser(t *testing.T) {
// 设置测试环境
gin.SetMode(gin.TestMode)
router := setupRouter()

// 准备测试数据
userData := map[string]interface{}{
"username": "testuser",
"email": "test@example.com",
"password": "password123",
}

jsonData, _ := json.Marshal(userData)

// 创建请求
req, _ := http.NewRequest("POST", "/user/register", bytes.NewBuffer(jsonData))
req.Header.Set("Content-Type", "application/json")

// 执行请求
w := httptest.NewRecorder()
router.ServeHTTP(w, req)

// 验证响应
assert.Equal(t, http.StatusOK, w.Code)

var response map[string]interface{}
err := json.Unmarshal(w.Body.Bytes(), &response)
assert.NoError(t, err)
assert.Equal(t, float64(0), response["code"])
}

2. 性能测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// benchmark_test.go
package service

import (
"testing"
)

func BenchmarkUserService_GetUserByID(b *testing.B) {
service := setupUserService()

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, err := service.GetUserByID(1)
if err != nil {
b.Fatal(err)
}
}
}

func BenchmarkUserService_GetUserList(b *testing.B) {
service := setupUserService()

b.ResetTimer()
for i := 0; i < b.N; i++ {
_, _, err := service.GetUserList(PageInfo{Page: 1, PageSize: 10})
if err != nil {
b.Fatal(err)
}
}
}
Author

Cofeesy

Posted on

2025-11-29

Updated on

2025-11-29

Licensed under

Comments