仓库源文站点原文


title: 工作五年,后面四年重复着第一年的活儿? description: 当我们沉浸在旺盛的需求之中时,整个人便会成为一台工作的机器,切着类似的页面,写着同样的逻辑,重复着昨天或者上个月做的事情,时间久了,觉得腻味,没有什么创新,也没有明显的成长。用一句通俗的话来讲:工作五年,后面四年重复着第一年的活儿。 warning: true categories:


当我们沉浸在旺盛的需求之中时,整个人便会成为一台工作的机器,切着类似的页面,写着同样的逻辑,重复着昨天或者上个月做的事情,时间久了,觉得腻味,没有什么创新,也没有明显的成长。用一句通俗的话来讲:工作五年,后面四年重复着第一年的活儿。

//unsplash.com/photos/EaGsRRRcKjc by Khara Woods<!--<source src="https://ww1.sinaimg.cn/large/6c0378f8gw1f61wl4o981j20p00dwwhx.jpg">-->

<!--more-->

很多人尝试跳出这个怪圈,不过基于环境压力和思维受阻,最后又不得不选择放弃。今天想通过介绍如何高效有保障地开发一个无线页面来帮助大家找到突破口。

日常开发状态

很多无线页面的开发有两种模式,一种是后台输出 JSON 数据,前端根据数据来渲染页面(同步模式);第二种是前端异步加载后端数据然后渲染(异步模式)。当然,两种模式夹杂在一起也是存在的,这种情况一般会有一个由前端控制的中间层提供同步数据和异步数据。为了减少前后端的沟通成本,往往采用第二种模式。

拿到设计稿后,与后端同学约定接口格式,让后端同学尽快提供 mock 数据,如果提供不了,便自己构造测试数据。接着回到自己的工位上切图,切图过程中会解决好响应式问题和兼容性问题,待到后端产出真实数据时,更换 JS 中的接口地址,联调 ok 便发布页面,大功告成!

整个流程很顺畅,这对一个工作了三四年的程序员来说,没有任何压力便完成甚至提前完成了任务。但是,回过头来想一想,整个开发过程中我们留下了什么?沉淀了什么?

放慢节奏,我们再走一遍流程

对于上面的开发流程,先提出几个常见的问题:

上面提出的几个问题,列的不全面。有一些可能是你经常碰到的,甚至有了成熟的解决方案,而也有一些问题可能是你从未考虑过的。

我们把整个前端开发流程做简单切割:切图、获取数据、渲染、事件绑定、数据统计、页面优化、监控。这种切割很暴力,也比较粗糙,不过它不妨碍我们在下面讨论,作为前端工程师,除了完成日常需求外,还要做什么?还能做什么?

切图

隐约还记得三年前,我接了一个无线页面的外包活儿,页面的结构很简单,但我做的很糟糕。为了适配不同尺寸的机型,我写了无数 Media Query,加上当时采用的 em 作单位,很多细节位置都没控制好。

回到现在,已经有了很通用、主流的方案——使用 rem,动态计算 html 标签的 font-size,思路很简单,但是存在不少的坑,和一些较难理解的概念,Google 搜索下 lib-flexible 能够找到这些问题以及解决方案。不过我们切图时还可以思考一些其他的问题:

以上问题,没有哪一个会让人特别苦恼,但是堆积起来,却让我们的开发效率和开发体验落后了好几个档次。这些问题并非无解,我们可以尝试着帮助同事和团队找到问题的答案,比如:

有些解决方案只需要几行脚本就能搞定,而有一些可能需要投入时间和精力。

获取数据

本地、预发、线上三套环境,如何做到环境的顺滑切换?我在百度的时候,团队最常用的方案就是:

可一旦与后端约定的接口有变动,本地 mock 数据也要跟着一起变动。这个问题有什么好的处理方案?在团队中,好的方案一定不是几行文字的提示或指引,而是通过流程和监控来控制!

这里提到的获取数据,细想之下可不是什么轻松的事情。有很多问题需要思考:

以上每个问题都有很多处理方案,而这些问题不仅仅是自己会遇到,身边的同事也会遇到。如果可以站在团队的角度去思考问题,很多思路会比较容易涌现出来,比如:

数据是最容易出问题的地方,每一个接口请求都需要一大堆的逻辑处理异常。倘若接口格式、开发流程和前端模式都可以规范化,我们需要做的就剩下套公式,这种高效你能否想象?

渲染

大胆地揣测下大家在写一个模块的时候,跟我一样也是这么划分的函数:

var Module = function() {
  this.init();
};

// 初始化
Module.prototype.init = function() {
  this.fetchData(function() {
    // do something
  });
};

// 绑定事件
Module.prototype.bindEvent = function() {
  // ...
};

// 获取数据
Module.prototype.fetchData = function(cb) {
  var self = this;
  ajax({}).then(function(data) {
    self.renderData(data);
  }).catch(function() {
    self._fetchDataFailed();
  }).fin(function() {
    cb && cb();
  });
};

// 渲染数据
Module.prototype.renderData = function(data) {
  data = this._resolveData(data);
  // ...
  this.bindEvent();
};

// 处理数据
Module.prototype._resolveData = function() {
  // ...
};

// 加载失败
Module.prototype._fetchDataFailed = function() {
  // ...
};

不管一个模块有多么简单,它基本都会包含以上步骤,倘若没有用函数隔离每步操作的意图,代码会显得十分散乱。我经常看到,有同学把「渲染」这一块的代码被放到「获取数据」甚至是「初始化」中,这种程序结构显然是不合理的。同时,也经常会看到渲染时,

以上,没有哪一种是不正确的,我也没有对哪一种写法开喷的意图。但是至少我们可以在多次编程经验中提炼出一些有价值的内容:

有一个可执行的编码规范,加上适当合理的 Code Review,整个团队代码便会如出一辙。

后续操作

本想写成一篇长文,把每个环节可以综合考虑的问题都提出来,不过本文的目的,只是表述一些观点,期望大家在编程的时候,有更多基于团队的思考,针对具体问题提出一些通用的解决方案。比如下面,再提出几个问题:

以上问题,都有相当成熟的解决方案,那你们团队呢?

小结

当发现工作做起来索然无味的时候,我脑海中蹦出来的第一个念头是:最近是不是有点放纵了?

我喜欢用编程解决问题,只要是重复的事情,我一定会想尽办法简化,然后交给机器去做。我希望今年可以用程序解决更多的问题。