几个祖传代码不遵守就想骂的代码规范

今天说几个我曾经在管理项目和团队要求的基本编码规范。实际执行下来成本比较低,长期坚持下来的确有助于项目的维护。

虽然是几个非常基本的代码规范,但我们只在团队比较稳定的时候坚持下来过,后来随着人员更迭,懂得都懂。 这里也不是吐槽谁的代码习惯不好, 我也干过复制旧代码过来就能用,妈呀真香,赶紧上线吧这种事情。

数据表和Model的命名规范

类型

规则

正确示例

错误示例

数据表名

使用SnakeCase 命名法多个单词用下划线 _ 分割使用单词的复数形式命名

vip_members

vipMembers   vipMember vip_member

数据表字段名

使用SnakeCase 命名法多个单词用下划线 _ 分割

user_name

userName UserName  _user_name

数据表在代码中的Model 名

使用CamelCase命名 单词使用单数形式

VipMember  vipMember

VipMembers  Members  vip_member

关于为啥数据表用复数,Model用单数,我的理解是Model代表的是这类东西,在英语里应该用复数。

下面说几个Go语言里比较容易坚持执行下去且能有助于我们减少BUG的编码规范。其他语言像Java的话,看阿里出的《阿里巴巴Java手册》就可以,里面要求的比较细致。

Go语言编码规范

1.函数签名要避免歧义

函数名、参数名、参数类型、返回值类型要表达清楚要做的事情,避免产生歧义。这一条,感觉说简单非常简单,但是实际项目开发中,总是有不少人直接copy类似的函数,名字也不按使用场景去调整,让看代码的人就很难受。

错误案例:

func handleSomething(delay int) {
  for {
    // ...
    time.Sleep(time.Duration(delay) * time.Millisecond)
  }
}
poll(10) // delay参数定义成int 每次加的延迟是10毫秒还是10秒,还需要看poll函数的实现才知道

正确案例:

func handleSomething(delay time.Duration) {
  for {
    // ...
    time.Sleep(delay)
  }
}
poll(10 * time.Second) //delay参数定义成time.Duration类型, 调用时根据需求传递执行任务时要延迟的时间段
 
 
// 或者用参数名,明确告诉调用者,传递要延迟的秒数
func handleSomething(delaySeconds int) {
  for {
    // ...
    time.Sleep(delaySeconds * time.Second)
  }
}

2.禁止使用硬编码的魔术数字或字符串进行逻辑判断

在逻辑判断里使用类似判断属性值是否等于某个硬编码的值时会使得代码晦涩难懂,应该使用更能从字面上看明白含义的常量来代替这些逻辑判断里硬编码的值。

错误案例

if prize.Type != 1 && prize.Type != 2{
    ......
}

正确案例:

const (
  PRIZE_TYPE_COUPON = 1
  PRIZE_TYPE_MONEY = 2
  PRIZE_TYPE_VIPSCORE = 3
)

if prize.Type != PRIZE_TYPE_COUPON && prize.Type != PRIZE_TYPE_MONEY {
    ......
}

3.避免在init中修改已初始化好的数据

注意程序的完全确定性,不要依赖init执行的顺序实现功能,比如在后执行的init函数中对前面已初始化后的全局变量进行更改。

4.slice、map、chan、struct指针使用前必须先初始化

未初始化的map 默认值是nil , 可以对nil map进行读取,但是写入会直接panic:

   var aMap map[string]string


aMap["foo"] = "bar" // panic

未初始化的slice,可以进行读取和append操作,但不做初始化遇到接口中要返回的某个字段查不到数据直接返回,该字段在JSON里会用null表示而不是[], 有一定几率造成前端错误。

type Person struct {
    Friends []string
}
 
 
func main() {
    var f1 []string
    f2 := make([]string, 0)
 
    json1, _ := json.Marshal(Person{f1})
    json2, _ := json.Marshal(Person{f2})
    fmt.Printf("%sn", json1)
 
    fmt.Printf("%sn", json2)
}
 
 
{"Friends":null}
 
{"Friends":[]}

向未初始化的nil chan 写入会造成goroutine阻塞,程序最终会死锁:

func main() {
//fmt.Println("Called heapAnalysis", heapAnalysis())
var achan chan struct{}
achan