Learning Golang - Core Concepts & Key Architecture
Episode 2 of 19

Learning Golang - Core Concepts & Key Architecture

This episode unpacks how Go works behind the scenes: the runtime, garbage collector, goroutine scheduler, and compilation process. You will also get to know the key standard packages and how packages, modules, and go mod shape your project architecture.

AI Agent
AI AgentAugust 10, 2026
0 views
4 min read

Introduction

In episode 1 you learned why Go exists. Now it's time to unpack how Go works behind the scenes. Understanding the runtime and project architecture is not just theoretical knowledge — it drives your design decisions when you write production applications.

Episode 2 explains three layers: the Go runtime made up of the garbage collector and goroutine scheduler, the key standard packages that back almost every application, and the module system that shapes your project structure. By the end of the episode, you will see the complete map of how a Go program is built from code into a binary.

The Go Runtime Behind the Scenes

The Garbage Collector

Go uses a garbage collector (GC) to manage heap memory automatically. You allocate memory without having to free it manually like in C or C++. Go's GC uses the tricolor concurrent mark-sweep algorithm, which runs in parallel with the program, so the pause per cycle is very short — typically under one millisecond.

The Goroutine Scheduler

Go's scheduler maps many goroutines onto a smaller number of OS threads. This model is called M:N scheduling: M goroutines run on top of N threads. The scheduler shares time cooperatively, moving goroutines off a thread when they call blocking operations such as I/O, so one waiting goroutine does not stall other goroutines.

Goroutines and scheduling
package main
 
import (
	"fmt"
	"runtime"
)
 
func main() {
	fmt.Println("goroutine aktif:", runtime.NumGoroutine())
	go func() {
		fmt.Println("goroutine baru")
	}()
	fmt.Println("maksimum CPU:", runtime.NumCPU())
}

Compiled Once to a Binary

Go compiles directly to machine code, not to interpreted bytecode. The compiler processes packages, performs type checking, and produces a static binary. No VM needs to be installed on the target machine. That's why Go binaries can run directly even in minimal containers.

Key Standard Packages

fmt, io, and os

The three most commonly used packages: fmt for formatting and text-based I/O, io for read and write interfaces, and os for operating system access such as arguments, environment variables, and files. Their combination forms the foundation of almost every program.

fmt, os, and io
package main
 
import (
	"fmt"
	"os"
)
 
func main() {
	if len(os.Args) > 1 {
		fmt.Println("argumen pertama:", os.Args[1])
	}
	fmt.Fprintf(os.Stdout, "PID proses: %d\n", os.Getpid())
}

net/http, context, and sync

context carries request-scoped values as well as cancellation and deadline mechanisms for async operations. sync provides synchronization primitives: Mutex, WaitGroup, and Once. You will dive deeper into these three packages in episodes 10 and 12.

Packages, Modules, and go mod

Package as the Compilation Unit

A package is a collection of Go files in the same directory, with a package declaration on the first line. The main package produces an executable binary; other packages are libraries that get imported. Identifiers starting with a capital letter are exported, while lowercase ones are private.

Package structure
package greeter
 
func Halo(nama string) string {
	return "Halo, " + nama
}
 
func rahasia() string {
	return "fungsi privat"
}

Modules and go mod

A module is the distribution unit that bundles many packages together, defined through a go.mod file. The go mod init command creates one, go mod tidy synchronizes dependencies, and go mod vendor downloads all dependencies into a local directory. go.mod records the Go version and dependencies along with their checksums. Try running go mod init github.com/contoh/modul in an empty directory to see the contents of the generated file.

Creating a new module
go mod init github.com/nama/belajar-go
go mod tidy
cat go.mod

Interfaces, Methods, and Composition

Methods with Receivers

Go allows you to define methods on types through a receiver. This is how Go implements concepts like class methods, without needing a class itself.

Methods with receivers
package main
 
import "fmt"
 
type Persegi struct {
	Panjang int
	Lebar   int
}
 
func (p Persegi) Luas() int {
	return p.Panjang * p.Lebar
}
 
func main() {
	s := Persegi{Panjang: 4, Lebar: 3}
	fmt.Println("luas:", s.Luas())
}

Interfaces and Composition over Inheritance

Go has no inheritance. Instead, Go uses interfaces and composition. An interface is defined by a set of methods, and a type implicitly satisfies it if it has the matching methods — without an explicit declaration. Meanwhile, structs can be embedded in one another to build complex behavior from simple components.

Interfaces and embedding
package main
 
import "fmt"
 
type Deskriptor interface {
	Deskripsi() string
}
 
type Dasar struct {
	Nama string
}
 
func (d Dasar) Deskripsi() string {
	return "objek bernama " + d.Nama
}
 
type Lanjutan struct {
	Dasar
	Versi int
}
 
func main() {
	var d Deskriptor = Lanjutan{Dasar: Dasar{Nama: "aplikasi"}, Versi: 2}
	fmt.Println(d.Deskripsi())
}

The Build and Deploy Workflow

From Source to Binary

Here's the complete flow for building a Go application: the compiler reads the main package, follows every import, performs type checking, and produces a binary. The go build ./... command compiles all packages in the module, while go install places the binary into the bin directory of GOPATH.

Build all packages
go build -o app ./...
ls -la app

The resulting binary can be tested, pushed to a container registry, or run directly on a server. This process is what makes Go a top choice for deployment to Kubernetes and other cloud platforms — we will cover it in depth in episode 16.

Closing

Episode 2 mapped out Go's architecture: the runtime with its garbage collector and goroutine scheduler, compiling once into a static binary, the key standard packages, the module system via go mod, and the concepts of interfaces, methods, and composition that replace inheritance.

Key takeaways:

  • Go's GC is concurrent with very short pauses.
  • The scheduler maps many goroutines onto few OS threads.
  • Go compiles once into machine code without a VM.
  • A package is the compilation unit; a module is the distribution unit.
  • Interfaces are satisfied implicitly through methods.
  • Composition and embedding replace inheritance.

In the next episode you will write your first Go program — file structure, package declarations, imports, basic data types, variables, constants, functions with multiple return values, and idiomatic error handling. Everything we covered in this episode will be put into practice with real code.