- Một đề xuất về việc đưa chức năng tạo và phân tích UUID vào thư viện chuẩn của ngôn ngữ Go đang được thảo luận trên GitHub
- Người đề xuất đưa ra căn cứ rằng hiện nay phần lớn các dự án server·DB viết bằng Go đều phụ thuộc vào các gói bên ngoài như github.com/google/uuid
- Các ngôn ngữ lớn như C#, Java, Python đã cung cấp hỗ trợ UUID ở cấp thư viện chuẩn
- Trong quá trình thảo luận, các vấn đề chính gồm UUIDv7, mức độ tuân thủ RFC 9562, phạm vi bao gồm chức năng phân tích và tính nhất quán của API đã được bàn luận
- Đề xuất này sau đó được hợp nhất để tiếp tục dưới dạng đề xuất hỗ trợ UUIDv4·UUIDv7 trong gói crypto/rand (#76319)
Tổng quan đề xuất
- Đưa ra phương án bổ sung API tạo và phân tích UUID vào thư viện chuẩn Go
- Các phiên bản mục tiêu là UUID v3, v4, v5
- Căn cứ chính là mức độ phụ thuộc vào gói bên ngoài và các trường hợp được hỗ trợ chuẩn trong những ngôn ngữ khác
- UUID là một tiêu chuẩn quốc tế được định nghĩa trong RFC 4122 (sau này là RFC 9562)
- Người đề xuất chỉ ra rằng Go là trường hợp ngoại lệ hiếm hoi trong số các ngôn ngữ lớn khi không có hỗ trợ UUID chuẩn
Phản ứng ban đầu và thảo luận
- Một số người tham gia nhắc đến việc đã từng có các đề xuất tương tự nhưng bị từ chối trước đó (#23789, #28324)
- Lý do là việc dùng gói bên ngoài đã đủ thuận tiện, và chu kỳ phát hành linh hoạt hơn so với thư viện chuẩn
- Người đề xuất lập luận rằng “nếu đa số dự án đều phải import gói bên ngoài mỗi lần, thì thà đưa luôn vào chuẩn còn hơn”
- Việc nhiều ngôn ngữ đưa UUID vào thư viện chuẩn liên quan đến crypto cũng được nêu làm căn cứ ủng hộ
Phản ánh các phiên bản UUID mới và RFC
- Một số ý kiến chỉ ra rằng UUID v1~v5 đã cũ, còn v7 là phiên bản mới và nhiều hứa hẹn hơn
- v7 có nhiều tùy chọn triển khai khác nhau, nên cần theo dõi thêm kết quả áp dụng
- Bản nháp RFC khuyến nghị không nên phân tích UUID một cách không cần thiết mà nên xử lý nó như một định danh opaque
- Sau khi RFC 9562 được phát hành chính thức, thảo luận liên quan đã chuyển trọng tâm sang hỗ trợ UUIDv7
Chỉnh sửa và hợp nhất đề xuất
- Đến năm 2025, khi RFC 9562 được chính thức hóa, đã xuất hiện nhắc tới việc PostgreSQL 18 hỗ trợ UUIDv7
- Sau đó phía Go khởi động một đề xuất riêng về việc chỉ bổ sung chức năng tạo UUIDv4·UUIDv7 trong gói crypto/rand (#76319)
- Chức năng phân tích bị loại trừ theo khuyến nghị của RFC
- Đề xuất gốc (#62026) được đánh dấu là trùng lặp (duplicate) và bị đóng
Thảo luận thiết kế API
- Có thảo luận về việc liệu hành vi mặc định của
uuid.New() nên là v4 hay nên để ngỏ khả năng thay đổi trong tương lai
- Một số ý kiến đề xuất luôn cố định là v4 vì “nếu đổi phiên bản sau này có thể phát sinh vấn đề tương thích”
- Thảo luận về việc có nên cung cấp các phương thức như
Compare, MustParse, Parse hay không
- Có ý kiến cho rằng
Compare là cần thiết để hỗ trợ UUID có thể sắp xếp theo định nghĩa của RFC
MustParse được đưa vào để giữ tính nhất quán với các hàm Must* khác trong chuẩn
- Kết luận là phương thức
IsZero() không cần thiết cho kiểu UUID
- Nhiều đề xuất thiết kế khác nhau cũng được đưa ra như thêm struct
Generator, tách kiểu theo từng phiên bản (UUIDv4, UUIDv7, v.v.)
- Một số ý kiến chỉ ra sự mơ hồ của hàm
New() và đề xuất chỉ cung cấp các hàm chỉ rõ phiên bản (NewV4, NewV7)
Các vấn đề kỹ thuật chính
- Có thảo luận về việc định nghĩa sắp xếp UUID (sorting) có phải chỉ tồn tại rõ ràng ở v6·v7 hay không
- Xem xét cách triển khai bảo đảm sắp xếp theo thời gian khi tạo UUIDv7 và ngăn xung đột đồng thời (theo cơ chế counter)
- Có ý kiến chỉ ra giới hạn của thiết kế một kiểu duy nhất do khác biệt ý nghĩa giữa các phiên bản (ví dụ: v1 chứa địa chỉ MAC, v7 dựa trên thời gian)
- Một số người đề xuất tách kiểu theo phiên bản và bổ sung các phương thức chuyển đổi tường minh như
AsV4(), AsV7()
Kết luận và trạng thái hiện tại
- Cộng đồng Go nhìn chung đồng ý rằng cần có hỗ trợ UUID chuẩn
- Tuy vậy, để giữ sự đơn giản của thư viện chuẩn và tuân thủ khuyến nghị của RFC
- chức năng phân tích bị loại bỏ
- chỉ bổ sung chức năng tạo UUIDv4·UUIDv7 vào crypto/rand
- Đề xuất gốc (#62026) đã được hợp nhất vào đề xuất #76319 và hiện đang tiếp tục,
đưa hỗ trợ UUID chuẩn trong ngôn ngữ Go đến gần giai đoạn được chính thức hóa hơn
1 bình luận
Ý kiến trên Hacker News
Thật thú vị khi có người nói UUID phiên bản 1~5 đã lỗi thời
Nhưng v4 vẫn có tính ngẫu nhiên cao nhất và được khuyến nghị làm khóa chính để tránh vấn đề hotspot và các vấn đề về quyền riêng tư trong DB phân tán
Liên kết tham khảo: Tài liệu UUID của CockroachDB, Hướng dẫn UUID của Google Cloud Spanner
Mỗi phiên bản UUID (bao gồm cả v4) đều có khuyết điểm trong những tình huống nhất định. Trên thực tế, nhiều tổ chức tự định nghĩa giá trị 128-bit thuần túy để dùng thay cho UUID tiêu chuẩn
Cuối cùng thì ngày càng có nhiều yêu cầu phức tạp vượt quá giới hạn thiết kế của UUID
Thật vui khi hôm nay HN có một mẩu tin nhỏ liên quan đến Go như thế này
Dạo này toàn là tương lai của lập trình hay chuyện AI, nên chủ đề kỹ thuật kiểu này thấy mới mẻ
Những người theo chủ nghĩa hoàn hảo, lập trình viên thực chiến và cộng đồng crypto đều có lập trường khác nhau
Tài liệu liên quan: RFC 9562
Tôi mong Go sẽ đưa ra quyết định đúng. Đặc biệt TinyGo thực sự rất tuyệt cho vi điều khiển
Tôi không quá quan tâm việc Go hỗ trợ tạo UUID, nhưng việc có kiểu UUID tiêu chuẩn thì thực sự quan trọng
Nó sẽ cho phép marshal nhất quán trong JSON, Text, database/sql, v.v.
Trong một phân tích phụ thuộc Go gần đây, google/uuid là package được dùng nhiều thứ hai
Phân tích liên quan: The most popular Go dependency
Sức hấp dẫn của Go nằm ở tính thực dụng hơn là các tính năng hào nhoáng
Ngôn ngữ không trở nên phức tạp đến mức sụp đổ, mà chỉ thêm những gì cần thiết
Nhờ cam kết tương thích nên có thể yên tâm sử dụng. Đây là ngôn ngữ thay đổi chậm nhưng cải thiện đều đặn
So với việc package uuid của Google không còn hoạt động mạnh, tôi nghĩ điều quan trọng hơn là gofrs/uuid đang tuân theo tiêu chuẩn mới và được duy trì tích cực
Kho lưu trữ gofrs/uuid
Issue #194
Tôi thực sự ghét UUID. Đây là loại định danh không thân thiện với con người
Khi debug hoặc xem kết quả truy vấn, nó quá dài và bất tiện.
Dĩ nhiên nó hữu ích khi cần ID duy nhất giữa các hệ thống tách biệt hoàn toàn, nhưng phần lớn trường hợp là bị lạm dụng
Trong các trường hợp thông thường, bộ cấp số tập trung tốt hơn nhiều.
Ví dụ, một thủ tục như GetNextId trong DB sẽ thân thiện và hiệu quả hơn
Kết quả là nó trở thành mã mà con người không thể đọc được, thậm chí còn là bản tự triển khai nên lại có tính tuần tự kỳ lạ. Một quyết định tệ hại hoàn toàn
Với Postgres, dùng bảng bộ đếm có thể tạo hàng chục nghìn ID mỗi giây
Cách này còn giúp tiết kiệm bộ nhớ, tăng hiệu quả nén và hiệu năng hashmap
UUID thì tiện nhưng phá hỏng hiệu năng
Ví dụ: dạng như
BASKETBALL-...-FISHgắn thêm checksum dựa trên từ ngữ thì sẽ dễ nhớ hơnTôi từng thắc mắc liệu UUID có thật sự sẽ được thêm vào Go hay không
Nếu không có phản đối đặc biệt nào, khả năng cao là sẽ được đưa vào
Kotlin cũng недавно thêm hỗ trợ các phiên bản UUID dựa trên RFC 9562 vào thư viện chuẩn trong phiên bản 2.3
Hỗ trợ cả JVM, JS, WASM và Native.
Khi RFC của IETF đã ổn định, việc Go làm theo là hợp lý
Việc Go thiếu hỗ trợ cho những chức năng cơ bản như thế này khá đáng tiếc
Cá nhân tôi thấy hệ thống logging của Go quá đơn giản nên phải tự làm
Mô-đun slog thì chậm và bất tiện. Có vẻ như chỉ nghĩ đến môi trường enterprise
Tôi từng nghĩ xem có cách nào để vừa có hiệu quả gom cụm DB của v7 vừa có tính ngẫu nhiên của v4 hay không
Có vẻ nếu dùng v7 ở bên trong, rồi xáo trộn bằng XOR hoặc AES trước khi gửi ra ngoài thì sẽ làm được
Ví dụ dùng mã hóa Feistel thì có thể tạo public ID dạng opaque mà không gặp vấn đề hiệu năng của UUID