Golang代码规范实践总结

535 阅读7分钟

Golang 代码规范总结.

完全遵守破窗原理.

1、常量.
  • 命名。遵循驼峰原理,可导出的大写.
  • 注释。常量代码块必须有一个总的说明,并且类型必须自定义,自定义类型必须紧跟着常量代码块,并且可导出的需要进行注释申明,除了有一个总的说明之外,还需对每一个常量进行额外说明用来表示当前常量在当前常量快中的一个细致的说明. 注释规范:// ConstName comment
  • 使用。如果一个函数内使用某个常量来作为入参进行使用,那么调用者就应该在调用方哪里转换为自定义的枚举类型,而不是在函数内部进行多余的类型转换。因为函数内部进行比较的话,需要额外进行常量转换,如果调用方在调用时进行转换,那么调用者一定知道该参数类型才会进行转换进行调用.
  • 归拢。
    • 就近原则。
2、结构体.
  • 命名。结构体命名必须遵循驼峰命名,并且前缀不能和包名重叠. 每一个可导出的函数必须有注释进行申明.
  • 字段。控制每一个结构体字段的冗余程度,要保证每一个字段都物尽其用,不要申明含义相同的字段,同时要保证每一个对外的结构体字段都必须有用,如果在某个接口里面该字段没有用到,那么就说明该接口不适合用当前结构体来进行返回.
  • 构造函数。如果结构体是通用结构体,则必须使用sync.Once来实现单例模式。尽量不要再init进行初始化一些实例。
3、函数(方法).

函数或者方法从整体上看流程应该是很清晰的才对,如果看的整体流程不是清晰,那么就说明当前函数设计的不是很理想。

  • 功能。如果是通用工具类则用方法,否则则用函数。虽然golang在面向对象非常灵活,但是必须遵守以对象来进行开发。

  • 接受者。函数接受者应该简单,避免this特殊字符,可以考虑结构体首字母。

  • 命名。命名应该通过函数名字以及参数就能知道函数大概是怎么实现原理,如果更加细致可以通过注释Demo来细致说明,避免通用化函数名称。同时在命名时避免多个含义名字混合使用,比如get和filter混合使用,但是filter又没说明通过什么来进行filter,导致含义不是很明确。

  • 参数。

    • 命名。参数命名必须通过这个参数命名就可以了解这个参数在上下文的具体含义,不需要调用者去看上下文源码去理解该参数的含义。
    • 顺序。常用通用参数定义靠前,log以及context放置最前,经常变化的参数追加在后面。
    • 个数。传进来的参数必须进行最小化处理,不需要的参数不需要额外传入,通过结构体封装也一样,如果一个结构体含有5个字段,但是我只用一个,那么我只需要接受一个字段的参数就行,没必要传这个结构体进来。如果是指针类型或者引用类型,虽然不会进行copy造成性能低下原因,但是会影响对该函数上下文的理解,同时还要清楚每一个字段是否有在上文进行赋值,如果没有的话直接调用可能会出现panic异常。
    • 修改。函数不能为简便实现某个功能就直接修改参数的值,函数内部不能直接修改结构体参数的值,否则后续查找问题就会很痛苦。
  • 功能。整个函数的功能实现结果上必须符合函数的命名,不能造成函数命名和函数实现原理不一致的情况,比如函数命名getInterestsByXXX的内部又根据某个条件进行过滤,这样就会导致函数功能和函数命名不统一。

  • 变量。在函数内部定义变量时,如果连续申明2个以及以上的变量,通过变量块来进行声明,这样会显示代码比较整洁。同时,为了考虑当前申明的变量很可能会向下个函数透传,所以命名必须要能体现该参数的含义,而不能通过通用的命名来命名,否则每次看下文都要追踪上文源码才知道该参数的含义。

  • 返回值。

    • 命名。函数或者方法返回值命名必须能够体现出返回的含义,这样调用者在一点进来源码时就能通过返回变量名就可以知道大概的含义,而不需要在一行一行追代码。
    • 个数。如果返回值有多个类型相同的返回值,则可以通过定义函数返回值变量来进行说明,同时在注释中也进行说明每个参数的含义是什么。通常error参数放在返回值的最后一个。
  • 异步。能用异步则尽量用异步,否则耗时会很长。要充分利用goroutine进行编码。

  • 函数长度。腾讯内部规范函数长度不能超过80行,但是IDEA默认函数不能超过60行。

4、逻辑.
  • 简洁性。减少圈复杂度,在处理函数逻辑上,要尽可能减少圈的复杂度,能合并则合并,如果不能合并则要考虑是否独立出来一个函数是否会比较好。并且要保证逻辑的简单性,能以最简单的方法实现就通过最简单的方法来实现。
  • 严谨性。考虑每一个分支可能出现的意外情况,要为未来进行编码,隐藏的BUG能否触发不能交给其他人来进行把控,而是应该自己把控。做每一个函数逻辑前都必须充分考虑该分支的意外情况,在正常思维逻辑思维内的代码很简单,很好处理,我们要处理的就是处理预期情况的代码,处理好每一个分支的逻辑。
  • 封装。在功能逻辑上将大函数拆分成几个小函数,同时,在函数层面,抽出来的函数应该是能够进行复用的函数,只要传参不同,那么就应该能进行复用。
  • 面向对象。充分考虑需求后期的扩展以及灵活性,充分利用面向对象思想以及设计模式(每次写代码前可以问下GPT当前功能可用的设计模式)。
5、实例.
  • 单例模式。通用对象(能够复用)应该实现单例模式。
  • 工厂模式。非同用类型对象,可以通过设置Tag通过工厂模式进行构建。
  • 其他。如果上面两种不适用,那么就应该提供New函数来进行构建。一个包下面应该只有一个New函数,如果一个New函数搞不定,那么就说明分包分的不对。
6、调用.
  • 方法调用。方法调用一般都是通过package.method()来进行调用,为了让调用显示的更加简洁,Method不应该包含包名,因为调用前就已经知道属于那个包了。
  • 函数调用。被调用的函数应该通过函数名字、参数、返回值、注释就能知道该函数内部做了什么逻辑,返回了什么值,而不需要调用者通过查看源码才知道该函数具体实现了什么逻辑。
7、收拢.
  • 收拢。代码都应该进行收拢,顶层代码慢慢收拢于底层代码,常量慢慢收拢于具体文件,上层代码复用底层代码。

欢迎关注公众号:社恐的小马同学。