一些提高开发效率的小体会

3,753 阅读7分钟

最近在工作中遇到了比较紧急的项目,短时间以及不能再删减(甚至还可能会变)的需求就意味着要尽可能地提升开发效率。前端因为与交互相关,因此会受到大部分需求变更的影响。如何尽可能地减少因需求变更而产生的工作量,一直以来都困扰着前端开发人员。

由于自己平时的代码风格还不够规范以及知识领悟不深,自然我也没少受苦,但也因此对提高开发效率方面有了一些体会。本文便是总结与复盘,用于日后提醒自己。

如何提高效率

对于我们做开发的同学来说,提高工作效率最有效的方法就是降低 BUG 率;而降低 BUG 率最有效的方法就是减少代码量。还记得 GitHub 上之前大火的项目 No Code 吗?资深的谷歌工程师告诉我们,一行代码都没有的程序是最安全的稳定的。

其次如果代码拓展性足够强,那么在面对需求变更时的工作量就会相对减少(作为前端,不变更时不存在的)。而增强代码拓展性比较常用的方法就是通用组件的封装与抽象。

下面就是有关于这两部分的一些总结和思考。

降低 BUG 的方法

良好的代码风格应该是降低 BUG 最有效的方法,可以参考《代码整洁之道》一书。下面的一些方法是我在平时工作中所总结出来的几点。

1. 减少代码量

代码量越少也就越难出现 BUG。在平时的工作中,应该尽可能地减少编写的代码量。在前端中,最简单的就是尽量使用 ES6 语法。相比 ES5,通过 ES6 的解构、箭头函数、async/await 可以减少 30% 以上的代码量。在有大量(3 个以上)的 if 判断时,可以使用对象的形式。

// 常规赋值操作
let a = 1
let b = 2
let c = 3
// 使用解构赋值
let [a,b,c] = [1,2,3]

// 使用 if
if(a === '1'){
  ....
}else if(a === '2'){
  ...
}else if(a === '3'){
  ....
}
...

// 使用对象进行分类处理, 逻辑上会更简洁一点
// PS:这个方法在 React 进行组件渲染的时候非常有用
const handleAction = (act) => {
  const actions = {
    '1': action1,
    '2': action2,
    '3': action3
  }
  const action = actions[act]
  action()
}
// 根据情况进行处理
handleAction('1')

在 React 的项目中,如果使用了 Redux。那么应该尽可能地使用 function 组件来减少代码。同时这么做也可以让我们在进行 UI 移植的时候省下很多改动(最近有一个项目是部分功能的迁移,Redux -> dva 在移植 function 组件时几乎没有什么改动),而且现在有了 Hook,function 组件中不能控制 state 的问题也能解决。

2. 设定默认值

缺少默认值非常容易造成 BUG,这是之前一个项目中血和泪的教训。特别是 React 项目中使用了上面介绍的对象的方法进行组件切换时,如果没有设置默认值就会直接造成页面崩溃。

class A extends React.Component {
  const Components = {
    // 特别是根据 Response 来进行组件切换时,应该设置 default 防止意外情况
    A: Component1,
    B: Component2,
    C: Component3,
    'default': () => <div />
  }

  render(){
    const {render} = this.state
    // 如果没有默认值,一旦对象匹配不到,页面直接崩溃
    const RenderComponent = Components[render] || Components.default
    return (
      <RenderComponent />
    )
  }
}

其次函数参数的默认值除了能减少 BUG 外也能帮助减少代码量。对于使用次数较多的方法,直接设置默认值可以让我们在调用时省去参数的传入。

// 当 0.0.0.1 和 api service 方法较多时,设为默认参数可以减少参数的传入
function customizeFetch(service='api', base = '0.0.0.1'){
  ...
}

customizeFetch()

3. 拆分函数与抽象方法

说到拆分函数,用的最多的应该是 request 的应用部分。比如对 fetch 的封装。

