Skip to content

Go Conventions

All Amadla tools and libraries follow idiomatic Go coding conventions.

Naming

Interfaces

Interfaces use descriptive concept names — no I prefix:

type Git interface {
    Clone(url string) error
    Pull() error
}

type File interface {
    Read(path string) ([]byte, error)
    Write(path string, data []byte) error
}

Structs

Implementation structs are unexported — no S prefix:

type gitImpl struct {
    url      string
    repoPath string
}

type fileImpl struct {
    basePath string
}

Constructors

Constructor functions follow the New() pattern and return the interface type. Use New() when there is one primary type per package:

func New(url, repoPath string) Git {
    return &gitImpl{
        url:      url,
        repoPath: repoPath,
    }
}

This pattern enables dependency injection and mocking.

Mocks

Mocks are generated by mockery and follow the Mock* naming with mock_*.go files:

type MockGit struct {
    mock.Mock
}

Dependency Injection

Package-Level Function Variables

OS and system calls are assigned to package-level variables so tests can replace them:

// Production code
var osOpen = os.Open
var execCommand = exec.Command

func readFile(path string) ([]byte, error) {
    f, err := osOpen(path)
    // ...
}
// Test code
func TestReadFile(t *testing.T) {
    osOpen = func(name string) (*os.File, error) {
        return nil, errors.New("mock error")
    }
    defer func() { osOpen = os.Open }()
    // ...
}

Interface-Based Injection

Services accept interfaces in constructors, enabling mock injection:

type entity struct {
    git    Git
    cache  Cache
    schema Schema
}

func New(git Git, cache Cache, schema Schema) Entity {
    return &entity{git: git, cache: cache, schema: schema}
}

Error Handling

  • Use typed errors in message/ packages
  • Wrap errors with context: fmt.Errorf("failed to clone repo: %w", err)
  • Return errors up the call stack; handle at command level

Code Organization

  • One interface + implementation per file (named after the interface)
  • Tests alongside implementation: git.go + git_test.go
  • Mocks generated in-package: mock_*.go