之前聊的一些内容都倾向于某个方向,不够普遍适用。所以今天就聊一聊在技术生涯中的一些经验和思路,可以应用在各种方案设计和选型中。

学习

无论做什么事情,都是始于学习的。技术这个行业更是要求很强的学习能力,每天都在更新各种各样的新技术,每一项技术也都可以研究得很深入。

当然一开始还是先把基础打好。当年在学校的时候总会想,学习一些计算机原理、编译原理之类的知识,对以后做软件开发的帮助应该不大。但事实上了解一些相关基础,对于思路的拓展和理解更深层次的技术,还是会有不少帮助的。另一些算法与数据结构、面向对象开发之类的知识就更不用说了,都是基础中的基础。

然后就是一些经验类和通用类知识的学习,推荐一些经典书籍:《程序员修炼之道》、《设计模式》、《代码整洁之道》等等。书籍基本上都是沉淀了各位大师毕生的经验心得,真的把这些都理解吃透,可以少走很多弯路。第一遍阅读时可能会无法完全理解书中奥秘,过两年再回味一下或许就会有新的收获。

关于什么样的设计算是好的设计,推荐大家可以了解下SOLID设计原则,这算是最精简的总结了。总之一个设计方案拿出来对比着SOLID设计原则来看,不符合其中的部分原则,那设计应该是存在问题的。

31-A

最后要学习工作方向的专业知识和相关知识,通俗来说就是深度学习和广度学习。在深度上一路磕到底,在广度上放飞自我,两种极端都是不行的。在深度上耕耘可以让我们胜任自己专业范围内更高难度的工作,但是光在深度上钻研容易进入一种井底之蛙的状态。比如我们写iOS端,完全不懂web端、服务端和Android端,遇到app需要内嵌web页面进行js-bridge交互的时候怎么设计方案?遇到dns污染如何解决?怎么保证移动端多端逻辑和行为一致?到最后只能变成一个无情的按照需求实现逻辑的代码机器。在广度上适当耕耘可以拓宽我们的思路和视野,甚至可以造些实用的“玩具”。比如学习了Apache Kafka的设计思想后,我们可以把思路应用在客户端做一个消息队列,这对消息/通知集中式管理的系统(比如一些聊天软件)很有帮助。比如学习了python之后,可以做一些自动化构建脚本,提醒写周报的机器人等等。但是在广度上不经筛选的学习并且过度发散,也是得不偿失的。我见过有人说自己会搭建十几种服务器,会写近百种语言的hello world,也不知道怎么评价比较好……

所以总结起来,学习这事情需要我们投入精力,而且要规划权衡好学习的方向。大公司可能需要在自己的岗位上更专业深入些,其它的工作由同事来配合完成;小公司分工没那么明确,可能更需要能力多面的“全栈工程师”。但是小公司会发展成大公司,大公司的各位也可能自己去创业,世事无绝对,要考虑好未来。

方案选型和设计

选择适和应用场景的方案

JSON和ProtoBuf,两大数据格式大家应该都比较熟悉了。如果让我们选择用其中一种来作为我们和服务端进行数据通讯的格式,应该选哪一个呢?很多人会觉得,PB是比较新的格式,体积更小,类型确定,兼容性和性能也很棒,用就完事了。但是抱着这种简单想法就直接选方案是很危险的,我们选择方案应该仔细的考虑哪种方案对我们来说更适用。PB体积是小了,但是采用二进制格式也会带来些问题:

  1. 没办法直观的查看数据内容,不方便进行修改和mock等操作,这会对测试和联调带来很大的困难。所以没有做好对应的工具建设前,过早的使用PB反而会降低效率。
  2. 类型固定也会带来些兼容问题。例如B站的视频ID从纯数字的avID变成现在类似Base64编码的bvID,如果早期设计PB模型的时候没有考虑到这种情况,会需要进行蛋疼的迁移工作。这个例子可能不太好,不过主要是为了说明JSON格式里万物皆字串的优势,字串意味着灵活。

