537 lines
11 KiB
Markdown
537 lines
11 KiB
Markdown
# 📋 最佳实践指南
|
||
|
||
## 开发最佳实践
|
||
|
||
### 1. 代码规范
|
||
|
||
```bash
|
||
# 格式化代码
|
||
gofmt -w .
|
||
goimports -w .
|
||
|
||
# 代码检查
|
||
golangci-lint run
|
||
|
||
# 生成文档
|
||
godoc -http=:6060
|
||
```
|
||
|
||
**编码标准**:
|
||
|
||
- 遵循 Go 官方编码规范
|
||
- 使用有意义的变量和函数名
|
||
- 保持函数简洁,单一职责
|
||
- 添加必要的注释和文档
|
||
|
||
### 2. Git 工作流
|
||
|
||
```bash
|
||
# 功能分支开发
|
||
git checkout -b feature/user-profile
|
||
git add .
|
||
git commit -m "feat: add user profile management"
|
||
git push origin feature/user-profile
|
||
|
||
# 代码审查后合并
|
||
git checkout main
|
||
git merge feature/user-profile
|
||
git push origin main
|
||
```
|
||
|
||
**提交规范**:
|
||
|
||
- `feat`: 新功能
|
||
- `fix`: 修复问题
|
||
- `docs`: 文档更新
|
||
- `style`: 代码格式修改
|
||
- `refactor`: 代码重构
|
||
- `test`: 测试相关
|
||
- `chore`: 构建过程或辅助工具的变动
|
||
|
||
### 3. 测试策略
|
||
|
||
```bash
|
||
# 运行所有测试
|
||
make test
|
||
|
||
# 只运行单元测试
|
||
go test ./internal/domains/...
|
||
|
||
# 运行集成测试
|
||
go test -tags=integration ./test/integration/...
|
||
|
||
# 生成覆盖率报告
|
||
make test-coverage
|
||
open coverage.html
|
||
```
|
||
|
||
**测试金字塔**:
|
||
|
||
- **单元测试**:70% - 测试单个函数/方法
|
||
- **集成测试**:20% - 测试模块间交互
|
||
- **端到端测试**:10% - 测试完整用户流程
|
||
|
||
### 4. 错误处理
|
||
|
||
```go
|
||
// 统一错误处理
|
||
func (s *userService) CreateUser(ctx context.Context, req *dto.CreateUserRequest) (*dto.UserResponse, error) {
|
||
// 参数验证
|
||
if err := req.Validate(); err != nil {
|
||
return nil, errors.NewValidationError("invalid request", err)
|
||
}
|
||
|
||
// 业务逻辑
|
||
user, err := s.userRepo.Create(ctx, req.ToEntity())
|
||
if err != nil {
|
||
s.logger.Error("failed to create user", zap.Error(err))
|
||
return nil, errors.NewInternalError("failed to create user")
|
||
}
|
||
|
||
return dto.ToUserResponse(user), nil
|
||
}
|
||
```
|
||
|
||
### 5. 日志记录
|
||
|
||
```go
|
||
// 结构化日志
|
||
logger.Info("user created successfully",
|
||
zap.String("user_id", user.ID),
|
||
zap.String("username", user.Username),
|
||
zap.Duration("duration", time.Since(start)))
|
||
|
||
// 错误日志
|
||
logger.Error("database connection failed",
|
||
zap.Error(err),
|
||
zap.String("host", dbHost),
|
||
zap.String("database", dbName))
|
||
```
|
||
|
||
**日志级别使用**:
|
||
|
||
- `DEBUG`: 详细调试信息
|
||
- `INFO`: 一般信息记录
|
||
- `WARN`: 警告信息
|
||
- `ERROR`: 错误信息
|
||
- `FATAL`: 致命错误
|
||
|
||
## 安全最佳实践
|
||
|
||
### 1. 认证和授权
|
||
|
||
```go
|
||
// JWT 令牌配置
|
||
type JWTConfig struct {
|
||
Secret string `yaml:"secret"`
|
||
AccessTokenTTL time.Duration `yaml:"access_token_ttl"`
|
||
RefreshTokenTTL time.Duration `yaml:"refresh_token_ttl"`
|
||
Issuer string `yaml:"issuer"`
|
||
}
|
||
|
||
// 密码加密
|
||
func HashPassword(password string) (string, error) {
|
||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||
return string(bytes), err
|
||
}
|
||
```
|
||
|
||
### 2. 输入验证
|
||
|
||
```go
|
||
// 请求验证
|
||
type CreateUserRequest struct {
|
||
Username string `json:"username" validate:"required,min=3,max=20,alphanum"`
|
||
Email string `json:"email" validate:"required,email"`
|
||
Password string `json:"password" validate:"required,min=8,containsany=!@#$%^&*"`
|
||
}
|
||
|
||
func (r *CreateUserRequest) Validate() error {
|
||
validate := validator.New()
|
||
return validate.Struct(r)
|
||
}
|
||
```
|
||
|
||
### 3. SQL 注入防护
|
||
|
||
```go
|
||
// 使用参数化查询
|
||
func (r *userRepository) FindByEmail(ctx context.Context, email string) (*entities.User, error) {
|
||
var user entities.User
|
||
err := r.db.WithContext(ctx).
|
||
Where("email = ?", email). // 参数化查询
|
||
First(&user).Error
|
||
return &user, err
|
||
}
|
||
```
|
||
|
||
### 4. HTTPS 配置
|
||
|
||
```yaml
|
||
# 生产环境配置
|
||
server:
|
||
tls:
|
||
enabled: true
|
||
cert_file: "/etc/ssl/certs/server.crt"
|
||
key_file: "/etc/ssl/private/server.key"
|
||
min_version: "1.2"
|
||
```
|
||
|
||
## 性能最佳实践
|
||
|
||
### 1. 数据库优化
|
||
|
||
```go
|
||
// 连接池配置
|
||
func setupDB(config *config.DatabaseConfig) (*gorm.DB, error) {
|
||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
sqlDB, err := db.DB()
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
|
||
// 连接池设置
|
||
sqlDB.SetMaxOpenConns(config.MaxOpenConns) // 最大连接数
|
||
sqlDB.SetMaxIdleConns(config.MaxIdleConns) // 最大空闲连接
|
||
sqlDB.SetConnMaxLifetime(config.ConnMaxLifetime) // 连接最大生命周期
|
||
|
||
return db, nil
|
||
}
|
||
```
|
||
|
||
**查询优化**:
|
||
|
||
```sql
|
||
-- 添加索引
|
||
CREATE INDEX idx_users_email ON users(email);
|
||
CREATE INDEX idx_users_created_at ON users(created_at);
|
||
|
||
-- 复合索引
|
||
CREATE INDEX idx_users_status_created ON users(status, created_at);
|
||
```
|
||
|
||
### 2. 缓存策略
|
||
|
||
```go
|
||
// 多级缓存
|
||
type CacheService struct {
|
||
localCache cache.Cache
|
||
redisCache redis.Client
|
||
ttl time.Duration
|
||
}
|
||
|
||
func (c *CacheService) Get(ctx context.Context, key string) (string, error) {
|
||
// L1: 本地缓存
|
||
if value, ok := c.localCache.Get(key); ok {
|
||
return value.(string), nil
|
||
}
|
||
|
||
// L2: Redis 缓存
|
||
value, err := c.redisCache.Get(ctx, key).Result()
|
||
if err == nil {
|
||
c.localCache.Set(key, value, c.ttl)
|
||
return value, nil
|
||
}
|
||
|
||
return "", cache.ErrCacheMiss
|
||
}
|
||
```
|
||
|
||
### 3. 异步处理
|
||
|
||
```go
|
||
// 使用工作池处理任务
|
||
type WorkerPool struct {
|
||
workers int
|
||
jobQueue chan Job
|
||
wg sync.WaitGroup
|
||
}
|
||
|
||
func (wp *WorkerPool) Start() {
|
||
for i := 0; i < wp.workers; i++ {
|
||
wp.wg.Add(1)
|
||
go wp.worker()
|
||
}
|
||
}
|
||
|
||
func (wp *WorkerPool) Submit(job Job) {
|
||
wp.jobQueue <- job
|
||
}
|
||
```
|
||
|
||
### 4. 内存管理
|
||
|
||
```go
|
||
// 对象池减少GC压力
|
||
var bufferPool = sync.Pool{
|
||
New: func() interface{} {
|
||
return make([]byte, 4096)
|
||
},
|
||
}
|
||
|
||
func processData(data []byte) error {
|
||
buffer := bufferPool.Get().([]byte)
|
||
defer bufferPool.Put(buffer)
|
||
|
||
// 使用buffer处理数据
|
||
return nil
|
||
}
|
||
```
|
||
|
||
## 运维最佳实践
|
||
|
||
### 1. 监控告警
|
||
|
||
**关键指标监控**:
|
||
|
||
```yaml
|
||
# Prometheus 告警规则
|
||
groups:
|
||
- name: tyapi-server
|
||
rules:
|
||
- alert: HighErrorRate
|
||
expr: rate(http_requests_total{status=~"5.."}[5m]) > 0.01
|
||
labels:
|
||
severity: critical
|
||
annotations:
|
||
summary: "High error rate detected"
|
||
|
||
- alert: HighResponseTime
|
||
expr: histogram_quantile(0.95, rate(http_request_duration_seconds_bucket[5m])) > 0.5
|
||
labels:
|
||
severity: warning
|
||
annotations:
|
||
summary: "High response time detected"
|
||
```
|
||
|
||
### 2. 备份策略
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# 数据库备份脚本
|
||
|
||
BACKUP_DIR="/backups/tyapi"
|
||
DATE=$(date +%Y%m%d_%H%M%S)
|
||
BACKUP_FILE="$BACKUP_DIR/tyapi_backup_$DATE.sql"
|
||
|
||
# 创建备份
|
||
pg_dump -h localhost -U postgres tyapi_prod > $BACKUP_FILE
|
||
|
||
# 压缩备份文件
|
||
gzip $BACKUP_FILE
|
||
|
||
# 保留最近7天的备份
|
||
find $BACKUP_DIR -name "*.sql.gz" -mtime +7 -delete
|
||
|
||
# 上传到云存储
|
||
aws s3 cp $BACKUP_FILE.gz s3://tyapi-backups/
|
||
```
|
||
|
||
### 3. 配置管理
|
||
|
||
```yaml
|
||
# 生产环境配置模板
|
||
server:
|
||
port: 8080
|
||
mode: release
|
||
read_timeout: 30s
|
||
write_timeout: 30s
|
||
|
||
database:
|
||
host: ${DB_HOST}
|
||
port: ${DB_PORT}
|
||
user: ${DB_USER}
|
||
password: ${DB_PASSWORD}
|
||
name: ${DB_NAME}
|
||
max_open_conns: 100
|
||
max_idle_conns: 10
|
||
|
||
redis:
|
||
host: ${REDIS_HOST}
|
||
port: ${REDIS_PORT}
|
||
password: ${REDIS_PASSWORD}
|
||
pool_size: 10
|
||
|
||
security:
|
||
jwt_secret: ${JWT_SECRET}
|
||
bcrypt_cost: 12
|
||
|
||
logging:
|
||
level: info
|
||
format: json
|
||
output: stdout
|
||
```
|
||
|
||
### 4. 容器化最佳实践
|
||
|
||
```dockerfile
|
||
# 多阶段构建 Dockerfile
|
||
FROM golang:1.21-alpine AS builder
|
||
|
||
WORKDIR /app
|
||
COPY go.mod go.sum ./
|
||
RUN go mod download
|
||
|
||
COPY . .
|
||
RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main ./cmd/api
|
||
|
||
FROM alpine:3.18
|
||
|
||
# 安全加固
|
||
RUN adduser -D -s /bin/sh appuser
|
||
RUN apk --no-cache add ca-certificates tzdata
|
||
|
||
WORKDIR /root/
|
||
|
||
COPY --from=builder /app/main .
|
||
COPY --from=builder /app/config.yaml .
|
||
|
||
USER appuser
|
||
|
||
EXPOSE 8080
|
||
|
||
HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
|
||
CMD curl -f http://localhost:8080/api/v1/health || exit 1
|
||
|
||
CMD ["./main"]
|
||
```
|
||
|
||
## 团队协作最佳实践
|
||
|
||
### 1. 代码审查
|
||
|
||
**审查检查清单**:
|
||
|
||
- [ ] 代码符合项目规范
|
||
- [ ] 测试覆盖率充足
|
||
- [ ] 错误处理正确
|
||
- [ ] 性能影响评估
|
||
- [ ] 安全漏洞检查
|
||
- [ ] 文档更新
|
||
|
||
### 2. CI/CD 流程
|
||
|
||
```yaml
|
||
# GitHub Actions 示例
|
||
name: CI/CD Pipeline
|
||
|
||
on:
|
||
push:
|
||
branches: [main, develop]
|
||
pull_request:
|
||
branches: [main]
|
||
|
||
jobs:
|
||
test:
|
||
runs-on: ubuntu-latest
|
||
steps:
|
||
- uses: actions/checkout@v3
|
||
- uses: actions/setup-go@v3
|
||
with:
|
||
go-version: 1.21
|
||
|
||
- name: Run tests
|
||
run: |
|
||
go test -v -race -coverprofile=coverage.out ./...
|
||
go tool cover -html=coverage.out -o coverage.html
|
||
|
||
- name: Upload coverage
|
||
uses: codecov/codecov-action@v3
|
||
|
||
deploy:
|
||
needs: test
|
||
runs-on: ubuntu-latest
|
||
if: github.ref == 'refs/heads/main'
|
||
steps:
|
||
- name: Deploy to production
|
||
run: |
|
||
echo "Deploying to production..."
|
||
```
|
||
|
||
### 3. 文档维护
|
||
|
||
- **API 文档**:使用 Swagger/OpenAPI 自动生成
|
||
- **架构文档**:定期更新系统架构图
|
||
- **运维手册**:记录部署和运维流程
|
||
- **故障手册**:记录常见问题和解决方案
|
||
|
||
### 4. 版本管理
|
||
|
||
```bash
|
||
# 语义化版本控制
|
||
git tag v1.2.3
|
||
|
||
# 版本发布流程
|
||
git checkout main
|
||
git pull origin main
|
||
git tag v1.2.3
|
||
git push origin v1.2.3
|
||
```
|
||
|
||
**版本号规则**:
|
||
|
||
- **MAJOR**:不兼容的 API 修改
|
||
- **MINOR**:向下兼容的功能性新增
|
||
- **PATCH**:向下兼容的问题修正
|
||
|
||
## 扩展性最佳实践
|
||
|
||
### 1. 微服务拆分
|
||
|
||
**拆分原则**:
|
||
|
||
- 按业务边界拆分
|
||
- 保持服务自治
|
||
- 数据库分离
|
||
- 独立部署
|
||
|
||
### 2. 事件驱动架构
|
||
|
||
```go
|
||
// 事件发布
|
||
type EventBus interface {
|
||
Publish(ctx context.Context, event Event) error
|
||
Subscribe(eventType string, handler EventHandler) error
|
||
}
|
||
|
||
// 事件处理
|
||
func (h *UserEventHandler) HandleUserCreated(ctx context.Context, event *UserCreatedEvent) error {
|
||
// 发送欢迎邮件
|
||
return h.emailService.SendWelcomeEmail(ctx, event.UserID)
|
||
}
|
||
```
|
||
|
||
### 3. 配置外部化
|
||
|
||
```go
|
||
// 配置热重载
|
||
type ConfigManager struct {
|
||
config *Config
|
||
watchers []ConfigWatcher
|
||
}
|
||
|
||
func (cm *ConfigManager) Watch() {
|
||
for {
|
||
if changed := cm.checkConfigChange(); changed {
|
||
cm.reloadConfig()
|
||
cm.notifyWatchers()
|
||
}
|
||
time.Sleep(time.Second * 10)
|
||
}
|
||
}
|
||
```
|
||
|
||
### 4. 服务治理
|
||
|
||
- **服务注册与发现**
|
||
- **负载均衡**
|
||
- **熔断器**
|
||
- **限流器**
|
||
- **链路追踪**
|
||
|
||
通过遵循这些最佳实践,可以确保 TYAPI Server 项目的高质量、高性能和高可维护性。
|