I started learning Go to build CLI tools and small network utilities. Coming from Python, some things clicked immediately. Others took a week of confusion before they made sense.
What Felt Familiar
Go’s standard library is excellent, like Python’s. net/http, encoding/json, os, flag — you can build real tools without importing anything external. The philosophy of “batteries included” translates well.
Error handling is explicit. In Python you use try/except; in Go you check if err != nil. Different syntax, same idea: don’t ignore errors.
What Didn’t
No exceptions. Every function that can fail returns an error. At first this felt repetitive. After a week, I started appreciating that the error path is always visible. No hidden control flow.
No generics (until recently). Coming from Python’s duck typing, writing type-specific functions felt like a step backward. Go 1.18+ generics help, but the culture still favors concrete types.
Pointers. Python hides memory management completely. Go makes you think about whether you’re passing a copy or a reference. It’s not hard, but it’s a new dimension to consider.
Things I Wish Someone Told Me
go fmtis non-negotiable. Don’t fight the formatter. There are no style debates in Go.- Interfaces are implicit. You don’t declare that a type implements an interface — if it has the methods, it satisfies it. This is powerful but invisible.
- Goroutines are not threads. They’re cheaper. Use them freely, but learn channels before you reach for mutexes.
- The zero value is your friend. An empty struct is usable. A nil slice can be appended to. Lean into this.
One Month In
Go is not replacing Python for me. They solve different problems. Python is for scripts, data work, and web apps. Go is for compiled tools, network services, and anything where startup time matters.
The best part: Go binaries are single files with no runtime dependencies. go build and you have a binary you can copy anywhere. After years of managing virtualenvs and requirements.txt, that feels like freedom.