所以说,我们要考虑的是:

  1. 我们现在的流量、带宽是瓶颈么?接口PB化省下来的带宽费、流量费对我们来说优先级很高么?
  2. PB带来的性能提升明显么?我们有对应的工具和数据来证明性能提升了多少么?
  3. 我们的人力是瓶颈么?有能力支持PB工具的建设么?没有的话大家效率降低后还能完成快速迭代么?

可以看出来,如果我们的app现在用户量少,调用接口也不多,并且我们也没有能力和精力做好基础工具和性能监控的建设,那么一开始完全可以采用更简便易用的JSON。

31-B

类似的问题:bitmap、jpg、gif、png和webp等众多图片格式,我们应该选用哪一种?可能又有人会说webp动态图静态图都能支持,图片压缩比高体积小,也没有严重失真等问题,应该用它最好。但是机智点的朋友现在应该知道了,只考虑优点是不对的。

  1. 首先最重要的一点,大部分系统都没有原生支持webp格式。当用户开开心心把喜欢的图片保存到本地,却发现打不开,就会心态爆炸了。
  2. 因为webp的压缩率很高所以才能同时保证体积小且不失真,但是这就会导致压缩和解压的时候需要进行更多的运算。同一时刻压缩或者加载大量的webp图片,会导致编解码压力很大。
  3. jpg和png只支持静态图(apng也不被大部分系统原生支持),gif可以支持动态图。
  4. gif和jpg的图片质量都比较低,但是gif可以轻松应对颜色较为简单的图片,jpg应用在色彩绚丽的图片上时,虽然会有失真但是肉眼感觉不明显。
  5. png图片质量较高,但是一般相较于jpg来说体积会大一些。

图片格式这么多,每个格式又有它们各自的特色,所以我们的选择会多样化点:

  1. 广为流传的表情包,需要方便大家存储,动态图会采用gif格式,静态图会采用jpg或者png格式。

  2. 用户进行截图的时候,会希望图片质量更高,尽量还原所截的画面,一般会采用png格式。

  3. 各种icon需要透明底色,也需要比较高的清晰度,一般会采用png格式。当然还有很多情况会采用Iconfont方案。

  4. 各种风景画式的背景图或者闪屏图,图片超级大,对清晰度要求又不高,一般可以采用jpg格式。

  5. 列表页和详情页的大量图片,一般可以采用webp格式,用以加速网络图片的加载,节省cdn带宽和流量。

可以看到,单一的一个方案已经不能满足全部的场景,所以我们才会在不同的场景分别选择最合适的方案。

31-C

等等,为什么始终没有bitmap的戏份呢?我们得想一想,为什么我们现在用图片一定要压缩呢?因为我们的存储空间是有限的,因为我们的网络带宽也是有限的,压缩再解压虽然会浪费一点时间,但是能在网络传输过程中节约更多的时间,也让我们能够存储更多的内容。那么会不会有那么一天,硬盘变得更加廉价更加快速,网络带宽也变得无限大,反而是CPU性能遇到瓶颈无法再提高了。如果真的有这么一天,那么bitmap应该会登上王座。

选择能产生收益的方案

就像上面说的图片格式选择那样,当压缩不再能产生收益的时候,这一项技术或许会整体走上末路。技术的发展和选择都是为了产生切实的收益,有些技术不能给我们带来收益时,就需要考虑下我们到底该不该使用这项技术。

网络请求基本上是现在的app必须的功能,我们该用NSURLSession(AFNetworking)?还是更底层的CFNetwork?还是完全独立的网络库,比如Cronet这种呢?

NSURLSession已经可以满足日常的各种网络请求,但是也只是能做到很基础的请求而已。在iOS 10之前,甚至连个像样的性能监控模型都没有:

31-E

从iOS 10开始,有了NSURLSessionTaskTransactionMetrics,但是数据项很少,直到iOS 13,才开始补齐更多的属性:

31-D

