The Business & Technology Network
Helping Business Interpret and Use Technology
«  
  »
S M T W T F S
1
 
2
 
3
 
4
 
5
 
6
 
7
 
8
 
9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
25
 
26
 
27
 
28
 
29
 
30
 
31
 
 
 
 
 

10 Golang Tricks For Faster Go Development

DATE POSTED:March 24, 2026

Go has this funny reputation: “simple language, boring syntax, easy to learn.” All true… and also misleading.

Because once you start building real services, APIs that get traffic, background workers that run all day, indexers that never stop, stuff that needs to be fast but also not fall over, Go’s simple surface hides a bunch of habits that make a huge difference.

A lot of teams write Go that’s perfectly fine. It compiles, it ships, it runs. But it’s often missing the little patterns that make Go development feel effortless instead of grindy.

So here are 10 practical things I see experienced Go devs do constantly. Nothing magical. Just the “this saves you time and prevents pain later” stuff.

1) go run is your best friend (especially early on)

In the prototype stage, I’ve watched teams create a whole zoo of scripts and make targets just to run a program.

You usually don’t need it.

If you’re experimenting, iterating, or debugging a small service, just do:

go run main.go

Or, in a normal module:

go run .

It’s quick, it’s boring, and it keeps you moving. You can always add build steps later when it actually matters.

2) Goroutines: don’t overthink it, just start one

The first time you use goroutines, it feels like cheating. You add go and suddenly work happens “in parallel.”

A tiny example:

package main

import (
"fmt"
"time"
)
func worker(id int) {
fmt.Println("worker", id, "started")
time.Sleep(time.Second)
fmt.Println("worker", id, "finished")
}
func main() {
for i := 1; i <= 3; i++ {
go worker(i)
}
time.Sleep(2 * time.Second)
}

This is the baby version. In real systems you’ll coordinate with channels, contexts, and WaitGroups, but the mental model stays the same: goroutines are cheap and they’re how Go “wants” you to do concurrency.

3) But also: unlimited goroutines is how you melt a server

Yes, goroutines are lightweight. No, they are not free.

If you spawn one per job and the job queue spikes, you can easily create a self-inflicted outage. The fix most teams land on is a worker pool: fixed number of goroutines, jobs buffered through a channel.

package main

import (
"fmt"
"sync"
)
func worker(id int, jobs <-chan int, wg *sync.WaitGroup) {
defer wg.Done()
for j := range jobs {
fmt.Printf("worker %d processing job %d\n", id, j)
}
}
func main() {
jobs := make(chan int, 5)
var wg sync.WaitGroup
for w := 1; w <= 3; w++ {
wg.Add(1)
go worker(w, jobs, &wg)
}
for j := 1; j <= 5; j++ {
jobs <- j
}
close(jobs)
wg.Wait()
}

This pattern shows up everywhere: consumers, indexers, ETL pipelines, webhook processors, anything with “lots of little tasks.”

4) Learn context early so you don’t regret it later

The fastest way to build a “haunted” service is to write code that can’t stop.

No timeouts. No cancellation. Just goroutines that keep running because… why would they stop?

Go’s context is the standard tool for this:

ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
defer cancel()

select {
case result := <-taskChan:
fmt.Println(result)
case <-ctx.Done():
fmt.Println("timed out / cancelled")
}

If you work on APIs, background jobs, distributed systems, blockchain indexing — anything long-running — context is how you keep the system from slowly leaking resources until it dies at 3am.

5) Go errors look annoying… until you run production

Go doesn’t do exceptions. You return errors. You check errors. Over and over.

It looks repetitive. It also makes failures explicit, which is exactly what you want when real money / real users / real uptime is on the line.

func divide(a, b int) (int, error) {
if b == 0 {
return 0, fmt.Errorf("division by zero")
}
return a / b, nil
}

result, err := divide(10, 0)
if err != nil {
log.Println(err)
return
}
_ = result

