蔚来日常实习收获
-
- 前言
- [1. Communication comes first](#1. Communication comes first)
-
- [1.1. 求助/需要他人做事](#1.1. 求助/需要他人做事)
- [1.2. 领任务](#1.2. 领任务)
- [1.3. 开会](#1.3. 开会)
- [2. 熟悉公司环境](#2. 熟悉公司环境)
- [3. 快速上手项目](#3. 快速上手项目)
- [4. 负起责任【重要!!!】](#4. 负起责任【重要!!!】)
- [5. 任务管理](#5. 任务管理)
- [6. git使用习惯](#6. git使用习惯)
- [7. 快速定位问题](#7. 快速定位问题)
- [8. 不要陷进去](#8. 不要陷进去)
- [9. 记录问题解决过程](#9. 记录问题解决过程)
- [10. 怎么高效看业务代码](#10. 怎么高效看业务代码)
- [11. 及时汇报进度](#11. 及时汇报进度)
- [12. 设计方案](#12. 设计方案)
- [13. 技术性收获](#13. 技术性收获)
前言
我去年11月份进入一家车企行业公司做供应链系统的研发.
学到了很多学校里不教但十分必要的知识.
这里做一下总结, 以供各位朋友以及自己未来参考.
1. Communication comes first
上班以后才发现, 写代码只占程序员很少一部分的时间. 其余大部分时间被用来沟通.
互相准确地理解对方的意思是一件重要且困难的事情.(不要自卑或懊恼, 这是一个困扰全人类的长久存在的难题)
这对于木讷的工科生来说的确是一个挑战, 但是请尽快适应.
下面是一些常用沟通场景以及经验. 力求准确, 高效.
1.1. 求助/需要他人做事
简要描述自己的情况, 然后说明期望对方做的事.
我曾经犯的一个错误是, 在请教问题时, 把整个思考过程描述一遍. 对方还没听完就迷糊了.
实际上他根本不需要关注那些细节, 我只要把我的思考结论和自己遇到的困难告诉他, 然后表示我需要他帮助找出问题, 就可以了.
1.2. 领任务
- mentor在描述任务时, 自己最好用纸或者电子设备对任务进行一个简单记录 , 他说完以后当场用你自己的语言去复述一遍你对任务的理解, 避免因为理解偏差导致南辕北辙.
- 还要问ddl, 以合理安排时间
1.3. 开会
- 开会对精力和注意力的要求是最高的.
- 听别人讲时, 简单记录他人观点, 有问题及时发问, 对方说完以后在会议结束后当场向对方复述以保证理解准确.
- 讲给别人时, 共享屏幕, 展示提纲/配图(要提前准备, 把时间花在会前而不是会议中). 优秀的文档能力可以弥补临场表达能力的不足.
- 以书面形式留存会议共识
2. 熟悉公司环境
- 进公司以后先搞清楚哪个同事是干啥的, 求助时要知道找谁. 比如找运维问gitlab和各种平台的权限, vpn配置, 怎么发布运行新代码, 怎么看日志. 比如找产品问字段的定义...
- 再请教一下同岗位的同事日常开发流程, git使用规范.
目标是了解: 一个需求从分配到交付的过程中你需要做什么.
3. 快速上手项目
你要面临的项目可能很庞大, 因此, 快速上手项目是你的第一个考验.
我实习接触的第一个项目是一个spring cloud微服务, 大概有几万行, 有四五名后端在协作开发. 这样的规模对于我来说已经像是一座山一样庞大了, 根本不知道该从哪开始学.
"看项目就好比盲人摸象, 你要先搞懂这个大象有几条腿, 然后再去关心它哪条腿上长了几根毛"
- 面对新项目, 第一步是解决那一堆报错(配环境), 先把代码编译通过跑起来.
- 我请mentor讲了一下主要业务, 在纸上画出来我们项目在整个业务流程中的位置和职责.
然后对着需求文档, 把以前做过的需求在图上画出来(比如我们从A系统接收到了数据, 经过处理再调用B系统)
画完以后你一看就能发现, 大部分业务所遵循的其实是差不多的模式, 你也理解了和本项目有关系的其他系统的职责.
到这里, 你就大概知道大象长几条腿了.- 然后就可以挑几个典型的业务流程, 顺着代码走一遍. 从接口出发,差不多也就知道了各个微服务模块的职责(比如说A模块主要负责处理各种mq消费者逻辑的, B模块主要负责操控xxx数据库的, C模块主要负责对接外部系统, D模块主要负责和前端页面的交互)
到这里, 你就知道怎么去数大象腿上长了几根毛. 至于具体有几根, 最牛逼的人也记不住, 他也是碰到了再去现看的.
4. 负起责任【重要!!!】
mentor也知道大学生是个什么水平, 他给你的任务一般都是合理的.
所以我们要尽可能独立面对任务中发生的问题.而不是碰到陌生的挑战就觉得深不可测, 全都扔给同事, 自己在那等着别人嚼碎了把饭喂到嘴里.
其实自己钻研一下也能解决.(但是该求助还要求助, 水哥说得好: 业务的问题立马问, 技术的问题超出半小时没解决也要问)
5. 任务管理
我们可能同时有好几个任务在进行, 对于单核cpu来说, 实现多线程的方式就是频繁切换. 很容易就在忙碌之中把一些任务的细节甚至整个任务都忘了.
建议在一个统一的位置记录所有任务的进度, 比如开发已完成, 下一步的测试方案是什么, 或者因为其他团队进度没跟上而阻塞在了哪里...
这样, 当你要切换到另一个线程的时候, 记得先保存一下现场, 记录一下现在的情况, 以便能够在切换回来时快速恢复现场继续执行.
我的话是用google keep, 一个像todo list的网站
6. git使用习惯
- 每天上班第一件事: 更新代码. 下班前最后一件事: 提交代码
有一次, 我做的事情和一个同事做重复了, 导致合代码的时候发生了冲突
一方面是分配任务的时候我没理解对, 还有一方面是git的使用习惯有待规范
我就是一直埋头干, 长时间没有更新代码也没有提交代码, 导致自己和主分支的差异越来越大, 最后一合, 冲突是不可避免的.
"一个高级程序员每天上班会先花半小时看一下其他人昨天都做了些什么, 改了哪些地方"- 一次提交只做一件事情, 多件事多次提交.
- 对pom.xml的改动一定要单独写一个提交, 单独说明, 因为这是整个项目的基础设施.
- 提交前检查一下, 本地做的临时性修改不要提交上去
7. 快速定位问题
应该直接看日志, 看异常信息, 先定位到报错行. 然后再去有目标地去追报错原因.
而不是花大量时间顺着代码走一遍流程, 因为大部分流程应该是没问题的, 我们只需要关心有问题的一小段就好了
8. 不要陷进去
修bug时, 有时候我会陷入一种半停转的状态, 盲目/重复地去尝试改代码, 然后期待着瞎猫能逮到死耗子.
这样人看起来总是很忙, 但是效率低下, 还有可能拖累测试让他帮你做大量无用的测试
这时候应该清空脑子里的调用栈, 重新审视整个问题, 想清楚问题是什么, 为什么会发生, 怎么去解决.
这个道理同样适用于刷算法题.
拿做测试举例子, 你应该清楚要做什么样的测试, 要观察的指标是什么, 期望得到什么样的结果, 怎样用最少的测试次数去覆盖你要测试的所有场景?
9. 记录问题解决过程
解决一些比较普遍的问题(例如新项目maven报错)时, 记录解决过程和思路. 以后遇到类似问题有得参考可以快速解决
10. 怎么高效看业务代码
看代码时经常跳来跳去容易乱, 为了避免重复地探路, 建议在纸上画出来业务的流程, 以及里面关键的分支, 调用.
这样走过的路就有了一个具体的记录, 即能避免迷路, 也能在看完以后对业务流程有一个清晰而整体的认识
11. 及时汇报进度
你应该让你的直接上级知道你在干嘛.
上班以后我才算真正地理解"抛异常"这个概念.
当你的任务无法正常推进时(可能是因为等待其他团队进度, 或者是遇到了难以解决的问题), 你应该及时向你的直接上级(调用者)汇报这个情况, 由他来决定这个事情怎么处理, 是暂时放下该任务, 还是有其他方法解决.
就算任务在正常推进, 你也应该及时汇报进度.
最怕的就是卡住了还闷着不说, 结果到了ddl才发现没做完.
做事要有始有终, 接到任务和完成任务都要有一个明确的反馈("收到"/"xxx任务已完成"). 这样会让人感觉你办事靠谱. (还给了对方一个机会夸夸你~)
12. 设计方案
对于稍微大一点的设计方案, 建议在执行之前先让同事评审一下, 因为新人的设计一般都还有优化空间, 优化后你可以学到更好的设计思想, 而且还可以让同事看到你的勤于思考和谦虚好学.
13. 技术性收获
-
如果需要用到"", 最好使用org.apache.commons.lang3.StringUtils.EMPTY, 因为直接使用""会导致生成多个对象, 增加jvm压力, 而使用同一个静态对象, 可以避免此问题
-
使用jenkins发布新代码之后, 可能发生"老进程没有被杀死, 导致运行的代码并未被更新"的情况, 可以使用ps命令检查相应进程的启动时间, 来判断代码是否更新成功
-
使用mybatis时, 如果发现有个字段没有插入数据库, 除了看实体类对应属性有没有赋值以外, 还应该检查一下mapper.xml的sql语句有没有缺少该字段, 因为有的sql是手写的, 给实体类新增属性时可能忘记改sql语句
-
catch里面的异常, 要么打印一下, 要么抛出去. 否则出了问题不好排错
-
有关mq消费的一些收获后续记录一下
-
不同事物职责分离, 这样可能会导致设计稍微臃肿一点, 但是逻辑更清晰.
"比如一个苹果, 即可以吃也可以用它砸钉子, 但是最好还是把苹果专门用来吃, 另拿一把锤子专门来砸钉子."
-
接口返回的结果, 最好用统一的类包装起来, 好处: 返回值可以包含更丰富的信息, 例如报错原因, 调用者也方便处理.
而直接返回结果对象, 在失败时除了null以外什么都不知道
可以使用泛型指定真正的数据的类型, 这样便于调用者解析结果, 在接口文档上也会更清晰
-
mq消费者应该集中于一个模块中, 这样在照着代码走流程时, 好找mq出口.
-
避免职责混乱的大文件, 最好按照职责拆分成多个小文件, 便于找代码
-
数据库/网络IO操作, 尽量使用批处理, 在循环场景下能极大提升效率
-
不要用parallelStream, 因为其底层会共用一个静态的ForkJoinPool对象, 而这个对象的线程池大小是有限的, 当项目中使用parallelStream的地方很多时, 新提交的任务将会一直阻塞等待执行, 此时效率还不如stream高
-
低质量技术性代码(例如一个长几十行的setXXX)不要和业务逻辑混在一起, 最好抽出一个方法, 虽然可能复用不了几次, 但是主要目的是使业务代码更精简
可以参考spring的AbstractApplicationContext的refresh方法try里面的11行代码, 流程写得很清晰.