Update tech_docs/golang_getting_started.md
This commit is contained in:
@@ -3833,4 +3833,245 @@ func main() {
|
||||
5. **[Go net Package Documentation](https://pkg.go.dev/net)**
|
||||
6. **[Go unix Package Documentation](https://pkg.go.dev/golang.org/x/sys/unix)**
|
||||
|
||||
These guides should help you get started with each package and provide a solid foundation for building more complex Go applications that interact with the operating system and network.
|
||||
These guides should help you get started with each package and provide a solid foundation for building more complex Go applications that interact with the operating system and network.
|
||||
|
||||
---
|
||||
|
||||
You got it\! Here's a comprehensive Golang coding standards document, adhering to the established structure and principles, with a strong emphasis on Go's idiomatic practices and the tools that enforce them.
|
||||
|
||||
-----
|
||||
|
||||
# Golang Coding Standards Documentation
|
||||
|
||||
## Introduction
|
||||
|
||||
This document outlines our conventions and best practices for writing **Golang (Go) code**. By adhering to these standards, we ensure our projects are **consistent, readable, maintainable, and performant**. This approach fosters **seamless team collaboration**, **reduces debugging time**, and **improves overall code reliability and scalability**.
|
||||
|
||||
Our guidelines are heavily influenced by the official Go documentation, including ["Effective Go"](https://go.dev/doc/effective_go) and ["Go Code Review Comments"](https://go.dev/wiki/CodeReviewComments), and are designed to be enforced by standard Go tools.
|
||||
|
||||
-----
|
||||
|
||||
## Code Formatting
|
||||
|
||||
Go has strong opinions on formatting, largely enforced by its tooling.
|
||||
|
||||
### 1\. `gofmt` and `goimports`
|
||||
|
||||
* **Description**: **Always run `gofmt`** on your code. It automatically formats Go source code according to the official style. **Always run `goimports`** (which includes `gofmt`) to also manage import paths (adding missing ones, removing unused ones, and organizing them).
|
||||
* **Benefit**: Eliminates debates over formatting, ensures consistency across the entire codebase, and streamlines dependencies.
|
||||
* **Usage**: Configure your IDE/editor to run `goimports` on save. From the command line:
|
||||
```bash
|
||||
goimports -w .
|
||||
```
|
||||
|
||||
### 2\. Line Length
|
||||
|
||||
* **No Hard Limit**: Unlike some languages, Go doesn't have a strict line length limit (like 80 characters). However, strive for **reasonable line lengths** that are easy to read without horizontal scrolling. If a line becomes too long, consider breaking it into multiple lines using natural Go syntax (e.g., after commas, operators, opening parentheses).
|
||||
* **Benefit**: Promotes readability and avoids awkward line breaks that `gofmt` might otherwise introduce.
|
||||
|
||||
### 3\. Blank Lines
|
||||
|
||||
* **Logical Grouping**: Use blank lines to separate logical sections of code within functions or between related function definitions.
|
||||
* **Imports**: `goimports` will handle blank lines between standard library, third-party, and internal imports automatically.
|
||||
* **Usage**:
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt" // Standard library
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin" // Third-party
|
||||
)
|
||||
|
||||
// Two blank lines before top-level declarations
|
||||
type User struct {
|
||||
ID int
|
||||
Name string
|
||||
}
|
||||
|
||||
func main() {
|
||||
// One blank line for logical separation
|
||||
router := gin.Default()
|
||||
router.GET("/users/:id", getUserHandler)
|
||||
router.POST("/users", createUserHandler)
|
||||
|
||||
// Another logical separation
|
||||
server := &http.Server{
|
||||
Addr: ":8080",
|
||||
Handler: router,
|
||||
ReadTimeout: 10 * time.Second,
|
||||
WriteTimeout: 10 * time.Second,
|
||||
}
|
||||
|
||||
fmt.Println("Server starting on :8080")
|
||||
server.ListenAndServe()
|
||||
}
|
||||
```
|
||||
|
||||
-----
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
Go's naming conventions are crucial, especially for controlling visibility (exporting).
|
||||
|
||||
### 1\. Visibility (Exporting)
|
||||
|
||||
* **`PascalCase` (first letter capitalized)**:
|
||||
* **Description**: For **exported** (publicly visible) names: packages, types, functions, methods, and variables that should be accessible from outside their defining package.
|
||||
* **Usage**: `MyStruct`, `GetUserByID`, `ErrNotFound`
|
||||
* **`camelCase` (first letter lowercase)**:
|
||||
* **Description**: For **unexported** (private to the package) names: types, functions, methods, and variables.
|
||||
* **Usage**: `myHelperFunction`, `userCache`, `errorHandler`
|
||||
|
||||
### 2\. General Naming Guidelines
|
||||
|
||||
* **Descriptive and Concise**: Names should be clear but also succinct. Avoid unnecessary verbosity.
|
||||
* **Bad**: `get_user_by_unique_identifier_from_database`
|
||||
* **Good**: `GetUserByID`, `fetchUser`
|
||||
* **Acronyms**: Keep acronyms (e.g., `ID`, `HTTP`, `URL`, `API`) consistently cased.
|
||||
* **Exported**: `userID`, `httpClient` (NOT `userId`, `httpClient`)
|
||||
* **Unexported**: `apiConfig` (NOT `APIConfig` unless it's a type)
|
||||
* **Receiver Names (Methods)**:
|
||||
* **Description**: In method declarations, the receiver variable name should be short, usually one or two letters, and consistent across methods of the same type.
|
||||
* **Usage**: `(u *User)`, `(s *Server)`
|
||||
* **Interface Names**:
|
||||
* **Description**: If an interface has a single method, its name is typically the method name plus `er` (e.g., `Reader`, `Writer`, `Closer`).
|
||||
* **Usage**: `io.Reader`, `fmt.Stringer`
|
||||
* **Package Names**:
|
||||
* **Description**: Package names should be short, all lowercase, and reflect the package's purpose (e.g., `http`, `fmt`, `json`, `user`, `auth`). Avoid `_` or `.` in package names.
|
||||
* **Usage**: `package main`, `package models`, `package utils`
|
||||
|
||||
-----
|
||||
|
||||
## Comments and Docstrings
|
||||
|
||||
Good documentation in Go means clear explanations for exported entities.
|
||||
|
||||
### 1\. Comments (`//`)
|
||||
|
||||
* **Descriptive**: Use comments to explain **why** a piece of code exists, or to clarify complex logic. Avoid commenting on obvious code.
|
||||
* **Concise**: Keep comments brief and to the point.
|
||||
* **Up-to-Date**: Ensure comments are updated if the code changes.
|
||||
* **Usage**:
|
||||
```go
|
||||
// Loop through connections, attempting to reconnect with exponential backoff.
|
||||
for i := 0; i < maxRetries; i++ {
|
||||
if err := connectToDatabase(); err == nil {
|
||||
break // Successfully connected
|
||||
}
|
||||
time.Sleep(time.Duration(2<<i) * time.Second) // Exponential backoff
|
||||
}
|
||||
```
|
||||
|
||||
### 2\. Docstrings (Godoc Style)
|
||||
|
||||
* **Exported Entities**: All exported (publicly visible) packages, functions, methods, types (structs, interfaces), and variables **must** have a docstring. Unexported entities generally do not require docstrings unless their purpose is unusually complex.
|
||||
* **First Sentence**: The first sentence should be a concise summary starting with the name of the documented entity.
|
||||
* **Usage**: Place docstrings immediately before the entity they describe.
|
||||
* **Package Doc**: A comment just before `package [name]` in one of the package's files.
|
||||
```go
|
||||
// Package user provides functionality for managing user accounts.
|
||||
package user
|
||||
```
|
||||
* **Function/Method Doc**:
|
||||
```go
|
||||
// GetUserByID retrieves a user from the database by their ID.
|
||||
// It returns the user object and an error if the user is not found
|
||||
// or a database issue occurs.
|
||||
func GetUserByID(id int) (*User, error) {
|
||||
// ...
|
||||
}
|
||||
```
|
||||
* **Struct/Interface Doc**:
|
||||
```go
|
||||
// User represents a user account in the system.
|
||||
type User struct {
|
||||
ID int
|
||||
Username string
|
||||
Email string
|
||||
}
|
||||
```
|
||||
* **`go doc`**: Docstrings are read by the `go doc` command and rendered on `pkg.go.dev`.
|
||||
|
||||
-----
|
||||
|
||||
## Best Practices and Principles
|
||||
|
||||
These principles guide our overall approach to writing effective, performant, and maintainable Go code.
|
||||
|
||||
### 1\. Error Handling
|
||||
|
||||
* **Explicit Error Returns**: Go functions explicitly return errors as the last return value.
|
||||
* **Nil Checks**: Always check for `nil` errors after a function call that returns an error. Do not ignore errors.
|
||||
* **Error Wrapping**: Use `fmt.Errorf` with `%w` to wrap errors, providing a chain of context.
|
||||
* **Custom Error Types**: Define custom error types for specific error conditions when standard errors are insufficient.
|
||||
* **Usage**:
|
||||
```go
|
||||
func ReadFile(filename string) ([]byte, error) {
|
||||
data, err := os.ReadFile(filename)
|
||||
if err != nil {
|
||||
// Wrap the error to add context
|
||||
return nil, fmt.Errorf("failed to read file %q: %w", filename, err)
|
||||
}
|
||||
return data, nil
|
||||
}
|
||||
|
||||
func processFile() {
|
||||
data, err := ReadFile("nonexistent.txt")
|
||||
if err != nil {
|
||||
// Check if it's a specific type of error
|
||||
if errors.Is(err, os.ErrNotExist) {
|
||||
log.Printf("File not found: %v", err)
|
||||
} else {
|
||||
log.Printf("An unexpected error occurred: %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
fmt.Println(string(data))
|
||||
}
|
||||
```
|
||||
|
||||
### 2\. Concurrency (Goroutines and Channels)
|
||||
|
||||
* **`go` Keyword**: Use `go` to launch goroutines for concurrent execution.
|
||||
* **Channels**: Use channels to safely communicate and synchronize between goroutines. Do not use shared memory directly without explicit synchronization (e.g., `sync.Mutex`).
|
||||
* **`select` Statement**: Use `select` to handle multiple channel operations (e.g., waiting for data or a timeout).
|
||||
* **`context` Package**: Pass `context.Context` (with `Done()`, `Err()`, `Value()`) to goroutines for cancellation and passing request-scoped values.
|
||||
* **Avoid Global State**: Minimize reliance on global variables; pass necessary data as arguments or via channels.
|
||||
|
||||
### 3\. Defer Statements
|
||||
|
||||
* **Resource Cleanup**: Use `defer` to ensure resources (like file handles, database connections, mutexes) are properly closed or released when the surrounding function returns.
|
||||
* **Usage**:
|
||||
```go
|
||||
func openAndProcessFile(filename string) error {
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
return fmt.Errorf("could not open file: %w", err)
|
||||
}
|
||||
defer file.Close() // Ensures file is closed when function exits
|
||||
|
||||
// Process file...
|
||||
return nil
|
||||
}
|
||||
```
|
||||
|
||||
### 4\. Package Structure
|
||||
|
||||
* **Small and Focused**: Keep packages small and focused on a single responsibility.
|
||||
* **Clear Dependencies**: Avoid circular dependencies between packages.
|
||||
* **Internal Package**: Use an `internal/` directory for code that should only be imported by packages within the same repository.
|
||||
* **Cmd Package**: For executable applications, place `main.go` files inside `cmd/[app-name]/`.
|
||||
|
||||
### 5\. Linter and Static Analysis Tools
|
||||
|
||||
* **`golangci-lint`**: Use `golangci-lint` (or similar) in your CI/CD pipeline and locally during development. This tool aggregates many Go linters (e.g., `staticcheck`, `go vet`, `nilaway`) and helps enforce best practices beyond just formatting.
|
||||
* **Benefit**: Catches common errors, identifies potential bugs, and enforces style guidelines automatically.
|
||||
|
||||
-----
|
||||
|
||||
## Conclusion
|
||||
|
||||
By diligently applying these **Golang coding standards**, we ensure our code is not only functional but also **highly readable, maintainable, and robust**. This commitment to quality coding practices promotes a more efficient development workflow, reduces technical debt, and strengthens the overall quality and reliability of our software projects.
|
||||
Reference in New Issue
Block a user