干货|Golang Programming Style(上)

点击上方“中兴开发者社区”,关注我们

每天读一篇一线开发者原创好文

前言

本规范是针对 Golang 语言的编码规范,目的是为了统一项目的编码风格,提高软件源程序的可读性、可靠性和可重用性,提高软件源程序的质量和可维护性,减少软件维护成本。

本规范适用于部门所有产品的软件源程序,同时考虑到不同产品和项目的实际开发特性,本规范分成规则性和建议性两种:对于规则性规范,要求所有软件开发人员严格执行;对于建议性规范,各项目编程人员可以根据实际情况选择执行。本规范的示例都以Golang 语言描述。

本规范的内容包括:开发环境、包设计、布局、注释、命名、基本元素设计、函数设计、错误和异常设计、整洁测试等。

本规范自生效日起,对以后新编写的和修改的代码有约束力。

对本规范中所用的术语解释如下:
原则:编程时应该坚持的指导思想。
规则:编程时必须遵守的约定。
建议:编程时必须加以考虑的约定。
说明:对此规则或建议的必要的解释。
正例:对此规则或建议给出的正确例子。
反例:对此规则或建议给出的反面例子。

开发环境

【规则1-1】为了防止代码出现可移植性问题和兼容性问题,团队使用的操作系统、编译器类型、版本保持一致性。


【规则1-2】团队统一使用相同的IDE,并使用统一的代码模板,保持代码风格的一致性。


 说明:系统中所有的代码看起来就好像是由单独一个值得胜任的人编写的。

【规则1-3】团队统一配置 IDE 的 TAB 为4个空格。

 

包设计

【原则2-1】包设计要满足单一职责原则。

 说明: 这是SRP(Single Reponsibility Priciple) 在包(package)设计时的一个具体运用,我们要将包设计的非常内聚,包间的 API 比较少(类似于class中的public方法)。

【原则2-2】包内标识符遵守最小可见性原则。

说明: 如果一个标识符(interface名、类型名、变量名或函数名)在语义上仅在包内可见,则它的命名不要用大写开头。

【规则2-1】测试文件放在实现文件的同级目录下,便于Golang工具的使用。

 说明: 虽然测试文件和实现文件的代码在同一个包内,但是测试用例的设计尽量站在包用户的角度去考虑,一般只测试包外可见的函数。

【规则2-2】包间禁止共享全局变量。

 **说明:常量除外

【规则2-3】 不允许一个目录下有多个包。

【规则2-4】 import包时不允许使用点(.)操作。

 

正例:

反例:

**说明:测试文件中的测试框架除外

【规则2-5】 import包时不允许使用别名。


正例:

反例:

【规则2-6】 import包时不允许使用下划线(_)操作。

说明:下划线(_)操作的含义是:导入该包,但不导入整个包,而是执行该包中的init函数,因此无法通过包名来调用包中的其他函数。使用下划线(_)操作往往是为了注册包里的引擎,让外部可以方便地使用。


正例:

反例:

注:反例中的time包仅为冗余的包,并不是为了注册引擎,同时我们的产品代码中,也没有隐式注册引擎的需求,所以我们在import包时统一不允许使用下划线(_)操作。

 

布局

**【规则3-1】import 导入包时统一使用小括号,包名要另起一行 **

**说明:import "C" 除外

 正例:

**【规则3-2】import 包时,路径分隔符一律使用Unix 风格,拒绝使用Windows 风格;即采用/ 而不是使用\ 分割路径。
**

正例:

反例:

**【规则3-3】import 包时以 $GOPATH 为基准使用绝对路径,不要从当前位置开始使用相对路径 **


正例:

反例:

**【规则3-4】包含空格在内,代码的行宽不应超过120列。 **
说明: 长行要在低优先级操作符处拆分成新行,拆分出的新行要进行适当的缩进,使排版整齐。

 【规则3-5】程序实体之间有且仅有一行空行区分。

说明: 函数之间的空行,能够帮组我们快速定位函数的始末的准确位置;甚至在函数内部,将逻辑相关的代码放在一起也同样具有意义,它能够帮组我们更好地理解代码块的语义。超过一行的空行完全没有必要,部分粗心的程序员在处理这些细节时总存在着或多或少的问题,团队应该杜绝这样的情况发生。

 【规则3-6】每个文件末尾都应该有且仅有一行空行。

 【规则3-7】一元操作符如“!”、“~”、“++”、“--”、 “”、 “&”(地址运算符)等前后不加空格; “[]”、“.”、“->”这类操作符前后不加空格。*

 【规则3-8】函数名之后不要留空格

