前言

这两天在好几个地方都看到了一篇关于为什么整个互联网行业都缺前端工程师?的文章,文章本身是去年的,中心思想是:其实我们并不缺前端工程师,我们缺的是优秀的前端工程师。我还是比较同意作者观点的,不过略有意犹未尽的感觉。于是我结合自己的经验,也来聊一下这个话题:我们真的缺前端工程师吗?

These walls are kind of funny like that. First you hate them, then you get used to them.Enough time passed, get so you depend on them. That’s institutionalising.

传统软件公司划分开发者的方式下,在前端部门的程序员永远不会去读缓存数据部分的代码,设计师也不太可能去和开发坐在一起,开发也不知道软件最终软件会以何种方式部署在服务器上。

什么是“前端”工程师

我在招聘广告和办公室的一些对话中,听到了一个新的角色:UI Dev,事实上我在知乎上还回答过一个关于ThoughtWorks的UI Dev的问题。简而言之,UI Dev可以快速的把设计师的作品实现为HTML/CSS/JavaScript代码。

front-end development

如果按照这个标准,我觉得UI Dev对自己的要求太低了。毕竟要学会HTML/CSS实现mockup并不困难,但是成为一名前端工程师则需要掌握更多的知识:

  • 会用PS来进行图片的处理(比如切图,微调等)
  • 用HTML/CSS实现mockup(可能还有SASS/LESS等工具)
  • 熟悉JavaScript(比如前端的MVVM框架,客户端模板)
  • 前端开发的工作流程(代码检查,精简化,模块化CSS,LiveReload,调试)
  • 编写测试(静态检查,单元测试)
  • 跨浏览器、跨设备的解决方法(不同分辨率,不同厂商)
  • 会根据项目的特点选择不同的前端技术栈(移动端,Web站点,响应式设计等)

在有了基础的HTML/CSS/JS技能之后,你会尝试做的更好:

  • 如何更高效的操作DOM
  • 如何将CSS写的更加清晰易懂
  • 如何编写更加易于维护的代码(更有意义的单元测试)
  • 如何组织大型的项目结构,模块化,组件化等等

这些要求事实上已经不那么容易做到了。它可能会花费你2到3年时间来完全掌握。但是2到3年之后,即便你已经成为了一个“合格的”前端工程师,这也还远远不够。在现实世界中,一个软件产品除了前端,还有非常广阔的空间,还有很多有趣的东西值得学习:

  • HTTP协议本身(缓存,鉴权)
  • Web容器/HTTP服务器如何工作
  • 无状态的Web应用的工作原理(如何让网站正确地运行在集群上)
  • 动态,静态内容如何分离部署(反向代理配置)
  • 安全机制如何配置
  • 监控机制如何配置

有了这些,也算是有点端到端的意思了。这时你也已经不是一个“纯前端”工程师了,系统中的大部分问题你都可以搞定,不过日常工作中可能更多的职责还是做前端的开发。但是这些还不够,软件除了交付之外,还有一些非功能性的需求:

  • 端到端测试(UI测试,比如selenium server/web driver)
  • devops(比如数据库环境,测试服务器,CI服务器的自动化provision)
  • 基本的UI设计原则(在某些页面确实的情况下,根据系统的已有UI做设计)
  • 数据库性能优化
  • 性能测试

不过这些还只是我对于Web开发这个领域的总结。其他领域,比如大数据,机器学习,GIS,图像/视频处理等等。

这时候,你才能算是一个严格意义上的“前端”工程师。不从系统的角度来思考,不真正做一些后端开发/配置,并不能算是前端工程师,或者可以被称为偏前端工程师(partial frontend developer)。但是即使称为上边这样的“前端工程师”,我想这离一个优秀的工程师还是有很大差距的。

我跟一位设计师同事聊过这个问题:

Dev眼中的世界是这样的,从墙上(物理的或者电子的)上找到一些卡片(story卡或者需求文档说明书),然后撸袖子开干,干的过程中有很多自以为是的理解,同样有一些自以为是的牛逼实践(TDD啊,自动化啊),最后功能做完,大功告成,然后接着做下一个卡片。传统的Dev,或者苦逼屌丝程序员的世界就是这样的:需求从哪儿来,不知道;做完之后谁来负责质量,不知道;最终上线的时候怎么发布,不知道;线上有问题了怎么办,不知道。

