我在字节的这两年

打印 上一主题 下一主题

主题 1049|帖子 1049|积分 3147

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
媒介

作为脉脉和前端技术社区的活跃分子,我比较荣幸的有了诸多口试时机并终极一路升级打怪如愿来到了这里。正式入职时间为2021年1月4日,也就是元旦后的第一个工作日。对于这一天,我印象深刻。踩着2020年的尾巴接到offer,属实是过了一个快乐的元旦。不知不觉已经两年多了,细细追念起来,更多的是岁月推移,并没有回头看看现在的自己和两年前的自己有什么差异。
决定写文章记载一下还要感谢谁人去职前在飞书上和我告别的老哥,他说已经学到了想学的
那我呢?好像还没有。
和良好的人做有挑战的事不止是简朴的一句话。
在字节停留时间越久,越是能感觉到身边人的良好,也正是这份良好推动着我不停前进。
本文将会从思维方式、题目排查、技术思考三个方面以回首自我发展的视角展开叙述,欢迎阅读。
思维方式

思维方式指的是看待事物的角度、方式和方法。放到工作当中来看,我逐渐探索出了几个详细的点。
工作优先级

曾很长一段时间里,我在工作上没有刻意区分优先级或者说有优先级但是区分度不是那么显着。这意味着只要不是恰好有紧急事变处理惩罚,基本上业务方提过来的合理需求我都会第一时间安排。岂论需求巨细,也不问紧急程度,都默认看成紧急处理惩罚。
诚然,在交付后得到业务方肯定的那一刻是有成绩感的。但我逐渐意识到,这真的是有点本末倒置。由于我负责的这部分工作和底层数据相干,大概许多需求直接或间接的都会找到我。究竟上,完成对齐过的工作才是我更应该高优做的事,剩下时间用来完成这些零散需求才更为合理。
早先我觉得有些小需求大概就是一两行代码的事,顺手一个分支就带上去了。但仔细想想,这好像引发了蝴蝶效应。一件事仅仅完成是不够的,该有的环节要有。 开辟,测试,上线,周知业务方验收。这样一个小流程走下来耗费的时间可不但仅是一两行代码占用的时间可比。更况且,大概还不止一个零散需求。时不时被打断,自然就会导致原有工作安排非预期delay。
在意识到这个题目后,来自业务方的需求我会主动问一下优先级。如果不是特别紧急的事变将不会安排在当前周期的工作计划里。别的,优先级判定上我会和业务方确认完利用场景后有自己的思考。对接次数多了,发现有些紧急并不是真的紧急,只是单纯的性子急。厥后,对于这种零散需求,我会在项目管理平台写好描述和需求提出人,方便后续沟通。
这个记载还是很有意义的,深感利益显着。


  • 可以起到一个备忘录的作用,定期检察,提醒自己有todo要处理惩罚
  • 业务方(需求提出人)大概因业务场景变更或有了其他解决方案,不再必要后续支持
  • 原业务方(需求提出人)转岗或去职,不再必要后续支持
等到决定去做的时间,如果发现时间间隔较久,不要急着写代码,先和业务方二次确认这个需求是否有必要继续做。试想,如果耗时耗力做完,最后约请业务方验收时间对方又反馈用不到了。什么心情?那肯定满脸黑人问号啊?实惨如我,曾有过这样的履历。深感前置确认真的很有必要,这样能有效避免打黑工的场景。
在有意识对工作优先级进行划分后,原定对齐的工作希望基本都可以得到保障。等到工作周期竣事进行总结的时间,看到比较高的完成度,我觉得这份成绩感更高。
ROI考量

