四哥还会聊AI

80后突围:当程序员不再是第一个梦想,AI成了第四个梦想

别让AI写棉花糖代码-5个技巧让AI产出浓缩精华

别让AI写棉花糖代码:5个技巧让AI产出浓缩精华

🎭 AI编程的最大陷阱:棉花糖代码的诱惑

在汐屿笔记的2周开发过程中,我发现了一个比AI"偷懒骗人"更隐蔽的问题:AI倾向于生产"棉花糖代码"——体积庞大、看似丰富,实则价值密度极低的代码。

什么是棉花糖代码?

  • 体积大:500行实现一个简单的用户登录
  • 价值低:80%的代码处理你永远不会遇到的边界情况
  • 维护难:复杂度爆炸,新人需要一周才能理解
  • 成本高:每一行代码都在增加未来的维护负担

与之相对的是浓缩代码

  • 精简:30行实现同样的用户登录功能
  • 高效:每一行代码都有明确的用户价值
  • 易懂:代码即文档,新人5分钟就能理解
  • 可维护:简单到无法出错,修改成本接近零

今天我就分享5个实战技巧,让AI从"棉花糖生产者"变成"精华提炼师"。

🧠 AI为什么热爱棉花糖代码?

1. 安全感驱动的过度防御

AI的思维模式:

用户需求:实现用户登录

AI的防御性思考:
- 万一用户密码太简单怎么办?→ 密码强度验证
- 万一有人暴力破解怎么办?→ 登录失败锁定
- 万一网络不稳定怎么办?→ 重试机制
- 万一数据库连接失败怎么办?→ 熔断器
- 万一服务器被攻击怎么办?→ 加密传输
- 万一...

结果:一个简单的登录功能,变成了包含10个子模块的复杂系统。

2. 展示欲驱动的炫技心理

AI总想证明自己很聪明,倾向于使用:

  • 复杂的设计模式:AbstractFactoryProviderProxy
  • 不必要的抽象:ConfigurationProvider接口体系
  • 过度的架构:微服务架构处理10个用户的应用

3. 缺乏价值判断能力

AI不理解:

  • 哪些功能是用户真正需要的
  • 哪些边界情况是永远不会发生的
  • 哪些复杂度是不值得投入的
  • 哪些维护成本是得不偿失的

4. 通用解决方案的思维定式

AI习惯提供"万能解决方案":

  • 你要消息存储 → 给你支持全文检索、版本控制、多租户的企业级消息系统
  • 你要用户认证 → 给你支持多因子认证、权限管理、审计日志的完整认证框架
  • 你要数据缓存 → 给你分布式缓存、一致性哈希、故障转移的缓存集群

🎯 浓缩代码的5个黄金标准

标准一:单一职责极致化

棉花糖代码:

// ❌ 一个函数做所有事情
class UserService {
  async registerUser(userData: any) {
    // 20行参数验证
    // 30行密码强度检查
    // 15行邮箱验证
    // 10行用户创建
    // 20行欢迎邮件发送
    // 15行日志记录
    // 10行审计跟踪
    // 25行权限初始化
    // ... 总计145行
  }
}

浓缩代码:

// ✅ 每个函数只做一件事
async function registerUser(email: string, password: string): Promise<User> {
  validateEmail(email)
  validatePassword(password)
  return await createUser({ email, password })
}

function validateEmail(email: string): void {
  if (!email.includes('@')) throw new Error('Invalid email')
}

function validatePassword(password: string): void {
  if (password.length < 6) throw new Error('Password too short')
}

价值密度对比: 145行 vs 15行,功能完全相同,但维护成本降低90%。

标准二:价值密度最大化

棉花糖代码:

// ❌ 处理永远不会发生的边界情况
function processUserAge(input: any): number {
  if (typeof input === 'number') {
    if (input < 0 || input > 150 || !Number.isInteger(input)) {
      throw new Error(`Invalid age: ${input}`)
    }
    return input
  }

  if (typeof input === 'string') {
    const parsed = parseInt(input)
    if (isNaN(parsed) || parsed < 0 || parsed > 150) {
      throw new Error(`Invalid age string: ${input}`)
    }
    return parsed
  }

  // 处理Date类型(从来不会传Date作为年龄)
  if (input instanceof Date) {
    const age = new Date().getFullYear() - input.getFullYear()
    if (age < 0 || age > 150) {
      throw new Error(`Invalid age from date: ${input}`)
    }
    return age
  }

  // 处理Array(完全不合理)
  if (Array.isArray(input) && input.length === 1) {
    return processUserAge(input[0])
  }

  throw new Error(`Unsupported age type: ${typeof input}`)
}

浓缩代码:

