创建时间:

最后修改:


# 麦乐学园社区系统技术架构

由于一些原因,我们抛弃掉了 Discuz 这个论坛系统,然后花了一些时间开发出了我们自己的一套全新的社区系统。这个主题我将试着介绍一下这整个系统中的一些技术细节。



## 01. 前后端分离

整套系统我们采用前后端分离的形式、面向接口的形式去开发的。这样不管是前端还是后端,所做的事情就变得更加的纯粹了。后端只负责业务(提供数据),而前端只负责展现。前后端的交互使用的是 WebSocket 双向协议。以长连接的形式进行数据的订阅与分发。而我们在此协议上做了进一步的封装,使交互变得更加容易与简单。



## 02. 技术栈
前端用的 Vue 全家桶(Vue2 + Vuex + VueRouter + Vue-Cli)

JS 使用 ES6 语法编写,CSS 使用 SCSS 扩展语言编写。最后使用 Webpack 配合各种 loader 转换并打包。

后端使用的是 Golang 配合 MongoDB 这一面向文档的数据库提供 WebSocket 长连接服务。

另外还用到了七牛云用来存储用户上传的图片资源(后端鉴权,前端上传)。



## 03. 前端
前端代码使用组件化开发的方式进行开发的,每个功能就是一个组件,这样增强了代码的可重用率。更加方便后期维护。前端路由是使用的 HTML5 中的 History 接口实现的,所以它看起来更像是真正的 URL。

然后我重点说一下单向数据流吧,它是整个前端项目中的核心,因为所有与后端交互有关的操作都离不开它。

单向数据流的整个流程是:用户操作产生行为(action),行为导致数据发生改变,数据发生改变后驱动页面重新渲染(render)。

Vuex 是非常人性化的,它允许我们在其中注册一个或多个插件(plugin)。正是利用了插件的功能,使得整个过程异常的简单。

当 dispatch 一个 action 的时候,在插件中拦截到了这个 action,然后对这个 action 进行识别(检查是否是与后端交互的操作),然后发送由协议层打包好的数据到后端服务器。

当后端服务器处理完毕后,响应的信息依然由 plugin 进行首先处理。如若是一次失败的操作,则直接停止向外传送,并且触发全局的消息事件报告错误。如果成功了,就附带上响应的信息提交(commit)这次操作。



## 04. 后端
后端在整个项目中充当的是最重要的角色,因为所有的业务操作都依赖于它。那么一个稳定且合理的架构必然成为了我们的第一需求。

在后端的架构设计初期是十分痛苦的,主要原因是我对 Golang 这门语言并不熟悉,当然这是我的原因。

在刚开始的时候,我并没有直接编写逻辑代码,而是先构建出了一个比较底层的框架,然后我们的业务全部围绕这个框架展开。这个框架比较类似于传统的 MVC 模式。但是也有很多不同,比如我们没有 V,所以显而易见的就只有 M 与 C 了。

- M:模型层,在这里叫做 Db 层
- C:业务层,在这里叫做 Module 层

除了上面的 2 层之外还有一个十分重要的,那就是服务(Service)层。就如它的名字一样,服务层当然是用来给我们提供服务的(各方面的)。比如:我要往数据库中添加数据,那么就需要用到 `数据库服务` 。或者我要(在业务层)获取一些配置信息,那么就会用到用于 `依赖注入` 的服务注入 `配置服务` 到业务层。

当然还有个最基本的也是最不能忽视的,就是整个路由映射、中间件以及对业务层的调度,也是由服务层完成的。总结之:服务驱动业务,业务依赖服务。



## 05. 目前存在的技术问题
目前主要的问题应该是对产品的定位问题,我们的社区系统做成了 SPA(Single page application)的形式,这类应用对 SEO 是不友好的(当然也有一些解决方案,比如服务端渲染)。

现在就面临着选择的困难,到底是做的更加开放还是更加封闭?
- 开放:做成传统的 Web 站点,可以被搜索引擎索引到;
- 封闭:做成类似 App 的东西,所有数据都是在 App 内才能看到的;

或者我们是否可以寻求一个平衡点呢?