Be Intentional About How AI Changes Your Codebase
概述
关于 AI 辅助编程时代代码设计最佳实践的深度思考,探讨语义函数、实用函数和模型设计的核心原则。
核心理念: 代码应该自我文档化——如何拆分逻辑函数和塑造传递的数据决定了代码库长期维护的质量。
语义函数 (Semantic Functions)
语义函数是代码库的构建块。一个好的语义函数应该尽可能最小化,以优先保证正确性。
特征
- 接受完成目标所需的所有输入
- 直接返回所有必要的输出
- 可以包装其他语义函数来描述期望的流程
- 副作用通常是不受欢迎的
- 应该易于单元测试
示例
quadratic_formula()- 简单明确retry_with_exponential_backoff_and_run_y_in_between()- 复杂但自描述
原则: 语义函数不需要注释——代码本身应该是其行为的自描述定义。
实用函数 (Pragmatic Functions)
实用函数作为一系列语义函数和独特逻辑的封装层。它们是代码库中的复杂流程。
使用场景
- 复杂业务逻辑的编排
- 跨多个语义函数的流程
- 不太可能在多处重用
示例
provision_new_workspace_for_github_repo(repo, user)handle_user_signup_webhook()
文档原则
- 避免重复函数名称的说明
- 记录意外情况,如"余额少于10时会提前失败"
- 把文档评论当作参考,要事实核查
模型设计 (Models)
数据的形状应该使错误状态变得不可能。
核心原则
- 精确命名: 模型名称应足够精确,以至于看任何字段都知道它是否属于该模型
- 组合而非合并: 两个经常一起需要但独立的概念应该组合而非融合
- 品牌类型: 使用品牌类型(brand types)区分形状相同但含义不同的值
品牌类型示例
// 而非 bare UUID
DocumentId(UUID)
MessageId(UUID)
// 模型组合
UserAndWorkspace {
user: User,
workspace: Workspace
}
好的命名示例
UnverifiedEmail- 明确状态PendingInvite- 明确生命周期BillingAddress- 明确用途
代码腐化模式
函数腐化
常见问题:语义函数变成实用函数后,其他依赖它的代码开始做意想不到的事情。
- 通过命名用途而非行为来明确创建函数
- 函数名应表明行为不严格定义
- 使调试回归更容易
模型腐化
常见问题:"就加一个可选字段"导致模型变成松散的数据袋。
- 每个可选字段都是代码需要回答的问题
- 松散类型字段是传入看似正确但实际错误数据的邀请
- 当模型名称不再描述数据时,是时候拆分了
AI 时代的特别考量
- AI 更容易阅读良好结构化的代码
- 语义函数帮助 AI 理解代码意图
- 清晰的模型边界减少 AI 产生幻觉
- 自描述代码减少 AI 添加不必要的注释