关于bug修复:可观测性最佳实践-警惕未知的风险正在摧毁你的系统

无声的刺客最为致命,往往外表看似云淡风轻,理论早已危机重重,血雨腥风剑拔弩张。这样的局面看似离咱们很边远,但每个开发运维人员理论都遇到过。在寰球数字经济大潮下,古代企业纷纷投身于业务数字化转型的浪潮。越来越多的行业演变成一个个互联网利用,以实时在线的数字化形式提供服务,解脱了传统意义上物理地位和营业时间的解放。此时在线服务的稳定性、可靠性和并发性能变得尤为重要,因为这些都会极大地影响用户体验和服务质量评估。 ▲ 图源自网络,侵删 比方在刚过去的 2022 年,全国百姓的日常民生问题,都和一个小小的在线实时生成的二维码产生亲密关联,若因服务质量不稳固会造成多重大的结果可想而知。如果此时零碎内呈现无声的刺客,他可能捣毁的不仅仅是一个零碎,甚至关乎企业多年累积的客户信赖与品牌形象,决定企业存亡。如何去发现和辨认这些未知的危险,提前做好预防和优化,是每个开发运维人员须要继续面对的问题。本文以零碎性能瓶颈为例,展现如何通过零碎全链路可观测,来辨认和定位系统前端性能、链路性能、基础设施性能瓶颈以及高效剖析系统日志。所波及到的实现思路和工具会笼罩软件开发、测试、部署和运维各个环节。 前端性能瓶颈体现行为性能瓶颈个别是体现在用户体验方面: 比方用户反馈说:页面加载过慢,动画卡顿,交互提早;比方用户反馈说:你们这个页面怎么加载这么慢啊,好几秒才出现;比方 PM 反馈说:这个列表滑动的时候加载数据一卡一卡的。总之前端的性能瓶颈往往都是有体现的,须要针对具体表现具体分析具体解决。 前端瓶颈介绍前端性能瓶颈通常包含以下几个方面: 加载工夫:页面的加载工夫是一个重要的方面。当页面加载工夫很长时,用户体验会受到显著的影响;渲染工夫:渲染工夫是指浏览器将 HTML、CSS 和 JavaScript 代码转换成理论界面的工夫;CPU 占用率:应用大量的 JavaScript 代码能够导致 CPU 占用率过高,从而导致页面性能降落;内存透露:内存透露是指未能开释已不须要的内存。当 JavaScript 代码不合理地应用内存时,页面的性能会受到影响。图像品质和大小:图片文件的大小会影响页面的加载工夫。more...小编继续更新面对瓶颈的排查思路工欲善其事,必先利其器,前端排查思路个别有以下几种: 思路1:F12可在浏览器的 devtool 里一项项排查,查看邻近运行状态,跟进片段的脚本调用,一点点调试,如下图: 思路2:利用某网站测试性能平台思路输出网址能够看到网站的性能测试后果,能够把所有性能相干指标(FCP、LCP、TBT、CLS)状态展现进去,然而仅仅代表点击测试之后的后果,偶现性能后果不代表所有测试后果,如下图: 思路3:可观测建设思路,性能指标等数据可视化为什么要可视化? 收集到性能监控或者性能指标后,就须要将数据可视化展现进去,广义上数据可视化是将性能的监控指标通过图表的模式展现进去,场景化能满足对数据观测的需要,其中就蕴含帮忙发现数据中暗藏的外在法则。接入观测云,将前端利用数据采集到后,能够通过「观测云控制台 」查看利用性能剖析,改善页面加载(LCP)、互动性(FID)和页面稳定性(CLS),进步用户体验。先讲一下谷歌网站外围指标几个外围指标:LCP、FID、CLS,咱们用这三个指标来掂量网站的载入速度、互动性和页面稳定性。 将我的一个网站接入 RUM 后,在 Web 利用的「性能剖析」页面能够看到,例如统计 PV 数、页面加载工夫、网站外围指标、最受关注页面会话数、页面长任务分析、XHR & Fetch 剖析、资源剖析等指标,如下图成果展现: 性能指标等数据可视化,疾速定位 总之,前端技术栈的性能调优须要从多个方面动手,并综合应用多种办法来进步页面的加载速度和用户体验。在思路3中,咱们曾经介绍了用的是观测云可视化进去性能指标,可视化后,有了根据这样就能够有针对性进行解决,以下实战中疾速定位了多个维度的优化点,别离从长工作、Image、XHR、JS、CSS、Document、Font 方面展现。 实战1:疾速定位长工作卡顿页面TopN 长耗时页面,通过饼图形式,将长工作耗时和页面关联,直观地看到是因为 xxx 页面导致的卡顿。 实战2:疾速定位优化的优先级长耗时工作在不同页面的时序散布,能够针对页面进行优化排等级,如 /statics 页面呈现的长耗时工作较多,可能须要优化的优先级就可能会靠前,或者对应的前端负责人员设定绩效考核点,让绩效间接跟性能挂钩。 实战3:疾速定位出 Top 资源耗费依照耗时来排序,找出耗时最长或者排名靠前的一个资源,定向进行优化,Image、XHR、JS、CSS、Document、Font,定位之后,明确性能优化方向,疾速解决问题。 ...

