给team整理的编码规范

8 篇文章 0 订阅
7 篇文章 0 订阅

前言

代码是程序员的生命,是程序员日日夜夜心血的凝结,请大家像爱惜自己的眼睛一样来合理编写程序。

命名规范

  1. 所有工程,包,类,接口,方法,属性,变量,参数均使用英文单词进行命名,命名必须见命知意。

1.1包、变量、属性、参数命名:第一个单词首字母小写,后面的单词根据你的需要首字母依次大写,如com.yihaodian.backend.sso.backOperator,backOperatorDto,backOperatorName等等

1.2 方法命名:DAO层如果是单条查询请用find开头,如:findBackOperatorById,查询集合通过list开头,listMerchantListByOperatorId,新增用add开头,更新用update开头,删除用delete开头,Service层方法命名根据具体业务来,见命知意,如取消订单,cancelSo。

1.3 类命名:Action层以**Action结尾,Service层以**Service结尾,实现类以**ServiceImpl结尾,Dao层以**Dao结尾,实现类以**DaoImpl结尾。

  1. 所有包名使用必须使用 com.yihaodian.backend前缀,所有项目使用com.yihaodian.backend.[project name], project name 是项目的开发代号或缩写。如:com.yihaodian.backend.backendcs.*.
  2. 所有新加的工程必须是标准的maven工程,maven版本是3.x,工程名称一律以backend-*开头,如backend-erp,backend-cs。
  3. 配置文件命名,spring框架前缀为spring-*,struts2前缀为struts-*,ibatis前缀为ibatis-*。
  4. 单元测试包名命和路径必须要和每个单元测试对应的方法,如:com.yihaodian.backend.sso.service.impl.CategoryServiceImpl. findCategoryAllFirstLevel方法对应的单元测试和路径为com.yihaodian.backend.sso.service.impl.CategoryServiceImplTest. testFindCategoryAllFirstLevel.

下图为一个后台maven工程参考

 


注释规范

概述

代码中为什么要包含注释?

  1. 别人要调用你的程序中的公共接口,对这部分进行文档描述,使别人能够正确而有效的使用它。
  2. 除了自己,别人要阅读和维护你的代码。为了使代码更容易维护,首先要使代码更易于理解,才能在理解的基础上进行维护。对这些代码进行文档描述,将使这个过程变得更加容易。

如果代码可读性很好,命名表意丰富,清晰,一般不需要特别多的注释。对于类,主要着重要描述它的职责,即它能干什么,对于复杂的算法实现,应该使用内部实现注释,说明算法的主要思路,对于长方法,要让阅读代码的人比较容易的明白方法实现的主要流程。反之,对于一看就懂的方法,则不需要进行注释,比如get/set 方法。

一般原则

  1. 代码应该和注释保持同步。
  2. 注释尽量简洁,尺度没有准确的定义,大部分人能明白即可,可以将自己的代码给同事看看。

注释内容

/***

 * 后台用户所有中间表操作的门面类

 * @create-time  2011-11-15

 * @author backend

 *

 */

public class BackOperatorFacadeServiceImpl implements BackOperatorFacadeService {

   

    private static final long serialVersionUID = 1380602554886673288L;

    private BackOperatorDao backOperatorDao;

    private BackOperatorMerchantDao backOperatorMerchantDao;

    private CacheService cacheService;

 

    Log logger = LogFactory.getLog(BackOperatorFacadeServiceImpl.class);

 

    /**

     * 根据用户Id查询所有用户的角色Id集合

     * @param backOperatorId

     * @return

     * @throws Exception

     * @modified-by  bing

     * @modifed-time 2011-11-20

     */

    public List<Long> listRolesByBackOperatorId(Long backOperatorId){

       if(null==backOperatorId)

           throw new SsoBizException(ExceptionCode.PARAM_IS_NULL, PropertiesUtils.getValueFromException(ExceptionCode.PARAM_IS_NULL));

       try {

           return this.backOperatorDao.listRolesByBackOperatorId(backOperatorId);

       } catch (Exception e) {

           e.printStackTrace();

       }

       return null;

    }

复杂的业务逻辑一定要针对每个操作进行注释

编码规范

Ø  约束原则

