【旧文】如何成为一名靠谱的程序员

本文从 2019 年开始编写,并最终于 2024.01 成文并发布在公司内网,同期转载于 腾讯云开发者公众号、腾讯大讲堂公众号、个人公众号。


(本插图为 2026.09.29 新生成)

1. 不靠谱程序员案例

1.1. 虚假的交付

十多年前,我们在做一款播放器软件,两周一个迭代对外发布新版本,开发的排期由技术负责人把控,时间压得很紧。某位刚加入没多久的新同事承接了几个富文本窗口的开发,他在承接需求之前并没有彻底的熟悉代码,他也不是经验丰富的开发者,deadline 将近,他把这些需求都从开发中挪到了测试中,交给测试做验收。后面测试同事发现了很多低级的 bug,甚至是有些功能没有实现,这位开发同事,连自测都没做,当然大家也没有去追究他写出太多有 bug 的代码,测试同事也例行的提 bug 单,等待修复后做回归测试。

现在仍然可以看到部分同事在降低完成标准,为了赶在 deadline 之前完成,他把完成定义为代码开发完成,而不是服务发版本或者 app 上线。

1.2. 随意的承诺

五六年前,我们在做一款搜索产品,有一段时间要把视频内容也加到搜索结果里,有一位同事抽调去负责这块业务的后台实现,项目两周一个迭代,每次需求排期由开发者给时间计划,但产品同事总是期望能更快的上线,于是需求排期经常变成时间倒排排期,这位同事很愿意看到产品变好,也很有激情,每次都答应了,而为了达成目标,他经常早点 9 点半上班,晚上 10 点半下班,周末也经常加班,即便如此,还是经常因为 bug 众多而导致上线延期或者线上业务出事故,考核的时候也拿了一个较低的绩效。

1.3. 推卸责任式的通知

几年前,我们使用的存储介质要做合并降本,A 存储实例的调用需要切换到 B 存储实例,负责切换的同事在一个沟通群里同步了切换时间,然后在时间到的时候将实例缩容下线,但下线的时候还有很多调用者并没有切换走,这导致了业务事故,切换同事说这不是我导致的,我已经通知了,被影响的使用者说我没有收到通知。协作中,我们把工作传给下一位负责人时,需要确保他接住了工作,而不是把工作丢出去,不管对方有没有接到。

1.4. 组织浪费多人时间的会议

某位同事组织了一场会议用来讨论某个大方向的一系列需求,有前端的、后台工程的、后台策略的,把大家都邀请到了会议室,在聊到某个需求的时候,他和后台开发在会议上讨论需求的合理性,聊了一个多小时,而其他人都在边上无聊的刷手机。

1.5. 重要事故不向上反馈

某天我们负责的关键服务突然出现故障,导致线上部分请求无法正常返回结果,负责值班的同事收到告警后马上投入处理,过去了几个小时,一直无法解决,产品同事也在体验时发现了业务故障,马上通知到产品负责人和技术负责人,技术负责人立刻电话值班的同事了解情况,此时才知道故障已经发生了几个小时,马上组织更多的人力做排查处理。

1.6. 延期不提前预警

我们团队对客户承诺要投入 30 人日,在 1 月 10 号交付某个复杂的大功能,到了 1 月 9 号的时候,做开发的同事向项目管理同事反馈 1 月 10 号完成不了,预计需要延期到 1 月 30 号。

1.7. 遗漏工作和疏忽大意

我们有一个服务业务团队的老系统要下线,项目负责人安排小 A 负责推进业务团队做迁移改造。 周一: 负责人:你本周的工作计划遗漏老系统下线,需要跟进下。

小 A:我和业务团队的开发小 B 沟通了,他说要问一下他们的领导,我们后面继续跟进。

负责人:小 B 有说什么时候能给答复吗?

小 A:小 B 好像有紧急告警在处理,他说本周会问他们的领导,我这周晚点再问。

负责人:不急,但需要有明确的时间节奏。

周三:

负责人:时间点有了吗?

小 A:还没,我问问。

(数小时之后)

小 A:小 B 说本周五才能和他的领导对齐改造节奏。

(这次沟通完,中间过了一个假期,然后小 A 把这件事情忘记了,直到一周之后)
一周之后: 负责人:没看到结论反馈,这里的进展怎么样?

小 A:(丢出一个文档)这里有排期,他们会做迁移。

负责人:符合我们预期吗?

小 A:他们把流量迁移完,我们的老服务就可以下线,符合预期,6 月中旬完成。

(负责人看完文档之后)

负责人:"无其他业务需求时做支持,预计 6 月中旬完成",整个承诺还带有附属条件,我们不能认为他们一定会在 6 月中完成业务迁移,应该要和他们再次确认,给出可以完成的时间点。

这里例子中,小 A 有几个问题:

  • 遗忘工作事项,需要负责人多次提醒

  • 在沟通进度的过程中,陷入追问模式,无法抓住要点回答

  • 他和业务团队对排期有明显的理解 gap:他以为 6 月中旬可以完成,实际上对方说的是没有其他需求的情况下才能 6 月中旬完成,对方给的这个承诺不需要负承诺责任,如果延期了,他们可以说:我说过了,没有业务需求才能这个时间完成,最近我们有业务需求。业务团队实际上没有给出确切的排期,这会威胁到我们团队的目标达成。

类似的例子还有很多,我们总是会不经意的掉入各种坑里,不经意的促成某个不靠谱的结果,怎么避开陷阱,建设一个高效可依赖的个人品牌,是本文的核心目标。

2. 你的目标

作为组织的一员,我们的第一个评估指标必然是组织目标的完成情况,如果没有合适的目标,完成更无从谈起。靠谱的程序员,每周在做工作计划的时候,都要问自己一句,我的目标是什么,我在完成我的目标吗?如果不明确,应该和你的领导聊聊。

3. 计划与执行

