LearningTech

Interview Questions & Answers

Comprehensive questions covering Go, CLI, System Design, Algorithms, and Cloud.

A. Go Language Basics

1. What is Go programming language, and why is it used? +

Go (Golang) is an open-source, statically typed, compiled programming language created at Google.

Used for: High-performance backend services, Cloud-native applications, Microservices, Concurrency-heavy systems, CLI tools, DevOps tools.

Why popular: Extremely fast compilation, Built-in concurrency (goroutines & channels), Simple syntax, No inheritance complexity, Excellent standard library.

Tip: Go is ideal for distributed systems and scalable cloud architecture.

2. How do you implement concurrency in Go? +

Using:

  • Goroutines: Lightweight threads managed by Go runtime.
  • Channels: Safe communication pipes between goroutines.
  • sync.WaitGroup: Waiting for a collection of goroutines to finish.
  • sync.Mutex: Locking mechanisms for shared data.
go func() {
    fmt.Println("Running in goroutine")
}()
3. How do you handle errors in Go? +

Go uses explicit error return values, not exceptions.

val, err := someFunc()
if err != nil {
    return err
}

Advanced: Use fmt.Errorf() with %w for wrapping, and errors.Is()/errors.As() for checking types.

4. How do you implement interfaces in Go? +

Interfaces are implicitly implemented. If a type provides the methods derived in the interface, it implements it (Duck Typing).

type Animal interface {
    Speak() string
}
// Dog implicitly implements Animal by having Speak()
func (Dog) Speak() string { return "Woof" }
5. How do you optimize the performance of Go code? +
  • Use goroutines for parallel execution.
  • Avoid unnecessary memory allocations (use pointers for large structs).
  • Use sync.Pool for object reuse to relieve GC pressure.
  • Prefer slices over arrays.
  • Minimize locking scope or prefer atomic operations.
  • Use buffered I/O.

Tools: go test -bench ., pprof (profiling), go build -gcflags "-m" (escape analysis).

6. What is the role of the init() function in Go? +
  • Automatically executed before main().
  • Used for package-level setup, initialization, or configuration.
  • Cannot be called manually.
  • A file/package can have multiple init functions.
7. What are dynamic and static types of variable declaration? +

Static: Explicit type declaration.

var age int = 10

Dynamic (Inference): Type inferred from value.

age := 10

B. Go Input / CLI Handling

8. How to read multiple inputs in Go? +

Using fmt.Scan (space-separated) or bufio (buffered IO).

var name string
var age int
fmt.Scan(&name, &age)
9. How to validate user input? +

Check values immediately after reading.

if age < 0 {
    fmt.Println("Invalid age")
}
10. How to loop input until valid? +
for {
    fmt.Print("Enter age: ")
    fmt.Scan(&age)
    if age > 0 { break }
}
11. How to build a mini CLI app? +

Use os.Args for raw arguments, flag for parsing flags, or libraries like Cobra/Viper for robust tools.

name := flag.String("name", "Guest", "User name")
flag.Parse()
fmt.Println("Hello", *name)

C. Code Explanations

12. Why does VS Code add package golangtestprojects? +

VS Code's Go extension auto-generates the package name based on the folder name you opened. If you opened a folder named golangtestprojects, it assumes that is the package.

13. Explain this bufio code snippet +
reader := bufio.NewReader(os.Stdin)
name, _ := reader.ReadString('\n')
name = strings.TrimSpace(name)

Explanation:

  1. Creates a buffered reader connected to Standard Input.
  2. Reads input bytes until it hits a newline character (Enter key).
  3. strings.TrimSpace removes the trailing newline and any surrounding whitespace.
14. Why is new user not added to JSON file? +

Common Mistake: Checking or writing to the wrong filename definition (e.g., user.json vs users.json).

D. Go CLI Features

15. Flag-based CLI +

The flag package parses command-line arguments like --port=8080.

port := flag.String("port", "8000", "Server port")
flag.Parse()
fmt.Printf("Starting on %s\n", *port)
16. Cobra/Viper based CLI +

Cobra is the standard for modern Go CLIs (used by Kubernetes, Docker). It manages commands, subcommands, and flags.

Viper handles configuration management (JSON/YAML files, env vars).

17. CLI with colors & spinners +

Enhance UX using libraries:

  • github.com/fatih/color: color.Red("Error!")
  • github.com/briandowns/spinner: Show activity during long tasks.
18. Save users to JSON file +

Use json.MarshalIndent for pretty-printing data to storage.

data, _ := json.MarshalIndent(users, "", "  ")
os.WriteFile("users.json", data, 0644)
19. CRUD operations using JSON +

Flow: Read File -> Unmarshal to Struct Slice -> Modify Slice (Append/Delete) -> Marshal -> Write Back.

20. Go + MySQL CLI app +

Use the database driver to connect.

import _ "github.com/go-sql-driver/mysql"
db, _ := sql.Open("mysql", "user:pass@/dbname")
21. Token-based menu system +