June 19, 2023 · 1 min · jiezi

关于bug修复:bug-solved-export-default-was-not-found-in-xxx

起因:export 导出不止一个 须要用花括号解构出本人想要的 例如: import Provider from 'mobx-react' 改为 import {Provider} from 'mobx-react'

April 12, 2023 · 1 min · jiezi

关于bug修复:long转为number溢出

问题:在进行后端接口调试的时候,发现无奈更新数据,最初发现是因为id的最初两位全副变为00。后端人员说ID的类型设置为long,而前端是Number类型,超过了17位产生溢出,不应用String是因为数据库的效率问题。解决方案:后端:在发送数据之前通过注解的形式将long转为string。前端:在接收数据的时候通过success回调函数进行解决转为string。最初是后端人员解决了这个问题,因为后端的接口会被其余人员调用,从源头解决不便大多数人。

June 23, 2021 · 1 min · jiezi

关于bug修复:关于京淘项目问题集

对于京淘我的项目问题集 1.maven我的项目创立第一行报错问题报错阐明:对于报错阐明:STS开发工具整合SpringBoot时,容易报maven插件异样的错误信息. STS中的插件版本与SpringBoot中的版本不统一导致的. 解决方案:阐明编辑POM.xml文件信息,批改实现之后须要更新我的项目. `<properties> <java.version>1.8</java.version> <!--指定插件版本 --> <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version> <!--跳过测试类打包 --> <skipTests>true</skipTests> </properties>` * 1* 2* 3* 4* 5* 6* 72).更新我的项目 2.maven工具创立SpringBoot我的项目报错阐明阐明: 利用maven工具,创立SpringBoot 创立时POM.xml文件报错.报错阐明: 个别pom.xml文件报错,个别都是maven私服镜像服务器问题. 步骤1:切换本地仓库的私服地址 `<mirror> <id>alimaven</id> <name>aliyun maven</name> <url>http://maven.aliyun.com/nexus/content/groups/public/</url> <mirrorOf>central</mirrorOf> </mirror>` * 1* 2* 3* 4* 5* 6步骤2: 强制更新maven 3.对于JDK和JRE报错问题阐明:配置环境变量,将JRE配置改为JDK配置信息. 保障JDK版本正确. 4.程序启动报 java.lang.ClassNotFoundException异样报错阐明: IDE在程序运行时无奈找到.class文件进行加载. 可能是将target目录下的文件删除,导致短少.class文件 解决方案: 让程序重写编译即可. 5 对于hosts文件批改的权限问题解决方案:1.增加管理权限 选中hosts文件之后 右键属性.形式2: 以超级管理员的形式运行Switch hosts软件形式3: 增加指定的用户权限 步骤 1.获取以后计算机的名称 PC 2.增加用户信息.注意事项: 计算机名称不要写中文. 形式4: 勾销只读属性 6.nginx拜访报错查看HOSTS文件配置失常.`# 京淘配置 #左侧写IP地址 右侧写域名 两头应用空格分隔127.0.0.1 image.jt.com127.0.0.1 manager.jt.com127.0.0.1 www.jt.com127.0.0.1 sso.jt.com` * 1* 2* 3* 4* 5* 6查看NGINX配置文件是否正确`# 配置图片服务器 server { listen 80; server_name image.jt.com; ##通过网址转向指定的目录 留神/的写法 location / { root D:/JT-SOFT/images; } }` * 1* 2* 3* 4* 5* 6* 7* 8* 9* 10* 11重启nginx在重启之前查看是否有多余的nginx服务项,如果有则敞开.hosts文件是否失效依据申请门路 查看代码中门路的拼接是否失常.http://image.jt.com/2020/08/0...D:JT-SOFTimages/2020/08/07/cc10f60491234317adf800aeafc6af1f.png ...

