Agentic AI Engineering with Python: Live Course
Go

Introduction

Where Go came from, the problems it was designed to solve, and why it became the default language for modern infrastructure.

The problem Go was built to solve

In 2007, three engineers at Google were waiting for a build. Not a short wait either. The C++ codebase they worked on took long enough to compile that the wait had become part of the working day, something people planned around. Robert Griesemer, Rob Pike, and Ken Thompson started sketching a language during one of those waits, and the first sketch was mostly a list of complaints.

Their complaints were specific and they are worth listing, because every one of them explains a decision you will meet later in this course:

  • Builds were slow, and slow builds change how people work
  • Dependency management had grown tangled and unpredictable
  • Writing correct concurrent code was far harder than it needed to be
  • Every large codebase eventually developed its own private dialect of the language
  • Machines had many cores, but the languages in use were not built with that in mind

Go was announced publicly in November 2009 and reached version 1.0 in March 2012. That 1.0 release came with a compatibility promise that the team has honoured ever since, which is a large part of why Go code written a decade ago still compiles today.

What makes Go feel different

Most languages grow by adding features. Go grew by refusing them. The specification is short enough that a determined reader can finish it in an afternoon, and that shortness is the point rather than a limitation.

Compilation is fast enough to feel interactive

Go compiles to a single native binary, and it does it quickly. A medium sized service builds in a couple of seconds. This sounds like a minor convenience until you work in a codebase where it is true, and then discover how much of your previous workflow existed only to work around slow builds.

One binary, no runtime to install

go build produces a standalone executable with no interpreter, no virtual machine, and no shared library hunt on the target machine. You copy the file to a server and run it. This single property is why Go took over the deployment tooling world so completely.

Concurrency is part of the language

Goroutines and channels are not a library bolted on afterwards. They are keywords and built-in types, designed together with the scheduler that runs them. Starting a concurrent task costs one word:

go handleRequest(conn)

A goroutine starts with a few kilobytes of stack that grows as needed, so a single program can run hundreds of thousands of them. Threads in most other runtimes are far heavier, which is why other languages reach for thread pools and callback chains where Go simply starts another goroutine.

There is usually one way to write it

Go ships with gofmt, a formatter with no configuration options. There is no debate about brace placement or tab width, because there is nothing to debate. The effect on real teams is larger than it sounds: code review conversations move to logic instead of layout, and unfamiliar Go code looks like the code you already know.

A first taste

Here is a complete Go program that serves HTTP traffic. It uses no external dependencies at all.

package main

import (
    "fmt"
    "net/http"
)

func main() {
    http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
        fmt.Fprintf(w, "Hello from Go, you asked for %s\n", r.URL.Path)
    })

    http.ListenAndServe(":8080", nil)
}

Fourteen lines, standard library only, and it compiles to one file you can drop onto any Linux box. Every request is handled in its own goroutine automatically, so this server is concurrent without you writing a single line of concurrency code.

The tradeoffs, stated honestly

Go is opinionated, and some of those opinions will annoy you. It is better to meet them now than to discover them halfway through the course.

What people missWhy Go does it this way
No exceptionsErrors are returned as values, so failure paths are visible in the code rather than hidden in a stack
Verbose error checksif err != nil appears often, and the team accepted that repetition as the price of clarity
No inheritanceComposition and interfaces cover the same ground with fewer surprises
Generics arrived lateType parameters landed in Go 1.18 after years of deliberate resistance to a rushed design
Small standard idiomsFewer ways to express something means less to learn and less to argue about

The repetition in Go code is intentional. The language designers preferred a program that is boring to read and obvious to debug over one that is clever to write and hard to follow six months later. Once you have maintained a Go service for a while, this trade starts to feel like a gift.

Where Go ended up

Go was designed for Google's own systems, but its adoption pattern turned out to be broader and quite specific in shape. It dominates in places where a program needs to be small, fast to start, easy to deploy, and comfortable handling many things at once.

  • Infrastructure and DevOps. Docker, Kubernetes, Terraform, Prometheus, and etcd are all written in Go. If you work anywhere near cloud tooling, you are already using Go daily.
  • Backend APIs and microservices. Low memory use and fast startup make Go a natural fit for services that scale horizontally.
  • Command line tools. A single binary with no dependencies is the easiest thing in the world to distribute.
  • Networking and streaming systems. Proxies, gateways, message brokers, and anything that holds many connections open at once.
  • Cloud platforms. Go is a first class language on AWS, Google Cloud, and Azure, with well maintained SDKs.

Go compared to what you already know

If you are arriving from another language, this table gives you a rough translation of expectations rather than a scorecard.

Coming fromWhat will feel familiarWhat will surprise you
JavaStatic types, packages, tooling maturityNo classes, no inheritance, no exceptions, far less ceremony
PythonReadable syntax, fast to get startedCompilation, static types, explicit error handling
JavaScriptClosures, first class functionsNo event loop, real threads underneath, strict typing
C or C++Pointers, structs, close to the machineGarbage collection, no pointer arithmetic, memory safety

What is actually new to learn

Strip away the syntax you already know and the genuinely new material in Go is quite small:

Slices and how they share memory

Go's most used data structure has behaviour that trips up almost everyone once. It is worth understanding properly rather than by trial and error.

Implicit interfaces

A type satisfies an interface by having the right methods. There is no implements keyword and no declaration linking the two.

Errors as values

You will write if err != nil thousands of times, and the design ideas behind that habit are worth taking seriously.

Goroutines and channels

The part of Go that changes how you design programs, not just how you write them.

Almost every unusual thing about Go traces back to that original frustration with large scale software engineering. Fast compiles, single file deployment, language level concurrency, and a feature list that stays deliberately short. Keep that origin in mind and the rest of the language stops looking arbitrary.

Next, let's get your machine set up and put a running program in front of you.

How is this guide?

Last updated on