这个最佳实践是我目前人在做的一个站点,主要功能:
- oauth登录
- 发布文章(我称为"片段"),片段可以自定义一些和内容有关的指标,如“文中人物:12”。支持自定义排版、插图、建立相册。
- 多个片段可以组织在一起,形成"事件"。
- 任意事件、片段都可以互相标记因果关系。
- 可以follow事件或者他人。
- 事件和片段模糊搜索。
我对目前前端框架的观点已在另一篇文章中讲过,这里只介绍一下目前实践的情况。
- 使用requirejs做模块化,上线时用r.js打包。
- 使用avalon做数据与视图渲染框架。
- 用page.js来管理路由。
- 用harp来做静态资源服务器。harp支持less、coffeescript等自动编译,当前端有css或js请求而相应的文件不存在时,它就会自动查找同名的less或coffeescript等文件并编译输出。
后端选型经历了两周左右,目标无非两个:开发便捷,适用于生产环境。
我对开发便捷的要求是。
- 可简可繁的路由配置,且非常容易生成REST接口。可弃用框架自带的视图层。
- 框架有一个良好的数据库层,可以是ORM也可以是AR。这个数据库层同时要支持开发者手动优化查询。
- 框架依赖少,容易安装和部署,社区支持强大。
对适用于生产环境的要求是:
- 框架本身轻巧,速度快。
- 支持大并发,有成熟集群部署方案。
- 能切换各种类型的数据库,有memcached等缓存中间件的接口。
在这期间,我试用了Django、drupal、discuz、codeigniter、expressjs、sails,以下记录选择过程中对前后端的考虑,希望对有类似需求的朋友有帮助。我的定论留在文章最后。
Django
比较惭愧,出于个人对python不如php和nodejs熟,放弃了Django。Django自带功能非常强大的ORM,有REST中间件。也有成熟的部署方案。并且有非常好的学习指南(搜"Django book"),推荐各位一定要自己用用。
drupal
要完整地描述和概括drupal有一点难。它既不是某一种具体业务逻辑的框架(把它说成CMS太狭隘),也不是纯粹的只有功能层面(如ORM、视图渲染)的框架。只能这样说:
首先,它包含了强大的功能层,如数据库层、视图层。其次,它通过“hook”机制以及一整套完善的附属功能,让开发者能非常自由地打造自己的业务逻辑。或者说使得它可以几乎可以包容任何业务逻辑。类似于AOP,类似于装饰类。
这里为不懂的读者再介绍一下它的核心“hook”。实现一个hook有两步:一、在业务流程中的某些点声明可以被hook。二、声明一个操作,和它要hook到哪个流程中的点。比如:一个用户注册模块声明,在获取用户的注册数据后,写到数据库之前,这一点可以被hook。一个加密模块声明,要对注册数据中的密码进行加密,并声明这个操作hook到刚才提到的用户模块声明的点上。这样在写到数据库前,密码就被加密了。
hook机制早已有之,drupal的精髓在于将其发展并运用到帮助开发者实现业务逻辑上。因为几乎任何人类的业务逻辑都是流程化的,并且很可能变化。hook满足了在不直接改变原有逻辑的情况下进行扩展和修改的需求。也是这种机制激活了drupal的开发社区,让它的每一个模块都能很好地与其他模块协作。
一开始我其实是选用了drupal做后端的。第一,它的后端功能十分完善,从用户注册到内容管理应有尽有。实在没有还可以去它强大的社区找支援。第二,drupal在部署、性能优化方面已经非常成熟。但最后仍然弃用了,这里先说说用的过程。
首先装上Service模块自动实现drupal的REST api,这时候节点、用户什么的增删改查接口就已经都有了,只需要按照Services的说明去打开这些接口就行。如果需要跨域调用,还要装上CORS模块来允许跨域请求,相关知识请自行google CORS。如果定制更多的查询接口,可以装上Services Views模块,它能直接将views生成的列表变成数据输出,不过这个模块和views本身一样有个让人很不爽的点:对于多值的字段,不能按数组输出,只能输出成一行字符串,以",“或者其他指定符号分割。
至此,后端已基本可用。然而随着继续开发,有了更多的需求,比如说投票。drupal有很多投票模块,但几乎都是直接嵌入到页面中的,对api支持不好。于是想自己写一个。这样的功能多了以后发现,去找有没有类似模块,并调研是否符合我需求和踩坑的时间都已经超过了自己开发的时间。如此一来都已经脱离我”快速开发“的本意了。况且如果都要自己写,为什么不选个轻量级的框架呢?比如codeigniter。于是开始便继续写,边寻觅其他框架。drupal整体而言其实应该是非常适合团队开发的,因为它迫使大家都遵循同样的机制,这样就解决了团队开发容易质量不可控这样一个最大的风险。对个人开发者来说,总是先搭个架子,或者先看看别人的架子是怎么搭的,再开始写代码,实在有点累。
discuz
看完drupal再看discuz、phpwind什么的,完全不能接受,架构太乱,控制器、模型、视图耦合严重。没有对REST api好的支持。略过。
codeigniter
codeigniter确实是非常轻,一个自动映射到控制器的路由系统,一个以AR方式实现的数据库层,一个可用可弃的视图层。就这么简单。codeigniter同样也有良好的社区支持,然而更重要的是,正是因为它非常简单,让它可以几乎无痛的与任何第三方类库集成。不过自己的业务逻辑,就得一点一点自己搭建了。如果是这样的话,那还是用nodejs的框架更好。
expressjs
expressjs是我所知的目前最成熟的nodejs框架了(如有其它更好的,只能说我孤陋寡闻了)。选nodejs框架最大优点:第一,没有切换语言编程的痛苦。第二,nodejs在处理并发、大规模部署都已经有成功经验。第三,能够良好地支持各种数据库。如果不是发现了sails的话,我应该就选expressjs了。
sails
对我个人来说,对小框架其实是有戒心的。特别是对于要上线的程序,万一碰到问题问作者,作者撒手不管,也没有大规模部署的例子等等情况,上线后可能就会面临推倒重来的结局。所以不能只看开发体验,框架的出身也是很重要的。首先值得说明的是,sails是基于expressjs的。 稍微让人放心了点。其次,sails虽然自称实时框架,强调自己对于web socket的封装。但我目前只需要用到它的ORM和自动生成REST api。毕竟这两个基础的东西看看源码是可以自己掌握的。下面来介绍以下实践过程:
首先是路由系统。分为两个部分,一个是sails对每一个model自动生成的REST api。sails支持标准的REST请求,同时也能让开发者通过配置文件将接口修改为常用的REST变种接口。另一部分是用户自己定义的接口,和codeigniter一样,sails也是自动将接口映射到相应controller的方法上,非常简单。它同时还提供了称之为polices的机制来保护接口,即在调用指定接口之前先用定义好的police检测一遍,不通过则直接拒绝请求。这样能让controller更专注于具体业务逻辑。
然后讲讲数据层。sails的数据库适配器非常多,几乎所有的主流的数据库都能支持。它也是通过写配置文件,来实现对字段的定义。一个叫做'Event'的模型例子:
module.exports = {
attributes: {
uid: {
type : 'string',
defaultsTo : ''
},
title: {
type:'string',
required : true,
},
content : 'string',
vote : {
type : 'integer',
defaultsTo : 0
}
},
afterCreate:function( event,next ){
Heat.create({
entity_id : event.id,
type : 'event'
}).done(function(){
next()
})
}
};
在这段代码里可以看出,sails的定义实现了主流数据库中对字段的检测、设置默认值等功能。值得一提的是例子最后的'afterCreate'函数,这是sails提供的类似于drupal hook的东西,它自己称为"生命周期回调"。它可以让开发者在模型的增删改查前后自动执行相应的管理操作。在我们的例子里就是在一条属于Event模型的记录创建之后,再创建一条相关的Heat模型的数据。
要注意的是sails ORM中是没有自动支持模型建的关联的。以我个人的观点来说,正好也不需要,因为模型间的关联常常是造成数据库查询负载的罪魁祸首,我常常通过储存冗余数据等方法来尽量减少关联查询。所以不支持模型关联,正好让我每一个需要关联的地方都手写,保障性能。
数据库我用了mongodb,我的需求里面有些非结构化的数据可以无需任何转换地存到数据库了。sails同时还支持对不同的model使用不同的数据库,这样未来要对数据库调优的话空间就很大了。
最后看看下对CORS的支持,直接在整站的配置文件中打开crsf选项即可。对于跨站请求,先请求crsf token,之后的请求带上这个头就可以跨站了。
结论自然是选择了sails。目前sails整体项目官方维护得非常积极,功能完备。实在有问题了看看源码也能够明白。相对于我的需求来说已经非常好了。
最后整体总结一下:
1.整个开发中前后端完全分离。后端只提供数据接口,并且支持跨域请求,也便于之后进行其他端的开发。
2.前端用avalon、requirejs、page.js三件套开发体验非常好。用harp来支持less和coffeescript等,自动编译,无需任何中间操作。
3.后端用sails来处理业务逻辑和提供REST api。各种功能齐全,开发顺畅。
文中内容若有偏颇,望不吝赐教。预祝屏幕前的你新年快乐。