腾讯实习生不到两个月独立完成开发项目交付,她有哪些秘诀?
导语:这是一个平凡的鹅厂开发实习生——阿草的故事。故事讲述了阿草如何在一个多月的时间,从0级的新手玩家,成功打败第一关大 BOSS ,晋升为1级玩家。
背景介绍
故事的主人公阿草最近拿到了鹅厂的实习 OFFER ,她感到开心的同时又有点惶恐:她是一名普通本科的大三学生,虽然本科三年主修专业是计算机,但是技能点都加到了 JAVA 后台开发,她的导师告诉她:入职后技能点需要重置,必须增加以下技能:C++ 、 PHP 、 Vue.js。
任务描述
来到鹅厂接到的第一个任务:在一个半月内,打倒第一关大 BOSS ,使用 C++ 和 PHP 独立完成生活缴费个性化配置平台的所有后台开发工作,并使用 Vue.js 完成部分前端页面开发。
任务分析与执行
接到任务后,阿草对其做了一些分析,打算采用分而治之的思想来完成任务:拆分总任务 → 制定子任务执行计划 → 逐步执行计划 → 完成总任务。
一、拆分总任务
对总任务进行拆分,可以细分为以下几个子任务:
1. 增加以下技能:C++ 、 PHP 、 Vue.js 。
2. 完成 C++ 后台开发任务。
3. 完成 PHP 后台开发任务。
4. 完成前端 Vue.js 开发任务。
5. 完成前后端基本联调任务。
二、制定子任务执行计划
针对细分的子任务,阿草指定了以下执行计划:
1. 入职前,完成 C++ 、 PHP 、 Vue.js 的学习。
2. 入职第一周,熟悉开发环境、技术栈、相关项目代码。
3. 入职第二、三周,完成 C++ 、PHP 后台开发任务。
4. 入职第四、五周,完成前端 Vue.js 开发任务和前后端基本联调。
三、逐步执行计划
1. 入职前,增加以下技能: C++ 、 PHP 、 Vue.js
- C++ 学习:《C++ Primers》 + 《Effective C++》→ 《C++ Templates》→ 《Linux 高性能服务器编程》
- 前端学习:Vue.js 官方文档
- PHP 学习:W3School PHP 教程
阿草预研了一番,决定了自己的学习资料和路线,跟着书籍和文档,模仿着写出自己的 demo ,一步步踏入 C++ 、 PHP 和前端的世界。
知识是无限的,但是时间和精力是有限的。怎么样才能在规定的时间内把上述的目标都完成呢?阿草给自己制定了一个周期任务:每天花固定时间看相关书籍和文档,按照书籍的内容多少和难度划分不同的阅读时长。
经过上述两步,阿草在入职前恶补了一下 C++ 、 PHP 和前端的知识,内心终于不再那么惶恐了。
2. 入职第一周,熟悉开发环境、技术栈、相关项目代码
第一周任务
阿草把本周的学习任务分成了四个部分:开发基础、前端技术、后台技术、业务熟悉。
- 开发基础:配置 VSCode 本地编辑开发机代码;申请 SVN 、 XPHP 、 Git 等权限;
- 前端技术:搭建 Vue.js 开发环境;使用 Vue.js 写 demo ;
- 后台技术:使用 Svrkit 搭建简单后台服务并测试;熟悉项目中的 Ao 、Dao 层模块的逻辑和代码编写;搭建 PHP 开发环境,使用 PHP 写 demo ;
- 业务熟悉:阅读生活缴费文档,了解业务对接过程;学习项目上线流程;熟悉开发环境(开发机、995、 IDC );
采坑记录
第一周什么都不懂的阿草,开始了她的疯狂踩坑之路。
(1) 不敢问问题
看文档不知道看哪里、用 tnpm 安装 Vue.js 的环境疯狂报错、VSCode 设置本地编辑开发代码失败、按照文章搭建 svrkit demo 失败……一开始就遇到了一连串的问题,阿草百思不得其解。但由于她不敢主动问问题,于是问题越来越多,学习也被各种问题卡着,进行不下去了。
(2) 毫无目的地看文档
第一周,导师给她发了一些学习资料和文档,阿草不知道该从哪里看,所以她决定从头到尾都看一遍。什么项目管理、开发流程、代码规范、安全风险等等,从头到尾一字不漏地看完了。看完了,也忘光了。
反思与总结
(1) 自己无法解决的问题要积极求助,不要钻牛角尖
不敢问问题使得阿草的学习之路严重受阻,所以她只能迈出第一步。而这一步,让她有了很大的收获。
她发现,积极提问带来的结果,不仅仅是解决问题本身,更为重要的是学习效率的提高。
举个例子:阿草在用 svrkit 写 demo 的时候,要自己引入一个头文件。但尽管她修改了 BUILD 文件,也没有用。在她自己研究了一个小时还是没用的情况下,她终于问了组里的 titus 哥。经过排查,发现原因有两个。一是依赖的名字写错了;二是修改的 BUILD 文件错了。在这个过程中,阿草除了解决问题,她还附带收获了如何通过工具有效查找源码、bb 和patchbuild 的区别以及它们的使用指南等。
(2) 看文档前先确定自己的需求(通过文档要学会什么),要带着目的性地查看文档和资料
阿草发现,通读完了一遍文档之后,好像什么都没记住。这时候她意识到了:文档应该是一个辅助手册,看文档的时候应该先确定自己的问题,然后带着问题去文档里面寻找答案。想明白了这一点,阿草不再盲目地查看文档,而是根据自己所需,到文档中相关的地方查找资料。
3. 入职第二、三周,完成 C++ 、 PHP 后台开发任务
第二、三周任务
- 学习监控平台、日志系统的使用;
- 了解 XPHP 的执行流程,学习 XPHP 平台的使用;
- 了解生活缴费中 DB 的总体架构,以及 DB 的连接和调度方式;
- 深入阅读了原有个性化配置平台的 Dao 、 Ao 层源码,总结其中存在的问题和编写接口的大致步骤及注意事项;
- 完成个性化配置平台中的 Ao 、Dao 层开发任务(包括代码编写和自测);
- 完成个性化配置平台中的 XPHP 层开发任务;
踩坑记录
(1) 没有站在特定的业务场景思考解决方案
在刚开始读项目源码的时候,阿草脑袋里充满了困惑。
在方法的哪里打 LOG 和加监控?每个数据库表分别是用来干什么的?为什么某个函数逻辑要这样处理?HaProxy 是用来干什么的?为什么一些方法不用切换环境,那怎么知道是在沙箱还是现网 DB 操作呢?
虽然依旧有很多问题,但本周的阿草已经并非上周的阿草,这些问题她已经能够通过查找文档、 km 平台、 google 或者是提问来解决。问题解决后,对业务逻辑有了一定的了解,阿草开始针对源码提出一些优化建议。
例如:个性化配置平台是用主从读写分离,可是这样会造成主从同步一致性的问题。应该把读写都放在主库,从库用来做备份和容灾。
她把这个想法告诉了导师之后,导师抛出了一连串问题:这里对一致性要求是怎么样的?什么情况下会因为读延时引发事故?你这个业务场景会有这种情况发生吗?另外,即使发生了延时的情况,会对你的业务造成影响吗?
这个时候阿草才意识到,她考虑问题的时候并没有考虑实际应用场景,可能不是最优解。
(2) 即使考虑了业务场景,也没有思考出合适的解决方案
举个例子:在批量获取个性化配置信息的接口中,需要先把记录插入沙箱 DB ,再插入现网DB ,并且它们的状态要一致。
阿草对于如何让两个 DB 的状态一致这个问题提出的解决方案是加锁。但她知道这不是最好的方案,加锁这个操作太重,但是不加锁还能怎么解决问题呢?
祥子哥给了她如下答案:对于严格要求原子性的业务,当操作中途失败,可以把消息塞进消息队列,让消费者去定时重试。但我们的这个接口使用的是只能是管理员,也不会影响线上用户的体验,所以不需要使用太过复杂的逻辑和重的操作。这里比较恰当的操作,是加个二星告警,让管理员处理就好了。
(3) 盲目参考以往的代码,没有加入自己的思考
对于 php ,阿草可谓是新手上阵。于是她决定看看以往类似的接口和配置是怎么做的,然后模仿着写新接口。写是很快写完了,但是接口获取不到正确的值。后来花了一天的时间,阿草才找到原因:写接口的时候完全按照以往的接口方式来取值,但是发送值的方式和取值的方式不统一,导致 XPHP 层取不到值。
反思与总结
(1) 要转变自己的思考方式,站在业务的角度来思考哪种方式是最合理的
学生时代写的系统,都是以完成功能为目的。因为不会实际使用,所以无论用什么方式实现都不会有问题出现。但工作时写的系统,每一种不合理的实现方式都可能会导致系统性能低下、后期难以维护、用户体验不好等问题。所以我们要尽可能地站在业务角度,思考出最合理的方案。
(2) 遇到不熟悉的业务场景,先思考,再提问,从别人的方案中总结经验
刚开始写业务代码的时候,总会不可避免地遇到不熟悉的业务场景。这时候,要先自己思考,得出一个可行方案,然后再结合别人给出的方案综合对比,找到自己方案的漏洞、不足。每一次都总结经验,找出不足,才能够不断拓展自己的思维广度和深度,为下一次的问题找到更好的解决方案。
(3) 不要做复制粘贴工程师,要为自己写的每一行代码负责
参考不等于盲目的复制粘贴,参考代码的目的是为了了解类似接口的框架、大致逻辑的走向。代码的实现细节要自己经过思考,每一行代码的作用自己都要非常清楚,才能写入接口。否则很容易出问题。
4. 入职第四、五周,完成前端 Vue.js 开发任务和前后端基本联调
第四、五周任务
- 使用 Element 组件库 + Vue.js 搭建了一个简单的管理页面;
- 使用whistle + SwitchyOmega 配合,在浏览器上抓包和切换代理;
- 完成个性化配置平台负责的前端开发部分,包括个性化配置管理页面、审核页面;
- 完成个性化配置平台前后端接口基本联调;
踩坑记录
(1) 前端开发过程中遇到很多问题,开发效率低下
由于前端基础比较薄弱、不了解前端整体的技术栈,阿草遇到了很多问题。不了解各种基本概念,例如插槽、 blur 事件、ES6中的...等等;构建页面的时候,表单数据丢失;使用 element-ui 的 validate 报错;对服务器接口发送 POST 请求遇到跨域问题……等等等等。在刚开始的两天,还陷入了一天解决一个 bug 的境况。
举个例子:阿草在插入表单里面,想要根据用户选定的 option,和通过 option 绑定的 id 来拿到这个 id 所对应的对象的部分值,来作为一个 POST 请求的参数。但是这里有两个问题。
从传值的角度看:这个id对应的对象是通过 get 请求从后台获取的,又把此对象的信息通过POST 请求返回给后台,这是不合理的。 所以作为 POST 请求的参数,应该是用户输入或者是 cookies 里面取。
从前端的角度看:el-select 只能取到它绑定的值(此处绑定的是选定对象的 id ,即只能取到id ),除非通过监听事件来取值。
经过了大半天的思考,她才得出最终的解决方案:只取对象的 id ,其他有关的信息从 cookies 里面取。
(2) 在前后端接口联调的过程中出现问题时,问题定位、解决耗时长
自己完成前端到后台的一站式开发,有利也有弊。调试的时候如果发现问题,可以自己修改错误和不合理的地方,一气呵成;但是排查问题的时候,需要每一层地排查,可能要同时看前端的报错和抓包结果、 XPHP 层打印的信息、后台的打印日志、数据库表的数据等,这个排查的过程中思路要保持清晰,否则可能会有一种无从下手的感觉。
举个例子:前端获取信息时,其中字段 create_time 并非为数据库中获取的数值,而是一个固定的默认时间。
正确的排查过程是这样的:先看后台调用接口打印的日志,发现打印的字段为正确的时间;再看 XPHP 层,发现打印出来的字段为默认时间。问题定位到 XPHP 层,检查字段名、类型是否对应得上,发现后台中 create_time 为 string 类型,而 XPHP 层的 create_time 为 time 类型,推测是由于类型不符合所以 XPHP 把获得字段忽略了,然后给前端返回一个默认值。
如果按照这样的思路,问题可能很快就被找到。但是阿草面对前端、后台、 XPHP 层、数据库打印出的一堆日志,已经有点晕了,还要来回改参数调试来查看不同的结果,这导致她定位问题的时候一直处于一种混乱的状态,从而没法高效地定位、解决问题。
反思与总结
(1) 通过目标驱动开发,不仅能快速掌握一门新技术,还能加快开发进度
当我们在使用一门新技术进行开发时,面对一堆问题,怎么样能够不被问题劝退,并且快速上手?阿草的解决方法就是通过目标驱动开发。把大目标拆解为小目标,分而治之。在达成目标的过程中会遇到很多问题,通过解决问题来提高对技术的掌握度和加快开发进度。我们之所以会对新的知识产生抵触,就是因为“不会”;把问题解决的过程,就是从“不会”到“会”。这样既能消除自己的抵触心态,同时也能在解决问题的过程中掌握技术,一举两得。
(2) 在前后联调的过程中,保持清晰的思路,有助于快速定位、解决问题
阿草刚开始在联调的时候,并没有先梳理出排查问题的流程,导致她定位问题花费了很长时间。我们在进行前后端联调的时候,可以先推测一下造成问题的原因、哪个层出现问题,然后给自己整理出一个排查问题的顺序,例如:先排查前端的问题,再看 XPHP 层的接口,都没问题的时候再看后台、数据库表的数据等。
任务结果与总结
在鹅厂这个新世界里,主人公阿草经历了一个从0到1的蜕变。在这个过程中,她遇到很多了问题和困难,在队友的帮助下,克服了种种困难,最后凭借自己的努力,阿草顺利完成了任务,打倒了第一关的大 BOSS ,独立完成了生活缴费个性化配置平台的所有后台开发工作以及大部分前端开发工作。
在庆祝胜利之余,阿草对任务做了一些经验总结:首先要明确总目标,然后拆分目标,制定子目标的执行计划,分步完成;在完成每个计划的过程中,遇到问题要先自主思考,然后再积极提问;此外,要有开放的学习心态,不要被思维局限。
写在最后
于我而言,阿草是一种精神喻示,希望大家都能够拥有“野火烧不尽,春风吹又生”的野草精神。