以及

在ThoughtWorks,Dev的工作有了很大的变化,一个最明显的变化是边界的模糊。比如很多项目都不设QA角色,所有人都对质量负责,都做测试,也有OPs角色,但是大部分非生产环境都是Dev自己发布。也就是说,软件/项目生命周期中的大部分实践我们都能涉足,而且可以带来改进,提升效率。但是这只是往下游(从开发,到测试,到部署,到运维),反过来看上游,比如需求从哪儿来,Dev还是不知道。这毫无疑问是一个令人沮丧的事实,因为这需求的产生才是核心,也就是我昨天跟你聊的:一个idea如何变成一个可视化的原型,然后进一步演进为项目原型?

开发工作不应该仅仅局限在编码上,作为开发者/工程师,应该尽可能的多了解一些上下文:比如我们的项目最终是给谁用的,需求从何而来,项目是如何部署在线上的等等。

software life cycle

简而言之,开发者视野应该放开开阔一些。不要将自己局限在某种角色上,不但不要局限在前端/后端开发上,压根就不要局限在开发这种角色本身上,你在系统中,可以是设计师,还可以是业务分析师。虽然不一定最终要你去转行做BA,或者UX,但是更广阔的视野可以使你更加高效的发挥自己的作用,也可以在和别的角色互动式,快速的了解上下文。

我所理解的,前端不一定要熟知所有这些知识和技能,但是一定不要认为自己做好了前端的一亩三分地就足够了,不要给自己设限。跨界会给你带来难以估量的好处,一个角色做久了,难免会产生一些盲点。这时候,换个视角,从其他角色的角度来看待你的工作,又会有很多新的发现。而且不仅如此,很可能你会发现之前很麻烦,很难搞定的事情,在新的方法/视角下变得很容易。

我的故事

其实,我是一名后端开发

工作之后,我在很长一段时间是专注于“非前端”的领域。和很多刚入行的新人一样,我对计算机能触及的几乎一切领域都感兴趣:语言解释器,人工智能(遗传算法,隐式马尔科夫模型,自动纠错,模式识别),嵌入式开发,图形处理,操作系统的进程调度,进程间通信,多线程模型,各种脚本语言(python,ruby,JavaScript等等),另外,日常开发流程中的一些工具的定制化也会花去我很多的时间,比如如何配置vim,写几个小脚本来和编辑器做集成等等。更别说那些令人一听就觉得激动的编程范式:面向对象,基于消息总线,函数式编程等等。如果你感兴趣,可以看看我几年前的博客

我的上一家公司的产品是一个省级电网的收费/计费系统(电其实和我们在超市里购买的其他生活用品一样,也是一种商品)。我在那里工作了差不多两年,日常的开发方式就是ssh登陆到RHEL(Redhat Enterprise Linux)服务器上,用vim(当然有一堆的vim插件)开发C代码,调试器是gdb(对,就是那个很牛逼,但是对新手特别不友好的gdb)。

我们用C语言给Apache的httpd写了一个扩展module,大约相当于现在rack里的中间件,这个module要和后端的一个要复杂的多的模块通信,其中不但涉及网络通信,还有*nix管道,缓冲,并发等等考虑。在这两年里,我几乎没有碰过任何的Web界面上的东西(除了用php写了一两百行的页面之外)。

在加入这家公司之前,我在一家用Java做报表的公司工作,技术栈为J2EE。其中有一些前端的工作,但是并不很多,而且说实话,我当时有些看不太上这些技术。HTML/CSS在我心目中的地位比线程池,语言解析等差远了,所以我也没有认真地去系统学习。

在加入ThoughtWorks之前,在“前端”方面,唯一算是比较擅长的也不过是写JavaScript,而且对于前端的MVVM框架,双向绑定,模块化等高级货都没听过。且不能论HTML/CSS的最佳实践,连根据设计稿做出一个静态页面的的能力也不具备。我之前有一点JSP/HTML经验,而CSS经验也并没有超出如何画一个细线表格的范畴。换句话说,我的前端(特别是HTML/CSS)是最近才学会的。

ThoughtWorks的开发

