25 เทคนิค Go ที่นักพัฒนามืออาชีพใช้จริงในงาน Production

25 เทคนิค Go ที่นักพัฒนามืออาชีพใช้จริงในงาน Production

Dev Team · IT ·

25 เทคนิค Go ที่นักพัฒนามืออาชีพใช้จริงในงาน Production

Go มีชื่อเสียงเรื่องความเรียบง่าย syntax ไม่ซับซ้อน เรียนรู้ได้เร็ว — แต่ความเรียบง่ายนี้ซ่อน pattern ที่สำคัญมากสำหรับงาน production ไว้เยอะ

บทความนี้รวบรวม 25 เทคนิค ที่นักพัฒนา Go มืออาชีพใช้กันจริงในการสร้าง API, background workers, distributed systems และ infrastructure ต่าง ๆ

หมายเหตุเรื่อง Go version: ตัวอย่างทั้งหมดในบทความนี้ทดสอบกับ Go 1.26 (stable release ล่าสุด ณ มีนาคม 2026) ฟีเจอร์ที่เพิ่มมาใน Go 1.25 หรือ 1.26 จะระบุไว้ชัดเจนในแต่ละหัวข้อ


1) go run — เพื่อนที่ดีที่สุดในช่วง Prototype

ในขั้นตอน prototype หลายทีมสร้าง Makefile, shell script มากมายแค่เพื่อรันโปรแกรม แต่จริง ๆ แค่:

go run main.go
// หรือใน module:
go run .

มันเร็ว เรียบง่าย และทำให้คุณ focus กับ logic ได้ ค่อยเพิ่ม build step ทีหลังเมื่อจำเป็นจริง ๆ

Mermaid Diagram


2) Goroutines — แค่ใส่ go แล้วมันก็ทำงานพร้อมกัน

Goroutine คือ lightweight thread ที่ Go จัดการเอง ใช้ memory น้อยมาก (เริ่มต้นแค่ ~2-8 KB stack) สร้างง่ายมาก:

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)
}

Mermaid Diagram

Goroutine ถูกมาก — แต่ในระบบจริงต้องใช้ร่วมกับ channel, context และ WaitGroup


3) Worker Pool — ป้องกัน Goroutine ระเบิด

Goroutine ถูก แต่ไม่ฟรี ถ้า spawn ไม่จำกัดตอน load สูง server อาจล่ม ทางออกคือ worker pool:

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, 100)
    var wg sync.WaitGroup

    for w := 1; w <= 3; w++ {
        wg.Add(1)
        go worker(w, jobs, &wg)
    }

    for j := 1; j <= 10; j++ {
        jobs <- j
    }
    close(jobs)
    wg.Wait()
}

Mermaid Diagram

Pattern นี้เจอได้ทุกที่: consumer, indexer, ETL pipeline, webhook processor


4) Context — หัวใจของการควบคุม Lifecycle

ถ้าเขียน Go service ที่ไม่มี context เท่ากับสร้าง goroutine ที่หยุดไม่ได้ ไม่มี timeout ไม่มี cancellation:

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:", ctx.Err())
}

Mermaid Diagram

ถ้าทำ API, background job, distributed system — context คือเครื่องมือป้องกัน resource leak


5) Error Handling — ไม่มี Exception, มีแต่ความชัดเจน

Go ไม่มี try/catch แต่ใช้ return error แทน ดูซ้ำซาก แต่ทำให้ failure ชัดเจน:

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

result, err := divide(10, 0)
if err != nil {
    log.Printf("error: %v", err)
    return
}
fmt.Println(result)

Mermaid Diagram

กฎทอง: ถ้าเห็น _ = err ใน production code นั่นคือ incident report ในอนาคต


6) errors.Is / errors.As / errors.AsType — Error Matching ที่ถูกวิธี

ตั้งแต่ Go 1.13 มี error wrapping ด้วย %w และ matching ด้วย errors.Is / errors.As และ Go 1.26 เพิ่ม errors.AsType ที่ใช้ generics ทำให้สะดวกขึ้น:

