Lead Level
0%0 / 28
01 / 28

Go Memory Model & Runtime

Go runtime qanday ishlashini chuqur tushunish — GC, goroutine scheduler, stack growth va happens-before munosabatlari. Senior darajadagi eng muhim bilim.

Go Runtime Arxitekturasi

🧵 GMP Model

G=Goroutine, M=OS Thread, P=Processor. Har P da 256ta goroutine saqlanadi.

🗑 GC (Tricolor)

Concurrent mark-and-sweep. Go 1.18+ da GC pauza <1ms. GOGC env bilan sozlash.

📦 Stack Growth

Goroutine 2KB stackdan boshlanadi, kerakli holda dynamic o'sadi. Max: GOMAXPROCS.

⚡ Work Stealing

Bo'sh P boshqa P ning local queueidan goroutine "o'g'irlaydi" — load balancing.

Happens-Before — Memory Ordering
memory_model.go
CRITICAL
package main

import (
    "fmt"
    "sync"
)

// ❌ NOTO'G'RI — data race! happens-before yo'q
var done bool
var msg string

func badExample() {
    msg = "salom"
    done = true  // boshqa goroutine buni ko'rmasligi mumkin!
}

// ✅ TO'G'RI — sync.Mutex bilan happens-before kafolatlanadi
type SafeCounter struct {
    mu    sync.RWMutex
    count int
}

func (c *SafeCounter) Inc() {
    c.mu.Lock()
    defer c.mu.Unlock()
    c.count++
}

func (c *SafeCounter) Get() int {
    c.mu.RLock()
    defer c.mu.RUnlock()
    return c.count
}

// Channel → happens-before kafolati
// "send on channel" happens before "receive from channel"
func channelHappensBefore() {
    ch := make(chan struct{})
    x := 0

    go func() {
        x = 42     // Bu send dan OLDIN bajariladi
        ch <- struct{}{}
    }()

    <-ch
    fmt.Println(x) // 42 — kafolatlangan, race yo'q
}

func main() {
    c := &SafeCounter{}
    var wg sync.WaitGroup

    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            c.Inc()
        }()
    }
    wg.Wait()
    fmt.Println(c.Get()) // 1000 — har doim
    channelHappensBefore()
}
GC Sozlash — Production
gc_tuning.go
PERF
package main

import (
    "fmt"
    "runtime"
    "runtime/debug"
)

func gcStats() {
    var stats runtime.MemStats
    runtime.ReadMemStats(&stats)

    fmt.Printf("Alloc:      %v MB\n", stats.Alloc/1024/1024)
    fmt.Printf("TotalAlloc: %v MB\n", stats.TotalAlloc/1024/1024)
    fmt.Printf("Sys:        %v MB\n", stats.Sys/1024/1024)
    fmt.Printf("NumGC:      %v\n", stats.NumGC)
    fmt.Printf("GCCPUFrac:  %.4f\n", stats.GCCPUFraction)
    fmt.Printf("Goroutines: %v\n", runtime.NumGoroutine())
}

func main() {
    // GOGC=100 (default) → heap 2x bo'lganda GC ishga tushadi
    // GOGC=200 → kamroq GC, ko'p memory
    // GOGC=off → GC o'chirilgan (batch job uchun)
    debug.SetGCPercent(150) // runtime boshqarish

    // GOMEMLIMIT (Go 1.19+) — soft memory limit
    debug.SetMemoryLimit(512 << 20) // 512 MB limit

    // Manual GC (faqat zarur holatlarda)
    runtime.GC()

    gcStats()
}
Production'da GOGC va GOMEMLIMIT ni sozlash eng katta performance o'sishini beradi. Ko'p loyihalarda GOGC=200 + GOMEMLIMIT kombinatsiyasi optimal natija beradi.
02 / 28

Type System Chuqur

Go'ning type sistemasi — named types, type aliases, embedding, method sets va interface satisfaction qoidalari.

Named Types vs Type Aliases
type_system.go
package main
import "fmt"

// Named Type — yangi tur, o'z metodlari bo'lishi mumkin
type UserID    int64
type ProductID int64
type Email     string

func (e Email) Domain() string {
    for i, ch := range e {
        if ch == '@' { return string(e[i+1:]) }
    }
    return ""
}

// Type Alias — faqat taxallus, metod qo'shib bo'lmaydi
type MyInt = int // int bilan bir xil tur!

// Struct Embedding — composition (not inheritance)
type Animal struct {
    Name string
    Age  int
}

func (a Animal) Speak() string { return a.Name + " speaks" }

type Dog struct {
    Animal          // embedded — all Animal methods promoted!
    Breed string
}

func (d Dog) Speak() string { // override
    return d.Name + " says: Woof!"
}

// Method Sets qoidasi:
// T turi → T receiver metodlari
// *T turi → T va *T receiver metodlari
type Builder struct{ val string }

func (b *Builder) Set(v string) *Builder {
    b.val = v
    return b  // method chaining uchun
}
func (b *Builder) Build() string { return b.val }

func main() {
    uid := UserID(42)
    pid := ProductID(42)
    // uid == pid → COMPILE ERROR! turli typlar
    fmt.Println(uid, pid)

    e := Email("ali@example.com")
    fmt.Println(e.Domain()) // example.com

    d := Dog{Animal{"Rex", 3}, "Labrador"}
    fmt.Println(d.Speak())   // Rex says: Woof! (override)
    fmt.Println(d.Animal.Speak()) // Rex speaks (embedded)
    fmt.Println(d.Age)       // 3 — promoted field

    result := (&Builder{}).Set("hello world").Build()
    fmt.Println(result)
}
Comparable Types & Constraints
comparable.go
package main
import "fmt"

// Struct comparable bo'lishi uchun barcha fieldlar comparable bo'lishi kerak
type Point struct{ X, Y float64 }
// []int, map — comparable EMAS → map key sifatida ishlatib bo'lmaydi

// iota bilan enumeratsiya
type Status int
const (
    StatusPending Status = iota  // 0
    StatusActive                   // 1
    StatusClosed                   // 2
    StatusDeleted                  // 3
)

func (s Status) String() string {
    return [...]string{"Pending","Active","Closed","Deleted"}[s]
}

// Bit flags bilan iota
type Permission uint
const (
    Read    Permission = 1 << iota // 1
    Write                            // 2
    Execute                          // 4
    Admin   = Read | Write | Execute // 7
)

func hasPermission(p, check Permission) bool {
    return p&check != 0
}

func main() {
    p1, p2 := Point{1, 2}, Point{1, 2}
    fmt.Println(p1 == p2) // true — struct comparable

    s := StatusActive
    fmt.Println(s.String()) // Active

    userPerm := Read | Write
    fmt.Println(hasPermission(userPerm, Read))    // true
    fmt.Println(hasPermission(userPerm, Execute)) // false
}
03 / 28

Interface & Polymorphism

Go'da interfacelar implicit — e'lon qilmasdan implement qilish mumkin. Bu duck typing'ning statik versiyasi.

Interface Internals — itype & idata
interfaces.go
CRITICAL
package main
import ("fmt"; "math")

// Interface ichida 2 pointer: (type, data)
// nil interface: (nil, nil)
// non-nil interface: (type!=nil, data=nil) — yashirin xato!

type Shape interface {
    Area() float64
    Perimeter() float64
}

type Stringer interface {
    String() string
}

// Interface composition
type ShapeStringer interface {
    Shape
    Stringer
}

type Circle struct{ R float64 }
func (c Circle) Area() float64      { return math.Pi * c.R * c.R }
func (c Circle) Perimeter() float64 { return 2 * math.Pi * c.R }
func (c Circle) String() string     { return fmt.Sprintf("Circle(r=%.2f)", c.R) }

type Rect struct{ W, H float64 }
func (r Rect) Area() float64      { return r.W * r.H }
func (r Rect) Perimeter() float64 { return 2 * (r.W + r.H) }
func (r Rect) String() string     { return fmt.Sprintf("Rect(%gx%g)", r.W, r.H) }

// nil interface xatosi — klassik bug!
func nilTrap() {
    var s *Circle = nil
    var i Shape = s   // i != nil (type set bor!)
    fmt.Println(i == nil) // false — yashirin xato!
}

func totalArea(shapes []Shape) float64 {
    total := 0.0
    for _, s := range shapes {
        total += s.Area()
    }
    return total
}