  1. 对于静态方法,应该使用类名去使用,不应该用实例去引用,主要是为了体现更多的语义。
  2. 对一些基本数据类型和不太可能通过继承进行扩展的类,应声明为final,提高效率。
  3. 类和方法的粒度保持适中,保持类的规模尽量短小,职责单一。小类有很多好处,易于设计,易于测试,易于理解。同样方法也要尽量的小,每个方法尽量不要超出25 行。
  4. 单一职责,如果一个类有多于一种的职责,当需求变化时,类的职责就要发生变化,而因此就会引起引用该类的代码发生改变,职责越多,这个类就容易跟更多的类产生耦合关系,而且改变一个职责,可能会影响到另外一个职责的履行。
  5. 编写代码前,先编写注释。

总的来说尽量保证类和方法职责单一,支持可扩展。

Ø  具体约束

 

1. int tempValue;

tempValue = maxValue;

tempValue = minValue;

tempValue = anotherValue;

tempValue 在生命周期内表示了各种各样的意图,增加理解代码的难度。

应该为每个独立概念定义单独的变量:

int tempMaxValue;

int tempMinValue;

int tempAnotherValue;

  1. 仅仅循环控制变量才能出现在 for()循环中

sum = 0;

for (i = 0; i < 100; i++) {

sum += value[i];

}

//避免:

for (i = 0, sum = 0; i < 100; i++){

sum += value[i];

}

  1. 循环变量应靠近循环体初始化

isDone = false;

while(!isDone){

...

}

//避免

isDone = false;

...

...

while(!isDone){

...

}

  1. 避免长的布尔表达式,应换成多个更容易理解的表达式。

boolean isFinished = (elementNo < 0) || (elementNo> maxElement);

boolean isRepeatedEntry = elementNo == lastElement;

if (isFinished || isRepeatedEntry) {

 ...

}

// 避免

if ((elementNo < 0) || (elementNo > maxElement)||elementNo ==

lastElement) {

...

}

  1. 不要在条件语句中执行方法,以提高可读性

InputStream stream = File.open(fileName, "w");

if (stream != null) {

...

}

//避免

if (File.open(fileName, "w") != null)) {

...

}

  1. 代码缩进,应该使用 4 个空格为一个单位进行缩进。