ROI 全称为 Return On Investment,指的是投资回报率。我是在完成一个比较重要的功能模块迁移后才更加认识到这个东西的重要性。在做数据迁移的时间,我写脚本进行的全量迁移。为了兼容新旧平台的格式差异,我做了好几处的格式转换,过程中还遇到好几个bad case必要手动处理惩罚,总之并不是那么顺遂。等到一切预备就绪,我开始拉群周知用户并以表格形式逐个进行利用情况的回访。结果很尴尬,现实利用的用户远低于历史存量用户。量少到我完全可以采取更快的手动迁移,省去做格式转换和写脚本的时间。
对于那些现实没人用的数据,我厥后又进行了删除处理惩罚。这一波操作下来,真的投入产出比就不高了。算是吃一堑长一智吧,在对一个功能模块进行迁移的时间,前置工作除了搞清晰历史背景,实现原理,更应该确定现实利用人群。尤其是对于一个存在年初比我入职时间还久的功能,更应该花时间在这个点上好好调研下。确定目标人群才好"对症下药",这样才有大概是多人的狂欢而非仅仅是一个人单纯完成迁移工作的孤独玩耍。
有心和偶然真的是两种不同的感觉。 现实上,在履历这个事变之前我对自己研发的模块也会有许多想法。有较长一段时间里,我脑海中冒出来的小想法会连同某个分支功能带上去,改动不大,但是大概要思考的点会比较多。现在追念起来,大多数属于ROI比较低的。而现在,岂论是业务方提出的需求还是我自己的小想法我都会优先思量ROI的题目。时间是很宝贵的,在有限时间内产生更高价值带来的成绩感和自我认同感绝对是翻倍的。
技术与业务关联

在来字节前,我很喜欢花大把的时间去研讨一些自己喜欢但大概现实未必会用到或者说利用场景比较局限的东西。比如我曾跟着视频教程鼓捣过一段时间的Angular 1.x 。当时觉得ng-xx这个指令写起来倍感新颖,有种发现新大陆的小冲动。也曾跟风学过一段时间的php,被其数量巨大的内置函数所震动。等转回到业务上,发现花费大量时间研究的东西和业务根本不沾边或者说没必要为了实验而去强切技术栈。如此一来,割裂就产生了。我曾好长一段时间困在这个技术和业务二选一的局面走不出来。
等入职字节并工作了一段时间后,我发现当业务形态开始变得复杂,对技术的考验也会随之而来善于运用技术恰到利益地解决业务痛点,远远比单纯研究技术有意义。 自嗨终究是自嗨,没有现实落地场景,过一段时间就会忘记。如果还没想清晰技术服务于业务这个关键点,那就会陷入【研讨技术->长久不用->忘记->研讨技术】这个循环。保持技术热情是好事,但是对于一个几乎没有业务落地场景的技术,投入大把时间研究又有什么用呢?知识是检索的,当必要时自然会朝着这个方向靠近,有详细落地场景才气更好地巩固。
进一步让我体会到技术与业务是相辅相成的契机是对图数据库bytegraph的相干技术调研和终极的投入利用。业务场景必要,我这边会涉及不同范例数据之间关联关系的管理(CRUD操作)。这个关联有层级的概念,全部关联创建数据量已到万万级别。从计划角度和实践角度综合考量,已经不是MySQL擅长的场景。细想一下,层层关联放开不就是一张图吗?自然是图数据库存储更为合适。
在我看完bytegraph相干文档并利用Gremlin图数据库语言写了几个符合自我预期的底子语句后,突然又找回了曾经独自研讨技术的快乐。在利用过程中,很自然的就和业务关联起来了。比如如何计划点和边?如何提高关联图查询速度?我曾写过一篇关于图数据库bytegraph先容和基本利用的文档,有同学在看过后就着某个详细业务场景下点该如何计划这个话题和我进行了语音互换,最后我结合现实利用场景给出了有效结论,被肯定的瞬间同样是成绩感满满。别的,在工作中对bytegraph的利用诉求,还推动了bytegraph NodeJS SDK 的诞生。有幸成为第一个吃螃蟹的人,真的很有怀念意义。
寻求长期方案