很多年前我在一个小型 feature team 做一款新产品的时候,隔壁小组的小 A 每周都很忙碌,其他人晚上 9 点下班,他经常要忙到 11 点,不止是两周一个迭代的需求很多,还因为今天修改需求 1,明天插入需求 2,为了产品能快速占领市场,他觉得都能做,至于技术基建改造,通通往后排,毕竟业务需求更重要。需求堆积越来越多,bug 也越来越多,迭代也越来越慢,基建优化更是从来都排不上时间,怎么办呢,只能更疯狂的加班,但效果并没有更好,需求不断的延期,线上 case 频发,直到他转岗。

这个故事暴露出来很多问题,譬如,产品经理应该想清楚需求,不要临时修改;项目管理应该守住两周一个迭代的规则,提高需求变更的成本;小 A 的领导应该帮助小 A 拦住突发需求,或者安排更多的人力支持;小 A 应该拒绝插入需求,给技术基建改造预留时间。这里我们聚焦在小 A 个人身上,他应该怎么办?他应该说"不",那他怎么有底气说"不",底气不是蛮横的拒绝,而是来自有理有据的规划分析,这就是计划与执行复盘。

制定计划并做执行复盘,是我多年来的工作习惯,很多人也会这么做,每周一开始工作之前,制定本周 40 小时的工作计划,为每一项工作安排若干小时,并在本周结束的时候复盘时间的实际投入情况,吸取经验时间预估的教训。经过长期的<计划-复盘>训练,你在预估工作耗时会更有经验,同时,因为你做计划时的深思熟虑,会让你在拒绝插入工作时,更有底气。

最近几年,我带领的团队都采用周计划和执行复盘的模式做自我时间管理。我们也知道,信息透明能让团队更有战斗力,我们团队每一个人的本周工作计划都写在公开的 iwiki(腾讯内部文档沉淀系统)上。

4. 需求讨论

这些年互联网公司的研发流程已演进得非常的规范。早些年的各种段子,日常中很少碰到,譬如: 1. 这个需求很简单,怎么实现我不管

2. 需求明细我没有,你照着竞品抄

3. 你先开始写代码,需求单我后面给你补

4. 写了一半的需求,又改了!

...

这些案例几乎绝迹。如果你日常中碰到了这些段子,建议和做项目管理同事(也可能是团队领导)聊聊,把项目流程定下来。还有一种例外情况,你们的小团队正关在一间小屋子里封闭开发做 MVP(最小化可实行产品),此时第一要务是造出产品样例,变化是常态,倒也不必追求标准的研发流程。
在开始写代码之前,通常会有一个需求讨论,这里有四点需要重点关注:讨论前的准备、理解需求的本意、确认和对齐、评估工作量。

4.1. 讨论前的准备

我们会要求讨论之前必须先有需求讨论稿,并且讨论稿要提前一天发出给大家做文字评审,缩短会议时间,这对参会者提出了较高的要求,也可以剔除掉非必要的参会者,以及让发起讨论的人能先理清逻辑。如果要讨论一个业务需求,但业务负责人却不能把要做的事情有逻辑的写清楚,那么说明他自己也没想清楚,此时不应该发起和开发者的讨论。如果团队里经常做无稿的需求讨论,靠谱的程序员应该抵制并提出抗议。总之,靠谱的程序员会在会议之前先阅读讨论稿并给出必要的评论。

4.2. 理解需求的本意

靠谱的程序员,不是需求的被动承接者,他们会从产品的本质去思考问题,会仔细想对方的需求是否合理,是否考虑周全,他是需要一匹更快的马,还是更快到达目的地的交通工具?如果是更快的马,那么我们应该挖掘更好的马,但如果是更快的到达目的地,我们应该发明汽车。

我曾经遇到一个需求,合作的业务团队给我们反馈,说我们的离线计算任务太慢了,应该加速一下,仔细聊下来,发现他们的诉求是数据干预生效太慢,因为当前数据干预依赖离线计算任务,所以他才提出要让离线计算任务做得更快,这个需求后面我们通过让数据干预不依赖离线计算任务,单独走一条数据流解决,实现思路上更合理,效果也更好。总之,靠谱的程序员热爱思考会挖掘需求背后的原因,给出更好的解决方案。

4.3. 确认和对齐

有时候我们会经历一场激烈的辩论,辩论到最后大伙都精疲力尽,期望能早点结束,终于开发和产品,上游和下游达成一致,会议结束,大家终于可以去吃饭。等到了联调或者是验收的时候,却发现 A 说达成的方案是这样,B 说达成的方案是那样。

为了避免这样的情况发生,我们讨论达成的结论,务必"白纸黑字"写到需求稿中。一方面是文字表达比口头表达更容易避免漏洞;另一方面是需要参与讨论者确认,避免事后不认账。

4.4. 评估工作量

我们通常在会议的结尾会被要求给出工时和排期,如果你之前已经做过很详细的分析工作,此时可以直接给出,但如果不是,建议仔细拆解需求后再给出。工时预估其实是一种猜测,而合作者们会把这个猜测当成你做出的承诺,能不能做到"承诺必达",这是一个关乎你个人品牌的大事。

虽然过去的工作经验可以参考,但我们从来不会遇到一模一样的需求,我们能做的就是把影响因素考虑得更详细一些,为可能有风险的地方多预留一些时间。某个数据接入的需求估 2 天工时,是这么考虑的:

1. 数据来自另一个团队,他们需要开发新接口把数据传给我,涉及协议定制、代码开发、双方联调;我们可以先把协议对齐,然后两边用假数据并行开发,最后约定一个联调时间;这里预估 4 小时用来沟通协议和开发数据接入代码,4 小时用来联调接口;
2. 数据使用者要求对数据做简单的变换处理,譬如:把标题和内容拼到一起、给文档 id 加一个前缀,这部分需要在插件工厂里写一个处理插件,代码比较简单,预估 2 小时开发,4 小时代码评审;
3. 数据处理完后需要发送到消息中间件,供使用者订阅,我们有现成的配置化插件,只需要在业务 meta 配置里添加一段描述即可,预留 1 小时做配置; 4. 上线,我们有成熟的持续发布(CD)流程,预留 1 小时;
我们把事项拆到小时粒度,同时为有外部依赖的事项预留较长的时间,看起来很合理。但即便如此,我们仍然有可能出现意外,譬如: 1. 合作方采用一种我们从没用过的新协议,调研新技术用了 2 天;
2. 虽然只有几十行代码,但是代码质量很差,导师给我做了三轮代码评审才通过,用了 1 天;
3. 需要写数据说明文档,详细描述数据有哪些字段,以方便众多使用者,用了 0.5 天;