public String invoke() throws Exception {

....String profileKey = "invoke: ";

....try {

........UtilStack.push(profileKey);

........if (executed) {

............test = true;

.......}

....catch{

....}

}

7. 常见的逻辑判断应该放到service层处理,比如数据为空判断,数据不合理判断,数据异常判断,都放到service层,复杂的业务逻辑一定要放在service层,DAO层和Action层只是简单的调用,异常处理、日志处理、事务处理也统一放到service层。怎样保证业务层精简请看上面“编码规范->约束原则第3条”。

8. If-else不应嵌套太多,不能超过三层,如果嵌套太多应该考虑调整你的逻辑了或者换种实现方式,比如:命令模式等等。

9. 嵌套循环不能超过三层

10.坚决避免循环依赖,工程和代码之间一定不能有循环依赖

11.数据库连接,读写流等等一定要关闭,常见情况是放到finally关键字里面处理,如:

    OutputStream os = null;

    try {

        //开启一个输出流

        os = new FileOutputStream("some file path");

    } catch (FileNotFoundException e) {

        e.printStackTrace();

    }finally{

        try {

           //关闭一个输出流

           os.close();

        } catch (IOException e) {

           e.printStackTrace();

        }

    }

 

12.日志处理,一般的异常情况都需要增加log4j日志,尽量不要用“System.out.println()”,log4j的常见级别为debug,info,warn,error。通过log4j记录日志应该判断当前日志级别是否可用,减少不必要的IO操作。如:

    Log logger = LogFactory.getLog(RoleAction.class);

     if(logger.isErrorEnabled())

        logger.error("some errors");

     if(logger.isDebugEnabled())

        logger.debug("some debugs");

13.习惯使用apache的工具类做常见判断,apache常见的工具类有StringUtils,CollectionUtils等等,存放的jar包commons-lang.jar,common-collections.jar。

14.敏感的数据更新记得加上乐观锁,有并发同步问题记得加锁。

15.并发量很大的业务逻辑考虑用线程池实现。

欢迎补充。。。。

外部接口规范

1.  项目间接口调用不应出现循环依赖调用,两个工程存在接口间调用应该将共有的接口和数据传输对象分装成公用jar包。如:客服系统backend-cs和工作流系统backend-bpm同时依赖公有的backend-bpm-api,backend-bpm-api存放是公用的dto和业务类接口。

2.  敏感数据接口调用考虑数据加密和签名,比如:后台数据加密目前使用的对称加密算法Base64,签名用的算法是MD5,密钥请尽量复杂包括数字字母和特殊字符。

3.  一号店内部项目接口调用请考虑hessian,对外网公布的接口请考虑Webservice。

4.  服务端并发量大的接口请考虑异步调用,比如使用线程池等等。

5.  接口调用的客服端和服务端请做好异常日志处理及相关异常处理,日志记录最好不要用主库的表,避免给主库造成太大的压力。

6.  暴露接口的服务端一定要有接口文档,并且要有详细的接口代码注释。

异常处理规范

  程序其实由若干个主程序和n个异常流组成,异常流发生于主程序里面,try里面是主程序,catch里面异常流,一个标准的try catch的格式如下:

try{

  程序代码

}catch(异常类型1 异常的变量名1){

  程序代码

}catch(异常类型2 异常的变量名2){

  程序代码

}finally{

  程序代码

}

合理的定义和处理异常可以方便开发人员查找问题,一个工程里面应该针对每种情况定义不同的异常,如:参数不合理,数据不存在,业务接口异常等等,举个例子,用户不存在我会定义一个OperatorNotExistsException,当查询用户不存在时抛出此异常,参数为空或者不符合某些规定的条件时抛出IllegalArgumentException,所有的异常处理都应该放在业务层处理。

SQL编写规范

 一个业务sql最好不要超过3张表,少用like,in,order等关键字

1. 不等于统一使用"<>"

Oracle认为"!="和"<>"是等价的,都代表不等于的意义。为了统一,不等于一律使用"<>"表示。

2. 使用表的别名

数据库查询,必须使用表的别名,方便阅读。

3. 禁止使用select *

5.减少子查询的使用 

  子查询除了可读性差之外,还在一定程度上影响了SQL运行效率。

请尽量减少使用子查询的使用,用其他效率更高、可读性更好的方式替代。

6.合理的使用索引

7.主表使用逻辑删除(is_deleted)

8.主表使用状态字段creator,modifier,update_time,create_time

9.少用clob等大字段,如果必须要用请拆分出单独的表

10.大表和附属表应该分开来,如:产品表product是一张大表,组合产品、序列产品等特殊的附属表不应该放到大表中,应该单独建表。

11.选择最有效率的表名顺序

  ORACLE的解析器按照从右到左的顺序处理FROM子句中的表名,因此FROM子句中写在最后的表(基础表driving table)将被最先处理。

  在FROM子句中包含多个表的情况下,必须选择记录条数最少的表作为基础,当ORACLE处理多个表时,会运用排序及合并的方式连接它们。

  首先,扫描第一个表(FROM子句中最后的那个表)并对记录进行排序;

  然后扫描第二个表(FROM子句中最后第二个表);

  最后将所有从第二个表中检索出的记录与第一个表中合适记录进行合并

  例如:

  表 product 16,384 条记录

  表 category 5 条记录

  选择category作为基础表 (最好的方法)

  select count(*) from product,category执行时间0.96秒

  选择product作为基础表 (不佳的方法)

  select count(*) from category,product执行时间26.09秒

  如果有3个以上的表连接查询,那就需要选择交叉表(intersection table)作为基础表,交叉表是指那个被其他表所引用的表

  例如:

  back_operator_category表描述了catgory表和back_operator表的交集

  select *

    from back_operator bo,catgory c,back_operator_categoryboc  

where bo.id = boc.back_operator_id and c.id = boc.category_id

  将比下列SQL更有效率

  select *

    from back_operator_category boc,back_operatorbo,catgory c

where bo.id = boc.back_operator_id and c.id = boc.category_id

12.WHERE子句中的连接顺序

  ORACLE采用自下而上的顺序解析WHERE子句

  根据这个原理,表之间的连接必须写在其他WHERE条件之前,那些可以过滤掉最大数量记录的条件必须写在WHERE子句的末尾.

13. 减少访问数据库的次数

  当执行每条SQL语句时,ORACLE在内部执行了许多工作:解析SQL语句,估算索引的利用率,绑定变量,读数据块等等

  由此可见,减少访问数据库的次数,就能实际上减少ORACLE的工作量.

14.使用exists(not exists)代替in(notin)

15.使用PrepareStatement,避免使用拼凑sql

ERD设计规范

    一个合理的ERD设计文档需要表机构设计、流程图、时序图,尽量避免长篇大论描述,用伪代码代替。

CODE REVIEW规范

    一个大项目(超过20人日)最少需要安排2次code review,更长周期的可以安排更多,code review一般都需要domain leader,team leader参加,如果他们有事,需要开发人员交叉review,如果是交叉review 需要记录问题点,改进方案并群发邮件到backend组。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值