[teamai] Push 87 resource(s) from XingfenD

This commit is contained in:
2026-09-10 16:10:45 +08:00
parent 425c9c078a
commit 65c04def51
1314 changed files with 211681 additions and 0 deletions
@@ -0,0 +1,116 @@
# Functions, Methods & Options
## Functions and Methods
Functions returning a value are named like **nouns** (what they return). Functions performing actions are named like **verbs** (what they do).
```go
// Noun-like: returns something
func UserName() string { ... }
func DefaultConfig() Config { ... }
// Verb-like: performs an action
func WriteFile(name string, data []byte) error { ... }
func SendNotification(user *User) error { ... }
```
NEVER repeat the package name in function names:
```go
// Good: users call http.Get(), not http.HTTPGet()
package http
func Get(url string) (*Response, error)
// Bad: stutters at the call site
package http
func HTTPGet(url string) (*Response, error)
```
Functions that accept a format string and variadic args (like `fmt.Sprintf`) MUST end with **`f`**:
```go
// Good
func Errorf(format string, args ...any) error
func Wrapf(err error, format string, args ...any) error
func Logf(format string, args ...any)
// Bad
func Error(format string, args ...any) error // looks like it takes a plain string
func WrapError(err error, format string, args ...any) error
```
### Getters and Setters
Getters MUST NOT use the `Get` prefix. The getter is simply the field name, capitalized.
```go
// Good
func (u *User) Name() string { return u.name }
func (u *User) SetName(name string) { u.name = name }
// Bad
func (u *User) GetName() string { return u.name }
```
Only use `Get` when the underlying concept inherently uses "get" (e.g., HTTP GET). For expensive or blocking operations, use `Fetch` or `Compute` to signal that the call is not trivial.
**Exception — boolean predicates keep the `Is`/`Has`/`Can` prefix.** The no-Get rule applies to value getters, not boolean predicates. A method returning `bool` SHOULD use `Is`/`Has`/`Can` to read naturally as a question — this follows the standard library pattern (`reflect.Type.IsVariadic()`, `net.IP.IsLoopback()`, `big.Int.IsInt64()`).
```go
// Good — boolean predicate keeps Is prefix
func (s *Server) IsHealthy() bool { return s.healthy }
// Good — value getter omits Get prefix
func (s *Server) Port() int { return s.port }
// Good — richer return type, bare name is fine (different semantics)
func (s *Server) Healthy() (HealthStatus, error)
// Bad — bare adjective for bool is ambiguous
func (s *Server) Healthy() bool { return s.healthy }
// Bad — Get prefix on value getter is redundant
func (s *Server) GetPort() int { return s.port }
```
### Constructors
Name constructors `New` when the package exports a single primary type, or `NewTypeName` when there are multiple types.
```go
// Single primary type — New is unambiguous
package ring
func New(size int) *Ring
// Multiple types — qualify with the type name
package http
func NewRequest(method, url string, body io.Reader) (*Request, error)
func NewServeMux() *ServeMux
```
### Named Return Values
Named return values SHOULD only be used when it improves readability — typically when multiple return values have the same type, or when the names serve as documentation.
```go
// Good — names clarify which int64 is which
func Copy(dst Writer, src Reader) (written int64, err error)
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error)
// Good — single error return, no name needed
func Write(p []byte) (int, error)
// Bad — names add no clarity
func Read(p []byte) (bytes int, e error) // "bytes" shadows the package, "e" is non-standard
```
NEVER use named returns just to enable bare `return` — bare returns hurt readability in anything but the shortest functions.
## Functional Options Pattern
When a constructor has 3+ optional parameters that may grow, use the **functional options pattern** for clean, extensible APIs.
- **Struct**: `ServerOptions`, `ClientOptions` (not `Opts`, `Params`, `Settings`, `Config`)
- **Function type**: `ServerOption` (singular, not plural)
- **With\* functions**: `WithPort()`, `WithTimeout()`, `WithLogger()`
- **Factory**: `DefaultServerOptions()`
@@ -0,0 +1,165 @@
# Variables, Booleans, Receivers & Acronyms
## Variables
Name length SHOULD be **proportional to scope size**. Short names for small scopes, descriptive names for large scopes.
```go
// Small scope (1-7 lines): short names are fine
for i, v := range items {
result = append(result, v.Name)
}
// Medium scope: moderately descriptive
userCount := len(users)
// Large scope / package-level: explicit and clear
var defaultHTTPTransport = &http.Transport{
MaxIdleConns: 100,
}
```
Common single-letter conventions:
| Letter | Meaning |
| ------------- | ---------------------- |
| `i`, `j`, `k` | Loop indices |
| `n` | Count or length |
| `v` | Value (in range loops) |
| `k` | Key (in map ranges) |
| `r` | `io.Reader` |
| `w` | `io.Writer` |
| `b` | `[]byte` or buffer |
| `s` | String |
| `t` | `*testing.T` |
| `ctx` | `context.Context` |
| `err` | Error |
### Avoid Type in the Name
The name should describe what the value represents, not its type.
```go
// Good
users := getUsers()
count := len(items)
// Bad
userSlice := getUsers()
countInt := len(items)
nameString := "hello"
```
### Avoid Repetition with Context
Omit words already clear from the enclosing function, method, or type.
```go
// Good — "user" is clear from the method receiver
func (u *UserService) Create(name string) error { ... }
// Bad — "user" is redundant
func (u *UserService) CreateUser(userName string) error { ... }
```
### Use Predictable Names
The same concept MUST always use the same name across the codebase. If a user is called `user` in one function, it should not become `account`, `person`, or `u` in another. Consistency makes code searchable and reduces cognitive load.
```go
// Good — same concept, same name everywhere
func CreateUser(user *User) error { ... }
func UpdateUser(user *User) error { ... }
func DeleteUser(userID string) error { ... }
// Bad — same concept, different names
func CreateUser(user *User) error { ... }
func UpdateAccount(acct *User) error { ... } // why "acct"? it's a User
func RemovePerson(id string) error { ... } // why "person"? why "remove"?
```
This applies to variables, parameters, functions, and fields. Pick one name per domain concept and stick with it: `order` not sometimes `order` / sometimes `purchase`; `userID` not sometimes `userID` / sometimes `uid` / sometimes `userId`.
### Parameters
Parameters double as documentation at the call site. When the type is descriptive, keep the name short. When the type is ambiguous, use a longer name to clarify intent.
```go
// Good — type is descriptive, short name is fine
func AfterFunc(d Duration, f func()) *Timer
func Escape(w io.Writer, s []byte)
// Good — type is ambiguous (int64, string), longer name documents meaning
func Unix(sec, nsec int64) Time
func HasPrefix(s, prefix string) bool
// Bad — ambiguous type with cryptic name
func Unix(a, b int64) Time // what are a and b?
func HasPrefix(a, b string) bool // which is the prefix?
```
## Booleans
Boolean variables and fields MUST read naturally as true/false questions. Use prefixes like `is`, `has`, `can`, `allow`, `should`. This applies to **both variables and struct fields**.
```go
// Good — struct fields use is/has prefix
type Client struct {
isConnected bool // reads as "client is connected"
hasPermission bool // reads as "client has permission"
}
// Good — variables
isReady := true
hasPermission := user.CanEdit(doc)
// Bad — bare adjective is ambiguous
type Client struct {
connected bool // could be confused with a connection object
permission bool // noun, not a question
}
```
For exported boolean methods, the prefix becomes part of the method name: `IsValid()`, `HasPrefix()`, `CanRetry()`. The unexported field keeps the prefix too: `isConnected` field → `IsConnected()` method.
## Receivers
Receivers MUST be **1-2 letter abbreviations** of the type name. Use the same name across all methods of a type.
```go
// Good — short, consistent
func (s *Server) Start() error { ... }
func (s *Server) Stop() error { ... }
func (s *Server) Handle(r *Request) { ... }
// Bad — too long
func (server *Server) Start() error { ... }
// Bad — inconsistent names across methods
func (s *Server) Start() error { ... }
func (srv *Server) Stop() error { ... }
// Bad — NEVER use "this" or "self"
func (this *Server) Handle(r *Request) { ... }
```
## Acronyms and Initialisms
Acronyms MUST be **all caps or all lower**, NEVER mixed. This preserves readability in MixedCaps names.
```go
// Good
URL // all caps
url // all lower
HTTPServer // HTTP is all caps
xmlParser // xml is all lower
userID // ID is all caps
newHTTPSURL // both HTTPS and URL all caps
// Bad
Url // mixed case acronym
HttpServer // mixed case
userId // mixed case for ID
```
When exporting a lowercase acronym, capitalize the whole thing: `url` → `URL`, `grpc` → `GRPC`, `ios` → `IOS`.
@@ -0,0 +1,96 @@
# Packages, Files & Import Aliasing
## Packages
Package names MUST be **lowercase, single-word**, with no underscores or MixedCaps. They should be short, concise, and evocative of their purpose. Numbers are allowed (`oauth2`, `k8s`).
```go
// Good
package json
package http
package tabwriter
package oauth2
// Bad
package httpServer // no MixedCaps
package http_server // no underscores
package util // too generic
package common // meaningless
package helpers // what does it help with?
package base // says nothing
package model // too vague
```
NEVER use generic package names like `util`, `helper`, `common`, `base`, `model`. They fail to communicate purpose and cause import collisions. If you reach for `util`, the function probably belongs in a more specific package.
Package names SHOULD be **singular**, not plural — `net/url` not `net/urls`, `go/token` not `go/tokens`.
### Directory vs Package Name
Directory names SHOULD **match the package name** when possible. Multi-word directories use **hyphens**, but since package names cannot contain hyphens, the package drops them.
```
// Good — directory matches package
httputil/ → package httputil
middleware/ → package middleware
auth/ → package auth
// Good — hyphenated directory, package drops hyphens
user-service/ → package userservice
rate-limit/ → package ratelimit
go-chi/ → package chi
// Good — special directories
cmd/api/ → package main (cmd/ subdirectories are always main)
internal/auth/ → package auth (internal/ restricts visibility)
// Bad
user_service/ → package user_service (underscores in both)
UserService/ → package UserService (no MixedCaps in directories)
myPackage/ → package mypackage (directory has caps, package doesn't)
```
Special directories have Go toolchain meaning and don't follow normal naming:
- `cmd/` — entry points, each subdirectory is `package main`
- `internal/` — restricts import visibility to parent module
- `testdata/` — ignored by the Go tool
- `vendor/` — vendored dependencies
Package names SHOULD NOT duplicate exported names — users see `bufio.Reader`, not `bufio.BufReader`. Think about the call site.
## Files
File names MUST be **lowercase** with words separated by **underscores**.
```
user_handler.go
string_converter.go
http_client_test.go
```
Special suffixes:
- `_test.go` — test files (excluded from production builds)
- `_linux.go`, `_amd64.go` — OS/architecture-specific (build constraints)
## Import Aliasing
Import aliases SHOULD only be used on name collision. When an alias is necessary, use a descriptive short name.
```go
// Good — no alias needed
import "github.com/go-chi/chi/v5"
// Good — alias resolves collision
import (
"crypto/rand"
mrand "math/rand"
)
// Good — conventional alias for generated code
import pb "myapp/proto/userpb"
// Bad — unnecessary alias
import f "fmt"
```
@@ -0,0 +1,37 @@
# Test Naming
## Test Functions
Test functions follow `Test` + the name of what is being tested. Use underscores for subcases.
```go
func TestParseToken(t *testing.T) { ... }
func TestServer_Handle(t *testing.T) { ... } // method test
func TestParseToken_InvalidInput(t *testing.T) { ... } // subcase
```
## Table-Driven Tests
Table-driven test case names SHOULD be **fully lowercase, descriptive phrases** — including acronyms. Use `input` for inputs and `expected` for expected outputs to make the data flow clear:
```go
tests := []struct {
name string
input string
expectedCode int
expectedErr bool
}{
{name: "empty input", input: "", expectedCode: 400, expectedErr: true},
{name: "valid token", input: "abc123", expectedCode: 200},
{name: "expired token", input: "exp", expectedCode: 401, expectedErr: true},
{name: "invalid id", input: "???", expectedCode: 400, expectedErr: true}, // "id" not "ID"
}
// Bad — mixed case in test names
{name: "valid ID", ...} // should be "valid id"
{name: "Empty Input", ...} // should be "empty input"
```
## Test Helpers
Test helper functions that panic on failure conventionally use the `must` prefix: `mustLoadFixture()`, `mustParseURL()`.
@@ -0,0 +1,159 @@
# Types, Constants & Errors
## Interfaces
### Single-Method Interfaces
Name them with the **method name + `-er`** suffix:
```go
type Reader interface {
Read(p []byte) (n int, err error)
}
type Stringer interface {
String() string
}
type Closer interface {
Close() error
}
```
### Multi-Method Interfaces
Use a descriptive **noun** or compose from single-method interfaces:
```go
type ReadWriteCloser interface {
Reader
Writer
Closer
}
type Handler interface {
ServeHTTP(ResponseWriter, *Request)
}
```
### Canonical Method Names
Honor established Go method names and their signatures. If your type implements `Read`, it MUST match `io.Reader`'s signature. NEVER invent variations like `ReadData` or `ToString` — use `String`.
| Method name | Expected interface |
| ----------- | ------------------ |
| `Read` | `io.Reader` |
| `Write` | `io.Writer` |
| `Close` | `io.Closer` |
| `String` | `fmt.Stringer` |
| `Error` | `error` |
| `Len` | `sort.Interface` |
| `ServeHTTP` | `http.Handler` |
## Structs
Name structs with **MixedCaps nouns** describing the entity. Fields follow exported/unexported rules.
```go
type Server struct {
Addr string // exported
Handler http.Handler // exported
timeout time.Duration // unexported
}
```
NEVER suffix struct names with `Struct`, `Object`, or `Data` — they add no information.
## Constants
Constants MUST use **MixedCaps**, NEVER `ALL_CAPS`. The name should explain the **role**, not the **value**.
```go
// Good — MixedCaps, name explains purpose
const MaxRetries = 3
const defaultTimeout = 30 * time.Second
const DefaultPort = 8080
// Bad — ALL_CAPS is not idiomatic Go
const MAX_RETRIES = 3
const DEFAULT_TIMEOUT = 30
// Bad — name is the value, not the purpose
const Three = 3
const Port8080 = 8080
```
### Enums (iota)
Prefix enum values with the **type name** to avoid collisions and improve readability at the call site.
```go
type Status int
const (
StatusUnknown Status = iota // zero value = unknown/invalid
StatusReady
StatusRunning
StatusDone
)
type Color int
const (
ColorRed Color = iota + 1 // skip zero to catch uninitialized values
ColorGreen
ColorBlue
)
```
**Always protect the zero value.** A `var s Status` will silently be 0 — if that maps to a real state like `StatusReady`, code can behave as if a status was deliberately chosen when it wasn't. Either place an explicit `Unknown` sentinel at iota 0, or start at `iota + 1`. This is not optional — uninitialized enums are a common source of silent bugs.
## Errors
### Sentinel Errors
Sentinel error variables use the `Err` prefix. Error strings SHOULD include the package name as prefix to identify the origin when errors are wrapped:
```go
// Good — package prefix identifies origin
var ErrNotFound = errors.New("mypackage: not found")
var ErrPermissionDenied = errors.New("mypackage: permission denied")
var ErrTimeout = errors.New("mypackage: operation timed out")
// Bad — bare strings lose origin when wrapped
var ErrNotFound = errors.New("not found")
```
### Error Types
Custom error types use the `Error` suffix:
```go
type PathError struct {
Op string
Path string
Err error
}
type SyntaxError struct {
Offset int64
msg string
}
```
### Error Strings
Error strings MUST be **fully lowercase — including acronyms** — and MUST NOT **end with punctuation**, because they are often printed following other context (`fmt.Errorf("parsing config: %w", err)`). Acronyms that would normally be capitalized in identifiers (`ID`, `URL`, `HTTP`) become lowercase in error strings.
```go
// Good — lowercase including acronyms, no punctuation
errors.New("image: unknown format")
errors.New("mypackage: invalid message id") // "id" not "ID"
errors.New("mypackage: invalid url") // "url" not "URL"
fmt.Errorf("decoding config: %w", err)
// Bad — capitalized, acronyms, punctuation
errors.New("Image: Unknown format.")
errors.New("mypackage: invalid message ID") // ID should be lowercase in error strings
fmt.Errorf("Failed to decode config: %w.", err)
```