困在绩效里的程序员们!
共 16636字,需浏览 34分钟
·
2024-05-05 10:36
👉导读
👉目录
01
1.1 收到请回复
案例1:同事 A 习惯性的不回复,他把沟通理解为单方向的消息通报,不仅自己这么做,且也认为别人可以这么做的,某次他在群里通知:“A DCache(注:一种存储服务) 要更换到 B DCache,这几个 IR(注:搜索召回平台) 的策略需要对应更改”。群里没有人回应他,而他也不觉得有问题,两个月后,线上业务还在访问 A DCache,而它已经下线,导致线上事故。他通知消息的群是一个小群,这几个 IR 策略的负责人都不在群里,群里的人都以为是其他人要负责跟进的,所以没有在群里响应,而同事 A 自己理解为:消息没有得到回复是正常的,我已经通知到位。这就是忽略沟通共识造成的事故,A 同事的沟通做法,也是一种推卸责任式通知:不管你们有没有收到,反正我是通知了,这是很不靠谱的行为。
案例2:同事 B 也有习惯性不回复的习惯,特别是在群聊中,并且认为别人也可以这么做。某次五一长假,他在群里通知五一值班安排,仅把消息贴到群里,并 @ 了多位负责人,但没有确认大家是否都回复,仅是看企业微信的“已读”,看到大家都已读,就认为大家都通知到了。后续某一天轮到同事 C 值班时,他没有做值班,导致线上告警没有人处理,造成事故。事后复盘时,同事 C 反馈没有收到通知,此时同事 B 无话可说,因为同事 C 确实没有回应确认他已经收到消息,同事 B 要负值班安排不到位导致事故的责任。
1.2 外部依赖的处理
1. 想清楚,沟通之前先想清楚你的诉求,思考是否全面,避免沟通过程浪费对方时间;
2. 礼貌沟通,譬如:
a. 说话之前先称呼对方,然后再描述要求,表达要有条理有逻辑; b. 如果是远程沟通,要及时回应对方的信息;沟通效率: 当面沟通 > 电话沟通 > IM 沟通 > 邮件沟通;
3. 时间节点,需要对方给出完成时间承诺;
4. 签字画押,确保大家意见统一之后,通过邮件或者讨论群将讨论结果同步;
5. 进度跟进,协议达成之后,接下来就是不定期地跟对方沟通,确保进展顺利,或者是将不顺利的影响面降到最低;
6. 上升反馈,当事情无法按承诺执行,并且跟你对接的同事也无法很好地处理时(沟通不顺、能力不济、信息不足...等等多个方面原因),需要跟双方的上级做反馈。上升反馈可能会给对接同事造成很大的压力,这可能会影响到与该同事的下一次顺畅沟通,所以上升反馈非必要不使用;
当你找对方要时间节点时,可能会遇到:“还不知道,需要评估”、“事情太多,不好说”等等类似的无法给出时间点的情况。怎么办呢? a. 一般人的做法:每天问一次,类似编程里的while死循环轮询,低效且让人烦躁。 b. 高效人士做法:让对方给出来什么时间点可以给出事情完成的时间点,类似编程里的事件通知,高效且有条理。
2. 外部依赖优先,在处理工作事项时,尽量优先处理有外部依赖的,因为这部分是最不可控的。
3. 最后,很重要的一点:即便你负责的是一个项目里的一小部分,你也需要知道整个项目的计划节奏,这有利于你做出更有全局观的决策。
1.3 应对紧急故障
1. 及时响应。首先,你告知反馈者消息我已经收到:“收到,我们看一下。”
2. 阶段性反馈。如果问题非常严重,你马上通过干预工具临时解决问题,然后再回复:“问题原因还在调查,我们先通过干预工具将问题临时解决,避免对用户造成更大伤害。”
3. 总结反馈。case 解决之后,你再回复:“case 已经解决,case 现象是......,case 原因是......,case 解决情况是......” 。
4. 转出。如果这个 case 你调查之后发现是其他人的问题,你应该把球传给他,并给他提供必要的信息帮助。
1. 看到反馈不管不顾:他大概没办法成为我们的同事。
2. 看到反馈之后:闷头干活,快速地修复 case,然后再到群里回复:“case 已经解决.....”。 做事无交代,大家都在干着急。
3. 看到反馈之后:马上回复“收到,我们看一下”,然后发现不是自己的问题,私下把问题丢给了另一位同事,导致大家一直不知道事情进展。做事无回音,大家都在干着急。
4. 这位同事及时响应,也阶段性反馈,但是最后总结反馈的时候,没有给反馈者一个合理的预期,譬如:什么时候解决 case?这里解决的是一个 case 还是一类 case?
1.4 如何组织多人会议
1.4.1 常见的错误
1. 临时起意,并且特别强调是某位领导参加的会议,未经预约的会议容易失败,也会给其他人的工作计划造成干扰
2. 没有日程,会议没有加入到参会者日程,导致参会者时间做了其他安排
3. 没有会议议题,导致参会者无法决策到底需不需要参加,可能会浪费大家时间
4. 只是例行的信息传递,写邮件或者文档即可搞定的
5. 会议修改通知不到位,会议议题、参会者、参会时间等信息的调整没有及时同步修改
6. 没做好参会人挑选和会议控场,导致参会者虽然参会了,但心不在会议上,坐在会议室里写代码或者刷手机
1.4.2 会前
(1)组织者自审
会议的目的是什么? 会议有哪些议题,分为几个阶段? 哪些人必须全程参与,哪些人只需要部分参与? 参会者需要准备什么? 会议是必须线下还是线上?是否需要预定会议室?
(2)组织者预约会议
1. 时间:没有提早发出会议预约;会议有多个主题,没有针对多个主题排时间;本次分享是否真的需要 1 个半小时? 2. 人物:哪些人需要参与?必要参会者混在一长串文本中,不利于参会者快速的了解到; 3. 议题:会议主题的表达没有条理逻辑,一长串的介绍内容混在一起,主题容易分散,不利于只想参加部分主题的参会者,参会者也没办法快速了解到他能获得什么; 4. 重点不突出:本次分享重点在于给大家介绍怎么高效的使用,“反馈、改进”之类的话跟本次分享无关,没必要提。
(3)提早发出会议材料
建议会议材料需要提早发出,可以填写在会议的描述中,也可以放到群聊的公告中。提早发出材料可以让参会者有时间先做阅读和思考,有利于缩短会议时间,特别是项目需求评审、技术方案评审的文档材料,应该提早发出,并提醒参会者先做文档批阅,可以大幅度提升评审效果和会议效率。
(4)会议调整
会议目的、议题、参与人、材料、时间、地点等任何可能影响到参会者的信息修改,都应该及时修改预约日程,并确保参会者收到信息。
1.4.3 会中
(1)参会人。组织者要确保必要参会人必须出席,同时也避免临时拉人入会。如果会中才发现某个关键环节缺少参会者,应该搁置该项讨论,待下次再约或者小范围约聊。也尽量在会前做好充足准备,避免在会议中才发现缺参与者。
(2)控场。组织需要做好控场,确保会议围绕主题展开,避免偏航、避免陷入某个细节导致浪费集体的会议时间。
(3)记录。组织者需要指定会议记录人,确保达成的结论和待办事项不会遗漏。
错误案例:
在会议中间发现缺少某位必要参会者,于是临时电话他入会。这会打断他的工作安排,很不礼貌,并且他没有提早做准备,可能参会效果不佳。
在多方参与的汇报会议上讨论技术细节、在排期 PK 会议上讨论需求实现细节等等。这些细节只需要少数人参与,应该在线下或者其他小型会议上对齐,避免浪费他人时间。
1.4.4 会后
会议结束后,记录者需要立刻总结并在沟通群中或者邮件发出会议纪要,内容包括:会议达成的结论、待办事项及其负责人等,同时应再次和参会者确认纪要文字内容无错误、无遗漏。
到此会议全流程就结束了,待办事项可能会在后续的会议中继续跟进,或者是线下逐个处理,不管是哪种方式,都需要有人执行、有人检查验收。
1.5 如何处理大量的沟通消息
我们有各种途径去找某位同事,我们也被各种途径触达。当面、电话、邮件、企业微信、微信,企业微信群里还有大量的群聊说着不同的事情。大量的沟通消息,我们既担心处理不及时,又不想写代码被频繁打断,还担心忘记答复,怎么办呢?
首先不要逃避消息轰炸,这是无法回避的,应该正视并接受这种状态,然后设计流程解决问题。下面这套流程供参考:
1.5.1 设定响应的频率
(1)需要立刻响应的:
- 当面,当面找到你,肯定需要立刻响应,但如果当时时间不允许,确认紧急程度后可以另约时间;
- 电话,打电话的一般是紧急情况,需要立刻响应;
- 微信,通常工作事项都在企业微信上沟通,如果微信找你,是紧急情况,需要立刻查看,但如果有些同事组建了沟通日常业务需求的微信群,则建议做通知屏蔽,然后定期查看;
(2)短周期定期检查的通讯工具:
企业微信和微信,定期检查沟通消息,如果可以马上答复处理的则马上处理,否则给对方答复表示消息收到,同时标记为待办。企业微信和微信的待办记录通常是置顶。
(3)每天检查数次的通迅工具:
邮件,邮件通常不是需要高优响应的信息,可以在每天的固定时间点处理,譬如:上午到工位时、下午干活之前、离开公司前。
1.5.2 记录待办事项和处理
1.5.3 邮件分类
1.6 避免低效率的追问式沟通
在协作过程中,我们经常遇到需要咨询别人或者答复别人的情况,不同水平的协作者在这里会表现出不同的特征。
例子 1:
A 向 项目负责人承诺完成某个需求,今天接近 deadline。
● 负责人:明天能不能完成需求?
● A :不能。
● 负责人:遇到什么困难了?还需要多久?
例子 2:
某天在群里聊到业务有异常。
● 负责人:服务有超时监控吗?
● A 回答:有。
● 负责人继续追问:超时了吗?
例子 3:
某天在群里聊到业务有异常。
● 负责人:服务有超时监控吗?
● A 回答:没有。
● 负责人继续追问:能加上吗?
分析:
- 例子 1 中,项目负责人的沟通诉求是:A 按期完成,如果不能按期完成,请给出一个合理的理由以及新的排期。
- 例子 2 和 例子 3 中:负责人的沟通诉求是:有超时监控,那就给出数据;没有超时监控,那应该给出能加上的监控时间。
- 上述 3 个例子,A 在首次回答时,就应该把对方的核心述求回应出来,让对方不需要在这个问题上再次提问。如果 A 不了解对方的核心诉求时,也可以在回答的同时做反问。
总结:
沟通过程中,需要多想一步:对方的诉求是什么,避免在一个简单问题上陷入不断追问的低效率沟通中,当无法满足对方诉求时,也应该给对方一个预期。
1.7 群聊的基本常识
1.7.1 大群和小群
1.7.2 群聊是集体沟通
很多人可能会说,谁不知道群聊是集体沟通呢?而据我观察,很多人并没有理解什么叫做“集体沟通”。举个例子:小 A 在群里问小 B 一个问题,小 B 觉得这个问题不适合在群里沟通,于是私聊小 A 解答,这时候群聊记录就停留在小 A 提问题,而没有人解答。按照“群聊是集体沟通”这个定义,小 B 应该在群聊中做出回应,譬如答复:“已私聊解决”。
群聊不只是沟通双方或者多方,还有大量的相关人在,为提高效率和避免误解,应当确保群聊信息是完整的。潜在的误解:“小 B 这人做事不靠谱,有人提问也不答复”、“这个问题我也关注,咋没有人答复,我再问一次”、“这个事情不重要,群里问题都没人解答”....
1.7.3 必要的总结陈述
你是否有遇到这种情况:某个群里聊了几十上百条聊天记录,他们好像达成了某个结论,或者暴露了某个问题,你想了解到底是什么,需要看几百条聊天记录。
突然被拉入到某个群里,附带了几十条聊天记录,拉你的人还说,“@xxx,看看这个问题”。你心里想,“卧槽,你就不能总结一下?”。这是不礼貌的行为,我说的是拉你进群的人。
对于沟通许久的群聊,建议做总结陈述,一方面确保沟通者意见一致,另一方面也让阅读者可以减少爬楼,提升效率。
1.7.4 有针对性的 @ 人
你有没有发现,当你 @all 的时候没有人理你,当你 @某个人 的时候,他才会答复你? 在大多数需要集体承担的场景都是如此,小时候上课时,老师提问,回答的志愿者总是稀缺甚至没有,点名是高效获得回答的解决办法。当你在群聊里想要高效获得答案时,@某个责任人 是最有效的,避免 @all。
1.8 在对抗中产出最佳决策
每个都在捍卫自己的目标,项目管理者要赶在 deadline 之前完成项目,开发者要确保做出高质量产品。
反面案例:
A:这个功能下周一必须上线
(B 知道这个功能至少要到下周五才能做完,但他还是答应了)
B:好的,我试试
下周一到了,功能带着很多 bug 上线,最终不得不回滚,给产品口碑造成伤害。这个案例合理的做法是,B 要尽力去争取更多的开发时间或者是功能做减法,而非简单地答应或者说“不”。
如果 B 轻易地答应,那么可能之前 B 的工时预估过于宽松,这是不靠谱的表现。但更可能的情况是 B 做出了错误的承诺,导致功能无法符合预期地上线。如果 B 粗暴地拒绝,又可能给人一种“不善协作”的标签,因此最合理的做法应该是结合工作计划(注:靠谱的程序员必须做工作计划),有理有据地给出拒绝理由,最终产品经理和工程师达成对产品最有力的协议,可能是功能做减法,也可能是另外约定一个上线时间。
1.9 基于事实的讨论
避免陷入偏执,辩论应该基于事实。我在做评审、需求沟通的时候,有时候会陷入长时间的讨论,很重要的一个原因是被评论者有了情绪,不是基于事实在做讨论,而是基于情感。
反面案例1:
代码评审人:这个成员变量应该在构造的时候就判断有效性,不应该在每一个成员函数里去判断空,这会有性能浪费。
代码开发者:防御编程,就应该判断空。
开发者不正面回应“性能浪费”这个关键点,转而引用不合适本场景的“原则”做诡辩,合理的讨论应该正面回应对方的论证,而不是回避对方的论证转而讨论其他。
反面案例2:
借用几年前的一个代码评审案例:
案例中的开发者明显有情绪,陷入了偏执。他没有正面回应评委提出的建议,反而去讨论无关紧要的笔误,以及后续进一步去讨论评委行为背后的动机,其实评委的动机很简单,就是为了让代码更好,开发者却认为评委在攻击他。我和你讲道理,你和我讲情感,没法聊。
反面案例3:
需求评审人:你要开发的这个需求,是真实的用户需求吗?有没有对用户的日志做分析?
需求提出者:还没有做分析,我作为一名资深的用户,有深刻的体会,这个需求做了一定有很大价值。
需求提出者在感性的表达需求的合理性,感性确实容易打动人心,但我们更希望看到基于数据的理性讨论,即便他说的是对的,也应该想办法在数字上能证明自己是对的。感情可以骗人,但数字不会,基于理性和数字,可以降低风险。
02
2.1 权利与责任
从你为产品写的第一行代码开始,你便是这个产品的创造者,这是权力也是责任。产品成功或者失败,都有你的一份功劳,靠谱的程序员从来不会让自己“置身事外”。
有时候,我们会看到一些推卸责任式的话语,“这是产品经理 A 要加的挽留用户弹窗”、“我们领导说要用 C++ 来写业务代码”...... 就好像在说:“这都是他们做的错误决策,和我没关系”,但你不发声就表示你认可这个方案,不能说都是他们的错误。靠谱的程序员会“置身事内”,他们会积极参与方案的决策讨论,他会表达自己不一样的想法,并在和其他人的辩论中,得到最佳方案。
大多数情况下,我们都有充分讨论的环境,如果充分讨论之后,无法通过逻辑推导达成共识,那么我们可以更完整的说:“我并不认同这个方案,但谁也无法说服谁,最后领导拍板决策,事实证明我的想法更合理。”
如果极端情况下,遇到无法讨论又频繁决策错误的“一言堂”团队,这样的团队不适合靠谱的程序员,应该尽快洞察到这一点并离开。
2.2 批判性思考
作为独立思考的创造者,在评审需求、架构、代码时,都会先自问一句:“它应该是这个样子吗?”,然后去思考它最合理的设计。下面举几个例子。
2.2.1 例子1:告警邮件的设计
在做搜索中台 XSearch 项目早期,我们的告警通过邮件发出(后来修改为企业微信群),当时离线系统开发同事设计了邮件告警,样例如下:
这个邮件告警的标题设计不合理。我们看邮件,首先看到的是标题,点击之后才看到内容。这个告警标题无法让阅读者快速得知是哪个业务有告警,我们服务了上百个业务,不同业务有不同的关注人,每个告警都需要点开之后才能看到是哪个业务,效率太低。修正后样例:
优化后的版本,看标题即可知道是哪个业务出了问题,且标题内容亦不会长到难以阅读。
2.2.2 例子2:监控看板的设计
我们为搜索中台 XSearch 设计了一个看板,可以直接展示历史存量数据,而实时数据则需要跳到 007 监控页面(现在的伽利略监控),我们决定在看板上增加一个跳 007 监控页面的快链。前端开发同事给的第一版样式如下:
操作步骤:
1. 鼠标移动到页面右侧
2. 点击“监控”快链
3. 鼠标移动到页面中间
4. 下拉选择“地区”
5. 鼠标往下移动几厘米
6. 点击 007 监控链接
这一系列操作时间不长,最终也能实现目标,但很繁琐,我们可以做得更简单。
优化后的样式:
优化后的操作步骤:
1. 鼠标移动到页面右侧
2. 点击地区快链
减少了用户多次鼠标点击和移动操作。这不仅仅是体验的优化,更是保持极致追求的态度。可以点击一次鼠标完成的事情,不要点击两次,即便是一秒钟的优化,也是值得的。
2.2.3 例子3:微服务和单体服务的思考
22年底,我们团队接手并重构一套经过多次交接的数据接入和处理系统,之前也在《腾讯云开发者》公众上分享过《微服务回归单体,代码行数减少75%,性能提升1300%》,这次重构最大的一个改造点是从微服务服务改造为单体服务。微服务设计这些年在后台系统架构上得到广泛应用,我们很容易去讲它的合理性,但也自问一句“忘记微服务和单体服务的斗争,我们系统这么设计是合理的吗?”,很快我们就联想到,我们老系统有大量的服务间数据一致性容灾处理,进一步还能想到一个需求拆分到多个服务去实现带来的人力消耗。最后我们判断,微服务带来的好处无法抵消它的代价,前人的设计是错误的,我们需要一个单体服务。
我们的设计也不是一次成型,最初开发同事给的新设计方案是两个服务,又经过一番批评性思考和讨论之后,大家才达成共识,只需要一个服务。
靠谱的程序员会捕捉心灵中稍纵即逝的叛逆,去思考它的本质,去解答它应该是什么样子。另外,还有一点需要注意,有时候:“自由思考比畅所欲言更重要。”——《黑客与画家》
2.3 系统性思考
作为考虑周全的创造者,我们在思考问题时,想到的是这个产品的方方面面,它能做什么、它由哪些组成、它的使用者是谁、它依赖了谁等等,系统性的考虑问题,看到的是一系列的问题点,这一个个“点”组成“面”。下面举几个例子。
2.3.1 例子1:我们给接口调用增加了重试
某同事 A 接手一套老系统,在完成系统串讲后,他在工作计划里列了很多项优化工作:
● 解决企业微信群的业务告警
● 数据处理从 20 分钟优化到 10分钟
● 接入代码规范和安全流水线,解决所有警告
● 接口调用增加失败重试
● ...
从串讲的 TODO 来看,确实需要做这些事情,但是总感觉哪里不对劲。譬如,为什么接口调用要增加失败重试?看起来是为了提高稳定性。那增加重试就能达到这个效果吗?看起来也不是,代码里的异常没有捕获,这也影响稳定性。只看到个别优化点,而无法全面的看待系统,是缺乏系统性思考的体现,这也是直觉这里不太对劲的原因。
系统性思考一般可以借鉴《金字塔原理》,先提出一个目标,然后基于目标思考需要做哪些事项,把事项穷举出来。以“接口调用增加失败重试”为例,这是一个事项,这个事项的目标是“提升稳定性”,因此我们最关键的目标应该定义为:提升稳定性,然后基于提升稳定性穷举出要做的事项,调整如下:
提升系统稳定性,事项拆解如下:
○ 接口调用增加失败重试
○ 代码内增加异常捕获防御
○ 接入 CI 流水线,修复代码规范和代码安全警告
○ ...
上述的例子是从某个事项抽象到目标,然后再从目标穷举事项。有时候有经验的我们也可以直接正向推导,后台系统不外乎:功能、成本、性能、效率、稳定性这些点,把它们映射到自己的系统上做穷举。
2.3.2 例子2:客户需要一匹更快的马
某天我在评审团队同事个人工作计划的时候,发现有一个需求:利用多线程加速数据处理。我很奇怪,这个业务索引量很少,每半小时全量重算一次,每次只需要20分钟,为什么要做加速呢?仔细咨询后才知道,因为有两个反馈:
(1)产品经理反馈,数据处理太慢了,导致他给某游戏配置的同义词、标签等干预不能及时在线上生效;
(2)合作伙伴反馈,数据处理太慢了,导致他配置的某游戏实时字段(一些活动信息)需要 60 分钟才能在线上生效;
总的来说,我们的协作方都在反馈数据处理太慢,导致干预不能及时生效。因此,我们的一线开发同事就去分析为什么慢,最终得到优化思路:多个计算任务之间并行实现加速 50%。于是就制定多线程优化计划。
这是一个典型的“浮于表面”分析需求的案例,和“客户要一匹更快的马”类似,实际上协作方想要的是干预更快生效,而不是数据处理更快,数据处理更快是实现目标的手段之一,但不是完整方案,我们只负责数据处理环节,数据到上线生效还有一系列的上线流程,只优化个别流程并不能很好的达到目标,并且协作方的本质诉求是个别数据的修改能更快生效,而不是他们嘴里说的“数据处理更快”。这个需求,我们应该是基于“怎么让个别数据修改能更快生效”这个本质诉求,去分析全链路所有流程,才能寻找到最佳的解法。
2.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 来做数据传输。
客户提出来的解决方案,未必是最佳方案,我们应该深入的和对方聊聊,他做出这个设计的缘由,而不是对方说要什么就是什么,单方面的信息是有限的,更多的信息汇聚才能产生最合适的方案。
03
尽管我期望本文可以为读者讲解什么是靠谱的程序员,但每个的人遭遇不尽相同,在成为靠谱程序员的路上,很容易有各种困惑,除了请教导师,还可以阅读一些书籍,下面推荐一些我阅读过觉得不错,且适合所有程序员的书籍:
编程知识:《重构-改善既有代码的设计》
软件工程:《Google 软件工程》、《持续交付2.0》
沟通表达:《金字塔原理》、《一本小小的红色写作书》
时间管理:《高效能人士的七个习惯》、《卓有成效的管理者》
元知识:《程序员修炼之道:通向务实的最高境界》(注:第一版也不错)、《程序员的职业素养》、《黑客与画家》
-End-