看到了吧,一个看起来很简单的小需求,我们考虑了很多细节(但不是所有细节),仍然有可能出现遗漏,所以一定要给自己足够的时间去全盘的拆解问题。有几点经验之谈:

  • 把大需求拆小,小到能以小时预估,拆小可以看得更透彻;
  • 一天以 8 小时或者 6 小时算工作时间,不要算上你的加班时间;
  • 不要在一段时间内并行做 N 个需求,需求之间切换有损耗,容易预估不准;
  • 预留 buffer 时间,可以是在你预估的时间上,再乘上一个系数,系数可能是 2 也可能是 1.3,你通过<计划-执行>来得到你的系数;

讲了很多工时预估过短的风险,你可能会有取巧的想法:那我就预估得长一些,譬如,改一行代码预估一周工时。这很难做到,技术管理者会关注工作安排的合理性,这伎俩很快就会被发现,而且在一个实干的团队里,这种做法会被其他正直的同事排斥。

总之,靠谱的程序员不会随便给出承诺,给出了承诺就一定会做到,他们会仔细的做需求评估,避免让自己陷入困境,但总有意外,也许需要每天工作 12 个小时,也许需要节假日都加班,但这都不重要,因为靠谱的程序员承诺必达。

5. 编写代码

5.1. 编码之前

在写代码之前,应先熟悉团队的研发流程,譬如,有些团队要求先通过代码规范和安全考试,否则代码无法合入仓库主干。大多数团队也会有从研发到版本上线的全套 CICD(持续集成持续发布)流程。还有,要看看团队给大家推荐的研发工具,至少会包括代码规范配套的自动格式化工具。

5.2. 注意事项

在编码之前你做了充足的准备,实际写好代码,还有一些规则需要遵守。

(1)大范围的修改需要多周知

原则上,我们将代码拆分得足够细,减少大范围的修改代码。但有时候大范围修改不可避免,譬如代码大重构,这种修改量很大,需要周知其他同事后,选择合适的时间,避免出现大量 merge 冲突。

(2)在需求开发中逐步重构

一个函数原来只有一个小功能,后来逐步的增加功能,变成了一个有若干个功能的 100+ 行大函数,当你又做一个新的需求,需要改动到这个函数时,必须对这个函数进行拆分。这样做带来几个好处:

  • 后来开发者(可能也是你)可以更快的增加功能,保持敏捷;
  • 代码结构更清晰,不容易隐藏 bug;

(3)写好单元测试

很多开发者不愿在需求开发中逐步重构,很大的原因是怕改出问题,而单元测试可以让你修改代码时更安全。写好单元测试也可以帮助开发者提早发现 bug,避免 bug 在代码评审、上线后才发现,bug 数永远不可能等于零,但靠谱的开发者会想办法让它无限接近零。"失误率永远不可能等于零,但你有责任让它无限接近零。"------《程序员的职业素养》。

(4)代码里的 TODO

我们经常会在代码中看到躺了几个月、几年的 TODO,建议不要轻易的写 TODO,如果一定要写,请给它定一个期限。写之前问自己一句,我真的会安排时间来修改吗?很多时候,我们只是求个心理安慰,今天不去完成它,以后也不太可能会来修改,垃圾会慢慢堆积,直到不可收拾。

"如果你说有空闲时间才去做,意味着你可能永远都不会做。"------《程序员修炼之道-通向务实的最高境界》

(5)持续的练习

写代码是一项专业技能,它需要学习才能获得,初级程序员经过一段时间的练习才能上岗,并且行业在持续的演进,为了跟上趋势,为了更娴熟,靠谱的程序员还需要不断训练,就好像赛场上的运动员,最优秀的运动员除了天赋,勤勉更不可少。

做练习是很多程序员容易忽略的点,他们更喜欢在实际工作项目中尝试新的编程语法,而不是提前做几个练习,相比因循守旧不敢使用新语法的伙伴,他们算是不错了,但还可以做得更好。譬如,安排一些做练习的时间,提升自己的技能,这和工作无关,纯粹是在磨练自己的编程技艺,靠谱的程序员会更负责的对待自己的职业生涯。

6. 代码评审

代码评审是建设个人品牌的好时机,并且这样的机会非常多。其他人会看到你的代码,然后在心里给你打上一些标签:质量很好几乎看不出来问题;很一般,还需要继续提升;太粗心了,有很多低级错误;乱七八糟,都写的啥,浪费时间......

靠谱的程序员会很重视代码评审,避免给他人造成麻烦,也避免损害自己的品牌形象。通常会严格执行团队里"CR 前的 checklist"规范,直到自己不能发现错误,才把代码评审单发给评审人。在评审过程中,也会注意和评审人沟通,而不是一味的接受或者一味的反驳。

刚开始接受代码评审的人,可能会有抵触心理,他们把代码视作自己,把对代码的批评视作对自己的批评,因而无法客观的对待,容易陷入无意义的辩论,靠谱的程序员会感谢指出代码错误的人,而不是抵触。如果你指出他人的代码不合理,他却对你"咆哮",建议在组织层面寻求共识,这样的事情在鹅厂也并不少见。

7. 文档编写

写技术文档是开发者的义务,它和写可读代码一样重要,它也可以体现个人做事态度、逻辑思考能力。

7.1. 核心原则

文档是给人阅读的,因此第一要务是面向读者,让读者高效的获得信息,这是文档写作的核心原则。为达成这个目标,通常会有一些关键词,譬如:准确、完整、简洁。

(1)准确

文档里不应该出现错误的信息,譬如,在一个申请上线的评审文档里,把收入增长数据写错了,这会误导读者。

(2)完整

文档的信息需要完整,譬如,写一个算法性能评测文档,但却没有给出评测是在什么设备上做的,采用了什么数据。

(3)简洁