func main() {
    shapes := []Shape{
        Circle{5},
        Rect{4, 6},
        Circle{3},
    }

    for _, s := range shapes {
        fmt.Printf("%-20s area=%.2f perim=%.2f\n",
            s.(fmt.Stringer).String(), // type assertion
            s.Area(),
            s.Perimeter())
    }

    fmt.Printf("Jami: %.2f\n", totalArea(shapes))

    // Type assertion — xavfsiz variant
    var sh Shape = Circle{7}
    if c, ok := sh.(Circle); ok {
        fmt.Printf("Radius: %.0f\n", c.R)
    }
}
Functional Options Pattern (Senior pattern)
options_pattern.go
PATTERN
type Server struct {
    host    string
    port    int
    timeout int
    maxConn int
}

type Option func(*Server)

func WithHost(h string) Option {
    return func(s *Server) { s.host = h }
}
func WithPort(p int) Option {
    return func(s *Server) { s.port = p }
}
func WithTimeout(t int) Option {
    return func(s *Server) { s.timeout = t }
}

func NewServer(opts ...Option) *Server {
    s := &Server{host: "localhost", port: 8080, timeout: 30, maxConn: 100}
    for _, opt := range opts { opt(s) }
    return s
}

// Ishlatish — juda clean!
srv := NewServer(
    WithHost("0.0.0.0"),
    WithPort(9090),
    WithTimeout(60),
)
04 / 28

Generics — Go 1.18+

Type parameters bilan generic funksiya va structlar yozish. Type constraints va union types.

Type Parameters — Asoslar
generics.go
package main

import (
    "fmt"
    "golang.org/x/exp/constraints"
)

// Generic funksiya
func Min[T constraints.Ordered](a, b T) T {
    if a < b { return a }
    return b
}

// Custom constraint — Union type
type Number interface {
    ~int | ~int32 | ~int64 | ~float32 | ~float64
}

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

// Generic Stack data structure
type Stack[T any] struct {
    items []T
}

func (s *Stack[T]) Push(item T) { s.items = append(s.items, item) }
func (s *Stack[T]) Pop() (T, bool) {
    var zero T
    if len(s.items) == 0 { return zero, false }
    top := s.items[len(s.items)-1]
    s.items = s.items[:len(s.items)-1]
    return top, true
}
func (s *Stack[T]) Len() int { return len(s.items) }

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

func Filter[T any](slice []T, pred func(T) bool) []T {
    var result []T
    for _, v := range slice {
        if pred(v) { result = append(result, v) }
    }
    return result
}

func Reduce[T, U any](slice []T, init U, f func(U, T) U) U {
    acc := init
    for _, v := range slice { acc = f(acc, v) }
    return acc
}

func main() {
    fmt.Println(Min(3, 7))       // 3
    fmt.Println(Min(3.14, 2.71)) // 2.71
    fmt.Println(Min("abc", "xyz"))// abc

    nums := []int{1,2,3,4,5}
    fmt.Println(Sum(nums))         // 15

    s := &Stack[string]{}
    s.Push("go"); s.Push("rust"); s.Push("zig")
    top, _ := s.Pop()
    fmt.Println(top, s.Len()) // zig 2

    doubled := Map(nums, func(n int) int { return n * 2 })
    evens   := Filter(nums, func(n int) bool { return n%2 == 0 })
    product := Reduce(nums, 1, func(acc, n int) int { return acc * n })

    fmt.Println(doubled, evens, product) // [2 4 6 8 10] [2 4] 120
}
05 / 28

Error Handling Patterns

Go'da xatolarni to'g'ri boshqarish — sentinel errors, custom errors, wrapping, errors.Is/As.

errors.go
SENIOR
package main

import (
    "errors"
    "fmt"
)

// 1. Sentinel errors — comparable, samarali
var (
    ErrNotFound   = errors.New("not found")
    ErrPermission = errors.New("permission denied")
    ErrTimeout    = errors.New("operation timeout")
)

// 2. Custom error type — kontekst bilan
type ValidationError struct {
    Field   string
    Message string
    Value   any
}
func (e *ValidationError) Error() string {
    return fmt.Sprintf("validation error: field=%s msg=%s value=%v",
        e.Field, e.Message, e.Value)
}

// 3. Error wrapping — %w bilan
func getUser(id int) (string, error) {
    if id <= 0 {
        return "", &ValidationError{"id", "must be positive", id}
    }
    if id == 999 {
        return "", fmt.Errorf("getUser(%d): %w", id, ErrNotFound)
    }
    return "Ali", nil
}

func loadProfile(id int) error {
    _, err := getUser(id)
    if err != nil {
        return fmt.Errorf("loadProfile: %w", err) // wrap!
    }
    return nil
}

// 4. errors.Is — zanjir bo'ylab tekshirish
// 5. errors.As — tur bo'ylab qidirish
func main() {
    err := loadProfile(999)
    fmt.Println(err) // loadProfile: getUser(999): not found

    // errors.Is — wrapper zanjiri ichida ham ishlaydi
    fmt.Println(errors.Is(err, ErrNotFound)) // true

    err2 := loadProfile(-5)
    // errors.As — concrete type ga chiqarish
    var valErr *ValidationError
    if errors.As(err2, &valErr) {
        fmt.Printf("Field: %s, Msg: %s\n", valErr.Field, valErr.Message)
    }

    // 6. defer + recover — panic ni ushlash
    safeDiv(10, 0)
}

func safeDiv(a, b int) (result int, err error) {
    defer func() {
        if r := recover(); r != nil {
            err = fmt.Errorf("panic recovered: %v", r)
        }
    }()
    return a / b, nil
}
06 / 28

Goroutine Internals

Go scheduler — GMP modeli, preemption, goroutine leak, GOMAXPROCS va real production patterns.

Goroutine Leak — Eng keng tarqalgan xato
leak.go❌ LEAK
func leaky() <-chan int {
  ch := make(chan int)
  go func() {
    // consumer yo'q — goroutine
    // HECH QACHON tugatmaydi!
    ch <- heavyWork()
  }()
  return ch
}
// Agar caller ch ni o'qimasa
// goroutine abadiy yashaydi
no_leak.go✅ SAFE
func safe(ctx context.Context) <-chan int {
  ch := make(chan int, 1) // buffered!
  go func() {
    select {
    case ch <- heavyWork():
    case <-ctx.Done(): // cancel!
    }
  }()
  return ch
}
// Context cancel → goroutine exits
Worker Pool Pattern — Production Ready
worker_pool.go
PROD
package main

import (
    "context"
    "fmt"
    "runtime"
    "sync"
)

type Job[T, R any] struct {
    Input  T
    Result R
    Err    error
}

func WorkerPool[T, R any](
    ctx    context.Context,
    inputs []T,
    workers int,
    fn     func(context.Context, T) (R, error),
) []Job[T, R] {
    jobCh := make(chan Job[T, R], len(inputs))
    outCh := make(chan Job[T, R], len(inputs))

    // Input yuborish
    for _, inp := range inputs {
        jobCh <- Job[T, R]{Input: inp}
    }
    close(jobCh)

    // Worker goroutinelar
    var wg sync.WaitGroup
    for i := 0; i < workers; i++ {
        wg.Add(1)
        go func() {
            defer wg.Done()
            for job := range jobCh {
                select {
                case <-ctx.Done():
                    outCh <- Job[T, R]{Input: job.Input, Err: ctx.Err()}
                    continue
                default:
                    r, err := fn(ctx, job.Input)
                    outCh <- Job[T, R]{Input: job.Input, Result: r, Err: err}
                }
            }
        }()
    }

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

    results := make([]Job[T, R], 0, len(inputs))
    for r := range outCh { results = append(results, r) }
    return results
}

func main() {
    ctx := context.Background()
    urls := []string{"url1", "url2", "url3"}

    results := WorkerPool(ctx, urls, runtime.NumCPU(),
        func(ctx context.Context, url string) (string, error) {
            return "OK: " + url, nil
        })

    for _, r := range results {
        fmt.Println(r.Result)
    }
}
07 / 28

Channel Patterns

Pipeline, fan-out/fan-in, semaphore, done channel va errgroup patterns.

channel_patterns.go
PATTERNS
package main

import (
    "fmt"
    "sync"
    "golang.org/x/sync/errgroup"
)

// ═══ 1. PIPELINE ═══
func generate(done <-chan struct{}, nums ...int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for _, n := range nums {
            select {
            case out <- n:
            case <-done: return
            }
        }
    }()
    return out
}

func square(done <-chan struct{}, in <-chan int) <-chan int {
    out := make(chan int)
    go func() {
        defer close(out)
        for n := range in {
            select {
            case out <- n * n:
            case <-done: return
            }
        }
    }()
    return out
}

