前后端分离，你应该知道的八件事
===

> 前后端不分离，是怎样的？大概也只有我们这些『老古董』们，才对此有更多感受。不对，那些写 React 的人，可能会对此也有一些体会。

今天，如果有一个前端工程师说，不知道前后端分离是什么。那么，要么是刚毕业不久的，要么是从老版的公司里出来的员工，要么是刚从时光机里出来的。

前后端分离
---

我刚开始接触前后端分离的时候，正值它开始慢慢扩散的时候，也还没有意识到它带来的好处。觉得它甚是麻烦，当我改一个接口的时候，我需要同时修改两部分的代码，以及对应的测试。反而，还不如直接修改原有的模板来得简单。

可是当我去使用这个，由前后端分离做成的单页面应用时，我开始觉得这些是值得。当页面加载完后，每打开一个新的链接时，不再需要等网络返回给我结果；我也能快速的回到上一个页面，像一个 APP 一样的体现这样的应用。整个过程里，我们只是不断地从后台去获取数据，不需要重复地请求页面——因为这些页面的模板已经存在本地了，我们所缺少的只是实时的数据。

后来，当我从架构去考虑这件事时，我才发现这种花费是值得的。

### 什么是前后端分离？

前后端分离和微服务一样，渐渐地影响了新的大型系统的架构。微服务和前后端分离要解决是类似的问题，**解耦**——可以解耦复杂的业务逻辑，解耦架构。可要是说相像吧，消息队伍和前后端便相似一些，通过传递数据的形式来解耦组件。

前后端分离意味着，**前后端之间使用 JSON 来交流，两个开发团队之间使用 API 作为契约进行交互**。从此，后台选用的技术栈不影响前台。当后台开发人员选择 Java 的时候，我可以不用 JSP 来编写前端页面，继续使用我的 React 又或者 Angular。而我使用 React 时，也不影响后台使用某一个框架。

概念我们已经清楚了，但是还有一个问题：我们真的需要前后端分离吗？

### 真的需要前后端分离吗？

过去，听说 TDD (Test-driven development，测试驱动开发) 可以改善代码的质量，我们便实施了 TDD；接着，听说 BDD (Behavior-driven development，行为驱动开发)  可以交付符合业务需求的软件，我们便实施了 BDD；后来，听说 DDD (Domain-driven design，领域驱动设计) 可以分离业务代码与基础代码，我们便实施了 DDD。今天，听说了前后端分离很流行，于是我们就实施了前后端分离——这就是传说中的 HDD（Hype-driven Development，热闹驱动开发）。

前后端分离在过去的两三年里，确实特别的热闹。但是我们怎么才能知道，是不是需要这样的架构呢？

- **页面交互是否复杂 ？** 是简单的提供页面给用户浏览？或者想要支持复杂的用户操作？
- **是否需要搜索引擎优化？**如果需要的话，那么从一开始我们就需要考虑后端渲染。
- **能提升开发效率吗？**如果不能有效的提升开发效率，为什么要作死呢？
- **是否会提供 API 给 APP？**如果我们已经有一个 API 提供给 APP，那么要做这件事就很容易了。如果未来会有的话，那么我们更应该尝试去分离。
- **前端的修改是不是非常频繁？**如果不需要经常修改的话，那么这种优化便没有优势。

当然了，如果老板说，我们需要前后端分离，那就做呗！很多时候，一些技术决策都会由于战略原因，而发生一些有意思的变化。

### 前后端分离将遇到的那些挑战

而，当我们决定需要前后端分离时，我们仍然还需要面对一系列的问题：

- **是否足够的安全？**如果我们设计出来的架构不够安全，那么这一系列的操作都是白搭。我们怎么去存储用户数据，使用 LocalStorage 的话，还要考虑加密。采用哪种认证方式来让用户登录，并保存相应的状态？
- **是否有足够的技术来支撑前后端分离？**有没有能力创建出符合 RESTful 风格的 API？
- **是否有能力维护 API 接口？**当前端或者后台需要修改接口时，是否能轻松地修改。
- **前后端协作的成本高不高？**前端和后台两个团队是不是很容易合作？是不是可以轻松地进行联调？
- **前后端职责是否能明确？**即：**后台提供数据，前端负责显示**。
- **是否建立了前端的错误追踪机制？**能否帮助我们快速地定位出问题。

