Why Go Started Clicking for Me
I started using Go in early 2026 on a DSPM project. Before that, my comfort zone was TypeScript on the UI side and Python for backend work. On DSPM, I wanted something calmer on the backend.
The work pushed me there. We had jobs that needed to scan data, run multiple tasks at once, and still read clearly when I came back weeks later. I did not want clever code. I wanted software I could trust.
That is what made Go click. It kept asking one useful question: can you make this simple enough that another engineer can understand it quickly and trust it in production?
What Go gets right
Simplicity
Go feels small. A handful of keywords, little room to be too clever. Coming from TypeScript, that felt limiting at first. For backend work, it started feeling like a feature.
When I read my Go code, it usually says exactly what it is doing. Go has pushed me toward writing plainer software, and I mean that as praise.
Concurrency
This is where the language won me over. Goroutines and channels gave me a mental model I could trust. In other stacks, concurrent work can get noisy fast once you add retries, partial failures, cancellation, and rate limits. In Go, a lot of that work starts from a shape that feels closer to how I think.
I stopped thinking about concurrency as hidden runtime magic and started thinking about work moving through a small, readable pipeline.
Goroutine 1
Scan one table or task without blocking the rest.
Goroutine 2
Keep another unit of work moving at the same time.
Goroutine 3
Send the result back when it is done.
Main routine
Collect results, apply backpressure, and keep the whole thing easy to follow when you come back to it later.
This is the kind of code that made me smile the first few times I wrote it:
gotype scanResult struct {
table string
rows int
err error
}
results := make(chan scanResult, len(tables))
for _, table := range tables {
go func(name string) {
rows, err := scanTable(name)
results <- scanResult{table: name, rows: rows, err: err}
}(table)
}
for range tables {
result := <-results
if result.err != nil {
log.Printf("scan failed for %s: %v", result.table, result.err)
continue
}
log.Printf("scanned %s with %d rows", result.table, result.rows)
}It is not advanced or magical. That is exactly why I like it. I can read it six months later and still see the flow immediately.
The standard library
Need an HTTP server? net/http. Need JSON? encoding/json. Need tests? testing. Need context propagation? context. You can get surprisingly far before installing anything, and smaller dependency surfaces usually mean fewer moving parts to debug.
gofunc healthHandler(w http.ResponseWriter, r *http.Request) {
response := map[string]string{
"status": "ok",
"service": "dspm-api",
}
w.Header().Set("Content-Type", "application/json")
if err := json.NewEncoder(w).Encode(response); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
}It is direct. No ceremony, no digging through layers to see how a simple response is built.
What I still find hard
TypeScript is still my default for UI work. Python still earns its place for plenty of backend and data tasks. In Go, I am still learning how to write code that feels idiomatic, not just correct. Those are not the same thing.
Why this matters
The bigger lesson has not been “Go is better than everything else.” The language you choose changes how you think about the system you are building.
Go makes me reach for simplicity earlier. It makes concurrency feel concrete. It makes me depend on fewer things by default. When I am building services, small APIs, or anything that needs to do a lot of work without becoming hard to reason about, Go has started becoming my default.
I am still learning. Maybe that is exactly why I like it right now. It already lets me write good software, and it still has more to teach me.