如何优雅地分析和防范前端 BUG?

发表于 3年以前  | 总阅读数:366 次

两个公式

开发效率 = 1 - (思考时间+编码时间+debug时间+改bug时间) / 迭代总时长

bug率 = bug数 / 测试用例数

八种问题

  • 需求理解不透彻 视觉交互没过细
  • 语言基础待加强 错误异常未处理
  • 代码逻辑太混乱 边界情况欠考虑
  • 后端接口常变动 二次修改漏东西

需求评审

需求理解

bug原因:

  • 开发和产品对需求的理解不一致
  • 前期经过沟通达成一致的需求,在开发后期忘做了
  • 多个模块关联同一份代码,需求文档只提到某一模块的改动,错估改动影响范围

方案:

  • 同一功能有多种实现方案,思考尽可能多的可能性,给产品出选择题,在理解上达成一致。比如可做可不做的功能,交互文档中未提到的细节
  • 写Q&A list,根据自己对需求的理解,以提问的方式写下Q,在自己思考到解决方案或和产品,交互,UI确认后,写下对应的A,每一个问题尽可能单一明确,在开发过程中既当作实现方案,又可当成用例进行自测
  • 充分理解现有系统,评估需求改动的影响范围,对相似模块提高警惕性,找熟悉系统的人了解

示例1:

思考实现一个自定义输入框的删除文字功能 有以下几种方式:

  • 退格键
  • 框选文字+退格键
  • 框选文字+Ctrl+X
  • Ctrl+A+退格键

示例2:

假设实现一个可根据题型进行排序的题目列表,以下是一个简单的QA list:

  • Q:题型排序需要实时保存吗?(和产品讨论)
  • A:实时保存。
  • Q:题型排序的实时保存方案?(思考方案)
  • A:首次进入按默认题型排序,经过题型排序后将顺序保存在本地,不走接口。
  • Q:本地缓存和接口中的题目顺序信息同时存在,题型顺序以哪个为准?(先讨论,后思考方案)
  • A:接口中的信息优先(讨论),先通过接口导出实际题目的题型顺序,再对本地缓存中存在的题型进行排序,更新本地缓存(方案)。

在不断的讨论+思考实现方案的循环下,需求和思路会越来越清晰。

技术实现

根据需求难易程度区分为简单需求,复杂需求

简单需求

  • 简单的增删改查
  • 展示多,交互少

这类需求出bug率较低,且易解决,不做讨论

复杂需求

  • 逻辑复杂

bug原因:

逻辑理解不清楚,思维混乱,导致写代码出错

方案:

写伪代码,将逻辑以代码的形式写出来,然后逐个去实现伪代码中的需求,每一个if里面尽量只有1个条件,方便理解

示例:

if(是作文){         
    if(在第一面的第一列){            
        if(当前面的总列数 - 1 >= col){                
            放到下一列        
        }else{                
            放到下一面的第一列        
        }    
    }else{            
        var 作文已占用的列数 = 0;        
        if(当前列只有这一个题目questionBox){                
            作文已占用的列数 = 1;            
        }        
        if(当前面的总列数 - 题目所在的列数 >= col - 作文已占用的列数){                
            正常跨页        
        }else{                
            放到下一面的第一列        
        }    
    } 
}
  • 功能复杂

bug原因:

需要实现的功能比较复杂,不能一步到位直接想出实现的思路

方案:

  • 正逆向思维推导,从易实现的功能和源数据开始正推,也可从结果开始逆推,然后去逐个思考每个功能点的实现方式
  • 构思出mvp版本,在此基础上不断完善功能
  • 拆分功能点,形成todolist,并附上优先级,在完成阶段性功能时, 逐一检查git提交文件
  • 和团队一起讨论解决方案,自己想出来的不一定是最好的,不成熟的方案会导致后期维护成本高,隐藏bug多

示例1:

录入编辑器功能比较复杂,大致流程是 OCR识别的题目结构 --> 编辑器结构 --> 编辑后的题目结构,可通过正向推导思考怎么从题目结构转化为编辑器结构,也可以通过逆向推导思考什么样的编辑器结构可以转化为题目结构,在推导过程中将功能做拆分,逐个实现

正向推导

逆向推导

示例2:

假如项目的实现功能点较多,可以先完成mvp版本,在其基础上去拆分功能点,列出todolist,有以下2种方式:

  1. 在技术方案文档中列出,优点是有层级结构,一个功能点可以接着拆出更多子功能点。
  2. 通过数据表列出,并打上标签(比如优先级、功能模块等),优点是分类、排序比较方便,更加清晰。
  • 基于第三方库的使用

bug原因:

  • 库本身的缺陷
  • 多个开发者对库的使用方式的差异,导致后期维护成本增加,出现bug

方案:

  • 使用第三方库前先看下issue list,看作者维护是否积极,大致浏览下前两页的issue,看自己用到的功能是否有提及
  • 看changelog日志是否规范,文档是否更新及时
  • 在多个库都能实现相同功能的前提下综合考虑前两项
  • 根据业务需要,可以对库进行二次封装,写成业务需要的api或组件。好处是业务相关的api或组件更容易被开发者所理解,并且统一了使用方式,减轻维护成本
  • 在综合考量实现成本和维护成本下,也可以选择自己实现

