读开发规范有感
首先我们为什么要开发规范
第一点,是开发代码规范,代码机构清晰,便于后其维护,更有助于代码重构,好处之大,可想而知,一个项目的生命周期,百分之八十在项目维护上。
第二地,规范的 代码,让人赏心悦目,更能体现出开发者的水平,也能表现出整体团队的实力程度。
编码环境约定发
- 开发代码统一编码采用UTF-8
- 数据源链接:jdbc:mysql://ip:port/dbname?charaterEncoding=utf-8
- Java编码:utf-8
- jsp文件:utf-8
- Xml文件:utf-8
- Properties文件:utf-8
构建工具
- 基于maven进行项目构建,用Jenkins来做系统发布和持续集成
DB
- 应用MySQL配置链接,密码进行加密
IDE
- IntelliJ IDEA
- Eclipse
命名原则
- 见名知意
- 拼写准确
- 在语义表达清楚的情况下,字符尽量少用
工程,模块命名
- 全部小写
- 多个工程前缀相同,后缀用“-”隔开
包命名
- 全部小写,避免使用下划线等特殊字符
- 以“公司域名+(项目组名)+项目名称+(子项目名称)+模块名称”。按照实际开发,减少层级
- 优先使用“web,model,domain,dao,service,business,controller,common,listener,cost,util,proxy,api”等词汇进行命名
- 实现包类用impl结尾
类命名
- 大骆驼拼写法(UpperCamelCase),形成驼峰式,更有助于读取理解
- 接口实现类用impl结尾
- 抽象类命名使用Abstract或者Base为前缀
- 类结构采用设计模式,可加上设计模式的前缀。如“Factory,Proxy,Strategy,Adapter,Facade”等 词语
- 根据性质,类型,职能进行划分,划分如下:
功能 | 后缀 | 实例 |
数据对象 | PO或者DO | UserPO,UserDO |
业务对象 | BO | UserBO |
展示对象 | VO | UserVO |
请求对象 | Req | UserReq |
响应对象 | Resp | UserResp |
数据访问实现类 | DaoImpl | UserDaoImpl |
业务逻辑处理实现类 | ServiceImpl | UserServiceImpl |
远程服务实现类 | ClientImpl | UserClientImpl |
控制器 | Controller | UserController |
工具类 | Utils | StringUtils |
单元测试类 | Test | UserServiceTest |
工厂类 | Factory | RuleFactory |
Filter类 | Filter | CroeFilter |
Servlet类 | Servlet | UserServlet |
监听器 | Listener | CreaterOrderListener |
方法命名规范
- 使用lowerCamelCase风格,遵循驼峰形式。
- 以动词+名词形式命名,如:findUserById
Dao 层方法命名
- 单条件查询,以select(推荐),find,query,get作为前缀
- 多条件查询,以list(推荐),query,select作为前缀
- 插入操作,以save(推荐),insert作为前缀
- 删除操作,以remove(推荐),delete作为前缀
- 更新操作,以update作为前缀
- 统计数值,以count作为前缀
- 批量操作,以batch作为前缀
变量命名
- 成员变量、局部变量、方法参数使用lowerCamelCase风格,遵循驼峰形式。
- 局部变量命名名可以一定程度使用缩写。
- 常量全部大写,单词间用下划线分隔。
- 如果是集合或数组,⽤名词复数
代码风格
通用原则
- 追求代码结构美学。
- 不要省略,可选大括号也加上。
- if, else, for, do, while语句一起使用,即使只有一条语句,也建议把大括号写上.
- 左大括号前不换行,左大括号后换行, 右大括号前换行
源文件结构
package语句
- 每个package语句独立成行。
import语句
- 每个import独立成行。
- 不要使用通配符,比如import java.util.*
写注释的原则
- 释不宜过多。注释固然重要, 但好的代码应当本身就是文档。有意义的命名, 要远胜过要用注释解释的含糊不清的名字。
- 需要注释解释的代码尽量提成小方法,用方法名称解释。
- 注释不应该只是浅显的描述,注释要描述代码背后的意图。
- 注释要简洁,不要封闭在由星号或其它字符绘制的框架里。
- 应用了高级技巧的地方尽量写上注释
- 注释要言简意赅, 不要拖沓冗余, 复杂的东西简单化和简单的东西复杂化都是要被鄙视的
- 注释应与代码保持同步
- 注释是为了让别人看懂,用中文吧
单元测试
- 测试代码和生产代码需遵守相同代码规范。
- 尽量写更多的单元测试
- 测试类的命名以它要测试的类的名称开始,以Test结尾。如StdPriceUtilsTest
- 单数据断言, 应使用assertTrue, assertFalse, assertNull, assertNotNull。
- 多数据断言, 应使用assertThat。
- 精确断言, 尽量不使用not, containsString断言。
- 调用业务方法的变量, 应命名为actualXXX, 期望值应命名为expectedXXX。
- 只有junit assertXXX, hamcrest, mocktio相关可以使用static import。
- 基于maven构建的工程,测试类放在src/test/java目录下,测试类包名和要测试的类包名一致。
异常规范
- 异常不要用来做流程控制。
- 为抛出的异常写注释,写文档。
- 如果要声明异常。一定要声明具体的异常,避免泛化的Exception。
- 尽量捕获具体的异常,而不是捕获泛化的Exception。
- 避免空的catch块吞噬掉异常。至少需要记录日志(确实不需要向上抛时),以供查看分析。
- 在catch之后封装成新异常抛出的时候, 不要记录日志. 抛出的异常会有上层来处理并记录日志, 再记录日志就重复了。
- 不要在finally块中抛出异常
- 不要使用e.printStackTrace()。
- 在finally程序块中关闭或者释放资源。
- 优先使用标准异常或错误。如IllegalArgumentException,IllegalStateException,UnsupportedOperationException,NoSuchElementException,FileNotFoundException、AssertionError等。
- 不要把异常放置在循环体内。try-catch语句本身性能不高,在开发中,要尽量避免。
- 不要在只读操作中轻易抛出异常。没有数据时,要返回长度为0的数组或列表。如:return Collections.emptyList()。只读结果让调用者来确定如何处理。
- 如果你认为调用者不能通过try…catch来处理你抛出的异常,要使用非受检查异常。对可恢复的情况使用受检异常,对编程错误使用运行时异常。
- 要做异常包装。工程内要有统一的异常体系。如BossBizException,BossServiceException,RuleTypeUnsupportedException等。
- 基于mybatis的Dao层不需要显式抛出异常;Service要捕获异常dao层异常,并抛出可读的业务异常。
- 在Service层捕获了异常后,一定要重新抛出一个新的异常,这个异常最好是运行时异常,否则可能会影响的声明式事务的执行。
- Web MVC开发中要使用全局的异常处理。
日志规范
- 采用slf4j + logback日志组件,这是当下最好的组合
- 日志变量定义推荐如下。
- private static final Logger logger = LoggerFactory.getLogger(ChargeServiceImpl.class);
- private static final Logger noCalcCostPriceLogger = LoggerFactory.getLogger("noCalcCostPriceLogger");
- 不要因为记录日志,导致系统异常,从而导致正常的业务逻辑被中断。是否会引起NPE?是否会导致OOM(比如输出巨大的列表)?是否会因打印无效日志造成磁盘被打爆?等等。
- 一般来说,日志只记录有效的方便定位问题的信息,比如只记录对象的id,只记录列表的长度等。忌直接输出整个对象的toString。
- 要使用参数化(占位符)方式记录日志,不要使用拼接字符串的方式。原因:代码较乱,不易一眼看出日志格式;字符串拼接,性能较差。
- 不要写魔法日志。有些开发人员为查找信息方便,会输出一些类似&&###>>>>>>。这是一种陋习,要避免。
- 不要将异常直接显示在页面或客户端。
- 日志文件命名规范
- 代码中只是用ERROR、WARN、INFO、DEBUG这几个日志级别
- 生产环境默认使用INFO级别。
- 关注日志记录对于系统性能、安全性的影响
- 禁止使用System.out、System.err、 e.printStackTrace()输出日志
- 避免重复输出日志,浪费磁盘空间。在logback.xml中设置additivity=false。
- 正确的使用输出模式。 生产环境,不要在日志中输出文件名、类全名、方法名、行号、Logger全名。在日志模式中指定文件名、类全名、方法名、行号会带来严重的性能问题。
- 生产环境关掉ConsoleAppender。生产环境输出到控制台是完全没有必要的,既浪费磁盘空间,又损耗性能。
logback去掉ch.qos.logback.core.ConsoleAppender
log4j去掉org.apache.log4j.ConsoleAppender
- 生产、开发、测试等环境的日志配置文件要做分离。
- 要做日志分离。按日志级别输出到不同文件中,比如错误(error)和警告(warn)日志输出到单独的文件中;针对访问日志、性能统计、个性化的业务,也可以输出到独立的文件中。方便查找和定位问题
- 需要输出日志的一些地方。
请求入口和出口
与第三方接口的交互(调用和返回)
程序异常: 如数据库无法连接
用户访问统计:用户IP、上传下载的数据量,请求耗时等
启动、关闭、配置加载(系统在启动过程中通常会首先读启动参数,可以在系统启动后将这些参数输出到日志中,方便确认系统是按照期望的参数启动的)
审计、安全操作日志
性能统计日志
后台定期执行的任务:如定期更新缓存的任务,可以记录任务开始时间,任务结束时间;缓存配置的更新等等,这样可以掌握定期执行的任务的状态;
并发编程指导原则
- 如果需要频繁创建线程,考虑使用线程池,而不是使用最原始的Thread。用Executors.newSingleThreadExecutor代替new Thread吧。
- 永远为线程取一个有意义的名称,方便问题诊断。
- 并发编程最好先做数据分离,每个线程处理不同的数据,减少数据的同步。
- 优先使用JUC中的CountDownLatch、CyclicBarrier等工具。
- 计数器优先使用原子类,非阻塞,以获得最好的性能。
- 注意非线程安全的SimpleDateFormat。
- 使用ThreadLocal保存状态变量。
- 合理使用volatile。
- CountDownLatch要避免在countDown方法之前遇到异常,导致countDown没被执行,永远等待。
安全编码指导原则
通用
- 敏感数据如密码,加盐哈希存储应该是标配。
- 永远不要信任用户输入,对用户输入数据做后端要有效性的检查。
- 严格控制文件上传,文件类型判断不能仅根据文件后缀确定。
- 源码中不出现密码,配置文件中也不要出现密码(要加密)。
- 注意敏感信息的保护。
用户的敏感信息包括密码、短信验证码、支付验证码、身份证号、银行卡号、银行密钥,商户密钥等信息;用户敏感信息不能泄露,否则可能会带来不安全因素。
可能会导致敏感信息泄露的方式有:Logger、URL的get参数(因为 URL 的get 参数会在nginx和tomcat 日志中被输出)。敏感信息输出要打码(***输出)。