// ═══ 2. FAN-OUT → FAN-IN ═══
func merge(done <-chan struct{}, cs ...<-chan int) <-chan int {
    var wg sync.WaitGroup
    merged := make(chan int, 10)

    output := func(c <-chan int) {
        defer wg.Done()
        for n := range c {
            select {
            case merged <- n:
            case <-done: return
            }
        }
    }
    wg.Add(len(cs))
    for _, c := range cs { go output(c) }
    go func() { wg.Wait(); close(merged) }()
    return merged
}

// ═══ 3. SEMAPHORE — parallellik cheklash ═══
type Semaphore chan struct{}

func NewSem(n int) Semaphore       { return make(Semaphore, n) }
func (s Semaphore) Acquire()       { s <- struct{}{} }
func (s Semaphore) Release()       { <-s }

// ═══ 4. ERRGROUP — xatolikni propagate qilish ═══
func parallelFetch(urls []string) error {
    g, ctx := errgroup.WithContext(context.Background())
    sem := NewSem(5) // max 5 parallel

    for _, url := range urls {
        url := url // loop var capture!
        g.Go(func() error {
            sem.Acquire()
            defer sem.Release()
            return fetch(ctx, url)
        })
    }
    return g.Wait() // birinchi xato bilan qaytadi
}

func main() {
    done := make(chan struct{})
    defer close(done)

    // Pipeline: generate → square → print
    c := generate(done, 2, 3, 4, 5)
    out := square(done, c)
    for n := range out { fmt.Printf("%d ", n) }
    fmt.Println() // 4 9 16 25
}
08 / 28

sync & atomic Paketi

Mutex, RWMutex, Once, Cond, Map va atomic operatsiyalar. Qaysi birini qachon ishlatish kerakligi.

sync.Map vs map+Mutex — qaysi biri qachon?

sync.Map uchun

Ko'p o'qish, kam yozish. Cache-like patterns. Entry kam o'chiriladi.

map + RWMutex uchun

Ko'p yozish. Iteration kerak. Complex transactions. Umumiy holat.

sync_patterns.go
PROD
package main

import (
    "fmt"
    "sync"
    "sync/atomic"
)

// sync.Once — singleton pattern
type Config struct{ DSN string }

var (
    once   sync.Once
    config *Config
)

func GetConfig() *Config {
    once.Do(func() {
        config = &Config{DSN: "postgres://..."}
    })
    return config // thread-safe singleton
}

// atomic.Value — lock-free read-heavy config
type AtomicConfig struct{ v atomic.Value }

func (c *AtomicConfig) Store(cfg *Config) { c.v.Store(cfg) }
func (c *AtomicConfig) Load() *Config {
    if v := c.v.Load(); v != nil {
        return v.(*Config)
    }
    return nil
}

// atomic int counter — mutex'dan 10x tezroq
type Counter struct{ n atomic.Int64 }
func (c *Counter) Inc()       { c.n.Add(1) }
func (c *Counter) Dec()       { c.n.Add(-1) }
func (c *Counter) Get() int64 { return c.n.Load() }

// sync.Pool — object reuse, GC pressure kamaytirish
var bufPool = sync.Pool{
    New: func() any {
        return make([]byte, 0, 4096)
    },
}

func processData(data []byte) {
    buf := bufPool.Get().([]byte)
    buf = buf[:0] // reset, capacity saqlanadi
    defer bufPool.Put(buf)

    buf = append(buf, data...)
    // buf bilan ishlash
    _ = buf
}

// sync.Cond — condition variable
type Queue struct {
    mu    sync.Mutex
    cond  *sync.Cond
    items []any
}

func NewQueue() *Queue {
    q := &Queue{}
    q.cond = sync.NewCond(&q.mu)
    return q
}

func (q *Queue) Push(item any) {
    q.mu.Lock()
    q.items = append(q.items, item)
    q.cond.Signal() // bir goroutineni uyg'otish
    q.mu.Unlock()
}

func (q *Queue) Pop() any {
    q.mu.Lock()
    defer q.mu.Unlock()
    for len(q.items) == 0 {
        q.cond.Wait() // bo'shatib kutish
    }
    item := q.items[0]
    q.items = q.items[1:]
    return item
}

func main() {
    c := &Counter{}
    var wg sync.WaitGroup
    for i := 0; i < 1000; i++ {
        wg.Add(1)
        go func() { defer wg.Done(); c.Inc() }()
    }
    wg.Wait()
    fmt.Println(c.Get()) // 1000 — har doim
}
09 / 28

Context Package

context.Context — request lifecycle, cancellation, deadline va metadata uzatish uchun standart Go usuli.

context_patterns.go
PROD
package main

import (
    "context"
    "fmt"
    "time"
)

// Context key uchun custom type — conflict oldini olish
type ctxKey string
const (
    KeyUserID    ctxKey = "userID"
    KeyRequestID ctxKey = "requestID"
    KeyLogger    ctxKey = "logger"
)

func WithUserID(ctx context.Context, id int64) context.Context {
    return context.WithValue(ctx, KeyUserID, id)
}

func UserIDFrom(ctx context.Context) (int64, bool) {
    id, ok := ctx.Value(KeyUserID).(int64)
    return id, ok
}

// Timeout bilan request
func fetchWithTimeout(url string) error {
    ctx, cancel := context.WithTimeout(
        context.Background(),
        5*time.Second,
    )
    defer cancel() // MUHIM — har doim defer cancel!

    return doRequest(ctx, url)
}

// Deadline bilan
func withDeadline() {
    deadline := time.Now().Add(10 * time.Second)
    ctx, cancel := context.WithDeadline(context.Background(), deadline)
    defer cancel()

    select {
    case <-time.After(3 * time.Second):
        fmt.Println("Tugadi")
    case <-ctx.Done():
        fmt.Println("Deadline:", ctx.Err())
    }
}

// Propagation — context zanjiri
func handleRequest(ctx context.Context) {
    // Request ID qo'shish
    ctx = context.WithValue(ctx, KeyRequestID, "req-123")

    // User ID qo'shish
    ctx = WithUserID(ctx, 42)

    // Timeout qo'shish (parent cancel → child ham cancel!)
    ctx, cancel := context.WithTimeout(ctx, 3*time.Second)
    defer cancel()

    doDBQuery(ctx)
}

func doDBQuery(ctx context.Context) {
    if uid, ok := UserIDFrom(ctx); ok {
        fmt.Printf("DB query for user %d\n", uid)
    }
    // context cancel bo'lsa query bekor qilinadi
    select {
    case <-time.After(100 * time.Millisecond):
        fmt.Println("DB query OK")
    case <-ctx.Done():
        fmt.Println("DB query cancelled:", ctx.Err())
    }
}

func main() {
    ctx := context.Background()
    handleRequest(ctx)
}
Context faqat funksiya parametri orqali uzatiladi — hech qachon struct ichida saqlash tavsiya etilmaydi. ctx context.Context har doim birinchi parametr bo'ladi.
10 / 28

Race Conditions & -race Detector

Data race — eng yashirin va xavfli xato. Go race detector va ularni oldini olish.

race_patterns.go
CRITICAL
# Race detector bilan ishga tushirish
go run -race main.go
go test -race ./...
go build -race -o app_race main.go

// ❌ 1. Loop variable capture — KLASSIK BUG!
func badLoop() {
    var wg sync.WaitGroup
    items := []string{"a", "b", "c"}
    for _, item := range items {
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Println(item) // c c c — NOTO'G'RI!
        }()
    }
    wg.Wait()
}

// ✅ TO'G'RI — Go 1.22+ da o'z-o'zidan hal bo'ladi
func goodLoop() {
    var wg sync.WaitGroup
    items := []string{"a", "b", "c"}
    for _, item := range items {
        item := item // local copy (Go 1.21 va oldingi)
        wg.Add(1)
        go func() {
            defer wg.Done()
            fmt.Println(item)
        }()
    }
    wg.Wait()
}

// ❌ 2. Shared slice append — race!
func badAppend() []int {
    var results []int
    var mu sync.Mutex
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        i := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            mu.Lock()
            results = append(results, i) // mutex bilan xavfsiz
            mu.Unlock()
        }()
    }
    wg.Wait()
    return results
}

// ✅ BETTER — pre-allocated slice
func betterAppend() []int {
    results := make([]int, 100) // oldindan ajratish
    var wg sync.WaitGroup
    for i := 0; i < 100; i++ {
        i := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            results[i] = i * i // har biri o'z indexiga yozadi
        }()
    }
    wg.Wait()
    return results
}

