Go: Simplicity by Design

Jul 03, 2024

Go, developed at Google by industry veterans Rob Pike, Ken Thompson, and Robert Griesemer, released in 2012. Despite initial scrutiny due to its perceived simplicity, Go has gained popularity for addressing key issues in software development

  • Readability
  • Fast compilation
  • Controlled dependencies
  • Cross-environment builds

Go intended to address these issues and more at the language level.

Key language features

Concise language grammar

With only 25 keywords (compared to C's 60 and C++20's 97), Go offers a low barrier to entry while remaining powerful enough to compete with C/C++ in certain domains like web servers.

Streamlined syntax

Go's syntax prioritizes readability and consistency. For example, the versatile for loop can also simulate while loops and infinite loops:

// standard C-style for loop
for i := 5; i > 0; i-- {
    fmt.Println(i)
}

// while loop
i := 5
for i > 0 {
    fmt.Println(i)
    i--
}

// infinite loop
for {
    fmt.Println("I'm infinite!")
}

Go's if statements have also been enhanced with the option to include a short statement before the condition is evaluated, scoped to the if-else block:

if num, err := strconv.Atoi(str); err != nil {
    fmt.Println("Error: ", err)
} else {
    fmt.Println("Integer value of string: ", num)
}
// num and err cannot be referenced after its scope

Resource management

Go's defer keyword ensures proper resource cleanup once the scope in which it was created has terminated:

file, err := os.Open("example.txt")
if err != nil {
    fmt.Println("Error: ", err)
    return
}
defer file.Close()
// file will be closed when this scope is terminated

Error handling

Go uses explicit error returns instead of exceptions:

file, err := os.Open("example.txt")
// os.Open returns a value of type (*File, *PathError)
if err != nil {
    return fmt.Errorf("something went wrong: %w", err)
}
defer file.Close()
// use file

This approach encourages immediate error handling and avoids complex try-catch structures. You essentially build a stack trace as the error gets propagated up the call stack, which can then be logged.

Built-in concurrency

Go's goroutines and channels make concurrent programming straightforward. Goroutines offer lightweight threads and channels provide communication across threads:

resultChan := make(chan int)
// spawn goroutine
go func() {
    // perform some calculation
    resultChan <- value
}()
// block thread until something can be read from the channel
value := <-resultChan

These features combine to create a language that's easy to learn, read, and maintain, without sacrificing power or efficiency.

Go's efficiency

Simplified dependencies

Go addresses the complex dependency issues of languages like C and C++ with a streamlined approach. The compiler only looks at package object files, not source files. This reduces redundant I/O and processing operations, resulting in significantly faster compile times.

Let's look at an example. Package A imports package B which imports package C. First C is compiled. Next B is compiled, pulling in necessary information from C into its object file. Finally, A is compiled, only needing to look at one file, the object file for B. 

Static and cross-compilation

Go is statically compiled. This means all imported packages, including the standard library, are compiled together into a single binary. Go can also cross-compile to target different operating systems and architecture combinations using the GOOS and GOARCH environment variables.

For example, if I develop on MacOS and/or Windows and want to deploy to an AWS T3 instance which runs Linux with x86 architecture, I could build my binary like this:

GOOS=linux GOARCH=amd64 go build myapp

These features make Go applications easy to deploy and makes "it works on my machine" issues less common.

The future of Go

The Go team has committed to backwards compatibility. No breaking changes in future versions ensures long-term stability and easy maintenance of legacy code.

Go has been adopted by major companies for various application: Docker, Kubernetes, and Terraform are built with Go. Companies like Google, Netflix, Paypal, an Uber use Go internally.

Go's simplicity, efficiency, and stability make it an attractive option for developers tackling complex problems. As the language continues to grow, it's becoming an increasingly valuable tool in the software development ecosystem.