四哥还会聊AI

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

第3篇-KISS原则+Let it Crash,AI编程的黄金法则

KISS原则+Let it Crash,AI编程的黄金法则

🎪 AI编程最大的陷阱:复杂化诱惑

AI有一个天生的毛病:喜欢炫技。当你给它一个简单需求时,它总会想方设法展示自己的"才华",把简单问题复杂化。

在汐屿笔记开发中,我发现KISS原则Let it Crash是约束AI、保持代码简洁的两个最有效法则。

今天我就告诉你如何在AI编程中应用这两个黄金法则。

🎯 KISS原则:简单是终极的复杂

KISS是什么?

KISS = Keep It Simple, Stupid

  • 保持简单,别耍小聪明
  • 能用1行代码解决的,绝不用10行
  • 能用简单方案的,绝不用复杂方案

AI为什么违反KISS原则?

1. 展示欲作祟
AI想证明自己很聪明,所以倾向于使用复杂的技术方案。

2. 过度安全考虑
AI会预想各种边界情况和未来需求,导致过度设计。

3. 缺乏上下文
AI不知道你的真实业务场景和用户规模,只能给出"通用"的复杂方案。

汐屿笔记的KISS实践

原则1:单文件1500行限制

// ❌ AI可能生成的复杂代码
class AbstractFactoryProviderProxy {
  private decoratorChain: DecoratorPattern[]
  private middlewareStack: MiddlewareComposite[]
  private configurationManager: ConfigurationManager
  private dependencyInjector: DependencyInjector

  constructor() {
    // 200行复杂的初始化逻辑
  }

  public createProvider<T>(type: ProviderType): Promise<T> {
    // 复杂的工厂模式实现
    // 包含多层抽象和间接调用
  }
}

// ✅ 简单直接的实现
function createUser(userData: UserData): Promise<User> {
  return prisma.user.create({ data: userData })
}

原则2:单一职责原则

// ❌ AI可能会写的"万能函数"
async function processUserAction(data: any) {
  // 验证用户
  // 处理数据
  // 发送通知
  // 记录日志
  // 更新统计
  // 清理缓存
  // ... 100行代码
}

// ✅ 每个函数只做一件事
async function validateUser(data: UserData): Promise<User> {
  return await userValidator.validate(data)
}

async function saveUserData(data: UserData): Promise<User> {
  return await userRepository.save(data)
}

async function sendNotification(user: User): Promise<void> {
  return await notificationService.send(user)
}

原则3:避免过度抽象

// ❌ 过度抽象的配置管理
interface ConfigurationProvider {
  getValue<T>(key: string): T
  setValue<T>(key: string, value: T): void
  hasKey(key: string): boolean
  clear(): void
  reload(): Promise<void>
}

class EnvironmentConfigurationProvider implements ConfigurationProvider {
  // 复杂的实现
}

class DatabaseConfigurationProvider implements ConfigurationProvider {
  // 复杂的实现
}

// ✅ 简单的配置对象
const config = {
  apiUrl: process.env.API_URL || 'http://localhost:3001',
  databaseUrl: process.env.DATABASE_URL,
  jwtSecret: process.env.JWT_SECRET,
}

export function getConfig(key: keyof typeof config) {
  return config[key]
}

💥 Let it Crash:让错误尽早暴露

Let it Crash是什么?

Let it Crash = 让程序崩溃吧

  • 遇到无法处理的错误,直接崩溃
  • 不要试图掩盖错误或提供降级方案
  • 崩溃是最好的错误提示,因为它能暴露问题的根源

传统错误处理的误区

❌ 传统的"防御式编程":

async function getUser(id: string): Promise<User | null> {
  try {
    const user = await prisma.user.findUnique({ where: { id } })
    if (!user) {
      logger.warn(`User not found: ${id}`)
      return null
    }
    return user
  } catch (error) {
    logger.error(`Error fetching user: ${error.message}`)
    return null
  }
}

