我们需要更加优秀灵活的开发框架来协助我们更

作者: mgm娱乐网址  发布:2019-11-08

线上质量保障:前端之难,不在前端

前端开发完成并不意味着万事大吉,笔者在一份周报中写道,我们目前所谓的Bug往往有如下三类:
(1)开发人员的粗心大意造成的Bug:此类型Bug不可避免,但是可控性高,并且前端目前配置专门的辅助单元测试人员,此类型Bug最多在开发初期大规模出现,随着项目的完善会逐步减少。
(2)需求变动造成的Bug:此类型Bug不可避免,可控性一般,不过该类型Bug在正式环境下影响不大,最多影响程序员个人情绪。
(3)接口变动造成的Bug:此类型Bug不可避免,理论可控性较高。在上周修复的Bug中,此类型Bug所占比重最大,建议未来后端发布的时候也要根据版本划分Release或者MileStone,同时在正式上线后设置一定的灰度替代期,即至少保持一段时间的双版本兼容性。

线上质量保障,往往面对的是很多不可控因素,譬如公司邮件服务欠费而导致注册邮件无法发出等问题,笔者建立了frontend-guardian,希望在明年一年内予以完善:

  • 实时反馈产品是否可用
  • 如果不可用,即时通知维护人员
  • 如果不可用,能够迅速辅助定位错误

frontend-guardian希望能是尽量简单的实时监控与回归测试工具,大公司完全可以自建体系或者基于Falcon等优秀的工具扩展,不过小公司特别是在创业初期希望尽可能地以较小的代价完成线上质量保障。

函数式思维:抽象与直观

近年来随着应用业务逻辑的日益复杂与并发编程的大规模应用,函数式编程在前后端都大放异彩。软件开发领域有一句名言:可变的状态是万恶之源,函数式编程即是避免使用共享状态而避免了面向对象编程中的一些常见痛处。函数式编程不可避免地会使得业务逻辑支离破碎,反而会降低整个代码的可维护性与开发效率。与React相比,Vue则是非常直观的代码架构,每个Vue组件都包含一个script标签,这里我们可以显式地声明依赖,声明操作数据的方法以及定义从其他组件继承而来的属性。而每个组件还包含了一个template标签,等价于React中的render函数,可以直接以属性方式绑定数据。最后,每个组件还包含了style标签而保证了可以直接隔离组件样式。我们可以先来看一个典型的Vue组件,非常直观易懂,而两相比较之下也有助于理解React的设计思想。

在现代浏览器中,对于JavaScript的计算速度远快于对DOM进行操作,特别是在涉及到重绘与重渲染的情况下。并且以JavaScript对象代替与平台强相关的DOM,也保证了多平台的支持,譬如在ReactNative的协助下我们很方便地可以将一套代码运行于iOS、Android等多平台。总结而言,JSX本质上还是JavaScript,因此我们在保留了JavaScript函数本身在组合、语法检查、调试方面优势的同时又能得到类似于HTML这样声明式用法的便利与较好的可读性。

1 从功能开发角度说,React的思路很好。
2 从页面设计角度说,传统的HTML+CSS以及同样思路的模板更好。

纷扰之虹

笔者在前两天看到了Thomas Fuchs的一则Twitter,也在Reddit等社区引发了热烈的讨论:我们用了15年的时间来分割HTML、JS与CSS,然而一夕之间事务仿佛回到了原点。
图片 1分久必合,合久必分啊,无论是前端开发中各个模块的分割还是所谓的前后端分离,都不能形式化的单纯按照语言或者模块来划分,还是需要兼顾功能,合理划分。笔者在2015-我的前端之路:数据流驱动的界面中对自己2015的前端感受总结中提到过,任何一个编程生态都会经历三个阶段,第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。在2016的上半年中,笔者在以React的技术栈中挣扎,也试用过VueJS与Angular等其他优秀的前端框架。在这一场从直接操作DOM节点的命令式开发模式到以状态/数据流为中心的开发模式的工具化变革中,笔者甚感疲惫。在2016的下半年中,笔者不断反思是否有必要使用React/Redux/Webpack/VueJS/Angular,是否有必要去不断追逐各种刷新Benchmark 记录的新框架?本文定名为工具化与工程化,即是代表了本文的主旨,希望能够尽可能地脱离工具的束缚,回归到前端工程化的本身,回归到语言的本身,无论React、AngularJS、VueJS,它们更多的意义是辅助开发,为不同的项目选择合适的工具,而不是执念于工具本身。

总结而言,目前前端工具化已经进入到了非常繁荣的时代,随之而来很多前端开发者也甚为苦恼,疲于学习。工具的变革会非常迅速,很多优秀的工具可能都只是历史长河中的一朵浪花,而蕴藏其中的工程化思维则会恒久长存。无论你现在使用的是React还是Vue还是Angular 2或者其他优秀的框架,都不应该妨碍我们去了解尝试其他,笔者在学习Vue的过程中感觉反而加深了自己对于React的理解,加深了对现代Web框架设计思想的理解,也为自己在未来的工作中更自由灵活因地制宜的选择脚手架开阔了视野。

引言的最后,我还想提及一个词,算是今年我在前端领域看到的出镜率最高的一个单词:Tradeoff(妥协)。