文档内容应该聚焦在主题上,避免发散,避免主次不分,不同类型的文档有不同的风格。譬如,

  • 汇报总结类的文档,通常建议采用《金字塔原理》,最重要的结论信息放在最前面,以上统下结论先行,读者可以先看到结论,然后再评估是否有必要阅读细节。譬如,新系统的性能压测文档,通常会把压测结论放在前面,后面的段落才介绍压测背景细节。
  • 项目评审类的文档,通常建议开篇先介绍为什么要做这个项目,然后再按照<总-分>的思路介绍项目。譬如,我们写项目技术方案评审,通常在第一章量化的介绍目标,让读者可以第一时间看到项目的价值。

固定的文档格式,可以让我们文档的样式看起来有模有样,但这还不够,还应该注意一些基础写作常识,以及精简意识。譬如:反例:

上述的反例违背多个写作常识:随意分段、前后不连贯、文字拖沓啰嗦。修正:

7.2. 规范和培训

团队通常会有一些文档写作规范,譬如我们团队有《技术文档编写建议》,通常也会有一些培训,譬如 PCG 有"知行"课程《像管理代码一样管理技术文档》,建议充分阅读。

8. 沟通协作

沟通占据我们完成目标的大部分时间,沟通需求、反馈进度、总结进展等等。下面介绍一些常见场景的处理经验。

8.1. 收到请回复

收到请回复,这是一个关乎个人品牌建设的大事。收到消息及时回复是职场人的共识,如果你收到消息不回复,容易给对方造成误解,一旦你养成习惯,也容易在与人沟通上出现理解偏差。企业微信有已读功能,当你已读却不回复消息时,容易给人造成无视、忽略的误解。你可以关掉这个功能,但读消息必回复的习惯建议养成并保持,也建议开启这个功能,并塑造及时回复的形象。

下面举两个对共识无认知,造成事故的负面案例:

案例1:同事 A 习惯性的不回复,他把沟通理解为单方向的消息通报,不仅自己这么做,且也认为别人可以这么做的,某次他在群里通知:"A DCache(注:一种存储服务) 要更换到 B DCache,这几个 IR(注:搜索召回平台) 的策略需要对应更改"。群里没有人回应他,而他也不觉得有问题,两个月后,线上业务还在访问 A DCache,而它已经下线,导致线上事故。他通知消息的群是一个小群,这几个 IR 策略的负责人都不在群里,群里的人都以为是其他人要负责跟进的,所以没有在群里响应,而同事 A 自己理解为:消息没有得到回复是正常的,我已经通知到位。这就是忽略沟通共识造成的事故,A 同事的沟通做法,也是一种推卸责任式通知:不管你们有没有收到,反正我是通知了,这是很不靠谱的行为。

案例2:同事 B 也有习惯性不回复的习惯,特别是在群聊中,并且认为别人也可以这么做。某次五一长假,他在群里通知五一值班安排,仅把消息贴到群里,并 @ 了多位负责人,但没有确认大家是否都回复,仅是看企业微信的"已读",看到大家都已读,就认为大家都通知到了。后续某一天轮到同事 C 值班时,他没有做值班,导致线上告警没有人处理,造成事故。事后复盘时,同事 C 反馈没有收到通知,此时同事 B 无话可说,因为同事 C 确实没有回应确认他已经收到消息,同事 B 要负值班安排不到位导致事故的责任。

8.2. 外部依赖的处理

当你依赖外部同事帮你完成某个功能、或者你负责一个大项目的某一块时,你需要了解项目的全貌,需要主驱动去跟对方沟通、跟进。
有几个沟通的原则: 1. 想清楚,沟通之前先想清楚你的诉求,思考是否全面,避免沟通过程浪费对方时间;

2. 礼貌沟通,譬如:

  • 说话之前先称呼对方,然后再描述要求,表达要有条理有逻辑;
  • 如果是远程沟通,要及时回应对方的信息;沟通效率: 当面沟通 > 电话沟通 > IM沟通 > 邮件沟通;

3. 时间节点,需要对方给出完成时间承诺;
4. 签字画押,确保大家意见统一之后,通过邮件或者讨论群将讨论结果同步;
5. 进度跟进,协议达成之后,接下来就是不定期的跟对方沟通,确保进展顺利,或者是将不顺利的影响面降到最低;
6. 上升反馈,当事情无法按承诺执行,并且跟你对接的同事也无法很好的处理时(沟通不顺、能力不济、信息不足...等等多个方面原因),需要跟双方的上级做反馈。上升反馈可能会给对接同事造成很大的压力,这可能会影响到与该同事的下一次顺畅沟通,所以上升反馈非必要不使用;

一些常识:

1. 当你找对方要时间节点时,可能会遇到:"还不知道,需要评估"、"事情太多,不好说"等等类似的无法给出时间点的情况。怎么办呢?

  • 一般人的做法:每天问一次,类似编程里的 while 死循环轮询,低效且让人烦躁。

  • 高效人士做法:让对方给出来什么时间点可以给出事情完成的时间点,类似编程里的事件通知,高效且有条理。

2. 外部依赖优先,在处理工作事项时,尽量优先处理有外部依赖的,因为这部分是最不可控的。

3. 最后,很重要的一点:即便你负责的是一个项目里的一小部分,你也需要知道整个项目的计划节奏,这有利于你做出更有全局观的决策。

8.3. 应对紧急故障

紧急故障并不少见,如何成熟的处理,也是个人品牌建设的重点。同事在业务群里反馈你负责的某个业务出了故障。靠谱的反应是这样的: 1. 及时响应。首先,你告知反馈者消息我已经收到:"收到,我们看一下。" 2. 阶段性反馈。如果问题非常严重,你马上通过干预工具临时解决问题,然后再回复:"问题原因还在调查,我们先通过干预工具将问题临时解决,避免对用户造成更大伤害。" 3. 总结反馈。case 解决之后,你再回复:"case 已经解决,case 现象是......,case 原因是......,case 解决情况是......" 。 4. 转出。如果这个 case 你调查之后发现是其他人的问题,你应该把球传给他,并给他提供必要的信息帮助。
一位不靠谱的同事他的表现可能是这样子: 1. 看到反馈不管不顾:他大概没办法成为我们的同事。