// 调用方需要处理null
const user = await getUser(userId)
if (user) {
  // 处理用户
} else {
  // 处理null,但不知道为什么是null
}

问题:

  • 调用方不知道为什么返回null
  • 错误被掩盖,难以调试
  • 业务逻辑变得复杂

✅ Let it Crash的写法:

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

// 调用方直接使用,出错就让程序崩溃
const user = await getUser(userId) // 如果出错,程序崩溃,立即暴露问题
// 处理用户,无需检查null

Let it Crash在AI编程中的应用

1. 输入验证:拒绝无效数据

// ❌ AI可能会写的"宽容"验证
function parseAge(input: any): number {
  if (typeof input === 'number') return input
  if (typeof input === 'string') {
    const parsed = parseInt(input)
    if (!isNaN(parsed)) return parsed
  }
  return 0 // 默认值,掩盖了问题

// ✅ 严格验证,不行就崩溃
function parseAge(input: unknown): number {
  if (typeof input === 'number' && input >= 0 && input <= 150) {
    return input
  }
  throw new Error(`Invalid age: ${input}`)
}

2. 环境配置:缺少必需配置就崩溃

// ❌ 过度容错
const dbUrl = process.env.DATABASE_URL || 'sqlite://default.db'
const jwtSecret = process.env.JWT_SECRET || 'default-secret'

// ✅ 缺少必需配置就崩溃
if (!process.env.DATABASE_URL) {
  throw new Error('DATABASE_URL is required')
}
if (!process.env.JWT_SECRET) {
  throw new Error('JWT_SECRET is required')
}

3. API调用:失败就失败,不要降级

// ❌ AI可能会写的复杂重试逻辑
async function callAPI(url: string): Promise<any> {
  try {
    const response = await fetch(url)
    return await response.json()
  } catch (error) {
    // 重试1次
    try {
      const response = await fetch(url)
      return await response.json()
    } catch (retryError) {
      // 返回空数据
      return {}
    }
  }
}

// ✅ 简单直接,失败就崩溃
async function callAPI(url: string): Promise<any> {
  const response = await fetch(url)
  if (!response.ok) {
    throw new Error(`API call failed: ${response.status}`)
  }
  return await response.json()
}

🛡️ 类型安全:避免AI错误的最有效方法

虽然AI很强大,但它在类型推断上容易犯错。使用类型安全语言是约束AI的有效方法。

TypeScript在汐屿笔记中的应用

1. 清晰的数据类型定义

interface UserSession {
  id: string
  userId: string
  status: 'active' | 'completed' | 'paused'
  createdAt: Date
  updatedAt: Date
}

interface CreateSessionData {
  userId: string
  initialMood?: 'happy' | 'sad' | 'neutral'
  notes?: string
}

2. API响应类型约束

type ApiResponse<T> = {
  success: boolean
  data?: T
  error?: {
    code: string
    message: string
  }
}

// 使用示例
async function createSession(data: CreateSessionData): Promise<ApiResponse<UserSession>> {
  try {
    const session = await sessionRepository.create(data)
    return { success: true, data: session }
  } catch (error) {
    return {
      success: false,
      error: {
        code: 'SESSION_CREATE_FAILED',
        message: error.message
      }
    }
  }
}

3. 避免any类型

// ❌ AI可能会用any
function processUserData(data: any): any {
  // 不安全的处理
}

// ✅ 明确类型定义
interface UserData {
  name: string
  email: string
  age: number
}

function processUserData(data: UserData): ProcessedData {
  // 类型安全的处理
}

📋 Claude.md:项目的灵魂文档

为什么Claude.md如此重要?

Claude.md是AI编程项目中最重要的文件,它定义了你的核心需求和开发原则。

汐屿笔记Claude.md的核心内容:

  1. 项目概述:智能情绪陪伴应用的定位
  2. 三层Playbook架构:L1核心画像、L2近期战报、L3本次简报
  3. 技术栈选择:Taro + React + Fastify + PostgreSQL
  4. 开发原则:KISS原则、Let it Crash、类型安全
  5. API模式:Mock/Real/Local三种模式
  6. 错误处理标准:logger.exception、结构化错误响应

Claude.md的最佳实践

1. 保持简洁明了,突出重点

# 项目概述
汐屿笔记:为深夜emo的年轻人提供AI情绪陪伴

# 核心原则
- KISS原则:简单至上,单文件不超过1500行
- Let it Crash:错误直接暴露,不要掩盖
- 类型安全:严格使用TypeScript,避免any

# 技术栈
- 前端:Taro + React + TypeScript
- 后端:Fastify + TypeScript + Prisma
- 数据库:PostgreSQL
- AI:OpenAI API

2. 包含具体的代码示例和最佳实践

# 错误处理示例
// ❌ 不要这样做
try {
  // some code
} catch (error) {
  return null // 掩盖错误
}

// ✅ 应该这样做
try {
  // some code
} catch (error) {
  logger.exception('Error details', error)
  throw error // 让错误暴露
}

3. 定期更新,反映项目的新要求

  • 新功能需求
  • 技术栈调整
  • 开发原则更新
  • 经验教训总结

🎯 实战应用:在汐屿笔记中的具体案例

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

AI初始方案:

  • 支持多种消息格式(文本、图片、语音、视频)
  • 实现消息版本控制
  • 添加消息搜索功能
  • 支持消息撤回和编辑
  • 实现消息同步和冲突解决

应用KISS原则后的简化:

  • 只支持文本消息
  • 简单的增删改查
  • 按时间排序显示
  • 基本的消息状态(已发送、已读)

案例2:用户认证系统的重构

传统复杂方案:

  • 多种登录方式(手机、邮箱、微信、QQ)
  • 复杂的权限管理系统
  • 操作审计日志
  • 密码强度验证和重置流程

应用Let it Crash后的简化:

  • 只支持微信登录
  • 简单的用户身份验证
  • 登录失败直接崩溃,不提供降级方案
  • 缺少必要配置直接启动失败

案例3:错误处理的标准化

AI推荐的复杂错误处理:

  • 自定义错误类型体系
  • 错误码映射表
  • 多层错误捕获和处理
  • 错误恢复和重试机制

应用类型安全和Let it Crash:

  • 使用TypeScript严格类型检查
  • 错误直接抛出,用logger.exception记录
  • 不提供错误兼容方案
  • 开发环境直接崩溃,生产环境统一错误页面

🌟 总结:AI编程的黄金法则

KISS原则要点

  1. 单文件1500行限制:强迫保持简单
  2. 单一职责原则:每个函数只做一件事
  3. 避免过度抽象:不要为了"未来需求"增加复杂度
  4. 拒绝炫技:能工作的代码就是好代码

Let it Crash要点

  1. 错误直接暴露:不要试图掩盖或兼容
  2. 缺少必需配置直接崩溃:不要使用默认值
  3. 验证失败直接抛异常:不要返回特殊值
  4. API调用失败直接崩溃:不要复杂的重试逻辑

类型安全要点

  1. 严格使用TypeScript:避免any类型
  2. 清晰的接口定义:让AI生成的代码更可控
  3. 运行时类型验证:不要相信输入数据
  4. 编译时错误检查:把问题消灭在萌芽阶段

Claude.md要点

  1. 明确定义项目原则:约束AI的行为边界
  2. 包含具体示例:给AI明确的参考模板
  3. 定期更新维护:反映项目的最新要求
  4. 保持简洁明了:突出最重要的约束条件

记住:AI编程不是让AI做它想做的,而是让AI做你需要的。KISS原则和Let it Crash就是约束AI的最佳工具。


下一篇预告: 《Token经济学实战:AI编程如何省下90%成本》


微信搜索"四哥还会聊AI",看这些原则如何在实际项目中应用

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

← 返回首页