Skip to content

Frequently Asked Questions

GoXercise is an interactive learning platform that teaches intermediate and advanced Go programming concepts through runnable code examples and exercises. Every code sample runs directly in your browser using the Go Playground, so you can experiment and learn without installing anything.

No! All code runs in your browser using the Go Playground API. However, for real-world development, we recommend installing Go locally. You can download it from go.dev.

How long does it take to complete the course?

Section titled “How long does it take to complete the course?”

The 14 chapters take approximately 6-8 hours total to read and understand. The 19 exercises add another 4-6 hours for hands-on practice. You can work at your own pace and your progress is automatically saved.

Yes! Your progress is saved in your browser’s localStorage. This means your progress persists across browser sessions, but it’s tied to your specific browser and device. You can also export your progress to continue on another device.

You should know basic Go syntax (variables, functions, structs) and have written simple Go programs. If you’re completely new to Go, start with the official Tour of Go first, then come back to GoXercise for intermediate and advanced topics.

Use interfaces when you need:

  • Abstraction: Hide implementation details behind a contract
  • Testability: Mock dependencies for unit testing
  • Multiple implementations: Accept different types that share behavior
  • Loose coupling: Depend on behavior, not concrete types

Keep interfaces small (1-3 methods) and define them where they’re used, not where they’re implemented.

What’s the difference between goroutines and threads?

Section titled “What’s the difference between goroutines and threads?”

Goroutines are lightweight (2KB initial stack) and managed by the Go runtime, not the OS. The Go scheduler multiplexes thousands of goroutines onto a few OS threads. This means:

  • You can easily run 100,000+ goroutines
  • Goroutines are cheaper to create and destroy
  • Context switching between goroutines is faster
  • Goroutines automatically grow their stack as needed

Threads are OS-level (1-2MB stack), require system calls to create, and are limited by OS resources (typically thousands, not millions).

How do I choose between sync.Mutex and channels?

Section titled “How do I choose between sync.Mutex and channels?”

Use mutexes when:

  • Protecting shared state within a struct
  • Performance is critical (mutexes are faster)
  • The critical section is very short
  • You need fine-grained locking

Use channels when:

  • Communicating between goroutines
  • Passing ownership of data
  • Coordinating work (pipelines, fan-out/fan-in)
  • The operation is naturally message-passing

Remember: “Share memory by communicating, don’t communicate by sharing memory.”

  1. Goroutine leaks - Not properly closing or canceling goroutines
  2. Forgetting to close channels - Causes deadlocks when ranging over channels
  3. Range over channels without close - Goroutine will block forever
  4. Pointer vs value receivers - Mixing them inconsistently on the same type
  5. Not handling errors - Ignoring err return values
  6. Overusing interfaces - Creating abstractions before they’re needed
  7. Deferring in loops - Deferred functions don’t run until function returns
  8. Map access without checking - Not checking if key exists before use

Use generics for:

  • Type-safe data structures (Stack[T], Set[T], Cache[K, V])
  • Algorithms that work with multiple types (Map, Filter, Reduce)
  • Reducing code duplication for similar functions

Don’t use generics when:

  • Interfaces work just as well (accept io.Reader, not Reader[T])
  • The code is simpler with concrete types
  • You’re just trying to use a new feature

Start with concrete types, refactor to generics only when duplication becomes painful.

Use pointers when:

  • Modifying the receiver in methods
  • The struct is large (>64 bytes guideline)
  • You need identity (same instance across calls)
  • Required by interfaces (e.g., sql.Scanner)

Use values when:

  • The type is small and cheap to copy
  • Immutability is important
  • Passing basic types (int, bool, string)

Be consistent: Use all pointer receivers or all value receivers on a type, not a mix.

Do:

  • Always check errors immediately: if err != nil { return err }
  • Wrap errors with context: fmt.Errorf("failed to open file: %w", err)
  • Use errors.Is() and errors.As() for error inspection
  • Create custom errors for package-specific errors
  • Return errors, don’t panic (except for truly unrecoverable situations)

Don’t:

  • Ignore errors
  • Use panic() for normal error handling
  • Log and return the same error (choose one)
  • Create error strings with capitalized messages

Currently, no. The Go Playground API requires an internet connection to execute code. The documentation pages can be viewed offline if you cache them, but code execution needs the playground API.

The Go Playground runs the latest stable version of Go (currently Go 1.21+). It’s updated regularly to match new Go releases.

How do I report bugs or suggest improvements?

Section titled “How do I report bugs or suggest improvements?”

Contact us at krimvp@goxercise.com with any bugs or suggestions. We welcome your feedback!

Are there any prerequisites for the exercises?

Section titled “Are there any prerequisites for the exercises?”

Each exercise lists its prerequisites in the frontmatter. Generally, you should complete the corresponding chapter before attempting the exercises. Some advanced exercises require knowledge from multiple chapters.

Yes! Each chapter is designed to be relatively self-contained, but later chapters build on concepts from earlier ones. Check the “Prerequisites” section at the top of each chapter.

Can’t find your answer here? Reach out to us:

We’re here to help you master Go programming!