Repository: unknwon/go-code-convention
Branch: main
Commit: 51ad51df2dd0
Files: 12
Total size: 30.4 KB
Directory structure:
gitextract_0skmej70/
├── LICENSE
├── README.md
├── en-US.md
└── zh-CN/
├── README.md
├── coding_guidelines.md
├── commentary.md
├── copyright.md
├── declaration.md
├── import_packages.md
├── naming_rules.md
├── project_structure.md
└── test_case.md
================================================
FILE CONTENTS
================================================
================================================
FILE: LICENSE
================================================
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org>
================================================
FILE: README.md
================================================
# Go Code Convention
This is a 100% opinionated and paranoid code convention for the Go Programming Language by [@unknwon](https://github.com/unknwon). It may or may not be compatible with [Go Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments), or any other guidelines out there. That's fine, that is neither mine nor your problem.

Be sure to always remember, "尽信书不如无书".
For non-Chinese readers, [what does 尽信书不如无书 mean?](https://chinese.stackexchange.com/a/26717)
<br>
Ready? OK, pick one you like:
- [English](en-US.md)
- [简体中文](zh-CN/README.md) _Stay tuned!_
## Roadmap for current version
- [x] Overhaul exsiting content for en-US
- [ ] Add more pages about:
- [x] Linting
- [ ] Database layer construction and testing
- [ ] Error wrapping
- [ ] Dependency injection
- [ ] TBD
- [ ] Re-translated everything from en-US to zh-CN
## Notes about v1
The [v1](https://github.com/unknwon/go-code-convention/tree/v1) was originally drafted back in 2015, and majority of the content hasn't been updated since. As of 2021, after another 6 years working with Go, some of aspects already feel outdated for me, especially I've learned more practices by working with amazing people. I would love to have these practices documented so I can reference back.
## License
This project is under the Unlicense License. See the [LICENSE](LICENSE) file for the full license text.
================================================
FILE: en-US.md
================================================
# Go Code Convention
## Copyright
For any open source project, there must be a LICENSE file in the repository root to claim the rights.
Here are two examples of using [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) and MIT License.
### Apache License, Version 2.0
This license requires to put following content at the beginning of every file:
```
// Copyright [yyyy] [name of copyright owner]
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
```
Replace `[yyyy]` with the creation year of the file. Then use personal name for personal projects, or organization name for team projects to replace `[name of copyright owner]`.
### MIT License
This license requires to put following content at the beginning of every file:
```
// Copyright [yyyy] [name of copyright owner]. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
```
Replace `[yyyy]` with the creation year of the file.
### Other notes
- Other types of license can follow the template of above two examples.
- If a file has been modified by different individuals and/or organizations, and multiple licenses are compatiable, then change the first line to multiple lines and sort them in the order of time:
```
// Copyright 2011 Gary Burd
// Copyright 2013 Unknwon
```
- Spefify which license is used for the project in bottom of the README file:
```
## License
This project is under the MIT License. See the [LICENSE](LICENSE) file for the full license text.
```
## Project structure
For server-side services and CLI applications, they generally follow the same style of project structure as follows:
```
.bin/ # The directory to put all locally compiled binaries, should be ignored by .gitignore
.github/ # GitHub specific configuration
assets/ # Static resources, including those to be embeded into binaries
migrations/ # Files for database schema migrations
templates/ # Template files for rendering HTML pages
embed.go # The main file to tell Go toolchain to embed resources
cmd/ # All "main" packages which produce binaries should be placed under this directory
<logan smith>/
main.go # The entry point of a main package
data/ # Application generated data
dev/ # Scripts for enhancing quality-of-life of development
docs/ # Project specific documentation
internal/ # Common packages, "internal" is also a keyword to prevent other projects to import in Go
conf/ # Read and/or write application configuration
db/ # Database layer
route/ # Routing layer
log/ # Appication generated logs
.golangci.yml # Custom configuration for golangci-lint
```
### Example `embed.go`
The following shows an example of embeding database schema migrations using Go 1.16 [embed](https://blog.carlmjohnson.net/post/2021/how-to-use-go-embed/):
```go
package assets
import (
"embed"
)
//go:embed migrations/*.sql
var Migrations embed.FS
```
## Import packages
All package import paths must be valid Go Modules path except packages from standard library.
Generally, there are four types of packages a source file could import:
1. Packages from standard library
2. Third-party packages
3. Packages in the same organization but not in the same repository
4. Packages in the same repository
Basic rules:
- Use different groups to separate import paths by an blank line for two or more types of packages.
- Must not use `.` to simplify import path except in test files (`*_test.go`).
- Must not use relative path (`./subpackage`) as import path.
Here is a concrete example:
```go
import (
"fmt"
"html/template"
"net/http"
"os"
"github.com/urfave/cli"
"gopkg.in/macaron.v1"
"github.com/gogs/git-module"
"github.com/gogs/gogs/internal/route"
"github.com/gogs/gogs/internal/route/repo"
"github.com/gogs/gogs/internal/route/user"
)
```
## Commentary
- All exported objects must be well-commented; internal objects can be commented when needed.
- If the object is countable and does not know the number of it, use singular form and present tense; otherwise, use plural form.
- Comment of package, function, method and type must be a complete sentence (i.e. capitalize the first letter and end with a period).
- Maximum length of a comment line should be 80 characters.
### Package
- Only one file is needed for package-level comment.
- For `main` packages, a line of introduction is enough, and should start with the binary name:
```Go
// Gogs is a painless self-hosted Git Service.
package main
```
- For sub-packages of a complex project, no package level comment is required unless it's a functional module.
- For simple non-`main` packages, a line of introduction is enough as well.
- For more complex functional non-`main` packages, comment should have some basic usage examples and must start with `Package <name>`:
```Go
/*
Package regexp implements a simple library for regular expressions.
The syntax of the regular expressions accepted is:
regexp:
concatenation { '|' concatenation }
concatenation:
{ closure }
closure:
term [ '*' | '+' | '?' ]
term:
'^'
'$'
'.'
character
'[' [ '^' ] character-ranges ']'
'(' regexp ')'
*/
package regexp
```
- When few paragraphs cannot explain the package well, you should create a [`doc.go`](https://github.com/robfig/cron/blob/master/doc.go) file for it.
### Struct and interface
- Type is often described in singular form, and the comment should state what it actuall does:
```Go
// Request represents a request to run a command.
type Request struct { ...
```
- Interface should be described as follows, and the comment should state what implementations should be doing:
```Go
// FileInfo is the interface that describes a file and is returned by Stat and Lstat.
type FileInfo interface { ...
```
### Functions and methods
- Comments of functions and methods must start with its name:
```Go
// Post returns *BeegoHttpRequest with POST method.
```
- If one sentence is not enough, go to next line:
```Go
// Copy copies file from source to target path.
// It returns false and error when error occurs in underlying function calls.
```
- If the main purpose of a function or method is returning a `bool` value, its comment should start with `<name> returns true if`:
```Go
// HasPrefix returns true if name has any string in given slice as prefix.
func HasPrefix(name string, prefixes []string) bool { ...
```
### Other notes
- When something is waiting to be done, use comment starts with `TODO:` to remind maintainers.
- When a known problem/issue/bug needs to be fixed/improved, use comment starts with `FIXME:` to remind maintainers.
- When something is too magic and needs to be explained, use comment starts with `NOTE:`:
```Go
// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
// which will lead "no such file or directory" error.
return os.Symlink(target, dest)
```
- When dealing with security-related logic, use comment starts with `SECURITY:`
- When something important but is easy to overlook, use comment starts with `WARNING:`
- When the object is deprecated, use comment starts with `DEPRECATED:`:
```go
// Email returns the user's oldest email, if one exists.
// Deprecated: use Emails instead.
func (r *UserResolver) Email(ctx context.Context) (string, error) {
```
## Naming rules
### Directories
- Do not use underscores (`_`) in directory names, use hyphens (`-`) instead.
### Files
- Do not use hyphens (`-`) in file names, use underscores (`_`) instead.
- The file contains the entry point of the application or package should be named as `main.go` or same as the package.
### Functions and methods
- If the main purpose of the function or method is returning a `bool` type value, the name of function or method should starts with `Has`, `Is`, `Can` or `Allow`, etc.
```go
func HasPrefix(name string, prefixes []string) bool { ... }
func IsEntry(name string, entries []string) bool { ... }
func CanManage(name string) bool { ... }
func AllowGitHook() bool { ... }
```
### Constants
- Constant should use camel cases except for coined terms and brand names (see later):
```go
const appVersion = "0.13.0+dev"
```
- If you need enumerated type, you should define the corresponding type first:
```go
type Scheme string
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
)
```
- If functionality of the module is relatively complicated and easy to mixed up with constant name, you can add prefix to every constant for the enumerated type:
```go
type PullRequestStatus int
const (
PullRequestStatusConflict PullRequestStatus = iota
PullRequestStatusChecking
PullRequestStatusMergable
)
```
### Variables
- A variable name should follow general English expression or shorthand.
- In relatively simple (less objects and more specific) context, variable name can use simplified form as follows:
- `userID` to `uid`
- `repository` to `repo`
- If variable type is `bool`, its name should start with `Has`, `Is`, `Can` or `Allow`, etc.
```go
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
```
- Same rules also apply for defining structs:
```go
// Webhook represents a web hook object.
type Webhook struct {
ID int64
RepoID int64
OrgID int64
URL string
ContentType HookContentType
Secret string
Events string
*HookEvent
IsSSL bool
IsActive bool
HookTaskType HookTaskType
Meta string
LastStatus HookStatus
CreatedAt time.Time
UpdatedAt time.Time
}
```
### Coined terms and brand names
When you encounter coined terms and brand names, naming should respect the original or the most widely accepted form for the letter case. For example, use "GitHub" not "Github", use "API" not "Api", use "ID" not "Id".
When the coined term and brand name is the first word in a variable or constant name, keep them having the same case. For example, `apiClient`, `SSLCertificate`, `githubClient`.
Here is a list of words which are commonly identified as coined terms:
```go
// A GonicMapper that contains a list of common initialisms taken from golang/lint
var LintGonicMapper = GonicMapper{
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SSH": true,
"TLS": true,
"TTL": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XSRF": true,
"XSS": true,
}
```
## Declarations
### Functions or methods
Order of arguments of functions or methods should generally apply following rules (from left to right):
1. More important to less important.
2. Simpler types to more complicated types.
3. Same types should be put together whenever possible.
#### Example
In the following declaration, type `User` is more complicated than type `string`, but `Repository` belongs to `User` (which makes the `user` argument more important), so `user` is more left than `repoName`:
```Go
func IsRepositoryExist(user *User, repoName string) (bool, error) { ...
```
## Coding guidelines
- Do not initialize structs with unnamed fields and do break fields into multiple lines:
```go
func main() {
...
awsCloudwatchLogsLogGroup := os.Getenv("AWS_CLOUDWATCH_LOGS_LOG_GROUP")
if awsCloudwatchLogsLogGroup != "" {
client := awsutil.NewDefaultClient()
err := log.New(
"cloudwatchlogs",
awsutil.CloudWatchLogsIniter(),
1000,
awsutil.CloudWatchLogsConfig{ // <---- Focus here
Level: log.LevelInfo,
Client: client.NewCloudWatchLogsClient(),
LogGroupName: awsCloudwatchLogsLogGroup,
LogStreamPrefix: awsCloudwatchLogsLogGroup + "-stream",
Retention: 30,
MaxRetries: 3,
},
)
if err != nil {
log.Fatal("Failed to init cloudwatchlogs logger: %v", err)
}
}
...
}
```
- Group declaration should be organized by types, not all together:
```go
const (
// Default section name.
DefaultSection = "DEFAULT"
// Maximum allowed depth when recursively substituing variable names.
depthValues = 200
)
type ParseError int
const (
ErrSectionNotFound ParseError = iota + 1
ErrKeyNotFound
ErrBlankSectionName
ErrCouldNotParse
)
```
- Functions or methods are ordered by the dependency relationship, such that the most dependent function or method should be at the top. In the following example, `ExecCmdDirBytes` is the most fundamental function, it's called by `ExecCmdDir`, and `ExecCmdDir` is also called by `ExecCmd`:
```go
// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
...
}
// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
return string(bufOut), string(bufErr), err
}
// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
return ExecCmdDir("", cmdName, args...)
}
```
- Methods of struct should be put after struct definition, and order them by the order of fields they mostly operate on:
```go
type Webhook struct { ... }
func (w *Webhook) GetEvent() { ... }
func (w *Webhook) SaveEvent() error { ... }
func (w *Webhook) HasPushEvent() bool { ... }
```
- If a struct has operational functions, should basically follow the `CRUD` order:
```go
func CreateWebhook(w *Webhook) error { ... }
func GetWebhookById(hookId int64) (*Webhook, error) { ... }
func UpdateWebhook(w *Webhook) error { ... }
func DeleteWebhook(hookId int64) error { ... }
```
- If a struct has functions or methods start with `Has`, `Is`, `Can` or `Allow`, they should be ordered by the same order of `Has`, `Is`, `Can` or `Allow`.
- Declaration of variables should be put before corresponding functions or methods:
```go
var CmdDump = cli.Command{
Name: "dump",
...
Action: runDump,
Flags: []cli.Flag{},
}
func runDump(*cli.Context) { ...
```
## Testing
- Unit tests must use [github.com/stretchr/testify](https://github.com/stretchr/testify) and code coverage must above 80%.
### Examples
- The file of examples of helper modules should be named as `example_test.go`.
- Test cases of functions must start with `Test`, e.g. `TestLogger`.
- Test cases of methods must use format `Text<Struct>_<Method>`, e.g. `TestMacaron_Run`.
## Linting
**Warnings will be ignored in practice**, CI should either fail or pass on linting, anything that is not failing the CI should be removed.
Here is the best practice for configuring `.golangci.yml`:
```yml
linters-settings:
nakedret:
max-func-lines: 0 # Disallow any unnamed return statement
linters:
enable:
- deadcode
- errcheck
- gosimple
- govet
- ineffassign
- staticcheck
- structcheck
- typecheck
- unused
- varcheck
- nakedret
- gofmt
- rowserrcheck
- unconvert
- goimports
```
================================================
FILE: zh-CN/README.md
================================================
# 规范索引
- [版权声明](copyright.md)
- [项目结构](project_structure.md)
- [导入标准库、第三方或其它包](import_packages.md)
- [注释规范](commentary.md)
- [命名规则](naming_rules.md)
- [声明语句](declaration.md)
- [代码指导](coding_guidelines.md)
- [测试用例](test_case.md)
================================================
FILE: zh-CN/coding_guidelines.md
================================================
# 代码指导
### 基本约束
- 所有应用的 `main` 包需要有 `APP_VER` 常量表示版本,格式为 `X.Y.Z.Date [Status]`,例如:`0.7.6.1112 Beta`。
- 单独的库需要有函数 `Version` 返回库版本号的字符串,格式为 `X.Y.Z[.Date]`。
- 当单行代码超过 80 个字符时,就要考虑分行。分行的规则是以参数为单位将从较长的参数开始换行,以此类推直到每行长度合适:
```go
So(z.ExtractTo(
path.Join(os.TempDir(), "testdata/test2"),
"dir/", "dir/bar", "readonly"), ShouldBeNil)
```
- 当单行声明语句超过 80 个字符时,就要考虑分行。分行的规则是将参数按类型分组,紧接着的声明语句的是一个空行,以便和函数体区别:
```go
// NewNode initializes and returns a new Node representation.
func NewNode(
importPath, downloadUrl string,
tp RevisionType, val string,
isGetDeps bool) *Node {
n := &Node{
Pkg: Pkg{
ImportPath: importPath,
RootPath: GetRootPath(importPath),
Type: tp,
Value: val,
},
DownloadURL: downloadUrl,
IsGetDeps: isGetDeps,
}
n.InstallPath = path.Join(setting.InstallRepoPath, n.RootPath) + n.ValSuffix()
return n
}
```
- 分组声明一般需要按照功能来区分,而不是将所有类型都分在一组:
```go
const (
// Default section name.
DEFAULT_SECTION = "DEFAULT"
// Maximum allowed depth when recursively substituing variable names.
_DEPTH_VALUES = 200
)
type ParseError int
const (
ERR_SECTION_NOT_FOUND ParseError = iota + 1
ERR_KEY_NOT_FOUND
ERR_BLANK_SECTION_NAME
ERR_COULD_NOT_PARSE
)
```
- 当一个源文件中存在多个相对独立的部分时,为方便区分,需使用由 [ASCII Generator](http://www.network-science.de/ascii/) 提供的句型字符标注(示例:`Comment`):
```go
// _________ __
// \_ ___ \ ____ _____ _____ ____ _____/ |_
// / \ \/ / _ \ / \ / \_/ __ \ / \ __\
// \ \___( <_> ) Y Y \ Y Y \ ___/| | \ |
// \______ /\____/|__|_| /__|_| /\___ >___| /__|
// \/ \/ \/ \/ \/
```
- 函数或方法的顺序一般需要按照依赖关系由浅入深由上至下排序,即最底层的函数出现在最前面。例如,下方的代码,函数 `ExecCmdDirBytes` 属于最底层的函数,它被 `ExecCmdDir` 函数调用,而 `ExecCmdDir` 又被 `ExecCmd` 调用:
```go
// ExecCmdDirBytes executes system command in given directory
// and return stdout, stderr in bytes type, along with possible error.
func ExecCmdDirBytes(dir, cmdName string, args ...string) ([]byte, []byte, error) {
...
}
// ExecCmdDir executes system command in given directory
// and return stdout, stderr in string type, along with possible error.
func ExecCmdDir(dir, cmdName string, args ...string) (string, string, error) {
bufOut, bufErr, err := ExecCmdDirBytes(dir, cmdName, args...)
return string(bufOut), string(bufErr), err
}
// ExecCmd executes system command
// and return stdout, stderr in string type, along with possible error.
func ExecCmd(cmdName string, args ...string) (string, string, error) {
return ExecCmdDir("", cmdName, args...)
}
```
- 结构附带的方法应置于结构定义之后,按照所对应操作的字段顺序摆放方法:
```go
type Webhook struct { ... }
func (w *Webhook) GetEvent() { ... }
func (w *Webhook) SaveEvent() error { ... }
func (w *Webhook) HasPushEvent() bool { ... }
```
- 如果一个结构拥有对应操作函数,大体上按照 `CRUD` 的顺序放置结构定义之后:
```go
func CreateWebhook(w *Webhook) error { ... }
func GetWebhookById(hookId int64) (*Webhook, error) { ... }
func UpdateWebhook(w *Webhook) error { ... }
func DeleteWebhook(hookId int64) error { ... }
```
- 如果一个结构拥有以 `Has`、`Is`、`Can` 或 `Allow` 开头的函数或方法,则应将它们至于所有其它函数及方法之前;这些函数或方法以 `Has`、`Is`、`Can`、`Allow` 的顺序排序。
- 变量的定义要放置在相关函数之前:
```go
var CmdDump = cli.Command{
Name: "dump",
...
Action: runDump,
Flags: []cli.Flag{},
}
func runDump(*cli.Context) { ...
```
- 在初始化结构时,尽可能使用一一对应方式:
```go
AddHookTask(&HookTask{
Type: HTT_WEBHOOK,
Url: w.Url,
Payload: p,
ContentType: w.ContentType,
IsSsl: w.IsSsl,
})
```
================================================
FILE: zh-CN/commentary.md
================================================
# 注释规范
- 所有导出对象都需要注释说明其用途;非导出对象根据情况进行注释。
- 如果对象可数且无明确指定数量的情况下,一律使用单数形式和一般进行时描述;否则使用复数形式。
- 包、函数、方法和类型的注释说明都是一个完整的句子。
- 句子类型的注释首字母均需大写;短语类型的注释首字母需小写。
- 注释的单行长度不能超过 80 个字符。
### 包级别
- 包级别的注释就是对包的介绍,只需在同个包的任一源文件中说明即可有效。
- 对于 `main` 包,一般只有一行简短的注释用以说明包的用途,且以项目名称开头:
```Go
// Gogs (Go Git Service) is a painless self-hosted Git Service.
package main
```
- 对于一个复杂项目的子包,一般情况下不需要包级别注释,除非是代表某个特定功能的模块。
- 对于简单的非 `main` 包,也可用一行注释概括。
- 对于相对功能复杂的非 `main` 包,一般都会增加一些使用示例或基本说明,且以 `Package <name>` 开头:
```Go
/*
Package regexp implements a simple library for regular expressions.
The syntax of the regular expressions accepted is:
regexp:
concatenation { '|' concatenation }
concatenation:
{ closure }
closure:
term [ '*' | '+' | '?' ]
term:
'^'
'$'
'.'
character
'[' [ '^' ] character-ranges ']'
'(' regexp ')'
*/
package regexp
```
- 特别复杂的包说明,可单独创建 [`doc.go`](https://github.com/robfig/cron/blob/master/doc.go) 文件来加以说明。
### 结构、接口及其它类型
- 类型的定义一般都以单数形式描述:
```Go
// Request represents a request to run a command.
type Request struct { ...
```
- 如果为接口,则一般以以下形式描述:
```Go
// FileInfo is the interface that describes a file and is returned by Stat and Lstat.
type FileInfo interface { ...
```
### 函数与方法
- 函数与方法的注释需以函数或方法的名称作为开头:
```Go
// Post returns *BeegoHttpRequest with POST method.
```
- 如果一句话不足以说明全部问题,则可换行继续进行更加细致的描述:
```Go
// Copy copies file from source to target path.
// It returns false and error when error occurs in underlying function calls.
```
- 若函数或方法为判断类型(返回值主要为 `bool` 类型),则以 `<name> returns true if` 开头:
```Go
// HasPrefix returns true if name has any string in given slice as prefix.
func HasPrefix(name string, prefixes []string) bool { ...
```
### 其它说明
- 当某个部分等待完成时,可用 `TODO:` 开头的注释来提醒维护人员。
- 当某个部分存在已知问题进行需要修复或改进时,可用 `FIXME:` 开头的注释来提醒维护人员。
- 当需要特别说明某个问题时,可用 `NOTE:` 开头的注释:
```Go
// NOTE: os.Chmod and os.Chtimes don't recognize symbolic link,
// which will lead "no such file or directory" error.
return os.Symlink(target, dest)
```
================================================
FILE: zh-CN/copyright.md
================================================
# 版权声明
作为开源项目,必须有相应的开源许可证才能算是真正的开源。在选择了一个开源许可证之后,需要在源文件中进行相应的版权声明才能生效。以下分别以 [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) 和 MIT 授权许可为例。
### Apache License, Version 2.0
该许可证要求在所有的源文件中的头部放置以下内容才能算协议对该文件有效:
```
// Copyright [yyyy] [name of copyright owner]
//
// Licensed under the Apache License, Version 2.0 (the "License"): you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
```
其中,`[yyyy]` 表示该源文件创建的年份。紧随其后的是 `[name of copyright owner]`,即版权所有者。如果为个人项目,就写个人名称;若为团队项目,则宜写团队名称。
### MIT License
一般使用 MIT 授权的项目,需在源文件头部增加以下内容:
```
// Copyright [yyyy] [name of copyright owner]. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
```
其中,年份和版权所有者的名称填写规则与 Apache License, Version 2.0 的一样。
### 其它说明
- 其它类型的开源许可证基本上都可参照以上两种方案。
- 如果存在不同作者或组织对同个源文件的修改,在协议兼容的情况下,可将首行变为多行,按照先后次序排放:
```
// Copyright 2011 Gary Burd
// Copyright 2013 Unknwon
```
- 在 README 文件最后中需要说明项目所采用的开源许可证:
```
## 授权许可
本项目采用 MIT 开源授权许可证,完整的授权说明已放置在 [LICENSE](LICENSE) 文件中。
```
================================================
FILE: zh-CN/declaration.md
================================================
# 声明语句
### 函数或方法
函数或方法的参数排列顺序遵循以下几点原则(从左到右):
1. 参数的重要程度与逻辑顺序
2. 简单类型优先于复杂类型
3. 尽可能将同种类型的参数放在相邻位置,则只需写一次类型
#### 示例
以下声明语句,`User` 类型要复杂于 `string` 类型,但由于 `Repository` 是 `User` 的附属品,首先确定 `User` 才能继而确定 `Repository`。因此,`User` 的顺序要优先于 `repoName`。
```Go
func IsRepositoryExist(user *User, repoName string) (bool, error) { ...
```
================================================
FILE: zh-CN/import_packages.md
================================================
# 导入标准库、第三方或其它包
除标准库外,Go 语言的导入路径基本上依赖代码托管平台上的 URL 路径,因此一个源文件需要导入的包有 4 种分类:标准库、第三方包、组织内其它包和当前包的子包。
基本规则:
- 如果同时存在 2 种及以上,则需要使用分组来导入。每个分类使用一个分组,采用空行作为分区之间的分割。
- 在非测试文件(`*_test.go`)中,禁止使用 `.` 来简化导入包的对象调用。
- 禁止使用相对路径导入(`./subpackage`),所有导入路径必须符合 `go get` 标准。
下面是一个完整的示例:
```Go
import (
"fmt"
"html/template"
"net/http"
"os"
"github.com/codegangsta/cli"
"gopkg.in/macaron.v1"
"github.com/gogits/git"
"github.com/gogits/gfm"
"github.com/gogits/gogs/routers"
"github.com/gogits/gogs/routers/repo"
"github.com/gogits/gogs/routers/user"
)
```
================================================
FILE: zh-CN/naming_rules.md
================================================
# 命名规则
### 文件名
- 整个应用或包的主入口文件应当是 `main.go` 或与应用名称简写相同。例如:`Gogs` 的主入口文件名为 `gogs.go`。
### 函数或方法
- 若函数或方法为判断类型(返回值主要为 `bool` 类型),则名称应以 `Has`, `Is`, `Can` 或 `Allow` 等判断性动词开头:
```go
func HasPrefix(name string, prefixes []string) bool { ... }
func IsEntry(name string, entries []string) bool { ... }
func CanManage(name string) bool { ... }
func AllowGitHook() bool { ... }
```
### 常量
- 常量均需使用全部大写字母组成,并使用下划线分词:
```go
const APP_VER = "0.7.0.1110 Beta"
```
- 如果是枚举类型的常量,需要先创建相应类型:
```go
type Scheme string
const (
HTTP Scheme = "http"
HTTPS Scheme = "https"
)
```
- 如果模块的功能较为复杂、常量名称容易混淆的情况下,为了更好地区分枚举类型,可以使用完整的前缀:
```go
type PullRequestStatus int
const (
PULL_REQUEST_STATUS_CONFLICT PullRequestStatus = iota
PULL_REQUEST_STATUS_CHECKING
PULL_REQUEST_STATUS_MERGEABLE
)
```
### 变量
- 变量命名基本上遵循相应的英文表达或简写。
- 在相对简单的环境(对象数量少、针对性强)中,可以将一些名称由完整单词简写为单个字母,例如:
- `user` 可以简写为 `u`
- `userID` 可以简写 `uid`
- 若变量类型为 `bool` 类型,则名称应以 `Has`, `Is`, `Can` 或 `Allow` 开头:
```go
var isExist bool
var hasConflict bool
var canManage bool
var allowGitHook bool
```
- 上条规则也适用于结构定义:
```go
// Webhook represents a web hook object.
type Webhook struct {
ID int64 `xorm:"pk autoincr"`
RepoID int64
OrgID int64
URL string `xorm:"url TEXT"`
ContentType HookContentType
Secret string `xorm:"TEXT"`
Events string `xorm:"TEXT"`
*HookEvent `xorm:"-"`
IsSSL bool `xorm:"is_ssl"`
IsActive bool
HookTaskType HookTaskType
Meta string `xorm:"TEXT"` // store hook-specific attributes
LastStatus HookStatus // Last delivery status
Created time.Time `xorm:"CREATED"`
Updated time.Time `xorm:"UPDATED"`
}
```
#### 变量命名惯例
变量名称一般遵循驼峰法,但遇到特有名词时,需要遵循以下规则:
- 如果变量为私有,且特有名词为首个单词,则使用小写,如 `apiClient`。
- 其它情况都应当使用该名词原有的写法,如 `APIClient`、`repoID`、`UserID`。
下面列举了一些常见的特有名词:
```go
// A GonicMapper that contains a list of common initialisms taken from golang/lint
var LintGonicMapper = GonicMapper{
"API": true,
"ASCII": true,
"CPU": true,
"CSS": true,
"DNS": true,
"EOF": true,
"GUID": true,
"HTML": true,
"HTTP": true,
"HTTPS": true,
"ID": true,
"IP": true,
"JSON": true,
"LHS": true,
"QPS": true,
"RAM": true,
"RHS": true,
"RPC": true,
"SLA": true,
"SMTP": true,
"SSH": true,
"TLS": true,
"TTL": true,
"UI": true,
"UID": true,
"UUID": true,
"URI": true,
"URL": true,
"UTF8": true,
"VM": true,
"XML": true,
"XSRF": true,
"XSS": true,
}
```
================================================
FILE: zh-CN/project_structure.md
================================================
# 项目结构
以下为一般项目结构,根据不同的 Web 框架习惯,可使用括号内的文字替换;根据不同的项目类型和需求,可自由增删某些结构:
```
- templates (views) # 模板文件
- public (static) # 静态文件
- css
- fonts
- img
- js
- routes # 路由逻辑处理
- models # 数据逻辑层
- pkg # 子模块
- setting # 应用配置存取
- cmd # 命令行程序命令
- conf # 默认配置
- locale # i18n 本地化文件
- custom # 自定义配置
- data # 应用生成数据文件
- log # 应用生成日志文件
```
## 命令行应用
当应用类型为命令行应用时,需要将命令相关文件存放于 `/cmd` 目录下,并为每个命令创建一个单独的源文件:
```
/cmd
dump.go
fix.go
serve.go
update.go
web.go
```
================================================
FILE: zh-CN/test_case.md
================================================
# 测试用例
- 单元测试都必须使用 [GoConvey](http://goconvey.co/) 编写,且辅助包覆盖率必须在 80% 以上。
### 使用示例
- 为辅助包书写使用示例的时,文件名均命名为 `example_test.go`。
- 测试用例的函数名称必须以 `Test_` 开头,例如:`Test_Logger`。
- 如果为方法书写测试用例,则需要以 `Text_<Struct>_<Method>` 的形式命名,例如:`Test_Macaron_Run`。
gitextract_0skmej70/
├── LICENSE
├── README.md
├── en-US.md
└── zh-CN/
├── README.md
├── coding_guidelines.md
├── commentary.md
├── copyright.md
├── declaration.md
├── import_packages.md
├── naming_rules.md
├── project_structure.md
└── test_case.md
Condensed preview — 12 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (38K chars).
[
{
"path": "LICENSE",
"chars": 1211,
"preview": "This is free and unencumbered software released into the public domain.\n\nAnyone is free to copy, modify, publish, use, c"
},
{
"path": "README.md",
"chars": 1460,
"preview": "# Go Code Convention\n\nThis is a 100% opinionated and paranoid code convention for the Go Programming Language by [@unknw"
},
{
"path": "en-US.md",
"chars": 16626,
"preview": "# Go Code Convention\n\n## Copyright\n\nFor any open source project, there must be a LICENSE file in the repository root to "
},
{
"path": "zh-CN/README.md",
"chars": 228,
"preview": "# 规范索引\n\n- [版权声明](copyright.md)\n- [项目结构](project_structure.md)\n- [导入标准库、第三方或其它包](import_packages.md)\n- [注释规范](commentary."
},
{
"path": "zh-CN/coding_guidelines.md",
"chars": 3569,
"preview": "# 代码指导\n\n### 基本约束\n\n- 所有应用的 `main` 包需要有 `APP_VER` 常量表示版本,格式为 `X.Y.Z.Date [Status]`,例如:`0.7.6.1112 Beta`。\n- 单独的库需要有函数 `Vers"
},
{
"path": "zh-CN/commentary.md",
"chars": 2096,
"preview": "# 注释规范\n\n- 所有导出对象都需要注释说明其用途;非导出对象根据情况进行注释。\n- 如果对象可数且无明确指定数量的情况下,一律使用单数形式和一般进行时描述;否则使用复数形式。\n- 包、函数、方法和类型的注释说明都是一个完整的句子。\n- "
},
{
"path": "zh-CN/copyright.md",
"chars": 1498,
"preview": "# 版权声明\n\n作为开源项目,必须有相应的开源许可证才能算是真正的开源。在选择了一个开源许可证之后,需要在源文件中进行相应的版权声明才能生效。以下分别以 [Apache License, Version 2.0](http://www.ap"
},
{
"path": "zh-CN/declaration.md",
"chars": 328,
"preview": "# 声明语句\n\n### 函数或方法\n\n函数或方法的参数排列顺序遵循以下几点原则(从左到右):\n\n1. 参数的重要程度与逻辑顺序\n2. 简单类型优先于复杂类型\n3. 尽可能将同种类型的参数放在相邻位置,则只需写一次类型\n\n#### 示例\n\n以"
},
{
"path": "zh-CN/import_packages.md",
"chars": 553,
"preview": "# 导入标准库、第三方或其它包\n\n除标准库外,Go 语言的导入路径基本上依赖代码托管平台上的 URL 路径,因此一个源文件需要导入的包有 4 种分类:标准库、第三方包、组织内其它包和当前包的子包。\n\n基本规则:\n\n- 如果同时存在 2 种及"
},
{
"path": "zh-CN/naming_rules.md",
"chars": 2551,
"preview": "# 命名规则\n\n### 文件名\n\n- 整个应用或包的主入口文件应当是 `main.go` 或与应用名称简写相同。例如:`Gogs` 的主入口文件名为 `gogs.go`。\n\n### 函数或方法\n\n- 若函数或方法为判断类型(返回值主要为 `"
},
{
"path": "zh-CN/project_structure.md",
"chars": 745,
"preview": "# 项目结构\n\n以下为一般项目结构,根据不同的 Web 框架习惯,可使用括号内的文字替换;根据不同的项目类型和需求,可自由增删某些结构:\n\n```\n- templates (views) # 模板文件\n- public ("
},
{
"path": "zh-CN/test_case.md",
"chars": 243,
"preview": "# 测试用例\n\n- 单元测试都必须使用 [GoConvey](http://goconvey.co/) 编写,且辅助包覆盖率必须在 80% 以上。\n\n### 使用示例\n\n- 为辅助包书写使用示例的时,文件名均命名为 `example_tes"
}
]
About this extraction
This page contains the full source code of the unknwon/go-code-convention GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 12 files (30.4 KB), approximately 9.7k tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.