2. 看到反馈之后:闷头干活,快速的修复 case,然后再到群里回复:"case 已经解决....."。做事无交代,大家都在干着急。
3. 看到反馈之后:马上回复"收到,我们看一下",然后发现不是自己的问题,私下把问题丢给了另一位同事,导致大家一直不知道事情进展。做事无回音,大家都在干着急。
4. 这位同事及时响应,也阶段性反馈,但是最后总结反馈的时候,没有给反馈者一个合理的预期,譬如:什么时候解决 case?这里解决的是一个 case 还是一类 case?

8.4. 如何组织多人会议

8.4.1. 常见的错误

在日常工作中,经常见到一些不专业的会议组织者,使得会议难以成行或者效率低下。会议组织者常见的错误包括: 1. 临时起意,并且特别强调是某位领导参加的会议,未经预约的会议容易失败,也会给其他人的工作计划造成干扰

2. 没有日程,会议没有加入到参会者日程,导致参会者时间做了其他安排
3. 没有会议议题,导致参会者无法决策到底需不需要参加,可能会浪费大家时间
4. 只是例行的信息传递,写邮件或者文档即可搞定的
5. 会议修改通知不到位,会议议题、参会者、参会时间等信息的调整没有及时同步修改
6. 没做好参会人挑选和会议控场,导致参会者虽然参会了,但心不在会议上,坐在会议室里写代码或者刷手机

8.4.2. 会前

(1)组织者自审

会议组织者首先需要想清楚会议的目的是什么,是否一定要开会才能解决,会议有哪些议题,能否分阶段,哪些人需要参与,是否需要全程参与,参与需要提前准备什么事情,是否可以先做文档评审 等等。明确这些信息之后,发起会议预约,并把会议的关键信息给出。自审要点: 会议的目的是什么?

会议有哪些议题,分为几个阶段?
哪些人必须全程参与,哪些人只需要部分参与?
参会者需要准备什么?
会议是必须线下还是线上?是否需要预订会议室?

(2)组织者预约会议

组织者通常需要先拉起沟通群,沟通群方便信息的快速同步,然后再做会议预约。预约信息包括:时间、地点、人物、议题、参会者需做的准备。

不同类型的会议,在给参会者传递会议信息上有不同的侧重点,对于知识分享类会议,应该突出"参会者能获得什么 ";对于工作协同类会议,应该突出"参会者对项目有重大影响 "。特别注意"参会者需做的准备 "这一点,如果需要参会者先做文档评审,那么预约的会议时间需要在文档发出后,预留 1~2 天时间。在预约大家的会议时间时,应先参考参会者的日程表,给出几个可选的时间让大家选择,避免询问"大家什么时候有空",甚至有时候可以先占住大家的日程表空闲时间,然后再询问是否可行。下面举一个会议预约做得不够好的例子:

会议预约邮件错误示范:

错误的地方:

1. 时间:没有提早发出会议预约;会议有多个主题,没有针对多个主题排时间;本次分享是否真的需要 1 个半小时?
2. 人物:哪些人需要参与?必要参会者混在一长串文本中,不利于参会者快速的了解到;
3. 议题:会议主题的表达没有条理逻辑,一长串的介绍内容混在一起,主题容易分散,不利于只想参加部分主题的参会者,参会者也没办法快速了解到他能获得什么;
4. 重点不突出:本次分享重点在于给大家介绍怎么高效的使用,"反馈、改进"之类的话跟本次分享无关,没必要提。

会议预约邮件修正示范:

注:现在大家习惯用企业微信的日程预约,预约信息可以填写到会议的"描述"中。

(3)提早发出会议材料

建议会议材料需要提早发出,可以填写在会议的描述中,也可以放到群聊的公告中。提早发出材料可以让参会者有时间先做阅读和思考,有利于缩短会议时间,特别是项目需求评审、技术方案评审的文档材料,应该提早发出,并提醒参会者先做文档批阅,可以大幅度提升评审效果和会议效率。

(4)会议调整

会议目的、议题、参与人、材料、时间、地点等任何可能影响到参会者的信息修改,都应该及时修改预约日程,并确保参会者收到信息。

8.4.3. 会中

(1)参会人。组织者要确保必要参会人必须出席,同时也避免临时拉人入会。如果会中才发现某个关键环节缺少参会者,应该搁置该项讨论,待下次再约或者小范围约聊。也尽量在会前做好充足准备,避免在会议中才发现缺参与者。
(2)控场。组织需要做好控场,确保会议围绕主题展开,避免偏航、避免陷入某个细节导致浪费集体的会议时间。
(3)记录。组织者需要指定会议记录人,确保达成的结论和待办事项不会遗漏。
错误案例:

  • 在会议中间发现缺少某位必要参会者,于是临时电话他入会。这会打断他的工作安排,很不礼貌,并且他没有提早做准备,可能参会效果不佳。
  • 在多方参与的汇报会议上讨论技术细节、在排期 PK 会议上讨论需求实现细节等等。这些细节只需要少数人参与,应该在线下或者其他小型会议上对齐,避免浪费他人时间。

8.4.4. 会后

会议结束后,记录者需要立刻总结并在沟通群中或者邮件发出会议纪要,内容包括:会议达成的结论、待办事项及其负责人等,同时应再次和参会者确认纪要文字内容无错误、无遗漏。

到此会议全流程就结束了,待办事项可能会在后续的会议中继续跟进,或者是线下逐个处理,不管是哪种方式,都需要有人执行、有人检查验收。

8.5. 如何处理大量的沟通消息

我们有各种途径去找某位同事,我们也被各种途径触达。当面、电话、邮件、企业微信、微信,企业微信群里还有大量的群聊说着不同的事情。大量的沟通消息,我们既担心处理不及时,又不想写代码被频繁打断,还担心忘记答复,怎么办呢?

首先不要逃避消息轰炸,这是无法回避的,应该正视并接受这种状态,然后设计流程解决问题。下面这套流程供参考:

8.5.1. 设定响应的频率