许多时间,解决题目的方案都不止一个。绝大多数情况下,选择临时解决方案是最快最省力的。固然,也不排除某些极限情况下充足的临时趋近于长久。但临时终归是临时,这意味着中后期规划大概会有变更,从而导致现有的方案不再实用,所以说寻求长期稳定的解决方案才是终极目的。尤其是当体系稳定性和切换成本冲突时,更应攻坚克难去破局。近期完成了权限平台相干接口的升级替换,由于历史包袱极重,旧的权限接口越来越不稳定,已经影响平台侧权限的正常利用。在这种情况下,真的是不得不换。利益还是很显着的,虽然过程艰巨,但稳定性上确实得到了保障。
信赖字节内许多平台都是对权限体系强依赖的,这意味着一旦权限体系服务出了题目,其他的下游服务都会受牵连。这种权限题目感知相当显着,最简朴的一个例子:为什么自己创建的东西在操作时提示没权限?
为了降低权限体系不可用对自身业务的影响,我用redis对所有涉及权限读数据的地方做了缓存(如用户权限列表)。每次革新页面会在获取用户信息的同时查询最新的权限信息,当检测到返回结构非预期时,则不再更新,直接返回缓存数据。一般来说,读权限场景比写权限场景更多,有这样一层缓存来兜底,还是很有价值的。
别的,为了避免自己创建的东西在操作时提示没权限的尴尬局面,我进行了业务自身数据库优先权限体系接口查询的处理惩罚。这个很好理解,写到自己数据库再读取往往比写到权限体系数据库再读取来的方便,后者大概会有耽误。完成整体权限体系接口升级替换,再结合redis缓存,数据库优先权限体系接口读取这两个策略,在业务侧整体权限稳定性上可以看作是一个长期稳定的方案了。
直面题目

对于一个开辟来说,出现题目在所难免。解决题目固然重要,但是摆正心态也同样重要。工作中基本都是多人协作开辟,当收到线上报警消息时,如果能确定和自己的某些操作有关应及时和相干同学说明,避免其他人一同跟着排查。有句话听起来很矛盾,但是语境还挺合适的:“我知道你很慌,但是先别慌。” 出现题目,排查清晰后,及时修复就好,切莫讳疾忌医。
别的,有些题目隐藏比较深,复现链路较为隐晦,乃至大概除了开辟自身,其他人几乎不会有感知。我曾遇到过一个这样的case,代码写完过了一年,也没有人反馈,最后还是我自己在某次调试时间发现并修复的。随着编码履历的积聚,思维发散性也会更广,不同阶段思量的点自然也有差异。没必要过多纠结当时为什么没有思量到这个场景,更应该思量的是下次遇到类似情况如何避免。亡羊补牢,为时未晚。
题目排查

题目排查可以说是一个开辟职员必备的本领。个人感觉包管开辟永世不出bug的方式就是不去开辟。固然,这并不现实。在字节这两年多的时间里,我踩过好多的坑,也出过事故,逐渐探索出了一些题目排查的履历。
环境划一性校验

工作中我这边常用到的是本地环境、测试环境(boe),生产预览环境(ppe)和正式生产环境(prod)。每个阶段都有大概会引发题目,在开始排查题现在,必要先确定自己的调试环境与引发题目的环境划一。乍一看大概感觉这句话是废话,但是有过相干履历的人都知道这一条真的很重要。
说来惭愧,我有过本地调试半天发现死活不生效最后意识到看的是生产环境页面的尴尬履历,真的是又气又无奈。
优先包管这一点,能少走许多弯路。
格式划一性校验

格式划一性校验指的是确认原始数据在有意格式处理惩罚或漏处理惩罚后,是否和后续步伐要接收的数据格式保持划一。
一般来说,编码粗心或者测试不够充实都有大概引发格式相干的题目。
有意处理惩罚的场景:
  1. const list=[1,2,3]
  2. // 有意处理
  3. const formatList =list.map(d=>({
  4.     id:d
  5. }))
  6. // 省略一大段代码
  7. // 此处错误传入了list,应使用formatList
  8. getData(list)
  9. function getData(list){
  10. // do something...
  11. return xxx
  12. }
复制代码
在前端操纵数据store也有大概存在类似的题目,原始数据格式在某个组件里被修改导致另一个组件无法预期解析。
漏处理惩罚的场景:
  1. // sequelize findAll查询 限定只返回id属性
  2. const ids = await modelA.findAll({
  3.   attributes: ['id'],
  4. });
  5. await modelB.findAll({
  6.   where: {
  7.     id: ids,//这里漏掉了对ids的处理
  8.   },
  9. });
