- Go (Golang) là gì? Tại sao nên học Go?
Go là ngôn ngữ lập trình do Google tạo ra (2009), biên dịch (compiled), statically typed, cú pháp đơn giản. Ưu điểm: tốc độ gần C/C++, concurrency mạnh (goroutines), binary đơn (không cần runtime), stdlib phong phú, phù hợp cho microservices, cloud tools, APIs.
- Khai báo biến trong Go có mấy cách?
3 cách: (1) var name string = "Go" (đầy đủ). (2) var name = "Go" (type inference). (3) name := "Go" (short declaration, chỉ trong function). := phổ biến nhất. var dùng ở package level hoặc khi cần zero value. Go không có let/const như…
- Go có những kiểu dữ liệu cơ bản nào?
Go có các nhóm kiểu dữ liệu cơ bản: nhóm số gồm int, int8/16/32/64, float32/64, complex64/128; nhóm văn bản là string (immutable, mã hoá UTF-8); và bool cho giá trị logic true/false. Ngoài ra còn có byte (alias của uint8) dùng cho dữ liệu nhị…
- Zero value trong Go là gì?
Giá trị mặc định khi khai báo biến không khởi tạo — Go đảm bảo mọi biến đều có giá trị hợp lệ (khác JS/undefined, Python/None). Cụ thể: - int/float → 0 - string → "" (rỗng) - bool → false - pointer/slice/map/channel/interface → nil…
- Hàm (function) trong Go khai báo thế nào?
Khai báo hàm cơ bản dùng từ khoá func. Go hỗ trợ multiple return values và named returns. Functions là first-class citizens, có thể gán cho biến hoặc truyền như tham số.
- Multiple return values trong Go dùng khi nào?
Pattern phổ biến nhất: trả (result, error). Nếu không cần 1 giá trị, dùng (blank identifier). Khác biệt lớn với JS/TS: Go không dùng try/catch mà handle error ngay tại chỗ.
- Package và import trong Go hoạt động thế nào?
Mỗi file Go thuộc 1 package (package main). main package + func main() = entry point. Import: import "fmt" hoặc grouped import. Exported names (public) viết hoa chữ cái đầu: fmt.Println. Lowercase = unexported (private trong package).
- Go có class không? Struct là gì?
Go KHÔNG có class. Struct là kiểu dữ liệu composite, methods gắn vào struct qua receiver. Composition thay vì inheritance: embed struct trong struct khác.
- Pointer trong Go là gì? Khi nào dùng?
int là pointer type, &x lấy address, p dereference. Go không có pointer arithmetic như C. nil pointer gây panic. Dùng pointer khi: (1) muốn modify giá trị gốc. (2) struct lớn (tránh copy). (3) method cần modify receiver.
- Array và Slice trong Go khác nhau thế nào?
Array: size cố định, value type [5]int. Slice: dynamic, reference type []int. Slice dùng phổ biến hơn. make([]int, 0, 10) tạo slice capacity 10. append(slice, item) thêm phần tử. Slice là view lên underlying array.
- Map trong Go hoạt động thế nào?
Map là kiểu dữ liệu key-value tích hợp sẵn trong Go, khai báo bằng m := map[string]int{"a": 1} hoặc make(map[string]int). - Check key tồn tại: val, ok := m["key"] — ok là false nếu key không tồn tại (zero value của value type). - Xoá:…
- Range loop trong Go dùng thế nào?
range là cú pháp duy nhất để iterate qua collection trong Go, hoạt động khác nhau theo từng kiểu dữ liệu: - Slice / array: for i, v := range slice { } — trả về index và value. - Map: for k, v :=…
- Error handling trong Go khác gì JS/Python?
Go không có try/catch/throw. Errors là values, check lỗi ngay sau khi gọi. Explicit implicit. errors.Is(), errors.As() để check error chain.
- defer, panic, recover trong Go dùng khi nào?
defer đảm bảo một function sẽ được gọi khi function chứa nó return (LIFO). panic dừng chương trình khi gặp lỗi không thể khôi phục. recover bắt panic bên trong deferred function. Trong thực tế, hạn chế dùng panic/recover và ưu tiên trả error thông…
- Interface trong Go hoạt động thế nào?
Interface = tập hợp method signatures. Implicit implementation: struct tự động satisfy interface nếu có đủ methods (không cần implements keyword). interface{} (hoặc any) là empty interface chấp nhận mọi type.
- Empty interface (any) dùng khi nào?
any (alias interface{}) chấp nhận mọi type, nhưng cần type assertion để dùng value cụ thể. Go 1.18+ có generics thay thế nhiều use cases. Dùng cho: generic containers, JSON parsing, function nhận nhiều types.
- Type assertion và type switch là gì?
Type assertion lấy giá trị cụ thể từ interface. Type switch xử lý nhiều types một cách gọn gàng. Tương tự instanceof trong JS.
- Pointer receiver vs value receiver khác nhau?
Hai dạng receiver có ngữ nghĩa khác nhau về copy và mutation: - Value receiver func (u User) Name() — nhận một copy của struct, không thể modify giá trị gốc. - Pointer receiver func (u User) SetName(n string) — modify trực tiếp struct gốc,…
- Generics trong Go (1.18+) hoạt động thế nào?
Generics cho phép viết function và type hoạt động với nhiều kiểu dữ liệu mà không cần lặp code, ví dụ func MapT any, U any U) []U nhận slice bất kỳ và trả về slice đã transform. Type parameters được khai báo trong dấu…
- Goroutine là gì? Khác thread thế nào?
Goroutine là lightweight thread do Go runtime quản lý. Khác OS thread: goroutine stack default ~8KB, tự grow/shrink; Go scheduler multiplex goroutines lên OS threads (M:N scheduling). Có thể chạy hàng triệu goroutines cùng lúc.
- Channel trong Go là gì? Dùng thế nào?
Kênh giao tiếp giữa goroutines. Unbuffered channel: block đến khi cả sender và receiver sẵn sàng. Buffered: không block nếu buffer chưa đầy.
- Select statement dùng để làm gì?
select { case v := <-ch1: ... case ch2 <- x: ... default: ... } chờ multiple channel operations, chạy case sẵn sàng đầu tiên. Nếu nhiều case sẵn sàng → chọn random. default chạy nếu không case nào sẵn sàng (non-blocking). Dùng cho timeout:…
- WaitGroup dùng khi nào?
Dùng khi cần đợi nhiều goroutines hoàn thành trước khi tiếp tục. Đơn giản hơn channel cho fan-out/fan-in. wg.Add(n) đăng ký n goroutines. wg.Done() thường dùng kết hợp defer.
- Mutex và RWMutex dùng khi nào?
- Context package dùng để làm gì?
- Worker pool pattern trong Go?
- Errgroup dùng khi nào?
- HTTP server cơ bản trong Go viết thế nào?
Stdlib đủ mạnh cho production. Không bắt buộc framework. http.ServeMux là default router.
- Gin framework là gì? Khác net/http thế nào?
Gin là HTTP web framework phổ biến nhất trong hệ sinh thái Go, được thiết kế tập trung vào hiệu năng với routing dựa trên radix tree, nhanh hơn đáng kể so với http.ServeMux mặc định. So với stdlib net/http, Gin cung cấp sẵn: middleware…
- Middleware trong Go HTTP server viết thế nào?
Middleware trong Go là một wrapper function nhận handler và trả về handler mới, cho phép chèn logic trước hoặc sau khi xử lý request.
- JSON encode/decode trong Go thế nào?
Go sử dụng package encoding/json. Struct tags quyết định cách ánh xạ field sang JSON key.
- GORM ORM trong Go dùng thế nào?
GORM là ORM phổ biến nhất trong Go, cung cấp API trực quan để thao tác database: db.Create(&user) để insert, db.First(&user, 1) để query theo primary key, và db.Where("age ?", 18).Find(&users) cho query có điều kiện. GORM hỗ trợ auto migration (db.AutoMigrate(&User{})) để tự tạo/cập…
- Database connection trong Go best practices?
sql.Open() trả connection pool (không phải single connection). Set: db.SetMaxOpenConns(25), db.SetMaxIdleConns(5), db.SetConnMaxLifetime(5time.Minute). KHÔNG defer db.Close() mỗi request vì sql.DB là long-lived pool — chỉ close khi app shutdown. Prepared statements cho queries lặp lại. Context timeout cho queries: db.QueryContext(ctx, query).
- Go modules là gì? go.mod hoạt động thế nào?
Go modules là hệ thống quản lý dependency chính thức của Go, khởi tạo bằng go mod init module-name để tạo file go.mod chứa tên module và danh sách dependencies. Khi cần thêm thư viện, dùng go get package@version, và go mod tidy để tự…
- gRPC trong Go dùng khi nào?
- Graceful shutdown trong Go server thế nào?
- Rate limiter implement trong Go?
- Testing trong Go viết thế nào?
File test.go, function TestXxx(t testing.T). Run: go test ./.... Go không có built-in assert — dùng if/t.Errorf. Table-driven tests là pattern phổ biến.
- Table-driven tests trong Go là gì?
Pattern test nhiều cases bằng slice of structs — DRY, dễ thêm cases, idiomatic Go. Mỗi sub-test chạy độc lập với t.Run, có thể filter: go test -run TestSquare/positive.
- Benchmark testing trong Go?
func BenchmarkXxx(b testing.B) — Go đo lường performance tự động điều chỉnh số lần chạy.
- Mock/stub trong Go thế nào?
Go khuyến khích mocking dựa trên interface: define một interface nhỏ cho dependency cần mock, sau đó tạo mock struct implement interface đó với behavior tuỳ chỉnh, ví dụ type MockDB struct { GetFunc func(id int) (User, error) } rồi gọi m.GetFunc(id) trong method Get.…
- Go toolchain có những công cụ nào?
Go đi kèm bộ toolchain rất mạnh ngay từ khi cài đặt: go build để compile thành binary, go run để compile và chạy luôn, go test để chạy unit test và benchmark, và go fmt để format code theo chuẩn thống nhất (bắt buộc…
- Profiling Go application thế nào?
Go có hỗ trợ profiling tích hợp sẵn thông qua package net/http/pprof: chỉ cần import "net/http/pprof" là server tự expose các endpoint profiling tại /debug/pprof/. Để phân tích CPU, dùng go test -cpuprofile=cpu.prof rồi mở bằng go tool pprof cpu.prof; tương tự với memory profiling…
- Functional options pattern trong Go?
- Dependency injection trong Go thế nào?
- Pipeline pattern với channels?
- Go production best practices?
- Docker image cho Go app tối ưu thế nào?
- Structured logging trong Go dùng gì?
Từ Go 1.21, stdlib cung cấp package log/slog cho structured logging với cú pháp slog.Info("user created", "id", user.ID, "email", user.Email), output ra JSON có cấu trúc rõ ràng thay vì chuỗi text khó parse. Slog hỗ trợ các mức log chuẩn (Debug, Info, Warn, Error)…
- Go vs Node.js khi nào nên chọn Go?
Chọn Go khi: CPU-intensive tasks, high concurrency (100K+ connections), microservices, CLI tools, system programming, cần type safety mạnh. Chọn Node.js khi: full-stack JS, rapid prototyping, npm ecosystem, real-time (Socket.io), team quen JS. Go nhanh hơn ~10-50x cho compute, Node.js ecosystem lớn hơn.
- Struct tags trong Go là gì và dùng thế nào?
Struct tags là metadata gắn vào field của struct dưới dạng string literal sau tên field, được đọc tại runtime thông qua reflection. Phổ biến nhất là JSON tags và validation tags. Các tags phổ biến: - json:"name,omitempty" — encoding/json - db:"columnname" — sqlx, GORM…
- Comparable constraint và type sets trong generics Go là gì?
- errors.Is vs errors.As khác nhau thế nào?
Cả hai dùng để kiểm tra error chain (chuỗi lỗi được wrap), nhưng mục đích khác nhau. errors.Is(err, target) — kiểm tra identity: err có phải (hoặc wrap) target không? Dùng cho sentinel errors (lỗi được định nghĩa sẵn). errors.As(err, &target) — kiểm tra type:…
- Sentinel errors và custom error types — khi nào dùng cái nào?
- t.Helper() trong Go testing dùng để làm gì?
t.Helper() đánh dấu function hiện tại là helper function. Khi test fail, Go runtime báo lỗi tại caller của helper (không phải bên trong helper), giúp dễ đọc output test hơn. Khi nào dùng: bất kỳ helper function nào nhận testing.T hoặc testing.B đều nên…
- go test -race là gì? Khi nào nên chạy?
Race detector (-race flag) là công cụ tích hợp trong Go runtime, phát hiện data race — khi hai goroutines truy cập cùng vùng nhớ đồng thời mà không sync, ít nhất một thao tác là write. Race detector hoạt động bằng cách instrument binary…
- Observability trong Go service: metrics với Prometheus thế nào?
- gofmt vs goimports vs golangci-lint — khác nhau thế nào?
- Trong Go, `byte` và `rune` khác nhau thế nào?
byte là alias của uint8 (1 byte thô); rune là alias của int32, đại diện cho một code point Unicode. String trong Go là chuỗi byte UTF-8 bất biến, không phải mảng ký tự. Hệ quả: - s[i] trả về byte, và len(s) đếm byte…
- Variadic function trong Go là gì, và toán tử `...` hoạt động ra sao?
Tham số cuối cùng của hàm có thể khai báo ...T để nhận số lượng đối số biến thiên. Bên trong hàm, tham số đó là một []T thường. Hai chiều dùng ...: - Gọi với nhiều đối số rời: sum(1, 2, 3). - Spread…
- `new` và `make` trong Go khác nhau ở đâu?
Cả hai đều cấp phát, nhưng cho mục đích khác nhau: - new(T) — dùng cho mọi kiểu. Cấp phát một T đã zeroed và trả về con trỏ T. Nó không khởi tạo gì thêm. - make(T, ...) — chỉ cho slice, map, channel.…
- Hàm `init` là gì, và thứ tự khởi tạo package trong Go diễn ra thế nào?
Khi một package được nạp, Go khởi tạo theo thứ tự: 1. Các package được import khởi tạo trước (đệ quy) — mỗi package chỉ một lần. 2. Biến cấp package được gán, theo thứ tự phụ thuộc (không phải thứ tự viết): biến nào…
- `iota` là gì, và dùng nó cùng typed constant để tạo enum ra sao?
iota là bộ đếm compile-time: nó reset về 0 ở đầu mỗi block const và tăng 1 sau mỗi dòng ConstSpec. Kết hợp với một kiểu riêng, đây là cách Go dựng enum. - Gán một kiểu (Weekday int) để tạo enum có type an…
- Empty struct `struct{}` là gì, và khi nào nên dùng?
struct{} là struct không có field nào → chiếm 0 byte. Mọi giá trị struct{}{} share cùng một địa chỉ, nên dùng nó ở đâu chỉ cần "sự hiện diện" chứ không cần dữ liệu. Ba chỗ thường gặp: - Set: map[string]struct{} — tiết kiệm…
- Vì sao một `error` chứa con trỏ nil lại không bằng `nil` trong Go?
- Slice aliasing là gì, và `append`/`copy` gây bẫy thế nào?
Một slice là view gồm (con trỏ, len, cap) trỏ vào một backing array. Nhiều slice có thể share cùng array → sửa qua slice này, slice kia thấy theo. Điểm bẫy nằm ở append: - Còn cap dư → append ghi in-place lên array…
- Làm sao sắp xếp một slice struct bằng `sort.Slice`?
sort.Slice(s, less) sắp xếp slice tại chỗ dựa trên hàm so sánh less(i, j) bool — trả về true nếu phần tử i phải đứng trước j. Không cần implement interface sort.Interface. Lưu ý: - sort.Slice không ổn định (thứ tự phần tử bằng nhau…
- Channel có buffer và không buffer khác nhau thế nào? Khi nào chương trình báo `all goroutines are asleep - deadlock`?
Unbuffered (make(chan int)): mỗi lần gửi phải có một bên nhận sẵn sàng ngay tại thời điểm đó — gửi và nhận là một điểm đồng bộ. Buffered (make(chan int, 3)): gửi chỉ chặn khi buffer đầy, nhận chỉ chặn khi buffer rỗng. Runtime phát…
- `close(ch)` có tác dụng gì? Gửi và nhận trên channel đã đóng thì xảy ra chuyện gì?
close là tín hiệu "không còn dữ liệu nào nữa", không phải thao tác giải phóng bộ nhớ (channel do GC thu hồi). Sau khi đóng: - Nhận: trả về ngay lập tức, không chặn. Dữ liệu còn trong buffer được trả ra trước, hết…
- Nhánh `default` trong `select` dùng để làm gì? Lỗi hay gặp khi dùng nó là gì?
select không có default sẽ chặn cho tới khi một nhánh sẵn sàng. Thêm default biến nó thành thao tác không chặn: nếu không có nhánh nào sẵn sàng ngay, default chạy luôn. Ứng dụng chính là try-send / try-receive — bỏ bớt việc khi…
- Vì sao sau `context.WithTimeout` / `WithCancel` luôn phải gọi `defer cancel()`?
Vì cancel là thứ giải phóng tài nguyên gắn với context đó, kể cả khi công việc đã hoàn tất bình thường. Mỗi context con được đăng ký vào danh sách con của context cha. Với WithTimeout / WithDeadline còn có thêm một time.Timer đang…
- Goroutine leak là gì? Những nguyên nhân hay gặp nhất?
Goroutine leak là goroutine được tạo ra nhưng không bao giờ kết thúc — nó chặn vĩnh viễn trên một thao tác không bao giờ hoàn tất. Goroutine đó giữ luôn stack, biến nó tham chiếu và cả connection nó đang cầm, nên GC không…
- Đọc/ghi lên channel `nil` xảy ra chuyện gì? Vì sao có người cố tình gán channel về `nil`?
Mọi thao tác gửi hoặc nhận trên channel nil đều chặn vĩnh viễn — không panic, không lỗi, chỉ đứng im. Đây là hành vi được định nghĩa trong spec chứ không phải bug. Hệ quả trong select: nhánh có channel nil không bao giờ…
- Làm sao dừng một pipeline goroutine đang chạy dở? `done` channel và `ctx.Done()` khác nhau ở đâu?
Vấn đề của pipeline là stage phía sau có thể dừng sớm (đủ dữ liệu, người dùng huỷ request, lỗi), còn stage phía trước thì vẫn đang chặn ở lệnh gửi. Muốn dừng sạch, mọi thao tác gửi phải đi kèm một nhánh thoát. done…
- Có 10.000 URL cần gọi, làm sao giới hạn chỉ 20 request chạy song song?
Tạo 10.000 goroutine cùng lúc là chạy được về mặt kỹ thuật nhưng sẽ mở 10.000 kết nối, làm đối tác trả 429 hoặc chính service bị hết file descriptor. Cần chặn trần số việc chạy đồng thời. Cách 1 — semaphore bằng buffered channel.…
- `sync.Once` giải quyết vấn đề gì? Nếu hàm bên trong `once.Do` panic thì sao?
sync.Once bảo đảm một đoạn khởi tạo chạy đúng một lần dù có bao nhiêu goroutine gọi tới. Kiểm tra bằng biến bool thường là sai: hai goroutine có thể cùng thấy false và cùng khởi tạo. Điểm quan trọng thứ hai: Do chặn cho…
- `context.WithValue` nên dùng cho loại dữ liệu nào? Vì sao key không được để kiểu `string`?
Tài liệu context giới hạn rõ: WithValue chỉ dành cho dữ liệu theo phạm vi một request đi xuyên qua biên process/API — request ID, trace ID, danh tính người dùng đã xác thực, locale. Không dùng nó để truyền tham số của hàm, và…
- Những lỗi hay gặp khi dùng `sync.WaitGroup` là gì?
1. Gọi Add bên trong goroutine. Tài liệu yêu cầu Add phải xảy ra trước Wait. Đặt Add(1) trong goroutine thì Wait có thể chạy khi bộ đếm vẫn là 0 và trả về ngay, bỏ qua toàn bộ công việc. 2. Truyền WaitGroup theo…
- Vì sao không được copy `sync.Mutex`? `go vet` phát hiện lỗi này bằng cách nào?
- Khi nào `RWMutex` không nhanh hơn `Mutex`? Vì sao gọi `RLock` lồng nhau có thể deadlock?
- Data race khác race condition thế nào? Go memory model nói gì, có tồn tại "benign race" không?
- Scheduler G-M-P của Go hoạt động thế nào? Trong container nên đặt `GOMAXPROCS` bao nhiêu?
- Nghi ngờ service Go bị goroutine leak trên production, bạn điều tra thế nào?
- `http.Handler` và `http.HandlerFunc` khác nhau thế nào?
http.Handler là interface chỉ có một method: http.HandlerFunc là một kiểu hàm có sẵn method ServeHTTP gọi lại chính nó — nhờ vậy một hàm thường có thể đóng vai Handler mà không cần định nghĩa struct riêng: Thực tế: Ý nghĩa khi phỏng vấn:…
- Trong `fmt.Errorf`, `%w` khác `%v` ra sao? Khi nào nên bọc lỗi?
Cả hai đều in ra chuỗi giống nhau, nhưng %w giữ lại lỗi gốc trong chuỗi unwrap, còn %v chỉ ghép chuỗi và cắt đứt liên kết. Nguyên tắc dùng: - Bọc bằng %w khi tầng trên cần phân biệt loại lỗi để quyết định…
- Struct embedding trong Go là gì? Nó có phải kế thừa không?
Embedding là khai báo một field không có tên, chỉ có kiểu. Field và method của kiểu được nhúng được promote lên struct ngoài, gọi trực tiếp như của chính nó. Không phải kế thừa. Đây là composition cộng đường tắt cú pháp: - Không…
- Đặt `defer` trong vòng lặp có vấn đề gì? Sửa thế nào?
defer chạy khi hàm kết thúc, không phải khi hết một vòng lặp. Đặt trong loop nghĩa là mọi tài nguyên bị giữ đến tận cuối hàm — vòng lặp vài nghìn file sẽ chạm giới hạn file descriptor. Cách sửa 1 — tách thân…
- Vì sao không nên chạy production với `http.ListenAndServe` mặc định? Cấu hình timeout thế nào?
Vì http.Server mặc định có mọi timeout bằng 0, nghĩa là không giới hạn. Một client chậm (hoặc cố tình giữ kết nối) có thể chiếm goroutine và file descriptor vô hạn định — dạng tấn công Slowloris. Điểm hay bị hỏi thêm: - WriteTimeout…
- Khi chain nhiều middleware `func(http.Handler) http.Handler`, thứ tự chạy ra sao?
Middleware bọc từ trong ra ngoài, nhưng khi request tới thì chạy từ ngoài vào trong, rồi phần sau lời gọi next chạy ngược lại — giống ngăn xếp. Hệ quả thực tế: - Middleware đo thời gian / recover panic phải ở ngoài cùng…
- Vì sao gán giá trị struct vào interface báo lỗi "method has pointer receiver"?
Vì method set của T chỉ gồm method có value receiver, còn method set của T gồm cả hai. Nếu interface đòi một method khai báo trên T thì chỉ con trỏ mới thoả mãn. Lý do sâu hơn: gọi r.Save() trên biến addressable, compiler…
- Duyệt map trong Go có giữ thứ tự không? Muốn kết quả ổn định thì làm sao?
Không. Spec quy định thứ tự lặp trên map là không xác định, và runtime còn cố tình ngẫu nhiên hoá điểm bắt đầu mỗi lần chạy để lập trình viên không lỡ phụ thuộc vào nó. Muốn ổn định thì sắp xếp khoá rồi…
- Table-driven test dùng `t.Run` subtest có lợi gì? `t.Parallel` trong subtest có bẫy gì?
t.Run biến mỗi case thành một subtest độc lập: có tên riêng trong output, chạy lẻ được bằng go test -run TestX/casename, và một case fail không dừng các case còn lại. Lưu ý: - Trước Go 1.22, biến loop tc dùng chung một ô…
- `omitempty` trong struct tag hoạt động thế nào? Vì sao nó không bỏ được struct rỗng?
omitempty bỏ field khỏi JSON khi giá trị là empty value theo định nghĩa của encoding/json: false, 0, con trỏ/interface nil, và string/array/slice/map có độ dài 0. Danh sách này không bao gồm struct. Hệ quả hay gặp khi làm API: - Page: 0 và…
- Chuyển đổi `string` và `[]byte` có tốn kém không? Khi nào cần tránh?
string trong Go là bất biến, []byte thì không — nên []byte(s) và string(b) thường phải cấp phát bộ nhớ mới và copy toàn bộ dữ liệu. Trên hot path xử lý request, việc này tạo áp lực GC rõ rệt. Các trường hợp compiler…
- Khi nào **không** nên dùng generics trong Go? Nêu tiêu chí quyết định.
- Escape analysis là gì? Làm sao biết một biến được cấp phát trên stack hay heap?
- `sync.Pool` giải quyết vấn đề gì? Khi nào dùng và khi nào không?
- Viết benchmark trong Go sai ở đâu thì ra số vô nghĩa? `b.ResetTimer` dùng khi nào?
- Service Go ăn CPU/RAM bất thường trên production, bạn dùng pprof điều tra thế nào?