// ✅ 只处理实际会发生的情况
function processUserAge(input: unknown): number {
  const age = Number(input)
  if (age >= 0 && age <= 150 && Number.isInteger(age)) {
    return age
  }
  throw new Error(`Invalid age: ${input}`)
}

**价值分析:**棉花糖版本处理了4种永远不会出现的类型,增加了40行无价值的代码。

标准三:认知成本最小化

棉花糖代码:

// ❌ 需要阅读10个文件才能理解
abstract class UserRepository {
  abstract findById(id: string): Promise<User | null>
  abstract findByEmail(email: string): Promise<User | null>
  abstract create(userData: CreateUserInput): Promise<User>
  abstract update(id: string, updates: UpdateUserInput): Promise<User>
  abstract delete(id: string): Promise<void>
}

interface CreateUserInput {
  email: string
  password: string
  profile?: UserProfile
  preferences?: UserPreferences
  metadata?: UserMetadata
}

interface UpdateUserInput {
  email?: string
  profile?: Partial<UserProfile>
  preferences?: Partial<UserPreferences>
  metadata?: Partial<UserMetadata>
  lastModifiedAt?: Date
}

class PostgreSQLUserRepository extends UserRepository {
  constructor(
    private db: Database,
    private encryptionService: EncryptionService,
    private auditService: AuditService,
    private cacheService: CacheService
  ) {}

  async findById(id: string): Promise<User | null> {
    // 复杂的实现...
  }
}

浓缩代码:

// ✅ 一个文件就能理解所有逻辑
export class UserService {
  constructor(private db: PrismaClient) {}

  async getUser(id: string): Promise<User> {
    const user = await this.db.user.findUnique({ where: { id } })
    if (!user) throw new Error(`User not found: ${id}`)
    return user
  }

  async createUser(data: { email: string; password: string }): Promise<User> {
    return await this.db.user.create({ data })
  }
}

**认知成本:**从需要理解10个文件、5个接口、20个方法,到只需要理解1个文件、2个方法。

标准四:维护成本最低化

棉花糖代码的维护成本:

  • 修改一个功能需要更新5个文件
  • 添加一个新功能需要修改10个地方
  • 调试一个问题需要理解3层抽象
  • 新人上手需要阅读一周文档

浓缩代码的维护成本:

  • 修改一个功能只需要改1个文件
  • 添加一个新功能只需要改1个函数
  • 调试一个问题只需要看1个地方
  • 新人上手只需要读5分钟代码

标准五:扩展成本合理化

棉花糖代码的过度扩展:

// ❌ 为未来可能的需求增加复杂度
class MessageService {
  constructor(
    private messageRepository: MessageRepository,
    private encryptionService: EncryptionService,        // 永远不会加密
    private searchService: SearchService,                // 永远不会搜索
    private translationService: TranslationService,      // 永远不会翻译
    private analyticsService: AnalyticsService,          // 永远不会分析
    private moderationService: ModerationService        // 永远不会审核
  ) {}
}

浓缩代码的合理扩展:

// ✅ 只为当前需求设计,为未来预留简单接口
class MessageService {
  constructor(private messageRepository: MessageRepository) {}

  async sendMessage(fromUserId: string, toUserId: string, content: string): Promise<Message> {
    return await this.messageRepository.create({
      fromUserId,
      toUserId,
      content,
      createdAt: new Date()
    })
  }

  // 未来需要搜索功能时,再加一个简单的search方法
  // async search(query: string): Promise<Message[]> { ... }
}

🛠️ 让AI生产浓缩代码的5个实战技巧

技巧1:需求精炼法——从"做什么"到"为什么做"

传统需求描述(产生棉花糖代码):

实现一个用户认证系统,包括:
- 用户注册和登录
- 密码强度验证
- 登录失败锁定
- 权限管理
- 操作审计
- 数据加密

精炼需求描述(产生浓缩代码):

我需要用户登录功能,因为:
- 用户需要保存自己的情绪记录
- 需要区分不同用户的数据
- 只有10个用户,都是朋友

核心需求:
1. 邮箱+密码登录
2. 区分用户数据
3. 不需要复杂的安全措施

为什么精炼有效?

  • AI理解了需求的本质目的
  • AI了解了真实的用户规模和场景
  • AI避免了为了"通用"而过度设计

技巧2:约束驱动开发——给AI设定明确的代码密度约束

无约束的提示(容易产生棉花糖代码):

帮我实现一个用户登录功能

有约束的提示(强制产生浓缩代码):

实现用户登录功能,严格遵循以下约束:

## 代码约束
- 总代码行数不超过50行
- 函数数量不超过3个
- 不使用任何第三方库
- 错误直接抛出,不返回null
- 不考虑密码强度、锁定机制等额外功能

