近期因12月20日西安健康码崩溃事件引发了互联网界很多人自发复盘,也诞生了很多对该事件反思的相关文章,有同行还发出《为什么这个社会需要高级前端》的感慨,也有人《从前端角度分析:西安一码通崩溃事件》,也有雲著君建言献策《西安一码通BUG分析——盼一码通稳定运行》,虽然这是一次故障,但这反映了这个时代社会对技术的依赖,也彰显了技术在深深的改变着人们的生活方式,作为一名前端工程师,作为互联网中的一员,我很自豪,因为我感到我从事的工作不仅仅是为了一份薪水,也是为这个科技改变生活的时代尽绵薄之力。
作为读后感,首先我很看好各位同行,本质上这是一次典型的系统过载现象,但同行们“见贤思其焉,见不贤而内自醒也”,能从一个社会现象联系到自身职业,那怕可能面对的是评论区的“千夫所指”也敢于发声,并积极给出优化意见,这让我看到了一种社会担当。作为技术人员,我们需要工匠精神,但也需要这种以身边发生的事去"格物致知"的情怀。
认真写代码是一种执行力,时刻关注新技术 get 新技能是一种向上的精神,但这只是一个技术人员基本的职业素养。当然这也是很多人面对失业威胁的无奈之举,因此我们好多同行被贴上了“码奴”、“互联网民工”、“咸鱼”这样的标签,究其原因便是缺少一种思考的能力,前者过分强调“把事情做了就行了”,或者虽有思考但只是“光说不练假把式”,而后者讲究每做的每一件事情要对它进行提炼以及升华,我想也正是这种精神,才有我们前端工程化、SPA 框架、自动化这些工具,才有我们自己的鲁班、敦煌、云长、无相这样的提效产品。
思考可大可小,往小了想是自我反思,即每件事情都有自己的反思沉淀,把自己的事情做的更好,我们的每周的 codeReview、我们沉淀的前端技术方案、技术文章等都是这方面的体现。往大了想便是创新,比如根据自身遇到的痛点,写出一个工具为相似场景赋能,比如我们的无相、华生等系列低代码工具,或者把我们经验输出为文章为更多的人布道,让那些看到文章的人不踩同样的坑,比如我们的掘金上的系列文章。
当然上述是思想层面的感悟,也许你觉得已经跑题了,但我认为毕竟是读后感,我应该毫无保留的将我想到的有价值思考寄托于文章之上,毕竟这也是我看到这几篇文章后的真实感悟。
关于这次事件的根本原因,这篇由 10 余位来自鹅厂、华为、中兴、ICT 数据分析的大佬从前端、后端、测试问题进行了原因分析后产出的文章《西安一码通BUG分析——盼一码通稳定运行》已经说的很清楚了,并且个人感觉分析的很全面,因此这里不做过多表述了。
接下来我就前端方面聊聊 《为什么这个社会需要高级前端》、《从前端角度分析:西安一码通崩溃事件》二文,虽然两位作者已经就前端方面做了分析,但凡事“横看成岭侧成峰”,可能因“远近高低”的问题,我读了二文后感觉作者所提很多表述可能欠妥,甚至有误导倾向,以此文与大家共同探讨下,也借此二文抛砖引玉,阐述下部分个人看法。
1.文章说要干掉所有 css 、js 统一采用 内联样式是否可取?
我想作者这样做的目的无非是想减少 http 请求的次数,出发点是好的,但方式这显然是不推崇的,程序设计也讲究低耦合,作者所说的方式势必导致 html、css、js 耦合在一起,这样对于后期的维护成本是可想而知的,同时这也违背了单一职责原则,在我看来 html 就应该单纯的承载 DOM 部分的代码,css 承载样式,js 承载逻辑。
那么对于作者的考虑的性能方面是否有其他更好的方式替代?
答案是肯定的,首先就上面的问题静态文件可以使用 CDN 分发,利用 CDN 的负载均衡、动态分发、缓存特性,不把访问压力全部集中在站点服务群,这样变可以很大程度上节约服务器的带宽。
当然文章中说的利用浏览器缓存特性也是一种手段,比如让服务端在响应头上塞入 Cache-Control,设置强缓存,让浏览器在一定时间(max-age)内的本地磁盘里面的内容,或塞入 ETag 设置协商缓存,间接的让浏览器读本地磁盘内容,当然浏览器本身也会默认对静态文件进行缓存。
2.接口数据缓存在前端是否合理?
文章中说因为“通过以往的使用,基本可以确认个人的健康状态非实时更新”,因此个人的健康状态在两次计算的间隔期就应该利用前端缓存,作者的意思我大概揣测了一下,大概是说利用浏览器本地存储如 localStorage 的方式把当前更新的数据缓存在本地,并记录当前时间,然后在一定时间内不去调用后端接口,直接读本地存储的数据,不去增加服务端访问压力。这明显是有漏洞的,首先你无法保证在你存健康码的时刻刚好是健康码更新的起始时间,其次即便要做缓存也应该放在服务端,再者新冠疫情传播如此迅速的时刻,如果健康码的数据都不能做到实时更新,那么你能保证你身边的绿码是真正的绿码?滞后的数据又如何作为人们健康的屏障?这个时候为何不想淘宝的双十一看齐,通过扩容、增加带宽、限流等的方式去增强服务端承受能力。
3.文章中说“从界面分析中发现前端在逻辑实现中并没有把健康码、接种疫苗状态、核酸检测状态进行分批加载,正是这种一把梭的加载方式导致一处崩所有崩”
这一点我也很不认同,一个信息量本身就不多的页面如果还要连续调用多个多个接口一来这势必增加前端页面书写逻辑,再者每多一个接口也毕竟要增加一次 http 请求,这难道不是在浪费带宽吗?再者作者的意图我想应该是觉得这是一个胖接口,但是后端也有接口隔离的思想呀,为何先通过接口隔离将健康码、接种疫苗状态、核酸检测状态单独拆分,完了通过一个聚合的接口将这三个接口组装呢?
4.作者批判前端没有 对异常进行处理是否合理?
这里不得不承认,页面在接口出现异常的时候没有做一个友好的兜底界面,但是不能说完全没有进行异常处理,因为如果没有对异常进行处理,那么其结果应该是整个页面都挂了,而不是只是显示了局部。这里也提醒我们前端在平时自测的时候一定要将接口异常情况的也纳入到自测用例,毕竟我们前端的工作是以视觉形式直接呈现给用户的,所以要保证在任何时候页面样式不能乱,当然面对异常情况的展示形式,也要反推视觉、测试提供合理的兜底方案,避免因防御问题贻笑大方。
5.作者说“ 这个页面有一个致命的问题,一旦成功加载便会被浏览器强缓存。这样的结果就是,如果现在领导要加一个验证码,那么用户必须要手动刷新页面,或者等待默认缓存过期以后,才能真正的看到验证码,否则展现给用户的依然是没有验证码版本的老页面”原因分析。
如果作者所言属实,那么我认为前端的确可以从代码层面上做一定的优化,比如加入如下代码,禁掉浏览器对 html 默认的缓存机制。
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
6.此事另一个值得反思的是,对于健康码这种千万级流量的项目,为何在使用前没有考虑到这种高并发的情况而提前进行压测?
可见软件在设计之初整个研发团队都缺乏一种敬畏之心,这样一款高流量的应用,没有在上线前进行系统的压力测试,也没有进行后续的持续监控,可见所有人都抱着只要把任务完成了就行了,完全没有考虑后续可能遇到的风险。
据说只是找了几个外包和实习生做的,不过27万的预算作为健康码一个开发团队的报酬貌似也只能找这样的团队了,这明显就是“又要马儿跑,又要马儿不吃草”嘛,不由得让我想起了韩愈《马说》里的,“千里马常有,而伯乐不常有”,“虽有千里之能,食不饱,力不足,安求其能千里也”。
再者也替这些外包和实习生感到同情,也让我感到跟对团队的重要性,与狼共舞你可能最终你也成为狼,相反与羊共事你可能顶多也只是一只羊,大多数情况下,好的氛围能够助长你的进步,匡正你的作品。尤其是这些实习生,他们缺乏的是在职业生涯中能够框正自己的人,因为我们每个人都是从这个阶段过来的,换做是我们在实习生阶段也可能缺乏类似事件的意识,但我的导师总会在关键时候孜孜不倦的向我传道,培养我最初的意识。
其实这二文主要是讲的是前端性能方面的事情,但是不可否认的是前端再怎么解决都不如再加一台服务器。但即便如此他们能够走在复盘的最前列,由此掀起一场“百家争鸣“般复盘热潮,我认为也是非常有价值的,当然二文的确谬论颇多,刚入道的前后端工程师很可能会被文章所误导,导致前后端职能不清晰问题,误将后端应该处理的事情强加给了前端,因此工作上的不顺畅,因此我写了这篇文章就二文中的一些观点做了反驳,希望能够起到框正的作用。
当然作为一名前端,我们也要有一定的技术追求,诸如上文提到的性能优化、异常问题处理、新的变更因为缓存刷不出来问题,我们前端是可以通过一定的手段做的更好的。
最后感谢你阅读这篇文章,文章开头也说了“横看成岭侧成峰,远近高低各不同”,这毕竟是我的个人看法,若有不妥之处,还望读在评论区提点!