Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

使用 React & Redux 开发跨客户端应用 #3

Open
ingf opened this issue Feb 24, 2016 · 2 comments
Open

使用 React & Redux 开发跨客户端应用 #3

ingf opened this issue Feb 24, 2016 · 2 comments

Comments

@ingf
Copy link
Owner

ingf commented Feb 24, 2016

此文深受 @xufei一系列博客 影响,亦有很多引用,非常感谢。

客户端(Client)或称为用户端,是指与服务器相对应,为客户提供本地服务的程序。一般安装在普通的客户机上,需要与服务端互相配合运行。因特网发展以后,较常用的用户端包括了如万维网使用的网页浏览器,收寄电子邮件时的电子邮件客户端,以及即时通讯的客户端软件等。

在这里,我们说的客户端应用包含桌面浏览器和移动设备浏览器(或者其他 Web 容器)中运行的 Web App,iOS 和 Android 上的原生应用,Mac 和 tvOS 上的原生应用等等。

对于一家公司的客户端产品而言,或多或少会运行在上述的几个平台之上。而这些客户端产品中,基础的业务逻辑是相同的,稳定的。那么你肯定猜出来了,我们希望能够在多个客户端产品中,共用这部分基础业务逻辑,然后上层根据不同的平台和产品设计实
现相应的 UI 展示。

实现这个目标是比较难的,先看看 Web 前端普遍存在的情况:一个产品,不管他在初期还是成熟阶段,产品经理总会花点时间出来,整个改版,这个改动主要是在 UI 层面,当然也会涉及一部分的产品逻辑调整。这时候前端工程师就不淡定了,我是改改 UI 呢还是重构呢还是重构呢😂

此时,工程师大多会思考,如果把业务逻辑和 UI 层分开多好呀。

UI 层(View) ---- 业务逻辑层(Controller)

如果把 Model 层和业务逻辑放在一起,那么就是酱紫

UI 层(View) ---- 业务逻辑层(Controller) ---- 数据层(Model)

对,这就是我们经常说的 MVC,而他最终很有可能变成了这个样子。

mvc

这张图片是 Facebook 软件工程师 Jing Chen 在 F8上面提出来的,实际情况不是所有项目都有这么严重,但是比这严重的项目肯定有很多。这并没有从根本上将 UI 层和业务逻辑分开,还是耦合在一起,怎么样才能真正将 UI 层和业务逻辑层分开来呢,我们再来看看这张图。

redux

上图的 React Component 就是 UI 层,Action,Store,Reducer 就相当于业务逻辑层,其中 store 就是一个大 Model。
UI 层和逻辑层的关系:UI 层的数据来源于逻辑层的 Store,必要的时候,UI 层通过调用 Action 修改 Store。采用这种方式,我们能比较从容的面对产品改版,因为修改主要集中在 UI 层,以前的逻辑层稍作修改就好。目前 UI 层是 React,可以实现在浏览器上面的需求,如果我们再将 UI 层稍微修改,换成 React-Native
React-tvOS
React-Desktop,甚至还可以换成 Angular 和 Vue,那么就实现了我们初期的目标。在底层,有稳健的业务逻辑实现,在 UI 层,可以使用合适的熟悉的框架,甚至可以更换 UI 层框架。

screenshot 2016-04-17 20 17 19-min

当然,实现 UI 层和逻辑层的分离可以很多方案,我们这里是采用 Redux 作为逻辑层的实现。先扔出结论,接下来我们详细讨论一下这种分层、组件化的开发方式,先看一下 Web 前端组件化的一些理念。

前端组件的复用

在大型软件中,组件化是一种共识,它一方面提高了开发效率,另一方面降低了维护成本。但是在 Web 前端,还没有很通用的组件模式,因为缺少一个大家都能够认同的实现方式。所谓组件化,核心意义莫过于提取真正有复用价值的东西。那怎样的东西有复用价值呢

  • UI 控件
  • 基础逻辑功能
  • 公共样式
  • 稳定的业务逻辑

以上几点在 @xufei2015前端组件化框架之路中已经说的很清楚了,不再多言。除此以外,还有大量的业务界面,这部分基本不具备复用性,但是大部分还是会把他们组件化,也就是把大块的业务界面,拆分成若干小块组件,然后进行组装。这并不是为了复用,纯粹是为了使得整个工程易于管理,易于维护,组件化的最重要作用就是提升开发和维护的效率。

组件化的主要目标

很多人会把复用作为组件化的第一需求,但实际上,在 UI 层,复用的价值远远比不上分治,将代码从 UI 层和逻辑层分开来,就是一种分治。

