- It is recommended that a line of code does not exceed 120 characters. If the part exceeds, please use an appropriate line break method. But there are also some exception scenarios, such as import lines, code automatically generated by tools, and struct fields with tags.
- The file length cannot exceed 800 lines.
- Function length cannot exceed 80 lines.
- import specification
- All code must be formatted with `goimports` (it is recommended to set the code Go code editor to: run `goimports` on save).
- Do not use relative paths to import packages, such as `import ../util/net`.
- Import aliases must be used when the package name does not match the last directory name of the import path, or when multiple identical package names conflict.
When multiple variables need to be used in a function, the `var` declaration can be used at the beginning of the function. Declaration outside the function must use `var`, do not use `:=`, it is easy to step on the scope of the variable.
- Embedded types (such as mutexes) should be at the top of the field list within the struct, and there must be a blank line separating embedded fields from regular fields.
-`error` is returned as the value of the function, `error` must be handled, or the return value assigned to explicitly ignore. For `defer xx.Close()`, there is no need to explicitly handle it.
- Tell users what they can do, not what they can't.
- When declaring a requirement, use must instead of should. For example, `must be greater than 0, must match regex '[a-z]+'`.
- When declaring that a format is incorrect, use must not. For example, `must not contain`.
- Use may not when declaring an action. For example, `may not be specified when otherField is empty, only name may be specified`.
- When quoting a literal string value, indicate the literal in single quotes. For example, `ust not contain '..'`.
- When referencing another field name, specify that name in backticks. For example, must be greater than `request`.
- When specifying unequal, use words instead of symbols. For example, `must be less than 256, must be greater than or equal to 0 (do not use larger than, bigger than, more than, higher than)`.
- When specifying ranges of numbers, use inclusive ranges whenever possible.
- Go 1.13 or above is recommended, and the error generation method is `fmt.Errorf("module xxx: %w", err)`.
- Panic is prohibited in business logic processing.
- In the main package, panic is only used when the program is completely inoperable, for example, the file cannot be opened, the database cannot be connected, and the program cannot run normally.
- In the main package, use `log.Fatal` to record errors, so that the program can be terminated by the log, or the exception thrown by the panic can be recorded in the log file, which is convenient for troubleshooting.
- An exportable interface must not panic.
- It is recommended to use error instead of panic to convey errors in the package.
The naming convention is a very important part of the code specification. A uniform, short, and precise naming convention can greatly improve the readability of the code and avoid unnecessary bugs.
- The package name must be consistent with the directory name, try to use a meaningful and short package name, and do not conflict with the standard library.
- Package names are all lowercase, without uppercase or underscores, and use multi-level directories to divide the hierarchy.
- Item names can connect multiple words with dashes.
- Do not use plurals for the package name and the directory name where the package is located, for example, `net/url` instead of `net/urls`.
- Don't use broad, meaningless package names like common, util, shared or lib.
- The package name should be simple and clear, such as net, time, log.
- The function name is in camel case, and the first letter is uppercase or lowercase according to the access control decision,For example: `MixedCaps` or `mixedCaps`.
- Code automatically generated by code generation tools (such as `xxxx.pb.go`) and underscores used to group related test cases (such as `TestMyFunction_WhatIsBeingTested`) exclude this rule.
In accordance with the naming conventions adopted by OpenIM and drawing reference from the Google Naming Conventions as per the guidelines available at https://google.github.io/styleguide/go/, the following expectations for naming practices within the project are set forth:
1.**File Names:**
+ Both hyphens (`-`) and underscores (`_`) are permitted when naming files.
+ A preference is established for the use of underscores (`_`), suggesting it as the best practice in general scenarios.
2.**Script and Markdown Files:**
+ For shell scripts (bash files) and Markdown (`.md`) documents, the use of hyphens (`-`) is recommended.
+ This recommendation is based on the improved searchability and compatibility in web browsers when hyphens are used in names.
3.**Directories:**
+ A consistent approach is mandated for naming directories, exclusively using hyphens (`-`) to separate words within directory names.
- Each exportable name must have a comment, which briefly introduces the exported variables, functions, structures, interfaces, etc.
- All single-line comments are used, and multi-line comments are prohibited.
- Same as the code specification, single-line comments should not be too long, and no more than 120 characters are allowed. If it exceeds, please use a new line to display, and try to keep the format elegant.
- A comment must be a complete sentence, starting with the content to be commented and ending with a period, `the format is // name description.`. For example:
- All commented out code should be deleted before submitting code review, otherwise, it should explain why it is not deleted, and give follow-up processing suggestions.
- When there is a large block of constant or variable definition, you can comment a general description in front, and then comment the definition of the constant in detail before or at the end of each line of constant, for example:
- Each structure or interface that needs to be exported must have a comment description, the format is `// structure name structure description.`.
- The name of the exportable member variable in the structure, if the meaning is not clear, a comment must be given and placed before the member variable or at the end of the same line. For example:
- Each type definition and type alias that needs to be exported must have a comment description, the format is `// type name type description.`, for example:
- If the function returns two or three arguments of the same type, or if the meaning of the result is not clear from the context, use named returns, otherwise it is not recommended to use named returns, for example:
- When resources are created, resources should be released immediately after defer (defer can be used boldly, the performance of defer is greatly improved in Go1.14 version, and the performance loss of defer can be ignored even in performance-sensitive businesses).
- First judge whether there is an error, and then defer to release resources, for example:
- After Go 1.11, the GOPATH rule has been weakened. Existing code (many libraries must have been created before 1.11) must conform to this rule. It is recommended to keep the GOPATH rule to facilitate code maintenance.
- Only one GOPATH is recommended, multiple GOPATHs are not recommended. If multiple GOPATHs are used, the bin directory where compilation takes effect is under the first GOPATH.
- Minimize the use of global variables, but pass parameters, so that each function is "stateless". This reduces coupling and facilitates division of labor and unit testing.
- Verify interface compliance at compile time, for example:
- When the server processes a request, it should create a context, save the relevant information of the request (such as requestID), and pass it in the function call chain.
- string represents an immutable string variable, modifying string is a relatively heavy operation, and basically needs to re-apply for memory. Therefore, if there is no special need, use []byte more when you need to modify.
golangci lint can select the types of tools, refer to the official documentation: [https://golangci-lint.run/usage/linters/](https://golangci-lint.run/usage/linters/)
The types of comments we currently use include: [https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml](https://github.com/openimsdk/open-im-server/blob/main/.golangci.yml) the `linters.enable` field in the file.
e.g:
```yaml
linters:
# please, do not use `enable-all`: it's deprecated and will be removed soon.
# inverted configuration with `enable-all` and `disable` is not scalable during updates of golangci-lint
# enable-all: true
disable-all: true
enable:
- typecheck # Basic type checking
- gofmt # Format check
- govet # Go's standard linting tool
- gosimple # Suggestions for simplifying code
- misspell # Spelling mistakes
- staticcheck # Static analysis
- unused # Checks for unused code
- goimports # Checks if imports are correctly sorted and formatted
- godot # Checks for comment punctuation
- bodyclose # Ensures HTTP response body is closed
- errcheck # Checks for missed error returns
fast: true
```
Add that Chinese comments are not allowed in go code, please write a complete golangci lint specification on the basis of the above.
### 10.1 Configuration Document
This configuration document is designed to configure the operational parameters of OpenIM (a hypothetical or specific code analysis tool), customize output formats, and provide detailed settings for specific code checkers (linters). Below is a summary of the document drafted based on the provided configuration information.
#### 10.1 Runtime Options
- **Concurrency** (`concurrency`): Default to use the available CPU count, can be manually set to 4 for parallel analysis.
- **Timeout** (`timeout`): Timeout duration for analysis operations, default is 1 minute, set here to 5 minutes.
- **Issue Exit Code** (`issues-exit-code`): Exit code defaults to 1 if at least one issue is found.
- **Test Files** (`tests`): Whether to include test files, defaults to true.
- **Build Tags** (`build-tags`): Specify build tags used by all linters, defaults to an empty list. Example adds `mytag`.
- **Skip Directories** (`skip-dirs`): Configure which directories' issues are not reported, defaults to empty, but some default directories are independently skipped.
- **Skip Files** (`skip-files`): Specify files where issues should not be reported, supports regular expressions.
#### 10.2 Output Configuration
- **Format** (`format`): Set output format, default is "colored-line-number".
- **Print Issued Lines** (`print-issued-lines`): Whether to print the lines where issues occur, defaults to true.
- **Print Linter Name** (`print-linter-name`): Whether to print the linter name at the end of issue text, defaults to true.
- **Uniqueness Filter** (`uniq-by-line`): Whether to make issue outputs unique per line, defaults to true.
- **Path Prefix** (`path-prefix`): Prefix to add to output file references, defaults to no prefix.
- **Sort Results** (`sort-results`): Sort results by file path, line number, and column number.
#### 10.3 Linters Settings
In the configuration file, the `linters-settings` section allows detailed configuration of individual linters. Below are examples of specific linters settings and their purposes:
- **bidichk**: Used to check bidirectional text characters, ensuring correct display direction of text, especially when dealing with mixed left-to-right (LTR) and right-to-left (RTL) text.
- **dogsled**: Monitors excessive use of blank identifiers (`_`) in assignment operations, which may obscure data processing errors or unclear logic.
- **dupl**: Identifies duplicate code blocks, helping developers avoid code redundancy. The `threshold` parameter in settings allows adjustment of code similarity threshold triggering warnings.
- **errcheck**: Checks for unhandled errors. In Go, error handling is achieved by checking function return values. This linter helps ensure all errors are properly handled.
- **exhaustive**: Checks if `switch` statements include all possible values of an enum type, ensuring exhaustiveness of code. This helps avoid forgetting to handle certain cases.
#### 10.4 Example: `errcheck`
**Incorrect Code Example**:
```go
package main
import (
"fmt"
"os"
)
func main() {
f, _ := os.Open("filename.ext")
defer f.Close()
}
```
**Issue**: In the above code, the error return value of `os.Open` function is explicitly ignored. This is a common mistake as it may lead to unhandled errors and hard-to-trace bugs.
**Correct Form**:
```go
package main
import (
"fmt"
"os"
)
func main() {
f, err := os.Open("filename.ext")
if err != nil {
fmt.Printf("error opening file: %v\n", err)
return
}
defer f.Close()
}
```
In the correct form, by checking the error (`err`) returned by `os.Open`, we gracefully handle error cases rather than simply ignoring them.
#### 10.5 Example: `gofmt`
**Incorrect Code Example**:
```go
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
```
**Issue**: This code snippet doesn't follow Go's standard formatting rules, for example, incorrect indentation of `fmt.Println`.
**Correct Form**:
```go
package main
import "fmt"
func main() {
fmt.Println("Hello, world!")
}
```
Using `gofmt` tool can automatically fix such formatting issues, ensuring the code adheres to the coding standards of the Go community.
#### 10.6 Example: `unused`
**Incorrect Code Example**:
```go
package main
func helper() {}
func main() {}
```
**Issue**: The `helper` function is defined but not called anywhere, indicating potential redundant code or missing functionality implementation.
**Correct Form**:
```go
package main
// If the helper function is indeed needed, ensure it's used properly.
func helper() {
// Implement the function's functionality or ensure it's called elsewhere
}
func main() {
helper()
}
```
To improve the section on Linters settings in the document, we'll expand with more detailed explanations and reinforce understanding through examples.
#### 10.7 Example: `dogsled`
**Incorrect Code Example**:
```go
func getValues() (int, int, int) {
return 1, 2, 3
}
func main() {
_, _, val := getValues()
fmt.Println(val) // Only interested in the third return value
}
```
**Explanation**: In the above code, we use two blank identifiers to ignore the first two return values. Excessive use of blank identifiers can make code reading difficult.
**Improved Code**:
Consider refactoring the function or the usage of return values to reduce the need for blank identifiers or explicitly comment why ignoring certain values is safe.
#### 10.8: `exhaustive`
**Incorrect Code Example**:
```go
type Fruit int
const (
Apple Fruit = iota
Banana
Orange
)
func getFruitName(f Fruit) string {
switch f {
case Apple:
return "Apple"
case Banana:
return "Banana"
// Missing handling for Orange
}
return "Unknown"
}
```
**Explanation**: In this code, the `switch` statement doesn't cover all possible values of the `Fruit` type; the case for `Orange` is missing.
**Improved Code**:
```go
func getFruitName(f Fruit) string {
switch f {
case Apple:
return "Apple"
case Banana:
return "Banana"
case Orange:
return "Orange"
}
return "Unknown"
}
```
By adding the missing `case`, we ensure the `switch` statement is exhaustive, handling every possible enum value.
#### 10.9 Optimization of Configuration Files and Application of Code Analysis Tools
Through these examples, we demonstrate how to improve code quality by identifying and fixing common coding issues. OpenIM's configuration files allow developers to customize linters' behavior according to project requirements, ensuring code compliance with predefined quality standards and style guidelines.
By employing these tools and configuration strategies, teams can reduce the number of bugs, enhance code maintainability, and facilitate efficient collaboration during code review processes.