关于前端架构的过去、现在与未来

早期的软件架构模式建立在有限的硬件功能上并尊重这一事实,然而,今天的情况已经变了。计算能力在不断提升,而软件架构印证了这种观点。本文从经典MVC说起,详尽解读了当代前端架构及下一阶段的展望。对于前端工程师,以及想从宏观层面理解现代Web应用程序架构的Web开发人员来说,均能从中获益。

软件架构的核心思想,就是推断软件系统各个组件之间数据流动的方式。

软件架构的质量取决于你设法推断这些数据流的难易程度!

本文要讲的内容,就是在今天的 Web 应用程序背后探索这些数据流和最终的体系结构。Web 应用已从简单的静态网站(双层结构)发展为复杂的多层次、SPA 和 SSR 驱动的 API 优先系统。CMS 系统已发展成无头(Headless)和内容优先的系统。

近年来,前端社区的面貌日新月异。早年流行的是 jQuery 引入的 DOM 注入算法,其很快被基于 MVC 的 Backbone.js 所取代。之后一夜之间,我们就身陷于双向和单向数据流架构的丛林之中。我们的成长足迹在某处中断了。曾几何时沉浸在 MVC 的世界是如何突然进入 React 开创的单向数据流时代的?它们之间有什么联系?随着本文的展开,我们将尝试解开这个难题。

虽然本文针对的是前端工程师,但想要从宏观层面理解现代 Web 应用程序架构的 Web 开发人员都能从本文中获益。软件体系背后有着大量活动——流程、需求收集、部署拓扑、技术栈等等,但那些已经超出了本文所涉及的范围。

必要的前置知识——什么是计算机?

计算机是一种从用户收集数据 / 信息,并立刻或稍后将处理过的数据 / 信息提供给用户的机器。计算机如何收集和展示这些数据呢?它使用软件应用来实现这一目的。

软件架构的关键是提供合理的手段来组成软件,同时保持一切井然有序。

这里的关键在于,软件应用正在处理的数据被称为模型或应用程序状态。一些勇士可能将其称为应用程序的域模型或业务逻辑。应用程序可以是桌面端也可以是 Web 端。

本文的宗旨是探索向(Web 前端的)用户表示这种应用程序状态的合理方式,同时让一切井然有序。我们将探索数据如何从模型流向视图层,仅此而已。

经典 MVC——起源

将数据与表示分离是(Web 端和桌面端)图形用户界面的核心思想。对于 MVC——模型 - 视图 - 控制器来说,将表示(视图)与关注域(模型)分离是其主导的设计理念。毫无疑问,MVC 是一项开创性的成果,其影响力绵远流长。

如果要为软件开发写出第一原则,那么它就会是 SoC——关注点分离。而且 MVC 模式可能是它第一个真正的落地实践。

MVC 是为 Smalltalk-80 语言推出的。在 MVC 中,视图(View)对象显示模型(Model)对象持有的数据。在我们全面研究 MVC 中的数据流之前,我们必须了解当时(约 20 世纪 70 年代)的软件应用环境:

  • 这个 MVC 仅适用于桌面应用。那时离 Web 诞生还有几十年的时间。

  • 没有 Web,复杂的 GUI 驱动的操作系统也不存在。

  • 这意味着应用软件非常接近底层硬件。

以上这些限制对 MVC 影响很大。于是需要由控制器(Controller)对象负责响应键盘或鼠标等用户输入并转换为模型上的操作。此外,操作系统缺少 GUI 小部件意味着视图与屏幕内容无法对应。

相反,视图和控制器以配对的形式结合在一起。其中视图部分向用户显示输出内容,控制器部分接收来自用户的输入。应该注意的是,屏幕上的每个控件都有一个视图——控制器配对,这也是小部件(widget)理念的雏形。

今天,在 React、Vue 或 Angular 中,这种视图——控制器配对与组件的思想是一样的,尽管状态处理层面的具体机制有所不同。

关于 MVC 就介绍到这里,下面的图片展示了 MVC 中的数据流示例。在这个例子中,我们有一个带递增和递减按钮的简单计数器。计数器状态维持着模型。此外,我们把两个按钮简化成了一个来简化叙述。

经典 MVC

在协作方面:

  1. 视图和控制器包含对模型的直接引用,但反过来不行。这意味着模型不依赖 UI,可以在不担心 UI 问题的前提下做更改。

  2. 模型实现了观察者(Observer)模式,被一个或多个视图对象注册(subscribe)。当模型更改时会触发事件,事件响应后视图也会更新。

MVC 中有两条数据流。在视图流中不涉及模型,只涉及 UI 的更改。显示按钮单击效果或对鼠标滚动事件作出响应就是视图流的例子。

MVC中的数据周期

 
今天我们不再使用这个 MVC 了,它有时被称为经典 MVC 或老爹的 MVC。

 

开始使用应用程序模型

人们很快就意识到应用程序状态无法与 GUI 完全隔离。我们总是要维护某种表示逻辑或视图状态。

复杂的图形界面需要额外的状态,这些状态只用来辅助 UI 小部件,实现更好的用户体验。

但这可能会导致一些问题。来看看之前的计数器示例。当计数器达到 10 时,我们必须将标签的颜色从黑色更改为红色以表示警告。这种颜色变化行为实际上不是业务逻辑或关注点。这是纯粹的美学部分(用户体验),需要加进来。真正的问题是——放在哪里?是模型还是视图?

由于这种表示逻辑或视图状态基本上是从域模型派生的状态,因此必须在模型对象中维护它。但是域模型又要维护视觉部分(比如说红色),这种定义就很尴尬。如果我们将它放在视图对象中,那么它会引入另一组问题。我们的标签小部件不再是通用的了,无法在其他地方复用。此外,在视图对象中放一个带有硬编码数字 10 的条件,意味着我们正在泄漏某些业务逻辑。

