写这篇东西的起因,是我这几年在带项目、做技术评审、帮同事复盘时反复撞见同一个现象:很多人解决A问题很利落,但遇到差不多的B问题又从头开始踩一遍坑。你说他能力不行,也不对,具体事上手比谁都快;可你让他总结一下规律、沉淀一套方法,他就开始绕圈子。这背后缺的其实不是执行能力,而是一种能把“具体问题”翻译成“通用模型”的本事——抽象思维。
这篇文章我想把这件事掰开揉碎讲清楚:抽象思维到底在抽什么、怎么从眼前的乱麻里拎出那根主线,以及怎么把一次性的解决方案变成可以反复调用的兵器库。适合谁看?程序员、产品经理、运营、做研究的、管项目的,只要你日常工作需要跟复杂问题和不确定性打交道,这篇都能给你一套能直接上手的思考框架。它不教具体的某种技术栈,教的是比技术栈更底层的东西:怎么想问题,才能少做无用功。
1. 先搞清楚抽象思维到底在“抽”什么
1.1 抽象不是玄学,是“删细节”和“找共性”的组合动作
很多人一听到“抽象思维”就觉得是哲学家干的事,跟日常写代码、做方案没啥关系。这是个天大的误解。抽象思维说白了就两个动作:第一个动作叫删细节,把一个问题里那些只在这个场景下成立、换个场景就失效的边角料删掉;第二个动作叫找共性,把删完之后剩下的骨架跟其他问题的骨架摆在一起对比,看哪些结构是反复出现的。
我举个例子。你在给一个电商系统做订单超时关闭功能,需求是“下单后30分钟未支付就自动取消”。大部分人开始想的是定时器怎么设置、数据库怎么存状态、消息队列怎么消费。但如果你把这些细节全删掉,剩下来的骨架是什么呢?是“一个事件在指定时间后触发另一个动作”。你再回头看,用户注册后没激活需要提醒、优惠券领取后过期要失效、工单长时间没人处理要升级,全是同一个骨架。你管这个骨架叫定时任务也好、延迟消息也罢,本质就是“时间触发”。
一旦你完成了这个抽象,你就不是在写“订单超时功能”,而是在设计一个“延迟事件处理平台”。前者是一次性需求,后者是可复用的能力。这就是抽象的第一个价值:它把“做一件事”变成“造一个可以做一类事的机器”。
1.2 抽象的三个层次:具体层、映射层、通用层
我习惯把思维的层级分成三层,这个框架帮我看清自己和别人卡在哪。
最底下是具体层,眼睛里全是“这一个”问题:这个接口返回超时了、这个页面样式错位了、这个客户投诉了。处理这一层靠的是经验和熟练度,遇到得多,解决得就快。第二层是映射层,已经把眼前的“这一个”跟过去遇到的“那一个”连上线了:这个接口超时,本质上跟上次那个数据库连接池耗尽是一样的故障模型,都是资源不足导致的雪崩。到这一层,你已经能借力过去的经验,但还是在“相似问题”之间打转。第三层才是通用层,你已经不看具体业务了,而是看结构:超时、限流、降级、重试,这些都是“分布式系统中的容错模式”,换到物流调度里就是备用路线、分批运输、优先级排序。
绝大多数人一辈子停在具体层,偶尔用用映射层,通用层很少真正抵达。抽象思维训练的核心目标,就是让我把自己往上挪一层,哪怕不能长期待在第三层,至少在遇到复杂问题时知道“还有更高的视角”,主动跳出来看看。
1.3 为什么说抽象能力决定了一个人的天花板
这不是鸡汤,是特别实在的经验判断。抽象能力差的人,能力全锁死在特定场景里。你在淘宝写过订单系统,换到美团你还是要从订单系统重新学起;你在A公司处理过用户增长,跳去B公司发现模型不太对,又要从头摸。表面看是行业壁垒,本质上是抽象层级不够——你的经验没有提炼成脱离具体业务的通用模型,所以换一个壳就不认识了。
抽象能力好的人,经验是可迁移的。做过订单超时关闭,看物流延迟赔付、看直播预约开播、看云主机到期回收,一眼就知道里面是同一个齿轮在转。这种人在行业里叫“有底层思维的人”,在新领域上手特别快。再说团队里为什么有人能从一个功能负责人长成平台负责人?因为平台负责人要面对的不再是一两个具体需求,而是一整类需求的合集,没有抽象能力,连需求都捋不清,更别说设计架构了。
所以训练抽象思维,短期内能让你做方案想得全、做设计少返工、写代码少重复,长期看,它决定了你是那个永远在写业务代码的人,还是那个有能力定义一个系统的人。
2. 从具体问题到通用方案的四步拆解法
2.1 第一步:把问题“喂”给纸,而不是喂给情绪
碰到一个棘手问题,人的本能是马上想解法。但我建议你先忍一忍,花个十分钟把问题“喂”给纸——在一张空白文档里回答四个问题:我在解决谁的什么问题?这个问题的发生场景是什么?现在的做法是什么?卡住我的那个点到底是什么?
别小看这个笨功夫。做了这么多年我发现,很多问题之所以解决不了,不是方法不对,而是对问题的定义根本就是错的。比如有个团队来跟我说“我们的报表加载太慢了”,这就是一个没被定义清楚的问题。慢是哪里慢?是查询慢、传输慢还是浏览器渲染慢?这个报表谁在用?如果是一个每天只打开一次的内部运营看板,慢3秒根本无所谓;如果是客服在客户电话里查数据,慢1秒都是事故。你没定义清楚,连优化方向都定不了,更别说抽象通用模型了。
写下来之后,你还要做一道“剔除题”:把问题描述里那些换一个客户、换一个时间段、换一个业务线就不再成立的话划掉。划到最后剩下的那句,才是你真正要解决的问题。
2.2 第二步:问三个“为什么”,剥离业务外壳
这是最难的一步,因为业务外壳最诱人。你今天做的是跨境电商的订单推送,业务细节丰富得能写本书,但那些细节恰恰是“噪音”。我给你一个特别好用的工具,叫“三层为什么”:
第一问:这个需求/问题背后的目标是什么?——别回答“推送订单”,往上游想,目标是“让买家实时知道物流状态”。 第二问:这个目标在别的行业/场景里会被谁提出?——查快递能看到轨迹、点外卖能看到骑士到哪了、打车能看到车到哪了。原来这是个“位置/状态可视化”需求。 第三问:实现这个目标的本质规律是什么?——不是推送协议,而是“状态变化及时触达相关方”。
你看,走到第三问,“跨境电商订单推送”这个业务外壳已经被扒掉了,露出来的东西叫“状态广播机制”。你现在可以站在一个很高的位置上审视问题:我到底是要做一个消息中心,还是只是在订单模块里写死一个推送逻辑?答案显而易见,前者。因为有“物流轨迹变化”这个状态,就一定还有“退款状态变化”“库存预警变化”“风控事件变化”,你想清楚这个,一开始就去做通用的状态广播组件,后面所有业务都能往上挂,而不是每个需求单独写一次推送。
2.3 第三步:用一句话定义“通用模型”
我还是拿实际体验来说。这个步骤最容易两种极端:一种是想得太小,抽象完之后发现其实也就比具体问题大一点点;另一种是扯得太大,恨不得把一个简单的接口超时上升成“万物互联的熵减模型”,那种抽象毫无用处,因为它不可落地。
我总结了一个检验标准:你抽象出的通用模型,必须能一句话说清楚,而且这句话里不能出现原问题的具体业务名词。举个例子,你抽象完“订单超时关闭”这个问题,得到的一句话可以是“为任意事件设置延时触发能力”,这里没有“订单”这两个字,说明剥离干净了。如果你说出来是“针对订单做超时取消的通用配置”,那说明你还没脱离业务外壳,抽象不彻底。要是你说“熵增定律在业务生命周期中的应用”,恭喜你,过度抽象了。
在“业务特定”和“空泛玄虚”之间,那个甜蜜点的判断标准只有一句话:换一个业务场景念一遍这句话,如果还成立,那就是合适的抽象粒度。
2.4 第四步:画“结构图”而不是写“流程图”
这是我自己改造出来的招。普通人在梳理方案时喜欢画流程图:从A开始,走到B,走到C,分支到D,这种图的好处是直观,坏处是它太依赖特定路径了。比如用户从A入口进来走的是这条分支,从B入口进来就走另一条分支,每条分支都长得不一样,图画得越来越复杂,到后来根本没法复用到下个需求上。
抽象思维要的是结构图,不是流程图。结构图只画两样东西:有哪几类角色,它们之间有什么样的关系。同一张结构图,不管用户从哪个入口进来、经历什么分支,角色和关系都不变。就拿订单超时关闭来说,流程图画的是状态如何跳转:待支付→超时→已关闭;结构图画的是三个角色:订单(一个带生命周期的实体)、时钟(触发源)、状态机(业务规则)。你再换到优惠券、工单、直播预约上,画出来还是这三个角色。有了这张结构图,你设计的不再是一条条流程分支,而是一个带状态的实体、一个触发机制、一套可配置规则。
从流程图思维转向结构图思维,是最关键的一次认知升级。一旦转过来,你看很多问题都会有一种“啊,原来就是这点事”的通透感。
3. 一个案例走全流程:从“文件导来导去”到通用同步框架
3.1 背景还原:另一个团队甩过来的“脏活”
去年有其他业务线找过我们,提出需求特别朴素:他们有一套客户数据存在Excel里,要定期导入我们的CRM系统;另外我们系统里一些数据要导给他们的财务系统,最好也是Excel,他们老大要看表。按常规做法,这就是两个一次性需求:写一个Excel解析导入接口,加工客户数据;再写一个查询导出接口,生成财务要的Excel表格。两周能做完,做完就完事。但我当时刚读完那段时间的抽象思维笔记,脑子里的雷达响了——这两个需求外层不一样,但核心骨架几乎是复制粘贴的:一端是数据源,一端是目标系统,中间需要做格式转换、校验清洗、异常处理。我们已经走到了新的通用模型面前,再做一次性开发确实太亏了。
于是我们往上游多问了一轮:你们为什么还要手工导Excel?答案很老实:因为两边系统没有对接,数据又散落在好几个地方。继续问:你们期望的最终状态是什么?答:我们不想管这个事,最好数据自动同步。这个要求一出来,Excel其实只是过渡方案,真正的目标是“异构系统间的数据流动”。
3.2 识别抽象层:从“Excel导入导出”到“管道-适配器”模型
我们开了一次会,把问题剥到第二层后,我当场画了一张结构草图。Excel导入只是“数据管道”的一个接入端,Excel导出只是管道另一端的输出端而已。真正通用的东西是一条“管道”:它负责从上游源头把数据取出来,经过若干个加工环节,投递到下游目的地。管道不关心上游是Excel还是数据库还是API,也不关心下游是Excel还是财务系统还是数据仓库,它是无知的搬运工。
那每个具体系统怎么接进来?用适配器。Excel算一个适配器,数据库算一个适配器,API也算一个适配器。任何系统想接入这条管道,只要写一个适配器实现统一接口就行。我拿铅笔在纸上写完这几行字,抬起头看到的对面的同事眼睛也亮了,那个瞬间我们很清楚,这个方案不再是在解决“Excel导入导出”,而是在做公司层面的“异步数据管道平台”,以后再接财务、接物流、接仓储系统,都不用再造轮子,全部复用这一套。
3.3 落地实操:抽接口、建配置、控边界
抽象模型想得再好,落不了地都是空中楼阁。下面是我们实际落地时的具体做法,比较简单但已有参考价值,我按代码组织的粒度说一下:
我们把整个管道抽象成三段,每段一个接口。
第一段叫Source,管数据的读出来。规定它只干一件事:返回原始数据的迭代器。Excel实现就是把文件流一行行读进来,数据库实现就是执行SQL返回结果集,API实现就是拉分页数据。这个接口只负责“把数据挪到管道里”,不做任何业务加工。
第二段叫Processor,管数据加工。它是个函数链路,输入一条原始记录,输出一条加工后的记录。校验、格式转换、字段映射、补默认值、打标脏数据,全做成可插拔的Processor,按配置顺序执行,比如先清洗、再映射、最后校验。
第三段叫Sink,管数据写出去。Excel导出只是Sink的一个实现。将来要接财务系统,就新增一个财务格式的Sink,里面做字段映射和HTTP调用。写完这三个接口后,接入一个新场景就是写三个小类的事。
然后我们再抽象两个横向关注点:配置化编排和任务状态跟踪。每个管道任务用一份元数据描述:用什么Source、接哪些Processor、写到哪个Sink、错误后是重试还是告警。这个元数据存表里,运营同事自己都能配置新管道,不需要开发介入。任务状态跟踪则统一了执行日志、成功条数、失败原因、重试次数,每个任务一个Task ID,出问题直接按ID查到底。
3.4 本案例的抽象收益:复用与边界划清
这个方案上线后,最初两个需求各花了一周,但你未来接到新管道需求的成本会大幅度降低。第一个新需求是接第三方物流公司的运单回传,团队里一个刚入职两个月的同事看了文档,花了一天半写了一个Source、一个Processor、一个Sink就交付了。如果当初走了老路,这个需求量最少也是两周起。后面陆陆续续又接了十几个管道,全是同一套框架在跑,团队从“天天做Excel表搬运工”变成了“平台的建造者”,工作的创造性完全不一样。
更值钱的收益是组织层面的。以前这类需求是散落在各业务线的野活,没有统一的所有者,出了问题互相推。现在有了管道平台,责任边界非常清楚:管道框架归基础组,各管道的转换逻辑由各业务线的接入方负责,联合排障也更快了。抽象思维在这里起到的作用,不只是省了代码量,是把混乱的接口关系理成一套有主次的秩序。
4. 抽象思维的实战心法:避坑清单与常见问题
4.1 抽象不足:像是在造“一次性筷子”
抽象不足是最常见的问题,表现是每次新需求来都从头搭一遍。很多人的理由是“这个需求太简单了,没必要抽象”“这是临时的,先跑通再说”——我在实际项目里听到过太多这种话,尤其是“先跑通再说”,最后几乎都变成了“再说”之后就再也不重构了。这就像一次性筷子,用过就扔,每一次成本都很低,但架不住你天天用、月月用、年年用,累计成本高得吓人。
判断该不该抽象,我给自己定了一个“三次原则”:如果同一个模式出现了三次,我就停下来做一个通用版本。三次之前,做专用实现可以,因为需求可能还没稳定,过早抽象反而会被变化折腾。第三次出现的时候,你已经有了足够多的样本去识别共性,这时候做抽象风险最低、收益最高。
4.2 过度抽象:把简单问题做成花瓶
另一头的坑是过度抽象,常见于满脑子方法论又缺少实战约束的工程师。明明就一个简单的状态变更通知,非得抽象出一个事件驱动、规则引擎、消息总线,计划搞出一个分布式编排平台。代码一堆,配置文件几层,新来的人看一周都看不懂。这种抽象不是为了解决问题,而是为了满足自己“看起来很厉害”的冲动。
过度抽象的代价最隐蔽:它不会立刻爆雷,但是会把团队拖进维护地狱,让本来五分钟能改完的逻辑变成要在五个抽象层里翻山越岭。我治这个毛病的办法是“实用主义抽象”:抽象之后带来的收益,能否在下次遇到同类问题时体现出来?抽象的代价,你是否支付得起?如果答案模糊,那就先做最简单能用版本,再在第四次出现时重新评估。
4.3 跳步抽象:路径都没走通,就想建高速公路
还有一种常见的失败是跳步抽象。什么意思呢?就是你还没实际解决过哪怕一个具体问题,上来就照着理论搭一个大平台。你做的不是抽象,是空想。你自己都没爬过那座山,怎么能画出通用登山地图呢?真正的抽象一定是从具体实践中长出来的,你得先解决A问题,再解决B问题,然后发现A和B的解法背后有同一棵树的根,那时抽象才是有根的。
所以我的第一个经验法则:抽象必须发生在至少两个成功实践之后。如果你连一个具体实现都没有,那就先忍着,老老实实把第一个方案做出来。“三轮法则”指的不是等你抽象出完美模型才开始动手,而是从第一轮就带着“未来要做通用”的意识,用通用模块的思路来组织代码,只是不急着抽成框架而已。
4.4 各阶段的常见症状与检查方法
我把这些年的经验和团队成员常犯的问题梳理了一张速查表。它解决“我知道自己卡了,但不知道卡在哪”的状态,特别好用。
| 症状 | 可能的问题 | 检查方法 |
|---|---|---|
| 代码里大量复制粘贴,改一处要改五处 | 抽象不足 | 搜索重复代码,统计重复次数,超过三次开始提取公用 |
| 新需求排期永远不收敛 | 抽象不足导致每次都在造新轮子 | 复盘需求,看它是否能用已有模块拼接完成 |
| 简单需求被拆成一堆组件和接口 | 过度抽象 | 问“加这层接口解决了哪个现实痛点?”,答不上来就去掉 |
| 配置文件和接口比业务代码还长 | 过度抽象 | 计算逻辑代码行数,如果占比不到三成,简化设计 |
| 做新需求时完全套不上已有框架 | 跳步抽象/伪通用 | 停下来重新审视抽象模型是否从实践而来,必要时回退重来 |
| 抽象模型总在改,稳定性差 | 过早抽象,样本不足 | 抽回具体实现,等第三个真实需求出现再重构 |
这张表不是标准答案,但每次开会拿不准设计时,我拿出来过一遍,通常能定位到问题根源。
5. 把抽象思维内化的日常训练方法
5.1 “翻译练习”:每天找一个具体现象,用一句话说出它的本质
这个练习是我自己坚持了好几年的:每天刷新闻或者日常聊天时,遇到一个有意思的具体现象,强迫自己用一句话说出它的本质。比如“这家奶茶店排队很长”,本质是“供给不足造成的稀缺信号”。“我们的App用户留存掉了5个百分点”,本质是“用户的预期管理与体验交付之间出现了系统性偏差”。
这种练习的价值在于训练大脑“剥离业务外壳”的反射。做得多了,遇到复杂问题时,你不用刻意提醒自己“我要抽象一下”,大脑会自动在具体细节后面搜索结构。这个习惯像是给思维方式装了个后台进程,不必刻意调动,但一直在运转。
5.2 跨领域类比接龙:把A领域的概念翻译成B领域
另一个我很推荐的游戏是“跨领域类比接龙”,特别适合团队头脑风暴时用。规则特别简单:拿到一个概念,把它翻译到完全不相关的领域去。比如“缓存”,翻译到餐厅场景就是预约排队等位时,先把菜单给你看好,省得落座后再花5分钟看菜单;翻译到物流就是先把高频商品前置到离用户最近的仓库。
玩这个游戏的本质是在练“结构识别能力”。当你发现餐厅排队和系统缓存靠的是同一个结构——把低频动作提前或并行处理——你对那个通用模型的理解会比只看技术文章深得多。因为你是从两个完全不同的领域里看到了同一根柱子,这种理解是无法从抽象定义中获得的。
5.3 复盘时多问“模型”而不是“细节”
团队复盘是最被浪费的抽象训练场。大多数复盘都在纠结细节,比如“那个接口为什么超时了”“谁的责任”“下次一定要加监控”。这些当然重要,但你还可以在快结束时多问一个问题:这个事故背后的通用模型是什么?是容量规划不到位?是依赖管理混乱?是变更流程缺失?这些问题指向的才是战略性改进,而不是一次性的补丁。
我也开始要求团队在写事故报告时增加一栏“我提炼出的通用性改进”,不写代码层面的修复,写你这次踩坑后在认知层面收获了什么。一开始响应寥寥,但坚持几个月后,成员之间明显出现了“这类问题本质上是那个问题”的对话,这就说明抽象思维开始变成了团队语言。
结尾
抽象思维不是一个需要专门报班学的学科,它更像是手艺,得在日常工作里反复磨。有一条经验建议分享给你:下次遇到看起来特别“脏”的问题,先深呼吸,别急着动手。哪怕多花十分钟,把问题摊开、剥掉外壳,问问自己“它跟之前哪些问题长着同一副骨架”。刚开始的时候会被领导催、被同事觉得你磨蹭,但一旦你尝到“一次解决一串问题”的甜头,这个习惯就再也戒不掉了。我最近几年反而越来越觉得,不抽象的努力就像是背着重物跑步,看起来很忙很努力,但走不远。而这个可以训练、可以内化的思维习惯,是最值得为自己和团队投资的一项底层能力。