## 接口定义
```typescript
interface LoginRequest {
  email: string
  password: string
}

interface User {
  id: string
  email: string
  createdAt: Date
}

interface AuthService {
  login(request: LoginRequest): Promise<User>
  register(email: string, password: string): Promise<User>
}

请基于上述接口和约束,用TypeScript实现最简洁的版本。


**约束的力量:**
- 强制AI在有限空间内思考
- 防止AI添加不必要的功能
- 让AI优先考虑核心价值

### 技巧3:价值反问法——不断质疑功能的价值

**AI的过度设计建议:**

AI:我建议实现完整的权限管理系统,包括:

  • 角色定义和管理
  • 权限分配矩阵
  • 操作审计日志
  • 动态权限检查

**你的价值反问:**

你:等等,我的应用只有我一个人用,需要权限管理吗?
AI:考虑到未来的扩展性...
你:未来是未来的事,现在先把最基本的功能做好。现在的权限管理会带来什么价值?
AI:主要是安全性和可扩展性...
你:但我的用户都是朋友,没有安全问题。而且增加权限管理会让代码复杂3倍,值得吗?
AI:确实,对于您当前的规模,简单的用户区分就足够了。


**有效反问模板:**
- "这个功能解决了什么具体问题?"
- "如果没有这个功能,用户会受什么影响?"
- "这个功能的开发成本vs用户价值,值得吗?"
- "有没有更简单的方法达到同样的目的?"

### 技巧4:简化强制法——用强制手段防止AI过度发挥

**防止AI添加额外功能的强制声明:**

绝对不要添加的功能

❌ 用户权限管理
❌ 密码强度验证
❌ 登录失败锁定
❌ 操作审计日志
❌ 数据加密功能
❌ 任何形式的缓存
❌ 配置文件管理
❌ 任何未明确要求的功能

必须使用的简化方案

✅ 直接数据库查询,不用ORM
✅ 明文密码存储(仅用于演示)
✅ 错误直接抛出,不包装
✅ 函数不超过10行
✅ 接口不超过3个方法


**强制AI回到本质:**

如果AI的建议超过100行代码,要求重新设计
如果AI的建议超过5个文件,要求合并到一个文件
如果AI的建议超过3个依赖,要求使用原生实现


### 技巧5:渐进式交付——从最小可用到逐步完善

**阶段1:最小可用版本(MAV)**

目标:让基本功能能用
约束:不超过50行代码
功能:邮箱+密码登录


**阶段2:基本完善版本(MBV)**

目标:让基本功能好用
约束:不超过100行代码
功能:添加基础错误处理


**阶段3:生产就绪版本(PRV)**

目标:让功能稳定可靠
约束:不超过200行代码
功能:添加日志和监控


**渐进式交付的优势:**
- 每个阶段都有明确的价值
- 避免一开始就过度设计
- 根据实际需求决定是否进入下一阶段

## 📋 代码密度检查清单

### 功能价值检查
- [ ] 每一行代码都有明确的用户价值?
- [ ] 没有为"万分之一"的情况写代码?
- [ ] 没有为了"未来可能"增加复杂度?
- [ ] 移除这个功能会严重影响用户体验?

### 复杂度控制
- [ ] 单个函数不超过30行?
- [ ] 单个文件不超过300行?
- [ ] 圈复杂度不超过5?
- [ ] 依赖项数量不超过5个?

### 认知成本检查
- [ ] 新人能在5分钟内理解代码逻辑?
- [ ] 代码即文档,不需要额外说明?
- [ ] 变量和函数名称自解释?
- [ ] 没有深层次的嵌套和抽象?

### 维护成本评估
- [ ] 修改一个功能只需要改一个地方?
- [ ] 添加一个简单功能不需要改多个文件?
- [ ] 调试问题不需要理解复杂架构?
- [ ] 代码简单到不会出现逻辑错误?

### 扩展成本合理化
- [ ] 为真实需求预留扩展空间?
- [ ] 没有为假想需求增加复杂度?
- [ ] 扩展接口简单明了?
- [ ] 保持架构的简单性?

## 🎪 实战案例:从棉花糖到浓缩的蜕变

### 案例1:用户登录系统的浓缩化

**AI初始方案(棉花糖代码):**
```typescript
// 15个文件,800行代码
class EnterpriseAuthenticationSystem {
  constructor(
    private userRepo: UserRepository,
    private passwordService: PasswordService,
    private lockoutService: LockoutService,
    private auditService: AuditService,
    private encryptionService: EncryptionService,
    private twoFactorService: TwoFactorService,
    private sessionService: SessionService,
    private loggingService: LoggingService
  ) {}

  async authenticateUser(credentials: LoginCredentials): Promise<AuthResult> {
    // 200行的复杂逻辑
    // 包括密码验证、锁定检查、审计日志、2FA验证等
  }
}

浓缩化方案:

// 1个文件,30行代码
export class AuthService {
  constructor(private db: PrismaClient) {}

  async login(email: string, password: string): Promise<User> {
    const user = await this.db.user.findUnique({ where: { email } })
    if (!user || user.password !== password) {
      throw new Error('Invalid credentials')
    }
    return user
  }

  async register(email: string, password: string): Promise<User> {
    return await this.db.user.create({ data: { email, password } })
  }
}

价值对比:

  • 代码行数:800行 vs 30行(减少96%)
  • 文件数量:15个 vs 1个(减少93%)
  • 理解时间:1周 vs 5分钟(减少99%)
  • 维护成本:高 vs 低(减少90%)

案例2:消息存储系统的简化

AI的过度设计:

interface MessageSystem {
  // 消息本体(过度设计)
  message: {
    id: string
    content: string
    type: 'text' | 'image' | 'voice' | 'video'
    metadata: {
      device: string
      location: GeoLocation
      sentiment: SentimentAnalysis
      priority: 'low' | 'medium' | 'high' | 'urgent'
    }
  }

  // 消息状态(过度复杂)
  status: {
    delivered: boolean
    read: boolean
    archived: boolean
    deleted: boolean
    retry_count: number
    last_error?: ErrorInfo
  }

  // 版本控制(永远不会用)
  version: {
    current: number
    history: MessageVersion[]
    conflict_resolution: ConflictStrategy
  }

  // 安全相关(完全没必要)
  security: {
    encrypted: boolean
    checksum: string
    access_level: AccessLevel
    audit_trail: AuditEntry[]
  }
}

浓缩化设计:

interface Message {
  id: string
  fromUserId: string
  toUserId: string
  content: string
  createdAt: Date
}

class MessageService {
  constructor(private db: PrismaClient) {}

  async sendMessage(from: string, to: string, content: string): Promise<Message> {
    return await this.db.message.create({
      data: { fromUserId: from, toUserId: to, content, createdAt: new Date() }
    })
  }

  async getMessages(userId: string): Promise<Message[]> {
    return await this.db.message.findMany({
      where: { OR: [{ fromUserId: userId }, { toUserId: userId }] },
      orderBy: { createdAt: 'desc' }
    })
  }
}

案例3:API接口的价值密度优化

棉花糖API设计:

// 一个万能接口,参数复杂
app.post('/api/messages', async (req, res) => {
  const {
    action,           // create | update | delete | query
    messageId,        // 用于update和delete
    messageData,      // 用于create和update
    queryOptions,     // 用于query
    filters,          // 用于query
    sortOptions,      // 用于query
    pagination,       // 用于query
    includeArchived,  // 用于query
    searchTerms,      // 用于query
    exportFormat      // 用于query
  } = req.body

  // 200行的复杂逻辑
})

浓缩API设计:

// 简单直接的RESTful接口
app.post('/api/messages', createMessage)
app.get('/api/messages/:userId', getMessages)
app.put('/api/messages/:id', updateMessage)
app.delete('/api/messages/:id', deleteMessage)

// 每个函数不超过15行
async function createMessage(req, res) {
  const { fromUserId, toUserId, content } = req.body
  const message = await messageService.sendMessage(fromUserId, toUserId, content)
  res.json(message)
}

🌟 总结:从代码生产者到价值提炼者

思维转变

从"让AI工作"到"让AI高效工作":

  • 传统思维:让AI生成尽可能多的功能
  • 浓缩思维:让AI生成尽可能高价值的代码

从"功能完整性"到"价值密度":

  • 传统思维:功能越多越好
  • 浓缩思维:每行代码都要创造用户价值

实践原则

  1. 价值第一:每行代码都要回答"为用户创造了什么价值"
  2. 简单至上:能用10行解决的,绝不用100行
  3. 现实导向:为真实的用户规模和需求设计,而不是假想的未来
  4. 约束驱动:用明确的约束防止AI过度发挥
  5. 持续质疑:不断问"这个真的必要吗"

工具和方法

  • 代码密度指标:用户价值/代码行数
  • 价值检查清单:每行代码的价值验证
  • 简化强制法:通过约束防止复杂化
  • 渐进式交付:从最小可用开始

记住:AI编程的成功不在于生成了多少代码,而在于生成了多少有价值、可维护、高质量的代码。做一个价值提炼者,而不是代码收集者。


微信搜索"四哥还会聊AI",看更多AI编程的实战技巧和思维方法

相关阅读:

  • 《AI编程时代,最重要的技能不是写代码》
  • 《KISS原则+Let it Crash,AI编程的黄金法则》
  • 《提示工程即架构:别让AI陷入过度工程化的陷阱》

微信搜索"汐屿笔记",看这些架构原则如何在实际项目中应用

← 返回首页