码前准备

  • 放松心态,专注防打扰
  • 多方业务同时进行时,列出每日计划,排优先级,设deadline提醒,来一件事情记一项,有条不紊
  • 如果被打扰太多次,白天处理动脑少的事,晚上处理动脑多的事,或者带回家做

编程习惯

语言基础

this指向

示例:

var person = {    
    age: '12',    
    say: function(){        
        console.log(this.age);    
    } 
}  
var foo = function(func){    
    this.age = 15;    
    func(); 
};  
foo(person.say); // 15

内存

常见bug:

  • 递归死循环,导致堆栈溢出;内存泄露

同步异步

常见bug:

  • 执行顺序不清楚

方案:

了解事件循环的机制,清楚promise,setTimeout等的执行顺序

引用传递

示例:

var obj = {    
    a: {        
        b: 1,    
    } 
}; 
var obj2 = obj.a; 
obj2.b = 2; 
console.log(obj.a.b); // 2

运算符

常见bug:

  • 对使用运算符后的结果计算出错

示例:

++a; a++;
相等比较和类型转换:'0' 0 false null undefined NaN

错误异常

SyntaxError(语法错误)

常见提示:

  • Unexpected token

方案:

  • 检查一下是不是少了括号,或者变量定义不符合规范

Uncaught ReferenceError(引用错误)

常见提示:

  • xxx is not defined

方案:

  • 一般eslint可以检查出来,检查一下变量所在的作用域

TypeError(类型错误)

bug原因:

  • 常出现在函数的返回值或参数中,由于参数或返回值可能是多种类型导致使用的错误
  • 没有给参数默认值,参数变成undefined

常见提示:

  • xxx is not a function

方案:

  • 给函数的参数默认值
  • 对函数的参数和返回值在使用时先做类型校验,或者统一类型

代码逻辑

bug原因:

  • 重复代码太多,在后期修改同一个功能时需要重复改多份,容易漏改
  • 一个函数包含的代码太多,阅读困难,难以理解
  • 一个函数包含的逻辑太多,做了多个操作,耦合性强,难以维护
  • if else的分支太多,写起来容易出错
  • 前人挖坑自己填,自己挖坑坑自己

方案:

  • 给每一个函数加上注释,标明输入输出的值的含义

  • 尽量写成纯函数,幂等设计

  • 减少重复代码,提炼成公共的函数,提炼需注意,如果提炼出来的函数不能给出一个合理的注释,就不要提

  • 如果单个函数不能用一段简单的描述表达,则可能需要将其拆分成多个函数

  • 如果单个函数代码行数超过100行,则可能需要将函数内部的一些逻辑写成函数提出来

  • 单个函数尽量只做一个操作,如果单个函数做了多个操作,可以将其修改成主操作+回调的形式,这样可以解耦多个操作

  • 如果if else分支过多,可分为2种情况处理:

  • 单层级的if else,可以用switch或hash代替

  • 嵌套型的if else,将易判断的逻辑放在前面,处理完后使用return退出后续判断,减少嵌套

  • 不断自我review,自我质疑:

  • 如果下次我要改这块东西好不好改?

  • 如果这段代码给别人看能不能看懂?

  • 如果我3个月后再来看自己的代码,能不能看懂?

  • 现在的需求是否已考虑了大部分情况,好不好扩展?

  • 这个组件好不好复用,是否逻辑耦合,是否可以抽象?

示例:

  • 函数内部减少代码行数,提炼公共函数
// 将获取a,b,c的逻辑写成函数的形式调用,减少代码体积 
function foo1() {    
    var a = getA();    
    var b = getB();    
    var c = getC();    
    return a + b + c; 
}  
function foo2() {    
    var a = getA();    
    var b = getB();    
    var c = getC();    
    return a - b - c; 
}  
// 是否需要一个函数getABC,取决于该函数的功能是否能用一段简单的描述表达 
function getABC() {    
    var a = getA();    
    var b = getB();    
    var c = getC();    
    return { a, b, c }; 
}
  • 多个操作拆成主操作+回调
// getAndSetData函数获取数据,并且处理数据,渲染UI,getAndSaveData函数获取数据,但是只保存数据,这时函数变得耦合
function getAndSetData(){    
    http.get('/list').success(res => {              
        const data = this.dealData(res);        
        this.render(data);    
    }) 
}  
function getAndSaveData(){    
    http.get('/list').success(res => {        
        this.saveData(res);    
    }) 
}  
// 改成回调参数的形式,getData只做请求数据的操作,其他操作以回调参数传入 
function getData(callback){    
    http.get('/list').success(res => {              
        callback.call(this, res);    
    }) 
}  
getData(res => {    
    const data = this.dealData(res);    
    this.render(data); 
});  
getData(this.saveData);  
// 改成链式,代码更清晰 
function getData(){          
    return new Promise(resolve => {        
        http.get('/list').success(res => {                      
            resolve(res);            
        });    
    }); 
}  
getData().then(res => {    
    const data = this.dealData(res);    
    this.render(data); 
});  
getData().then(res => this.saveData(res));
  • if else单层级优化
