第十章 暗战
一
入职第四个月,王志远遇到了一个大机会。
公司拿下了一个重要客户——一家连锁零售企业,需要在现有系统上做一套"会员积分体系"。这个项目是季度重点,周旋经理亲自盯,做好了整个团队都有奖金。
赵北辰在 Sprint Planning 会上分配任务时,把积分体系的核心模块——"积分规则引擎"——交给了王志远。
"志远,这个模块有一定复杂度,但我觉得你现在可以独立搞定。"赵北辰说。"先出设计文档,我来 Review。"
王志远既兴奋又紧张。这是他入职以来接到的最重要的任务。
他花了三天时间做调研和设计。积分规则引擎的核心需求是:不同的消费场景(线上购物、线下门店、会员日活动等)有不同的积分计算规则,而且规则会经常变化——比如"双十一期间积分翻倍"、"新会员首单三倍积分"。
他设计了一个基于策略模式的规则引擎:每种积分规则是一个策略类,实现统一的 PointRule 接口;规则的配置存在数据库里,可以动态加载和切换,不需要改代码就能调整规则。
他把设计文档写好,发了邮件给赵北辰,抄送了周旋和李想。邮件标题是:
【设计文档】会员积分规则引擎 - 技术方案 v1.0 — 王志远
赵北辰 Review 后提了几条小意见,改完之后设计通过了。
二
接下来的一周,王志远埋头编码。他按照设计文档一步步实现,先写测试再写代码,进展顺利。
周三下午,他去茶水间倒水的时候,听到了一段对话。
是陈锐和周旋在小会议室里说话,门没关严。
"……周总,积分规则引擎这块,我有一些想法。"陈锐的声音。
"哦?说说看。"周旋的声音。
"我觉得可以用规则引擎框架来做,比如 Drools。比自己写策略模式灵活多了,规则可以用 DSL 配置,业务人员都能改,不需要开发介入。我画了一个方案……"
王志远端着杯子站在门外,心里咯噔了一下。
他没有偷听——他只是路过。但他听到的内容让他很不舒服。
陈锐在跟经理单独汇报积分规则引擎的"替代方案",而这个模块是分配给他的。陈锐没有在组内讨论,没有在设计评审上提出,而是私下找经理。
他端着水回到了工位上,心里很乱。
三
第二天的站会上,周旋突然说了一句:"积分规则引擎这块,陈锐提了一个用 Drools 的方案,我觉得挺有意思的。志远,你看看能不能结合一下?"
王志远愣了一下。
陈锐在旁边接话:"我昨天跟周总聊了一下,觉得 Drools 比纯策略模式更灵活。我写了一个简单的 POC,可以给大家看看。"
他打开笔记本电脑,展示了一个用 Drools 实现的积分规则 demo。规则用 DRL 文件配置,确实看起来很灵活——业务人员可以直接修改规则文件,不需要改 Java 代码。
周旋看了连连点头:"不错不错,这个方案好。志远,你觉得呢?"
王志远张了张嘴,想说"我的方案也能做到动态配置",但话到嘴边又咽了回去。他不想在站会上跟陈锐争论——那样显得他在争功。
"我回去看看。"他说。
站会结束后,他回到工位上,心里五味杂陈。
他花了三天做的设计,被陈锐用一个下午的 POC 抢了风头。更让他难受的是,陈锐的方案确实有亮点——Drools 的规则 DSL 确实比他的策略模式更灵活。但陈锐的做法让他很不舒服——不在组内讨论,私下找经理,用"我的方案"来包装一个替代方案。
这不是技术讨论,这是抢功。
四
中午吃饭的时候,林秀秀看出了他的心事。
"怎么了?脸色不太好。"
王志远犹豫了一下,把事情简单说了。他没有说陈锐的名字,只是说"有个同事提了一个替代方案,经理很认可"。
林秀秀听完,想了想说:"你觉得他的方案比你的好吗?"
"……有些地方确实更灵活。但他的做法不对。"
"做法不对是一回事,方案好不好是另一回事。"林秀秀说。"如果他的方案确实有可取之处,你可以吸收好的部分,让你的方案更完善。至于做法的问题……你的实力大家都看在眼里。"
王志远看着她,觉得这个行政部的姑娘有时候比他这个程序员看问题更清楚。
"但我还是很委屈。"他老实说。
"委屈是正常的。"林秀秀笑了笑。"但委屈不能当饭吃。你得想办法保护自己。"
五
下午,王志远去找了赵北辰。
赵北辰听完,沉默了一会儿,然后说:"陈锐这个人,技术不差,但做事的方式有问题。不过这件事,你也有需要反思的地方。"
"我哪里做得不对?"
"你的设计文档发邮件的时候,抄送了我和周旋、李想。但你有没有在组内做过正式的设计评审?"
王志远想了想:"没有。你 Review 完我就开始写代码了。"
"这就是问题。"赵北辰说。"你的设计只有我看过,其他人不知道你的方案细节。陈锐提了一个替代方案,周旋没有对比的基础,自然觉得陈锐的方案'挺有意思'。如果你之前在组内做了设计评审,大家都了解你的方案,陈锐再提替代方案的时候,大家就能做出公正的比较。"
"另外,"赵北辰继续说,"技术人要学会保护自己的成果。邮件确认、文档留痕、版本记录——这些不是多余的,是必要的。你的设计文档有版本号吗?有修改记录吗?"
"有版本号,v1.0。但没有修改记录。"
"加上。每次修改都记录:谁改的、什么时候改的、改了什么。这样将来有争议的时候,版本记录就是证据。"
赵北辰看着他,语气认真了一些:"志远,吃一堑长一智。职场不是学校,不是你做得好就一定有人看到。你得学会让自己的成果摆在明面上——不是显摆,是让大家都知道。"
六
王志远回到工位上,做了几件事。
第一,他在设计文档里加了修改记录表:
| 版本 | 日期 | 修改人 | 修改内容 |
|---|---|---|---|
| v1.0 | 3/15 | 王志远 | 初稿 |
| v1.1 | 3/16 | 王志远 | 根据赵北辰 Review 意见修改 |
第二,他约了一个组内设计评审会,把自己的方案和陈锐的 Drools 方案放在一起做了一个对比分析:
| 维度 | 策略模式方案 | Drools 方案 |
|---|---|---|
| 灵活性 | 中等,新规则需要写 Java 类 | 高,规则用 DRL 文件配置 |
| 学习成本 | 低,团队都熟悉 | 高,需要学习 Drools DSL |
| 维护成本 | 低,纯 Java 代码 | 中等,DRL 文件调试困难 |
| 性能 | 高,直接 Java 调用 | 中等,规则引擎有解析开销 |
| 依赖 | 无外部依赖 | 引入 Drools 框架(~15MB) |
| 适用场景 | 规则数量有限、变化不频繁 | 规则数量多、变化频繁 |
他在对比表下面写了自己的结论:
当前积分规则约 5-8 种,变化频率约每季度一次。策略模式方案足以满足需求,且学习成本和维护成本更低。建议采用策略模式方案,同时预留扩展点——如果将来规则数量超过 20 种或变化频率达到每周一次,再考虑引入 Drools。
第三,他把对比分析发了邮件,抄送全组。
七
设计评审会上,王志远把两个方案都讲了一遍。
他没有贬低陈锐的方案,而是客观地分析了两者的优缺点。他甚至主动说:"陈锐的 Drools 方案在规则灵活性上确实更强,如果将来业务复杂度上升,这是一个值得考虑的方向。"
陈锐坐在角落里,表情有点复杂。他大概没想到王志远会这么大度。
苏薇第一个发言:"我同意志远的分析。当前的业务场景用策略模式就够了,引入 Drools 是过度设计。而且 Drools 的 DRL 文件调试起来很痛苦,我之前在上一家公司用过,踩了不少坑。"
马德华说:"我也觉得策略模式简单,好维护。"
赵北辰总结:"两个方案都有道理,但要根据当前的实际需求来选择。志远的分析很到位——先用简单方案解决当前问题,预留扩展点应对未来变化。这就是 YAGNI 原则——You Aren't Gonna Need It,不要提前实现将来可能用到的功能。"
他看了一眼陈锐:"陈锐的 Drools 调研也有价值,可以作为技术储备。但下次有替代方案,建议先在组内讨论,不要直接找经理。技术决策应该在技术团队内部达成共识。"
陈锐的脸微微红了一下,点了点头,没说话。
周旋在旁边听着,若有所思。
八
评审会结束后,周旋把王志远叫到了办公室。
"志远,你那个对比分析写得不错。"周旋说。"以后重要的技术决策,都按这个标准来——有对比、有数据、有结论。"
"好的,周总。"
"另外,"周旋顿了一下,"积分规则引擎这个模块,还是你来负责。按你的方案来。"
王志远点了点头。
走出办公室的时候,他心里松了一口气。但他知道,这件事没有真正结束——陈锐不会因为一次评审就改变做事的方式。
九
转机来得比他预想的快。
一周后,周旋在周会上让陈锐汇报积分体系的另一个模块——"积分商城"的技术方案。陈锐之前主动请缨要做这个模块,周旋同意了。
陈锐打开 PPT,讲了十分钟。方案看起来很完整——架构图、流程图、技术选型,一应俱全。
周旋听完,问了一个问题:"积分兑换的时候,如果用户的积分余额不足,但同时有一笔积分正在入账(比如刚完成一笔订单),这种并发场景怎么处理?"
陈锐愣了一下:"这个……可以用数据库锁。"
"什么锁?行锁还是表锁?乐观锁还是悲观锁?"
"呃……悲观锁。"
"悲观锁在高并发场景下性能怎么样?如果双十一期间有几万人同时兑换积分呢?"
陈锐的额头开始冒汗:"可以……可以用 Redis 做分布式锁。"
"Redis 锁的过期时间怎么设?如果持有锁的进程崩溃了怎么办?"
陈锐答不上来了。
会议室里安静了几秒。苏薇在旁边冷冷地说了一句:"内部设计文档的版本记录里写得很清楚,这个方案的初始版本是上周三创建的,只有一个版本,没有任何修改记录。也就是说,这个方案没有经过任何 Review 和迭代。"
她的意思很明显——陈锐的方案是赶工出来的,没有经过深入思考。
周旋的脸色不太好看。他没有当众批评陈锐,但说了一句:"方案回去再想想,下周重新评审。技术方案不是 PPT,要经得起追问。"
十
会后,王志远在走廊里遇到了陈锐。
陈锐的表情很难看。他看了王志远一眼,欲言又止,最后什么都没说,转身走了。
王志远看着他的背影,心里没有幸灾乐祸的感觉。他想起自己第一次 Sprint Review 上被陈锐追问线程池配置的场景——那种答不上来的窘迫,他太熟悉了。
他回到工位上,打开邮箱,给陈锐发了一封邮件:
标题:关于积分商城的并发处理方案
陈锐,
关于周总问的并发场景,我之前在做通知中心的时候研究过类似的问题。积分余额的并发控制,可以考虑用"乐观锁 + 重试"的方案——在积分表加一个 version 字段,更新时带上 version 条件,如果更新失败说明有并发冲突,自动重试。这种方案在中等并发场景下性能比悲观锁好很多。
如果并发量特别大(比如双十一),可以考虑用 Redis 做预扣减——先在 Redis 里扣积分,成功后再异步更新数据库。这样数据库的压力会小很多。
这只是我的一些想法,供参考。如果需要讨论,随时找我。
王志远
他发完邮件,犹豫了一下,又抄送给了赵北辰。
赵北辰的话在他脑子里回响:"邮件确认、文档留痕。"
不是为了邀功,是为了留痕。
十一
那天晚上,王志远在笔记本上写下:
Day 120
吃一堑长一智。这一堑吃得值。
职场不是象牙塔,做得好不一定会被看到。邮件确认、文档留痕、设计评审公开做——这些不是多余的,是必要的自我保护。以前觉得"酒香不怕巷子深",现在觉得这话害人不浅。
给陈锐发了那封邮件,承认他的方案里有可取之处。不知道他会怎么想,但我觉得这是对的。技术人之间,应该用技术说话,不是用手段。
格局比技术重要。这话说起来容易,做起来真难。
他合上笔记本,想起林秀秀说的那句话:"你的实力大家都看在眼里。"
他不确定"大家"是不是真的都看在眼里。但他确定,自己的实力在一天天增长。
而实力,是别人抢不走的东西。
:::{admonition} 小胖的笔记 :class: tip
本章知识卡片:职场沟通与文档化习惯
1. 保护技术成果的方法
| 方法 | 具体做法 | 作用 |
|---|---|---|
| 邮件确认 | 重要决策发邮件,抄送相关人 | 留下书面记录 |
| 文档版本记录 | 每次修改记录:谁、何时、改了什么 | 证明原创性和迭代过程 |
| 公开评审 | 设计方案在组内公开评审 | 提高透明度,减少信息不对称 |
| Git 提交记录 | 规范的 commit 信息 | 代码归属可追溯 |
| 会议纪要 | 重要会议后发纪要邮件 | 确认共识,避免事后扯皮 |
2. 技术方案对比分析模板
做技术选型时,用表格对比多个方案:
| 维度 | 方案 A | 方案 B |
|---|---|---|
| 功能满足度 | ||
| 学习成本 | ||
| 维护成本 | ||
| 性能 | ||
| 外部依赖 | ||
| 社区活跃度 | ||
| 团队熟悉度 | ||
| 适用场景 |
结论:基于以上对比,推荐方案 X,理由是……
3. YAGNI 原则
You Aren't Gonna Need It — 不要提前实现将来可能用到的功能。
做: - ✅ 解决当前已知的问题 - ✅ 预留扩展点(接口、配置) - ✅ 记录未来可能的演进方向
不做: - ❌ 为"将来可能需要"的场景写代码 - ❌ 引入当前不需要的框架 - ❌ 过度设计(Over-engineering)
4. 积分系统并发控制方案
| 方案 | 原理 | 适用场景 | 优缺点 |
|---|---|---|---|
| 悲观锁 | SELECT ... FOR UPDATE |
低并发 | 简单但性能差 |
| 乐观锁 | version 字段 + 重试 | 中等并发 | 性能好,需处理重试 |
| Redis 预扣减 | 先扣 Redis,异步更新 DB | 高并发 | 性能最好,需保证最终一致性 |
5. 职场沟通原则
- 对事不对人:讨论方案优劣,不攻击提出方案的人
- 用数据说话:对比分析要有具体的维度和依据
- 大方承认:对手的方案有可取之处,要公开认可
- 透明沟通:技术决策在团队内公开讨论,不搞小动作
- 留有余地:给对方台阶下,不要赶尽杀绝
:::