Go: Style, Decisions, and Best Practices
Google's style, decisions, and best practices guide for the Go language is a set of recommendations intended to promote clarity, simplicity, and efficiency in software developm...

Google’s style, decisions, and best practices guide for the Go language is a set of recommendations intended to promote clarity, simplicity, and efficiency in code development.
These guidelines help developers write readable and maintainable code, which is essential for long-term projects. In this article, we explore the main points covered in these documents, emphasizing the importance of consistency, maintenance, and collaboration within development teams.
1. Code Style
Maintaining a consistent code style is essential for team collaboration and project maintenance. It also makes code reviews and onboarding new team members easier.
1.1 Formatting
Use gofmt to ensure standardized formatting. Using this tool removes ambiguity around spacing, indentation, and code organization. In addition, it integrates easily with IDEs and CI/CD pipelines.
Additional best practices:
Avoid lines longer than 80 characters to improve readability.
Use spaces instead of tabs to ensure compatibility across different editors.
Example:
// Formatação correta
func Add(a int, b int) int {
return a + b
}
// Formatação incorreta
func Add(a int, b int) int {
return a + b // Errado: indentacão incorreta
}
1.2 Naming Conventions
Names for variables, functions, and packages should be clear and descriptive, reflecting their responsibilities. This improves maintainability and reduces the need for extensive comments.
Main rules:
camelCase: Use for variables, functions, and internal arguments.
PascalCase: Use for exported functions, structures, and constants.
snake_case: Avoid this pattern in Go code.
Packages should use short lowercase names, without underscores.
Example:
// Correto
func CalculateSum(a int, b int) int {
total := a + b
return total
}
// Errado
func calculatesum(a int, b int) int {
total := a + b
return total
}
Package names:
// Correto
package mathutils
// Errado
package math_utils
1.3 Comments
Add explanatory comments that describe the “why” rather than the “how”. Excessive or redundant comments should be avoided. For exported functions, follow Go’s standard format, where the comment begins with the function name.
Best practices:
Use docstrings for packages and important functions.
Comments should be updated whenever code behavior changes.
Example:
// CalculateSum soma dois inteiros e retorna o resultado.
func CalculateSum(a int, b int) int {
return a + b
}
// Comentário redundante e desnecessário
// A função retorna a soma de dois inteiros
func Sum(a, b int) int {
return a + b
}
2. Design Decisions
Clear decisions about project organization and use of language features help avoid confusion, bugs, and rework. A well-thought-out design also makes it easier to expand the project in the future.
2.1 Project Structure
Code organization should be modular, intuitive, and reflect the system’s main goals. Adopt a directory structure that favors separation of concerns.
Guidelines:
Avoid generic packages such as
utilswhenever possible. Prefer specific names.Keep
main.goclean and delegate logic to other packages.Use patterns such as
internal/for code that should not be accessed outside the repository.
Suggested structure:
project/
cmd/
app/
main.go
mathutils/
math.go
internal/
db/
connection.go
2.2 Interfaces
Interfaces are most effective when they are small and represent a single responsibility. This allows greater implementation flexibility and makes testing easier.
Principles:
Avoid adding methods to an interface before they are needed.
Use composition to create more complex interfaces.
Example:
// Correto
type Reader interface {
Read(p []byte) (n int, err error)
}
// Composição de interfaces
type ReadWriter interface {
Reader
Write(p []byte) (n int, err error)
}
// Errado: Interface genérica e inflexível
type Service interface {
Start()
Stop()
Restart()
}
2.3 Dependency Control
Dependency management is crucial for maintaining project security and stability. Use go mod to manage dependencies efficiently.
Best practices:
Update dependencies regularly and test carefully before merging.
Use tools such as
dependabotto monitor updates.
Example:
module example.com/project
go 1.20
require (
github.com/pkg/errors v0.9.1
)
3. Best Practices
3.1 Error Handling
Error management in Go is designed to be simple and explicit. Always handle errors immediately or propagate them with additional context.
Tips:
Use
errors.Isanderrors.Asto check and unwrap errors.Standardize error messages to make debugging easier.
Example:
if err := doSomething(); err != nil {
if errors.Is(err, ErrSpecific) {
return fmt.Errorf("erro especifico: %w", err)
}
return fmt.Errorf("erro genérico: %w", err)
}
3.2 Concurrency
Go’s built-in support for concurrency is one of its greatest strengths. However, common mistakes such as Goroutine leaks or unsynchronized concurrent accesses should be avoided.
Useful tools:
sync.WaitGroupto wait for multiple Goroutines.sync.Mutexto protect critical sections.context.Contextto cancel Goroutines.
Example with Context:
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()
ch := make(chan int)
go func() {
defer close(ch)
for i := 0; i < 5; i++ {
select {
case <-ctx.Done():
return
case ch <- i:
}
}
}()
for val := range ch {
fmt.Println(val)
}
3.3 Logging
Structured logs help with monitoring and diagnosing production issues. Prefer libraries such as log/slog for richer and more configurable logs.
Example:
package main
import (
"log/slog"
)
func main() {
// Criando um logger padrão
logger := slog.Default()
// Registrando uma mensagem de informação com campos
logger.Info("iniciando operação",
slog.Int("valor", 42),
slog.String("status", "inicializado"))
}
3.4 Testing
Adopt TDD (Test-Driven Development) whenever possible. Use subtests to split complex tests into smaller parts, and mock modules to simulate external dependencies.
Example with mocks:
type MockService struct {}
func (m *MockService) Process(data string) error {
if data == "error" {
return errors.New("mock error")
}
return nil
}
func TestService(t *testing.T) {
service := &MockService{}
err := service.Process("error")
if err == nil {
t.Fatalf("esperava erro, mas obteve nil")
}
}
In short, Google’s recommended style, decisions, and best practices guides for Go are fundamental to ensuring that code is clear, concise, and easy to maintain. Following these guidelines not only improves code quality, but also makes collaboration easier on development teams. These practices promote consistency and readability, essential elements for successful long-term projects. For more information, see the full resources on the official site.


