====== GOLANG CODING CONVENTION ====== This document defines the coding conventions for projects written in Go (Golang). ===== Goals ===== * Improve readability and maintainability of the codebase * Ensure a consistent coding style across the team * Reduce friction in code reviews and onboarding * Leverage Go’s ecosystem and tools effectively These conventions apply to all Go code in this repository unless explicitly stated otherwise. ===== Table of Contents ===== * [[#general_principles|1. General Principles]] * [[#naming_conventions|2. Naming Conventions]] * [[#package_names|2.1 Package Names]] * [[#variables_functions_and_methods|2.2 Variables, Functions, and Methods]] * [[#structs_interfaces_and_exported_symbols|2.3 Structs, Interfaces, and Exported Symbols]] * [[#constants_and_acronyms|2.4 Constants and Acronyms]] * [[#general_naming_guidelines|2.5 General Naming Guidelines]] * [[#formatting|3. Formatting]] * [[#project_structure|4. Project Structure]] * [[#functions_and_methods|5. Functions and Methods]] * [[#error_handling|6. Error Handling]] * [[#comments_and_documentation|7. Comments and Documentation]] * [[#configuration_context_and_logging|8. Configuration, Context, and Logging]] * [[#batch_coding|9. Batch Coding]] * [[#testing|10. Testing]] * [[#tools_and_static_analysis|11. Tools and Static Analysis]] ===== 1. General Principles ===== * Prefer clarity over cleverness * Keep functions, types, and packages small and focused * Follow idiomatic Go practices References: * [[https://golang.org/doc/effective_go.html|Effective Go]] * [[https://go.dev/wiki/CodeReviewComments|Go Code Review Comments]] * Go standard library (fmt, net/http, context, time, strings, errors, io, etc.) When in doubt, idiomatic Go style takes precedence over personal preference. ===== 2. Naming Conventions ===== Identifiers starting with an uppercase letter are **exported**. Identifiers starting with a lowercase letter are **unexported**. ==== 2.1 Package Names ==== * Use lowercase names * Do not use CamelCase * Avoid underscores unless absolutely necessary Examples: * ``package user`` * ``package auth`` * ``package config`` File naming examples: * ``user_service.go`` * ``user_repository.go`` * ``http_handler.go`` ==== 2.2 Variables, Functions, and Methods ==== Use **camelCase** for unexported identifiers. var maxRetries = 3 func newUserRepo(db *sql.DB) *userRepo { return &userRepo{db: db} } type userRepo struct { db *sql.DB } ==== 2.3 Structs, Interfaces, and Exported Symbols ==== Use **PascalCase** for exported identifiers. type UserService struct { Repo UserRepository } func NewUserService(repo UserRepository) *UserService { return &UserService{Repo: repo} } type UserRepository interface { FindByID(ctx context.Context, id string) (*User, error) } ==== 2.4 Constants and Acronyms ==== Constants typically use PascalCase. const ( DefaultTimeout = 30 * time.Second HTTPTimeout = 10 * time.Second MaxRetries = 3 ) Common acronyms should be all caps. type HTTPServer struct{} type UserID string func NewJSONEncoder() JSONEncoder {} const HTTPTimeout = 10 * time.Second ==== 2.5 General Naming Guidelines ==== ; Types : Should be nouns or noun phrases : Examples: ``User``, ``Order``, ``UserService`` ; Functions and methods : Should be verbs or verb phrases : Examples: ``CreateUser``, ``ValidateToken`` ; Interfaces : Should, where appropriate, end with ``-er`` : Examples: ``Reader``, ``Writer``, ``UserRepository`` ; Short-lived or small scopes : Used in loops or short blocks : Examples: ``i``, ``j``, ``n``, ``err`` ; Longer-lived or wider scopes : Should use meaningful names : Examples: ``userID``, ``ctx``, ``cfg`` ===== 3. Formatting ===== * Always format code using ``gofmt`` or ``goimports`` * Tabs are used for indentation * Opening braces must be on the same line if condition { // ... } Import grouping example: import ( "context" "fmt" "net/http" "github.com/yourorg/yourproject/internal/user" ) ===== 4. Project Structure ===== . ├── cmd/ │ └── appname/ │ └── main.go ├── internal/ │ ├── domain/ │ ├── infrastructure/ │ ├── presentation/ │ ├── config/ │ ├── constant/ │ ├── validator/ ├── pkg/ ├── configs/ └── go.mod Guidelines: * ``cmd``: application entry points and wiring * ``internal``: non-public application code * ``pkg``: reusable libraries (if needed) ===== 5. Functions and Methods ===== * Functions should have a single responsibility * Avoid very long functions (over ~100 lines) * Prefer no more than 3 parameters Options struct example: type CreateUserOptions struct { Name string Email string Role string } func (s *UserService) CreateUser( ctx context.Context, opts CreateUserOptions, ) (*User, error) { // ... } Prefer early returns: if err != nil { return nil, err } ===== 6. Error Handling ===== Always handle errors immediately. user, err := s.repo.FindByID(ctx, id) if err != nil { return nil, err } Use ``errors.Is`` and ``errors.As``: if errors.Is(err, sql.ErrNoRows) { return nil, ErrUserNotFound } Error message rules: * Start with a lowercase letter * Do not end with a period * Be short and descriptive return fmt.Errorf("failed to save user: %w", err) ===== 7. Comments and Documentation ===== ==== 7.1 Doc Comments ==== Every exported identifier must have a doc comment. // UserService handles user-related operations. type UserService struct {} ==== 7.2 Comment the Why ==== Avoid comments that repeat code behavior. Bad: // Increase increases the counter by 1. func (c *Counter) Increase() { c.value++ } Good: // Increase increments the counter safely for concurrent use. func (c *Counter) Increase() {} ===== 8. Configuration, Context and Logging ===== ==== 8.1 Configuration ==== Centralize configuration loading and validation in ``internal/config``. ==== 8.2 context.Context ==== Rules: * Must be the first parameter * Must not be stored in struct fields * Must never be nil func (s *UserService) GetByID( ctx context.Context, id string, ) (*User, error) { // ... } ==== 8.3 Logging ==== Use ``log/slog`` for structured logging. slog.InfoContext(ctx, "user created", "user_id", userID) slog.ErrorContext(ctx, "failed to create user", "error", err) ===== 9. Batch Coding ===== Batch jobs must implement: Run(ctx context.Context, args []string) error Healthcheck example: type healthcheck struct{} func (h *healthcheck) Run(ctx context.Context, args []string) error { slog.InfoContext(ctx, "OK") return nil } ===== 10. Testing ===== * Use the ``testing`` package * Prefer table-driven tests * Use ``testify/assert`` for assertions * Use ``gomock`` for mocking * Suppress logs in tests Dependency injection example: func NewPointAddUsecase( repo IAddPointRepository, crm IYappliCRMClient, ) *PointAddUsecase { return &PointAddUsecase{ repo: repo, crm: crm, } } ===== 11. Tools and Static Analysis ===== ==== 11.1 gofmt ==== gofmt -w ./... ==== 11.2 goimports ==== Formats code and manages imports automatically. ==== 11.3 go vet ==== go vet ./... ==== 11.4 golangci-lint ==== Configured via ``.golangci.yml``. linters: enable: - govet - staticcheck - errcheck