| name | go |
| description | Apply Go style guide conventions to code |
| license | CC-BY-4.0 |
| compatibility | opencode |
| metadata | {"language":"go","source":"https://google.github.io/styleguide/go/","audience":"developers"} |
What I do
I help you write Go code that follows professional style guide conventions based on Google's Go Style Guide. This includes:
- Enforcing naming conventions (MixedCaps, mixedCaps)
- Applying proper documentation and commentary
- Managing imports correctly (grouping, ordering, renaming)
- Following formatting rules (gofmt compliant)
- Implementing error handling patterns
- Writing clear, simple, and maintainable code
- Applying concurrency best practices
- Structuring packages effectively
When to use me
Use this skill when:
- Writing new Go code that should follow style guide conventions
- Refactoring existing Go code to match best practices
- Reviewing Go code for style compliance
- Adding documentation to Go packages, functions, or types
- Organizing imports in Go files
- Designing APIs and interfaces
- Handling errors appropriately
Style Principles
Go style follows these core principles in order of importance:
- Clarity - The code's purpose and rationale is clear to the reader
- Simplicity - The code accomplishes its goal in the simplest way possible
- Concision - The code has a high signal-to-noise ratio
- Maintainability - The code can be easily maintained
- Consistency - The code is consistent with the broader codebase
Key style rules I enforce
Formatting
All Go source files must conform to gofmt output:
gofmt -w .
- No fixed line length (prefer refactoring over splitting)
- Use
MixedCaps or mixedCaps (never snake_case)
- Let the code speak for itself when possible
Naming Conventions
Packages:
package creditcard
package tabwriter
package oauth2
package credit_card
package tabWriter
package oAuth2
Functions and Methods:
package yamlconfig
func Parse(input string) (*Config, error)
func ParseYAMLConfig(input string) (*Config, error)
Variables:
- Short names in small scopes:
i, c, db
- Longer names in larger scopes:
userCount, databaseConnection
- Avoid type in name:
users not userSlice
Constants:
const MaxPacketSize = 512
const ExecuteBit = 1 << iota
const MAX_PACKET_SIZE = 512
const kMaxBufferSize = 1024
Initialisms:
Keep same case throughout:
func ServeHTTP(w http.ResponseWriter, r *http.Request)
func ProcessXMLAPI() error
var userID string
func ServeHttp()
func ProcessXmlApi()
var userId string
Receiver Names:
- Short (1-2 letters)
- Abbreviation of type
- Consistent across methods
func (c *Client) Get(url string) (*Response, error)
func (c *Client) Post(url string, body io.Reader) (*Response, error)
func (client *Client) Get(url string) (*Response, error)
func (this *Client) Post(url string, body io.Reader) (*Response, error)
Documentation
Package Comments:
package math
Function Comments:
func Join(elems []string, sep string) string
func Join(elems []string, sep string) string
Comment Sentences:
- Complete sentences for doc comments
- Capitalize and punctuate properly
- Start with the name being described
Imports
Import Grouping (separated by blank lines):
- Standard library packages
- Other (project and vendored) packages
- Protocol Buffer imports
- Side-effect imports
package main
import (
"fmt"
"hash/adler32"
"os"
"github.com/dsnet/compress/flate"
"golang.org/x/text/encoding"
foopb "myproj/foo/proto/proto"
_ "myproj/rpc/protocols/dial"
)
Import Renaming:
import (
foogrpc "path/to/package/foo_service_go_grpc"
foopb "path/to/package/foo_service_go_proto"
)
import (
foo "some/really/long/package/path"
)
Never use import dot (except in tests):
import . "foo"
import "foo"
Error Handling
Return errors, don't panic:
func Open(path string) (*File, error) {
f, err := os.Open(path)
if err != nil {
return nil, fmt.Errorf("open %s: %w", path, err)
}
return f, nil
}
func Open(path string) *File {
f, err := os.Open(path)
if err != nil {
panic(err)
}
return f
}
Error strings:
err := fmt.Errorf("something bad happened")
err := fmt.Errorf("Something bad happened.")
Handle errors:
if err := doSomething(); err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
_ = doSomething()
Indent error flow:
if err != nil {
return err
}
if err != nil {
} else {
}
Error wrapping:
return fmt.Errorf("process failed: %w", err)
return fmt.Errorf("process failed: %v", err)
Function Design
Keep signatures simple:
func (r *Reader) Read(p []byte) (n int, err error)
func WithTimeout(parent Context, d time.Duration) (ctx Context, cancel func())
func Process() (result int, err error) {
result = 42
return
}
Avoid repetition:
func (c *Config) WriteTo(w io.Writer) (int64, error)
func (c *Config) WriteConfigTo(w io.Writer) (int64, error)
Nil Slices
Prefer nil slices over empty slices:
var s []int
s := []int{}
if len(s) == 0 {
}
if s == nil {
}
Interfaces
Small interfaces:
type Reader interface {
Read(p []byte) (n int, err error)
}
type ReadWriter interface {
Reader
Writer
}
Accept interfaces, return structs:
func Process(r io.Reader) (*Result, error)
func Process(r *os.File) (*Result, error)
Concurrency
Document concurrency:
type Cache struct { ... }
type Client struct { ... }
Context usage:
func Process(ctx context.Context, data []byte) error
func (w *Worker) Run(ctx context.Context) error
Testing
Table-driven tests:
func TestParse(t *testing.T) {
tests := []struct {
name string
input string
want int
wantErr bool
}{
{name: "valid", input: "123", want: 123},
{name: "invalid", input: "abc", wantErr: true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Parse(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if got != tt.want {
t.Errorf("Parse() = %v, want %v", got, tt.want)
}
})
}
}
Test names:
func TestParse(t *testing.T)
func TestParse_InvalidInput(t *testing.T)
func TestClient_Get_Success(t *testing.T)
func TestParseFunction(t *testing.T)
func Test_Parse(t *testing.T)
Literal Formatting
Field names in structs:
r := csv.Reader{
Comma: ',',
Comment: '#',
FieldsPerRecord: 4,
}
okay := LocalType{42, "hello"}
Matching braces:
items := []*Item{
{Name: "foo"},
{Name: "bar"},
}
items := []*Item{
{Name: "foo"},
{Name: "bar"}}
Package Design
Package size:
- Not too large (thousands of lines in one package)
- Not too small (one type per package)
- Group related functionality
- Standard library is a good example
Avoid utility packages:
package util
package common
package helper
package cache
package auth
package stringutil
Common Patterns
Options Pattern
type Options struct {
Timeout time.Duration
Retries int
}
func NewServer(addr string, opts Options) *Server
type Option func(*Server)
func WithTimeout(d time.Duration) Option {
return func(s *Server) {
s.timeout = d
}
}
func NewServer(addr string, opts ...Option) *Server
Constructor Pattern
package widget
func New() *Widget
package widget
func NewWidget() *Widget
func NewGizmo() *Gizmo
Cleanup Pattern
func Open(name string) (*File, error)
f, err := os.Open(filename)
if err != nil {
return err
}
defer f.Close()
Least Mechanism
Prefer simpler constructs:
- Use core language features first (channels, slices, maps, loops)
- Then standard library (http.Client, template engine)
- Finally, external dependencies (only if necessary)
users := make(map[string]*User)
import "github.com/deckarep/golang-set"
users := mapset.NewSet()
How I work
When you ask me to help with Go code, I will:
- Analyze the code for style violations and clarity issues
- Suggest specific improvements citing relevant style principles
- Rewrite code sections to match professional Go style
- Add proper documentation following godoc conventions
- Format imports, grouping, and structure correctly
- Simplify complex code while maintaining correctness
- Apply idiomatic Go patterns and best practices
I prioritize clarity, simplicity, and maintainability. The goal is code that is easy to read, understand, and maintain.
References