(1)需要立刻响应的:

  • 当面,当面找到你,肯定需要立刻响应,但如果当时时间不允许,确认紧急程度后可以另约时间;
  • 电话,打电话的一般是紧急情况,需要立刻响应;
  • 微信,通常工作事项都在企业微信上沟通,如果微信找你,是紧急情况,需要立刻查看,但如果有些同事组建了沟通日常业务需求的微信群,则建议做通知屏蔽,然后定期查看;

(2)短周期定期检查的通讯工具:

企业微信和微信,定期检查沟通消息,如果可以马上答复处理的则马上处理,否则给对方答复表示消息收到,同时标记为待办。企业微信和微信的待办记录通常是置顶。

(3)每天检查数次的通迅工具:

邮件,邮件通常不是需要高优响应的信息,可以在每天的固定时间点处理,譬如:上午到工位时、下午干活之前、离开公司前。

8.5.2. 记录待办事项和处理

如果是企业微信,待办事项可以置顶,如果是其他途径的待办,可以记录到工作日志文档中。前面的《计划与执行》章节建议写个人工作日志,既用来复盘计划与执行,也可以用来记录待办事项,待办事项需要及时处理,避免企业微信置顶过多,全都置顶就相当于没有置顶,建议待办事项做到日清、周清。

8.5.3. 邮件分类

虽然大家更喜欢用 IM 做沟通,但每天的各类通知邮件还是有不少,有些需要重点关注,有些则可忽略,建议建邮件过滤规则,将邮件分类,譬如:组织架构调整邮件、表彰邮件、告警邮件、工蜂通知邮件、OA 系统邮件 等等。

8.6. 避免低效率的追问式沟通

在协作过程中,我们经常遇到需要咨询别人或者答复别人的情况,不同水平的协作者在这里会表现出不同的特征。

例子 1:

A 向 项目负责人承诺完成某个需求,今天接近 deadline。

● 负责人:明天能不能完成需求?
● A :不能。
● 负责人:遇到什么困难了?还需要多久?

例子 2:

某天在群里聊到业务有异常。

● 负责人:服务有超时监控吗?
● A 回答:有。
● 负责人继续追问:超时了吗?

例子 3:
某天在群里聊到业务有异常。 ● 负责人:服务有超时监控吗?

● A 回答:没有。
● 负责人继续追问:能加上吗?
分析:

  • 例子 1 中,项目负责人的沟通诉求是:A 按期完成,如果不能按期完成,请给出一个合理的理由以及新的排期。
  • 例子 2 和 例子 3 中:负责人的沟通诉求是:有超时监控,那就给出数据;没有超时监控,那应该给出能加上的监控时间。
  • 上述 3 个例子,A 在首次回答时,就应该把对方的核心述求回应出来,让对方不需要在这个问题上再次提问。如果 A 不了解对方的核心诉求时,也可以在回答的同时做反问。

总结:
沟通过程中,需要多想一步:对方的诉求是什么,避免在一个简单问题上陷入不断追问的低效率沟通中,当无法满足对方诉求时,也应该给对方一个预期。

8.7. 群聊的基本常识

大家经常会在群里沟通,我介绍一些沟通的常识。

8.7.1. 大群和小群

群聊的一个重要用途是信息广播,当有多个小群时,容易导致信息广播遗漏,譬如:作为"数据中介"的团队,一方面要对接合作方的数据源,一方面要分发给下游的数据应用团队,如果要拉一个上下游信息同步的沟通群,应该把多方都拉到一起,确保有一个可以全流程在线沟通的群聊环境。而当要单独聊一些技术细节时,则建议在开发小群中沟通,避免对其他不需要关注的人造成打扰。

8.7.2. 群聊是集体沟通

很多人可能会说,谁不知道群聊是集体沟通呢?而据我观察,很多人并没有理解什么叫做"集体沟通"。举个例子:小 A 在群里问小 B 一个问题,小 B 觉得这个问题不适合在群里沟通,于是私聊小 A 解答,这时候群聊记录就停留在小 A 提问题,而没有人解答。按照"群聊是集体沟通"这个定义,小 B 应该在群聊中做出回应,譬如答复:"已私聊解决"。

群聊不只是沟通双方或者多方,还有大量的相关人在,为提高效率和避免误解,应当确保群聊信息是完整的。潜在的误解:"小 B 这人做事不靠谱,有人提问也不答复"、"这个问题我也关注,咋没有人答复,我再问一次"、"这个事情不重要,群里问题都没人解答"....

8.7.3. 必要的总结陈述

你是否有遇到这种情况:某个群里聊了几十上百条聊天记录,他们好像达成了某个结论,或者暴露了某个问题,你想了解到底是什么,需要看几百条聊天记录。

突然被拉入到某个群里,附带了几十条聊天记录,拉你的人还说,"@xxx,看看这个问题"。你心里想,"卧槽,你就不能总结一下?"。这是不礼貌的行为,我说的是拉你进群的人。

对于沟通许久的群聊,建议做总结陈述,一方面确保沟通者意见一致,另一方面也让阅读者可以减少爬楼,提升效率。

8.7.4. 有针对性的 @ 人

你有没有发现,当你 @all 的时候没有人理你,当你 @某个人 的时候,他才会答复你?在大多数需要集体承担的场景都是如此,小时候上课时,老师提问,回答的志愿者总是稀缺甚至没有,点名是高效获得回答的解决办法。当你在群聊里想要高效获得答案时,@某个责任人 是最有效的,避免 @all。

8.8. 在对抗中产出最佳决策

每个都在捍卫自己的目标,项目管理者要赶在 deadline 之前完成项目,开发者要确保做出高质量产品。

反面案例:

A:这个功能下周一必须上线
(B 知道这个功能至少要到下周五才能做完,但他还是答应了)
B:好的,我试试

下周一到了,功能带着很多 bug 上线,最终不得不回滚,给产品口碑造成伤害。这个案例合理的做法是,B 要尽力去争取更多的开发时间或者是功能做减法,而非简单的答应或者说"不"。

如果 B 轻易的答应,那么可能之前 B 的工时预估过于宽松,这是不靠谱的表现。但更可能的情况是 B 做出了错误的承诺,导致功能无法符合预期的上线。如果 B 粗暴的拒绝,又可能给人一种"不善协作"的标签,因此最合理的做法应该是结合工作计划(注:靠谱的程序员必须做工作计划),有理有据的给出拒绝理由,最终产品经理和工程师达成对产品最有力的协议,可能是功能做减法,也可能是另外约定一个上线时间。