小而美的视图层

React 与 VueJS 都是所谓小而美的视图层Library,而不是Angular 2这样兼容并包的Frameworks。任何一个编程生态都会经历三个阶段,第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。
React 并没有提供很多复杂的概念与繁琐的API,而是以最少化为目标,专注于提供清晰简洁而抽象的视图层解决方案,同时对于复杂的应用场景提供了灵活的扩展方案,典型的譬如根据不同的应用需求引入MobX/Redux这样的状态管理工具。React在保证较好的扩展性、对于进阶研究学习所需要的基础知识完备度以及整个应用分层可测试性方面更胜一筹。不过很多人对React的意见在于其陡峭的学习曲线与较高的上手门槛,特别是JSX以及大量的ES6语法的引入使得很多的传统的习惯了jQuery语法的前端开发者感觉学习成本可能会大于开发成本。与之相比Vue则是典型的所谓渐进式库,即可以按需渐进地引入各种依赖,学习相关地语法知识。比较直观的感受是我们可以在项目初期直接从CDN中下载Vue库,使用熟悉的脚本方式插入到HTML中,然后直接在script标签中使用Vue来渲染数据。随着时间的推移与项目复杂度的增加,我们可以逐步引入路由、状态管理、HTTP请求抽象以及可以在最后引入整体打包工具。这种渐进式的特点允许我们可以根据项目的复杂度而自由搭配不同的解决方案,譬如在典型的活动页中,使用Vue能够兼具开发速度与高性能的优势。不过这种自由也是有利有弊,所谓磨刀不误砍材工,React相对较严格的规范对团队内部的代码样式风格的统一、代码质量保障等会有很好的加成。
一言蔽之,Vue会更容易被纯粹的前端开发者的接受,毕竟从直接以HTML布局与jQuery进行数据操作切换到指令式的支持双向数据绑定的Vue代价会更小一点,特别是对现有代码库的改造需求更少,重构代价更低。而React及其相对严格的规范可能会更容易被后端转来的开发者接受,可能在初学的时候会被一大堆概念弄混,但是熟练之后这种严谨的组件类与成员变量/方法的操作会更顺手一点。便如Dan Abramov所述,Facebook推出React的初衷是为了能够在他们数以百计的跨平台子产品持续的迭代中保证组件的一致性与可复用性。

     大家开发前端的思路早已不是当年的 Web page,而是Application。大多数公司不是Facebook,没有那么多全栈高手。团队中擅长写业务的,未必擅长页面布局;擅长页面布局的,未必擅长写业务。这样在团队中必定会有分工,其中会有些人着重实现炫酷的页面效果,而React显然对这种分工不友好。

相辅相成的客户端渲染与服务端渲染

  • Tradeoffs in server side and client side rendering
    Roy Thomas Fielding博士的Architectural Styles andthe Design of Network-based Software Architectures

笔者在2015-我的前端之路提及最初的网页是数据、模板与样式的混合,即以经典的APS.NET、PHP与JSP为例,是由服务端的模板提供一系列的标签完成从业务逻辑代码到页面的流动。所以,前端只是用来展示数据,所谓附庸之徒。而随着Ajax技术的流行,将WebAPP也视作CS架构,抽象来说,会认为CS是客户端与服务器之间的双向通信,而BS是客户端与服务端之间的单向通信。换言之,网页端本身也变成了有状态。从初始打开这个网页到最终关闭,网页本身也有了一套自己的状态,而拥有这种变化的状态的基础就是AJAX,即从单向通信变成了双向通信。图示如下:

图片 2

上文描述的即是前后端分离思想的发展之路,而近两年来随着React的流行服务端渲染的概念重回人们的视线。需要强调的是,我们现在称之为服务端渲染的技术并非传统的以JSP、PHP为代表的服务端模板数据填充,更准确的服务端渲染作用的描述是对于客户端应用的预启动与预加载。我们千方百计将客户端代码拉回到服务端运行并不是为了替换现有的API服务器,并且在服务端运行过的代码同样需要在客户端重新运行,这里推荐参考笔者的Webpack2-React-Redux-Boilerplate,按照三个层次地渐进描述了从纯客户端渲染到服务端渲染的迁移之路。引入服务端渲染带来的优势主要在于以下三个方面:

  • 对浏览器兼容性的提升,目前React、Angular、Vue等现代Web框架纷纷放弃了对于旧版本浏览器的支持,引入服务端渲染之后至少对于使用旧版本浏览器的用户能够提供更加友好的首屏展示,虽然后续功能依然不能使用。
  • 对搜索引擎更加友好,客户端渲染意味着整体的渲染用脚本完成,这一点对于爬虫并不友好。虽然现代爬虫往往也会通过内置自动化浏览器等方式支持脚本执行,但是这样无形会加重很多爬虫服务器的负载,因此Google这样的大型搜索引擎在进行网页索引的时候还是依赖于文档本身。如果你希望提升在搜索引擎上的排行,让你的网站更方便地被搜索到,那么支持服务端渲染是个不错的选择。
  • 整体加载速度与用户体验优化,在首屏渲染的时候,服务端渲染的性能是远快于客户端渲染的。不过在后续的页面响应更新与子视图渲染时,受限于网络带宽与重渲染的范畴,服务端渲染是会弱于客户端渲染。另外在服务端渲染的同时,我们也会在服务端抓取部分应用数据附加到文档中,在目前HTTP/1.1仍为主流的情况下可以减少客户端的请求连接数与时延,让用户更快地接触到所需要的应用数据。