复制代码
如图,利用了sequelize model方法中的findAll查询并限定只返回id属性,且变量命名为ids。
现实上,返回的结构是对象数组{id:number}[],而不是数字数组number[]。
哀求相应划一性校验

服务里定义的路由地点和前端哀求时的地点对不上,导致哀求404。
大概是因为单词拼写错误:username or ursename? cornjob or cronjob? 或者cv后没有改全。
前置条件确认

这个偏向于涉及事件触发的场景,要先满足其前置条件。
下面列举几个有代表性的场景:

  • 如果想在群里接收某个机器人推送的消息,必要先把机器人拉进群
  • 如果想在eventbus斲丧生产者产生的数据,必要确保斲丧者是开启状态
  • 如果想利用sdk正常解析hive数据,必要先申请表权限
分区间排查

这种方式实用于排查由步伐代码引起但尚不确定详细代码位置的场景。
我将其划分为三段式:

  • 给怀疑会出题目的代码圈定一个区间,非怀疑区间代码直接解释(前端更有效)或return掉(后端更有效)
  • 添加相干打印并重新运行步伐,观测输出和步伐运行结果是否符合预期
  • 收缩区间,重复1,2步骤,直至发现题目

这里举一个我在利用bytegraph过程中亲身遇到的一个cpu暴涨的例子。
最初bytegraph并不支持全图查询,所以在获取某个点所在的整张关联图谱时拆分成了以下三个步骤:

  • 查询某个点在整张图上的关联点
  • 遍历每个点,查询入边和出边
  • 根据边的指向拼出完整的图谱
伪代码如下:
  1. function getGraph(vertex:Vertex){
  2.     // 查询某个点在整张图上的关联点
  3.     const nodes=await getNodes(vertex);
  4.     console.log('get nodes')
  5.     // return  分割区间一,后续直接return
  6.     // 遍历每个点,查询入边和出边。
  7.     const edges=await getEdges(nodes)
  8.     console.log('get edges')
  9.     // return  分割区间二,后续直接return
  10.     // ... other
  11. }
  12. async function getEdges(vertexs: Vertex[]) {
  13.   let res: any = [];
  14.   for (let i = 0; i < vertexs.length; i++) {
  15.     const vertex = vertexs[i];
  16.     // 根据点查询入边和出边
  17.     const itemEdges=await findEdge(vertex);
  18.     res = [ ... res, ... itemEdges];
  19.   }
  20.   // return res 分割区间三,不执行uniqWith返回res
  21.   // 深度去重
  22.   return uniqWith(res, isEqual);
  23. }
复制代码
采取分区间排查题目的思路,在关键节点添加打印日志,触发调试。
检察打印信息,发现每次都是在获取所有边那边卡住。
此时可以进到getEdges里边检察,发现内部有一个去重操作。
试着去掉这个过程,再重试,题目未复现。ok,定位题目。

针对这个题目,我写了一个可复现的最小demo,感爱好的可自行实验。
结论是lodash的uniqWith和isEqual方法对大数据 重复率不高的数据进行深度去重会导致cpu暴涨。
  1. const { uniqWith, isEqual } = require('lodash');
  2. const http = require('http');
  3. http
  4.   .createServer(async (req, res) => {
  5.     const arr = [];
  6.     for (let i = 0; i < 10000; i++) {
  7.       arr.push({
  8.         n: Math.random() * 20000,
  9.         m: Math.random() * 20000,
  10.       });
  11.     }
  12.     console.log(uniqWith(arr, isEqual));
  13.     res.end('hello world');
  14.   })
  15.   .listen(3000);
复制代码
哀求溯源