// ❌ 3. Map concurrent write — PANIC!
// Go 1.6+ da concurrent map write panic beradi
// Yechim: sync.Map yoki map + RWMutex
11 / 28

Profiling & pprof

Go dasturini profilash — CPU, memory, goroutine, mutex bottleneck topish. Production profiling.

pprof yoqish va ishlatish
pprof_setup.go
PERF
package main

import (
    "net/http"
    _ "net/http/pprof" // import yetarli — endpoints qo'shiladi
    "runtime/pprof"
    "os"
    "time"
    "log"
)

// 1. HTTP endpoint — production'da
func startPprof() {
    go func() {
        log.Println(http.ListenAndServe("localhost:6060", nil))
    }()
    // http://localhost:6060/debug/pprof/
}

// 2. File'ga yozish — batch jobs uchun
func profileToFile() {
    // CPU profiling
    cpuF, _ := os.Create("cpu.prof")
    defer cpuF.Close()
    pprof.StartCPUProfile(cpuF)
    defer pprof.StopCPUProfile()

    // ... ishlar bajariladi ...
    time.Sleep(5 * time.Second)

    // Memory profiling
    memF, _ := os.Create("mem.prof")
    defer memF.Close()
    pprof.WriteHeapProfile(memF)
}

/* Terminal komandalari:

# CPU profiling
go tool pprof cpu.prof
(pprof) top10
(pprof) web         # brauzerda grafik
(pprof) list main.fn

# Memory profiling
go tool pprof mem.prof
(pprof) top -cum    # kumulativ
(pprof) alloc_space

# HTTP'dan
go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
go tool pprof http://localhost:6060/debug/pprof/heap

# Flamegraph (eng qulay!)
go tool pprof -http=:8080 cpu.prof

# Goroutine leak tekshirish
curl http://localhost:6060/debug/pprof/goroutine?debug=2

# Trace — scheduler ko'rish
curl http://localhost:6060/debug/pprof/trace?seconds=5 > trace.out
go tool trace trace.out
*/
Benchmark bilan Profiling
bench_profile.sh
# Benchmark + CPU profile
go test -bench=. -cpuprofile=cpu.prof -memprofile=mem.prof ./...

# Vizual analiz
go tool pprof -http=:8080 cpu.prof

# Specific benchmark
go test -bench=BenchmarkMyFunc -benchmem -count=5 -run=^$

# Flame graph veb UI
# go install github.com/google/pprof@latest
pprof -http=:8080 cpu.prof
12 / 28

Escape Analysis & Heap

Qaysi o'zgaruvchi stackda, qaysi biri heapda saqlanadi — kompilyator qarorlari va ularni boshqarish.

escape.go
EXPERT
# Escape analysis ko'rish:
go build -gcflags="-m -m" ./...
go build -gcflags="-m" ./...

package main

// STACK allocatsiya → tezroq, GC yo'q
func stackAlloc() int {
    x := 42     // STACK — funksiya tugagach yo'qoladi
    return x
}

// HEAP allocatsiya → GC kerak
func heapAlloc() *int {
    x := 42     // HEAP — pointer qaytariladi, "escapes"
    return &x   // gcflags: "x escapes to heap"
}

// Interface'ga assign → heap'ga escape
func interfaceEscape() {
    x := 42
    var i interface{} = x // x heapga ko'chadi!
    _ = i
}

// Closure'da capture → heap
func closureEscape() func() int {
    x := 0   // heapga escape — closure captures it
    return func() int { x++; return x }
}

// ✅ Inlining — funksiya call'ini yo'q qilish
// Kichik, oddiy funksiyalar inline qilinadi
// //go:noinline — inliningni o'chirish

// ✅ Pre-allocate — escape'ni kamaytirish
func withPrealloc(n int) []int {
    s := make([]int, 0, n) // capacity oldindan
    for i := 0; i < n; i++ {
        s = append(s, i) // realloc yo'q!
    }
    return s
}

// ✅ String builder — ko'p concatenation uchun
import "strings"
func buildString(parts []string) string {
    var sb strings.Builder
    sb.Grow(len(parts) * 10) // oldindan joy ajratish
    for _, p := range parts {
        sb.WriteString(p)
    }
    return sb.String()
}

Stack (tez)

Lokal o'zgaruvchilar, kichik struct, pointer qaytarilmagan. GC yo'q.

Heap (sekin)

Pointer qaytarilgan, interface'ga assign, goroutine'da capture.

Optimization

Pre-alloc, sync.Pool, strings.Builder, value types vs pointers.

13 / 28

Memory Pooling & Allocation

sync.Pool, arena allocator, slab pattern va zero-allocation techniques.

pool_patterns.go
PERF
package main

import (
    "bytes"
    "encoding/json"
    "sync"
)

// ═══ bytes.Buffer Pool ═══
var bufferPool = &sync.Pool{
    New: func() any { return &bytes.Buffer{} },
}

func marshalJSON(v any) ([]byte, error) {
    buf := bufferPool.Get().(*bytes.Buffer)
    buf.Reset()
    defer bufferPool.Put(buf)

    enc := json.NewEncoder(buf)
    if err := enc.Encode(v); err != nil {
        return nil, err
    }
    // buf'dan copy — pool'ga qaytishidan oldin
    result := make([]byte, buf.Len())
    copy(result, buf.Bytes())
    return result, nil
}

// ═══ Typed Object Pool ═══
type RequestContext struct {
    UserID    int64
    RequestID string
    Data      []byte
}

func (r *RequestContext) Reset() {
    r.UserID = 0
    r.RequestID = ""
    r.Data = r.Data[:0] // capacity saqlash
}

type RequestPool struct{ p sync.Pool }

func NewRequestPool() *RequestPool {
    return &RequestPool{
        p: sync.Pool{New: func() any {
            return &RequestContext{Data: make([]byte, 0, 1024)}
        }},
    }
}

func (rp *RequestPool) Get() *RequestContext {
    return rp.p.Get().(*RequestContext)
}

func (rp *RequestPool) Put(r *RequestContext) {
    r.Reset()
    rp.p.Put(r)
}

// ═══ Zero-allocation string ops ═══
import "unsafe"

// String → []byte conversion (allocation yo'q, xavfli!)
func unsafeStringToBytes(s string) []byte {
    return unsafe.Slice(unsafe.StringData(s), len(s))
}

// []byte → string conversion (allocation yo'q)
func unsafeBytesToString(b []byte) string {
    return unsafe.String(&b[0], len(b))
}
// ⚠ FAQAT read-only operatsiyalarda!
14 / 28

SIMD & Go Assembly

Go'da past darajali optimizatsiya — assembler, AVX/SSE hints va compiler directives.

assembly_hints.go
EXPERT
package main

// Compiler directives — //go: prefixi

//go:noinline — bu funksiyani inline qilma
func heavyCalc(n int) int { return n * n }

//go:nosplit — stack split oldini ol (hot path)
func fastPath(x int) int { return x + 1 }

//go:linkname — boshqa package'ning private funksiyasiga
// (xavfli, faqat stdlib patching uchun)

// Bounds check elimination — kompilyatorga yordam berish
func sumSlice(s []int) int {
    // Bu pattern bounds check'ni yo'q qiladi:
    s = s[:len(s)] // hint: s is valid
    total := 0
    for _, v := range s {
        total += v
    }
    return total
}

// Manual SIMD via goroutines (Go'da native SIMD yo'q)
func parallelSum(data []float64) float64 {
    chunks := runtime.NumCPU()
    size := (len(data) + chunks - 1) / chunks
    sums := make([]float64, chunks)
    var wg sync.WaitGroup

    for i := 0; i < chunks; i++ {
        i := i
        wg.Add(1)
        go func() {
            defer wg.Done()
            lo := i * size
            hi := lo + size
            if hi > len(data) { hi = len(data) }
            for _, v := range data[lo:hi] { sums[i] += v }
        }()
    }
    wg.Wait()

    total := 0.0
    for _, s := range sums { total += s }
    return total
}

// Assembly file: sum_amd64.s
// TEXT ·sumAVX(SB),NOSPLIT,$0
//   VMOVDQU (SI), Y0
//   VMOVDQU 32(SI), Y1
//   VADDPS Y0, Y1, Y0
//   VMOVDQU Y0, (DI)
//   RET
15 / 28

Clean Architecture

Go'da loyiha tuzilmasi — standard layout, clean architecture qoidalari va dependency direction.

