经验教训概述
在辣评项目三年多的开发历程中,我们积累了大量的经验和教训。本文总结了技术选型、架构设计、团队协作、测试策略和文档维护等方面的经验,希望能为类似项目提供参考。
技术选型建议
成功的选择
1. Go 语言作为后端
优势:
- 高性能和并发能力满足需求
- 编译为单一二进制文件,部署简单
- 标准库完善,第三方库生态良好
- 静态类型减少运行时错误
经验:
// Go 的并发特性让我们轻松处理高并发场景
func ProcessComments(comments []Comment) {
var wg sync.WaitGroup
semaphore := make(chan struct{}, 10) // 限制并发数
for _, comment := range comments {
wg.Add(1)
go func(c Comment) {
defer wg.Done()
semaphore <- struct{}{}
defer func() { <-semaphore }()
processComment(c)
}(comment)
}
wg.Wait()
}
教训:
- 初期对 goroutine 泄漏问题认识不足,导致内存占用过高
- 解决方案:使用 context 控制 goroutine 生命周期,添加超时机制
2. Vue 3 + Vite 作为前端
优势:
- Composition API 提供更好的代码组织
- Vite 开发体验极佳,热更新快速
- TypeScript 支持良好
- Element Plus 组件库完善
经验:
<!-- Composition API 让代码更易维护 -->
<script setup>
import { ref, computed, onMounted } from 'vue'
import { useAuthStore } from '@/stores/auth'
// 逻辑清晰,易于复用
const authStore = useAuthStore()
const isAdmin = computed(() => authStore.hasRole('admin'))
onMounted(() => {
loadData()
})
</script>
教训:
- 初期过度使用 Composition API,导致组件过于复杂
- 解决方案:合理拆分组件,提取可复用的 composables
3. SQLite 作为数据库
优势:
- 轻量级,无需独立数据库服务
- 部署简单,适合中小型项目
- 性能足够满足需求
- 备份简单(单文件)
教训:
- 并发写入性能有限
- 解决方案:使用连接池,优化写入策略,考虑读写分离
需要改进的选择
1. 微信机器人作为初期架构
问题:
- 依赖第三方平台,稳定性受限
- 交互方式受限,用户体验不佳
- 功能扩展困难
教训:
- 应该更早地规划 Web 平台架构
- 微信机器人可以作为辅助入口,但不应作为主要架构
2. 前端状态管理
问题:
- 初期使用 Vuex,迁移到 Pinia 花费了不少时间
- 状态管理过于分散,难以维护
教训:
- 应该从一开始就使用 Pinia(Vue 3 官方推荐)
- 合理规划状态结构,避免过度使用全局状态
架构设计心得
成功的设计
1. 前后端分离
优势:
- 前后端可以独立开发和部署
- 便于团队协作
- 技术栈选择更灵活
经验:
前端(Vue 3)→ REST API → 后端(Go)→ 数据库(SQLite)
最佳实践:
- 定义清晰的 API 接口规范
- 使用 TypeScript 类型定义增强类型安全
- 前后端使用相同的数据模型定义
2. 分层架构
架构层次:
表现层(Handlers)→ 业务层(Services)→ 数据层(Models/Database)
优势:
- 职责清晰,易于维护
- 便于单元测试
- 易于替换实现
示例:
// Handler 层:处理 HTTP 请求
func (h *CommentHandler) CreateComment(c *gin.Context) {
var req CreateCommentRequest
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(400, gin.H{"error": err.Error()})
return
}
// 调用 Service 层
comment, err := h.commentService.CreateComment(c, &req)
if err != nil {
c.JSON(500, gin.H{"error": err.Error()})
return
}
c.JSON(200, comment)
}
// Service 层:业务逻辑
func (s *CommentService) CreateComment(ctx context.Context, req *CreateCommentRequest) (*Comment, error) {
// 验证业务规则
if err := s.validateComment(req); err != nil {
return nil, err
}
// 调用 Data 层
comment := &Comment{
UserID: req.UserID,
SubmissionID: req.SubmissionID,
Content: req.Content,
}
if err := s.db.Create(comment).Error; err != nil {
return nil, err
}
return comment, nil
}
3. 配置化管理
优势:
- 便于环境切换
- 敏感信息集中管理
- 便于定制化
最佳实践:
// config.json
{
"environment": "production",
"apiPort": 8888,
"database": {
"type": "sqlite",
"path": "./data/laping.db"
},
"jwt": {
"secret": "your-secret",
"expireHours": 24
},
"system": {
"name": "辣评",
"logo": "/assets/logo.svg"
}
}
需要改进的设计
1. 缓存策略
问题:
- 初期没有考虑缓存,导致重复查询
- 后期添加缓存时改动较大
教训:
- 应该在设计初期就考虑缓存策略
- 对于频繁查询的数据(如配置、统计数据)应该使用缓存
改进方案:
// 使用内存缓存
type CacheService struct {
cache map[string]interface{}
mutex sync.RWMutex
ttl time.Duration
}
func (s *CacheService) Get(key string) (interface{}, bool) {
s.mutex.RLock()
defer s.mutex.RUnlock()
value, ok := s.cache[key]
return value, ok
}
func (s *CacheService) Set(key string, value interface{}) {
s.mutex.Lock()
defer s.mutex.Unlock()
s.cache[key] = value
}
2. 错误处理
问题:
- 初期错误处理不统一
- 错误信息对用户不友好
- 缺少错误码规范
教训:
- 应该定义统一的错误处理机制
- 区分系统错误和业务错误
- 提供友好的错误提示
改进方案:
// 定义错误码
const (
ErrCodeSuccess = 0
ErrCodeInvalidParam = 400
ErrCodeUnauthorized = 401
ErrCodeForbidden = 403
ErrCodeNotFound = 404
ErrCodeInternalError = 500
ErrCodeDuplicateSubmit = 1001
)
// 统一错误响应
type ErrorResponse struct {
Code int `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
func HandleError(c *gin.Context, err error) {
var resp ErrorResponse
switch e := err.(type) {
case *BusinessError:
resp = ErrorResponse{
Code: e.Code,
Message: e.Message,
}
default:
resp = ErrorResponse{
Code: ErrCodeInternalError,
Message: "服务器内部错误",
}
log.Printf("Internal error: %v", err)
}
c.JSON(resp.Code, resp)
}
团队协作经验
成功的实践
1. Git 工作流
分支策略:
master (生产环境)
↑
dev (开发环境)
↑
feature/* (功能分支)
最佳实践:
- 功能开发在 feature 分支
- 完成后合并到 dev 测试
- 测试通过后合并到 master 发布
2. 代码审查
流程:
- 提交 Pull Request
- 团队成员审查代码
- 讨论和修改
- 审查通过后合并
收益:
- 提高代码质量
- 知识共享
- 发现潜在问题
3. 文档先行
实践:
- API 设计先写文档
- 功能开发前写设计文档
- 重要决策记录在文档中
收益:
- 减少沟通成本
- 便于后期维护
- 新成员快速上手
需要改进的地方
1. 沟通效率
问题:
- 初期沟通主要依赖微信,信息容易丢失
- 缺少正式的需求评审流程
改进:
- 使用专业的项目管理工具
- 建立定期的需求评审会议
- 重要决策记录在文档中
2. 任务管理
问题:
- 任务分配不够明确
- 进度跟踪不够及时
改进:
- 使用看板管理任务
- 每日站会同步进度
- 定期回顾和总结
测试策略
成功的实践
1. 单元测试
覆盖范围:
- 核心业务逻辑
- 工具函数
- 数据模型
示例:
func TestCalculatePoints(t *testing.T) {
tests := []struct {
name string
comments []Comment
want int
}{
{
name: "高质量评论",
comments: []Comment{
{Score: 5},
{Score: 5},
{Score: 4},
},
want: 28, // 3 + 5*3 + 10
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := CalculatePoints(tt.comments)
if got != tt.want {
t.Errorf("got %d, want %d", got, tt.want)
}
})
}
}
2. 集成测试
测试场景:
- API 接口测试
- 数据库操作测试
- 权限验证测试
工具:
- Go: httptest
- 前端: Vitest
需要改进的地方
1. 测试覆盖率
问题:
- 初期测试覆盖率较低
- 部分关键功能缺少测试
改进:
- 设定测试覆盖率目标(如 80%)
- 新功能必须包含测试
- 定期检查测试覆盖率
2. E2E 测试
问题:
- 缺少端到端测试
- 用户流程测试不足
改进:
- 使用 Playwright 或 Cypress
- 测试关键用户流程
- 自动化回归测试
文档维护建议
成功的实践
1. 代码注释
原则:
- 复杂逻辑必须注释
- 公共 API 必须注释
- 注释说明”为什么”而不是”是什么”
示例:
// CalculatePoints 计算用户积分
// 积分规则:
// - 每条评论 1 分
// - 评分 >= 4 的评论额外 5 分
// - 平均评分 >= 4.5 额外 10 分
func CalculatePoints(comments []Comment) int {
points := len(comments) // 基础分
var totalScore int
for _, comment := range comments {
totalScore += comment.Score
if comment.Score >= 4 {
points += 5 // 高质量评论奖励
}
}
avgScore := float64(totalScore) / float64(len(comments))
if avgScore >= 4.5 {
points += 10 // 高平均分奖励
}
return points
}
2. API 文档
工具:
- Swagger/OpenAPI
- Postman Collection
内容:
- 接口路径和方法
- 请求参数
- 响应格式
- 错误码说明
3. 开发文档
包含内容:
- 项目架构说明
- 开发环境搭建
- 编码规范
- 部署流程
需要改进的地方
1. 文档更新
问题:
- 代码更新后文档未及时更新
- 文档与实际代码不一致
改进:
- 代码变更时同步更新文档
- 定期审查文档准确性
- 使用工具自动生成文档
2. 知识沉淀
问题:
- 开发经验未及时记录
- 问题解决方案容易遗忘
改进:
- 建立知识库
- 记录常见问题和解决方案
- 定期分享经验
总结
关键经验
- 技术选型
- 选择成熟稳定的技术栈
- 考虑团队技术储备
- 评估长期维护成本
- 架构设计
- 分层架构,职责清晰
- 配置化管理,便于定制
- 预留扩展空间
- 团队协作
- 规范的工作流程
- 充分的沟通交流
- 及时的代码审查
- 质量保证
- 完善的测试覆盖
- 统一的错误处理
- 详细的日志记录
- 文档维护
- 代码即文档
- 及时更新文档
- 知识持续沉淀
持续改进
- 定期回顾和总结
- 学习新技术和最佳实践
- 优化开发流程
- 提升代码质量
- 改善用户体验
这些经验教训是辣评项目宝贵的财富,也是我们持续进步的动力。希望这些总结能够帮助到其他开发者,也期待在未来的开发中继续积累和分享经验。