|  | 
|  | 1 | +--- | 
|  | 2 | +description: Enforces best practices for Go development, focusing on context-aware code generation, modern patterns, and maintainable architecture. Provides comprehensive guidelines for writing clean, efficient, and secure Go code with proper context. | 
|  | 3 | +globs: **/*.go | 
|  | 4 | +--- | 
|  | 5 | +# Go Best Practices | 
|  | 6 | + | 
|  | 7 | +You are an expert in Go programming and related technologies. | 
|  | 8 | +You understand modern Go development practices, architectural patterns, and the importance of providing complete context in code generation. | 
|  | 9 | + | 
|  | 10 | +### Context-Aware Code Generation | 
|  | 11 | +- Always provide complete package context including imports and package declarations | 
|  | 12 | +- Include relevant configuration files (go.mod, go.sum) when generating projects | 
|  | 13 | +- Generate complete function signatures with proper parameters and return values | 
|  | 14 | +- Include comprehensive GoDoc comments explaining the purpose, parameters, and return values | 
|  | 15 | +- Provide context about the package's role in the larger system architecture | 
|  | 16 | +- Follow proper package organization and module structure | 
|  | 17 | + | 
|  | 18 | +### Code Style and Structure | 
|  | 19 | +- Follow Go style guide and clean code principles | 
|  | 20 | +- Structure code in logical packages following domain-driven design | 
|  | 21 | +- Implement proper separation of concerns (handlers, services, repositories) | 
|  | 22 | +- Use modern Go features (generics, error wrapping, context) appropriately | 
|  | 23 | +- Maintain consistent code formatting using gofmt | 
|  | 24 | +- Use proper interface design and composition | 
|  | 25 | +- Implement proper error handling with custom error types | 
|  | 26 | +- Use proper logging with structured data | 
|  | 27 | +- Use strict typing, avoid `any` or its analogues when possible | 
|  | 28 | +- Follow DRY, SOLID and KISS principles | 
|  | 29 | +- Write unit tests for all public/exported methods and functions | 
|  | 30 | +- Document functions, methods and logical blocks | 
|  | 31 | +- Critical code sections should always have a comment started with `ATTN:` and followed by explanation | 
|  | 32 | + | 
|  | 33 | +### Type System and Interfaces | 
|  | 34 | +- Use proper type definitions and interfaces | 
|  | 35 | +- Implement proper interface segregation | 
|  | 36 | +- Use proper type assertions and type switches | 
|  | 37 | +- Implement proper custom types and methods | 
|  | 38 | +- Use proper type embedding and composition | 
|  | 39 | +- Implement proper type constraints with generics | 
|  | 40 | +- Use proper type aliases when appropriate | 
|  | 41 | +- Implement proper type safety patterns | 
|  | 42 | + | 
|  | 43 | +### Testing and Quality | 
|  | 44 | +- Write comprehensive unit tests with proper test context | 
|  | 45 | +- Include integration tests for critical paths | 
|  | 46 | +- Use proper table-driven tests | 
|  | 47 | +- Implement proper test helpers and utilities | 
|  | 48 | +- Include performance tests for critical components | 
|  | 49 | +- Maintain high test coverage for core business logic | 
|  | 50 | +- Use proper test data factories | 
|  | 51 | +- Implement proper test doubles | 
|  | 52 | +- Use proper test organization with test packages | 
|  | 53 | + | 
|  | 54 | +### Dependency Injection | 
|  | 55 | +- Use constructor injection pattern for dependencies | 
|  | 56 | +- Define interfaces for all services and providers | 
|  | 57 | +- Implement providers in the infrastructure layer | 
|  | 58 | +- Wire up dependencies in the cmd layer | 
|  | 59 | +- Use functional options pattern for configurable components | 
|  | 60 | +- Keep service constructors simple and focused | 
|  | 61 | +- Avoid global state and singletons | 
|  | 62 | +- Use context.Context for request-scoped dependencies | 
|  | 63 | +- Inject tracer for distributed tracing | 
|  | 64 | +- Inject logger for structured logging | 
|  | 65 | +- Use closer.Closer for graceful shutdown | 
|  | 66 | +- Separate interface from implementation | 
|  | 67 | + | 
|  | 68 | +### Error Handling | 
|  | 69 | +- Domain-specific errors are to be separated (i.g. defined in `internal/domain/errors.go`) | 
|  | 70 | +- Use custom error types for domain-specific errors | 
|  | 71 | +- Always check errors and propagate them up the call stack | 
|  | 72 | +- Use meaningful error messages that describe what went wrong | 
|  | 73 | +- In API handlers (if any), map domain errors to appropriate HTTP status codes | 
|  | 74 | +- Use structured logging for errors with relevant context | 
|  | 75 | +- Don't expose internal errors to API clients | 
|  | 76 | +- Wrap errors with additional context when crossing layer boundaries | 
|  | 77 | +- Use sentinel errors for expected error conditions | 
|  | 78 | +- In workflows and activities, use appropriate error types for retryable vs. non-retryable errors | 
|  | 79 | + | 
|  | 80 | +### Error Prevention | 
|  | 81 | +- Always verify type consistency | 
|  | 82 | +- Check for potential NPE (Null Pointer Exception or its analogues) | 
|  | 83 | +- Validate against business rules | 
|  | 84 | +- Always ensure tracability - error handling and logging | 
|  | 85 | + | 
|  | 86 | +### Logging and Tracing Patterns | 
|  | 87 | +- Use structured logging with log fields | 
|  | 88 | +- Inject logger as a dependency | 
|  | 89 | +- Use appropriate log levels (debug, info, warn, error) | 
|  | 90 | +- Include relevant context in log messages | 
|  | 91 | +- Use OpenTelemetry for distributed tracing | 
|  | 92 | +- Inject tracer as a dependency | 
|  | 93 | +- Create spans for important operations | 
|  | 94 | +- Add attributes to spans for context | 
|  | 95 | +- Propagate trace context across service boundaries | 
|  | 96 | +- Use correlation IDs to link related operations | 
|  | 97 | +- Log errors with stack traces | 
|  | 98 | +- Implement proper error context | 
|  | 99 | +- Use middleware for request/response logging | 
|  | 100 | +- Implement proper log rotation and retention | 
|  | 101 | + | 
|  | 102 | +### Security and Performance | 
|  | 103 | +- Implement proper input validation and sanitization | 
|  | 104 | +- Use secure authentication and token management | 
|  | 105 | +- Configure proper CORS and CSRF protection | 
|  | 106 | +- Implement rate limiting and request validation | 
|  | 107 | +- Use proper caching strategies | 
|  | 108 | +- Optimize memory usage and garbage collection | 
|  | 109 | +- Implement proper error handling and logging | 
|  | 110 | +- Use proper data validation and sanitization | 
|  | 111 | +- Implement proper access control | 
|  | 112 | + | 
|  | 113 | +### API Design | 
|  | 114 | +- Follow RESTful principles with proper HTTP methods | 
|  | 115 | +- Use proper status codes and error responses | 
|  | 116 | +- Implement proper versioning strategies | 
|  | 117 | +- Document APIs using OpenAPI/Swagger | 
|  | 118 | +- Include proper request/response validation | 
|  | 119 | +- Implement proper pagination and filtering | 
|  | 120 | +- Use proper serialization and deserialization | 
|  | 121 | +- Implement proper rate limiting | 
|  | 122 | +- Use proper API authentication | 
|  | 123 | + | 
|  | 124 | +### Concurrency and Parallelism | 
|  | 125 | +- Use proper goroutine patterns | 
|  | 126 | +- Implement proper channel communication | 
|  | 127 | +- Use proper sync primitives | 
|  | 128 | +- Implement proper context cancellation | 
|  | 129 | +- Use proper worker pools | 
|  | 130 | +- Implement proper error handling in goroutines | 
|  | 131 | +- Use proper resource cleanup | 
|  | 132 | +- Implement proper backpressure | 
|  | 133 | +- Use proper concurrent data structures | 
|  | 134 | + | 
|  | 135 | +### Build and Deployment | 
|  | 136 | +- Use proper module management | 
|  | 137 | +- Implement proper CI/CD pipelines | 
|  | 138 | +- Use Docker for containerization | 
|  | 139 | +- Configure proper environment variables | 
|  | 140 | +- Implement proper logging and monitoring | 
|  | 141 | +- Use proper deployment strategies | 
|  | 142 | +- Implement proper backup strategies | 
|  | 143 | +- Use proper monitoring tools | 
|  | 144 | +- Implement proper error tracking | 
|  | 145 | + | 
|  | 146 | +### Examples | 
|  | 147 | + | 
|  | 148 | +```go | 
|  | 149 | +// Package user provides user-related operations. | 
|  | 150 | +// It handles user management and authentication. | 
|  | 151 | +package user | 
|  | 152 | + | 
|  | 153 | +import ( | 
|  | 154 | +	"context" | 
|  | 155 | +	"encoding/json" | 
|  | 156 | +	"errors" | 
|  | 157 | +	"fmt" | 
|  | 158 | +	"log" | 
|  | 159 | +) | 
|  | 160 | + | 
|  | 161 | +// UserService handles user-related operations. | 
|  | 162 | +type UserService struct { | 
|  | 163 | +	apiClient APIClient | 
|  | 164 | +	cache Cache | 
|  | 165 | +	logger *log.Logger | 
|  | 166 | +} | 
|  | 167 | + | 
|  | 168 | +// NewUserService creates a new UserService instance. | 
|  | 169 | +func NewUserService(apiClient APIClient, cache Cache, logger *log.Logger) *UserService { | 
|  | 170 | +	if logger == nil { | 
|  | 171 | +		logger = log.Default() | 
|  | 172 | +	} | 
|  | 173 | +	return &UserService{ | 
|  | 174 | +		apiClient: apiClient, | 
|  | 175 | +		cache: cache, | 
|  | 176 | +		logger: logger, | 
|  | 177 | +	} | 
|  | 178 | +} | 
|  | 179 | + | 
|  | 180 | +// FindUserByEmail finds a user by their email address. | 
|  | 181 | +// | 
|  | 182 | +// Parameters: | 
|  | 183 | +// - ctx: context for cancellation and timeouts | 
|  | 184 | +// - email: the email address to search for | 
|  | 185 | +// | 
|  | 186 | +// Returns: | 
|  | 187 | +// - *User: the user if found | 
|  | 188 | +// - error: any error that occurred | 
|  | 189 | +func (s *UserService) FindUserByEmail(ctx context.Context, email string) (*User, error) { | 
|  | 190 | +	// Check cache first | 
|  | 191 | +	cachedUser, err := s.cache.Get(ctx, fmt.Sprintf("user:%s", email)) | 
|  | 192 | +	if err == nil && cachedUser != "" { | 
|  | 193 | +		var user User | 
|  | 194 | +		if err := json.Unmarshal([]byte(cachedUser), &user); err == nil { | 
|  | 195 | +			return &user, nil | 
|  | 196 | +		} | 
|  | 197 | +	} | 
|  | 198 | + | 
|  | 199 | +	// Fetch from API | 
|  | 200 | +	user, err := s.apiClient.GetUser(ctx, email) | 
|  | 201 | +	if err != nil { | 
|  | 202 | +		s.logger.Printf("Failed to find user by email: %v", err) | 
|  | 203 | +		return nil, fmt.Errorf("failed to find user by email: %w", err) | 
|  | 204 | +	} | 
|  | 205 | + | 
|  | 206 | +	// Cache the result | 
|  | 207 | +	if user != nil { | 
|  | 208 | +		userJSON, err := json.Marshal(user) | 
|  | 209 | +		if err == nil { | 
|  | 210 | +			_ = s.cache.Set(ctx, fmt.Sprintf("user:%s", email), string(userJSON)) | 
|  | 211 | +		} | 
|  | 212 | +	} | 
|  | 213 | + | 
|  | 214 | +	return user, nil | 
|  | 215 | +} | 
|  | 216 | + | 
|  | 217 | +// Tests for UserService functionality. | 
|  | 218 | +func TestUserService_FindUserByEmail(t *testing.T) { | 
|  | 219 | +	tests := []struct { | 
|  | 220 | +		name string | 
|  | 221 | +		email string | 
|  | 222 | +		cacheResponse string | 
|  | 223 | +		apiResponse *User | 
|  | 224 | +		apiError error | 
|  | 225 | +		wantUser *User | 
|  | 226 | +		wantError bool | 
|  | 227 | +	}{ | 
|  | 228 | +		{ | 
|  | 229 | +			name: "user found in cache", | 
|  | 230 | +			email: "test@example.com", | 
|  | 231 | +			cacheResponse: `{"id":1,"email":"test@example.com"}`, | 
|  | 232 | +			wantUser: &User{ID: 1, Email: "test@example.com"}, | 
|  | 233 | +		}, | 
|  | 234 | +		{ | 
|  | 235 | +			name: "user found via API", | 
|  | 236 | +			email: "test@example.com", | 
|  | 237 | +			apiResponse: &User{ID: 1, Email: "test@example.com"}, | 
|  | 238 | +			wantUser: &User{ID: 1, Email: "test@example.com"}, | 
|  | 239 | +		}, | 
|  | 240 | +		{ | 
|  | 241 | +			name: "user not found", | 
|  | 242 | +			email: "nonexistent@example.com", | 
|  | 243 | +			apiResponse: nil, | 
|  | 244 | +			wantUser: nil, | 
|  | 245 | +		}, | 
|  | 246 | +		{ | 
|  | 247 | +			name: "API error", | 
|  | 248 | +			email: "test@example.com", | 
|  | 249 | +			apiError: errors.New("API error"), | 
|  | 250 | +			wantError: true, | 
|  | 251 | +		}, | 
|  | 252 | +	} | 
|  | 253 | + | 
|  | 254 | +	for _, tt := range tests { | 
|  | 255 | +		t.Run(tt.name, func(t *testing.T) { | 
|  | 256 | +			// Setup | 
|  | 257 | +			ctx := context.Background() | 
|  | 258 | +			apiClient := &mockAPIClient{ | 
|  | 259 | +				getUserResponse: tt.apiResponse, | 
|  | 260 | +				getUserError: tt.apiError, | 
|  | 261 | +			} | 
|  | 262 | +			cache := &mockCache{ | 
|  | 263 | +				getResponse: tt.cacheResponse, | 
|  | 264 | +			} | 
|  | 265 | +			service := NewUserService(apiClient, cache, nil) | 
|  | 266 | + | 
|  | 267 | +			// Execute | 
|  | 268 | +			user, err := service.FindUserByEmail(ctx, tt.email) | 
|  | 269 | + | 
|  | 270 | +			// Verify | 
|  | 271 | +			if tt.wantError { | 
|  | 272 | +				if err == nil { | 
|  | 273 | +					t.Error("expected error, got nil") | 
|  | 274 | +				} | 
|  | 275 | +				return | 
|  | 276 | +			} | 
|  | 277 | + | 
|  | 278 | +			if err != nil { | 
|  | 279 | +				t.Errorf("unexpected error: %v", err) | 
|  | 280 | +				return | 
|  | 281 | +			} | 
|  | 282 | + | 
|  | 283 | +			if !reflect.DeepEqual(user, tt.wantUser) { | 
|  | 284 | +				t.Errorf("got user %v, want %v", user, tt.wantUser) | 
|  | 285 | +			} | 
|  | 286 | +		}) | 
|  | 287 | +	} | 
|  | 288 | +} | 
0 commit comments