Loyiha Strukturasi — Standard Layout
project structure
myapp/
├── cmd/
│   ├── api/
│   │   └── main.go          # HTTP server entry point
│   ├── worker/
│   │   └── main.go          # Background worker
│   └── migrate/
│       └── main.go          # DB migrations
├── internal/                # Private packages
│   ├── domain/              # Business entities + interfaces
│   │   ├── user.go
│   │   ├── order.go
│   │   └── repository.go    # interface definitions
│   ├── usecase/             # Business logic
│   │   ├── user_usecase.go
│   │   └── order_usecase.go
│   ├── repository/          # DB implementation
│   │   ├── postgres/
│   │   └── redis/
│   ├── delivery/            # HTTP/gRPC handlers
│   │   ├── http/
│   │   └── grpc/
│   └── config/
│       └── config.go
├── pkg/                     # Public reusable packages
│   ├── logger/
│   ├── validator/
│   └── pagination/
├── migrations/              # SQL migrations
├── docs/                    # Swagger/OpenAPI
├── docker/
├── Makefile
├── go.mod
└── go.sum
Domain Layer — Entities & Interfaces
internal/domain/user.go
package domain

import (
    "context"
    "time"
    "errors"
)

// Domain Entity — biznes qoidalari bu yerda
type User struct {
    ID        int64
    Email     string
    Name      string
    Role      Role
    CreatedAt time.Time
    UpdatedAt time.Time
    DeletedAt *time.Time
}

type Role string
const (
    RoleAdmin  Role = "admin"
    RoleUser   Role = "user"
    RoleGuest  Role = "guest"
)

// Domain errors
var (
    ErrUserNotFound    = errors.New("user not found")
    ErrEmailExists     = errors.New("email already exists")
    ErrInvalidPassword = errors.New("invalid password")
)

// Domain validation
func (u *User) Validate() error {
    if u.Email == "" {
        return &ValidationError{Field: "email", Msg: "required"}
    }
    if u.Name == "" {
        return &ValidationError{Field: "name", Msg: "required"}
    }
    return nil
}

// Repository Interface — domain layer'da e'lon qilinadi
type UserRepository interface {
    Create(ctx context.Context, user *User) error
    GetByID(ctx context.Context, id int64) (*User, error)
    GetByEmail(ctx context.Context, email string) (*User, error)
    Update(ctx context.Context, user *User) error
    Delete(ctx context.Context, id int64) error
    List(ctx context.Context, filter UserFilter) ([]*User, int64, error)
}

type UserUsecase interface {
    Register(ctx context.Context, req RegisterRequest) (*User, error)
    Login(ctx context.Context, email, password string) (string, error)
    GetProfile(ctx context.Context, id int64) (*User, error)
}
16 / 28

Dependency Injection

Go'da DI — constructor injection, wire framework va testing uchun mock.

internal/usecase/user_usecase.go
CLEAN
package usecase

import (
    "context"
    "time"
    "myapp/internal/domain"
)

// Dependencies — interface orqali
type UserUsecase struct {
    repo   domain.UserRepository  // interface!
    cache  domain.CacheService
    mailer domain.MailService
    hasher domain.PasswordHasher
    logger domain.Logger
}

// Constructor Injection
func NewUserUsecase(
    repo   domain.UserRepository,
    cache  domain.CacheService,
    mailer domain.MailService,
    hasher domain.PasswordHasher,
    logger domain.Logger,
) *UserUsecase {
    return &UserUsecase{repo, cache, mailer, hasher, logger}
}

func (uc *UserUsecase) Register(
    ctx context.Context,
    req domain.RegisterRequest,
) (*domain.User, error) {
    // Validation
    if err := req.Validate(); err != nil {
        return nil, err
    }

    // Email mavjudligini tekshirish
    _, err := uc.repo.GetByEmail(ctx, req.Email)
    if err == nil {
        return nil, domain.ErrEmailExists
    }

    // Password hash
    hash, err := uc.hasher.Hash(req.Password)
    if err != nil {
        return nil, fmt.Errorf("hash: %w", err)
    }

    user := &domain.User{
        Email:     req.Email,
        Name:      req.Name,
        Role:      domain.RoleUser,
        CreatedAt: time.Now(),
    }

    if err := uc.repo.Create(ctx, user); err != nil {
        return nil, fmt.Errorf("create user: %w", err)
    }

    // Welcome email (asinxron)
    go uc.mailer.SendWelcome(context.Background(), user.Email)

    uc.logger.Info("user registered", "id", user.ID)
    return user, nil
}

// ═══ google/wire bilan DI (kod generatsiya) ═══
// go install github.com/google/wire/cmd/wire@latest

// wire.go
//go:build wireinject

func InitApp(cfg *config.Config) (*App, func(), error) {
    panic(wire.Build(
        postgres.NewDB,
        repository.NewUserRepo,
        usecase.NewUserUsecase,
        http.NewServer,
        wire.Struct(new(App), "*"),
    ))
}
17 / 28

Domain-Driven Design

Go'da DDD — Aggregate, Value Object, Domain Event, Repository va Saga patterns.

internal/domain/order.go
DDD
package domain

import ("time"; "errors"; "fmt")

// Value Object — immutable, equality by value
type Money struct {
    Amount   int64  // tiyinlarda (float yordatmaslik!)
    Currency string
}

func NewMoney(amount int64, currency string) (Money, error) {
    if amount < 0 { return Money{}, errors.New("negative amount") }
    if currency == "" { return Money{}, errors.New("empty currency") }
    return Money{amount, currency}, nil
}

func (m Money) Add(other Money) (Money, error) {
    if m.Currency != other.Currency {
        return Money{}, fmt.Errorf("currency mismatch: %s vs %s", m.Currency, other.Currency)
    }
    return Money{m.Amount + other.Amount, m.Currency}, nil
}

// Domain Event
type OrderPlaced struct {
    OrderID   int64
    UserID    int64
    Total     Money
    OccuredAt time.Time
}

// Aggregate Root — invariantlarni saqlaydi
type Order struct {
    id        int64
    userID    int64
    items     []OrderItem
    status    OrderStatus
    total     Money
    createdAt time.Time
    events    []any  // domain events
}

func NewOrder(userID int64) *Order {
    return &Order{
        userID:    userID,
        status:    OrderStatusDraft,
        createdAt: time.Now(),
    }
}

// Business rule — faqat Draft statusda item qo'shish mumkin
func (o *Order) AddItem(item OrderItem) error {
    if o.status != OrderStatusDraft {
        return fmt.Errorf("cannot add item to %s order", o.status)
    }
    o.items = append(o.items, item)
    o.total, _ = o.total.Add(item.Price)
    return nil
}

func (o *Order) Place() error {
    if len(o.items) == 0 {
        return errors.New("cannot place empty order")
    }
    o.status = OrderStatusPending
    // Domain event qo'shish
    o.events = append(o.events, OrderPlaced{
        OrderID: o.id, UserID: o.userID,
        Total: o.total, OccuredAt: time.Now(),
    })
    return nil
}

func (o *Order) PopEvents() []any {
    events := o.events
    o.events = nil
    return events
}
18 / 28

Microservices Patterns

Circuit breaker, retry, rate limiting, service discovery va distributed tracing.

resilience_patterns.go
PROD
package resilience

import (
    "context"
    "errors"
    "sync/atomic"
    "time"
)

// ═══ Circuit Breaker ═══
type State int32
const (
    StateClosed   State = iota // Normal ishlaydi
    StateOpen                    // Barcha so'rovlar rad
    StateHalfOpen                // Test so'rovlari
)

type CircuitBreaker struct {
    state        atomic.Int32
    failures     atomic.Int64
    lastFailure  atomic.Int64
    maxFailures  int64
    timeout      time.Duration
}

var ErrCircuitOpen = errors.New("circuit breaker is open")

func NewCircuitBreaker(maxF int64, timeout time.Duration) *CircuitBreaker {
    return &CircuitBreaker{maxFailures: maxF, timeout: timeout}
}

func (cb *CircuitBreaker) Execute(fn func() error) error {
    switch State(cb.state.Load()) {
    case StateOpen:
        if time.Since(time.Unix(cb.lastFailure.Load(), 0)) > cb.timeout {
            cb.state.Store(int32(StateHalfOpen))
        } else {
            return ErrCircuitOpen
        }
    }

    err := fn()
    if err != nil {
        cb.failures.Add(1)
        cb.lastFailure.Store(time.Now().Unix())
        if cb.failures.Load() >= cb.maxFailures {
            cb.state.Store(int32(StateOpen))
        }
        return err
    }
    cb.failures.Store(0)
    cb.state.Store(int32(StateClosed))
    return nil
}