为了解决这个问题,我们在原始的 MVC 中添加了另一个实体——应用程序模型(Application Model,AM)。有了 AM 以后,视图——控制器配对不再直接访问模型了。相反,它们向 AM 事件注册并使用它来访问所需的数据。

应用程序模型MVC 

数据流和经典 MVC 是一样的。当然,每种模式都有其优点和缺点,AM-MVC 也不例外。最突出的问题是AM没有对视图对象的直接引用,因此即使 AM 被设计为维持视图状态,也无法直接操作后者。

总的来说,引入应用程序模型会使视图特定的状态远离域层,并降低了视图对象的复杂性来简化视图对象。这和表示模型(Presentation Model)很像,这是 Martin Fowler 在其开创性研究中创造的概念:

表示模型的本质是一个完全自包含的类,它表示 UI 窗口的所有数据和行为,但没有任何用于在屏幕上渲染该 UI 的控件。视图只是将表示模型的状态显示在屏幕上。

现代桌面架构的时代

时光飞逝,世界也在不断变化,新一代操作系统开始展现威力。应用程序远离了底层硬件,它们之间加入了完整的内核、OS 驱动程序和实用程序。像 Windows 这样基于 GUI 的操作系统提供了开箱即用的 UI 小部件。

不再需要控制器来监听输入设备了。视图对象的理念改变了。

控制器的大多数功能都由操作系统接手。视图的理念发生了变化:之前它只是一个小部件,现在它是一个众多小部件的组合;一个视图可以包含另一个视图。视图在某种意义上变成了双向的,它响应用户操作并显示模型数据。

前端世界中视图的理念与这个概念非常相似。在 Web 环境中,视图是一个完整的页面。

经典 MVC 变得过时且难用。为了适应这些不断变化的环境,Dolphin 团队在 1995 年正在寻找一种创建用户界面的新模型。Dolphin 团队如何找出新设计的历史可参阅以下记录,本文不再赘述。http://aspiringcraftsman.com/2007/08/25/interactive-application-architecture/

总而言之,该团队最终将 MVC 模型旋转了 60 度,他们称其为 Twisting the triad。于是我们有了 MVP。

在协作方面:

  1. 表示器(Presenter) 监督表示逻辑。表示器可以直接更改视图。视图将用户事件委派给表示器。

  2. 根据实现,视图注册到模型上,并依赖表示器处理复杂逻辑;或者在其他情况下,视图只依赖表示器处理一切。

正如 Martin Fowler 在关于 GUI 架构的论文中总结的那样,他将 MVP 实现分为监督控制器 MVP 和被动视图 MVP。从图中可以看出它们的差异和各自的数据流。

MVP——模型视图表示器 

MVVM——模型 - 视图 - 视图模型

MVP 很棒,有许多可能的变种和复杂的细节。但从前端应用程序的角度来看,MVVM 确实更胜一筹。在一些实现中,后者也被称为模型 - 视图 - 绑定器。MVVM 很像被动视图 MVP,但增加了数据绑定的功能。它是一种编程技术,将来自提供者和消费者的数据源绑定在一起并同步。它摆脱了我们过去需要用来保持视图和模型同步的许多样板代码。这样我们就能在高得多的抽象级别上工作了。在协作方面:

  1. 视图模型(ViewModel) 是一个对象,它公开视图所使用的可绑定属性和方法。

  2. MVVM 有额外的绑定器(Binder) 实体,负责使视图与视图模型保持同步。每次视图模型上的属性更改时,视图都会自动更新以反映 UI 上的更改。

MVVM——Model View ViewModel

MVVM 中的数据绑定已经成为许多前端库的基础,包括 Knockout、Angular、Vue.js 和 React 等。

我们将在 Web 应用程序部分再讨论数据绑定。

进入 Web 应用程序领域

就像原始的 MVC 模式一样,出现了一种用于 Web 应用程序的模式。它被称为 Web MVC。实际上,Web 应用程序的构建和部署方式让 MVC 在 Web 端比在桌面端更加顺其自然。

社区的主要困惑是不知道桌面 MVC 和 Web MVC 是两种不同的模式。要是 Web MVC 当初不叫这个名字,大家就会清楚多了。

Web 应用程序是分布式应用程序的子类别。虽然 MVC 对 Web 应用程序感觉更自然一些,但一般来说构建分布式应用程序是很困难的。代码的某些部分在服务器上运行,同时还要保留在客户端(例如浏览器)上。

大规模 Web 应用程序架构的重点在于确定代码的哪个部分应该在哪里执行。我们有服务端驱动的应用程序或富客户端驱动的应用程序。在两者之间,我们可以无限自由组合。

在 MVC 的语境中讨论 Web 应用程序时有三个不同的数据周期,因此有三个 MVC 实现:服务端 MVC、浏览器内部的 MVC 和前端 MVC。浏览器负责三种类型交互的中介:

  1. 在客户端(JS+HTML)代码和服务端代码之间。

  2. 在用户和服务端代码之间。

  3. 在用户和客户端代码之间。

浏览器有自己的模型、视图和控制器。作为开发人员,我们不必担心浏览器 MVC。

服务端 MVC,亦即 2 号模型

服务端 MVC 的第一个众所周知的实现是 Sun Microsystems 针对 Java Web 应用程序的 2 号模型(Model 2)

服务端 MVC——前端视角

这个 MVC 与传统的 MVC 非常相似,但由于数据跨越客户端和服务端边界时数据流周期时间呈指数级上升,因此前者多出来很多复杂性。

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值