George

Facebook:MVC模式不适用,使用Flux模式代替 [更新版]

George · 2017-02-10翻译 · 361阅读 原文链接

这篇文章已经根据社区以及Jing Chen(Facebook)的反馈进行了更新。(参阅下面的更新部分)

Facebook发现MVC模式不能满足他们持续增长的需求,并决定采用一种不同的模式进行替代:Flux

在最近的F8会议(Hacker Way: Rethinking Web App Development at Facebook)期间,Facebook的技术总监Tom Occhino说,对于足够大型的代码库和大型组织,“MVC会很快变得十分复杂”,得出MVC并不适用的结论。每当尝试添加新的功能使得代码变得“脆弱并不可控”时系统的复杂程度成指数增长。这对于一个接手新代码库的开发者来说是个棘手的问题,因为他们害怕破坏所以不敢改代码。这是MVC模式被Facebook抛弃的原因。

这个问题的解决需要“将代码通过一种更可控的方式进行组织”。Flux和React做到了这一点。Flux是一种促进应用内数据单向流动的系统架构。据Occhino介绍,React是一种用来构建“可控”和“声明式”的web用户接口的JavaScript框架,使得Facebook可以更快的开发web应用。

Facebook的软件工程师Jing Chen补充道,MVC适用于小型应用,一旦许多模块以及对应的视图被添加到系统中时,系统的复杂性将爆炸性增长,如下图所示:

image

这样的应用将很难理解和调试,特别是由于模块和视图之间可能的双向数据流动。Jing Chen建议下图的Flux设计模式:

image

Store包括应用所有的数据,Dispatcher代替了之前的Controller,决定当Action被触发的时候如何更新Store。当Store改变后View同样会被更新,选择生成一个被Dispatcher处理的Action。这确保了系统组件之间的单向数据流动。一个拥有多个Store或者View的系统,当数据只沿一条路径流动,并且不同的Store和View不会直接相互影响的时候,可以看做只拥有一个Store和一个View。

Facebook在GitHub上的文档更加详细的解释了Flux, Dispatcher 和 Stores:

dispatcher是Flux应用中用于管理所有数据流动的中央枢纽,本质上是回调到store的注册。每一个store自行注册并提供一个回调。当dispatcher响应一个action的时候,应用中所有的store接收注册表中action通过回调产生的有效数据。

伴随着应用开发,dispatcher变得更加重要,因为它可以通过在特定的序列中调用注册的回调来管理store之间的依赖。store可以通过声明的方式其他store完成更新,之后相应的进行自身的更新。

store包含应用的状态和逻辑。规则类似于传统MVC模式中的model,但管理很多对象的状态,store并不是对象的实例。store同样类似于Backbone框架中的collection。不同于简单管理ORM风格对象中的collection,store管理着应用特定领域内的应用状态。

Jing Chen说,数据层在任何其他action被触发前完成视图的更新是很重要的。当Dispatcher存在之前没有处理完成的action时,可以拒绝处理其它的action。这种设计方式对于有类似于更新其它视图层这种副作用的action十分有帮助,使得代码更加简洁,使得新的开发者能够更加容易得理解和调试代码。Flux帮助Facebook消除了一个通知bug,就是当用户没有新消息时提示用户有新消息。

Flux TodoMVC的教程和源码可以在GitHub上获得。

虽然Facebook可以使用任何他们认为合适的设计模式,但还有一个问题:MVC是否适用?毕竟MVC适用于很多网站。

更新。发表这篇文章之后,许多开发者在Reddit评论关于Facebook使用MVC的问题。这里有一些评论,一些人认为Facebook一开始滥用了MVC,一些人认为他们在做正确的事情:

giveupitscrazy:

这没有任何意义。

首先,他们MVC图的缺陷十分明显。他们使用单一控制器处理多个模型,

当然他们所描述的那种设置并不有效,但同样那也不是真正的MVC。

如果你将他们的flux图与这样实际的MVC图相比较,你会得到更加清晰的认识,就是对web应用而言,MVC是适用的。

balefrost:

并且还有一个问题,就是他们的Flux图与你的MVC图非常相似。

他们重新定义了MVC,并且决定重新给它命名。天啊!

hackinthebochs:

看起来就像是这种架构将MVC转变成了基于事件的。“stores”通过dispatcher进行注册(并大概规定调用顺序的依赖),同时dispatcher处理action并确保生成正确的调用链。这将确保适当调用顺序的压力由controller转移到了dispatcher和store。这可以减少对于修改行为理解的重要性。

runvnc:

我只是随便看了看,虽然我觉得我还不太清楚,但我想我理解并同意这个观点。

根据评论看像是Jing Chen的Reddit用户jingc09,补充说明道:

jingc09:这是一个棘手的幻灯片[拥有多个model和view,以及双向的数据流],一定程度上是由于目前没有对于MVC确切的共识,很多人对于MVC到底是什么有不同的想法。我们真正讨论反对的是双向数据流动,因为这样改变会回环并产生级联影响。

她也尝试去阐明Flux中的Dispatcher并不是MVC中Controller的事实:

我想说明dispatcher并不承担与controller相同的角色。dispatcher中没有业务逻辑,并且我们在多个应用中使用相同的dispatcher代码。dispatcher只是一个让事件到达指定用户的事件中心(通常是store)。但它在Flux中是重要的,因为执行的是单向的数据流动。

维基百科这样解释MVC中的Controller:

controller会向model发送命令来修改model的状态(例如编辑文档)。也可以向相关的view发送指令来改变model中view的展示(例如滚动文件)。

Jing Chen说:

dispatcher不能做这些事情,指令需要从其他地方(视图,服务器响应,实时更新)产生并通过dispatcher传递。https://github.com/facebook/react/blob/master/examples/todomvc-flux/js/dispatcher/Dispatcher.js 可以帮助解释这一点。

根据Reddit的评论,关于MVC是什么和怎样实现有一些争论。

对于Facebook使用MVC我们有两种观点:

1)第一张幻灯片看上去真的是有太多的模块和视图,让人想实际是否真的存在这种情况。Fackbook使用Flux解决问题的是一个只有三个视图的聊天应用。

2)为什么View生成的数据流在他们的MVC示例中会产生双向的流动?并且为什么在Flux图中View会生成Action?View不应该产生任何东西。View只是一个“视图”,而不是其它东西。Facebbook是否滥用了MVC?

译者George尚未开通打赏功能

相关文章