- มีการถกเถียงกันบน GitHub เกี่ยวกับข้อเสนอให้ รวมความสามารถในการสร้างและพาร์ส UUID ไว้ในไลบรารีมาตรฐาน ของภาษา Go
- ผู้เสนอให้เหตุผลว่าในปัจจุบันโปรเจ็กต์เซิร์ฟเวอร์และฐานข้อมูลของ Go ส่วนใหญ่ พึ่งพาแพ็กเกจนอก อย่าง
github.com/google/uuid
- ภาษาหลักอย่าง C#, Java, Python เป็นต้น ต่างก็มี การรองรับ UUID ในระดับไลบรารีมาตรฐาน อยู่แล้ว
- ระหว่างการอภิปราย ประเด็นสำคัญได้แก่สเปกล่าสุดอย่าง UUIDv7, การปฏิบัติตาม RFC 9562, ขอบเขตของความสามารถในการพาร์ส และความสม่ำเสมอของ API
- ต่อมาข้อเสนอนี้ถูกรวมเข้าไปอยู่ใน ข้อเสนอรองรับ UUIDv4·UUIDv7 ของแพ็กเกจ crypto/rand (#76319) และกำลังดำเนินต่อในเส้นทางนั้น
ภาพรวมของข้อเสนอ
- มีการเสนอแนวทางเพิ่ม API สำหรับสร้างและพาร์ส UUID ลงในไลบรารีมาตรฐานของ Go
- เวอร์ชันเป้าหมายคือ UUID v3, v4, v5
- เหตุผลหลักคือการพึ่งพาแพ็กเกจนอกและกรณีตัวอย่างของการรองรับเป็นมาตรฐานในภาษาอื่น
- UUID เป็นมาตรฐานสากลที่กำหนดไว้ใน RFC 4122 (ภายหลังคือ RFC 9562)
- ผู้เสนอชี้ว่า Go เป็นกรณีที่ค่อนข้างผิดปกติในบรรดาภาษาหลัก เพราะ ยังไม่มีการรองรับ UUID แบบมาตรฐาน
ปฏิกิริยาแรกเริ่มและการอภิปราย
- ผู้เข้าร่วมบางส่วนกล่าวถึงว่าในอดีตก็เคยมีข้อเสนอคล้ายกันแต่ ถูกปฏิเสธมาแล้ว (#23789, #28324)
- เหตุผลคือการใช้แพ็กเกจนอกนั้นสะดวกเพียงพออยู่แล้ว และมี รอบการออกรุ่นที่ยืดหยุ่นกว่า ไลบรารีมาตรฐาน
- ผู้เสนอแย้งว่า “ถ้าโปรเจ็กต์ส่วนใหญ่ต้อง import แพ็กเกจนอกทุกครั้งอยู่แล้ว ก็รวมไว้ในมาตรฐานไปเลยน่าจะดีกว่า”
- อีกเหตุผลที่ใช้สนับสนุนคือหลายภาษามักรวม UUID ไว้ใน ไลบรารีมาตรฐานฝั่งที่เกี่ยวข้องกับ crypto
UUID เวอร์ชันใหม่และการสะท้อนตาม RFC
- ความเห็นบางส่วนชี้ว่า UUID v1~v5 ล้าสมัยแล้ว และ v7 คือเวอร์ชันใหม่ที่น่าสนใจที่สุด
- v7 มีตัวเลือกในการติดตั้งใช้งานหลายแบบ จึงควรรอดูผลจากการใช้งานจริงเพิ่มเติม
- ในร่าง RFC มีคำแนะนำว่า ไม่ควรพาร์ส UUID โดยไม่จำเป็น และควรปฏิบัติกับมันในฐานะตัวระบุแบบทึบแสง
- หลังจาก RFC 9562 ถูกประกาศใช้อย่างเป็นทางการ การอภิปรายที่เกี่ยวข้องก็ ย้ายมาโฟกัสที่การรองรับ UUIDv7
การแก้ไขและการรวมข้อเสนอ
- ในปี 2025 เมื่อ RFC 9562 มีผลอย่างเป็นทางการ ก็มีการกล่าวถึงว่า PostgreSQL 18 รองรับ UUIDv7 แล้ว
- หลังจากนั้นฝั่ง Go ก็เริ่มข้อเสนอแยกต่างหากคือ เพิ่มเฉพาะความสามารถสร้าง UUIDv4·UUIDv7 ในแพ็กเกจ crypto/rand (#76319)
- ความสามารถในการพาร์สถูกตัดออกตามคำแนะนำของ RFC
- ข้อเสนอเดิม (#62026) จึงถูกปิดโดยระบุว่าเป็น รายการซ้ำซ้อน (duplicate)
การอภิปรายด้านการออกแบบ API
- มีการถกเถียงกันว่าพฤติกรรมเริ่มต้นของ
uuid.New() ควรเป็น v4 หรือควรเปิดทางให้เปลี่ยนในอนาคต
- บางส่วนเสนอว่า “ถ้าเปลี่ยนเวอร์ชันทีหลังอาจเกิดปัญหาความเข้ากันได้” จึงควร ตรึงไว้ที่ v4 เสมอ
- มีการหารือว่าจะควรมีเมธอดอย่าง
Compare, MustParse, Parse หรือไม่
- มีความเห็นว่า
Compare จำเป็นสำหรับการรองรับ UUID ที่สามารถจัดเรียงได้ ตามนิยามของ RFC
- ส่วน
MustParse ควรรวมไว้เพื่อให้สอดคล้องกับฟังก์ชันตระกูล Must* อื่น ๆ ในไลบรารีมาตรฐาน
- สรุปว่าเมธอด
IsZero() นั้นไม่จำเป็นสำหรับชนิด UUID
- มีการเสนอแนวคิดด้านการออกแบบหลายแบบ เช่น การเพิ่มโครงสร้าง
Generator, การแยกชนิดตามเวอร์ชัน (UUIDv4, UUIDv7 เป็นต้น)
- บางส่วนชี้ว่าฟังก์ชัน
New() มีความกำกวม และเสนอให้มีเฉพาะ ฟังก์ชันที่ระบุเวอร์ชันชัดเจน (NewV4, NewV7)
ประเด็นทางเทคนิคสำคัญ
- มีการถกเถียงว่าคำนิยามของ การจัดเรียง UUID (sorting) นั้นชัดเจนเฉพาะใน v6·v7 หรือไม่
- มีการพิจารณาวิธีทำให้ การสร้าง UUIDv7 รองรับการเรียงตามเวลา และ ป้องกันการชนกันในการทำงานพร้อมกัน (แนวทางแบบ counter)
- มีการชี้ว่าความหมายของแต่ละเวอร์ชัน แตกต่างกันโดยเนื้อแท้ (เช่น v1 มี MAC address, v7 อิงเวลา) ทำให้การออกแบบเป็นชนิดเดียวมีข้อจำกัด
- บางส่วนเสนอให้ แยกชนิดตามเวอร์ชันและมีเมธอดแปลงแบบชัดเจน เช่น
AsV4(), AsV7()
บทสรุปและสถานะปัจจุบัน
- โดยรวมแล้วชุมชน Go เห็นพ้องค่อนข้างมากว่าจำเป็นต้องมีการรองรับ UUID แบบมาตรฐาน
- อย่างไรก็ตาม เพื่อรักษา ความเรียบง่ายของไลบรารีมาตรฐาน และ ปฏิบัติตามคำแนะนำของ RFC จึงสรุปแนวทางว่า
- ตัดความสามารถในการพาร์สออก
- เพิ่มเฉพาะความสามารถสร้าง UUIDv4·UUIDv7 ลงใน crypto/rand
- ข้อเสนอเดิม (#62026) ถูก รวมเข้าเป็นส่วนหนึ่งของข้อเสนอ #76319 และกำลังดำเนินอยู่
สถานะตอนนี้คือการ รองรับ UUID แบบมาตรฐานในภาษา Go กำลังเข้าใกล้ขั้นตอนการรับรองอย่างเป็นทางการ
1 ความคิดเห็น
ความเห็นจาก Hacker News
น่าสนใจที่มีคนบอกว่า UUID เวอร์ชัน 1~5 ล้าสมัยไปแล้ว
แต่ v4 ก็ยังคงมีความสุ่มสูงที่สุด และยังแนะนำให้ใช้เป็นคีย์หลักเพื่อหลีกเลี่ยงทั้ง ปัญหา hotspot และประเด็นด้านความเป็นส่วนตัว ใน distributed DB
ลิงก์อ้างอิง: เอกสาร UUID ของ CockroachDB, คู่มือ UUID ของ Google Cloud Spanner
UUID แต่ละเวอร์ชัน (รวมถึง v4) ต่างก็มีข้อบกพร่องในบางสถานการณ์ และในความเป็นจริงหลายองค์กรก็ใช้ ค่า 128 บิตล้วน ๆ ที่นิยามเองแทน UUID มาตรฐาน
ท้ายที่สุดแล้ว ความต้องการที่ซับซ้อนจำนวนมากก็เกินข้อจำกัดด้านการออกแบบของ UUID ไปแล้ว
รู้สึกดีที่วันนี้บน HN มี ข่าว Go เล็ก ๆ น้อย ๆ แบบนี้ขึ้นมา
ช่วงนี้มีแต่เรื่องอนาคตของการเขียนโปรแกรมหรือเรื่อง AI กันหมด หัวข้อเทคนิคแบบนี้เลยสดใหม่ดี
ทั้งกลุ่มสายสมบูรณ์แบบ นักพัฒนาสายปฏิบัติจริง และ ชุมชน crypto ต่างก็มีจุดยืนของตัวเอง
เอกสารที่เกี่ยวข้อง: RFC 9562
ฉันหวังว่า Go จะตัดสินใจได้ถูกต้อง โดยเฉพาะ TinyGo ที่เจ๋งมากสำหรับไมโครคอนโทรลเลอร์
ฉันไม่ได้สนใจมากนักว่า Go จะรองรับการสร้าง UUID หรือไม่ แต่การมี ชนิดข้อมูล UUID มาตรฐาน นั้นสำคัญมาก
มันจะทำให้การ marshal แบบสอดคล้องกันใน JSON, Text, database/sql และอื่น ๆ เป็นไปได้
ในการวิเคราะห์ dependency ของ Go เมื่อไม่นานมานี้ google/uuid เป็นแพ็กเกจที่ถูกใช้มากเป็นอันดับสอง
บทวิเคราะห์ที่เกี่ยวข้อง: The most popular Go dependency
เสน่ห์ของ Go อยู่ที่ ความใช้งานได้จริงมากกว่าฟีเจอร์หวือหวา
ภาษาไม่ได้ซับซ้อนจนพัง และเพิ่มเฉพาะสิ่งที่จำเป็นเท่านั้น
ด้วย การรับประกันความเข้ากันได้ย้อนหลัง จึงใช้งานได้อย่างสบายใจ เป็นภาษาที่เปลี่ยนแปลงช้าแต่ดีขึ้นอย่างต่อเนื่อง
สำหรับฉัน สิ่งที่สำคัญกว่าการที่แพ็กเกจ uuid ของ Google ไม่ค่อยเคลื่อนไหวแล้ว คือการที่ gofrs/uuid ปฏิบัติตามมาตรฐานใหม่และยังได้รับการดูแลอย่างต่อเนื่อง
คลังเก็บ gofrs/uuid
issue #194
ฉันเกลียด UUID มาก มันเป็น ตัวระบุที่ไม่เป็นมิตรกับมนุษย์
เวลา debug หรือดูผลลัพธ์ query มันยาวเกินไปและใช้งานลำบาก
แน่นอนว่ามันมีประโยชน์เมื่อจำเป็นต้องมี ID ที่ไม่ซ้ำกันระหว่างระบบที่แยกขาดจากกันโดยสิ้นเชิง แต่ส่วนใหญ่แล้วมันถูกใช้เกินความจำเป็น
ในกรณีทั่วไป ตัวออกเลขแบบรวมศูนย์ ดีกว่ามาก
เช่นขั้นตอนอย่าง GetNextId ใน DB ที่ทั้งเป็นมิตรกับคนและมีประสิทธิภาพกว่า
ผลคือมันกลายเป็น โค้ดที่มนุษย์อ่านไม่ออก และแย่กว่านั้นคือเป็น implementation ทำเองที่มีลักษณะเรียงลำดับแบบประหลาด เป็นการตัดสินใจที่พังมาก
ถ้าใช้ตาราง counter ใน Postgres ก็สามารถสร้าง ID ได้หลายหมื่นรายการต่อวินาที
วิธีนี้ยังช่วยให้ ประหยัดหน่วยความจำ บีบอัดได้ดีขึ้น และเพิ่มประสิทธิภาพของแฮชแมป อีกด้วย
UUID นั้นสะดวก แต่ทำลายประสิทธิภาพ
เช่นรูปแบบ
BASKETBALL-...-FISHที่ใส่ checksum แบบใช้คำ เพื่อให้จำง่ายขึ้นฉันสงสัยว่า Go จะเพิ่ม UUID จริงหรือเปล่า
ถ้าไม่มีการคัดค้านเป็นพิเศษ ก็มีโอกาสสูงว่าจะถูกรวมเข้าไป
Kotlin เองก็เพิ่งเพิ่ม การรองรับ UUID เวอร์ชันตาม RFC 9562 เข้าไปใน standard library ในเวอร์ชัน 2.3
รองรับทั้ง JVM, JS, WASM และ Native
เมื่อ IETF RFC มีความเสถียรแล้ว การที่ Go จะเดินตามก็ถือว่าสมเหตุสมผล
ก็น่าเสียดายที่ Go ยัง ขาดการรองรับฟังก์ชันพื้นฐาน แบบนี้
สำหรับฉัน ระบบ logging ของ Go เรียบง่ายเกินไปจนต้องทำเอง
โมดูล slog ทั้งช้าและใช้งานลำบาก ดูเหมือนออกแบบมาโดยมองแต่สภาพแวดล้อมแบบ enterprise
ฉันเคยคิดว่าจะทำอย่างไรให้ได้ทั้ง ประสิทธิภาพการทำคลัสเตอร์ใน DB ของ v7 และ ความสุ่ม ของ v4 พร้อมกัน
ถ้าใช้ v7 ภายใน แล้วตอนส่งออกภายนอกค่อย scramble ด้วย XOR หรือ AES ก็น่าจะพอทำได้
เช่นถ้าใช้ Feistel encryption ก็สามารถสร้าง public ID ที่ไม่โปร่งใสได้ โดยไม่ต้องเจอปัญหาด้านประสิทธิภาพของ UUID