说明: 函数名后紧跟左括号‘(’,以与关键字区别。


正例:

反例:【规则3-9】在进行“==”或“!="比较时,将常量或常数放在“==”或“!="号的右边。

正例:

反例:【规则3-10】 数组的初始化按照矩阵结构分行书写。

正例:

【建议3-1】 每写完一段代码,就使用gofmt工具格式化一下。

 

注释

注释有助于理解代码,有效的注释是指在代码的功能、意图层次上进行注释,提供有用、额外的信息,而不是代码表面意义的简单重复。

注释的恰当用法是弥补我们在用代码表达意图时遭遇的失败。每次写注释,你都应该做个鬼脸,感受自己在表达能力上的失败。

写注释时,首先想到的应该是通过重构来提高表达力,不要太早放弃。 

 

【规则4-1】注释与所描述内容进行同样的缩进。
说明: 可使程序排版整齐,并方便注释的阅读与理解。

【规则4-2】避免垃圾注释。

说明: 对于代码本身能够表达的意思,不必增加额外的注释。

【规则4-3】注释符 “//” 或 "/*” (“/”) 与注释内容之间用一个空格分隔。*

【建议4-1】并非所有的函数都要配有函数头,短函数需要一个好名字而非太多描述。

【建议4-2】提倡代码自注释。

说明: 能用函数或变量时就不要用注释,如果可以的话,应该创建一个描述与注释所言同一事物的函数或变量用于消除注释。

【建议4-3】行注释和块注释都可行时,优先使用行注释。

【建议4-4】保证代码和注释的一致性。

 说明: 修改代码同时修改相应的注释,不再有用的注释要删除。

【建议4-5】注释应与其描述的代码相近,对代码的注释应放在其上方或右方(对单条语句的注释)相邻位置,不可放在下面,如放于上方则需与其上面的代码用空行隔开,而且注释内容与与被注释的代码相同缩进。

 

命名

 

【规则5-1】命名要名副其实——要像给自己的baby 起名字一样谨慎来对待程序命名。

说明: 变量、函数的命名告诉我们,它为什么会存在,它做什么事,应该怎么用。如果名称需要注释来补充,那就不算是名副其实。要像给自己的baby 起名字一样谨慎来对待程序命名。

【规则5-2】目录名一律使用小写和中划线风格的名称。

 

正例:

knitter-agent

 

反例:

knitteragent

knitter_agent

KnitterAgent

knitterAgent

 

【规则5-3】 包名一律使用小写风格,通常为过滤掉中划线的目录名。

 

正例1

目录名:context

对应的包名:context

 

正例2

目录名:port-obj

对应的包名:portobj

 

【规则5-4】 开发文件命名一律使用小写和下划线风格的名称。

 

正例:

knitter_virtual_machine.go

 

反例:

knitter-virtual-machine.go

KnitterVirtualMachine.go

knittervirtualmachine.go

 

【规则5-5】标识符要采用英文单词或其组合,便于记忆和阅读,切忌使用汉语拼音来命名。

 

说明: 标识符应当直观且可以拼读,可望文知义,避免使人产生误解。程序中的英文单词一

般不要太复杂,用词应当准确。

 

【规则5-6】如果函数返回值的类型或变量的类型为bool,则名字前面加上is, has, may, can, should, need等词修饰会增强语意。

 

正例:

反例:

【规则5-7】接口名、类型名、变量名和函数名统一使用驼峰命名法,首字母是否大写由包外可见性决定。
说明: 应遵循最小可见性原则

【规则5-8】避免在名称中携带类型信息。


正例:

反例:


【规则5-9】避免在名称中携带作用域的信息。


正例:

反例:

【规则5-10】 变量名的主体应当使用“名词”或者“形容词+名词”。

【规则5-11】 函数名应当使用“动词”或者“动词+名词”(动宾词组)。

【规则5-12】 系统中每个实体概念对应一个词。

 

说明: 给每个抽象概念选一个词,并且在同一个系统中统一,以便符合SRP 原则。如在同一系统的代码中既有controller,还有manager 和driver,会令使用者困惑,应统一。

 

【规则5-13】 不使用双关语命名变量。

 

说明: 变量命名时应避免将同一单词用于不同目的,同一术语用于不同概念,应遵从“一词一义”规则。比如add在表达计算两个值的和的语义时,就不能再表达往一个数组切片插入一个元素的语义。

 

【规则5-14】 常量名使用驼峰命名法,首字母是否大写由包外可见性决定。
说明: 应遵循最小可见性原则

 

【规则5-15】 团队使用统一的缩略语,并和业界常用的缩略语保持一致。

 

说明: 较短的单词可通过去掉“元音”形成缩写,较长的单词可取单词的头几个字母形成缩写,一些单词有大家公认的缩写,常用单词的缩写必须统一。协议中的单词的缩写与协议保持一致。对于某个系统使用的专用缩写应该在某处注释中做统一说明。

 

正例: 如下单词的缩写能够被大家认可

temp 可缩写为:tmp

flag 可缩写为:flg

statistic 可缩写为:stat

increment 可缩写为:inc

message可缩写为:msg

 

规范的常用缩写如下:

 

常用词 | 缩写 | 常用词 | 缩写

----|----

Argument | Arg | Buffer | Buf

Clear | Clr | Clock | Clk

Compare | Cmp | Configuration | Cfg

Context | Ctx | Delay | Dly

Device | Dev | Disable | Dis

Display | Disp | Enable | En

Error | Err | Function | Fnct

Hexadecimal | Hex | High Priority Task | HPT

I/O System | IOS | Initialize | Init

Mailbox | Mbox | Manager | Mgr

Maximum | Max | Message | Msg

Minimum | Min | Multiplex | Mux

Operating System | OS | Overflow | Ovf

Parameter | Param | Pointer | Ptr

Previous | Prev | Priority | Prio

Read | Rd | Ready | Rdy

Register | Reg | Request | Req

Response | Rsp | Schedule | Sched

Semaphore | Sem | Stack | Stk

Synchronize | Sync | Timer | Tmr

Trigger | Trig | Write | Wr

 

【规则5-16】 用正确的反义词组命名具有互斥意义的变量或相反动作的函数等。

 

正例:

基本元素设计

变量与常量

 

【规则6-1-1】 一个变量有且只有一个功能,并与其名称相一致,不能把一个变量用作多种用途。

 说明: 一个变量只用来表示一个特定功能,不能把一个变量用作多种用途,即同一变量取值不同时,其代表的意义也不同。除循环变量和收集计算结果的变量,在一个函数中,一个变量被赋值不应该超过一次。

【规则6-1-2】 代码中不允许出现魔法数。

 说明: 魔法数,即拥有特殊意义,却又不能明确表现出这种意义的数字。用const来定义常数,并根据其意义为它命名,既提高了代码的可读性,又便于使用IDE 等工具进行查找修改。

【规则6-1-3】 如果 struct 中的数据变量需要进行 json 序列化,则需要以大写字母开头,同时需要 json 重命名。

 说明: 结构体中的变量以大写字母开头,可以保证 json.Marshal 的时候数据持久化正确。如果结构体中的变量以小写字母开头,则使得 json.Marshal 的时候忽略该字段,使得该字段的值丢失,从而 json.Unmarshal 的时候将该变量的值置为默认值。由于结构体中的变量以大写字母开头, json 串中的字段 key 的字符串形式变成了以大写字母开始,这对于追求以 json 串全小写为美的我们来说,需要进行  json 重命名。

 

正例:

反例:

【建议6-1-1】 变量应尽可能的满足短跨度和短存活时间。

 

说明: 那些介于同一个变量多个引用点之间的代码可称为攻击窗口,我们用跨度来衡量一个变量的不同引用点之间的靠近程度,而变量的存活时间是一个变量存在期间所跨越的语句总数。跨度越短,则表明一个变量的不同引用点越靠近;存活时间越短,则表明一个变量经历的语句数越少。

 

我们追求的目标是短跨度和短存活时间,因为

(1)可以提高程序的可读性;

(2)可以减小变量的攻击窗口;

(3)可以减少变量的初始化错误;

(4)可以减少全局变量的使用;

(5)可以方便修改Bug;

(6)可以方便重构代码。


扩展阅读

干货|GoMock框架使用指南

干货|GoStub框架二次开发实践

干货|GoConvey框架使用指南

干货丨Golang事务模型


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值