如果我们切换到更底层的网络库,就可以获得更全面的性能数据,对网络连接和请求的自定义能力也会越来越强。这无疑是增强了我们的能力,但是这些能力能给我们带来收益么?

如果我们的app就那么一台服务器,cdn也是用的xx云附送的,没有自行调度的能力,我们可以发现网络的波动和其它问题,然后呢?没有然后了……

我们利用更底层的网络库实现了智能的dns调度,避免了dns污染问题。但是我们就1000个用户,一个人都没有遇到过dns污染……

可以看到上面这些例子里,我们做出了更优秀的技术方案,但是短期没有能带来收益。不是说预先准备好优秀的技术方案是坏事,它在未来可能会迎来发挥价值的时刻。但是更多的时候,我们的资源是有限的,好钢要用在刀刃上。app发展的初期,做一两个新奇的功能可能会成本更低的带来更多的用户,更高效的促进团队发展和进步。如果把资源用在了短期不能带来收益的方案上,兴许app凉了方案都没实际派上用场,这就叫做过早和过度设计。

对方案进行验证

对方案只管上不管埋是不行的,强烈鄙视。做一个技术项目需要准备基本的验证方案,还有对不同验证结果的应对方案。

例如近几年移动端开始流行MVVM设计模式,经过初期的调研,觉得比较适合现在的团队和项目状况,可能会带来收益,那就可以开始准备使用并验证了。光觉得是个新技术,高大上,引入项目就开始吭哧吭哧的用,这种人肯定是个有毒的技术leader。简单点要跟踪下迭代效率、质量,看看同样的开发周期,是否还能平稳的完成开发任务,是否没有产生大量的bug等等。再深入点,我们要review代码,验证MVVM方案下完成的代码质量如何,是否真的按照合理的设计模式完成了代码。在有一点基础工程的支持下,可以验证使用了MVVM的页面的APM各项指标如何。如果出现了不符合预期的情况,考虑下是团队内工程师学不来MVVM,还是工程本身客观条件不适合使用MVVM,如果是人员问题可以考虑加强培训,如果是工程问题那可能需要尽早考虑更换方案,等等等等。

没有人可以做到料事如神,那么只能边走边试,在尽可能降低风险的情况下进行试验。为了达成这样的目标,会关联出更多的技术方案,慢慢的团队里会需要ABTest、分桶工具,在线调整参数的方案,APM监控平台等等。做这些又需要我们有完备的数据收集通道,上报方案,设备唯一ID生成方案等等。这一般就是诞生基础架构、底层团队的过程。能够思考得更长远,做好更万全的准备,项目才能更稳定高效的迭代下去。

任何事物都有两面性

总结来说,我们要做的各种各样的选择,都不应该是绝对的。每一个选项会有它的优点,也肯定会有它的缺点。就像前面提到的:用JSON还是PB,多种图片格式的选择。我们要考虑我们可以接受哪些缺点,希望获得哪些优点,综合权衡下利弊,才能确定到底该选择哪一个方案。

还有句话叫做小孩子才做选择题,成年人会说我全都要。有时候我们并不是要从选项中多选一,选项本来就会是个连续区间,所以我们是要动态的调整方案,保证能够均衡的获得各种优点。就比如说经典的不可能三角(如图),我们所有人都想要又快又好又便宜的方案,但是大家也都知道这是不可能的。最后,我们只能用各自的方法去摸索,怎样才能达到最接近“不存在”的那一块区域。在生活中也是类似的情况,比如说我们纠结今天吃什么,大家都想要吃上又好吃又便宜又健康的一顿,但是总会要在一些方面做出妥协和平衡。当然也可能有些人不在乎这些,那么对他们来说最重要的可能就是吃饱和省事,这也就是他们所希望获得的优点(奇怪的选择方向增加了~)。

02-F

用更加客观科学的方法去分析,认识到每个事物的多面性,再去做自己的决策和平衡,才是更好的。当然这其中最重要的就是自己的思考,人停止了思考那就和咸鱼没有什么区别了。

感谢阅读到这里的大家,今天的分享就到这里啦。