全部文章

职场之锤

本文另有英文译文 · 阅读英文版 →

“你这边就按之前那个功能复制一下就好了,应该很简单吧?”

那一刻我脑子一懵,感觉不是在听需求,而是在听一个未来的生产事故预告片。

作为程序员,这是我无数次踩坑的起点:看似简单的一个需求,结果牵一发而动全身,不仅改动范围比预期大三倍,还要扛下上线后的各种“为什么会这样”。

更可怕的是,等我把逻辑理清楚、边界弄明确,去和产品解释“为什么不简单”时,对面却像看外星人一样看我:“哎呀你太敏感了吧?”

但技术人“敏感”不是坏事,而是对系统负责的本能。真正的问题,是“简单”这两个字,背后藏着职能之间对复杂度的认知偏差。


我们口中的“简单”,根本不是同一回事

在产品经理眼里,“简单”是指用户流程没变、交互看起来不难、功能和之前的类似。

但在程序员眼里,“简单”得先过这几关:

  • 有没有改动数据库结构?

  • 有没有依赖第三方接口?

  • 会不会破坏现有逻辑链?

  • 能不能兼容老用户的历史数据?

所以产品说“只是把按钮挪个地方”,但程序员知道这可能涉及三个模块、四个服务和一堆缓存同步。

问题的根源不是谁对谁错,而是两个角色在定义“成本”和“风险”时,本身就使用的是不同的语言体系:

  • 产品更关注“是否值得做”,强调价值与投入比;

  • 程序员更关注“怎么做才稳”,强调技术债与演变成本。

而当我们用各自的语言说“简单”,听在对方耳朵里就成了不懂装懂。


程序员不是翻译器,但得学会翻译

我以前会在心里吐槽:你又不是写代码的,凭什么说简单?

但后来我开始反问自己:
如果我不把复杂讲清楚,对方怎么会知道“哪部分风险值得讨论”?

所以我试过换一种方式说话,不是反驳对方“你错了”,而是引导对方看到“你没看到的”。

比如产品说“就是加个校验嘛”,我不直接回“不行”,而是这样问:

  • “这个校验,是前端做就可以,还是要后端拦?拦了之后出错提示要长成什么样?”

  • “我们现在这套逻辑是不是默认每一步都成功?这加上去后失败流要不要补?”

  • “这一步失败后,用户的数据会不会卡在某个中间状态?”

我发现,当我用“判断题”变成“选择题”,对方反而更愿意参与进来一起权衡。

这是我后来总结的一个小技巧:

把技术复杂度翻译成选择题,
再把选择题的代价翻译成用户体验。

不是告诉对方“这不简单”,而是“你想要的效果,对应的选择路径可能不止一个,我们来挑一个既靠谱又省力的”。


别只做补锅的,也要画清锅的边界

有时候,技术人容易陷入一个误区:只要需求来了,我就得做。

但你不画边界,别人不会帮你考虑成本。于是你成了团队里的“万能修补匠”,但却永远无法定义工作。

所以我在一个团队做Tech Lead时,做了两个小机制:

  1. 每个需求评审会,必须由工程师来讲“风险图谱”
    不只是排期时间,而是明确有哪些模块会受影响、预计哪些地方最容易出Bug、是否需要回滚方案

  2. 建一个“变更前提清单”
    比如:

    • 有没有接口文档?

    • 有没有测试数据?

    • 有没有 fallback 方案?

    • 是否能灰度发布?

这不是在推卸责任,而是反过来帮助产品去理解:一个“看似简单”的需求,是不是应该花两小时再讨论清楚,而不是直接进入排期。

当你开始主动作边界,对方也会更容易尊重你的专业。


真正成熟的技术沟通,不是说服对方,而是共建定义

很多人以为程序员跟产品对话的关键,是把“复杂说简单”。

但我越来越觉得,真正的能力,是把“复杂讲得合理”。

你不需要一次把所有细节都抛出来吓人,而是能引导对方看到那些“看不见的复杂”,再一起决定哪些可以做简化,哪些不能妥协。

这样你既保住了系统的底线,也参与了产品价值的讨论——从被动响应需求,变成了共建定义的一份子。

所以,下次听到“这个需求很简单啊”,别急着吐槽。

也许那正是一次技术人站出来“重新定义复杂”的好机会。


互动彩蛋:你被“简单”坑过的最惨一次,是啥?