Aesthetics - 系统如何保持优雅
核心问题:
什么样的软件是优雅的?
软件的美,不是表面漂亮,而是:
复杂性被妥善安放之后呈现出来的秩序感。
Dimension 4 的目标,是训练工程师看见系统的结构气质:
- 是否少歧义
- 是否少意外
- 是否少牵连
- 是否能组合
- 是否整体统一
- 是否改起来顺手
1. 简洁不是少东西,而是少歧义
简陋模型:
type User = {
role: string
status: string
metadata: Record<string, unknown>
}
简洁模型:
Account
Credential
OrganizationMembership
CourseAccessGrant
Enrollment
判断问题:
- 它减少了歧义,还是只是减少了代码行?
- 它表达了本质复杂性,还是把复杂性藏进约定?
- 新人能否快速建立正确心智模型?
核心句:
简洁不是少东西,而是少歧义。
2. 本质复杂性要表达,偶然复杂性要消除
本质复杂性来自业务本身:
- 支付和退款
- 权限和访问权
- 订阅生命周期
- 组织成员关系
偶然复杂性来自实现问题:
- 命名含糊
- 重复判断
- 错误码不统一
- 参数顺序混乱
- 配置散落
- 状态乱传
核心句:
本质复杂性要被表达,偶然复杂性要被消除。
3. 一致性让系统可预测
相似动作应该有相似表达:
createCourse()
publishCourse()
archiveCourse()
deleteCourse()
不要:
createCourse()
courseGoLive()
setArchived()
remove()
检查:
- API 命名是否一致?
- 参数顺序是否一致?
- 错误模型是否一致?
- 状态机表达是否一致?
- 目录结构是否一致?
核心句:
好系统让你看过一部分,就能合理猜到另一部分。
4. 局部性让变化有地方去
坏信号:
新增兑换码访问课程,需要改 checkout、course page、mobile API、admin、worker、analytics。
好方向:
course-access/
grants.ts
policy.ts
revocation.ts
tests/
判断问题:
- 一个规则变化需要改几个模块?
- 相关规则是否放在一起?
- 调用方是否知道太多内部细节?
- 谁拥有数据写入口?
核心句:
好设计让相关变化靠近,让无关变化远离。
5. 信息隐藏保护变化边界
调用方不应该知道访问权内部细节:
canAccessCourse(accountId, courseId)
而不是:
hasPaidOrder(accountId, courseId) ||
hasActiveSubscription(accountId) ||
hasOrganizationAssignment(accountId, courseId)
核心句:
你暴露给外部的每个细节,都会变成未来改动的阻力。
6. 可组合性不是插件化
可组合性不是一上来做插件系统、规则引擎或低代码平台。
它更基本:
每个部件职责清楚、输入输出明确、没有隐藏副作用,因此能被可靠拼接。
例如:
grantAccessFromPurchase(purchaseId)
enqueueNotification(notification)
recordAuditLog(entry)
核心句:
好模块像积木,坏模块像胶水。
7. 组合优于继承
坏方向:
class Student extends User {}
class Instructor extends User {}
class Admin extends User {}
现实里一个人可以同时是讲师、学生、管理员、企业成员。
好方向:
Account
Enrollment
InstructorProfile
AdminAssignment
OrganizationMembership
核心句:
现实世界常常是关系网,不是继承树。
8. 隐藏副作用破坏组合
危险函数:
canAccessCourse(accountId, courseId)
如果它内部偷偷:
- 写 audit log
- 刷新缓存
- 创建 grant
- 发送通知
就很难组合。
核心句:
判断函数应该尽量只判断,副作用应该显式发生。
9. 概念完整性让系统可信赖
拼贴系统的坏味道:
User / Account / Member 混用
role / permission / access 混用
status: active 到处含义不同
错误码每个模块一套
后台操作有的审计,有的没有
需要统一:
- 领域语言
- 错误模型
- 权限模型
- 状态机风格
- API 风格
- 后台操作流程
核心句:
语言不统一,系统不可能统一。
10. Developer Flow 决定系统能否长期保持品质
好的 flow:
找到模块
-> 改规则
-> 补测试
-> 跑相关测试
-> 看日志和指标
-> 小步发布
坏的 flow:
全局搜索
-> 改很多地方
-> 不知道测什么
-> 本地跑不起来
-> 只能 staging 手测
核心句:
正确路径应该是最省力路径。
11. 品味是对未来维护成本的提前感知
别扭信号:
- 名字太宽
- 参数太多
- 布尔参数
- 特殊分支散落
- 可选字段太多
- 抽象比问题更难懂
- 新需求没有自然落点
判断问题:
- 它现在能跑,但未来会在哪里疼?
- 它降低理解成本,还是增加理解成本?
- 它是解决真实变化轴,还是只是看起来高级?
核心句:
品味的一半是克制。
12. 重构是恢复秩序
重构目标:
- 改名:恢复概念边界
- 抽规则:减少重复判断
- 移动代码:提高局部性
- 拆类型:承认真实差异
- 删除假抽象:恢复直接表达
重构前先问:
- 我要改善什么?
- 现有行为有没有测试保护?
- 是否改变外部契约?
- 能不能小步提交?
- 中途停下系统是否仍可运行?
核心句:
好重构不是炫技,而是让系统重新变得顺手。
一页总口诀
写代码前,先问是否少歧义。
命名时,先问别人能否猜对。
加接口时,先问是否和同类一致。
放模块时,先问变化会不会局部。
暴露细节前,先问未来是否会被绑住。
做组合前,先问是否有隐藏副作用。
做抽象前,先问是否降低理解成本。
看系统时,先问是否像一个人设计的。
做重构时,先问系统是否更顺手。
最终心法
优雅的软件不是没有复杂性,而是复杂性有秩序。
Dimension 4 的目标,是让工程师不只会判断:
能不能跑?
还会判断:
好不好懂?
好不好改?
好不好组合?
好不好延续?