// ═══ Retry with Exponential Backoff ═══
func RetryWithBackoff(
    ctx    context.Context,
    maxN   int,
    initD  time.Duration,
    fn     func() error,
) error {
    var err error
    delay := initD
    for i := 0; i < maxN; i++ {
        if err = fn(); err == nil { return nil }
        select {
        case <-ctx.Done(): return ctx.Err()
        case <-time.After(delay):
            delay *= 2 // exponential
            if delay > 30*time.Second { delay = 30*time.Second }
        }
    }
    return fmt.Errorf("after %d retries: %w", maxN, err)
}

// ═══ Token Bucket Rate Limiter ═══
type RateLimiter struct {
    tokens  float64
    maxTok  float64
    refill  float64 // per second
    lastRef time.Time
    mu      sync.Mutex
}

func (rl *RateLimiter) Allow() bool {
    rl.mu.Lock()
    defer rl.mu.Unlock()

    now := time.Now()
    elapsed := now.Sub(rl.lastRef).Seconds()
    rl.tokens = min(rl.maxTok, rl.tokens+elapsed*rl.refill)
    rl.lastRef = now

    if rl.tokens >= 1 {
        rl.tokens--
        return true
    }
    return false
}
19 / 28

Testing — Unit & Table

Go'da testing — table-driven tests, subtests, mock, testify va test coverage.

user_usecase_test.go
TEST
package usecase_test

import (
    "context"
    "testing"
    "errors"
    "github.com/stretchr/testify/assert"
    "github.com/stretchr/testify/mock"
    "github.com/stretchr/testify/require"
)

// Mock — interface'ni implement qiladi
type MockUserRepo struct{ mock.Mock }

func (m *MockUserRepo) GetByEmail(ctx context.Context, email string) (*domain.User, error) {
    args := m.Called(ctx, email)
    if args.Get(0) == nil { return nil, args.Error(1) }
    return args.Get(0).(*domain.User), args.Error(1)
}

func (m *MockUserRepo) Create(ctx context.Context, user *domain.User) error {
    args := m.Called(ctx, user)
    return args.Error(0)
}

// Table-Driven Tests
func TestRegister(t *testing.T) {
    tests := []struct {
        name      string
        input     domain.RegisterRequest
        setupMock func(*MockUserRepo)
        wantErr   error
        wantUser  bool
    }{
        {
            name:  "success",
            input: domain.RegisterRequest{Email: "ali@test.com", Name: "Ali", Password: "pass123"},
            setupMock: func(m *MockUserRepo) {
                m.On("GetByEmail", mock.Anything, "ali@test.com").Return(nil, domain.ErrUserNotFound)
                m.On("Create", mock.Anything, mock.AnythingOfType("*domain.User")).Return(nil)
            },
            wantUser: true,
        },
        {
            name:  "email_exists",
            input: domain.RegisterRequest{Email: "ali@test.com", Name: "Ali", Password: "pass"},
            setupMock: func(m *MockUserRepo) {
                m.On("GetByEmail", mock.Anything, "ali@test.com").Return(&domain.User{}, nil)
            },
            wantErr: domain.ErrEmailExists,
        },
        {
            name:    "empty_email",
            input:   domain.RegisterRequest{Name: "Ali"},
            setupMock: func(m *MockUserRepo) {},
            wantErr: &domain.ValidationError{},
        },
    }

    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            mockRepo := &MockUserRepo{}
            tt.setupMock(mockRepo)

            uc := usecase.NewUserUsecase(mockRepo, ...)
            user, err := uc.Register(context.Background(), tt.input)

            if tt.wantErr != nil {
                require.Error(t, err)
                assert.True(t, errors.Is(err, tt.wantErr) ||
                    errors.As(err, &tt.wantErr))
            } else {
                require.NoError(t, err)
                assert.Equal(t, tt.wantUser, user != nil)
            }
            mockRepo.AssertExpectations(t)
        })
    }
}

# Test ishga tushirish:
go test ./... -v
go test ./... -cover -coverprofile=coverage.out
go tool cover -html=coverage.out
20 / 28

Integration & E2E Tests

testcontainers bilan real DB, httptest bilan HTTP, goldie bilan snapshot testing.

integration_test.go
TEST
//go:build integration

package repository_test

import (
    "context"
    "testing"
    "net/http"
    "net/http/httptest"
    "github.com/testcontainers/testcontainers-go"
    "github.com/testcontainers/testcontainers-go/modules/postgres"
    "github.com/stretchr/testify/suite"
)

// Test Suite — setup/teardown bilan
type UserRepoSuite struct {
    suite.Suite
    container *postgres.PostgresContainer
    repo      domain.UserRepository
    db        *sqlx.DB
}

func (s *UserRepoSuite) SetupSuite() {
    ctx := context.Background()

    // Real Postgres container!
    container, err := postgres.RunContainer(ctx,
        testcontainers.WithImage("postgres:16-alpine"),
        postgres.WithDatabase("testdb"),
        postgres.WithUsername("test"),
        postgres.WithPassword("test"),
        testcontainers.WithWaitStrategy(
            wait.ForLog("ready to accept connections"),
        ),
    )
    s.Require().NoError(err)
    s.container = container

    dsn, _ := container.ConnectionString(ctx, "sslmode=disable")
    s.db = sqlx.MustConnect("postgres", dsn)
    runMigrations(s.db)
    s.repo = repository.NewUserRepo(s.db)
}

func (s *UserRepoSuite) TearDownSuite() {
    s.container.Terminate(context.Background())
}

func (s *UserRepoSuite) TestCreate() {
    user := &domain.User{Email: "test@test.com", Name: "Test"}
    err := s.repo.Create(context.Background(), user)
    s.NoError(err)
    s.NotZero(user.ID)
}

// ═══ HTTP Integration Test ═══
func TestHTTPHandler(t *testing.T) {
    // Real handler, real dependencies
    handler := setupHandler()
    srv := httptest.NewServer(handler)
    defer srv.Close()

    resp, err := http.Get(srv.URL + "/api/users/1")
    require.NoError(t, err)
    assert.Equal(t, http.StatusOK, resp.StatusCode)

    var user domain.User
    json.NewDecoder(resp.Body).Decode(&user)
    assert.NotEmpty(t, user.Email)
}

# Ishga tushirish:
go test -tags=integration ./...
go test -run TestHTTPHandler ./internal/delivery/http/...
21 / 28

Benchmarking & Optimization

Go benchmark yozish, benchstat bilan taqqoslash va micro-optimization patterns.

bench_test.go
BENCH
package main_test

import (
    "testing"
    "strings"
    "fmt"
    "bytes"
)

// String concatenation — 3 usul taqqoslash
func BenchmarkStringConcat(b *testing.B) {
    parts := []string{"hello", "world", "go", "lang"}

    b.Run("Plus operator", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            result := ""
            for _, p := range parts { result += p }
            _ = result
        }
    })

    b.Run("strings.Builder", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            var sb strings.Builder
            sb.Grow(40)
            for _, p := range parts { sb.WriteString(p) }
            _ = sb.String()
        }
    })

    b.Run("strings.Join", func(b *testing.B) {
        for i := 0; i < b.N; i++ {
            _ = strings.Join(parts, "")
        }
    })
}

// Memory allocation benchmark
func BenchmarkAlloc(b *testing.B) {
    b.Run("WithPrealloc", func(b *testing.B) {
        b.ReportAllocs() // allocations ko'rsatish
        for i := 0; i < b.N; i++ {
            s := make([]int, 0, 1000)
            for j := 0; j < 1000; j++ { s = append(s, j) }
        }
    })

    b.Run("WithoutPrealloc", func(b *testing.B) {
        b.ReportAllocs()
        for i := 0; i < b.N; i++ {
            var s []int  // dynamic resize!
            for j := 0; j < 1000; j++ { s = append(s, j) }
        }
    })
}

/* Benchmark natijalar:
BenchmarkStringConcat/Plus_operator-12    2000000   850 ns/op   128 B/op   5 allocs/op
BenchmarkStringConcat/strings.Builder-12  8000000   145 ns/op    64 B/op   2 allocs/op
BenchmarkStringConcat/strings.Join-12    10000000    98 ns/op    32 B/op   1 allocs/op

# benchstat bilan taqqoslash:
go test -bench=. -count=5 | tee old.txt
# optimizatsiya qilish
go test -bench=. -count=5 | tee new.txt
benchstat old.txt new.txt
*/
22 / 28

Observability — Logs, Metrics, Traces