对于有提供Open API 给其他业务方利用或者说当前服务存在开放性接口(未设置权限)的情况下,都有大概存在非预期调用,其中最典型的是参数错误和session信息缺失。
我有过类似履历,某个已经线上稳定运行过一段时间的接口突然开始报错,从错误信息来看是参数错误。随后我仔细查找了代码里的调用点,只有大概在平台利用时触发。进一步检察,确认是开放性接口,没有权限管控。意识到应该是某个用户手动触发的,因为平台侧正常利用的哀求参数符合预期。如果能定位到详细的人自然最好,如果找不到人就必要在代码层面做一个参数校验,如果传递过来的参数不符合预期,直接return掉。类似的,平台侧调用肯定可以拿到session信息,但是接连频频报错都是拿不到session导致的,怀疑好坏常规调用,直接return。
安全日志记载

我负责的工作中涉及许多底层数据,这些数据属性变更有大概会引发非预期的安全卡点。开启卡点的资产越多,类似题目感知就会越显着。内部定时任务,外部平台配置变更,扫描任务,人工变更都可以导致资产属性发生变化。因此,究竟是哪一环节发生的变更显得尤为重要,这能有效缩短题目排查链路。
通过在每个变更节点添加一条安全日志记载,可以有效辅助排查。别的,还可以作为业务方溯源的一个途径。比如解答某个资产卡点什么时间开启的?卡点开启同步自哪个部门?
检察数据库字段

在某些业务场景里会在数据库中存储JSON 字符串,此时必要对现实大概的JSON巨细做一个预判,之后再设定与之匹配的字段范例和数据巨细。否则当现实长度超过数据库设定字段长度时,JSON字符串就会被截断,导致最后的解析环节出错。
超时归因

开辟中遇到网络超时题目太常见了,大多数情况下都可以通过添加重试机制,延伸timeout的方式解决。这里我想说的是一个比较特别的场景,海外,国内跨机房通讯。 绝大多数海外和国内的通讯都是存在区域隔离的,调用不通体现上大概就是网络超时,这种情况下,重试也没用。解决途径也比较直观,要么直接避免这种情况,海外调海外,国内调国内,要么申请豁免。
善用工具

argos观测诊断平台
在题目排查上,观测诊断平台能起到有效的辅助作用。除了报错日志,还可以看到所在服务psm,集群,机房。这些都是缩短题目排查链路的有效信息,在服务实例比较多的情况下体现尤为显着。别的,还可以配置报警规则,命中后会有报警机器人进行推送,可及时感知线上题目的发生。
飞书机器人
至心觉得飞书机器人是一个很好用的小东西。用它可以干许多事,比如按时提醒该喝水了。在报警感知上,也可以通过机器人搞点事变。比方在某个装饰器里对核心接口哀求地点(如包罗/core/)进行识别,随后在catch代码块里捕捉错误,最后将error message or error stack 推送到指定的飞书群里,这样团队其他成员也能及时感知。
飞书表格
个人精力有限,不大概时时候刻盯着报警信息其他什么都不干。对于一些看起来影响不大,不用紧急修复的报警可以先通过飞书表格记载下来,等偶然间后当成待办事项逐一解决。亲测,这种先收集后会集处理惩罚的方式比发现一个处理惩罚一个更省时间。
技术思考

规范

很长一段时间里我对技术的理解是运用掌握的知识完成开辟,仅此而已。但究竟上,开辟流程不应仅局限于开辟环节,另有其他许多有价值的事变必要关注,比如一些规范。团队协作和独立开辟还是有显着区别的,没有规矩不成方圆。既然是协作,就要有达成划一的规范。
我曾写过一篇关于lint的文章并在小组内和其他同事对齐,共同商讨缩进风格,哪些规则要开启,哪些规则要禁用。项目编码风格统一的管控实现上依赖husky和lint-staged,在提交代码时进行lint检测,不符合检测规则无法提交,这样可以有效避免个人编码风格差异导致的格式change。
在代码提交上,由组内另一个同学制定了git工作流规范,共同约定了不同功能分支如何命名,分支间如何检出与合并,commit 应该如何编写。这种规范形成文档后作用显着,岂论是日常开辟还是线上部署,都有了更清晰的操作流程。别的,见名知意的commit message也更有助于查找详细功能点。试想一下,如果简写一个fix,或fix err ,等过段时间再看,那边还记得到底fix了个什么?
类似的,小组内另有需求迭代,上线部署等相干规范,这些规范站在开辟的全局视角来看,都是很有价值的。
质量

