好的抽象,是“被具体问题撑开的容器”,不是“凭空画的盒子”。
完全正确!👏
你这几句话——
“先解决具体问题,不要过早抽象;容忍适度重复,直到模式清晰;等发现了再重构就行,关键是看出来。”
——精准地概括了软件工程中最核心、也最容易被忽视的实践智慧。这不仅是写代码的原则,更是驾驭复杂系统演进的心法。
🌱 为什么“先解决具体问题”如此重要?
因为抽象的质量,取决于对具体细节的理解深度。
- 如果你在只见过
terms聚合时就设计“通用聚合框架”,你可能会:- 忽略嵌套需求
- 忘记值源(ValuesSource)的多样性
- 没考虑跨分片 reduce 的内存模型
- 结果:抽象要么太窄(无法扩展),要么太泛(充满无用钩子)
💡 好的抽象,是“被具体问题撑开的容器”,不是“凭空画的盒子”。
🔁 为什么“容忍重复”是美德?
很多人一看到两段相似代码就急着提取方法,但重复本身不是问题,盲目抽象才是。
| 情况 | 是否该抽象? | 原因 |
|---|---|---|
两个聚合都调用了 fieldData.getOrdinals() | ❌ 暂不抽象 | 可能只是巧合,第三个聚合用完全不同方式 |
五个聚合都需要解析 missing 参数 + 验证字段存在性 + 注册到上下文 | ✅ 立即抽象 | 模式稳定,变化方向一致 |
🧩 重复是模式的“显影液”。没有足够的样本,你看不清真正的共性。
Elasticsearch 早期代码中,TermsAggregator、DateHistogramAggregator 等确实有大量相似结构。但团队等到十几种聚合落地后,才提炼出 ValuesSourceAggregator 基类和 AggregatorFactories 框架——这才保证了抽象的恰到好处。
🔍 “关键是看出来”——洞察力从哪来?
这正是资深工程师与初级工程师的分水岭。
初级思维:
“这段代码和刚才那段很像,我把它抽成一个函数。”
资深思维:
“这三处修改都涉及‘如何从字段获取值并处理缺失’,背后其实是‘值源访问策略’的问题。也许我们需要一个统一的
ValuesSource抽象,而不是仅仅合并代码。”
洞察 = 在重复中识别“变化轴”(Axis of Change):
- 是数据结构在变?(如不同聚合类型)
- 是执行环境在变?(如 shard vs coordinator)
- 是扩展方式在变?(如插件 vs 内置)
- 是约束条件在变?(如权限、内存、超时)
当你能回答这些问题,你就“看出来了”。
🛠️ 如何训练这种“看出来”的能力?
-
写完功能后多问一句:
“如果明天要加一个类似功能,哪些地方会改?哪些不会?” -
做 Code Review 时关注“修改模式”:
不要看“这代码对不对”,而要看“下次加功能时,它会让事情变简单还是更乱?” -
读优秀开源项目的提交历史:
比如看 Elasticsearch 的 Git log,你会发现:- 先有
commit: add geo_distance aggregation - 再有
commit: refactor aggregations to use common values source - 最后
commit: introduce AggregatorFactories.Builder
架构是长出来的,不是画出来的。
- 先有
-
允许自己“返工”:
第一次写得“笨”一点没关系。关键是在第二次、第三次遇到同类问题时,主动停下来思考:“我们是不是在重复造轮子?”
🌟 一句话总结你的观点:
不要为了“看起来优雅”而抽象,而要为了“未来更容易扩展”而重构;
重复不可怕,可怕的是在模式未明时强行统一;
真正的架构能力,体现在“何时不动手”和“何时动手”的判断上。
这正是《重构》《领域驱动设计》《程序员修炼之道》等经典反复强调的:
“Make it work, make it right, make it fast.”
(先让它跑起来,再让它正确,最后让它快——而“正确”包括“结构清晰”)
你已经走在正确的路上了。继续写,继续看,继续“看出来” 💪。
更多推荐


所有评论(0)