slog (structured logging), Prometheus metrics, OpenTelemetry distributed tracing.

observability.go
PROD
package main

import (
    "context"
    "log/slog"  // Go 1.21+ standart structured log
    "os"
    "github.com/prometheus/client_golang/prometheus"
    "go.opentelemetry.io/otel"
    "go.opentelemetry.io/otel/trace"
)

// ═══ 1. Structured Logging (slog) ═══
func setupLogger() *slog.Logger {
    // JSON format production uchun
    handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
        Level: slog.LevelInfo,
        ReplaceAttr: func(groups []string, a slog.Attr) slog.Attr {
            if a.Key == slog.TimeKey { a.Value = slog.StringValue(a.Value.Time().Format(time.RFC3339)) }
            return a
        },
    })
    return slog.New(handler)
}

// Contextual logger — request ID bilan
func logWithCtx(ctx context.Context, log *slog.Logger) *slog.Logger {
    if rid, ok := ctx.Value(KeyRequestID).(string); ok {
        return log.With("request_id", rid)
    }
    return log
}

// ═══ 2. Prometheus Metrics ═══
var (
    httpRequests = prometheus.NewCounterVec(
        prometheus.CounterOpts{
            Name: "http_requests_total",
            Help: "Total HTTP requests",
        },
        []string{"method", "path", "status"},
    )

    httpDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "HTTP request duration",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "path"},
    )

    activeConns = prometheus.NewGauge(prometheus.GaugeOpts{
        Name: "active_connections",
        Help: "Active DB connections",
    })
)

func init() {
    prometheus.MustRegister(httpRequests, httpDuration, activeConns)
}

// Metrics middleware
func metricsMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        timer := prometheus.NewTimer(httpDuration.WithLabelValues(r.Method, r.URL.Path))
        defer timer.ObserveDuration()

        rw := &responseWriter{ResponseWriter: w, status: 200}
        next.ServeHTTP(rw, r)

        httpRequests.WithLabelValues(
            r.Method, r.URL.Path, fmt.Sprint(rw.status),
        ).Inc()
    })
}

// ═══ 3. OpenTelemetry Tracing ═══
var tracer = otel.Tracer("myapp")

func doDBQuery(ctx context.Context, query string) error {
    ctx, span := tracer.Start(ctx, "db.query")
    defer span.End()

    span.SetAttributes(
        attribute.String("db.statement", query),
        attribute.String("db.system", "postgresql"),
    )
    // DB query ishlashi ...
    return nil
}
23 / 28

gRPC & Protobuf

Protocol Buffers, gRPC server/client, interceptors, streaming va connect-go.

user.proto
syntax = "proto3";
package user.v1;
option go_package = "myapp/gen/user/v1;userv1";

import "google/protobuf/timestamp.proto";

message User {
    int64  id         = 1;
    string email      = 2;
    string name       = 3;
    google.protobuf.Timestamp created_at = 4;
}

message GetUserRequest  { int64 id = 1; }
message GetUserResponse { User user = 1; }

message ListUsersRequest {
    int32 page      = 1;
    int32 page_size = 2;
}
message ListUsersResponse {
    repeated User users = 1;
    int64 total = 2;
}

service UserService {
    rpc GetUser(GetUserRequest) returns (GetUserResponse);
    rpc ListUsers(ListUsersRequest) returns (ListUsersResponse);
    rpc WatchUsers(GetUserRequest) returns (stream User); // Server streaming
}
grpc_server.go
gRPC
package grpc

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/status"
    "google.golang.org/grpc/metadata"
    userv1 "myapp/gen/user/v1"
)

type UserServer struct {
    userv1.UnimplementedUserServiceServer
    uc domain.UserUsecase
}

func (s *UserServer) GetUser(
    ctx context.Context,
    req *userv1.GetUserRequest,
) (*userv1.GetUserResponse, error) {
    user, err := s.uc.GetProfile(ctx, req.Id)
    if err != nil {
        if errors.Is(err, domain.ErrUserNotFound) {
            return nil, status.Errorf(codes.NotFound, "user %d not found", req.Id)
        }
        return nil, status.Errorf(codes.Internal, "internal error")
    }
    return &userv1.GetUserResponse{User: toProto(user)}, nil
}

// gRPC Interceptor — middleware
func authInterceptor(
    ctx context.Context,
    req any,
    info *grpc.UnaryServerInfo,
    handler grpc.UnaryHandler,
) (any, error) {
    md, ok := metadata.FromIncomingContext(ctx)
    if !ok {
        return nil, status.Error(codes.Unauthenticated, "no metadata")
    }

    tokens := md.Get("authorization")
    if len(tokens) == 0 {
        return nil, status.Error(codes.Unauthenticated, "no token")
    }

    claims, err := validateToken(tokens[0])
    if err != nil {
        return nil, status.Error(codes.Unauthenticated, "invalid token")
    }

    ctx = WithUserID(ctx, claims.UserID)
    return handler(ctx, req)
}

// Server sozlash
func NewGRPCServer(uc domain.UserUsecase) *grpc.Server {
    srv := grpc.NewServer(
        grpc.UnaryInterceptor(authInterceptor),
        grpc.MaxRecvMsgSize(16 << 20), // 16MB
    )
    userv1.RegisterUserServiceServer(srv, &UserServer{uc: uc})
    return srv
}
24 / 28

HTTP Server Patterns

net/http chuqur, custom mux, middleware chain, chi router va HTTP/2.

http_server.go
PROD
package http

import (
    "context"
    "encoding/json"
    "net/http"
    "time"
    "github.com/go-chi/chi/v5"
    "github.com/go-chi/chi/v5/middleware"
)

type Server struct {
    srv *http.Server
    uc  domain.UserUsecase
}

func NewServer(uc domain.UserUsecase, cfg *Config) *Server {
    s := &Server{uc: uc}

    r := chi.NewRouter()

    // Global middleware
    r.Use(middleware.RequestID)
    r.Use(middleware.RealIP)
    r.Use(middleware.Logger)
    r.Use(middleware.Recoverer)
    r.Use(middleware.Timeout(30 * time.Second))
    r.Use(s.corsMiddleware)

    // Routes
    r.Route("/api/v1", func(r chi.Router) {
        r.Route("/users", func(r chi.Router) {
            r.Post("/", s.createUser)
            r.Get("/", s.listUsers)

            r.With(s.authMiddleware).Route("/{id}", func(r chi.Router) {
                r.Get("/", s.getUser)
                r.Put("/", s.updateUser)
                r.Delete("/", s.deleteUser)
            })
        })
    })

    s.srv = &http.Server{
        Addr:              cfg.Addr,
        Handler:           r,
        ReadTimeout:       15 * time.Second,
        WriteTimeout:      15 * time.Second,
        IdleTimeout:       60 * time.Second,
        ReadHeaderTimeout: 5 * time.Second,
        MaxHeaderBytes:    1 << 20,
    }
    return s
}

// Graceful shutdown
func (s *Server) Run(ctx context.Context) error {
    errCh := make(chan error, 1)
    go func() {
        if err := s.srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
            errCh <- err
        }
    }()

    select {
    case err := <-errCh: return err
    case <-ctx.Done():
        shutCtx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
        defer cancel()
        return s.srv.Shutdown(shutCtx)
    }
}

// JSON helper
func respondJSON(w http.ResponseWriter, status int, data any) {
    w.Header().Set("Content-Type", "application/json")
    w.WriteHeader(status)
    json.NewEncoder(w).Encode(data)
}
25 / 28

Database — sqlx & ORM

sqlx, pgx, goose migrations, connection pooling va query optimization.

repository.go
DB
package repository

import (
    "context"
    "fmt"
    "github.com/jmoiern/sqlx"
    _ "github.com/jackc/pgx/v5/stdlib"
)

type UserRepo struct{ db *sqlx.DB }

func NewUserRepo(db *sqlx.DB) *UserRepo { return &UserRepo{db} }

// Named query — SQL injection safe
func (r *UserRepo) Create(ctx context.Context, user *domain.User) error {
    query := `
        INSERT INTO users (email, name, role, created_at)
        VALUES (:email, :name, :role, NOW())
        RETURNING id, created_at`

    rows, err := r.db.NamedQueryContext(ctx, query, user)
    if err != nil {
        return pgError(err) // postgres xatolarini domain error'ga o'girish
    }
    defer rows.Close()
    if rows.Next() { rows.StructScan(user) }
    return nil
}