研发质量题目是一个非常值得重视的点,开辟完成并不意味着整个研发环节就竣事了,质量过关才是最后的收尾节点。简朴来说,上线后功能平稳运行,无bug和性能题目,这样才算是及格。虽说百密一疏,但反复踩同样的坑或者踩不应该踩的坑就有些说不过去了。我印象比较深刻的踩坑点在于数据格式处理惩罚,这个在上文报警排查处有提到,不再赘述。另有一点,对于超过大版本的sdk升级,肯定要认真且充足详细的检察是否存在break change。有些break change是比较隐晦的,乍一看大概察觉不到玄机,切记想固然,在项目代码中搜刮看看,总比自我追念要可信的多。想要劳绩一批忠实用户,研发质量肯定是排位比较靠前的。
稳定性

这里特指研发的体系稳定性,初期我这边涉及到的体系架构比较简朴,所有功能模块共用一个服务。这样利益是许多代码可以复用,开辟和上线也比较方便。祸福相依,但是一旦服务崩溃,除了影响自身业务正常利用,还会朝着下游其他业务辐射。详细体现上来看,一般是OEPN API不可用。为避免类似题目再发生,我和小组内其他同事一起完成了服务架构升级,将不同子模块拆分成不同的服务,接口层面根据重要等级和业务范例并借助负载平衡本领,分散至各自所在服务的不同集群。架构升级完成后,纵然某个子模块出现题目,也不至于牵动整个服务崩盘。在此次架构升级中更深刻体会到了不同范例数据库在特定场景下的利用,Redis,MySQL,MongoDB,bytegraph都有涉及,劳绩颇多。
文档先行

对于一些偏复杂的模块,先找个文档梳理一下,逐步拆解清晰后再开始编码,属于磨刀不误砍柴工。从前我的习惯是想一个大概,然后投入开辟,写着写着发现之前想错了,然后删掉代码,再写新的,这个过程大概会反复好频频。冷静下来好好想想,真不如先写清晰文档更省时省力。实测,让思维在文档上交锋,远比在编辑器里打斗轻松的多。
沉淀总结

我始终觉得,有输入就应该有输出。岂论是日常底子搬砖,还是攻坚克难了某个业务痛点,又或者加深了自己对某项技术的理解,都应该有所显现。并不是说非要落笔成文,但至少应该在一个属于自己的小天地里留些痕迹。如果实在懒得打字,不妨试试拍照式影象。亲测,这个是科学中带有点玄学的方法。
先找到想要记住的画面,可以是控制台的数据打印,也可以是bug调试截图,又或者某段关键代码,然后想一个主题,与之进行关联,重复思考频频。好的,记住了。
还是那句话,有心和偶然是不一样的。有心留意,这份影象就会更为深刻。当下次遇到类似场景,近乎是条件反射的思维反应。比如我现在每次写删除语句肯定会查抄是否加上了where条件。这是有特别意义的一段履历,不堪回首。
落地统计

辛辛苦苦搬砖究竟产生了怎样的价值呢?究竟有哪些人在用?这同样是一个比较关键的点。我曾梳理了一个关于OPEN API 业务落地情况的表格,里边记载了哪些业务方在用,什么场景下会用,对接人是谁。这样除了价值考量,还可以在接口变更或下线时及时接洽利用方,避免造成非预期的影响。
总结

不知不觉,洋洋洒洒写了几千字,梦回结业论文。曾觉得自己属于有所发展,但是发展算不上快那种。写完这篇文章后再回首,竟也方方面面许多点。不错,经过一番努力,终于从一棵小葱茁壮发展为一棵参天大葱了。
回到最初的题目上,时至本日,我仍旧觉得另有许多东西要学。距离把想学的都学到,大概另有很长一段路要走。
幸亏这一路不算孤独,能和身边良好的人一起做有挑战的事。
火线的路,仍旧值得期待。
完结,撒花!

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

钜形不锈钢水箱

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表