8.9. 基于事实的讨论

避免陷入偏执,辩论应该基于事实。我在做评审、需求沟通的时候,有时候会陷入长时间的讨论,很重要的一个原因是被评论者有了情绪,不是基于事实在做讨论,而是基于情感。

反面案例1:

代码评审人:这个成员变量应该在构造的时候就判断有效性,不应该在每一个成员函数里去判断空,这会有性能浪费。
代码开发者:防御编程,就应该判断空。

开发者不正面回应"性能浪费"这个关键点,转而引用不合适本场景的"原则"做诡辩,合理的讨论应该正面回应对方的论证,而不是回避对方的论证转而讨论其他。

反面案例2:

借用几年前的一个代码评审案例:

案例中的开发者明显有情绪,陷入了偏执。他没有正面回应评委提出的建议,反而去讨论无关紧要的笔误,以及后续进一步去讨论评委行为背后的动机,其实评委的动机很简单,就是为了让代码更好,开发者却认为评委在攻击他。我和你讲道理,你和我讲情感,没法聊。

反面案例3:

需求评审人:你要开发的这个需求,是真实的用户需求吗?有没有对用户的日志做分析?
需求提出者:还没有做分析,我作为一名资深的用户,有深刻的体会,这个需求做了一定有很大价值。

需求提出者在感性的表达需求的合理性,感性确实容易打动人心,但我们更希望看到基于数据的理性讨论,即便他说的是对的,也应该想办法在数字上能证明自己是对的。感情可以骗人,但数字不会,基于理性和数字,可以降低风险。

9. 独立思考

9.1. 权利与责任

从你为产品写的第一行代码开始,你便是这个产品的创造者,这是权力也是责任。产品成功或者失败,都有你的一份功劳,靠谱的程序员从来不会让自己"置身事外"。

有时候,我们会看到一些推卸责任式的话语,"这是产品经理 A 要加的挽留用户弹窗"、"我们领导说要用 C++ 来写业务代码"...... 就好像在说:"这都是他们做的错误决策,和我没关系",但你不发声就表示你认可这个方案,不能说都是他们的错误。靠谱的程序员会"置身事内",他们会积极参与方案的决策讨论,他会表达自己不一样的想法,并在和其他人的辩论中,得到最佳方案。

大多数情况下,我们都有充分讨论的环境,如果充分讨论之后,无法通过逻辑推导达成共识,那么我们可以更完整的说:"我并不认同这个方案,但谁也无法说服谁,最后领导拍板决策,事实证明我的想法更合理。"

如果极端情况下,遇到无法讨论又频繁决策错误的"一言堂"团队,这样的团队不适合靠谱的程序员,应该尽快洞察到这一点并离开。

9.2. 批判性思考

作为独立思考的创造者,在评审需求、架构、代码时,都会先自问一句:"它应该是这个样子吗?",然后去思考它最合理的设计。下面举几个例子。

9.2.1. 例子1:告警邮件的设计

在做搜索中台 XSearch 项目早期,我们的告警通过邮件发出(后来修改为企业微信群),当时离线系统开发同事设计了邮件告警,样例如下:

这个邮件告警的标题设计不合理。我们看邮件,首先看到的是标题,点击之后才看到内容。这个告警标题无法让阅读者快速得知是哪个业务有告警,我们服务了上百个业务,不同业务有不同的关注人,每个告警都需要点开之后才能看到是哪个业务,效率太低。

修正后样例:

优化后的版本,看标题即可知道是哪个业务出了问题,且标题内容亦不会长到难以阅读。

9.2.2. 例子2:监控看板的设计

我们为搜索中台 XSearch 设计了一个看板,可以直接展示历史存量数据,而实时数据则需要跳到 007 监控页面(现在的伽利略监控),我们决定在看板上增加一个跳 007 监控页面的快链。前端开发同事给的第一版样式如下:

操作步骤:

1. 鼠标移动到页面右侧
2. 点击"监控"快链
3. 鼠标移动到页面中间
4. 下拉选择"地区"
5. 鼠标往下移动几厘米
6. 点击 007 监控链接

这一系列操作时间不长,最终也能实现目标,但很繁琐,我们可以做得更简单。

优化后的样式:

优化后的操作步骤:

1. 鼠标移动到页面右侧
2. 点击地区快链

减少了用户多次鼠标点击和移动操作。这不仅仅是体验的优化,更是保持极致追求的态度。可以点击一次鼠标完成的事情,不要点击两次,即便是一秒钟的优化,也是值得的。

9.2.3. 例子3:微服务和单体服务的思考

22年底,我们团队接手并重构一套经过多次交接的数据接入和处理系统,之前也在《腾讯云开发者》公众号上分享过《微服务回归单体,代码行数减少75%,性能提升1300%》,这次重构最大的一个改造点是从微服务服务改造为单体服务。微服务设计这些年在后台系统架构上得到广泛应用,我们很容易去讲它的合理性,但也自问一句"忘记微服务和单体服务的斗争,我们系统这么设计是合理的吗?",很快我们就联想到,我们老系统有大量的服务间数据一致性容灾处理,进一步还能想到一个需求拆分到多个服务去实现带来的人力消耗。最后我们判断,微服务带来的好处无法抵消它的代价,前人的设计是错误的,我们需要一个单体服务。

我们的设计也不是一次成型,最初开发同事给的新设计方案是两个服务,又经过一番批评性思考和讨论之后,大家才达成共识,只需要一个服务。

靠谱的程序员会捕捉心灵中稍纵即逝的叛逆,去思考它的本质,去解答它应该是什么样子。另外,还有一点需要注意,有时候:"自由思考比畅所欲言更重要。"------《黑客与画家》

9.3. 系统性思考

作为考虑周全的创造者,我们在思考问题时,想到的是这个产品的方方面面,它能做什么、它由哪些组成、它的使用者是谁、它依赖了谁等等,系统性的考虑问题,看到的是一系列的问题点,这一个个"点"组成"面"。下面举几个例子。