import "errors"

var ErrNotFound = errors.New("not found")

func getUser(id int) (*User, error) {
    return nil, fmt.Errorf("getUser(%d): %w", id, ErrNotFound)
}

// ตรวจสอบ sentinel error
user, err := getUser(42)
if errors.Is(err, ErrNotFound) {
    // handle not found
}

// ดึง specific error type (แบบเดิม)
var pathErr *os.PathError
if errors.As(err, &pathErr) {
    fmt.Println("path:", pathErr.Path)
}

// Go 1.26: errors.AsType — generic version ที่สะดวกกว่า
if pe, ok := errors.AsType[*os.PathError](err); ok {
    fmt.Println("path:", pe.Path)
}

Mermaid Diagram

Go 1.26: errors.AsType[T] เป็น generic function ที่ type-safe กว่า errors.As ไม่ต้องประกาศตัวแปรก่อน และเร็วกว่าด้วย


7) select — Traffic Controller ของ Channels

เมื่อมีหลาย channel ที่ต้อง listen พร้อมกัน select คือคำตอบ:

select {
case msg := <-dataChan:
    process(msg)
case err := <-errChan:
    log.Println("error:", err)
case <-time.After(5 * time.Second):
    log.Println("timeout!")
case <-ctx.Done():
    log.Println("cancelled")
}

Mermaid Diagram

ใช้บ่อยสำหรับ: timeout, graceful shutdown, non-blocking read, fan-in pattern


8) sync.WaitGroup + .Go() — รอให้ Goroutine ทำงานเสร็จ

ปัญหาคลาสสิก: สร้าง goroutine แล้ว main() จบก่อน — WaitGroup แก้เรื่องนี้:

var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Add(1)
    go func(i int) {
        defer wg.Done()
        fmt.Println("task", i)
    }(i)
}

wg.Wait() // รอจนทุก goroutine เสร็จ

Go 1.25: เพิ่ม method WaitGroup.Go() ที่รวม Add(1) + go func() + Done() ในคำสั่งเดียว:

var wg sync.WaitGroup

for i := 0; i < 5; i++ {
    wg.Go(func() {
        fmt.Println("task", i)
    })
}

wg.Wait()

Mermaid Diagram

wg.Go() ลด boilerplate และป้องกัน bug จากการลืม Add(1) หรือ Done()


9) Struct Tags — ทำให้ JSON API เป็นเรื่องง่าย

Struct tags ควบคุมการ marshal/unmarshal โดยไม่ต้องเขียน custom code:

type User struct {
    ID        int       `json:"id"`
    Name      string    `json:"name"`
    Email     string    `json:"email,omitempty"`
    CreatedAt time.Time `json:"created_at"`
    Password  string    `json:"-"` // ไม่ส่งออก JSON
}

// Encode
json.NewEncoder(w).Encode(user)

// Decode
json.NewDecoder(r.Body).Decode(&user)

Mermaid Diagram

Go 1.25: มี encoding/json/v2 (experimental, เปิดด้วย GOEXPERIMENT=jsonv2) ที่ decode เร็วขึ้นมาก และมี option ใหม่ ๆ


10) defer — ป้องกัน Resource Leak

defer ทำให้ cleanup อยู่ติดกับ setup เสมอ ไม่ว่าจะ return ด้วยเหตุผลอะไร:

file, err := os.Open("data.txt")
if err != nil {
    return err
}
defer file.Close() // ปิดแน่นอน ไม่ว่าจะเกิดอะไร

mu.Lock()
defer mu.Unlock()

resp, err := http.Get(url)
if err != nil {
    return err
}
defer resp.Body.Close()

หลักการ: เปิดอะไร → defer ปิดทันที ล็อคอะไร → defer ปลดล็อคทันที

Mermaid Diagram


11) Go Modules — จัดการ Dependency อย่างมืออาชีพ

Go Modules เป็นมาตรฐานตั้งแต่ Go 1.11 และเป็น default ตั้งแต่ Go 1.16:

go mod init myapp           # สร้าง module
go get github.com/gin-gonic/gin  # เพิ่ม dependency
go mod tidy                 # ลบ dependency ที่ไม่ใช้
go mod vendor               # copy dependency ลง vendor/

Go 1.25: เพิ่ม ignore directive ใน go.mod สำหรับ exclude directory จาก package pattern matching

Go 1.26: go mod init จะ default ไปที่ Go version ต่ำกว่าเพื่อ compatibility กับ release ที่ยังรองรับอยู่

Mermaid Diagram


12) Generics — เขียน Type-Safe Code ที่ Reuse ได้ (Go 1.18+)

Generics มาตั้งแต่ Go 1.18 ทำให้เขียน function/type ที่ทำงานกับหลาย type ได้โดยไม่ต้อง interface{}:

func Map[T any, U any](slice []T, fn func(T) U) []U {
    result := make([]U, len(slice))
    for i, v := range slice {
        result[i] = fn(v)
    }
    return result
}

// ใช้งาน
names := Map(users, func(u User) string { return u.Name })
doubled := Map([]int{1, 2, 3}, func(n int) int { return n * 2 })
// Type constraint
type Number interface {
    ~int | ~float64 | ~int64
}

func Sum[T Number](nums []T) T {
    var total T
    for _, n := range nums {
        total += n
    }
    return total
}

Go 1.26: Generic types สามารถ self-reference ใน type parameter constraints ได้แล้ว:

type Adder[A Adder[A]] interface {
    Add(A) A
}

Mermaid Diagram


13) Table-Driven Tests — เขียนเทสต์แบบ Go Idiom

Pattern ที่ใช้กันมากที่สุดใน Go testing:

func TestDivide(t *testing.T) {
    tests := []struct {
        name    string
        a, b    int
        want    int
        wantErr bool
    }{
        {"normal", 10, 2, 5, false},
        {"divide by zero", 10, 0, 0, true},
        {"negative", -10, 2, -5, false},
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := divide(tt.a, tt.b)
            if (err != nil) != tt.wantErr {
                t.Errorf("error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if got != tt.want {
                t.Errorf("got %d, want %d", got, tt.want)
            }
        })
    }
}

Go 1.25: เพิ่ม testing/synctest สำหรับทดสอบ concurrent code ด้วย virtualized time:

synctest.Test(t, func(ctx context.Context) {
    // time.Sleep() เลื่อน fake clock ทันที ไม่ต้องรอจริง
})

Mermaid Diagram


14) Interfaces — Implicit Implementation สุด Flexible

Go interfaces เป็น implicit — ไม่ต้อง implements keyword:

type Logger interface {
    Log(msg string)
}

// แค่มี method ตรง ก็ implement แล้ว
type ConsoleLogger struct{}
func (c ConsoleLogger) Log(msg string) {
    fmt.Println(msg)
}

type FileLogger struct{ file *os.File }
func (f FileLogger) Log(msg string) {
    fmt.Fprintln(f.file, msg)
}

// ใช้งาน
func process(l Logger) {
    l.Log("processing...")
}

หลักการ: “Accept interfaces, return structs” — รับ interface เป็น parameter, return concrete type

Interface เล็ก ๆ ดีกว่า interface ใหญ่ — ประกอบกันได้:

type Reader interface { Read(p []byte) (n int, err error) }
type Writer interface { Write(p []byte) (n int, err error) }
type ReadWriter interface {
    Reader
    Writer
}

Mermaid Diagram


15) Embedding — Composition over Inheritance

Go ไม่มี inheritance แต่ใช้ embedding เพื่อ compose behavior:

type Animal struct {
    Name string
}
func (a Animal) Speak() string {
    return a.Name + " makes a sound"
}

type Dog struct {
    Animal    // embed Animal
    Breed string
}

d := Dog{
    Animal: Animal{Name: "Buddy"},
    Breed:  "Golden Retriever",
}
fmt.Println(d.Speak())  // "Buddy makes a sound"
fmt.Println(d.Name)     // "Buddy" — promoted field

Mermaid Diagram