January 30, 2021 · 2 min · jiezi

更新-移动端BUG管理小程序功能更新

目前,移动端BUG管理小程序已经上线并且保持持续更新,欢迎大家使用!扫描小程序码就可以随时随地进行BUG管理了哦!1.注册/登录如果您是第一次使用MadPecker,可以直接在小程序里完成注册。小程序登录时用的邮箱地址和密码和PC端的一致,而且登录一次之后,下次进入小程序直接进入项目界面,免去了重复登录的烦恼。2.处理BUGMadPecker小程序和PC端数据完全互通,在小程序上可以完成指派、完成、通过、不通过、关闭、再打开等操作。最早做MadPecker的初心,就是为了提高我们自身团队的工作效率。随着MadPecker进一步的成长,我们有了越来越多的产品线以及越来越多的支持者,我们也同样希望这款产品能够多少对您有一点小小的帮助。当然,如果您对我们的平台有哪些意见或者建议的话,欢迎您在我们的公众号后台留言,小啄我看到了之后会及时回复大家。Peace!

July 1, 2019 · 1 min · jiezi

教程-如何使用MadPecker进行敏捷开发

Hi,大家好,我是MadPecker,一款免费,好用的缺陷(Bug)管理SaaS软件! 今天,小啄给大家介绍一下如何使用MadPecker进行敏捷开发! 1.如何进行需求管理 点击页面下方的“+”号按钮新建需求,在输入需求名称、优先级(选填)之后,点击确定按钮,完成需求创建。 需求总共分为五个状态,分别是需求池、待评审、待开发、开发中、已完成。一般情况下,可以先在需求池中创建需求,再根据实际情况改变需求的状态。 2.如何进行迭代管理 点击界面右上角的【新建迭代】按钮,输入迭代名称、迭代日期、迭代版本(选填)、关联需求(选填),点击【确定】按钮,完成迭代创建。 创建完迭代之后,点击【关联需求】按钮,可以将“待开发”状态下的需求和本次迭代关联。 3.如何进行任务管理 在关联需求之后,就可以根据需求拆分任务了。任务初始状态分为三种,包括待处理、开发中、已完成。如果开发团队在开发过程中需要更多的任务状态的话,可以点击【新建列表】按钮,输入列表名称,完成任务状态的创建。同时,任务列表支持左右拖拽,可以根据自身的需要排列顺序。 左侧的“已关联需求池”主要方便用户在计划会中拆分任务,在开发过程中,如果开发人员不需要看到“已关联需求池”,可以点击“已关联需求池”左下角的小箱子隐藏“已关联需求池”。 点击“待处理”状态下“+”号新建任务,输入任务标题、处理人(选填)、日期(选填),点击【确定】按钮完成任务创建。如果填写更多内容的话可以点击【更多】按钮,选择标签、优先级、关联需求,输入工作量。 点击其中一个任务,可以对当前任务进行编辑、删除操作。 在实际项目开发过程中,开发人员可以根据实际情况拖拽任务到其它任务列中变更任务状态,直到所有任务都在“已完成”状态中。 4.如何开启一次迭代 在录制完任务之后,点击迭代列表中的小箭头开始迭代。开始迭代之后,本次迭代关联的需求会自动移动到“开发中”状态下。 当任务全部到“已完成”状态下的时候或是迭代结束的时候,可以点击打勾完成迭代,同样的,本次迭代关联的需求会自动移动到“已完成”状态下。

May 21, 2019 · 1 min · jiezi

SpringBoot启动报错Failed-to-determine-a-suitable-driver-class

SpringBoot启动报错如下 Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.2019-05-06 21:27:18.275 ERROR 10968 --- [ main] o.s.b.d.LoggingFailureAnalysisReporter : ***************************APPLICATION FAILED TO START***************************Description:Failed to configure a DataSource: 'url' attribute is not specified and no embedded datasource could be configured.Reason: Failed to determine a suitable driver classAction:Consider the following: If you want an embedded database (H2, HSQL or Derby), please put it on the classpath. If you have database settings to be loaded from a particular profile you may need to activate it (no profiles are currently active).Process finished with exit code 1把这个依赖注释掉就好了 ...

May 6, 2019 · 1 min · jiezi

为啥程序会有bug?