// 原始写法 
if(number == 1){    
    deal1(); 
}else if(number == 2){    
    deal2(); 
}else if(number == 3){    
    deal3(); 
}else{    
    deal4(); 
}  
// switch优化 
switch (number) {    
    case 1:        
        deal1();        
        break;    
    case 2:        
        deal2();        
        break;    
    case 3:        
        deal3();        
        break;    
    default:        
        deal4();        
        break; 
    }  
// hash优化 
const obj = {    
    1: deal1,          
    2: deal2,          
    3: deal3,          
    default: deal4, 
}; 
obj[number] ? obj[number]( "number] ? obj[number") : obj['default']( "'default'");
  • if else多层级嵌套优化
if(a){    
    deal1(); 
}else {    
    if(b){        
        deal2();    
    }else{        
        if(c){            
            deal3();        
        }else{            
            deal4();        
        }    
    } 
}  
// 优化 
if(a){    
    deal1();          
    return; 
} 
if(b){    
    deal2();          
    return; 
} 
if(c){    
    deal3();          
    return; 
} 
if(d){    
    deal4();          
    return; 
}

测试方法

数据层面

bug原因:

  • 数值的边界情况没有考虑,常见于接口无数据时的显示,组件应有的状态值没考虑全

方案:

  • 数值的变化会引起视图的变化,则去尝试数值的所有可能性

说明:

  • 数据来源一般是接口或者自己创造,数值不一定是指纯数字,也可以是单一状态的不同值

示例1:

  • 给出一个列表数据,实现一个分页选择器,一页10条,就需要考虑不同数据量下的展示与交互:

  • 无数据(无数据的展示)
  • 3条数据(只有1页)
  • 10条数据(边界情况,测试是否也是1页)
  • 11条数据(出现2页,点击页码跳页)
  • 20条数据(边界情况,测试是否也是2页)
  • 21条数据(出现3页,测试从第1页直接跳到第3页)
  • 100条数据(分页处的UI改变,会出现省略号)

示例2:

  • 文案展示,UI一般只会给一种理想情况,这里需要综合考虑多个数值的变化:

  • 文字容器宽度是定宽还是根据文字长度自适应
  • 无文字,少量文字,文字过长下的展示
  • 浏览器屏幕宽度缩放下的文案展示

交互层面

bug原因:

  • 未考虑某些非习惯性交互或者组合交互的情况

方案:

  • 如果多个交互会影响到同一数据或视图,则去尝试这些交互的组合

说明:

  • 一次交互是指一次操作(click, hover, drag)或一次数据自动变化(延时, 异步, socket)会引起数据或视图的改变

示例:

  • 以题型筛选项作为视图来看,其交互只有点击题型1个
  • 以题目列表作为视图来看,其交互有题型选择、难度选择、知识点切换、教辅切换、分页切换、加入作业、页内全选、作业篮子清空8个
  • 反复快速的切换精品题库和本校题库,看右侧列表数据是否是最后一次点击后的题目数据,测试race condition
  • 组合切换知识树,教辅和题库,看右侧列表数据是否正确

思维方式

产品思维

思考为什么要做,为什么其他产品不做,理解需求的意义**用四象限法评估需求价值:必要性,难易度**

  • 非必要且容易,和产品讨论,让产品说服自己,可以妥协
  • 非必要且复杂,据理力争,别给自己挖坑
  • 必要且容易,那就直接做
  • 必要且复杂,觉得有必要做的一定是自己已经充分理解了的,合理就应该做,可以参考功能复杂和逻辑复杂下的处理方式

如何评估必要性:

  • 对现有系统的破坏程度,影响范围
  • 站在用户的角度,这个功能对我有没有用
  • 是否会破坏用户体验

学生思维

用解数学题的逻辑思维去写代码

  • 看到题目(需求)就能意识到注意的点,比如要做分类讨论(数值变化测试),反证法(逆向推导)
  • 有解题思路再下笔(先充分理解需求,再写代码)

将每一次迭代开发都当作一场考试,提测是交卷,改完bug再次提测是补考

  • 在考试完后看到成绩进步时,动力会更大,更期待下一次的检验
  • 小学考满分次数多,其次初中,高中;能力提高,写法更高级,bug越难发现,但解决完bug后自我提升更明显,程序设计能力和开发效率都会提高
  • 提高第一次考试的成绩,减少补考的次数

把 bug 记录当成错题本

  • 每次解决完bug,在评论中记录bug原因
  • 分析归纳bug原因
  • 反思总结,挖掘更深层级的原因,避免在同一个地方摔倒两次
  • 定时回顾,下次遇到类似需求提高警惕意识

本文由哈喽比特于3年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/JonxbCa1l1QOKk3-gUWwRg

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237231次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8065次阅读
 目录