16) Graceful Shutdown — ปิดระบบอย่างสง่างาม

Production service ต้องรับ signal แล้ว drain connection ก่อนปิด:

func main() {
    srv := &http.Server{Addr: ":8080", Handler: mux}

    go func() {
        if err := srv.ListenAndServe(); err != http.ErrServerClosed {
            log.Fatal(err)
        }
    }()

    // รอ interrupt signal
    quit := make(chan os.Signal, 1)
    signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
    <-quit

    log.Println("shutting down...")
    ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
    defer cancel()

    if err := srv.Shutdown(ctx); err != nil {
        log.Fatal("forced shutdown:", err)
    }
    log.Println("server stopped gracefully")
}

Mermaid Diagram

ไม่ตัด request ที่กำลังทำอยู่ ไม่ทำให้ client เจอ connection reset


17) slog — Structured Logging (Go 1.21+)

ตั้งแต่ Go 1.21 มี log/slog ใน standard library สำหรับ structured logging:

import "log/slog"

// JSON output สำหรับ production
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))

logger.Info("user login",
    slog.String("user_id", "u-123"),
    slog.String("ip", r.RemoteAddr),
    slog.Duration("latency", elapsed),
)
// Output: {"time":"...","level":"INFO","msg":"user login","user_id":"u-123","ip":"...","latency":"..."}

Go 1.25: เพิ่ม slog.GroupAttrs() สำหรับจัดกลุ่ม attributes และ Record.Source() method

Go 1.26: เพิ่ม slog.NewMultiHandler() สำหรับส่ง log ไปหลาย destination พร้อมกัน:

// Go 1.26: ส่ง log ไปทั้ง stdout และ file พร้อมกัน
jsonHandler := slog.NewJSONHandler(os.Stdout, nil)
fileHandler := slog.NewJSONHandler(logFile, nil)
logger := slog.New(slog.NewMultiHandler(jsonHandler, fileHandler))

Mermaid Diagram


18) sync.Once — ทำครั้งเดียว ไม่ว่า Goroutine กี่ตัว

เหมาะสำหรับ lazy initialization ที่ต้อง thread-safe:

var (
    instance *Database
    once     sync.Once
)

func GetDB() *Database {
    once.Do(func() {
        instance = connectToDatabase()
        log.Println("database connected")
    })
    return instance
}

// เรียกจากหลาย goroutine ได้ — connectToDatabase() ทำงานแค่ครั้งเดียว

Mermaid Diagram


19) Channel Patterns — Fan-Out / Fan-In

Pattern สำคัญสำหรับ parallel processing:

// Fan-out: กระจายงานไปหลาย goroutine
func fanOut(input <-chan int, workers int) []<-chan int {
    channels := make([]<-chan int, workers)
    for i := 0; i < workers; i++ {
        ch := make(chan int)
        channels[i] = ch
        go func() {
            defer close(ch)
            for v := range input {
                ch <- v * v // process
            }
        }()
    }
    return channels
}

// Fan-in: รวม output จากหลาย channel เป็น channel เดียว
func fanIn(channels ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    merged := make(chan int)

    for _, ch := range channels {
        wg.Add(1)
        go func(c <-chan int) {
            defer wg.Done()
            for v := range c {
                merged <- v
            }
        }(ch)
    }

    go func() {
        wg.Wait()
        close(merged)
    }()
    return merged
}

Mermaid Diagram


20) errgroup — Goroutine Group พร้อม Error Propagation

golang.org/x/sync/errgroup ดีกว่า WaitGroup เมื่อต้องจัดการ error:

import "golang.org/x/sync/errgroup"

func fetchAll(ctx context.Context, urls []string) ([]string, error) {
    g, ctx := errgroup.WithContext(ctx)
    results := make([]string, len(urls))

    for i, url := range urls {
        i, url := i, url
        g.Go(func() error {
            resp, err := http.Get(url)
            if err != nil {
                return fmt.Errorf("fetch %s: %w", url, err)
            }
            defer resp.Body.Close()
            body, err := io.ReadAll(resp.Body)
            if err != nil {
                return err
            }
            results[i] = string(body)
            return nil
        })
    }

    if err := g.Wait(); err != nil {
        return nil, err
    }
    return results, nil
}

