go
Write Go code following best practices. Use when developing Go applications. Covers error handling, concurrency, and project structure.
When & Why to Use This Skill
This Claude skill empowers developers to build high-quality Go (Golang) applications by providing idiomatic code generation and architectural guidance. It ensures adherence to industry best practices for project structuring, robust error handling, efficient concurrency management, and comprehensive testing, enabling the creation of scalable and maintainable production-ready software.
Use Cases
- Bootstrap a production-ready Go project structure using the standard layout (cmd, internal, pkg) to ensure long-term maintainability.
- Implement sophisticated error handling strategies, including custom error types and error wrapping, to improve application observability and debugging.
- Design and deploy safe concurrent processes using goroutines, channels, and errgroup to maximize performance and resource utilization.
- Generate idiomatic HTTP handlers and middleware for RESTful APIs, ensuring consistent request processing and standardized JSON responses.
- Develop robust unit tests using table-driven testing patterns and Go's native testing package to ensure high code reliability and coverage.
| name | go |
|---|---|
| description | Write Go code following best practices. Use when developing Go applications. Covers error handling, concurrency, and project structure. |
| allowed-tools | Read, Write, Edit, Bash, Glob, Grep |
Go Development
Project Structure
myproject/
├── cmd/
│ └── server/
│ └── main.go
├── internal/
│ ├── handler/
│ ├── service/
│ └── repository/
├── pkg/
│ └── shared/
├── go.mod
└── go.sum
Error Handling
// Custom error types
type NotFoundError struct {
Resource string
ID string
}
func (e *NotFoundError) Error() string {
return fmt.Sprintf("%s not found: %s", e.Resource, e.ID)
}
// Error wrapping
func GetUser(id string) (*User, error) {
user, err := db.FindUser(id)
if err != nil {
return nil, fmt.Errorf("GetUser(%s): %w", id, err)
}
return user, nil
}
// Error checking
if errors.Is(err, sql.ErrNoRows) {
return nil, &NotFoundError{Resource: "user", ID: id}
}
Concurrency
// Goroutines with errgroup
func fetchAll(ctx context.Context, urls []string) ([]Response, error) {
g, ctx := errgroup.WithContext(ctx)
results := make([]Response, len(urls))
for i, url := range urls {
i, url := i, url // capture loop variables
g.Go(func() error {
resp, err := fetch(ctx, url)
if err != nil {
return err
}
results[i] = resp
return nil
})
}
if err := g.Wait(); err != nil {
return nil, err
}
return results, nil
}
// Channels
func producer(ch chan<- int) {
for i := 0; i < 10; i++ {
ch <- i
}
close(ch)
}
func consumer(ch <-chan int) {
for v := range ch {
fmt.Println(v)
}
}
HTTP Handler
func (h *Handler) GetUser(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := chi.URLParam(r, "id")
user, err := h.service.GetUser(ctx, id)
if err != nil {
var notFound *NotFoundError
if errors.As(err, ¬Found) {
http.Error(w, err.Error(), http.StatusNotFound)
return
}
http.Error(w, "Internal error", http.StatusInternalServerError)
return
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(user)
}
Testing
func TestGetUser(t *testing.T) {
t.Parallel()
tests := []struct {
name string
id string
want *User
wantErr bool
}{
{
name: "existing user",
id: "123",
want: &User{ID: "123", Email: "test@example.com"},
},
{
name: "non-existent user",
id: "999",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := service.GetUser(context.Background(), tt.id)
if (err != nil) != tt.wantErr {
t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("got = %v, want %v", got, tt.want)
}
})
}
}
Tooling
# Format
gofmt -w .
goimports -w .
# Lint
golangci-lint run
# Test
go test -v -race -cover ./...