如果这是第二次看到我的文章,欢迎文末扫码订阅我个人的公众号(跨界架构师)哟~ 本文长度为4818字,建议阅读13分钟。坚持原创,每一篇都是用心之作~这是一篇半娱乐性的吐槽文章,权当给广大技术人员解解闷:)。哈哈哈,然后我要开始讲一个经常在发生的事实了。(程序员们可能会感到一些不适)99.999999999%做技术的都会被问到或者被吐槽到:“你的程序怎么又出bug了!”反正,我作为程序员的内心世界是:如同一万只草泥马飞奔而过,难以压抑内心的激动,每次都差点忍不住想说“你写篇几百字的作文还有错别字呢,我码个几万行的代码还不允许出错了?“可能同样是做技术的你此时在不断点头,哈哈。但是这么讲毕竟也缓解不了矛盾,我们还是得摆事实讲道理不是?啥都不怕,就怕程序员有文化!所以,Z哥想来带你好好分析一下这个事情,当你再遇到这个情况的时候,可以拿这些观点来反驳(不是做技术的也可以了解下程序员的难处,谁没个难处呢,多多包容)什么是Bug任何一个「问题」的产生,本身是没有好坏之分的,但是为什么会有的就不被care,甚至还会很喜欢,而有的会被吐槽呢?根本原因是因为产生了利益损失。比如年前拼多多出问题送了很多无门槛券。作为一个用户,自然很喜欢,夸你夸到飞起,怎么会吐槽你呢。但是作为利益损失方,必然破口大骂,害我倾家荡产!所以,如果没有产生利益损失,我想其他人也不会来找你吐槽。但是「问题」就等于「bug」吗?我认为并不是,「问题」不等于「 bug」。因为程序员的职责是什么?拿造房子来比喻的话,我认为最核心的工作真的和“搬砖”(非贬义词)无异,就是根据设计师(产品经理)设计好的设计图砌砖(编码),建成和设计图纸上一模一样的建筑。所以,如果一个东西造出来与设计不符,那么它可以说是bug或者缺陷(缺斤少两不完整)。否则,并不是bug,但可以被称之为「漏洞」(完全没考虑到的),表示不在预料之内的情况。之前看到过一个形象的比喻:你家里的窗可以从外面打开,那叫漏洞。你家里的窗打不开,那叫bug。但是要承认,bug是必然存在的。为什么?它是如何出现的呢?Bug是如何出现的正如前面所说,程序员做的是“造房子”的事情。这件事完整的步骤分为3步。与产品经理讨论并确定功能(确定一个可以实现的设计图纸)将每个单独的元件抽象出来(确定施工方案)将相关的元件实现并进行组合,完成建设(带上材料开始施工)第一步,“与产品经理讨论并确定功能”主要是沟通,靠“看”和“理解”。但是沟通本身是一个有损耗的过程,特别是在职责非常明确的组织中,产品经理啪啦啪啦讲了很多,到实际做的时候你必然还是会去翻阅需求原型、需求文档之类的重新理解一下。这个时候就是一个非常危险的时期。比如像下面这个的答案是什么?答案是17?不对。我猜你可能没注意到这些地方。为了让你有深刻的印象,这个举例可能比较刻意和夸张一些,但是我想在你的身边,由于没注意到或者理解有误的现象肯定很常见。沟通是相互的,这锅只让程序员背的话的确太委屈了点。第二步,“将每个单独的元件抽象出来”这主要是一个人抽象能力的体现。但是抽象是啥?抽象是“透过现象看到本质”的能力,这个能力理论上是可以无限增长的。随着你对相关信息的掌握越多,这个能力会越强,会无限趋近于100%,但永远不会真正达到100%,因为没人知道怎么才算100%。所以,当你具备的信息没那么多的时候,是不是就抽象的不是那么合理?不合理会导致什么?虽然不会直接产生bug,但是会更容易产生bug。但是人不都是需要经历这么一个成长的过程么?可以说,精通一项能力的背后都是踩着无数的bug过来的。要么在来这个组织之前已经踩过了,要么在这个组织里踩。因此,前者的薪资也比后者高。所以,如果过分苛求没有bug,等于是在扼杀每个人成长的机会,并且在透支未来的可能性。人会变得非常保守、不敢尝试新事物。但是外部环境在不断变化,新事物总会被动的需要去接纳(技术的更新越来越快,趋势不可逆),然而对新事物的接受能力又得不到锻炼,一旦遇到这种情况,在接触新事物的时候会产生更多的问题(欠下的债总要还的)。第三步,“将相关的元件实现并进行组合,完成建设”这就是实际的coding过程,而coding是一个主观的,完全由人主观掌控的事情。人毕竟不是机器,不可能不犯错,就如前面提到的写文章的时候出现错别字一样。可能你会说,有测试人员啊,测试的工作不就是通过逆向思维来给程序员查缺补漏吗?的确是的,但测试的介入只是降低错误率,只是让不出现bug的概率小数点后多几位,指望发现100%的问题还是不太现实的。至少在当下的条件下是这样,为什么呢?因为代码的本质是各种逻辑的组合。比如,一个完整的业务流程有10个环节,每个环节有3种可能性,这是一个什么复杂度的系统?3 ^ 10 = 59049个分支(理论上存在的可能性数量),想要100%覆盖这些场景,付出的成本几乎是不可接受的。然而我们实际的系统中遇到的个别场景甚至还要复杂的多。其实每个正在运行的系统都有bug,包括我们每天在使用一些热门系统(玩游戏的小伙伴们肯定熟悉“卡bug”这个词)。只是这些bug有没有被执行到,有没有被发现,被多少人发现而已。那么,我们只能举手投降吗?那倒不至于,办法还是有的。减少bug的惯性想法首先最容易想到的一点是,增加测试人员。这也是最容易看得到的“成本”一种方式,毕竟招一个人就得支出一份工资啊。所以,增加测试人员这个方案是最不容易被老板们采纳的方案。除非你可以说服这个人力成本的投入小于获得的价值。另外,这个方案其实还增加了沟通成本,沟通的「隐性成本」其实非常大,但是往往容易被忽略。(关于沟通成本,感兴趣的可以看我之前写的《就简单聊聊沟通效率问题》)其次会想到的就是程序员代码写的严谨一点,仔细一点啊。这也是一种缺啥补啥的惯性思维。先撇开到底能不能达到严谨一点,仔细一点的目的。那怕达到了,他会产生什么结果呢?可能是下面3种。更多的条件验证更多的单元测试更多的抽象提炼可以确定的是,这些工作会增加2样硬性的东西,投入的时间和整体的复杂度。时间很好理解,我们就来聊聊复杂度。一个常识是,越简单的东西越不容易产生bug。比如1+1=2,出现bug的可能性无非就是加号写成来减号,1写成了4之类。但是,1+1=2,并且1*1=1,并且1/1=1,。。。等等这些验证条件越多,那么由于验证条件自身的错误而产生问题的可能性反而更多。所以,代码的复杂度和产生bug的概率是成正比的,并且具有「边际效用递减」的效果。这就意味着,做更多的验证带来的收益会越来越小。因此,这个方案哪怕真能执行到位,也不是一个特别好的方案。那有没有相对靠谱一些的办法呢?有,但需要我们换一个角度来看待这个问题。换一个角度看待bug既然无法100%避免bug,那我们可以换个角度考虑一下,如何让解决bug的过程更快,甚至快到你都没有察觉。解决bug主要就是做2件事,找到bug的产生点,然后修复它。每天都在解决bug的程序员们应该知道,这事最费时间的是“找bug”的过程。因为“修复bug”是一个技术性问题,这个对不同人的差异其实是很小的,因为程序员们每天在写的代码都是差不多的,非常同质化的,况且还有标准答案“文档”可以参考。比如,都知道string.concat()是拼接,string.split()是分割。该用分割的地方不小心用了拼接,那改掉就好。但是“找bug”就不是这样了。比如,你刚刚改完一行代码后发布出现的问题,你不用找就知道问题出现在哪。但是让你排查一个刚接手没多久的系统肯定是一脸懵逼。根本原因在于,这个过程不像技术性问题具有确定性,它是充满不确定性的,处在一个“混沌”的环境中。所以,对待bug的重点就变成了:如何更快的发现和找到bug。关于这点Z哥的建议是:打好日志学会利用工具每次的迭代规模尽可能的小首先,打好日志。日志其实就是我们在编码的时候安插在程序中“记录员”,它替我们记录着我们认为容易出现问题的地方所产生的信息。但是系统无时无刻都在运行着,必然会产生大量的日志信息,如何从这些信息中快速的找到关键信息,就是需要考虑的问题。另外,如果每个人都随意的用自己喜欢的记录日志的方式,那么从风格迥异的日志中找你需要的信息就变得很头疼,时间不一致,格式不一致等等。所以,要做好打日志这个事情,就需要定义一个标准,比如必须要有时间,包含当前上下文的参数等等。我们还可以给日志做一下归类,定义不同的日志级别,在记录的时候带上前缀。比如【info】、【warning】、【error】之类。如此一来,平时更着重关注的就是error级别的信息,而且由于将其他级别的信息剥离了出去,使得这里的数据量大大减少,更便于查看。不过,日志记录毕竟是一个在做“预判”,如果日志中没有记录到怎么办呢?这里提醒大家不要先想着怎么调试。如果你面对的系统是一个单体应用倒还好。如果你面对的是一个大型的分布式系统,调试的效率低不说,这事你一个人可能还完不成。而且,如果你直接调试生产环境的话,说不准还会产生什么副作用,摊上新的问题。找bug本质上是一个排除法的过程,设断点调试也是如此。但是从起点开始一步一步的做排除法效率太低了。应该先通过自己的经验、拥有的部分信息先逻辑推理一下,缩小排查的范围。哪怕你最终还是需要调试的话,先做这个事情也会让后续的工作更高效一些。第二点,利用工具。这里的“工具”不要简单的理解成利用“调试工具”。正如上面提到的,找bug的本质是一个排除法的过程,那么任何能够帮你更高效的做排除法的工具都是可以利用的。比如,从系统的「事件查看器」中获取更多的环境信息。利用windows平台的windbg、lunix平台的MAT之类的工具直接分析抓到的dump文件。借助可视化工具更高效的发现问题,如FlameGraph等。另外,如果能主动的告诉你哪里出现bug了,就更棒了。所以,我们可以搭建一套查看方便,信息同步及时的日志框架,以便让有价值的信息第一时间呈现在你的面前。如果有高效的筛选功能就更好了。很多日志框架Z哥没用过,就不发表什么言论了,但是elasticsearch + logstash + kibana这套用起来还是很爽的,体系也比较成熟,部署起来也很简单,大家可以尝试一下。再配上ElastAlert或者Sentinl,可以把实时预警机制也包含了。最后,每次的迭代规模尽可能的小。这个说起来容易,做起来难,因为这是由整个团队的文化来决定的。这个点的内容完全可以单独开一篇讲,这里就简要阐述下。MVP(Minimum Viable Product)式的小步快跑,其实除了让系统或者产品的功能演进更科学之外,还可以让每次迭代所面临的风险更小。正如前面提到的,你改一行代码发布上去,如果出问题,你说问题在哪?相对的,再想象一下,一次性发布一个开发了半年的版本,前一晚能睡的安稳不?总结好了,我们总结一下。这篇呢Z哥先阐述了我对“什么是bug”的理解,然后分析了bug是如何产生的,以及我们可能会做的一些惯性选择。最后给你的建议是,以如何更快的找到bug为出发点来考虑。通过「打好日志」、「学会利用工具」、「每次的迭代规模尽可能的小」这3种方式来进行。不过话说回来,虽然我们无法避免出bug(一个项目开发完后没测出bug?你问任何一个技术人员都说“做梦呢”),但是争取让bug更少是我们的本职工作。因为对bug容忍度低的另一层含义是,大家对系统的依赖越来越重,越来越多的事情在通过程序完成,而不是人力。但是再有人咄咄逼人,就把这篇文章丢给他!相关文章:就简单聊聊沟通效率问题作者:Zachary出处:https://www.cnblogs.com/Zacha…如果你喜欢这篇文章,可以点一下文末的「赞」。这样可以给我一点反馈。: )谢谢你的举手之劳。▶关于作者:张帆(Zachary,个人微信号:Zachary-ZF)。坚持用心打磨每一篇高质量原创。欢迎扫描下方的二维码~。定期发表原创内容:架构设计丨分布式系统丨产品丨运营丨一些思考。如果你是初级程序员,想提升但不知道如何下手。又或者做程序员多年,陷入了一些瓶颈想拓宽一下视野。欢迎关注我的公众号「跨界架构师」,回复「技术」,送你一份我长期收集和整理的思维导图。如果你是运营,面对不断变化的市场束手无策。又或者想了解主流的运营策略,以丰富自己的“仓库”。欢迎关注我的公众号「跨界架构师」,回复「运营」,送你一份我长期收集和整理的思维导图。

