题目所述,就是我最近很久一段时间都在用来思考的问题。
先说下个人的背景,目前已经毕业三年,第一年主要做前端开发,大约在两年前,我的主要精力从前端转向了 Rust,而后又开始在公司参与开发 c++。
在这三年里面,自己持续面临着一个问题,这个问题就是,如何从一个繁忙而重复的工作中,持续提升自己的技术深度。
因为我发现,当在一个公司久了以后,随着参与的业务增多,问题和 OnCall 也随之增多,另外随着你对业务的熟悉,会有越来越多的新同学向你问问题。处理这些问题会占据越来越多的精力。当然,如果你比较“幸运”中途业务黄掉或架构彻底变化了,你去参与新的项目,有可能能获得一次接近重新开始的机会,但大多数时候,你可能都没有这么幸运。
当这些问题处理的久了以后,你会发现甚至连完成工作都需要加班来解决,就更没有时间来进行技术的提升了,长此以往,焦虑感便倍增。
不过,最近我在思考这些问题的过程中,也渐渐总结了一些缓解的办法,接下来便和大家进行分享。
这里的核心点在于,减少犯错误的机会,提高处理问题的效率,释放出自己的更多时间
1. 提高对代码的要求,写更好的代码
我最近处理的众多问题,粗略估算,有大约 1/3 都是由于开发者代码水平不足带来的技术债务(即代码逻辑错误、边界情况未考虑、性能与稳定性不足等)。
我这里主要针对的是 PC 客户端,还有很多问题和特殊机器、其他模块干扰项、硬件驱动等关系密切,如果是纯前端项目,这个比例只会更高。
因为写代码的时候,并没有采用最合理的方式,导致有出现问题的隐患,如果你的问题出现的概率比较高,大概率会比较幸运地较早发现,但如果出现的概率低,甚至灰度阶段都没有暴露,那么当初几行代码的问题,会让自己之后花加倍的时间来去处理,甚至还可能面临更多后果。
那么,如何让自己写出更好的代码呢,我认为可以做到以下几点:
- 请熟读文档,比如如果是在开发 Vue 项目,那么请至少把 Vue 的文档看一遍,React 同理,这样你会更加清楚,框架到底提供了那些能力,什么时候使用更合适的 API 来完成一个目标。
- 注重注释,对于一些特殊处理的情况,注释是很有必要的,最好附上文档,否则可能时间久了,自己都不知道为什么这样去处理,会让修复问题花费更多的时间。
- 除非迫不得已,不要提交带有已知优化项的代码,例如重复代码并没有完全处理、代码在某些情况还可能造成问题。时间允许的情况下,一步到位,通常比分两次到位能节约更多的时间,至少能节约一次测试的时间,另外大脑的上下文切换还有开销。
- CI/CD 的建设,保证合并的代码是能够编译的。
- 对于前端来说,全部采用 Typescript,使用 ESLint 约束代码,禁止直接使用 JavaScript。
- 团队需要建立 Review 机制,并且对 Review 过程负责。对于别人提交 Review 的代码至少需要通读一遍,避免基本的错误。
2. 日志是语言的另一面,也很能体现代码水平
这里的日志,指的是在用户使用过程中,实时上传的的或者离线的日志。
这里单独提一点日志,是因为在实际中,我们大约有一半时间在写代码,而另外一半时间在查问题,那么为什么就不能好好写日志呢?
“日志不足/没打日志,需要加日志进一步定位”。
不知道你在 OnCall 的过程中,是否遇到过此类回复,当然并不能说每次这样的问题都是开发者水平不足导致日志不全,但的确有很多情况是我们可以提前规避的。
那么一个好的日志应该是什么样的呢?
- 前提:废话不要多,能简写就简写,这是因为一般日志都是存在用户本地的,日志量比较大的情况下会影响用户的硬盘占用,当然日志本身的打印也是消耗 CPU 的。
- 关键路径的日志要有,可能出问题的地方不要存在侥幸心理,把日志打全,特别是不同负责模块之间衔接的日志,一定打全,这样之后甩锅的时候有实锤也会方便一点。
- 关键日志需要有关键字,方便后面自动化分析,毕竟,对于一个比较完善的项目而言,机器人分析日志甚至比人分析更为靠谱。
- 日志也需要向前兼容,最好不要对以前的日志进行改动,这点我们可能通常会忽略,如果没有必要,建议不要对日志进行大的变动,防止自动化工具和其他分析日志的同学不知情。
什么?你说你们团队还没有日志系统?
那么第一件事,就是要有一个完善的离线日志回捞系统或在线日志系统。
3. 打破边界有助于开阔视野,但是是否深入需要慎重决定
虽然有的时候,员工打破边界对于公司来书并不是一个好事情,但大多数情况来说,对个人还是会有所帮助的。
为什么说不是一个好事情呢,比如一个客户端的同学,去做 c++ 了,这个时候应该鼓励还是反对呢。实际上这个时候,他除了仅存的业务熟悉度和一些通用的编程能力,c++ 的能力也许就只有应届生的水平,如果从新招聘可能连初试都过不了。公司就必须要承担因为他的编程能力不熟练带来的效率损失,甚至因为更容易引发问题造成更大的损失。
为什么说,对于个人来说是一个好事情呢,这个主要体现在以下几个方面:
- 在公司中大多数情况下都是多个语言的开发者相互配合的,而当你同时参与了你上游或者下游的工作,你会发现沟通会更加顺畅了,甚至自己也拥有了简单的处理需求和问题的能力,底气会高很多。
- 在你学习多个语言的过程中你会发现一些精华的部分,比如通用的框架设计方法、模块组织方法等各个语言都是通用的,甚至有些代码你直接翻译过来就可以直接用了,这也可以让你更深刻地了解到哪些是编程的精髓。
当然,有的时候如果你跨界参与的太多,例如本身是一个资深的前端开发者,当你跨界参与了 c++ 开发,你会发现短时间内你的前端水平是在下降的,而 c++ 水平也没有达到独立承担工作的程度,这短时间内你的市场价值其实是有所下降的,这也是你需要慎重考虑到底要参与多少的原因之一。
4. 复杂系统的初始架构设计,可以作为一个最后兜底
实际上,复杂的系统大多一开始都不复杂,但是如何正确地预判系统的走向,设计出可以沿用很久的基础骨架、约束性强却扩展型足够的组件系统(即使后来来的人水平差也不至于写出太难维护的代码),以及和外界其他系统进行灵活的配合,是对水平有一定的考验的。
这里我以某视频会议 App 举例,其最开始只有视频+音频的简单能力,在此基础上,团队负责人设计并编写了基于 Typescript 的核心状态机、按照 minor repo 划分了主要模块,设计了 Store 状态存储,设计了一套 API 注入方式可以注入系统外的 API 等等。
这套架构沿用了三年,核心代码基本没有发生变化,功能上却新增了共享屏幕、共享网页、聊天/表情、标注/白板、远程控制、字幕/录制/翻译、日程会议、面试等若干重要的模块。
虽然实际上,随着后面的同学的增多,以及最初核心开发者的离职,开发人员已经几乎换了一批,但是这套代码和架构基本上没发生太多变化,也一直支撑着若干项目。
(p.s. 据说最开始参与设计的同学吐槽后面的维护有点渐渐跑题,但是整体还是可用性比较高的)。
如果没有一定水平,想必业务框架早就随着业务的变更重构过多次了,肯定会带来巨大的人力浪费。
5. 持续练习,持续关注行业动态
最后一点,持续学习,大概是程序员的宿命吧。
这里其实不用多说了,但是想提一点,其实有的时候如果你发现主动的持续学习会比较难的情况下,可以选择一种半被动的方式。
比如,每周给自己定日程参与 leetcode 周赛,你把它当作自己工作的无可推脱的一部分,这样持续几次,你就会慢慢习惯这个过程。
以上共勉。