总结而言,服务端渲染与客户端渲染是相辅相成的,在React等框架的协助下我们也可以很方便地为开发阶段的纯客户端渲染应用添加服务端渲染支持。

前后端分离与全栈:技术与人

前后端分离与全栈并不是什么新鲜的名词,都曾引领一时风骚。Web前后端分离优势显著,对于整个产品的开发速度与可信赖性有着很大的作用。全栈工程师对于程序员自身的提升有很大意义,对于项目的初期速度有一定增速。如果划分合理的话能够促进整个项目的全局开发速度与可信赖性,但是如果划分不合理的话只会导致项目接口混乱,一团乱麻。

我们常说的前后端分离会包含以下两个层面:

  • 将原本由服务端负责的数据渲染工作交由前端进行,并且规定前端与服务端之间只能通过标准化协议进行通信。
  • 组织架构上的分离,由早期的服务端开发人员顺手去写个界面转变为完整的前端团队构建工程化的前端架构。

前后端分离本质上是前端与后端适用不同的技术选型与项目架构,不过二者很多思想上也是可以融会贯通,譬如无论是响应式编程还是函数式编程等等思想在前后端皆有体现。而全栈则无论从技术还是组织架构的划分上似乎又回到了按照需求分割的状态。不过呢,我们必须要面对现实,很大程度的工程师并没有能力做到全栈,这一点不在于具体的代码技术,而是对于前后端各自的理解,对于系统业务逻辑的理解。如果我们分配给一个完整的业务块,同时,那么最终得到的是无数个碎片化相互独立的系统。

虚拟 DOM

虚拟 DOM 解决了频繁操作 DOM
产生的性能问题。那么下面几项事实必定会导致这一特性「没有前途」:

  1. 设备的硬件性能会越来越好,性能在将来不再是问题。
  2. 假如说我们要解决性能问题,相比虚拟 DOM,
    下面几个解决方案会更好:
  3. 浏览器实现虚拟 DOM。而且这也是虚拟 DOM 被应用的正确场景和姿势。
  4. 再操作数据的地方做 diff,而不是在虚拟 DOM 的基础上做 diff。这是才是 cache/diff 的正确用法。

后记

2016年末如往昔一般很多优秀的总结盘点文章涌现了出来,笔者此文也是断断续续写了好久,公司项目急着上线,毕业论文也是再不写就要延期的节奏。这段时间笔者看了很多大家之作后越发觉得自己的格局与眼光颇低,这也是笔者一直在文中提及我的经验与感触更多的来自于中小创团队,希望明年能够有机会进一步开拓视野。如果哪位阅读本文的伙伴有好的交流群推荐欢迎私信告知,三人行,必有我师,笔者也是希望能够接触一些真正的大神。

1 赞 收藏 评论

图片 3

工程化

所谓工程化,即是面向某个产品需求的技术架构与项目组织,工程化的根本目标即是以尽可能快的速度实现可信赖的产品。尽可能短的时间包括开发速度、部署速度与重构速度,而可信赖又在于产品的可测试性、可变性以及Bug的重现与定位。

  • 开发速度:开发速度是最为直观、明显的工程化衡量指标,也是其他部门与程序员、程序员之间的核心矛盾。绝大部分优秀的工程化方案首要解决的就是开发速度,我们在追寻局部速度最快的同时不能忽略整体最优,初期单纯的追求速度而带来的技术负债会为以后阶段造成不可弥补的损害。
  • 部署速度:程序员在日常工作中,最常对测试或者产品经理说的一句话就是,我本地改好了,还没有推送到线上测试环境呢。在DevOps概念深入人心,各种CI工具流行的今天,自动化编译与部署帮我们省去了很多的麻烦。但是部署速度仍然是不可忽视的重要衡量指标,特别是以NPM为代表的难以捉摸的包管理工具与不知道什么时候会抽个风的服务器都会对我们的编译部署过程造成很大的威胁,往往项目依赖数目的增多、结构划分的混乱也会加大部署速度的不可控性。
  • 重构速度:听产品经理说我们的需求又要变了,听技术Leader说最近又出了新的技术栈,甩现在的十万八千里。
  • 可测试性:现在很多团队都会提倡测试驱动开发,这对于提升代码质量有非常重要的意义。而工程方案的选项也会对代码的可测试性造成很大的影响,可能没有无法测试的代码,但是我们要尽量减少代码的测试代价,鼓励程序员能够更加积极地主动地写测试代码。
  • 可变性:程序员说:这个需求没法改啊!
  • Bug的重现与定位:没有不出Bug的程序,特别是在初期需求不明确的情况下,Bug的出现是必然而无法避免的,优秀的工程化方案应该考虑如何能更快速地辅助程序员定位Bug。