9.3.1. 例子1:我们给接口调用增加了重试

某同事 A 接手一套老系统,在完成系统串讲后,他在工作计划里列了很多项优化工作:

● 解决企业微信群的业务告警
● 数据处理从 20 分钟优化到 10分钟
● 接入代码规范和安全流水线,解决所有警告
● 接口调用增加失败重试
● ...

从串讲的 TODO 来看,确实需要做这些事情,但是总感觉哪里不对劲。譬如,为什么接口调用要增加失败重试?看起来是为了提高稳定性。那增加重试就能达到这个效果吗?看起来也不是,代码里的异常没有捕获,这也影响稳定性。只看到个别优化点,而无法全面的看待系统,是缺乏系统性思考的体现,这也是直觉这里不太对劲的原因。

系统性思考一般可以借鉴《金字塔原理》,先提出一个目标,然后基于目标思考需要做哪些事项,把事项穷举出来。以"接口调用增加失败重试"为例,这是一个事项,这个事项的目标是"提升稳定性",因此我们最关键的目标应该定义为:提升稳定性,然后基于提升稳定性穷举出要做的事项,调整如下:

提升系统稳定性,事项拆解如下:

○ 接口调用增加失败重试
○ 代码内增加异常捕获防御
○ 接入 CI 流水线,修复代码规范和代码安全警告
○ ...

上述的例子是从某个事项抽象到目标,然后再从目标穷举事项。有时候有经验的我们也可以直接正向推导,后台系统不外乎:功能、成本、性能、效率、稳定性这些点,把它们映射到自己的系统上做穷举。

9.3.2. 例子2:客户需要一匹更快的马

某天我在评审团队同事个人工作计划的时候,发现有一个需求:利用多线程加速数据处理。我很奇怪,这个业务索引量很少,每半小时全量重算一次,每次只需要 20 分钟,为什么要做加速呢?仔细咨询后才知道,因为有两个反馈:

(1)产品经理反馈,数据处理太慢了,导致他给某游戏配置的同义词、标签等干预不能及时在线上生效;

(2)合作伙伴反馈,数据处理太慢了,导致他配置的某游戏实时字段(一些活动信息)需要 60 分钟才能在线上生效;

总的来说,我们的协作方都在反馈数据处理太慢,导致干预不能及时生效。因此,我们的一线开发同事就去分析为什么慢,最终得到优化思路:多个计算任务之间并行实现加速 50%。于是就制定多线程优化计划。

这是一个典型的"浮于表面"分析需求的案例,和"客户要一匹更快的马"类似,实际上协作方想要的是干预更快生效,而不是数据处理更快,数据处理更快是实现目标的手段之一,但不是完整方案,我们只负责数据处理环节,数据到上线生效还有一系列的上线流程,只优化个别流程并不能很好的达到目标,并且协作方的本质诉求是个别数据的修改能更快生效,而不是他们嘴里说的"数据处理更快"。这个需求,我们应该是基于"怎么让个别数据修改能更快生效"这个本质诉求,去分析全链路所有流程,才能寻找到最佳的解法。

9.3.3. 例子3:客户认为离线批量数据传输用 RPC 接口更好

我们团队负责外部数据的接入和处理,并将处理后的数据存放到 COS(云对象存储)上,由使用方拉取。某天新的使用团队建议我们提供 RPC(远程过程调用) 接口,理由是 COS 用起来不方便,而 RPC 接口更灵活。我们负责对接的同事小 A,想了下觉得批量数据用 RPC 提供不方便,于是退而求其次,建议通过 mysql 提供数据。

客户希望用 RPC,而小 A 评估后发现 RPC 很难实现,所以他建议用 mysql。看起来好像很合乎技术方案 PK 的常见做法,大家都退一步,选择一个双方都能接受的方案。实际上是这样吗?

客户为什么会认为 COS 不方便,为什么会认为 RPC 接口更适合来传输批量数据?小 A 没有深入了解,便轻率的接受了客户"COS 不方便"的结论,进而去思考满足客户诉求的其他方案,这也是缺乏独立思考、缺乏系统性思考的体现。

我们和客户进一步深入沟通之后,才了解到:

1. 他们团队较少使用 COS,而 RPC 接口用的很多,他们对外提供的检索服务也是采用 RPC 接口实现的;
2. 他们认为 COS 需要做数据完整性校验,相比 RPC 接口工作量较大。

看起来不是 COS 不好,而是业务团队用得不习惯,我们再进一步分析使用 RPC 接口或者 mysql 存储的不利:

1. 使用 RPC 接口来传递批量数据,需要考虑数据分页,而分页之后进一步需要考虑数据版本,需要做不少容错保护,复杂度较高
2. 使用 mysql 来传递批量数据,在新老数据版本上也需要做较多工作,要么是数据按版本分表;要么是在一个表里增加一个版本号信息,然后需要处理同时读写出现的资源竞争。总的来说,也有一定的复杂度

相对来说,用 COS 来存储批量数据,复杂度是最低的,最后我们还是继续采用 COS 来做数据传输。

客户提出来的解决方案,未必是最佳方案,我们应该深入的和对方聊聊,他做出这个设计的缘由,而不是对方说要什么就是什么,单方面的信息是有限的,更多的信息汇聚才能产生最合适的方案。

10. 推荐阅读

尽管我期望本文可以为读者讲解什么是靠谱的程序员,但每个的人遭遇不尽相同,在成为靠谱程序员的路上,很容易有各种困惑,除了请教导师,还可以阅读一些书籍,下面推荐一些我阅读过觉得不错,且适合所有程序员的书籍:

  1. 编程知识:《重构-改善既有代码的设计》
  2. 软件工程:《Google软件工程》、《持续交付2.0》
  3. 沟通表达:《金字塔原理》、《一本小小的红色写作书》
  4. 时间管理:《高效能人士的七个习惯》、《卓有成效的管理者》
  5. 元知识:《程序员修炼之道:通向务实的最高境界》(注:第一版也不错)、《程序员的职业素养》、《黑客与画家》

本文所在:https://www.cnblogs.com/cswuyg/p/23154823