面向人类和 LLM 的 Clean Code(不牺牲编码的乐趣)
Source: Dev.to
(请提供您希望翻译的文章正文内容,我将根据您提供的文本进行简体中文翻译。)
对LLM友好的整洁代码
LLM 可以写代码。它们可以重构。它们可以生成测试。
如果你已经编码多年,很容易感到不安——不是因为工具不好,而是因为它触及了个人的东西:编码的乐趣很大一部分来自于巧妙。
- 来自优雅的解决方案,来自看到问题坍缩为干净抽象的快感。
- 然后你会读到这样的建议:“宁可无聊也不要聪明。”
- 听起来像是对创造力的讣告。
事实并非一定如此。本文论证了两点:
- 面向人的整洁代码 与 面向 LLM 的整洁代码 稍有不同(可读性 vs. 模型歧义)。
- 我们可以在不牺牲编码乐趣的前提下调和它们,只需把巧妙放在合适的位置。
上下文 vs. 预测
人类在有上下文的情况下阅读代码
- 团队约定
- 架构历史
- 领域知识
- 对“我们这里的做事方式”的直觉
LLM 没有这些上下文。
它们通过预测工作,而非意图。
因此 对 LLM 友好 的代码是指:
- 最小化歧义
- 拥有明确的契约
- 结构上保持规律
- 能安全地进行局部重构
这 不是 “为机器写代码”。
它是写能够经受重构的代码——无论是人类 还是 自动化的。
“为机器写代码”这个说法具有误导性,因为它暗示:
- 巧妙是坏事
- 优雅是危险的
- 有趣是不专业的
但巧妙本身并不是敌人——错位的巧妙 才是问题。
两种巧妙
| 好的巧妙 | 坏的巧妙 |
|---|---|
| 减少认知负荷 | 将逻辑压缩进棘手的表达式 |
| 贴合领域模型 | 利用语言的边缘案例 |
| 创建稳定的抽象 | 依赖隐式假设 |
| 简化未来的变更 | 看起来很炫但脆弱 |
| 工程艺术 | 作者觉得有趣,其他人却痛苦 |
目标不是禁止巧妙——而是把它 放到正确的层次:内部巧妙,外部平凡。
调和方式
- 面向人的整洁代码
- 面向 LLM 的整洁代码
- 构建美好事物的乐趣
只要我们让 外部 明确、稳定、可预测且易于重构,同时保持 内部 优雅、富有表现力且聚焦领域,这三者就可以共存。
示例
1️⃣ Ruby 服务,具有稳定的签名
class CreateOrder
def self.call(input)
new.call(input)
end
def call(input)
input = Input.new(input)
validate(input)
.bind { persist(input) }
.bind { publish_event(input) }
end
end
- 可预测的
.call - 显式的 输入强制转换
- 清晰的 流程
- 无 元编程
结果类型(巧妙实现)
class Result
def self.ok(value = nil) = new(true, value, nil)
def self.err(error) = new(false, nil, error)
attr_reader :value, :error
def initialize(ok, value, error)
@ok = ok
@value = value
@error = error
end
def ok? = @ok
def bind
return self unless ok?
yield(value)
end
end
验证步骤
def validate(input)
return Result.err(:missing_customer) if input.customer_id.nil?
Result.ok(input)
end
面向领域、可组合的管道 → 人类通过组合获得优雅,LLM 获得显式契约和安全重构边界。
2️⃣ Go HTTP 处理器 – 显式且朴素
type Server struct {
Orders *OrdersService
}
func (s *Server) CreateOrder(w http.ResponseWriter, r *http.Request) {
var req CreateOrderRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "invalid json", http.StatusBadRequest)
return
}
order, err := s.Orders.Create(r.Context(), req.ToInput())
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
json.NewEncoder(w).Encode(order)
}
LLM 可以安全地重构此代码。
领域服务 – 乐趣所在
type OrdersService struct {
Repo OrdersRepo
Clock Clock
}
func (s *OrdersService) Create(ctx context.Context, in CreateOrderInput) (*Order, error) {
if err := in.Validate(); err != nil {
return nil, err
}
order := NewOrder(in.CustomerID, s.Clock.Now())
order.AddItem(in.ItemID, in.Qty)
if err := s.Repo.Save(ctx, order); err != nil {
return nil, err
}
return order, nil
}
领域模型、不变式、高内聚 → IO 很乏味;领域是艺术。
3️⃣ TypeScript – 类型降低歧义
// Explicit domain result
type Result<T, E> =
| { ok: true; value: T }
| { ok: false; error: E };
公共函数签名
export async function createOrder(
input: CreateOrderInput
): Promise<Result<Order, { code: string }>> {
if (!input.customerId) {
return { ok: false, error: { code: "MISSING_CUSTOMER" } };
}
const order = buildOrder(input);
await repo.save(order);
return { ok: true, value: order };
}
显式、易于使用、难以误用,LLM 能轻松安全地扩展。
强类型领域模型
type Money = { currency: "PLN" | "EUR"; cents: number };
function addMoney(a: Money, b: Money): Money {
if (a.currency !== b.currency) throw new Error("currency mismatch");
return { currency: a.currency, cents: a.cents + b.cents };
}
强制不变式、最小化表面、强语义 → “优雅编码”。
实用标准,您可以采用
| 指南 | 原因 |
|---|---|
| Stable function signatures (keyword args / typed structs) | 保证 LLM 可以依赖的契约 |
Explicit outputs (Result, typed errors) | 消除歧义 |
| Clean abstractions (small DSLs inside the module) | 将巧妙性局部化 |
| Composition pipelines | 在不泄漏复杂性的情况下实现算法优雅 |
| If you must use metaprogramming or DSLs: • place them in dedicated folders/modules • document WHY | 防止脆弱技巧意外蔓延 |
| Write tests like it’s a mini‑framework | 测试为人类 and LLM 提供安全网 |
不是 因为“短就是坏”,而是因为压缩的代码更难安全地修改。LLM 重构 结构,而不是 意图。DRY 是一条指南,而非信条。
TL;DR
- Cleverness belongs inside – 在它能够建模领域、降低认知负荷并创建稳定抽象的地方。
- Boring, explicit code belongs outside – 稳定的签名、清晰的契约、常规的结构。
当我们尊重这条边界时,我们会得到:
- 代码对人类 and LLM 都易于导航,
- 安全的重构能力,
- 以及构建优美、创新解决方案的乐趣。
如果可以防止误解,请重复意图。
如果编程的乐趣来源于:
- 手写每一行代码
- 炫耀语法技巧
- 把 10 个想法压缩到 1 行
…那么,是的,这部分会逐渐消退。
但更深层的乐趣仍在——并且会增长:
- 建模领域
- 设计 API
- 创建抽象
- 降低复杂度
- 让系统具备弹性
LLM 并不会取代这些,它们只会放大这些乐趣。
“Prefer boring over clever” 是不完整的建议。
更好的说法是:
- Prefer boring where change happens often.
- Prefer clever where meaning lives.
或者,简洁地说:
Clever inside, boring outside.
这就是为人类准备的干净代码。
这就是为 LLM 准备的干净代码。
它让编程的乐趣得以持续。