Go 1.26: io.ReadAll เร็วขึ้น ~2x และใช้ memory น้อยลง ~50%

Mermaid Diagram


21) Middleware Pattern — สำหรับ HTTP Handlers

Pattern ที่ใช้กันมากใน Go web frameworks:

type Middleware func(http.Handler) http.Handler

func Logging(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        start := time.Now()
        next.ServeHTTP(w, r)
        slog.Info("request",
            slog.String("method", r.Method),
            slog.String("path", r.URL.Path),
            slog.Duration("duration", time.Since(start)),
        )
    })
}

func Auth(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        token := r.Header.Get("Authorization")
        if token == "" {
            http.Error(w, "unauthorized", http.StatusUnauthorized)
            return
        }
        next.ServeHTTP(w, r)
    })
}

// Chain middlewares
mux := http.NewServeMux()
mux.HandleFunc("/api/data", handleData)
handler := Logging(Auth(mux))

Mermaid Diagram


22) Enhanced HTTP Routing — ServeMux ที่ทรงพลังขึ้น (Go 1.22+)

ตั้งแต่ Go 1.22 http.ServeMux รองรับ method matching และ path parameters:

mux := http.NewServeMux()

// Method matching
mux.HandleFunc("GET /api/users", listUsers)
mux.HandleFunc("POST /api/users", createUser)

// Path parameters
mux.HandleFunc("GET /api/users/{id}", func(w http.ResponseWriter, r *http.Request) {
    id := r.PathValue("id")
    // ...
})

// Wildcard
mux.HandleFunc("GET /files/{path...}", serveFile)

Go 1.26: trailing slash redirects ใน ServeMux เปลี่ยนจาก HTTP 301 เป็น 307 (รักษา method ของ request)

Mermaid Diagram

ทำให้หลายโปรเจกต์ไม่ต้องใช้ router library ภายนอกแล้ว


23) Modern Iteration — range over Integers & Functions

Range over Integers (Go 1.22+)

for i := range 10 {
    fmt.Println(i) // 0, 1, 2, ..., 9
}
// แทนที่: for i := 0; i < 10; i++ { ... }

Range over Function Iterators (Go 1.23+)

// Custom iterator ด้วย iter.Seq
func Fibonacci(n int) iter.Seq[int] {
    return func(yield func(int) bool) {
        a, b := 0, 1
        for i := 0; i < n; i++ {
            if !yield(a) {
                return
            }
            a, b = b, a+b
        }
    }
}

// ใช้งาน — เหมือน range ปกติ
for v := range Fibonacci(10) {
    fmt.Println(v)
}

// ใช้กับ slices package
all := slices.Collect(Fibonacci(10))

Go 1.26: reflect.Type มี iterator methods ใหม่: Fields(), Methods(), Ins(), Outs() ที่ใช้กับ range ได้เลย

Mermaid Diagram


24) embed — ฝังไฟล์ลงใน Binary

ตั้งแต่ Go 1.16 ฝัง static files, templates, migrations ลงใน binary ได้เลย:

import "embed"

//go:embed templates/*
var templates embed.FS

//go:embed version.txt
var version string

Mermaid Diagram

Deploy แค่ binary ตัวเดียว ไม่ต้องจัดการ file path หรือ Docker COPY เพิ่ม


25) Benchmarking — วัด Performance ด้วย testing.B

Go มี benchmarking tool built-in ไม่ต้องติดตั้งอะไรเพิ่ม:

func BenchmarkConcat(b *testing.B) {
    for b.Loop() {
        s := ""
        for j := 0; j < 100; j++ {
            s += "x"
        }
    }
}

func BenchmarkBuilder(b *testing.B) {
    for b.Loop() {
        var sb strings.Builder
        for j := 0; j < 100; j++ {
            sb.WriteString("x")
        }
        _ = sb.String()
    }
}