无论是前后端分离,还是后端流行的MicroService或者是前端的MicroFrontend,其核心都是牺牲局部开发速度换来更快地全局开发速度与系统的可信赖性的提高。而区分初级程序员与中级程序员的区别可能在于前者仅会实现,仅知其然而不知其所以然,他们唯一的衡量标准就是开发速度,即功能实现速度或者代码量等等,不一而足。中级程序员则可以对自己负责范围内的代码同时兼顾开发速度与代码质量,会在开发过程中通过不断地Review来不断地合并分割,从而在坚持SRP原则的基础上达成尽可能少的代码量。另一方面,区分单纯地Coder与TeamLeader之间的区别在于前者更注重局部最优,这个局部即可能指项目中的前后端中的某个具体模块,也可能指时间维度上的最近一段的开发目标。而TeamLeader则更需要运筹帷幄,统筹全局。不仅仅要完成老板交付的任务,还需要为产品上可能的修改迭代预留接口或者提前为可扩展打好基础,磨刀不误砍材工。总结而言,当我们探究工程化的具体实现方案时,在技术架构上,我们会关注于:

  • 功能的模块化与界面的组件化
  • 统一的开发规范与代码样式风格,能够在遵循SRP单一职责原则的前提下以最少的代码实现所需要的功能,即保证合理的关注点分离。
  • 代码的可测试性
  • 方便共享的代码库与依赖管理工具
  • 持续集成与部署
  • 项目的线上质量保障

单元测试

前后端分离后,意味着更多的业务逻辑将融入到前端程序中, 对应的我们需要前端工程师需要完成对应业务逻辑的单元测试, 以确保前端质量不会逐渐沦陷.

  • 基于 JavaScript 的单元测试被证明是一种高效的测试方法,其中 71% 的组织执行了 JavaScript 单元测试,而 84% 的组织则相信它是有益的!
  • Jasmine 和 Mocha 是最流行的 JavaScript 单元测试框架,Jasmine 主要配合 AngularJS 进行单元测试,而 Mocha 则与 ReactJS 配合使用。

目前前端自动化单元测试社区情况:

Jasmine & Protractor (72.4%),

Jasmine & Karma (67.7%),

Jasmine & Jest (58.3%),

Karma & Protractor (58.6%).

渐进的状态管理

  • redux-mobx-confusion

在不同的时间段做不同的事情,当我们在编写纯组件阶段,我们需要显式声明所有的状态/数据,而对于Action则可以放入Store内延后操作。以简单的表单为例,最初的时候我们会将表单的数据输入、验证、提交与结果反馈等等所有的逻辑全部封装在表单组件内。而后随着组件复杂度的增加,我们需要针对不同功能的代码进行切分,此时我们就可以建立专门的Store来处理该表单的状态与逻辑。抽象来说,我们在不同的阶段所需要的状态管理对应为:

  • 原型:Local State

这个阶段我们可能直接将数据获取的函数放置到componentDidMount中,并且将UI State与Domain State都利用setState函数存放在LocalState中。这种方式的开发效率最高,毕竟代码量最少,不过其可扩展性略差,并且不利于视图之间共享状态。

XHTML

// component <button onClick={() => store.users.push(user)} />

1
2
// component
<button onClick={() => store.users.push(user)} />

这里的store仅仅指纯粹的数据存储或者模型类。

  • 项目增长:External State

随着项目逐渐复杂化,我们需要寻找专门的状态管理工具来进行外部状态的管理了:

JavaScript

// component <button onClick={() => store.addUser(user)} /> // store <a href="; addUser = (user) => { this.users.push(user); }

1
2
3
4
5
6
7
// component
<button onClick={() => store.addUser(user)} />
 
// store
<a href="http://www.jobbole.com/members/Francesco246437">@action</a> addUser = (user) => {
  this.users.push(user);
}

这个时候你也可以直接在组件内部修改状态,即还是使用第一个阶段的代码风格,直接操作store对象,不过也可以通过引入Strict模式来避免这种不良好的实践:

JavaScript

// root file import { useStrict } from 'mobx'; useStrict(true);

1
2
3
4
// root file
import { useStrict } from 'mobx';
 
useStrict(true);
  • 多人协作/严格规范/复杂交互:Redux

随着项目体量进一步的增加与参与者的增加,这时候使用声明式的Actions就是最佳实践了,也应该是Redux闪亮登场的时候了。这时候Redux本来最大的限制,只能通过Action而不能直接地改变应用状态也就凸显出了其意义所在(Use Explicit Actions To Change The State)。

JavaScript

// reducer (state, action) => newState

1
2
// reducer
(state, action) => newState

React?Vue?Angular 2?

React,Vue,Angular 2都是非常优秀的库与框架,它们在不同的应用场景下各自具有其优势。Vue最大的优势在于其渐进式的思想与更为友好的学习曲线,Angular 2最大的优势其兼容并包形成了完整的开箱即用的All-in-one框架,而这两点优势在某些情况下反而也是其劣势,也是部分人选用React的理由。很多对于技术选型的争论乃至于谩骂,不一定是工具的问题,而是工具的使用者并不能正确认识自己或者换位思考他人所处的应用场景,最终吵的驴唇不对马嘴。

AngularJS

    在富应用开发中,跟Angular完全没得比,在同等熟练条件下,Angular开发效率=五倍React=三倍backbone=十倍jquery,然而虚拟dom并没有什么乱用,二十一世纪,效率为王,Angular万岁,它代表了前端最先进的生产力,代表了前端先进文化的前进方向,代表了最广大前端的根本利益,然而一切抄袭angular造轮子的技术都将被历史的车轮碾压,粉身碎骨。