March 27, 2019 · 1 min · jiezi

我们应该如何给需求排序?

摘要: 需求管理是一门艺术。开发产品的时候,我们每天都会面对各种各样、没完没了的需求,有的来自外部用户的反馈,有的来自内部团队的idea,有的是产品的BUG,有的是新的功能…看起来只要实现所有需求,产品就可以变得更好,然后吸引更多的用户,接着赚更多的钱,之后招更多的人,再完成更多的需求…问题是,需求会源源不断地进来,我们永远也不可能清空所有需求,996也做不完,这辈子都不可能。我们能做的,是不断将需求排序,实现优先级最高的需求。那么问题来了,我们应该如何给需求排序?以用户为核心确定优先级乔布斯曾经说过:People don’t know what they want until you show it to them.用户真的不知道他们想要什么吗?很多时候并非如此。我负责产品,每天都会和用户交流,他们知道自己想要什么功能,有时会做好简单的交互设计、帮忙想想算法、甚至给我开源代码。问题在于,用户只是产品的使用者,他们对于产品的理解没有我们那么深刻,所以他们提出的需求有时会偏离问题的本质,需要我们进一步分析与挖掘。我们不是乔布斯,没有能力创造需求;我们也不是张小龙,没有1亿人教我们做产品。因此,我们应该多与用户交流,以用户需求为核心确定优先级:用户反馈或者吐槽的时候,耐心一些,聊得更深入一些,同时做好记录修复BUG,优化功能或者新增功能时,与感兴趣的用户主动联系,他们会给你更多的反馈定期做用户调研,听听沉默的大多数是怎么说的对于用户所提的需求,根据反馈用户多少、影响范围、难易程度进行排序当我们做产品的时候,创造的欲望是非常惊人的,总会有一些新的idea让我们激动不已,恨不得明天就能上线。但是,我们应该克制自己的创造欲,尊重用户的意见。我们的产品是给客户用的,不是给自己玩的。流量红利已经枯竭的时代,获取一个新用户比留住一个老用户难太多了,因此提高留存率显得非常重要。重视每一个用户反馈,及时修复他们发现的BUG,优先实现他们想要的功能,是提高留存率最有效的方式,没有之一。BUG的优先级高于新功能墨菲定律是这样的:Anything that can go wrong will go wrong.程序员应该都知道,代码怎么可能没有BUG呢?很多时候只是我们没有发现,或者是知道了却没有及时修复。然而,对于当前产品的BUG,我们往往容易忽视。可能是BUG隐藏的太深,我们和用户都没有发现;可能是用户发现BUG,但是没有反馈;也可能是我们选择性失明,觉得问题不大。事实上,用户对产品质量的要求非常严格,再小的问题他们也会发现,也会吐槽。用户反馈的话我们还能知道,否则我们可能很晚才发现BUG,如果没有监控的话。还有一种微妙的情况,当用户反馈貌似不可能出现的BUG时,我们会本能的觉得产品应该没有问题,问题应该出在用户那里,大概是他的浏览器或者网络,或者某种无法解释的原因导致的。其实,这只是我们在逃避问题,代码的运行方式是确定的,没有什么不能解释的地方,如果什么地方不太对劲了,那基本上是BUG。这里分享一个我们的经历:某个用户反馈,他在邀请成员加入团队的时候发现,偶尔会有那么一次邀请失败。我们检查了一下监控数据,发现确实有失败过,影响的用户不止一个,但是很少。然后,我们检查了一下前后端代码,发现没有问题。既然业务代码没有问题,那应该没有BUG,这事大概是什么奇怪的原因导致的,我们什么也不用做吧…后来,又有几个用户反馈同一个问题,报错也越来来越多,我们不可能再骗自己了!再次检查,业务代码确实没有问题,但是报错的代码位置的行号和列号都偏移了,这么诡异?不难猜测,生产环境运行的是旧代码!检查一下果然是这样。接着,不难发现部署的Docker配置文件有问题,导致某个节点部署的后端代码是旧的…我们总是这样,不停地向前走,不断地追求新的成就,逃避当下的问题。听着是不是很像我们的生活?对于产品BUG,我们应该第一时间修复,或者设置一个Deadline,新的功能可以稍微延后。如果我们不停地开发新功能,那当初开发这个有BUG的旧功能究竟是为了什么?如果我们忽略当前用户反馈的问题,那我们费这么大劲拉新是为了什么?结论需求管理是一门艺术,需要考虑和权衡的东西很多,暂时给大家一个简单的优先级排序,仅供参考:用户反馈的BUG自己发现的BUG用户反馈的需求自己想出的需求严格按照这个顺序操作是不可能的,这是给大家提供2个思考维度。实际工作中,每个需求的影响范围、紧急程度、难易程度也需要考虑。你有什么更好的想法吗?欢迎留言讨论!本文作者为Fundebug的技术总监,欢迎添加微信交流:KiwenLau。参考产品需求优先级的艺术 – Kano模型如何成为优秀的技术主管?你要做到这三点为什么美国程序员工作比中国程序员工作轻松、加班少?关于FundebugFundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java线上应用实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了10亿+错误事件,付费客户有Google、360、金山软件、百姓网等众多品牌企业。欢迎大家免费试用!

