Rules
·v1.0.0·2026-04-22Go Projesi Kuralları
Modern Go (1.22+) projeleri için kural seti — paket yapısı, error handling, concurrency pattern'leri, context kullanımı, test disiplini, go vet + golangci-lint baseline. CLAUDE.md / .cursorrules için.
gogolangbackendconcurrencyrulesclaude-md
İçerik
Bu içeriği projenin CLAUDE.md / AGENTS.md / .cursorrules dosyasına yapıştır.
Go Projesi Kuralları
Version & tooling
- Go 1.22+ (generics, range-over-func, improved slog).
go mod tidycommit öncesi zorunlu.go.modvego.sumcommit edilir.- Replace directive CI'da yasak (local dev için geçici kabul, commit'ten önce kaldır).
- Formatter:
gofmt/goimports(pre-commit). - Linter:
golangci-lint. Aktif linter'lar:linters: enable: - errcheck # yakalanmayan error'lar - govet - gosec # security - revive # style (golint yerine) - staticcheck - unused - ineffassign - gocritic - bodyclose # HTTP body kapatılmadı mı? - contextcheck # context propagation - errorlint # fmt.Errorf + %w - gocyclo - exhaustive # switch exhaustive? - sqlclosecheck
Paket yapısı
- Layout:
cmd/,internal/,pkg/(opsiyonel).myapp/ cmd/ server/main.go // binary entry migrate/main.go internal/ // export edilmez, private api/ service/ repository/ pkg/ // diğer projelerle paylaşılacaksa go.mod internal/kurulum tercih — sızıntıyı derleyici engeller.pkg/sadece gerçekten public API için (library dışa açıyorsan).- Paket adı: kısa,
snake_casedeğillowercase, tek kelime tercih:user,payment,storage. util,common,helperspaketleri yasak — anlamsız gruplama.
Error handling
- Error döndüren fonksiyonda error kontrol:
✅ result, err := doThing() if err != nil { return fmt.Errorf("doThing: %w", err) } ❌ result, _ := doThing() // yasak (golangci-lint errcheck yakalar) - Error wrapping:
fmt.Errorf("context: %w", err). Mesaj + wrap, user-facing detay ayrı. - Sentinel error'lar:
var ErrNotFound = errors.New("not found") // kullanım: if errors.Is(err, ErrNotFound) { ... } - Custom error type'lar yapısal data gerekirse:
type ValidationError struct { Field string Message string } func (e *ValidationError) Error() string { ... } // kullanım: var ve *ValidationError if errors.As(err, &ve) { ... } - Panic yasak production kodda — sadece gerçekten unrecoverable (init failure) durumda.
recover()goroutine panic'i için — ayrıca log + metric.
Context
- Her I/O fonksiyonu
ctx context.Contextalır, ilk parametre:func (s *Service) GetUser(ctx context.Context, id UserID) (*User, error) context.Background()sadece main'de (veya long-running background job'ın kökünde).context.TODO()geçici — refactor PR'ında gerçek context'e çevrilir.- Cancel'ı unutma:
ctx, cancel := context.WithTimeout(parent, 5*time.Second) defer cancel() context.WithValueminimal kullan — tracing, request ID, auth user gibi cross-cutting.
Concurrency
- Goroutine'ı başlatan, sonlandırmasını da düşünür. Fire-and-forget yasak:
❌ go doWork() ✅ go func() { defer wg.Done() if err := doWork(ctx); err != nil { ... } }() - Wait group veya
errgroup.Groupçoklu goroutine için. - Channel direction:
chan<-,<-chan— unutma, dokümantasyon. - Mutex: zero value kullanılabilir (
var mu sync.Mutex), pointer yapma. - Atomic basit counter için (
atomic.Int64). sync.Mapsadece spesifik case'ler için — çoğu zamanmap + RWMutexdaha iyi.- Data race:
go test -raceCI'da zorunlu. - Channel'i sender kapatır (receiver değil). "Who owns the channel" net.
Slice / map nuance
- Slice append kopyası:
a := []int{1,2,3} b := append(a, 4) // a ve b paylaşılabilir — dikkat - Slice capacity hint:
s := make([]int, 0, 100) // capacity pre-allocated - Map concurrent access yasak. Read-only için bile
sync.RWMutexveyasync.Map. nilslice vs boş slice: API contract'ta belirt — genelde return nil kabul,len() == 0check.
Logging
log/slog(Go 1.21+) — structured.logpackage yasak.- Handler seçimi: JSON production, Text dev.
- Logger propagation: context içinde veya explicit parameter.
- Seviyeler:
Debug,Info,Warn,Error. log.Fatalyasak (defer çalıştırmaz, exit code 1). Yerineos.Exit(1)after graceful cleanup.
logger.Info("order created", "order_id", orderID, "user_id", userID)
HTTP handler'lar
http.Handlerinterface preferred:func (h *OrderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { ... }- Middleware pattern:
mux.Handle("/orders", authMiddleware(rateLimitMiddleware(orderHandler))) - Body close edilir:
defer r.Body.Close()(body'yi okuyorsan). - Response header status'tan önce yazılır.
- Timeout'lar:
http.Server{ReadTimeout, WriteTimeout, IdleTimeout}— her zaman set. http.DefaultServeMuxyasak — explicithttp.NewServeMux().
Database
database/sqlveya ORM (sqlc, Ent, GORM).sqlc(code generation) tercih edilir — raw SQL + type safety.- Connection pool config:
db.SetMaxOpenConns(25) db.SetMaxIdleConns(5) db.SetConnMaxLifetime(5 * time.Minute) Rows.Close()defer edilir.- Prepared statement prod'da cache'li.
context.Contextquery'ye geçer —QueryContext,ExecContext.
Testing
- Test dosyası:
*_test.go, aynı paket içinde. - Table-driven test:
tests := []struct{ name string input string want int wantErr bool }{ {"empty", "", 0, false}, ... } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { ... }) } testifypopüler ama tercih edilmez ileri projede (stdlib + helper yeterli). Kullanılıyorsarequirevsassertayrımına dikkat.t.Cleanupteardown için.t.Parallel()bağımsız testler için.- Benchmark:
BenchmarkX. Performance iddia ediliyorsa destekleyen benchmark. - Fuzz test Go 1.18+ — input parsing / serialization için.
httptest.NewServerHTTP handler test.
Struct & interface
- Struct field'lar exported ise dokümantasyon zorunlu:
// User represents a registered account. type User struct { // ID is a UUID v7 string. ID string } - Interface tanımı consumer tarafında, provider'da değil — "accept interfaces, return concrete types".
- Küçük interface —
io.Reader,io.Writerörnek. 5+ method = yeniden düşün. - Embedding inheritance değil composition.
- Pointer vs value receiver: tutarlı (bir tipte karıştırma). Büyük struct / mutation varsa pointer.
Build & deployment
- Build:
go build -ldflags="-w -s -X main.version=$(git rev-parse HEAD)" ./cmd/server - Static binary (
CGO_ENABLED=0) — Docker'dascratch/distroless. - Multi-stage Dockerfile golden.
- Reproducible build:
GOFLAGS="-trimpath", locked toolchain.
Performance pragmatiği
-racetest devamlı açık (performance cost ama production'da değil).- Profile önce optimize:
pprofCPU/memory. - Allocation sayısı: hot path'te azaltmak için
sync.Pool, buffer reuse. strings.Builderstring concat loop'ta.bytes.Bufferbinary concat için.- Benchmark'lı iddia — "bu daha hızlı" demeden ölç.
Secret & config
os.Getenv+ zod-benzeri validation yerineenvconfigkütüphanesi.- Viper karmaşık config hierarchy için.
- Hardcoded secret yasak.
- TLS config
MinVersion: tls.VersionTLS12.
Yasak listesi (özet)
_, err := ...; _(error ignore)panic()production koddalog.Fatal(defer atlatır)logpackage (uselog/slog)- Goroutine'ı wait group'sız başlatmak
- Context'siz I/O fonksiyon
- Global state (package-level var mutable) gereksiz yere
util,helpers,commonpaket adı- Interface tanımı 5+ method
- Channel'i sender dışında kapatmak
- Mutex'i embedding ile export etmek (Lock/Unlock public olur)
- Struct'a JSON tag eksik (field leak veya case mismatch)
init()çok iş yapan (test yan etkileri)interface{}/anygerçekten gerekli olmadıkça
Commit
Conventional Commits. Kapsam: api, cmd, db, worker, infra.