# 1995年的资深工程师，和你谈谈如何进阶

## 自我介绍

网络ID：杭城小刘，城市：顾名思义，人在杭州。1995年出生，本科毕业，现在是一名 iOS 资深工程师。兴趣爱好广泛：乒乓球、美食、电影、健身、山地车、养了2只布偶猫（Simba & Bella）、养花。技术领域：iOS、Web 前端，写过 Node、PHP 后端服务、写过爬虫、研究过[反爬虫技术方案](https://github.com/FantasticLBP/Anti-WebSpider)。在成长的路上...

## 工程师生涯的两三事

刚毕业开始还是一名普通的 iOS 工程师，做的东西一般是跟着 TL 开会讨论需求，完了自己脑补技术细节，完了编码、UI 还原、测试、发布、维护。在第一家公司做开发的时候，某次和一个后端工程师对接口遇到问题，人家说“别跟我说接口有问题。你跟我说是什么样的问题？我需要参数”。然后初生牛犊（小菜鸟）就把 Xcode 下面的 Debug 信息截图发出去，被人怼，说我需要网络的具体参数，Request、Reponse 信息。当时很尴尬，我在想封装好的网络框架，我一个个下断点 Debug 截图给你吗。后来才知道有 Charles 这么个抓包工具，简单搞了搞 Charles 之后就将截图 Request、Response 信息给他了，这样他没话说了，老老实实改了接口 Bug。当时他问我 Request、Response 的时候真的超尴尬，我说你等我半小时，我找好发给你。（😂  Too young, too simple）。

第一次看到 Charles 有那种看到仙女一样的感觉，因为它不只是可以抓包看 HTTP、HTTPS 的网络请求，还可以模拟数据、篡改网络请求信息、篡改网络返回的信息、模拟弱网环境、接口压力测试（类似于 Load Runner）、还可以隔山打牛（Map Remote：请求域名 A 下的接口 a 却重定向到域名 B 下的接口 b）。功能非常多，让我爱上了它，顺道写了一篇[文章](https://segmentfault.com/a/1190000017955654)。


另一个有趣的事情是慢慢在公司有了起色，自己钻研进步了很多。在做的东西 iOS Native + Hybrid 模式的应用，因为在校实验室期间有 web 前端经验，所以在公司经常设计 JS 与 Native（iOS、Android）的通信机制、Hybrid 的能力等等，Debug 的时候经常踩坑，比如 Android 浏览器访问 localStorage 需要开启权限、某些低版本的 Android 不支持 ES6 写法（Vue、React等工程自动引入 Babel 打包构建的工程是转换过的。之前的老工程直接写 ES6，则低版本浏览器不支持）。还有一些 CSS 在 iOS、Android 两端表现不一致。因为公司和别的上市公司合作项目，成立了微信群，我们公司对外输出 SDK，由于另一名同事解决不了。直接跟我说“刘哥，上吧”。由于经常解决疑难杂症，导致对面那个公司的项目经理，问我要不要跳槽，让我去他们公司工作 😂



## 优秀工程师如何进阶

说到工程师，肯定要谈如何进阶。那么我作为一个刚毕业不久，从 普通工程师 -> 高级工程师 -> 资深工程师，谈经验不敢当，说说个人的心路历程吧。

首先刚踏入职场，你必须完成从学生到职场的转换，这个转换不是说换个地方做事就行了，而是态度和观念需要改变。学生时代在校不管是课程作业还是毕设、或者学校实验室的那些东西，现在看看都很 low（排除一些高端院校的顶级实验室项目）。

遇到项目，你要认真分析、思考、编码。完了之后想想有没有优化空间、[代码规范](https://github.com/FantasticLBP/codesnippets)。代码写多了，可以自定义自己的[工作流](https://github.com/FantasticLBP/GitWorkflow) 和[快捷键](https://github.com/FantasticLBP/knowledge-kit/blob/master/第六部分%20开发杂谈/6.11.md)。

很多人强调没时间去学习，说什么白天在工作，下班后可能要回家路上花费时间、吃晚饭、然后累了一天可能要想着健身、娱乐下。一天除非睡觉、吃饭时间你有多少时间？所以我觉得学习和工作不是互斥的事件，你需要矫正态度，工作中的每个需求都是一次学习进阶和检验的过程，别人给了需求，你需要系统设计、架构设计、思考需要几个类、每个类负责什么行为、属性，对外暴露什么接口，类与类如何通信、如何低耦合、高内聚、可拓展？Unit test 设计等等问题都要考虑清楚。剩下就是编码实现了，这个时候考虑的就是一行行代码如何书写，才符合团队规范、业界规范、代码如何分组、如何做到自解释、代码注释等等都需要做到极致。完成后跑单元测试、最后集成测试。提交给测试工程师的项目个人至少保证 90% 的测试 case 通过，ut 覆盖率至少 90%。关于测试也有一堆经验，等后期我会出文章讲讲。


个人学习和工作的时候注意积累和归纳总结，梳理自己的技术栈和知识体系，等下次学到了新的东西塞到体系里面对应的地方去。最后你的知识系统会越来越完善。

工程师强调几个方面：
- 专业能力是第一要素。你的专业能力决定你是否具有不可代替行和价值。
- 软技能决定你的广度和效率：比如查找知识的能力、快速定位问题的能力、快捷键的熟练程度、自己的 WorkFlow、代码规范程度、为团队打造工程化的程度。比如我经常翻墙查找资料，公司的网络和自己家里的网络都可以翻墙查找资料。使用 iterm2 自己制定了很多 iOS、Web 相关的快捷键、这将显著提高工作效率、一天提高1分钟，一年下来就不少的时间节约（如果想看我的快捷键或者 WorkFlow 可以在评论区留言）。团队的代码规范在前端开发中有 ESLint 集合业界的 js 规范比如 airbnb 或者标准的。iOS 这端我使用 shell 脚本开发了一套团队的代码规范，最后还有一套 shell 脚本检测全局工程的代码规范，最后会生成报表用浏览器自动打开。
- 不要过分追求框架等表层东西，要思考原理。很多人初学前端会纠结用 Vue、React、Angular哪个？我觉得没必要，你首先需要打好基础功，基础功好了，框架就很好学习了。框架一般做的事情是在现状的基础上做了封装，让你很方便的做某些事情，或者使用一些设计模式或者先进一些的开发方式（比如单向数据流、虚拟 Dom、组件化等）。这些东西为什么诞生？还不是传统的命令式编程效率太低、操作 DOM 成本太高了，复杂逻辑的页面维护很复杂吗？因为是命令式编程，所以你需要思考每一步步骤，以及中间产生的状态变量，告诉计算机如何处理具体逻辑，导致代码量太大，维护不方便。响应式编程 + 虚拟 DOM + 单向数据流催生了类 React 的前端框架。比如我之前就看过 Vue 的关键逻辑的源代码，看过 React 的 Redux 的源代码。
- 你的水平高了你关心的技术点应该就是业界的研究方向了，比如多端融合能力。你会看到现在的 Flutter、React Native、Hybrid 他们不是没有关系的，而是一步步演进升级。电商公司（其他业务不再举例）业务经常变、运营活动经常变，传统的开发方式需要发布、审核、上线，iOS 这里尤其负责，审核严格，随意这样的流程不能满足，早期的 Hybyrid 就是这样诞生的，Native 提供基础能力，JS 写业务逻辑和 UI操作，但是这样很零散，比如 UI 操作，JS 需要一个 UI，Native 就需要事先注册号或者提供好这样的能力。React Native 解决了这个问题，JSX 的方式写业务，操作数据，setState 做 diff 算法计算出需要更新的虚拟 DOM，在移动端这样的虚拟 DOM 就可以和 Native UI 组件进行绑定，这样就可以有 Native UI 能力。JS 写业务，Native 捕获事件回调给 JS，然后操作数据，继续 setState。这样还不错，但是在低端手机上会卡顿，其中一个问题就是不同语言（JS、native语言）之间通信效率比较低，Flutter 诞生了，Dart 诞生就是为了解决 JS 的缺点。Google 自己的 skia 渲染引擎封装了 OpenGL 接口，所以不需要 Native 提供 UI 能力，Dart 使用声明式写 UI、Skia 去渲染看上去还不错，所以一开始国内的咸鱼团队就在跟进 Flutter，现在阿里 all in Flutter。



## 经验分享

大多数人喜欢碎片化时间阅读一些文章或者自己感兴趣的技术博文。比如你在上下班路上、点餐等饭时间看几个公众号技术文章，很多人会大致浏览完。我觉得这样不如不读，或者收效甚微。因为脑子只有印象的话，看完的文章过半年后问，肯定一问三不知了。与其多篇文章大致浏览，不如精读一篇文章，并动手实践每个技术点和细节。必要时做好博文记录最后总结输出。


另外对于每个技术不要停留在会用（我称之为 api 资深工程师）而是知道这个 api 背后的原理，设计模式、设计的优缺点。比如 iOS 领域著名的 WKWebView 很多人知道 NSURLProtocol 可以拦截其他的网络请求却拦截不到它里面 post 的 body 内容。你查看了 webkit 源代码之后就知道 WKWebView 官方宣传快，是说自身做的事情少了，很多任务比如网络是新开了一个独立线程去处理，所以独立线程处理网络完了通过 IPC 的方式将 post 的 body 通过压缩然后 IPC 给 WKWebView 这会非常消耗资源，所以系统索性不给你传递了。

带着这个疑问看看 Chrome for iOS 的开源项目（至于为什么会看它？因为个人研究多端融合能力、Chrome 这样的浏览器如何渲染处理等流程感兴趣所以看的），看到它里面在用 post 传 body。纳闷了，和 webkit2 源代码不一致。这些现象等都是需要深入才可以理解的。当你遇到一个问题发现网上找不到资料或者资料比较少的时候你就算对这个问题的研究比较深入了。

此外，不管做产品还是技术都不要凑合，必须要做到极致或者最好。上面说的反爬虫技术是我在公司担任 iOS 工程师的时候做的。当时进去一个月写完一个 App，追到 Android 进度。然后不满足于进度，在此基础上做到的一些优化、且通过抓包方式进行业务测试的时候找到了 Android 和服务端的一些 Bug，最后还发现安全性较低，在此基础上，做了 HTTPS + 证书验证 +RSA 证书校验、AES 数据加密，做到了 App 被别人抓包马上就断掉链接。假如技术再高明些看到请求信息也是加密过的（不是 HTTPS 自己的加密，是自定义的加密）和防重放策略。

之后鉴于公司的网站太落后，用 Vue 进行重写，再做了安全升级等工作，这样总经理看到个人能力，担任小公司大前端负责人的岗位。这阶段的成长也蛮快的
然后换工作，也是一样，严格要求自己，半年时间做了无痕埋点、组件化、模块化、Hybrid 能力提升、商城业务模块开发等等，从高级工程师升级为资深工程师。个人目标2年后成为技术专家。


很多人会去问有没有较好的学习资料是什么？我觉得如果有人回答除官方文档之外的答案，那么这个人本身就不够专业。在我看来官方文档是设计者（最熟悉技术细节的人）写出的注释和说明。那么肯定是最佳实践。举个例子 Objective-C 里面对 NSDictionary 进行处理成 JSON 字符串，解析的结果是会带空格和换行符的，但是服务端恰好如果对空格和换行敏感的话，那么你们的逻辑就会和预期的不一致。看看下面的代码。


```Objective-C
NSJSONWritingSortedKeys（兼容性）、NSJSONWritingPrettyPrinted (换行符)
NSDictionary *dict = @{@"name": @"lbp"};
NSData *json = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:nil];
NSString *jsonString = [[NSString alloc] initWithData:json encoding:NSUTF8StringEncoding];
````

很多人转换后可能会去做字符串处理，正则替换空格和换行符。稍微好一些的可能会看到官方的在 iOS11 推出一个新的枚举值 `NSJSONWritingSortedKeys`。那么就是判断当前系统小于 11 则字符串替换，否则就使用新的参数。如果你仔细看官方文档，上面说的非常仔细。看看下面的官方说明。


> Generate JSON data from a Foundation object. If the object will not produce valid JSON then an exception will be thrown. Setting the NSJSONWritingPrettyPrinted option will generate JSON with whitespace designed to make the output more readable. **If that option is not set, the most compact possible JSON will be generated.** If an error occurs, the error parameter will be set and the return value will be nil. The resulting data is a encoded in UTF-8.



另外，越来越觉得架构设计对于架构组同学来说是非常重要的。

为什么？假设你一个需求，预期10天时间；前期架构设计、类的设计、Uint Test 设计估计7天，到时候编码开发2天完成。

这么做的好处很多，比如：
- 除非是非常优秀，不然脑子想的再前面到真正开发的时候发现有出入，coding 完发现和前期方案设计不一样。所以建议用流程图、UML图、技术架构图、UT 也一样，设计个表格，这样等到时候编码也就是 coding 的工作了，将图翻译成代码
- 后期和别人讨论或者沟通或者 CTO 进行 code review 的时候不需要一行行看代码。你将相关的架构图、流程图、UML 图给他看看。他再看看一些关键逻辑的 UT，保证输入输出正确，一般来说这样就够了
- 软件项目管理也一样，确定好关键时间节点、甘特图、确定干系人、kick-of meeting、定期碰头等


## 程序员这个工作怎么样？

个人是很喜欢程序员这个工种的。做事情纯粹些、且培养了不断学习思考的能力和习惯。不断学习和思考是每个行业都需要的基本素养，所以看到事情本质、不断学习、不断进阶就是人生常态吧