A practical rule: if you see _ = err in production code, that’s usually a future incident report.

6) select is the “traffic controller” for channels

As soon as you have more than one channel, you’ll hit the problem of “I need to wait on multiple things.”

That’s what select is for:

select {
case msg := <-channel1:
fmt.Println(msg)
case <-time.After(time.Second):
fmt.Println("timeout")
}

You’ll use this constantly for timeouts, graceful shutdown, non-blocking reads, “wait for either result or cancellation,” and basically anything event-y.

7) WaitGroups prevent the classic “program exits too early” facepalm

If you’ve ever started goroutines and wondered why nothing prints, it’s because main() ends and your process exits.

sync.WaitGroup is the simplest coordination tool:

var wg sync.WaitGroupfor i := 0; i < 3; i++ {
wg.Add(1)
go func(i int) {
defer wg.Done()
fmt.Println("task", i)
}(i)
}wg.Wait()

It’s not fancy, but it’s dependable. And that’s kind of Go’s whole vibe.

8) Struct tags make JSON APIs feel effortless

If you build APIs in Go, struct tags are how you keep your JSON clean without writing custom marshaling code.

type User struct {
ID int `json:"id"`
Name string `json:"name"`
}

Then:

json.NewEncoder(w).Encode(user)

This isn’t just convenience — consistent JSON shapes reduce frontend bugs and keep your API predictable.

9) defer is small, but it prevents so many leaks

defer is one of those features you barely notice until you don’t have it.

Open a file? Defer close. Acquire a lock? Defer unlock. Start a timer? Defer stop. It keeps the “cleanup” logic next to the “setup” logic.

file, err := os.Open("data.txt")
if err != nil {
return err
}
defer file.Close()

It reads like a promise: “I’m cleaning this up no matter what happens next.”

10) Go Modules: use them, don’t fight them

If you’ve used older Go workflows, modules will feel like a relief.

Start a module:

go mod init myapp

Add a dependency:

go get github.com/gin-gonic/gin

The big win is reproducibility: teammates (and CI) get the same versions, and you don’t end up with “works on my machine” dependency chaos.

A quick word on security (because fast code that’s unsafe is still a problem)

A few habits worth repeating because they’re boring and important:

  • Validate inputs. Don’t assume the client is friendly.
  • Avoid unsafe unless you’re absolutely sure. It’s called unsafe for a reason.
  • Never ignore errors. Hidden failure is the worst failure.
  • Use contexts + timeouts. Especially on network calls and long-running tasks.
When Go shines (and why it shows up in Web3 so much)

Go is a strong fit when you need: fast APIs, distributed services, tooling, streaming pipelines, and “always-on” backend work.

That’s also why it’s common in Web3 infrastructure — nodes, indexers, relayers, validators, bridges, analytics pipelines. These systems are basically concurrency + networking + reliability problems, and Go handles that combo well.

Where teams usually get stuck

Most of the pain I see isn’t “Go is hard.” It’s architectural: unmanaged concurrency, missing timeouts, background work with no cancellation, and error handling that turns into a game of whack-a-mole.

That’s where experienced engineering makes a difference — setting the right patterns early so the system stays stable as usage grows.

About Ancilar

Ancilar works with founders and Web3 teams to build production-grade blockchain infrastructure — things like high-performance Go backends, indexing services, cross-chain integrations, and security-focused system design.

If you’re building something where “it works on testnet” isn’t good enough, the goal is simple: ship systems that stay reliable under real load.

Closing thought

Go is productive because it’s straightforward. But the real speed comes when you lean into the patterns Go expects: goroutines with control, contexts everywhere, explicit errors, clean APIs, and boring reliability.

Once you build that way, you ship faster and you sleep better.

If you are serious about building for the long term, we are ready to help.

Email: [email protected]
Website: https://www.ancilar.com

10 Golang Tricks For Faster Go Development was originally published in Coinmonks on Medium, where people are continuing the conversation by highlighting and responding to this story.