重构,不断地重构。-- 《重构》
前言
这篇文档不是类似PSRII的代码规范,也不是对PSRII的补充。
这篇文档总结了一些好的编写代码的习惯,是集体智慧的结晶。
它告诉你一段代码放在哪里比较合适,比如sql应该放在MVC的哪一部分;它告诉你代码应如何分层, 层与层之间应如何调用;诸如此类的规则。
代码如何分层
web开发中通常讲究MVC,也就是Model,View和Controller。 我们的View是H5或移动客户端,已经与我们完全分离了。因此重点讲讲Controller与Model。
Model代表的是数据,存取数据的方法应该封装在Model里。 数据可以存在很多地方,比如数据库:Mysql、Redis、Memcache等,或者其他服务:风控、BIZ等。
在Controller中调用Model类的方法有哪些缺点?
- 一个业务可能涉及多张表,controller会很臃肿
- 代码可复用性差
- 可维护性差:一旦数据结构修改,需要改动的地方太多
所以我们引入了service层。
service层是对一类业务的封装,比如用户模块,就可以封装成一个独立的service。service层的逻辑都应该是“可复用”的。 service可以简单的理解为Model类的聚合,并对外提供服务API,需要做到不将本模块的数据结构暴露给外部。 数据结构应该是"私有的"。
由于业务变化太快,service里面封装了很多不可复用的逻辑,救星bll出现了。bll层是纯面向业务的,这里的逻辑可以是“不可复用”的。 bll层调用service层的方法,完成自己的业务使命。
各层的使命
各层从高到低排序:controller -> bll -> service -> model
controller
- 参数校验
- 请求方法检查
- 权限检查
- 返回业务数据
bll
怒怼业务逻辑
service
封装可复用的方法
model
存取数据,例如update一条oauth_user记录,更新redis缓存,将用户信息提交给风控,将进件导入biz等。 model分类建议按业务模块,例如与进件相关的model可以放在common\models\apply,与biz相关的model可以放在common\models\biz。
公共代码
公共代码是与业务无关的代码,例如参数校验、http请求、日期转换、字符串操作、数组操作,可以放在common\lib、common\helpers目录。
编码准则
准则1 SQL应写在Model层
原生的SQL、对SQL的底层封装(find,findOne,findByCondition等)应写在Model层,以提高可维护性与可复用性,避免数据结构的改变造成维护困难。
准则2 参数校验应尽量早进行
应该将参数校验放在controller action的最顶部。不应挑战Model类的rules方法,那是最后的防线。简单的参数校验可直接调用common\helpers\Validate中的方法。复杂的参数校验可继承api\requests\BaseRequest,封装自己的校验方法。
准则3 模块化
我们的业务越来越复杂了,据我所知的模块就有很多:进件,优惠券,用户,现金红包等等。
应将这些模块封装起来,对外提供API。每个API的职责应该明确。一段业务代码应该写在哪里?首先去找对应的模块吧!
准则4 格式化返回数据只能在controller层
在非controller层格式化返回数据是禁止的。
bll、service、model应返回最原始的数据。
准则5 在controller的注释中加入wiki连接
在注释部分加一项@link,将wiki连接粘贴上去即可。
准则6 分层调用的规定
层间调用的基本准则:只能高层调用低层,或者同层间调用。 高级准则如下:
- controller可以调用:bll,service
- bll可以调用:service
- service调用:model,service(不推荐)
准则7 将复杂的缓存操作封装成model类
什么是复杂的缓存操作?例如用redis做一个队列,需要检查元素是否在队列中,入列,出列等。这就足够复杂了。
封装成model类,可以提高可复用性、可维护性,不用在各处拼接key,各处调用原生的redis方法了。
model类可以提供的,是一看便知其目的的方法名。
准则8 废弃代码的处理
可以立即移除的,优先移除,不能马上移除的打deprecated标签,签上名字和日期(可以确定移除的日期)
准则9 目录名称
为了风格统一,目录名称建议小写,例如common\models\activity为与activity相关的model目录。