Go 1.26: B.Loop() ไม่บล็อค inlining ใน loop body อีกต่อไป ทำให้ benchmark แม่นยำขึ้น

Go 1.26: เพิ่ม T.ArtifactDir() / B.ArtifactDir() สำหรับเก็บ artifacts จาก test

รัน:

go test -bench=. -benchmem ./...

Output จะบอก ns/op, B/op, allocs/op ทำให้เห็นชัดว่า strings.Builder เร็วกว่า += มาก

Mermaid Diagram


สรุป: Go Version Compatibility

เทคนิคGo version ขั้นต่ำ
1-5: พื้นฐาน (go run, goroutines, worker pool, context, errors)Go 1.16+
6: errors.AsTypeGo 1.26+ (Is/As ใช้ได้ตั้งแต่ 1.13)
7-11: select, WaitGroup, struct tags, defer, modulesGo 1.16+
8: WaitGroup.Go()Go 1.25+
12: GenericsGo 1.18+
13: Table-driven tests / testing/synctestGo 1.16+ / Go 1.25+
14-16: Interfaces, embedding, graceful shutdownGo 1.16+
17: slog / NewMultiHandlerGo 1.21+ / Go 1.26+
18-21: sync.Once, channels, errgroup, middlewareGo 1.16+
22: Enhanced ServeMux routingGo 1.22+
23: Range over int / Range over funcGo 1.22+ / Go 1.23+
24: embedGo 1.16+
25: Benchmarking / B.Loop improvementsGo 1.16+ / Go 1.26+

Go 1.25/1.26 Highlights ที่ Production Dev ควรรู้

Runtime: Green Tea Garbage Collector (Go 1.26 — default)

GC ตัวใหม่ที่ปรับปรุง marking/scanning สำหรับ small objects — ลด GC overhead 10-40% ในงานจริง:

# ปิด Green Tea GC (ถ้ามีปัญหา)
GOEXPERIMENT=nogreenteagc go build .

Runtime: Container-Aware GOMAXPROCS (Go 1.25)

Go runtime ปรับ GOMAXPROCS ตาม cgroup CPU limits อัตโนมัติ — ไม่ต้องใช้ uber-go/automaxprocs อีกต่อไป:

# ปิดถ้าต้องการ
GODEBUG=containermaxprocs=0,updatemaxprocs=0

Tooling: go fix Modernizers (Go 1.26)

go fix เวอร์ชันใหม่มี “modernizers” ช่วยอัปเดตโค้ดให้ใช้ idiom ใหม่ ๆ อัตโนมัติ:

go fix ./...

Experimental: Goroutine Leak Profile (Go 1.26)

ตรวจจับ goroutine ที่ blocked บน concurrency primitive ที่ไม่มีใคร reference ถึง:

GOEXPERIMENT=goroutineleakprofile go build .
# แล้วเข้า /debug/pprof/goroutineleak

เคล็ดลับด้าน Security

  • Validate inputs ทุกครั้ง อย่าเชื่อ client
  • หลีกเลี่ยง unsafe ถ้าไม่จำเป็นจริง ๆ
  • อย่า ignore errors — hidden failure คือ failure ที่แย่ที่สุด
  • ใช้ context + timeout ทุก network call และ long-running task
  • ใช้ crypto/rand แทน math/rand สำหรับ security-sensitive values
  • ใช้ go vet + staticcheck ใน CI — จับ bug ก่อนถึง production

Go เหมาะกับงานแบบไหน?

Go เป็นตัวเลือกที่ดีเมื่อต้องการ: fast APIs, distributed services, CLI tools, streaming pipelines และ always-on backend systems ที่ต้องการ concurrency + networking + reliability

เมื่อใช้ patterns ที่ถูกต้องตั้งแต่แรก — goroutines with control, contexts everywhere, explicit errors, clean APIs — ระบบจะ scale ได้ดีและ maintain ง่าย

Go productive เพราะ straightforward แต่ speed ที่แท้จริงมาจากการใช้ patterns ที่ Go ออกแบบมาให้ใช้