全部分类

您的位置:>首页 >技术文章

软件开发代码规范

作者: 时间:2021-03-03 13:20:59 点击量:351 来源:https://www.toutiao.com/i6927914410560258574

软件开发代码规范

https://www.toutiao.com/i6927914410560258574

代码规范本身就不是对与错的选择,而是结合很多人在工作中遇到的问题的分析、总结,通过一定的规则约束避免再次出现类似问题。

谷歌发布的代码规范中指出,80% 的缺失是由 20% 的代码所引起的。每个人写代码的思维方式、思路、方法不同,技术水平也不同,这时候确实需要有较为正式的编码规范作为约束。

本文主要参考了这份开源的代码规范: https://vipshop.github.io/vjtools/#/standard/

软件开发代码规范

太难了


编码规范:

命名规则:

  • 禁止使用非标准的英文缩写,禁止拼音缩写,尽量不用拼音
  • 包名全部小写。点分隔符之间尽量只有一个英语单词,即使有多个单词也不使用下划线或大小写分隔
  • 类名与接口名使用 UpperCamelCase 风格,遵从驼峰形式
  • 方法名、参数名、成员变量、局部变量使用 lowerCamelCase 风格,遵从驼峰形式,避免在解析时,大小写转换出问题
  • 常量命名全大写,单词间用下划线隔开。力求语义表达完整清楚,不要嫌名字长
  • 枚举类名以 Enum 结尾; 抽象类使用 Abstract 或 Base 开头;异常类使用 Exception 结尾;测试类以它要测试的类名开始,以 Test 结尾
  • 实现类尽量用 Impl 的后缀与接口关联,除了形容能力的接口
  • POJO 类中布尔类型的变量名,不要加 is 前缀,否则部分框架解析会引起序列化错误,例如 boolean delete,在调用时自动转换为 isDelete

代码格式和注释

  • 使用项目组统一的代码格式模板,基于 IDE 自动的格式化
  • 通过空行进行逻辑分段
  • 删除空注释,无意义注释
  • 避免创建人,创建日期,及更新日志的注释
  • 类、类的公有成员、方法的注释必须使用 Javadoc 规范,使用 /** xxx */ 格式,不得使用 //xxx 方式
  • 使用 //region 和 //endregion 包括代码,方便折叠查看
  • 一行代码不超过100个字符,缩进使用 2 个字符
  • 注释的 // 后面跟一个空格在写具体文字
  • 中文英文数字等之间建议加个空格隔开,例如:添加 hosts 文件

方法和类

  • 方法尽量不要超过 200 行,超过 10 行以上重复的代码,都可以考虑抽取公用的方法。
  • 方法参数最好不超过 3 个,最多不超过 7 个
  • 注意合理对参数进行校验
  • 正被外部调用的接口,不允许修改方法签名,避免对接口的调用方产生影响
  • 不使用 @Deprecated 废弃的方法和类
  • 可见性最小化:任何类、方法、参数、变量,严控访问范围
  • 类尽量不要超过 500 行
  • 构造函数如果有很多参数,且有多种参数组合时,建议使用 Builder 模式
  • 使用 lombok 插件来减少臃肿的代码 https://www.jianshu.com/p/365ea41b3573
  • 慎用继承,深度不要超过 3 层,继承数量不要超过 2 个

控制语句

  • if, else, for, do, while语句必须使用大括号,即使只有单条语句
  • 少用 if-else 方式,多用哨兵语句(不符合条件先 return)式以减少嵌套层次
  • 善用三元运算符,减少使用取反的逻辑(NodeJs 也可以这样,a==1 && (b=1) 满足条件时给 b 赋值)
  • 表达式中,能造成短路概率较大的逻辑尽量放前面,使得后面的判断可以免于执行
  • 在一个 switch 块内,都必须包含一个 default 语句并且放在最后,即使它什么代码也没有
  • 循环体中的语句要考量性能,RPC 操作尽量移至循环体外处理,能用 while 尽量不用 do-while

变量

  • 所有包装类对象之间值的比较,全部使用 equals 方法比较
  • double 及 float 的比较,要特殊处理
  • 当字符串拼接不在一个命令行内写完,而是存在多次拼接时(比如循环),使用 StringBuilde r的 append(),+ 实际是 StringBuilder,但循环时会重复 new StringBuilder
  • 字符串拼接对象时,不要显式调用对象的 toString(),+ 能很好地处理 null 的情况
  • 不要在 foreach 循环里进行元素的 remove/add 操作,remove 元素可使用 Iterator(迭代器:游标模式)方式
  • 使用 entrySet 遍历 Map 类集合 Key/Value,而不是 keySet 方式进行遍历,keySet 遍历的方式,增加了 N 次用 key 获取 value 的查询。
  • 当对象用于集合时(以对象作为 Map 的 Key,或将对象存入 Set 时)需要重新实现 hashCode() 和 equals()
  • 长生命周期的集合,里面内容需要及时清理,避免内存泄漏
  • 高度注意各种 Map 类集合 Key/Value 能不能存储 null 值的情况
  • 集合如果存在并发修改的场景,需要使用线程安全的版本

并发

  • 创建线程或线程池时请指定有意义的线程名称,方便出错时回溯
  • 线程池不允许使用 Executors 去创建,避资源耗尽风险
  • 正确停止线程,最优雅的退出方式是先执行 shutdown(),再执行 shutdownNow()
  • 编写可停止的 Runnable,Runnable 中必须捕获一切异常
  • 全局的非线程安全的对象可考虑使用 ThreadLocal 存放
  • 能锁区块,就不要锁整个方法体,能用对象锁,就不要用类锁

异常与日志:

  • 创建异常的消耗大,只用在真正异常的场景,不用异常来做条件判断,而应先充分校验
  • 捕获异常一定要处理;如果故意捕获并忽略异常,需要注释写明原因
  • 异常处理不能吞掉原异常,要么在日志打印,要么在重新抛出的异常里包含原异常
  • 如果不想处理异常,可以不进行捕获。但最外层的业务使用者,必须处理异常,将其转化为用户可以理解的内容
  • 必须对资源对象、流对象进行关闭,或使用语法 try-with-resource,不能放在 try 块或 catch 块
  • 如果处理过程中有抛出异常的可能,也要做 try-catch,否则 finally 块中抛出的异常,将代替 try 块中抛出的异常
  • 不能在 finally 块中使用 return,finally 块中的 return 将代替 try 块中的 return 及 throw Exception
  • 应用中不可直接使用日志库(Log4j、Logback)中的 API,而应使用日志框架 SLF4J 中的API
  • 对不确定会否输出的日志,采用占位符或条件判断,对确定输出,而且频繁输出的日志,采用直接拼装字符串的方式,因为查找占位符需要消耗资源
  • 除了应用启动时,禁止使用性能很低的 System.out() 打印日志信息
  • 禁止配置日志框架输出日志打印处的类名,方法名及行号的信息
  • 日志主要分为用户操作日志、程序运行日志、异常日志,多记录 “ 有营养 ” 的日志,以便于我们排查问题为目的

代码提交规范

  • 参考:https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines
类型
新增
修改
修复
移除
优化
重构
风格
测试
[发版]
[预发]
[调试] // 调试的改动是临时的,后续需要进行 reverse 操作 示例
新增 登录功能
修改 登录 IP 限制
修复 登录出错问题
移除 登录功能中已废弃的代码
优化 登录功能,提升性能
重构 登录过期判断逻辑
风格
测试 登录流程
[发版] 1.0.0+1807051000 [预发] 1.0.0+1807051000 [调试] 登录出错问题


感谢你能看到这里

点击这里给我发消息