命名规范
我自己非常注重搭建项目结构的起步过程,应用命名规范、模块的划分、目录(包)的命名,我觉得非常重要,如果做的足够好,别人导入项目后可能只需要10分钟就可以大概了解系统结构。
具体规范包括包命名、类的命名、接口命名、方法命名、变量命名、常量命名。
统一IDE代码模板
约定了IDEA/Eclipse IDE代码的统一模板,代码风格一定要统一,避免不同开发人员使用不同模板带来的差异化以及代码merge成本。使用IDEA的同学可以安装Eclipse Code Formatter插件,和Eclipse统一代码模板。
Maven使用规范
所有二方库、三方库的版本统一定义到parent pom里,这样来所有业务应用工程统一继承parent pom里所指定的二方库、三方库的版本,统一框架与工具的版本(Spring、Apache commons工具类、日志组件、JSON处理、数据库连接池等),同时要求生产环境禁用SNAPSHOT版本。这样以来升级通用框架与工具的版本,只需要应用工程升级parent pom即可。
代码Commit规范
基于Angular Commit Message规范生成统一的ChangeLog,这样一来对于每次发布release tag非常清晰,Mac下都需要安装对应的插件,IDEA也有对应的插件,具体可以参考阮一峰老师的《Commit message 和 Change log 编写指南》。代码的commit的规范对团队非常重要,清晰的commit信息生成的release tag,对于生产环境的故障回滚业非常关键,能够提供一些有价值的信息。
统一API规范
统一Rpc服务接口的返回值ResultDTO,具体代码如下
success代表接口处理响应结果成功还是失败,errorCode、errorMsg表示返回错误码和错误消息,module表示返回结果集,把ResultDTO定义到common-api顶层二方库,这样以来各个应用不需要来回转换返回结果。
Http Rest接口规范约定同ResultDTO相差无几,需要额外关注一下加解密规范和签名规范、版本管理规范。
异常处理规范
异常处理不仅仅是狭义上遇到了Exception怎么去处理,还有各种业务逻辑遇到错误的时候我们怎么去处理。service服务层捕获的异常主要包括BusinessException(业务异常)、RetriableException (可重试异常) 到 common-api,定义一个公共异常拦截器,对业务异常、重试异常进行统一处理,对于可重试的异常调用的服务接口需要保证其幂等性。
另外其他业务层有些特殊异常不需要拦截器统一处理,内部可以进行自我消化处理掉,根据场景对应的处理原则主要包括:
直接返回
抛出异常
重试处理
熔断处理
降级处理
这又涉及到了弹力设计的话题,我们的系统往往会对接各种依赖外部服务、Api,大部分服务都不会有SLA,即使有在大并发下我们也需要考虑外部服务不可用对自己的影响,会不会把自己拖死。我们总是希望:
尽可能以小的代价通过尝试让业务可以完成;
如果外部服务基本不可用,而我们又同步调用外部服务的话,我们需要进行自我保护直接熔断,否则在持续的并发的情况下自己就会垮了;
如果外部服务特别重要,我们往往会考虑引入多个同类型的服务,根据价格、服务标准做路由,在出现问题的时候自动降级。
推荐使用Netflix开源的hystrix容灾框架,主要解决当外部依赖出现故障时拖垮业务系统、甚至引起雪崩的问题。目前我团队也在使用,能够很好的解决异常熔断、超时熔断、基于并发数限流熔断的降级处理。
分支开发规范
早期的时候源码的版本管理基于 svn,后来逐步切换到 git,分支如何管理每一个公司(在Gitflow的基础上)都会略有不同。
针对分支开发规范,指定如下标准:
分支的定义(master、develop、release、hotfix、feature)
分支命名规范
checkout、merge request流程
提测流程
上线流程
Hotfix流程
虽然这个和代码质量和架构无关,按照这一套标准执行下来,能够给整个研发团队带领很大的便利:
减少甚至杜绝代码管理导致的线上事故;
提高开发和测试的工作效率,人多也乱;
减少甚至杜绝代码管理导致的线上事故;
方便运维处理发布和回滚;
让项目的开发可以灵活适应多变的需求,多人协同开发。
统一日志规范
日志是产品必不可少的一个功能,具备可回溯性、能够抓取问题现场信息是其独一无二的优点,尤其在生产系统上问题定位等方面具有不可替代的作用。
这里着重强调一下针对异常的日志规范:
WARN和ERROR的选择需要好好考虑,WARN一般我倾向于记录可自恢复但值得关注的错误,ERROR代表了不能自己恢复的错误。对于业务处理遇到问题用ERROR不合理,对于catch到了异常也不是全用ERROR。
记录哪些信息,最好打印一定的上下文(链路TraceId、用户Id、订单Id、外部传来的关键数据)而不仅仅是打印线程栈。
记录了上下问信息,是否要考虑日志脱敏问题?可以在框架层面实现,比如自定义实现logback的ClassicConverter。
正确合理的使用日志,能够指引开发人员快速查找错误、定位问题,因此约定了一套日志使用标准规范,现在可以更多的参考《阿里经济体开发规约——日志规约》。
统一MYSQL开发规范
表的设计和 Api 的定义类似,属于那种开头没有开好,以后改变需要花10x代价的,我知道,一开始在业务不明确的情况下,设计出良好的一步到位的表结构很困难,但是至少我们可以做的是有一个好的标准。
统一工具与框架
对开发过程中所用到的公共组件进行了统一抽象与封装,包括 dao 层框架mybatis、cache 组件 jetcache、httpclien t组件、common-tools (公共工具),同时抽取出全局唯一ID、分布式锁、幂等等公共组件,把以上公共组件进行集成到各个应用,进行统一升级、维护,这样以来方便大家将更多的精力集中到业务开发上。