Angular很清晰的劣势

- Angular的Dependency Injection很丑,为了minify还要用array写两遍变量名

- Angular的module和es6 module兼容性很不好

- Scope chain只能让人越用越糊涂。Controller as也没改善太多

- Provider, Factory, Service其实是一样的东西

- 目前的最佳实践是页面上所有东西都用Directive,强制组件化(那为啥不直接用React?)

- 侵入性太强,需要学很多Angular特有的语法,track by, transclude, $开头的所有变量,scope, promise. http 都必须使用它提供的

何谓工程化

所谓工程化,即是面向某个产品需求的技术架构与项目组织,工程化的根本目标即是以尽可能快的速度实现可信赖的产品。尽可能短的时间包括开发速度、部署速度与重构速度,而可信赖又在于产品的可测试性、可变性以及Bug的重现与定位。

  • 开发速度:开发速度是最为直观、明显的工程化衡量指标,也是其他部门与程序员、程序员之间的核心矛盾。绝大部分优秀的工程化方案首要解决的就是开发速度,不过笔者一直也会强调一句话,磨刀不误砍材工,我们在追寻局部速度最快的同时不能忽略整体最优,初期单纯的追求速度而带来的技术负债会为以后阶段造成不可弥补的损害。
  • 部署速度:笔者在日常工作中,最长对测试或者产品经理说的一句话就是,我本地改好了,还没有推送到线上测试环境呢。在DevOps概念深入人心,各种CI工具流行的今天,自动化编译与部署帮我们省去了很多的麻烦。但是部署速度仍然是不可忽视的重要衡量指标,特别是以NPM为代表的难以捉摸的包管理工具与不知道什么时候会抽个风的服务器都会对我们的编译部署过程造成很大的威胁,往往项目依赖数目的增多、结构划分的混乱也会加大部署速度的不可控性。
  • 重构速度:听产品经理说我们的需求又要变了,听技术Leader说最近又出了新的技术栈,甩现在的十万八千里。
  • 可测试性:现在很多团队都会提倡测试驱动开发,这对于提升代码质量有非常重要的意义。而工程方案的选项也会对代码的可测试性造成很大的影响,可能没有无法测试的代码,但是我们要尽量减少代码的测试代价,鼓励程序员能够更加积极地主动地写测试代码。
  • 可变性:程序员说:这个需求没法改啊!
  • Bug的重现与定位:没有不出Bug的程序,特别是在初期需求不明确的情况下,Bug的出现是必然而无法避免的,优秀的工程化方案应该考虑如何能更快速地辅助程序员定位Bug。

无论是前后端分离,还是后端流行的MicroService或者是前端的MicroFrontend,其核心都是牺牲局部开发速度换来更快地全局开发速度与系统的可信赖性的提高。而区分初级程序员与中级程序员的区别可能在于前者仅会实现,仅知其然而不知其所以然,他们唯一的衡量标准就是开发速度,即功能实现速度或者代码量等等,不一而足。中级程序员则可以对自己负责范围内的代码同时兼顾开发速度与代码质量,会在开发过程中通过不断地Review来不断地合并分割,从而在坚持SRP原则的基础上达成尽可能少的代码量。另一方面,区分单纯地Coder与TeamLeader之间的区别在于前者更注重局部最优,这个局部即可能指项目中的前后端中的某个具体模块,也可能指时间维度上的最近一段的开发目标。而TeamLeader则更需要运筹帷幄,统筹全局。不仅仅要完成老板交付的任务,还需要为产品上可能的修改迭代预留接口或者提前为可扩展打好基础,磨刀不误砍材工。总结而言,当我们探究工程化的具体实现方案时,在技术架构上,我们会关注于:

  • 功能的模块化与界面的组件化
  • 统一的开发规范与代码样式风格,能够在遵循SRP单一职责原则的前提下以最少的代码实现所需要的功能,即保证合理的关注点分离。
  • 代码的可测试性
  • 方便共享的代码库与依赖管理工具
  • 持续集成与部署
  • 项目的线上质量保障

相辅相成的客户端渲染与服务端渲染

最初的网页是数据、模板与样式的混合,即以经典的APS.NET、PHP与JSP为例,是由服务端的模板提供一系列的标签完成从业务逻辑代码到页面的流动。所以,前端只是用来展示数据,所谓附庸之徒。而随着Ajax技术的流行,将WebAPP也视作CS架构,抽象来说,会认为CS是客户端与服务器之间的双向通信,而BS是客户端与服务端之间的单向通信。换言之,网页端本身也变成了有状态。从初始打开这个网页到最终关闭,网页本身也有了一套自己的状态,而拥有这种变化的状态的基础就是AJAX,即从单向通信变成了双向通信。

而近两年来随着React的流行服务端渲染的概念重回人们的视线。需要强调的是,我们现在称之为服务端渲染的技术并非传统的以JSP、PHP为代表的服务端模板数据填充,更准确的服务端渲染作用的描述是对于客户端应用的预启动与预加载。我们千方百计将客户端代码拉回到服务端运行并不是为了替换现有的API服务器,并且在服务端运行过的代码同样需要在客户端重新运行。

