仓颉编程规范
[TOC]
命名与声明:
-
能使用const声明的常量一律使用const声明,使用const声明的标识符代替字面值(魔鬼数字)。
- 如果是对整个模块、整个包、当前文件所有代码生效的const应当做顶级声明,由不同的可见性修饰
- const声明的常量一律使用下划线分隔全大写英文单词。
- const声明的局部变量使用小驼峰命名法。
- 只有顶级const采用帕斯卡命名法。
- 代码中不要出现基本类型字面值,一律使用const声明的常量代替。
-
不强制要求必须使用const声明传统意义上的常量,大多数复合类型除非是注解或者作为实例化注解的实参,其它情况没有必要为它们声明const构造函数。
- const函数一律使用小驼峰命名法。
-
所有的类、接口一律采用帕斯卡(Pascal)命名法,例:
public class Sample{}
public interface FooBar{}
- 所有属性、函数、局部变量、顶级变量一律采用驼峰命名法,例:
let fooBoo = 0
let foo = 0
-
所有命名做到见名知义,不要有大段注释说明函数或类型能做什么,尽量做到意义明确的名字和简洁的注释,做到言简意赅。
-
package命名一律采用蛇型命名,按功能模块划分包名
-
下划线不能出现在非const的常量命名中
-
数字最好不要出现在命名中
-
所有命名一律使用英文,绝对不要用拼音和汉字命名,类名、函数名、属性名、常量名不要有数字,局部变量尽量不要有数字。如果不知道用什么词,有个网站是www.iciba.com http://unbug.github.io/codelf/#欺骗。
-
局部变量尽量做到何处使用何处声明
-
所有service实现都以ServiceImpl结尾,所有dao、service接口定义都是业务模块名以DAO/Service结尾,类中的DAO Service属性也以DAO/Service结尾。接口不以大写字母I开头,除非业务名称的英文描述以I开头;也不要包含interface这样的单词或缩写,比如inter Inter Interface等。
-
抽象类以Abstract开头
-
所有异常类名以Exception结束
-
关于设计模式
- 工厂类名以Factory结尾
- 适配器类名以Adaptor结尾
- 门面模式类名以Facade结尾
-
可以使用约定俗成的缩写命名,比如:conf config cfg fn props attr等
代码风格
- 避免不必要的嵌套
- 不要出现空的分支,比如下面的代码不能有
if(x < 1){
}else{
println(x)
}
- 不使用@Deprecated标记的api
- 不要使用;分隔代码
- 每行不要太长,尽量保证一眼看全一行代码。如果代码行太长可在操作符处截断配合缩进标明代码行之间的关系
- 一个类完成一类业务逻辑,不同类型的业务逻辑在不同类里实现。
- 一个函数完成一件事情。
- 尽量实现短小的函数体,大段函数不利于编译优化编译,也不利于阅读。保证一屏能大致显示一个函数实现即可,不要翻好多屏也见不到函数头尾。
- 函数体内各个更细致的逻辑之间用空行分割,但是函数体、循环体、match、if/else、类体、结构体、枚举声明代码块内不要出现连续三行以上的空行,否则会增加阅读难度。左花括号与类、结构体、枚举或函数的声明、if、else、for、while,紧接它们的上一行和下一行不要是空行。
- 复杂逻辑和曾经出错的地方有注释说明 eg. // fixed by wujingrun, on yyyy-MM-dd HH:mm, 简单描述问题或bug造成的后果
- 功能性或API级的类和函数开头有注释说明类的功能和实现人
/**
* 本类实现了XXXX,用于XXXX,解决XXX问题
* 如果是算法实现类,详细说明原理、数据结构、设计思想、参考URL
*/
public class ClassName{
/**
* 本函数实现了XXXX,用于XXXX
* @author wujingrun
* @param String 参数的意义
* @param Int64 参数的意义
* @return String
* @throws XxxxxException
*/
public func method(arg0: String, arg1: Int64): Unit {
…..//不要长久的保留TODO注释,
…..//如果此处踩过坑,请在此处简单说明
}
- 常量声明前面有注释说明常量的意义
/**
* 本常量的业务意义,eg.
* 当前应用程序版本过低,请您升级应用程序
*/
public const E0001 = "E0001";
- 算法复杂的类或函数,每段逻辑都有简单注释说明原理
/*
* implemented by wujingrun
* 采用的算法、数据结构、设计思想、参考文章的URL
*/
- 左花括号与类、结构体、枚举或函数的声明、if、else、for、while、match在同一行,右花括号与它们左对齐
- 函数体比函数声明向内缩进四个空格、循环体比for/while向内缩进四个空格、if else代码块比if/else向内缩进四个空格。
- 遵守最少知识原则,定义一个函数只接收这个函数所能完成任务的参数
- 对于必须调用close()或shutdown()才能释放资源的对象,遵守谁创建对象谁关闭的原则,作为局部变量,在try块外声明变量,在try块内创建并使用对象,在finally块内close()或shutdown()。如果需要释放资源的对象作为属性,相应的类必须实现close/end/shutdown等相关的public函数供对象使用方调用以便释放相关资源。对于实现了Resource接口的类型要使用try(....){….}。对于自定义的需要释放资源的类型也要实现Resource,以便使用方能够使用try(....){.....}方式释放资源。
try(file = File('/test.txt', Read)
out = File('/test.txt", Write)){
….//do sth
}
- && ||两边要有一个空格,或者代码行以它们结尾,后面的条件与它前面的条件左对齐。例:
a == b && b < c
a == b &&
b < c
-
多个逻辑表达式使用圆括号表示逻辑优先级。例:
(a == b && b < c) || a > d -
在需要性能和线程安全之间取舍时建议多使用std.collection.concurrent包下的集合。
-
最好不用锁,尽量避免竞态条件或多线程同时修改同一个对象。尽量做到一个对象属性由且只由一个线程修改,尽量不要发生线程争用。
-
不要采用返回字面值或常量值的方式控制代码流程,此处可以根据不同情况返回同一接口不同实现类的对象,在调用方执行返回的对象的函数,用这种方式完成不同的逻辑流程;而不要在调用方根据函数返回值执行大量if else或match。做到这一条有点难,需要在开发过程中持续改进。
-
对于连接字符串的场景,除非能够在一个表达式构造完成的情况可以使用+以外,其它情况一律使用StringBuilder,或者本工具库的StringGenerator。
关于日志
- 禁止使用中文记日志,有些操作系统里面没有中文库,没法检索。而且中文也会占用更多字节,浪费带宽。
- 禁止使用println记日志
- 除了做调试使用输出到控制台的内容,其它情况不要在正式代码中使用println print eprintln eprint等函数,也不要使用其它控制台API。
关于异常与错误
- 禁止在提交的代码里面出现printStackTrace()如果需要记录异常堆栈代码,请使用日志API。
- 对于应用开发由于参数错误导致的问题,属于业务逻辑范畴,为这些问题定义错误码。模块内部使用副作用管理控制业务执行过程,模块之间使用错误码。
- 对于工具库开发,遇到程序无法处理或不知如何处理的错误,都抛出异常。
- 公共代码的异常一律抛出,交给业务代码和公共拦截器处理异常,除非当前发生的异常不需要处理否则不要把异常隐藏起来,否则不易查错。
- 所有业务处理过的异常都要记日志。log.warn('simple exception description or business message, english only: ',e);