March 5, 2019 · 1 min · jiezi

git回滚错误合并的分支

场景线上分支:master你开发的分支:dev1同时开发的分支:dev2dev1分支开发的代码已经上线,并且已经merge到master同时dev2分支也已上线,并且已经merge到master这时发现dev1的巨大bug,线上版本要把这个分支的代码全部移除。想要达到的效果我们要撤销所有dev1的合并,并且保留dev2的代码。同时本地dev1的分支不想删除这些代码,还有在这基础上开发。master分支如果使用reset,那么线上的几个提交记录都不会保留,达不到我们想要的效果。这里使用git revert。首先我们要撤销所有dev1的更改,找到dev1的两次commit idgit revert 63db9b1228c9e38a015513f834a42fa55002fca8git revert a407174c5df3e47e1866663e4c3fe611419eb5a8此时master已经达到我们想要的效果:开发分支这时回到我们的dev1分支,修复bug,我还要保留以前提交的代码。但是在上线前总要先merge master,但是master的两次revert是领先你的,一旦merge后你的代码就没有了。下面是当前dev1的提交情况所以我们要在merge master后,再使用revert撤销这次merge。但是这时你发现,在merge完master之后你又在这个分支提交了新代码,这时revert就会报错:git revert ce479b597de6025da4a67ddd4a94d1b8034d8c67error: commit ce479b597de6025da4a67ddd4a94d1b8034d8c67 is a merge but no -m option was given.fatal: revert failed这是因为撤销的是一次合并,git不知道要保存这两个分支中哪个的修改。-m 1 表示保留当前分支的更改-m 2 表示保留master更改我们目的是为了保留dev1的代码,所以要保留当前代码,即使用 -m 1git revert -m 1ce479b597de6025da4a67ddd4a94d1b8034d8c67[dev1 bb363fa] Revert “Merge branch ‘master’ into dev1” 2 files changed, 0 insertions(+), 0 deletions(-) rename dev2 add => b (100%) create mode 100644 c执行完上面的代码,我们就会发现,代码又回来了,和master没有回滚前的代码一样。修完bug,再把当前代码合并到master,然后你就会发现,dev2提交的代码被你的merge干掉了???这是因为你的那次rever合并采用了你的分支代码,但是你的dev1分支并没有dev2的代码…所以我们应该在master回滚前,回到dev1分支,先merge一次最新代码,再执行后面的操作。总结总结起来流程很简单。1.保持你要开发的分支同步了master最新代码。2.revert所有该分支的提交。3.回到你的分支merge master。4.revert merge master的那次提交。

January 11, 2019 · 1 min · jiezi

定位问题的几种方法

遇到bug不要慌张,淡定!总结记录一下定位问题的几种方法1、回溯法通常程序都是 1-2-3-4-5这样按顺序执行的,根据错误提示反向查找,直至找到问题的根源,是最简单的方法2、二分法有时候遇到不知所以然的问题,可以使用二分法,例如将程序分为A、B两部分,只执行其中一部分,看程序是否可以 正常不正常 执行,然后在不正常的一部分内继续二分,不断的缩小查找范围3、对照法对照法通常用在程序可以正常运行,但是输出结果不对的情况下。这时候可以在正常的程序A、不正确的程序B内都打印日志,看看日志内的关键对象是否一致,达到快速分析出来问题的目的。4、执行最终SQL这种方法通常用在程序没有报错,正常运行情况下数据不对,或者数据库方面的错误的情况下,将最终要执行的SQL语句打印出来在数据库内执行,查看预期结果是否正确,再回溯错误原因通常这几种方法会结合使用,助你快速定位问题。

December 24, 2018 · 1 min · jiezi