引入服务端渲染带来的优势主要在于以下三个方面:

  • 对浏览器兼容性的提升,目前React、Angular、Vue等现代Web框架纷纷放弃了对于旧版本浏览器的支持,引入服务端渲染之后至少对于使用旧版本浏览器的用户能够提供更加友好的首屏展示,虽然后续功能依然不能使用。

  • 对搜索引擎更加友好,客户端渲染意味着整体的渲染用脚本完成,这一点对于爬虫并不友好。虽然现代爬虫往往也会通过内置自动化浏览器等方式支持脚本执行,但是这样无形会加重很多爬虫服务器的负载,因此Google这样的大型搜索引擎在进行网页索引的时候还是依赖于文档本身。如果你希望提升在搜索引擎上的排行,让你的网站更方便地被搜索到,那么支持服务端渲染是个不错的选择。

  • 整体加载速度与用户体验优化,在首屏渲染的时候,服务端渲染的性能是远快于客户端渲染的。不过在后续的页面响应更新与子视图渲染时,受限于网络带宽与重渲染的范畴,服务端渲染是会弱于客户端渲染。另外在服务端渲染的同时,我们也会在服务端抓取部分应用数据附加到文档中,在目前HTTP/1.1仍为主流的情况下可以减少客户端的请求连接数与时延,让用户更快地接触到所需要的应用数据。

总结而言,服务端渲染与客户端渲染是相辅相成的,在React等框架的协助下我们也可以很方便地为开发阶段的纯客户端渲染应用添加服务端渲染支持。

总结

   因为没有完美的框架,只有适合的应用场景,选择我们自己更适合的。
      框架都只是为了开发效率良好地组织项目代码,并不完全是为性能而生。 注意IT时代在变, 任何技术都会演进, 凡是存在的, 都是合理的。
       服务端研发工程师也少有全栈工程师。React.js适合长期, 用户体验高的交互多的项目或信息系统产品。


今天先到这儿, 希望对您在团队管理, 项目管理, 产品管理, 系统架构 有参考作用 , 您可能感兴趣的文章:
前端工程师技能整理
精益IT组织与分享式领导
企业信息化与软件工程的迷思
企业项目化管理介绍
软件项目成功之要素
人际沟通风格介绍一
精益IT组织与分享式领导
学习型组织与企业
企业创新文化与等级观念
组织目标与个人目标
初创公司人才招聘与管理
人才公司环境与企业文化
企业文化、团队文化与知识共享
高效能的团队建设
项目管理沟通计划
构建高效的研发与自动化运维
某大型电商云平台实践
互联网数据库架构设计思路
IT基础架构规划方案一(网络系统规划)
餐饮行业解决方案之客户分析流程
餐饮行业解决方案之采购战略制定与实施流程
餐饮行业解决方案之业务设计流程
供应链需求调研CheckList
企业应用之性能实时度量系统演变

如有想了解更多软件设计与架构, 系统IT,企业信息化, 团队管理 资讯,请关注我的微信订阅号:

图片 4

作者:Petter Liu
出处:
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。

接口

接口主要是负责进行数据获取,同时接口层还有一个职责就是对上层屏蔽服务端接口细节,进行接口组装合并等。笔者主要是使用总结出的Fluent Fetcher,譬如我们要定义一个最常见的登录接口:

 

建议开发人员接口写好后

JavaScript

/** * 通过邮箱或手机号登录 * @param account 邮箱或手机号 * @param password 密码 * @returns {UserEntity} */ async loginByAccount({account,password}){ let result = await this.post('/login',{ account, password }); return { user: new UserEntity(result.user), token: result.token }; }

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    /**
     * 通过邮箱或手机号登录
     * @param account 邮箱或手机号
     * @param password 密码
     * @returns {UserEntity}
     */
    async loginByAccount({account,password}){
        let result = await this.post('/login',{
            account,
            password
        });
 
        return {
            user: new UserEntity(result.user),
            token: result.token
        };
    }

,直接简单测试下:

JavaScript

let accountAPI = new AccountAPI(testUserToken); accountAPI.loginByAccount({account:'wyk@1001hao.com',password:'1234567'}).then((data) => { console.log(data); });

1
2
3
4
5
let accountAPI = new AccountAPI(testUserToken);
 
accountAPI.loginByAccount({account:'wyk@1001hao.com',password:'1234567'}).then((data) => {
  console.log(data);
});

这里直接使用babel-node进行运行即可,然后由专业的测试人员写更加复杂的Spec。

工具化的不足:抽象漏洞定理

抽象漏洞定理是Joel在2002年提出的,所有不证自明的抽象都是有漏洞的。抽象泄漏是指任何试图减少或隐藏复杂性的抽象,其实并不能完全屏蔽细节,试图被隐藏的复杂细节总是可能会泄漏出来。抽象漏洞法则说明:任何时候一个可以提高效率的抽象工具,虽然节约了我们工作的时间,但是,节约不了我们的学习时间。我们在上一章节讨论过工具化的引入实际上以承受工具复杂度为代价消弭内在复杂度,而工具化滥用的结局即是工具复杂度与内在复杂度的失衡。