State management in CLI: Variables hold the "logged in" state (token/user struct). The main loop renders different options based on this state.

22. CLI with concurrency +

Run background tasks without blocking the UI/Input loop.

go func() {
    performBackgroundSync()
}()
// Main CLI loop continues here...

E. Data Structures & Algorithms

23. Count subarrays with product < k (Sliding Window) +

Problem: Given nums[] and k, find number of contiguous subarrays having product less than k.

Algorithm: Sliding Window. Expand right pointer, multiply product. If product >= k, shrink left pointer until valid. Add right - left + 1 to count.

24. Why does sliding window work here? +
  • Product of positive numbers increases as window expands.
  • If a window [left, right] is valid, then all subarrays ending at right within that window are also valid.
  • This reduces complexity from O(N³) to O(N).

F. Go Advanced Questions

25. What is a Goroutine vs Thread? +

Goroutine: Managed by Go runtime, starts with small stack (2KB), grows dynamically, multiplexed onto OS threads.

Thread: Managed by OS, fixed large stack (1MB+), expensive context switch.

26. What are Channels? +

Typed conduits for synchronization and data transfer between goroutines.

ch := make(chan int)
go func() { ch <- 10 }() // Send
val := <-ch              // Receive
27. Buffered vs Unbuffered Channels +

Unbuffered: make(chan int). Synchronous. Sender blocks until Receiver performs receive.

Buffered: make(chan int, 3). Asynchronous until buffer is full. Sender only blocks if buffer is full.

28. Select Statement +

Like a switch for channels. Blocks until one of its cases (send/receive) can proceed. Used for handling timeouts or multiple data sources.

29. How does Go’s Garbage Collector work? +

It uses a concurrent, tri-color mark-and-sweep algorithm. It is optimized for low latency (short stop-the-world pauses) rather than raw throughput.

30. Slice vs Array +

Array: Fixed length, value type (copying copies entire array).

Slice: Dynamic length, reference type (pointer to underlying array).

31. Preventing concurrent map writes +

Maps are not safe for concurrent use. Use sync.Mutex to lock before access, or use sync.Map for specific high-concurrency read-heavy cases.

32. Embedding vs Inheritance +

Go favors Composition. Embedding a struct allows utilizing its methods, but it's not "is-a" relationship, it's "has-a" with syntax sugar.

type Car struct { Engine } // Car promotes methods of Engine
33. go mod & module management +

go mod init creates a new module. go.mod tracks dependencies and versions, replacing the old GOPATH system.

34. Use of defer +

Schedules a function call to be run after the surrounding function returns. Executed in LIFO order. Common for cleanup (closing files, unlocking mutexes).

35. Panic vs Recover +

Panic: Stops normal execution, unwinds stack, runs deferred functions. Used for unrecoverable errors.

Recover: Regains control of a panicking goroutine. Only works inside defer.

36. Memory Alignment +

The CPU reads data in word-sized chunks. Go struct fields are aligned to these boundaries. Proper ordering of struct fields (largest to smallest) can save memory by reducing padding.

37. Context Package +

Used to carry deadlines, cancellation signals, and request-scoped values across API boundaries and between processes.

Advanced: Golang & Concurrency

38. Escape analysis impact +

Determines if variables should be on stack or heap. Heap allocation causes GC pressure. Optimization: Keep variables on stack (don't return pointers to local vars if not needed) to reduce GC overhead.

39. Rate-limited HTTP client +

Use golang.org/x/time/rate.Limiter or a Token Bucket implementation. Call Wait(ctx) before making a request.

Advanced: Architecture

40. Hexagonal Architecture (Ports & Adapters) +

Separates Domain Logic (core) from Infrastructure (DB, UI, API). Dependencies point inward. Adapters implement Port interfaces.

41. API Gateway Patterns +

Handles AuthN/AuthZ, Rate Limiting, Routing, Protocol Translation (REST <-> gRPC). Keep logic minimal; don't put business logic in the gateway.

42. SAGA Pattern +

Manages distributed transactions. Choreography: Events trigger next step. Orchestration: Central coordinator tells services what to do. Use compensating transactions for rollback.

Advanced: Real-Time Systems

43. Backpressure +

Prevents system overwhelm. mechanisms: Drop messages, Buffer (Queue), or Reject new work (Rate Limit). In Go: limit goroutines or use blocking channel sends.

44. Kafka Ordering +

Guaranteed only within a partition. Use the same Partition Key for related events (e.g., same UserID) to ensure sequential processing.

Advanced: Cloud & AWS

45. EC2 vs Lambda +

EC2: Persistent, control over OS, good for long-running, steady-state apps.

Lambda: Event-driven, ephemeral, scales to zero, good for bursty traffic or glue code.

46. High Availability Multi-Region +

Active-Active (complex data sync) or Active-Passive (easier). Use Global Load Balancer (Route53), Replicated DBs (DynamoDB Global Tables, Aurora Global), and stateless app tiers.