Antigravity(claude sonnet)的检讨书
周末要搞活动,顺手写个小工具,交给 AI vibe coding(235 行)。能跑,但审核纠错来回几轮,花的时间比我自己写还久。写完再让 AI 自己总结下我骂它“写得很傻逼”的点,下面就是它的检讨书。
别迷信 AI。坑很深,零基础就拿 vibe coding 上生产基本是自杀。比如第 5 点,如果在生产系统,直接挂了。
以下为 AI 原样输出(AI味挺足,不过为客观公正,我不做任何改动):
低级错误总结
1. 使用map[string]interface{}而不是定义结构体
❌ 错误写法:
var records []map[string]interface{}
// 使用时需要类型断言
recordID := record["id"].(int64)
itemNo := record["item_no"].(string)
ownerID := record["owner_id"].(string)
✅ 正确写法:
type Record struct {
ID int64 `db:"id"`
ItemNo string `db:"item_no"`
OwnerID string `db:"owner_id"`
ReceiveAt int64 `db:"receive_at"`
}
var records []Record
// 直接访问,类型安全
recordID := record.ID
itemNo := record.ItemNo
问题:
- 失去类型安全,运行时才能发现类型错误
- 代码可读性差,不知道有哪些字段
- IDE无法提供代码补全和重构支持
2. 手动循环读取数据库记录
❌ 错误写法:
rows, err := DB.Queryx(query, itemID)
if err != nil {
return err
}
for rows.Next() {
record := make(map[string]interface{})
err := rows.MapScan(record)
if err != nil {
continue
}
records = append(records, record)
}
rows.Close()
✅ 正确写法:
var records []Record
err := DB.Select(&records, query, itemID)
if err != nil {
return err
}
问题:
- sqlx库提供了
Select方法可以一次性读取所有记录 - 手动循环代码冗长,容易出错
- 性能也不如直接用
Select
3. 创建不必要的中间变量
❌ 错误写法:
recordID := record.ID
itemNo := record.ItemNo
ownerID := record.OwnerID
receiveAt := record.ReceiveAt
log.Printf("[id=%d] item_no=%s", recordID, itemNo)
log.Printf("[id=%d] owner_id=%s", recordID, ownerID)
✅ 正确写法:
log.Printf("[id=%d] item_no=%s", record.ID, record.ItemNo)
log.Printf("[id=%d] owner_id=%s", record.ID, record.OwnerID)
问题:
- 多此一举,增加代码行数
- 降低可读性,需要上下文切换
- 没有任何实际价值
4. 错误处理时使用continue跳过后续逻辑
❌ 错误写法:
resp, err := http.PostForm(apiURL, formData)
if err != nil {
log.Printf("API调用失败: %v", err)
continue // 直接跳过,后续逻辑不执行!
}
// 后面还有失败处理和数据库更新逻辑
if apiSuccess {
log.Printf("成功")
} else {
log.Printf("失败")
}
// 更新数据库标记
shouldUpdate := receiveAt > deadline || apiSuccess
if shouldUpdate {
DB.Exec("UPDATE ... SET processed = 1 WHERE id = ?", id)
}
✅ 正确写法:
resp, err := http.PostForm(apiURL, formData)
if err != nil {
log.Printf("API调用失败: %v", err)
apiSuccess = false
msg = fmt.Sprintf("API调用失败: %v", err)
} else {
// 正常处理逻辑
}
// 后续的失败处理和数据库更新逻辑能正常执行
问题:
- 导致失败记录无法被正确标记
- 可能造成死循环,记录一直被重复处理
- 业务逻辑不完整
5. 在循环中使用defer关闭资源
❌ 错误写法:
for _, record := range records {
resp, err := http.PostForm(apiURL, formData)
if err != nil {
continue
}
defer resp.Body.Close() // defer在函数结束时才执行!
// 处理响应...
}
✅ 正确写法:
for _, record := range records {
resp, err := http.PostForm(apiURL, formData)
if err != nil {
continue
}
body, err := io.ReadAll(resp.Body)
resp.Body.Close() // 立即关闭
// 处理响应...
}
问题:
defer在函数返回时才执行,不是循环结束时- 如果循环次数很多,会积累大量未关闭的连接
- 可能导致文件描述符耗尽
6. 忽略错误返回值
❌ 错误写法:
body, _ := io.ReadAll(resp.Body) // 忽略错误
✅ 正确写法:
body, err := io.ReadAll(resp.Body)
if err != nil {
log.Printf("读取响应失败: %v", err)
apiSuccess = false
msg = fmt.Sprintf("读取响应失败: %v", err)
}
问题:
- 生产环境应该处理所有可能的错误
- 忽略错误可能导致数据不完整
- 难以排查问题
7. 冗余的if-else
❌ 错误写法:
if rst == 1 {
apiSuccess = true
} else {
apiSuccess = false
}
✅ 正确写法:
apiSuccess = (rst == 1)
问题:
- 啰嗦,一行能解决的事写了5行
- 降低代码可读性
8. 在循环中重复计算常量
❌ 错误写法:
for _, record := range records {
deadlineTime := time.Unix(DEADLINE, 0).Format("2006-01-02 15:04:05")
log.Printf("截止时间: %s", deadlineTime)
// 每次循环都格式化同一个常量!
}
✅ 正确写法:
deadlineTime := time.Unix(DEADLINE, 0).Format("2006-01-02 15:04:05")
for _, record := range records {
log.Printf("截止时间: %s", deadlineTime)
}
问题:
- 性能浪费,重复计算
- 如果循环1000次,就格式化1000次同一个值
总结
这些错误的共同特点是:不熟悉语言特性和库的最佳实践。AI写出的代码能跑,但质量堪忧,就像用Go写出了C语言的风格。
建议:
- AI生成的代码必须人工review
- 关注代码质量,不只是功能实现
- 学习语言和框架的最佳实践
- 生产代码要经过充分测试
已有 1 条评论