谈到这里我们就会明白,不同的项目具备不同的内在复杂度,一刀切的方式评论工具的好坏与适用简直耍流氓,而且我们不能忽略项目开发人员的素质、客户或者产品经理的素质对于项目内在复杂度的影响。对于典型的小型活动页,譬如某个微信H5宣传页,往往注重于交互动画与加载速度,逻辑复杂度相对较低,此时Vue这样渐进式的复杂度较低的库就大显身手。而对于复杂的Web应用,特别是需要考虑多端适配的Web应用,尽量使用React这样相对规范严格的库。

Vue.js

     Vue.js是2016年发展最快的JS框架之一,而且我认为它的崛起并不是因为粉丝的过度追捧,也不是因为某个大公司的权威推动。

Vue.js的优势

    Vue.js在可读性、可维护性和趣味性之间做到了很好的平衡。Vue.js处在React和Angular 1之间,而且如果你有仔细看Vue的指南,就会发现Vue.js从其它框架借鉴了很多设计理念。Vue.js从React那里借鉴了组件化、prop、单向数据流、性能、虚拟渲染,并意识到状态管理的重要性。Vue.js从Angular那里借鉴了模板,并赋予了更好的语法,以及双向数据绑定(在单个组件里)。从我们团队使用Vue.js的情况来看,Vue.js使用起来很简单。它不强制使用某种编译器,所以你完全可以在遗留代码里使用Vue,并对之前乱糟糟的jQuery代码进行改造。

    Vue.js可以很好地与HTML和JS一起协作。你可以开发出非常复杂的模板,而不会影响你对业务的专注,而且这些模板一般都具有很好的可读性。当模板膨胀到很大的时候,说明你在业务实现方面已经取得进展,这个时候你或许想把模板拆分成更小的组件。相比项目启动之初,此时你对应用的整体“映像”会有更好的把握。

    这个跟在React里不太一样:Vue.js帮我节省了很多时间。在React里,在一开始就要把组件拆分成微组件和微函数,否则你会很容易迷失在乱糟糟的代码里。在React里,你需要花很多时间在一次又一次的整理prop和重构微组件(这些组件可能永远都不会被重用)上面,因为如果不这么做,在修改应用逻辑时就看不清方向。

    在Vue里面使用表单是件轻而易举的事情。这个时候双向绑定就会派上用场。就算是在复杂的场景里也不会出现问题,不过watcher乍一看会让人想起Angular 1。在你拆分组件的时候,会经常用到单向数据流和回调传递。

    如果你需要用到编译器的一些特性、lint、PostCSS和ES6,你会如愿以偿。在Vue.js 2里,Vue的扩展特性将会成为开发公共组件的默认方式。顺便提一下,开箱即用的组件CSS看起来是个好东西,它们可以减少对CSS层级命名和BEM的依赖。

    Vue.js的核心具有简单有效的状态和prop管理机制,它的data()和props()方法在实际当中可以有效地工作。通过Vuex可以实现更好的关注点分离(它跟React里的Mobx有点类似,都包含了部分可变状态)。

    大部分Vue.js场景都不需要Vuex提供的状态管理,不过多一个选择总不是坏事。

Vue.js的不足

  1. 最大的一个问题:模板的运行时错误描述不够直观,这个跟Angular 1有点类似。Vue.js为JS代码提供了很多有用的警告信息,例如当你试图改变prop或不恰当地使用data()方法时,它会给出警告。这也是从React借鉴过来的比较好的方面。但对模板的运行时错误处理仍然是Vue的一个弱项,它的异常堆栈信息总是指向Vue.js的内部方法,不够直观。

  2. 这个框架还很年轻,还没有稳定的社区组件。大部分组件是为Vue.js 1创建的,对于新手来说有时候难以区分它们的版本。不过你可以在不使用其它第三方库的前提下在Vue里面完成很多事情,你可能需要一些ajax库(如果你不关心同构应用,可以考虑vue-resource)或者vue-router,这在一定程度上平衡了Vue在组件方面存在的不足。

3. 社区软件包里的代码有很多中文注释,这一点也不奇怪,因为Vue.js在中国很流行(它的作者就是个中国人)。

4. Vue.js是由一个人维护的项目,这个也算不上大问题,不过还是要考虑其它一些因素。尤雨溪是Vue的作者,他曾经在Google和Meteor工作,在那之后他创建了Vue。Laravel也曾经是一个单人项目,不过后来也很成功,但谁知道呢……

渐进的前端架构

笔者心中的前端架构如下所示,这里分别按照项目的流程与不同的开发时间应该开发的模块进行说明:

图片 5

纷扰

分久必合,合久必分啊,无论是前端开发中各个模块的分割还是所谓的前后端分离,都不能形式化的单纯按照语言或者模块来划分,还是需要兼顾功能,合理划分。

任何一个编程生态都会经历三个阶段:

  • 第一个是原始时期,由于需要在语言与基础的API上进行扩充,这个阶段会催生大量的Tools。
  • 第二个阶段,随着做的东西的复杂化,需要更多的组织,会引入大量的设计模式啊,架构模式的概念,这个阶段会催生大量的Frameworks。
  • 第三个阶段,随着需求的进一步复杂与团队的扩充,就进入了工程化的阶段,各类分层MVC,MVP,MVVM之类,可视化开发,自动化测试,团队协同系统。这个阶段会出现大量的小而美的Library。