在ThoughtWorks,很多团队是按照feature团队来组建的。相对于传统的component团队(按部门划分,比如研发组,测试组,设计组等,每个组还有可能会再细分成如用户调研,流程设计,视觉设计等等),feature团队里配备了软件开发过程中需要的几乎所有角色:业务分析,测试工程师,开发工程师,设计师(设计师一般不会常驻),有的团队还有项目经理的角色。

在feature团队里,你可以很容易看到不同的角色是如何工作的,很多时候,开发会和设计师一起来调整颜色,排版,布局,也可能和测试一起编写自动化测试用例,showcase等。也就是说,角色之间的藩篱在淡化,而就开发这一种角色而言,对于前端/后端的区分也会显得非常模糊,因为需求划分之后的story(敏捷开发中的一个术语,其实就是需求的一种展现方式)是端到端的,比如一个商品列表展示的story,会包括

  • 数据库的表结构
  • 访问数据库的ORM部分,
  • 使用ORM的业务逻辑service
  • 响应客户端的controller(消费JSON或者XML的HTTP接口)
  • 发送请求,处理响应的JavaScript代码
  • 和设计稿一致的CSS样式

而且在这个过程中还会涉及到一些外围的工具

  • 虚拟机环境准备
  • 数据库连接
  • 自动化测试(单元测试,集成测试,可能还有UI测试)
  • 数据库迁移脚本

在这个过程中,开发者需要掌握和开发过程相关的一切实践中的一切工具.

在我的ThoughtWorks的第一个项目中,我是以Java开发工程师角色加入的,下项目的时候,我学会了自动化provision,cucumber测试工具,Rails,gradle(没错,我之前用Java都是用IDE构建的,在Linux世界我用make),jasmine测试工具,Backbone.js,haml.js。

第二个项目的时候,我是以前端工程师角色加入,下项目的时候,我学会了nginx配置缓存、负载均衡服务器,gatling测试工具,Hadoop/Spark等的集群配置,还有一些和项目相关的GIS(地理信息系统)的技术栈,前后端分离策略等。

第三个项目我是以Java开发工程师角色加入的,下项目的时候,我学会了如何做性能测试,如何建立一个漂亮的Dashboard(可以用来展现CI等),而且在业余时间系统的学习了CSS3和HTML5,将之前零敲碎打的那些知识串起来,这些总结做了几次内部培训后,还整理成了一本电子书

第四个项目我又变成了一个前端工程师,但是这个项目有意思的地方是跟mobile相关,于是页面性能,体验又变成了一个重点,下项目的时候,我对无状态的Web应用,session的持久化,CSS3的动画,用Backbone.js组织多页面的方式等等又有了新的理解。

如果这些经历造成了你觉得我很牛的错觉,那我应该道歉。我觉得自己勉强可以算是个合格的程序员:对学习保持着热情,对解决问题保持着热情,仅此而已。在项目上,如果我发现了问题,我就想办法解决,如果属于知识欠缺,那我就会去学习。我还远远没有到达精通这些技术的地步,但是在工程实践领域,根据80/20原则,这些粗浅的知识足以解决80%的问题,而另外的20%,我们才真正需要一个专家来帮忙。也就是说,团队里需要有一个能解决20%的问题的前端工程师,而其他的80%的前端工作,应该可以被其他所有的开发完成,对于后端开发也是一样。

尝试从系统级别去解决一个问题,而不是将问题抛给另外一个角色(后端工程师,UX或者QA)

我是一个Dev,但是花了一些时间来学习界面设计,这里是我从设计到实现的两个小页面:

ilearn

lightweight

总结

我们缺的从来都不是前端/后端工程师,而是工程师(或者那些会系统思考,并总是想着解决问题的人)。角色划分在大的机构内可能是有意义的,就像历史上工厂里,工人被分为车工,钳工,木工,电工。但是这种模式在软件开发中未必好用,具体而微的小团队可能更具竞争力。而在一个个的小团队中,再细分前端后端就显得比较滑稽了。团队中的每个成员都应该具备基本的端到端能力(不仅仅是开发,更应该是具有业务上下文,即每个人都清楚我们要交付的最终产品是什么,以及这个产品是如何帮助最终用户的),每个成员也都需要为最终的交付物负责,而不是为自己的职责负责。