// 封装好的 fetch (有柯里化的影子在)
function customizeFetch(server = "api", base = "0.0.0.1") {
  return function(api = "", options = {}, withAuth = false) {
    const url = `${base}/${server}/${api}`;
    const opts = {
      method: options.method || "POST",
      headers: {
        // 可以设置默认参数,比如头什么的
        ...options.headers
      },
      body: {
        ...options.body
      }
    };

    return fetch(url, opts).then(response => response.json());
  };
}

// 当我们进行调用时,对于业务来说写起来基本一致
// 由于使用透传,其实在 service 还能偷懒写成一个方法
// 产品列表
const fetchAPI = customizeFetch("api1");
const getProductList = opts => {
  const options = {
    body: { ...opts }
  };
  return fetchAPI("getProductList", options);
};

// 新闻列表
const fetchAPI = customizeFetch("api2);
const getNewsList = opts => {
  const options = {
    body: { ...opts }
  };
  return fetchAPI("getNewsList", options);
};

4. 强类型和强检查

eslint 的好处就不用提了吧?再配合 prettier 可以让代码格式统一(umilint 虽然在不习惯时会觉得很烦,但是一旦习惯后对代码风格的提升还是很有帮助的)。如果再用上 TypeScript 更是可以让我们在编码时检查到错误。TypeScript 虽然在刚开始使用时很不习惯,特别是对于类型的强要求(全部 any 的话等于没有类型)很头痛。不过适应之后就能体会到 TypeScript 带来的快感了。

在引入 TypeScirpt 之后,最容易出现的 xxx from undefined 错误就能完全避免。可以帮助我们节省下许多调试的时间。

应对需求变更

前端的组件化开发,在更多的程度上是为了应对需求的变更(个人认为)。而由于前端是最接近用户的,因此只要需求有变是逃不过要进行一番修改的。因此让修改的工作量减少以及减少因修改带来的 BUG,也是提高效率的方法。

1. 提升副作用,尽量使用 Stateless 组件

对于 React/Vue 项目,只要使用了 Redux/Vuex 这类状态管理工具,我们就能很容易地把组件做成不依赖于 statestateless 组件。这类组件很“纯”基本只依赖于传入的 props,即便有 state 也是属于自治范围,不会参与业务逻辑计算。这么一来就能尽可能地让 UI 层更加纯净,职责更单一。(当然这只是一种美好的愿望,实际上根据副作用切换组件状态或者其他业务逻辑操作还是会让业务逻辑下沉到 UI 层去)

让 UI 层尽可能地变得简单,而处理业务逻辑的部分就应该转移到 Redux 的 action 的部分中。Reducer 的部分也应该尽量纯净,不做业务处理。这样如果当需求有变化的时候,修改的部分就能尽可能地被缩小在 action 部分,同时在做项目移植时也会比较方便(基本 action 层很大可能会重写)。当然实际中并不可能剥离得非常干净,UI 层往往也会跟着一起变动,不过还是可以减少修改的范围。

2. 通用业务组件的封装与抽象

另一个就是根据项目需求提炼出通用的业务组件,比如短信验证码、可编辑 label 的表单控件、权限验证组件、搜索组件等。这类组件基本与业务相关,基本是某个组件库的再封装(比如 antd),这个也是现在许多同学平时会做的。这样在某一个业务中可以减少我们的开发量。具体的可以使用 HOC 等方法来进行封装和抽象(比如权限验证组件)。

提炼组件固然不错,但是也要避免过度封装。曾经在写 Vue 的时候封装了一个可配置的表单组件,结果当业务需要两个表单控件的互相控制以及按钮状态控制时就傻眼了。因此在设计封装组件时也要考虑到之后业务的变化。

以上便是最近这段时间的一些工作感悟,算是作为自己的一个备忘。编程原本的目的就是提高做事的效率,而提高开发的效率又是每一个程序员都要面临的难题。所以编程是一件十分有意思的事情,其中一点就是可以不断地挑战和提升自己。