设计接口
基于《软件设计的哲学》中的"设计两次":你的第一个想法不太可能是最好的。生成多个截然不同的设计,然后进行比较。
工作流程
1. 收集需求
在设计之前,理解:
- 这个模块解决什么问题?
- 调用者是谁?(其他模块、外部用户、测试)
- 关键操作是什么?
- 有什么约束?(性能、兼容性、现有模式)
- 什么应该隐藏在内部 vs 暴露出来?
询问:"这个模块需要做什么?谁会使用它?"
2. 生成设计(并行子代理)
使用 Task 工具同时生成 3+ 个子代理。每个必须产生截然不同的方法。
每个子代理的提示模板:
为以下模块设计一个接口:[模块描述]
需求:[收集的需求]
此设计的约束:[为每个代理分配不同的约束]
- 代理 1:"最小化方法数量 - 最多目标 1-3 个方法"
- 代理 2:"最大化灵活性 - 支持多种用例"
- 代理 3:"优化最常见的情况"
- 代理 4:"从[特定范式/库]中汲取灵感"
输出格式:
1. 接口签名(类型/方法)
2. 使用示例(调用者如何使用它)
3. 此设计在内部隐藏了什么
4. 此方法的权衡
3. 展示设计
展示每个设计时包括:
- 接口签名 - 类型、方法、参数
- 使用示例 - 调用者在实践中如何实际使用它
- 它隐藏了什么 - 内部保持的复杂性
按顺序展示设计,以便用户在比较之前能够吸收每种方法。
4. 比较设计
展示所有设计后,从以下方面比较它们:
- 接口简洁性:更少的方法、更简单的参数
- 通用 vs 专用:灵活性 vs 专注
- 实现效率:形状是否允许高效的内部实现?
- 深度:小接口隐藏显著的复杂性(好)vs 大接口配薄实现(坏)
- 正确使用的容易程度 vs 误用的容易程度
用散文讨论权衡,而不是表格。突出设计分歧最大的地方。
5. 综合
通常最好的设计结合了多个选项的见解。询问:
- "哪种设计最适合你的主要用例?"
- "是否有其他设计中值得合并的元素?"
评估标准
来自《软件设计的哲学》:
接口简洁性:更少的方法、更简单的参数 = 更容易学习和正确使用。
通用性:无需更改即可处理未来的用例。但要警惕过度泛化。
实现效率:接口形状是否允许高效的实现?还是迫使笨拙的内部实现?
深度:小接口隐藏显著的复杂性 = 深模块(好)。大接口配薄实现 = 浅模块(避免)。
反模式
- 不要让子代理产生相似的设计 - 强制要求截然不同的差异
- 不要跳过比较 - 价值在于对比
- 不要实现 - 这纯粹是关于接口形状
- 不要基于实现工作量进行评估