开发效率 = 1 - (思考时间+编码时间+debug时间+改bug时间) / 迭代总时长
bug率 = bug数 / 测试用例数
bug原因:
方案:
示例1:
思考实现一个自定义输入框的删除文字功能 有以下几种方式:
示例2:
假设实现一个可根据题型进行排序的题目列表,以下是一个简单的QA list:
在不断的讨论+思考实现方案的循环下,需求和思路会越来越清晰。
根据需求难易程度区分为简单需求,复杂需求
这类需求出bug率较低,且易解决,不做讨论
bug原因:
逻辑理解不清楚,思维混乱,导致写代码出错
方案:
写伪代码,将逻辑以代码的形式写出来,然后逐个去实现伪代码中的需求,每一个if里面尽量只有1个条件,方便理解
示例:
if(是作文){
if(在第一面的第一列){
if(当前面的总列数 - 1 >= col){
放到下一列
}else{
放到下一面的第一列
}
}else{
var 作文已占用的列数 = 0;
if(当前列只有这一个题目questionBox){
作文已占用的列数 = 1;
}
if(当前面的总列数 - 题目所在的列数 >= col - 作文已占用的列数){
正常跨页
}else{
放到下一面的第一列
}
}
}
bug原因:
需要实现的功能比较复杂,不能一步到位直接想出实现的思路
方案:
示例1:
录入编辑器功能比较复杂,大致流程是 OCR识别的题目结构 --> 编辑器结构 --> 编辑后的题目结构,可通过正向推导思考怎么从题目结构转化为编辑器结构,也可以通过逆向推导思考什么样的编辑器结构可以转化为题目结构,在推导过程中将功能做拆分,逐个实现
正向推导
逆向推导
示例2:
假如项目的实现功能点较多,可以先完成mvp版本,在其基础上去拆分功能点,列出todolist,有以下2种方式:
bug原因:
方案:
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(语法错误)
常见提示:
方案:
Uncaught ReferenceError(引用错误)
常见提示:
方案:
TypeError(类型错误)
bug原因:
常见提示:
方案:
bug原因:
方案:
给每一个函数加上注释,标明输入输出的值的含义
尽量写成纯函数,幂等设计
减少重复代码,提炼成公共的函数,提炼需注意,如果提炼出来的函数不能给出一个合理的注释,就不要提
如果单个函数不能用一段简单的描述表达,则可能需要将其拆分成多个函数
如果单个函数代码行数超过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(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(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:
示例2:
bug原因:
方案:
说明:
示例:
思考为什么要做,为什么其他产品不做,理解需求的意义**用四象限法评估需求价值:必要性,难易度**
如何评估必要性:
用解数学题的逻辑思维去写代码
将每一次迭代开发都当作一场考试,提测是交卷,改完bug再次提测是补考
把 bug 记录当成错题本
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8