本文的主旨希望能够尽可能地脱离工具的束缚,回归到前端工程化的本身,回归到语言的本身,无论React、AngularJS、VueJS,它们更多的意义是辅助开发,为不同的项目选择合适的工具,而不是执念于工具本身。总结而言,目前前端工具化已经进入到了非常繁荣的时代,随之而来很多前端开发者也甚为苦恼,疲于学习。工具的变革会非常迅速,很多优秀的工具可能都只是历史长河中的一朵浪花,而蕴藏其中的工程化思维则会恒久长存。无论你现在使用的是React还是Vue还是Angular 2或者其他优秀的框架,都不应该妨碍我们去了解尝试其他。

组件化

组件化有一个很重要的目的是为了提高开发效率。再来看一下使用 React 开发效率高吗?

民间:想加班就用 React

为了说明 React 的开发效率,不妨点开两个链接看一下代码行数。下面两个链接都实现了一个聊天应用,完全一样的功能:

· React 版本:187 行

· Riot 版本:53 行

纯组件

在解构设计稿之后,我们需要总结出其中的纯组件,此时所谓的StoryBook Driven Development就派上了用场,譬如笔者总结出Material UI Extension这个通用类库。

前端的工程化需求

当我们落地到前端时,在历年的实践中感受到以下几个突出的问题:

  • 前后端业务逻辑衔接:在前后端分离的情况下,前后端是各成体系与团队,那么前后端的沟通也就成了项目开发中的主要矛盾之一。前端在开发的时候往往是根据界面来划分模块,命名变量,而后端是习惯根据抽象的业务逻辑来划分模块,根据数据库定义来命名变量。最简单而是最常见的问题譬如二者可能对于同意义的变量命名不同,并且考虑到业务需求的经常变更,后台接口也会发生频繁变动。此时就需要前端能够建立专门的接口层对上屏蔽这种变化,保证界面层的稳定性。
  • 多业务系统的组件复用:当我们面临新的开发需求,或者具有多个业务系统时,我们希望能够尽量复用已有代码,不仅是为了提高开发效率,还是为了能够保证公司内部应用风格的一致性。
  • 多平台适配与代码复用:在移动化浪潮面前,我们的应用不仅需要考虑到PC端的支持,还需要考虑微信小程序、微信内H5、WAP、ReactNative、Weex、Cordova等等平台内的支持。这里我们希望能够尽量的复用代码来保证开发速度与重构速度,这里需要强调的是,移动端和PC端本身是不同的设计风格,不建议过多的考虑所谓的响应式开发来复用界面组件,更多的应该是着眼于逻辑代码的复用,虽然这样不可避免的会影响效率。鱼与熊掌,不可兼得,这一点需要因地制宜,也是不能一概而论。
  • 目前, Web 开发技术框架选型为两种的占 80% 。这种戏剧性的变化持续了近 6 年。
  • 自 2013 年 5 月推出以来,ReactJS 在过去三年中已成为了 Web 开发领域的中坚力量。

回归现实的前端开发计划

本文的最后一个部分着眼于笔者一年中实践规划出的前端开发计划,估计本文只是提纲挈领的说一下,未来会有专门的文章进行详细介绍。缘何称之为回归现实的前端开发计划?是因为笔者感觉遇见的最大的问题在于需求的不明确、接口的不稳定与开发人员素质的参差不齐。先不论技术层面,项目开发中我们在组织层面的希望能让每个参与的人无论水平高低都能最大限度的发挥其价值,每个人都会写组件,都会写实体类,但是他们不一定能写出合适的优质的代码。另一方面,好的架构都是衍化而来,不同的行业领域、应用场景、界面交互的需求都会引发架构的衍化。我们需要抱着开放的心态,不断地提取公共代码,保证合适的复用程度。同时也要避免过度抽象而带来的一系列问题。笔者提倡的团队合理搭配方式如下,这个更多的是面向于小型公司,人手不足,一个当两个用,恨不得所有人都是全栈:
图片 6

质量保障

前端开发完成并不意味着万事大吉,我们目前所谓的Bug往往有如下三类:

  • 开发人员的粗心大意造成的Bug:此类型Bug不可避免,但是可控性高,并且前端目前配置专门的辅助单元测试人员,此类型Bug最多在开发初期大规模出现,随着项目的完善会逐步减少。
  • 需求变动造成的Bug:此类型Bug不可避免,可控性一般,不过该类型Bug在正式环境下影响不大,最多影响程序员个人情绪。
  • 接口变动造成的Bug:此类型Bug不可避免,理论可控性较高。在上周修复的Bug中,此类型Bug所占比重最大,建议未来后端发布的时候也要根据版本划分Release或者MileStone,同时在正式上线后设置一定的灰度替代期,即至少保持一段时间的双版本兼容性。

服务端

组件化是我们基础设施之一, 服务端(.net, java)也想做更多通用组件.但往往项目或产品研发周期紧, 在一些组织没有足够时间研发通用组件.

本文由mgm娱乐网址发布于mgm娱乐网址,转载请注明出处:我们需要更加优秀灵活的开发框架来协助我们更

关键词: