π§° Pro Tips for Writing Idiomatic Go
General Best Practices
-
π§ Follow Go naming conventions:
-
Exported names start with capital letters.
-
Keep names short and descriptive.
-
-
π Organize code by domain/package, not layers.
-
π§ͺ Always test! Use
testing
package and keep tests in*_test.go
files. -
βοΈ Use
go fmt
,go vet
, andgolangci-lint
.
1. π§ Code Design
-
β Keep functions small and focused β one responsibility per function.
-
π§ͺ Prefer pure functions when possible (no side effects).
-
π§± Use
struct
to represent entities with state. -
βοΈ Use methods with receivers when behavior depends on internal state.
-
π§© Use interfaces to decouple components and make testing easier.
- Define interfaces where they are used, not globally.
-
π Favor composition over inheritance.
-
πͺΆ Avoid unnecessary abstraction β Go values clarity over flexibility.
2. π¦ Data and Pointers
-
π Use pointers (
*Type
) when:-
You need to modify the original value.
-
You want to avoid copying large structs.
-
-
π Use values (
Type
) when:-
The data is small and immutable.
-
You want clear ownership (e.g.,
Log
struct in search results).
-
3. π§± Structs as βClassesβ
-
Use
struct
for data + methods with receiver when behavior belongs to the entity. -
Example:
type LogService struct { esClient ElasticSearchClient } func (s *LogService) Process(log Log) error { // logic using internal state }
4. π§© Interfaces
-
β Keep them small (1-2 methods).
-
π Define them at the consumer side, not producer.
-
Example:
type ElasticSearchClient interface { Index(ctx context.Context, index string, id string, body interface{}) error }
5. π§ Error Handling
-
Return
(result, error)
and handle errors immediately. -
Prefer clarity over cleverness:
res, err := doSomething()
if err != nil {
return nil, err
}
6. π Concurrency
-
π§΅ Use goroutines (
go func() { ... }()
) for async tasks. -
π‘ Use channels for safe communication between goroutines.
-
π Protect shared state with sync.Mutex or channel patterns.