分治带来的是可管理性,相比一大团 HTML 和 JavaScript 的混杂,组件化之后,整个应用成为了一个很清晰的树,一眼就能看清包含关系,也能够很容易理清数据的传递方向。而且,整个应用可以从叶子节点,逐步向上测试,哪一级出了问题,可以很容易发现。

但是复用就很麻烦了,因为组件的内部实现与外部接口都很难取舍。很可能我们在设计之初,都是把组件设想成一个单一的东西,然后在实际项目中,发现最后都面目全非了。

所以,复用的工程成本很高,在使用的时候需要权衡,除了最常用了基础控件,其他的不要刻意追求。

这个时候,思路就比较清晰了,基于组件化思想,应用分成 UI 层和逻辑层,逻辑相对比较稳定,采用 Redux 方式实现,UI 层也采用组件化方式,不过这种组件化并不是为了复用,而是从工程角度来说,为了便于理解、管理和维护。我做了一个 demo- captain,目前仅实现 Web 和 iOS 平台。

在深入之前,先看看 captain 的目录结构:

.
├── README.md
├── android            // Android 平台 UI 实现
├── app                // 业务逻辑
├── index.android.js   // Android 入口文件
├── index.html         // 
├── index.ios.js       // iOS 入口文件
├── index.web.js       // Web 入口文件
├── ios                // iOS 平台 UI 实现
├── server.js          // 
├── test               // test
├── web                // Web 浏览器 UI 实现
└── webpack.config.js

业务逻辑

业务逻辑指的是所处领域中的业务数据、规则、流程的集合。即使抛开所有展示层,这一层也是应当要能够运作起来的。

我们采用 Redux 来开发业务逻辑,当然这个不是绝对的。如果对于 Redux 还不太了解,请移步 这里。Redux 总结起来就一句话:

动作(Action) 通过 状态转换函数(Reducer),set 到一个统一的地方(Store),然后 UI 从 Store 中获取数据。

逻辑层应该是与 UI 层无关的,要能偶独立运作起来,能够独立测试。

在 captain 的 test 里面,实现了一套简单的逻辑测试,启动后可以在这个网页的控制台里面看到效果,下面有截图。

store.dispatch(actions.addTodo('Learn about actions'))    // 添加一个 todo
store.dispatch(actions.addTodo('Learn about reducers'))   // 添加一个 todo
store.dispatch(actions.addTodo('Learn about store'))      // 添加一个 todo
store.dispatch(actions.completeTodo(0))                   // 完成第零个 todo
store.dispatch(actions.completeTodo(1))                   // 完成第一个 todo
store.dispatch(actions.clearCompleted())                  // 清除已经完成的 todo

actions

简直没有比这再清晰的了,你甚至都不用阅读我的源码,只需要看一下这个 Action 列表(每个 Action 日志中会打印出初始状态、执行动作和执行后的状态),就知道业务逻辑是怎样执行的,再也不会出现 MVC 中一个 Model 更新了以后不知道哪些 View 会随之更新的情况了。这正是 Redux 的一个很大的优点 ---- 可预测性。正因为可预测性,你清楚的知道什么发生了改变(Action),改变之后的数据是什么样的(Store/State),以及发生了哪些改变(Action 记录)。

实际在开发 Redux 应用的过程中是比较折腾的,尤其是在前期,生态圈不够完善,缺乏大型应用的成熟案例等等。但是当我们慢慢摸着石头过到河中间,所以痛点都找到化解的方式之后,好像突然架起了一座桥,开发效率 biu 的一下就上去了。其实我认为 Redux 最能提升的不仅仅是开发效率,更是维护效率。若干年以后(如果产品还活着),你看到上图中打印出来的信息,还是能清楚的知道这个业务过程是怎样的。关于维护效率,我想多说一句,几乎每个大公司都有一个“运行时间长,维护的工程师换了一批又一批”的项目。Amazon 曾经有个工程师描述维护这种项目的感觉:“climb the shit mountain”,所以我猜想你能感受得到参与一个好维护的项目是怎样一种体验。

UI 层

UI 层与普通的 React 项目和 React-Native 项目一致,可参考:#2

@Duan112358
Copy link

废话少说,直接撸代码就是了

@ingf
Copy link
Owner Author

ingf commented Mar 4, 2016

@ingf ingf changed the title 使用 Redux 开发跨客户端应用 使用 React & Redux 开发跨客户端应用 Sep 23, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants