Code review in Go: what to check and how to give feedback to beginners

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Code review in Go: what to check and how to give feedback

\n

Code review is not just a formal check before merging a pull request. It is a powerful tool for improving code quality, sharing knowledge within the team, and preventing errors at early stages. For beginner Go developers, participating in a review can seem stressful: it's scary to receive comments or, conversely, to miss a critical error. In this article, we will break down what to pay attention to when reviewing Go code, and how to give feedback so that it is useful, not offensive.

\n\n

Why is code review especially important in Go?

\n

The Go language was designed with a focus on simplicity, readability, and reliability. However, the simplicity of the syntax does not eliminate the complexity of the logic. Typical problems in Go projects: ignoring errors, incorrect work with goroutines, resource leaks. A good code review helps identify these and other issues before they reach production.

\n\n

What to check in Go code: a checklist for beginners

\n

To make the review systematic, use a checklist. Here are the main points to check in every pull request.

\n\n

1. Error handling

\n

In Go, errors are values; they cannot be ignored. Check that every function returning error handles it or explicitly passes it up the call stack.

\n
// Bad: ignoring the error\nfile, _ := os.Open("config.yaml")\n\n// Good: handling the error\nfile, err := os.Open("config.yaml")\nif err != nil {\n    log.Fatalf("cannot open config: %v", err)\n}\ndefer file.Close()
\n

Also check that errors are wrapped using fmt.Errorf("...: %w", err) to pass context, rather than just being logged and swallowed.

\n\n

2. Naming and readability

\n

In Go, short names are used for variables (e.g., r for reader, w for writer) and long names for exported functions. Check that:

\n
    \n
  • Exported functions, types, and variables have comments (starting with the entity's name).
  • \n
  • Variable names reflect their purpose (not a, b, tmp).
  • \n
  • There are no unnecessary abbreviations (calc is better replaced with calculate).
  • \n
\n\n

3. Working with goroutines and concurrency

\n

Goroutines are a powerful but dangerous tool. Check:

\n
    \n
  • Is there a synchronization mechanism (channels, mutexes) for shared data.
  • \n
  • Are there any "leaking" goroutines (goroutine leak). Use context (context.Context) for cancellation.
  • \n
  • Is a goroutine blocked forever (deadlock).
  • \n
\n
// Example of safe work with a goroutine\nfunc worker(ctx context.Context, jobs <-chan int, results chan<- int) {\n    for {\n        select {\n        case job, ok := <-jobs:\n            if !ok {\n                return\n            }\n            results <- job * 2\n        case <-ctx.Done():\n            return\n        }\n    }\n}
\n\n

4. Resource management (defer)

\n

Check that all opened files, network connections, and database transactions are closed using defer. This should be done immediately after successfully opening the resource.

\n
// Correct: close immediately\nconn, err := net.Dial("tcp", "example.com:80")\nif err != nil {\n    return err\n}\ndefer conn.Close()
\n\n

5. Testing

\n

Beginners often forget about tests. Ensure that unit tests are written for new logic. Check:

\n
    \n
  • Tests cover not only the happy path but also edge cases.
  • \n
  • Is t.Run used for subtests.
  • \n
  • Are there any tests that depend on external resources (DB, network) without mocks.
  • \n
\n\n

How to give feedback: 5 rules for beginners

\n

The technical part is half the battle. The other half is the ability to communicate. Here a

Blogs

Book Recommendations