iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Examples

Five small, idiomatic Go programs that cover the patterns you reach for in real projects: a CLI flag parser, a context-aware HTTP client, a graceful HTTP server, a worker pool, and a small TUI table. Each is short and pasteable.

Five idiomatic Go snippets

EXAMPLE
package main

// ============================================================
// 1) CLI with flags + subcommands using flag package
// ============================================================
import (
	"context"
	"errors"
	"flag"
	"fmt"
	"io"
	"net/http"
	"os"
	"os/signal"
	"strings"
	"sync"
	"syscall"
	"time"
)

func runCLI() {
	user := flag.String("user", "", "username (required)")
	limit := flag.Int("limit", 20, "result limit")
	verbose := flag.Bool("v", false, "verbose output")
	flag.Parse()

	if *user == "" {
		fmt.Fprintln(os.Stderr, "missing -user")
		flag.Usage()
		os.Exit(2)
	}
	if *verbose {
		fmt.Printf("user=%s limit=%d\n", *user, *limit)
	}
}

// ============================================================
// 2) Context-aware HTTP client with timeout + retry
// ============================================================
var httpClient = &http.Client{Timeout: 5 * time.Second}

func fetch(ctx context.Context, url string) ([]byte, error) {
	var last error
	for attempt := 0; attempt < 3; attempt++ {
		req, _ := http.NewRequestWithContext(ctx, "GET", url, nil)
		req.Header.Set("user-agent", "shop-client/1.0")
		resp, err := httpClient.Do(req)
		if err != nil {
			last = err
		} else {
			defer resp.Body.Close()
			if resp.StatusCode/100 == 2 {
				return io.ReadAll(resp.Body)
			}
			last = fmt.Errorf("status %d", resp.StatusCode)
		}
		select {
		case <-time.After(time.Duration(1<<attempt) * 200 * time.Millisecond):
		case <-ctx.Done():
			return nil, ctx.Err()
		}
	}
	return nil, last
}

// ============================================================
// 3) Graceful HTTP server (SIGTERM-clean shutdown)
// ============================================================
func runServer() {
	mux := http.NewServeMux()
	mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) {
		fmt.Fprintln(w, "ok")
	})

	srv := &http.Server{
		Addr:              ":8080",
		Handler:           mux,
		ReadHeaderTimeout: 5 * time.Second,
		IdleTimeout:       60 * time.Second,
	}

	idle := make(chan struct{})
	go func() {
		sig := make(chan os.Signal, 1)
		signal.Notify(sig, syscall.SIGINT, syscall.SIGTERM)
		<-sig
		ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
		defer cancel()
		_ = srv.Shutdown(ctx)
		close(idle)
	}()

	if err := srv.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
		panic(err)
	}
	<-idle
}

// ============================================================
// 4) Worker pool with bounded concurrency
// ============================================================
type Job struct {
	URL string
}

type Result struct {
	URL string
	Err error
	N   int
}

func crawl(ctx context.Context, jobs []Job, workers int) []Result {
	in := make(chan Job)
	out := make(chan Result)
	var wg sync.WaitGroup

	for i := 0; i < workers; i++ {
		wg.Add(1)
		go func() {
			defer wg.Done()
			for j := range in {
				body, err := fetch(ctx, j.URL)
				out <- Result{URL: j.URL, Err: err, N: len(body)}
			}
		}()
	}

	go func() {
		defer close(in)
		for _, j := range jobs {
			select {
			case in <- j:
			case <-ctx.Done():
				return
			}
		}
	}()

	go func() { wg.Wait(); close(out) }()

	var results []Result
	for r := range out {
		results = append(results, r)
	}
	return results
}

// ============================================================
// 5) Tiny ASCII table for a CLI
// ============================================================
func printTable(headers []string, rows [][]string) {
	widths := make([]int, len(headers))
	for i, h := range headers {
		widths[i] = len(h)
	}
	for _, r := range rows {
		for i, c := range r {
			if len(c) > widths[i] {
				widths[i] = len(c)
			}
		}
	}

	row := func(parts []string) {
		var sb strings.Builder
		for i, p := range parts {
			sb.WriteString(p)
			sb.WriteString(strings.Repeat(" ", widths[i]-len(p)+2))
		}
		fmt.Println(strings.TrimRight(sb.String(), " "))
	}
	row(headers)
	sep := make([]string, len(headers))
	for i := range sep {
		sep[i] = strings.Repeat("-", widths[i])
	}
	row(sep)
	for _, r := range rows {
		row(r)
	}
}

func main() {
	if len(os.Args) > 1 && os.Args[1] == "serve" {
		runServer()
		return
	}
	printTable(
		[]string{"id", "customer", "total"},
		[][]string{
			{"o1", "alice", "49.95"},
			{"o2", "bob", "199.00"},
		},
	)
}

Why it matters

Always thread a context.Context through any function that does I/O or could block. Even when the caller does not need cancellation today, the moment somebody wraps the call in an HTTP handler or a worker pool, the threaded context turns "leaks goroutines forever" into "cleans up when the request is cancelled".

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
// Idiomatic Go is short, explicit, no magic. Read effective-go.
Try it Yourself »

Discussion

Loading…