核心问题
如何判断一个设计“别扭”?
工程品味不是玄学。
它是大量模式识别后的判断力:
这个设计现在能跑,但以后会疼。
有品味的工程师不只是知道怎么实现,还能提前感到:
- 名字太宽
- 抽象太早
- 边界太漏
- 参数太多
- 状态太散
- 错误模型不统一
- 规则放错地方
- 新需求会很难落位
核心句:
品味是对未来维护成本的提前感知。
品味来自经验,但可以训练
很多人说:
这个设计不优雅。
但如果说不出原因,就只是偏好。
工程品味要能落到判断:
- 它违反了哪条边界?
- 它制造了什么耦合?
- 它隐藏了什么规则?
- 它让什么变化变难?
- 它把复杂性转移给了谁?
能说清楚原因,品味才从审美变成工程判断。
别扭信号 1:名字太宽
危险名字:
User
Manager
Handler
Processor
Context
Metadata
Data
Info
Util
这些名字不是绝对不能用。
但如果核心领域里充满它们,说明系统还没真正命名。
例如:
CourseManager
它可能在做:
- 创建课程
- 发布课程
- 编辑课程
- 管理访问
- 发送通知
- 生成报表
品味好的工程师会问:
它到底管理什么?
别扭信号 2:参数太多
函数参数太多,常说明边界不清。
createAccess(
accountId,
courseId,
organizationId,
subscriptionId,
purchaseId,
source,
validUntil,
sendEmail,
auditReason
)
这可能说明:
- 缺少一个明确 command object
- 函数承担太多职责
- 不同场景被硬塞进一个入口
- 调用方知道太多内部细节
更好:
grantAccessFromPurchase(purchaseId)
grantAccessFromSubscription(subscriptionId)
grantAccessFromOrganizationAssignment(assignmentId)
或者:
grantCourseAccess({
accountId,
courseId,
source,
sourceId,
validUntil,
})
别扭信号 3:布尔参数
布尔参数经常让调用难读。
publishCourse(courseId, true)
true 是什么?
- 是否发送通知?
- 是否跳过审核?
- 是否立即发布?
- 是否记录审计?
更好:
publishCourse(courseId, { notifyStudents: true })
或者拆成不同动作:
publishCourse(courseId)
publishCourseSilently(courseId)
布尔参数常常是隐藏分支的味道。
别扭信号 4:到处都是特殊分支
if (organization.type === "enterprise") ...
if (course.source === "coupon") ...
if (user.role === "admin") ...
if (payment.provider === "stripe") ...
特殊分支不一定错。
但如果同一个判断散落各处,说明缺少合适边界。
例如:
if (payment.provider === "stripe")
可能应该被收进:
paymentProviderAdapter
而不是让全系统知道 Stripe 的存在。
别扭信号 5:可选字段太多
type Relationship = {
accountId?: string
courseId?: string
organizationId?: string
purchaseId?: string
subscriptionId?: string
role?: string
permissions?: string[]
metadata?: Record<string, unknown>
}
大量可选字段说明:
你可能把多个不同概念塞进了一个类型。
品味好的工程师会问:
- 哪些字段总是一起出现?
- 哪些组合非法?
- 是否应该拆成多个类型?
- 是否缺少 discriminated union?
别扭信号 6:规则和数据分离过远
例如:
type Subscription = {
status: string
currentPeriodEndsAt: Date
}
然后到处写:
subscription.status === "active" &&
subscription.currentPeriodEndsAt > now
规则散落,系统会腐烂。
更好:
isSubscriptionActiveAt(subscription, now)
品味好的人会把重要规则放到可信位置。
别扭信号 7:抽象比问题更难懂
坏抽象:
AbstractActorResourceRelationResolver
如果理解抽象比理解业务本身还难,它可能错了。
好的抽象应该降低理解成本。
例如:
CourseAccessGrant
AccessPolicy
OrganizationMembership
这些名字来自领域,而不是来自工程炫技。
别扭信号 8:新需求没有自然落点
当产品说:
新增兑换码访问课程。
如果团队第一反应是:
这个要改哪里来着?
说明系统缺少结构节奏。
好的系统应该有自然落点:
course-access
coupon
grant source
access policy tests
品味就是能感到“这个需求应该落在哪里”。
品味和克制
工程品味不只是知道什么时候该抽象。
也包括知道什么时候不要抽象。
例如两段代码相似,但概念不同:
createPurchase()
createEnrollment()
此时复制可能比抽象更好。
品味好的工程师不会为了消除表面重复,制造深层耦合。
核心句:
品味的一半是克制。
品味检查清单
看到一个设计时问:
- 名字是否具体?
- 抽象是否来自真实变化轴?
- 参数是否过多?
- 布尔参数是否隐藏分支?
- 可选字段是否暗示多个概念混在一起?
- 业务规则是否有可信位置?
- 新需求是否有自然落点?
- 调用者是否知道太多内部细节?
- 这个设计是降低理解成本,还是增加理解成本?
- 它现在能跑,但未来会在哪里疼?
小结
- 工程品味是对未来维护成本的提前感知。
- 品味不是偏好,必须能说清工程理由。
- 名字太宽、参数太多、布尔参数、特殊分支、可选字段过多都是别扭信号。
- 好抽象应该降低理解成本。
- 新需求没有自然落点,说明系统缺少结构节奏。
- 品味的一半是克制,不为了表面重复制造深层耦合。