当我们在不同的项目组上尝试时，就会发现主要的挑战是沟通上的挑战，而非技术上的局限。

前后端分离的核心：后台提供数据，前端负责显示
---

我曾经有过使用 PHP 和 Java 开发后台代码的经历，仍然也主要是集中在前端领域。在这样的传统架构里，编写前端页面可不是一件容易的事。后台只会传给前端一个 ModelAndView，然后前端就要扑哧扑哧地去丰富业务逻辑。

传统的 MVC 架构里，因为某些原因有相当多的业务逻辑，会被放置到 View 层，也就是模板层里。换句话来说，就是这些逻辑都会被放到前端。我们看到的可能就不是各种``if``、``else``还有简单的``equal``判断，还会包含一些复杂的业务逻辑，比如说对某些产品进行特殊的处理。

如果这个时候，我们还需要做各种页面交互，如填写表单、Popup、动态数据等等，就不再是简单的和模板引擎打交道了。我们需要编写大量的 JavaScript 代码，因为业务的不断增加，仅使用 jQuery 无法管理如此复杂的代码。

### 输出逻辑：数据显示

而仅仅只是因为逻辑复杂的前端代码，无法影响大部分团队进行前后端分离——因为它没有业务价值。实际上是先有了单页面应用，才会出现前后端分离。单页面应用可以让用户不需要下载 APP，就可以拥有相似的体现。并且与早期的移动网页相比，拥有更好的体验。

为了达到这样的目的，后台似乎返回对应的 Model 即可，稍微修改一下 Controller 的逻辑，然后返回这些数据。

```javascript
[{
    "content": "",
    "date": "2017-03-04",
    "description": "前后端分离，你应该知道的八件事\r\n\r\n前后端不分离，是怎样的？大概也只有我们这些『老古董』们，才对此有更多感受。不对，那些写 React 的人，可能会对此也有一些体会。",
    "id": 1,
    "slug": "iamafe-frontend-backend",
    "title": "我的职业是前端工程师:  前后端分离，你应该知道的八件事",
    "user": ""
}]
```

前端在一个 API 请求之后，可以直接渲染这些数据成 HTML。在这个时候，我们仍然可以看到，上面数据中的 date 字段值 2017-03-04 的格式，和我们日常用的 2017 年 3 月 4 号的不一样。所以，我们需要在前端引入 ``moment`` 这样的库，然后解析这个值。如果仅仅是这样的处理，那么应该由后台帮我们转换这个值。

与此同时，后台应该按时间来对博客进行排序。前端只需要遍历这个数组，随后取出相应的值显示即可，不需要做任何的逻辑处理。

遗憾的是，在真正的项目中开发的时候，并不能达到这么完美的状态。特别是，为了提高用户体验时，我们可能就会将数据存储在本地，随后直接操作这些数据，对其进行排序，筛选等等的操作。除此，还有诸如表格、图表等等的高级样式，也需要处理这些数据。

而当用户需要提交数据的时候，这些逻辑就会落到前端上。

### 不可避免的前端逻辑：表单

如果一个前端应用只显示数据的话，那么这个应用就没有充足的理由，做成一个单页面应用——单页面应用是为了更好的交互而存在的。当我们注册、登录、购买东西时，就需要开始与表单进行处理。

合理的表单验证模式应该是：**双向验证**。

前端在用户输入的过程中就需要实时地检查，是否带有特殊符号、值是否是在允许的范围内、是不是符合相应的规范等等。而不是等用户填写完内容并提交后，再由服务端来告诉用户说，“你的用户名不符合规范”。

服务在收到前端收到的数据后，不管前端有没有进行验证，都应该按后台的逻辑进行验证。

于是乎在这个时候，这些逻辑就被无可避免地放到前台里了。