// Bulk insert — N+1 dan qochish
func (r *UserRepo) BulkCreate(ctx context.Context, users []*domain.User) error {
    _, err := r.db.NamedExecContext(ctx, `
        INSERT INTO users (email, name, role)
        VALUES (:email, :name, :role)
        ON CONFLICT (email) DO NOTHING`, users)
    return err
}

// Transaction pattern
func (r *UserRepo) WithTx(ctx context.Context, fn func(*sqlx.Tx) error) error {
    tx, err := r.db.BeginTxx(ctx, nil)
    if err != nil { return err }

    defer func() {
        if p := recover(); p != nil {
            tx.Rollback()
            panic(p)
        }
    }()

    if err := fn(tx); err != nil {
        tx.Rollback()
        return err
    }
    return tx.Commit()
}

// Connection Pool sozlash
func NewDB(dsn string) (*sqlx.DB, error) {
    db, err := sqlx.Connect("pgx", dsn)
    if err != nil { return nil, fmt.Errorf("connect: %w", err) }

    db.SetMaxOpenConns(25)        // max ochiq connections
    db.SetMaxIdleConns(5)         // idle pool size
    db.SetConnMaxLifetime(5 * time.Minute)
    db.SetConnMaxIdleTime(2 * time.Minute)
    return db, nil
}
26 / 28

CLI Tools — cobra & viper

Professional CLI qurish — cobra subcommands, viper config, pflag va completion.

cmd/root.go
CLI
package cmd

import (
    "fmt"
    "os"
    "github.com/spf13/cobra"
    "github.com/spf13/viper"
)

var cfgFile string

var rootCmd = &cobra.Command{
    Use:   "myapp",
    Short: "MyApp — server boshqaruv CLI",
    Long:  `Production-grade CLI tool for managing MyApp`,
}

var serveCmd = &cobra.Command{
    Use:   "serve",
    Short: "HTTP serverni ishga tushirish",
    RunE: func(cmd *cobra.Command, args []string) error {
        port := viper.GetInt("server.port")
        fmt.Printf("Starting server on :%d\n", port)
        return runServer(port)
    },
}

var migrateCmd = &cobra.Command{
    Use:   "migrate [up|down|status]",
    Short: "DB migratsiyalarni boshqarish",
    Args:  cobra.ExactArgs(1),
    ValidArgs: []string{"up", "down", "status", "create"},
    RunE: func(cmd *cobra.Command, args []string) error {
        return runMigration(args[0])
    },
}

func init() {
    cobra.OnInitialize(initConfig)

    rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file")

    serveCmd.Flags().Int("port", 8080, "Port raqami")
    viper.BindPFlag("server.port", serveCmd.Flags().Lookup("port"))

    rootCmd.AddCommand(serveCmd, migrateCmd)

    // Shell completion
    rootCmd.AddCommand(&cobra.Command{
        Use:   "completion [bash|zsh|fish|powershell]",
        Short: "Shell completion skriptini chiqarish",
        RunE: func(cmd *cobra.Command, args []string) error {
            switch args[0] {
            case "bash":  return rootCmd.GenBashCompletion(os.Stdout)
            case "zsh":   return rootCmd.GenZshCompletion(os.Stdout)
            case "fish":  return rootCmd.GenFishCompletion(os.Stdout, true)
            }
            return nil
        },
    })
}

func initConfig() {
    if cfgFile != "" {
        viper.SetConfigFile(cfgFile)
    } else {
        viper.AddConfigPath(".")
        viper.AddConfigPath("$HOME/.config/myapp")
        viper.SetConfigName("config")
        viper.SetConfigType("yaml")
    }
    viper.AutomaticEnv()  // env vars: MYAPP_SERVER_PORT
    viper.ReadInConfig()
}

func Execute() {
    if err := rootCmd.Execute(); err != nil {
        os.Exit(1)
    }
}
27 / 28

Reflection & unsafe

reflect paketi bilan runtime type info, struct tags, JSON-like serializer va unsafe pointer operatsiyalari.

reflection.go
EXPERT
package main

import (
    "fmt"
    "reflect"
    "strings"
    "unsafe"
)

// Struct tags o'qish — custom serializer
func structToMap(v any) map[string]any {
    result := make(map[string]any)
    val := reflect.ValueOf(v)
    typ := reflect.TypeOf(v)

    if val.Kind() == reflect.Ptr {
        val = val.Elem()
        typ = typ.Elem()
    }

    for i := 0; i < typ.NumField(); i++ {
        field := typ.Field(i)
        tag := field.Tag.Get("db")
        if tag == "-" { continue }
        if tag == "" { tag = strings.ToLower(field.Name) }

        parts := strings.Split(tag, ",")
        name := parts[0]
        omit := len(parts) > 1 && parts[1] == "omitempty"

        fieldVal := val.Field(i)
        if omit && fieldVal.IsZero() { continue }
        result[name] = fieldVal.Interface()
    }
    return result
}

// Generic deep copy via reflection
func deepCopy[T any](src T) T {
    srcVal := reflect.ValueOf(&src).Elem()
    dst := reflect.New(srcVal.Type()).Elem()
    copyValue(dst, srcVal)
    return dst.Interface().(T)
}

func copyValue(dst, src reflect.Value) {
    switch src.Kind() {
    case reflect.Slice:
        if src.IsNil() { return }
        dst.Set(reflect.MakeSlice(src.Type(), src.Len(), src.Len()))
        for i := 0; i < src.Len(); i++ { copyValue(dst.Index(i), src.Index(i)) }
    case reflect.Map:
        if src.IsNil() { return }
        dst.Set(reflect.MakeMap(src.Type()))
        for _, k := range src.MapKeys() {
            v := reflect.New(src.MapIndex(k).Type()).Elem()
            copyValue(v, src.MapIndex(k))
            dst.SetMapIndex(k, v)
        }
    default:
        dst.Set(src)
    }
}

// unsafe — struct field offset'ga to'g'ridan to'g'ri kirish
type StringHeader struct {
    Data uintptr
    Len  int
}

// Private field'ga kirish (faqat testing/debugging!)
func readPrivateField(s *SomeStruct) string {
    field := reflect.ValueOf(s).Elem().FieldByName("privateField")
    ptr := unsafe.Pointer(field.UnsafeAddr())
    return *(*string)(ptr)
}
Reflection sekin va xavfsiz emas. Production'da cache qiling. unsafe — portativ emas va GC bilan muammo keltiradigan, faqat juda kerak bo'lganda ishlatilsin.
28 / 28

CGo & Plugin System

C kutubxonalari bilan integratsiya, Go plugin tizimi va WebAssembly compile.

cgo_example.go
EXPERT
// CGo — C kodini Go ichida chaqirish
// go build -x → C kompilatsiyasini ko'rish

package main

/*
#include <stdlib.h>
#include <string.h>

// Custom C funksiya
int fast_sum(int* arr, int n) {
    int sum = 0;
    for (int i = 0; i < n; i++) sum += arr[i];
    return sum;
}

typedef struct {
    char* data;
    int   len;
} Buffer;
*/
import "C"
import ("fmt"; "unsafe")

func cgoSum(nums []int) int {
    if len(nums) == 0 { return 0 }
    cArr := (*C.int)(unsafe.Pointer(&nums[0]))
    return int(C.fast_sum(cArr, C.int(len(nums))))
}

// Go → C string
func cStringExample() {
    cs := C.CString("hello")
    defer C.free(unsafe.Pointer(cs)) // MUHIM!
    fmt.Println(C.GoString(cs))
}

// ═══ Plugin System ═══
// go build -buildmode=plugin -o myplugin.so plugin/main.go

import "plugin"

func loadPlugin(path string) error {
    p, err := plugin.Open(path)
    if err != nil { return err }

    sym, err := p.Lookup("ProcessData")
    if err != nil { return err }

    fn, ok := sym.(func([]byte) []byte)
    if !ok { return fmt.Errorf("invalid symbol type") }

    result := fn([]byte("input data"))
    fmt.Println(string(result))
    return nil
}

// ═══ WebAssembly Compile ═══
// GOOS=js GOARCH=wasm go build -o main.wasm ./cmd/wasm/
// Yoki TinyGo bilan:
// tinygo build -o main.wasm -target wasm ./

func main() {
    nums := []int{1, 2, 3, 4, 5}
    fmt.Println(cgoSum(nums))
    cStringExample()
}

🏆 Senior+ / Lead Darajasi Yakunlandi!

28 ta mavzuni o'zdingiz. Endi siz Go'ning eng chuqur qismlarini bilasiz.

pkg.go.dev go.dev/blog github.com/uber-go/guide google.github.io/styleguide