การออกแบบที่ยึดข้อมูลเป็นศูนย์กลาง (2018)
(dataorienteddesign.com)- Data-Oriented Design ฉบับออนไลน์เป็นสื่อที่เปิดให้ผู้อ่านที่ต้องการเรียนรู้การออกแบบที่ยึดข้อมูลเป็นศูนย์กลางสามารถดูเนื้อหาหลักได้ฟรี
- แม้จะตัดบางบทที่ไม่ใช่แกนหลักของหนังสือทั้งเล่มออกไป แต่ยังคงเรียบเรียงโดยเน้น เนื้อหาสำคัญ ที่จำเป็นต่อการเรียนรู้
- เนื่องจากเป็นเอกสารที่แปลงอัตโนมัติจาก LaTeX เป็น HTML จึงอาจยังมี ข้อผิดพลาดด้านรูปแบบ, รูปภาพเสียหาย, และรายการซอร์สโค้ดที่แสดงผิดพลาด
- หากรายการซอร์สโค้ดเสียหาย สามารถดูโค้ดอ้างอิงได้จาก GitHub repository แยกต่างหาก
- การซื้อหนังสือฉบับพิมพ์เป็นทั้งวิธีอ่านในรูปแบบที่ดีกว่า และยังช่วยให้คงฉบับออนไลน์ไว้สำหรับผู้อ่านที่ซื้อได้ยาก
ลักษณะของฉบับออนไลน์
- Data-Oriented Design ให้บริการเป็นฉบับออนไลน์แบบย่อฟรีที่ว่าด้วยการออกแบบที่ยึดข้อมูลเป็นศูนย์กลาง
- แม้จะตัดบางบทที่ไม่ใช่แกนหลักออก แต่ยังคงรวมลำดับเนื้อหาสำคัญที่จำเป็นสำหรับใช้เรียนรู้ไว้
- เหมาะสำหรับผู้อ่านที่ต้องการทำความคุ้นเคยกับแนวทางการมองการออกแบบโดยให้ตัวข้อมูลเป็นศูนย์กลาง
คุณภาพการแปลงเอกสารและการอ้างอิงโค้ด
- เอกสารออนไลน์ถูกสร้างขึ้นโดยอัตโนมัติ จึงอาจมีบางส่วนที่ รูปแบบดูแปลก
- เครื่องมือที่ใช้แปลงจาก LaTeX เป็น HTML ยังไม่สมบูรณ์ จึงอาจทำให้รูปภาพหรือรายการซอร์สโค้ดเสียหายได้
- หากรายการซอร์สโค้ดแสดงผิดพลาด สามารถค้นหาโค้ดอ้างอิงได้ที่ GitHub
หนังสือฉบับพิมพ์และข้อเสนอแนะ
- หนังสือฉบับพิมพ์อ่านได้ในรูปแบบที่ดีกว่าฉบับออนไลน์
- การซื้อหนังสือฉบับพิมพ์ช่วยให้สามารถคงเวอร์ชันออนไลน์ไว้ต่อไปสำหรับผู้อ่านที่ยังไม่มีความพร้อมในการซื้อ
- สามารถส่งข้อเสนอแนะได้ที่ support@dataorienteddesign.com
1 ความคิดเห็น
ความคิดเห็นจาก Hacker News
หนึ่งในคำแนะนำที่ดีที่สุดที่เคยได้รับเกี่ยวกับการเขียนโค้ดที่ประกอบกันได้และมีประสิทธิภาพสูง คือ “จงจัดการกับ structure of arrays ไม่ใช่ array of structures” และบทความนี้ก็ให้ความรู้สึกสอดคล้องกับแนวคิดนั้นมาก
พอมารู้ทีหลัง สถาปัตยกรรมแบบ entity-component ไม่ได้เหมาะแค่กับเกม แต่ยังเข้ากับแอปพลิเคชันสำหรับงานธุรกิจได้ดีด้วย
เพียงแต่ developer ในองค์กรจำนวนมากยังยึดติดกับโมเดล CRUD แบบเก็บเรกคอร์ด จึงลำบากเมื่อต้องคิดเป็นคอลัมน์แทนที่จะเป็นแถว และแนวคิดอย่างการใส่ entity ID ลงในตาราง
publishedแทนการเปลี่ยนฟิลด์ booleanpublishedเป็นtrueก็มักไม่ค่อยรู้สึกเป็นธรรมชาติแต่เมื่อได้ตระหนักว่าวิธีนี้ขยายแบบ polymorphic ได้ง่ายแค่ไหน ก็จะเริ่มอยากใช้แนวทางนี้กับข้อมูลทุกอย่าง แล้วจะเกิดโอกาสใหม่ ๆ ในการนำข้อมูล component มาใช้ข้ามกัน และจะเริ่มสงสัยว่าทำไมโครงสร้างที่ network interface มีวันเกิด, invoice มีที่อยู่ IPv6 ติดอยู่, แมวเข้าไปอยู่ใน DHCP pool, limegreen ถูกลบ และวันอังคารราคา 5 ดอลลาร์ ถึงได้รับอนุญาตให้มีได้ ซึ่งนั่นแหละคือความสนุกครึ่งหนึ่ง
ผมไม่เห็นด้วยกับข้ออ้างที่ว่าวิธีนี้ไม่เข้ากับ object-oriented โดยสิ้นเชิง เคยใช้แนวทางนี้กับ Active Record ของ Ruby ด้วย และมันก็ทำงานได้ดีแม้ในขอบเขตที่ปกติไม่ค่อยถูกเรียกว่า “ประสิทธิภาพสูง” ระบบ object ของ Ruby ใกล้กับ Smalltalk มากกว่า C++/Java และชอบ การประกอบ (composition) มากกว่า inheritance อย่างชัดเจน จึงเข้ากันได้เป็นพิเศษ
ในภาษา object-oriented โดยทั่วไป เรามักโฟกัสกับ “สิ่งที่อยากคิดถึง” หนึ่งอย่าง เช่น user, blog post หรือธุรกรรมทางการเงิน แล้ว implement แยกออกจากส่วนอื่น ซ่อนข้อมูลไว้ จากนั้นค่อยคิดว่าจะ expose method อะไรให้ส่วนอื่นของระบบใช้ แนวคิดเรื่อง encapsulation นั้นแข็งแรงมาก
ใน data-oriented design โดยมาก ข้อมูลจากโดเมนต่าง ๆ จะเข้าถึงได้ และ subsystem จะเลือกใช้สิ่งที่จำเป็นสำหรับงานของตัวเอง Java หรือ Ruby ไม่ได้ขัดขวางเรื่องนี้ แต่สำหรับโปรแกรมเมอร์แล้ว มีกำแพงทางจิตวิทยาที่ชัดเจน
ยังพูดถึงการสนับสนุนด้านซอฟต์แวร์ที่ทำให้เข้าถึง SoA ได้เหมือน AoS เช่น data frame ของ R, Pandas ของ Python และ DataFrames.jl ของ Julia
ผมชอบ Snowflake มาก และคิดว่ามันจะแย่งส่วนแบ่งจากคู่แข่งรายอื่น ๆ ได้ น่าสนใจด้วยที่ Snowflake “รองรับ” foreign key แต่ไม่บังคับใช้ กล่าวอีกอย่างคือ Snowflake เป็น “NoSQL” ในระดับที่ผมรับได้
อีกแบบคือยอมละทิ้ง encapsulation แยกข้อมูลออกจาก method ที่จัดการข้อมูลนั้น และมองทั้งแอปโดยยึดตามว่าข้อมูลไหลอย่างไร เพื่อ model ให้เข้าใจและเปลี่ยนแปลงได้ง่ายขึ้น หากต้องการเพิ่มความถูกต้อง ก็สามารถใช้ โครงสร้างข้อมูลแบบ immutable และ pure function ได้
บทนำ ECS แบบสั้นมากสำหรับผู้ที่สนใจ: https://dev.to/ovid/the-unknown-design-pattern-1l64
“การจัดวางข้อมูลถูกนิยามด้วยการตีความแบบเดียวที่มาจากมุมมองเดียวหรือไม่?” อาจเป็นคำถามที่สำคัญที่สุดในแง่การเลือกเทคโนโลยีและสถาปัตยกรรม โดยปกติถ้าจะตอบคำถามนี้ ต้องคุยกับธุรกิจและลูกค้า
ถ้าคุณมั่นใจว่ามี “วิว” ที่ถูกต้องสำหรับข้อมูลเพียงหนึ่งเดียวที่จะใช้ทั้งระบบ การฝังสิ่งนั้นลงในโค้ดก็สมเหตุสมผล แต่ถ้ามีความไม่มั่นใจแม้เพียงเล็กน้อย โมเดลสไตล์เชิงสัมพันธ์ก็น่าจะเหมาะกว่า เมื่อหลายบริษัทตระหนักถึงทฤษฎีเกมของปัญหานี้ สุดท้ายก็มักลงเอยที่ SQL
สงสัยว่าทำไมทุกคนดูเหมือนจะถอยห่างจากฐานข้อมูล SQL ขนาดใหญ่เพียงตัวเดียว มีกรณีขอบแบบ “เว็บสเกล” ที่คุกคามความสามารถในการขยายแนวตั้งของงานเขียนอยู่ก็จริง แต่ผมคิดว่าบริษัทส่วนใหญ่ รวมถึงบริษัท F100 ก็ยังไปไม่ถึงจุดนั้นด้วยซ้ำ
ไม่เกี่ยวกับว่าวิธีใดโมเดลชุดข้อมูลนั้นได้ดีที่สุดหรือให้ประสิทธิภาพสูงสุดเลย แต่เป็นเพราะความยืดหยุ่นของสคีมาและประวัติที่การย้ายสคีมาล้มเหลวทำให้ระบบล่มล้วน ๆ ในการออกแบบ NoSQL ปัญหาแบบนั้นไม่เกิดขึ้น และข้อดีที่ฐานข้อมูล SQL ให้มาก็ไม่เพียงพอจะชดเชยข้อได้เปรียบใหญ่ของ NoSQL ที่ไม่มีสคีมาแข็งตัว
แน่นอนว่าถ้าใช้คีย์-แวลูสโตร์ผิด ๆ ประสิทธิภาพและต้นทุนอาจพังหนักได้ บนแพลตฟอร์มคลาวด์อย่าง DynamoDB ผมเห็นหลายกรณีที่จัดโครงสร้างข้อมูลไม่ดี ทำให้ต้องสแกนจำนวนมากและค่าใช้จ่ายพุ่งสูง
เพราะเป็นองค์กรใหญ่เก่าแก่ จึงมีหลายกรณีที่โซลูชันทางเทคนิคที่คนที่ไม่ใช่สายเทคนิคสร้างไว้ในอดีตแข็งตัวและต้องถูกดูแลต่อไป มี การแปลงข้อมูล SQL 5 ชั้น ตั้งแต่ฐานข้อมูลปฏิบัติการ ไปจนถึงโมเดลข้อมูลคนละรุ่นทุกครั้งที่ประเภทธุรกิจเปลี่ยนไป
ยิ่งเลเยอร์สะสมมากขึ้น ก็ยิ่งสร้างทับบนเลเยอร์ก่อนหน้าไปเรื่อย ๆ ถ้าแอปพลิเคชันที่สร้างไว้เมื่อ 10 ปีก่อนบนเลเยอร์นามธรรมชั้นที่ 2 ตอนนี้ต้องใช้ข้อมูลจากเลเยอร์ 4 ก็เขียนสคริปต์ส่งข้อมูลนั้นย้อนกลับไปยังเลเยอร์ก่อนหน้า แล้วเดินหน้าต่อ สุดท้ายจึงกลายเป็นก้อนมหึมาของตารางและวิวที่พึ่งพากัน อ่านข้อมูลด้วยวิธีแปลกและไม่เป็นสัญชาตญาณ ส่วนโปรเจกต์จัดระเบียบมันถูกมองว่าแพงเกินไปและถูกเลื่อนไปจนถึงทศวรรษ 2030
เข้าใจได้ที่ผู้คนเห็นปัญหาแบบนี้แล้วคิดว่าจะหลีกเลี่ยงได้อย่างไร แต่ไม่รู้ทำไม ดูเหมือนเป็นไปไม่ได้ที่จะบังคับใช้แนวทางที่ต้องอาศัยวินัยกับวิศวกรซอฟต์แวร์ และต้องทำให้ไม่สามารถสร้างสปาเกตตีขึ้นมาได้ไม่ทางใดก็ทางหนึ่ง ตรงนี้เองที่การแยกส่วนเข้ามา ถ้าอ่านข้อมูลของบริการอื่นไม่ได้ ก็สร้างสปาเกตตีที่ฆ่าความเร็วของทั้งสองฝั่งไม่ได้
การแยกแอปพลิเคชันในแนวตั้งจึงกลายเป็นโซลูชันเชิงซอฟต์แวร์สำหรับปัญหาเชิงคน นั่นคือวินัยทางวิศวกรรมที่อ่อนแอในองค์กร
เมื่อไม่นานมานี้ผมเผยแพร่เฟรมเวิร์กโอเพนซอร์สที่อิงกับการออกแบบเชิงข้อมูลอย่างเต็มรูปแบบ และได้รับฟีดแบ็กมากมายว่าการออกแบบนี้เข้ากันพอดี การเก็บข้อมูลทั้งหมดไว้ในที่เดียวทำให้หลายอย่างง่ายขึ้นจริง ๆ
https://sql.ophir.dev
ใน DB มหึมามีเศษตกค้างจำนวนมากที่ไม่มีใครใช้และไม่มีใครรู้ว่ามีไว้ทำไม แต่ก็ยังไม่แน่ใจว่ายังจำเป็นอยู่หรือไม่ อีกทั้งการอ่านและการเขียนต้องใช้กลยุทธ์การปรับแต่งที่ต่างกัน
นอกจากนี้ หากทีมต้องการเคลื่อนที่เร็ว ก็ต้องมี ความเป็นเจ้าของ ฐานข้อมูลและที่เก็บข้อมูลเอง โดยไม่ต้องรอให้ DBA ตอบทิกเก็ต
ตอนทำงานในบริษัทใหญ่เก่าแก่ ปัญหาส่วนใหญ่เป็นเรื่องการเมืองและการบริหาร ฐานข้อมูล SQL ขนาดใหญ่เพียงตัวเดียวนั้นมีประสิทธิภาพ แต่ทันทีที่องค์กรที่เป็นเจ้าของมันไม่เห็นด้วยกับกลยุทธ์ของ CTO คนใหม่หรือกับหน่วยธุรกิจหลักอื่น ๆ ปัญหาก็เกิดขึ้น
เมื่อรวมกับเหตุขัดข้องที่แสดงให้เห็นว่าโมเดลนี้มีความยืดหยุ่นต่อความล้มเหลวต่ำ มันก็กลายเป็นปัญหาการเมืองที่น่าปวดหัวอย่างรวดเร็ว และแม้โซลูชันทางเทคนิคจะยังดูชัดเจนสำหรับทุกคน ก็ผลักดันได้ยาก
คำแนะนำทั้งหมดนี้ ขึ้นกับบริบท
เกมเพียงแค่มีการทำงานจำนวนมากที่ต้องใช้แนวทางแบบคอลัมน์ และไม่ใช่ทุกโดเมนจะเป็นแบบนั้น การยัดเยียดแนวปฏิบัติที่ดีของฝั่งเกมไปยังโดเมนอื่นแบบไม่ลืมหูลืมตา มีแต่จะทำให้ชีวิตของทุกคนยากขึ้นและทำให้ระบบส่วนใหญ่แย่ลง
ฟิลด์บูลีนใน struct อาจกลายเป็นบิตเซ็ตได้ ฟิลด์ที่เป็น nullable อาจกลายเป็นแมปแบบ sparse หรือ dense ได้ และฟิลด์ pointer หรือ reference อาจกลายเป็นอาร์เรย์จำนวนเต็มขนาดบิตเล็กลงที่ใช้ทำดัชนีเข้าไปยัง pool ได้
ในสภาพแวดล้อมที่ CPU มักหยุดรอการเข้าถึงหน่วยความจำ ผลกระทบของการเปลี่ยนแปลงเหล่านี้ประเมินต่ำไม่ได้ ความต่างของ เวลาแฝงระหว่าง L3 cache กับ RAM อาจอยู่ราว ๆ 10 เท่า
สำหรับโปรแกรมใดก็ตามที่ประสิทธิภาพเป็นปัญหาแม้เพียงเล็กน้อย วิธีนี้ก็น่าจะเป็นหนึ่งในวิธีที่ช่วยรับประกันประสิทธิภาพที่ดีได้
สิ่งเดียวที่คาดหวังว่าจะขยายต่อไปบนฮาร์ดแวร์รุ่นใหม่คือความหนาแน่นของลอจิกเท่านั้น SRAM และขนาดแคชไม่ค่อยขยายตามกระบวนการลิโทกราฟีล่าสุดอีกแล้ว และแบนด์วิดท์ RAM ก็ไม่ได้เพิ่มขึ้นมากมานานพอสมควร ผมคิดว่าแบนด์วิดท์ต่อคอร์อาจลดลงด้วยซ้ำ การเข้าถึงหน่วยความจำเป็นคอขวดมาระยะหนึ่งแล้ว
การออกแบบเชิงข้อมูลสมเหตุสมผลมากภายในซับซิสเต็มบางอย่าง แต่สำหรับโค้ดเกมเพลย์ระดับสูงแล้ว ยกเว้นบางแนวเกม ก็ไม่จำเป็นต้องเป็นเช่นนั้น
งานนำเสนอใน CppCon 2014 ของ Mike Acton เรื่อง Data-Oriented Design and C++ ผมคิดว่าเป็นงานนำเสนอด้านการเขียนโปรแกรมที่ดีที่สุดเท่าที่เคยมีมา ควรค่าแก่การดูมาก: https://youtu.be/rX0ItVEVjHc
ก่อนหน้านี้เขายังเป็นผู้นำ Unity DOTS ด้วย แต่น่าเสียดายที่ตอนนี้ Unity ดูเหมือนกำลังสั่นคลอนอยู่ งาน DOTS เองแม้จะยังไม่เสร็จสมบูรณ์ แต่ก็แข็งแรงดี
ผมใช้เวลาส่วนใหญ่ในอาชีพไปกับการเขียนเว็บแอป แต่พอดูงานนำเสนอนี้แล้วก็เข้าใจว่า “ทำไมถึงมีคนใช้ C?”
Andrew Kelley เคยนำเสนออย่างมีประโยชน์และสนุกว่า การออกแบบเชิงข้อมูลส่งผลต่องานคอมไพเลอร์ Zig อย่างไร: https://vimeo.com/649009599
มือใหม่ก็สามารถเรียนการเขียนโปรแกรมแบบเชิงข้อมูลได้ตั้งแต่ต้น
หนังสือที่สอนสไตล์นี้ให้มือใหม่มี How to Design Programs และ A Data-Centric Introduction to Computing
https://htdp.org/
https://dcic-world.org/
เจอรีวิวออนไลน์เกี่ยวกับหนังสือเล่มนี้: https://gist.github.com/seece/25ed1b2108cf5782718b026382f2c5...
“ต้นเหตุที่ทำให้หลายโปรเจกต์เจ็บปวดและล่าช้าคือการยืนกรานว่าไม่ควรทำ optimization เร็วเกินไป เหตุผลที่การ optimize ในช่วงท้ายทำได้ยากขนาดนั้น เป็นเพราะซอฟต์แวร์จำนวนมากถูกก่อร่างขึ้นด้วยวิธีวางอินสแตนซ์ของอ็อบเจ็กต์ไว้ทุกที่ แม้แต่ตอนที่ไม่จำเป็นก็ตาม”
แน่นอนว่ามีแอปพลิเคชันที่ performance เป็นเรื่องสำคัญที่สุด และก็มีแอปพลิเคชันที่ไม่เป็นแบบนั้น ทำให้ผมคิดว่า สำหรับแอปที่ performance สำคัญ early optimization ก็อาจจะโอเคได้หรือเปล่า ไม่แน่ใจว่าอ่านแบบนี้ถูกไหม
ยังมีสิ่งที่เรียกว่า Data-Oriented Programming ด้วย: https://www.manning.com/books/data-oriented-programming
สงสัยว่าสองแนวคิดนี้เป็นเรื่องเดียวกันหรือไม่
การออกแบบเชิงข้อมูลเป็นมิตรกับมือใหม่ เพราะมันจัดการแค่ ความบริสุทธิ์ของการทำ data modeling ไม่ใช่การจัดการผู้คนและธุรกิจ
ตอนเด็ก ๆ ขั้นตอนแรกของโปรเจกต์ใหม่คือการวาด entity relationship model และนั่นก็กลายเป็นรากฐานของทุกอย่าง
ทุกวันนี้ ก่อนจะเริ่มทำ data model ผมจะทำความเข้าใจปัญหาและโดเมนก่อน แล้วคิดถึง capability รวมถึงว่าจะมัดรวมและขีดขอบเขตมันอย่างไร
แต่บทความนี้ดูเหมือนกำลังจะบอกว่า หากโฟกัสกับการรวบรวมความต้องการด้านข้อมูลตั้งแต่ต้น ก็อาจทำให้ต้องคุยเรื่องความต้องการทางธุรกิจน้อยลงเอง
หนึ่งในแนวคิดหลักเวลาใช้ DoD คือการไม่ซ่อนข้อมูลไว้หลัง abstraction กล่าวคือ ยิ่งน้อยยิ่งดี
แต่พออ่านบทนำแบบเร็ว ๆ กลับรู้สึกตรงกันข้าม มีการพูดมากเกินไปและเอาแนวคิดหลักไปทำให้เป็นนามธรรมเสียเอง สงสัยว่ามีแค่ผมหรือเปล่าที่รู้สึกประชดดี เหมือนคนเขียนไม่ดื่มไวน์ของตัวเอง
ย่อหน้าเกริ่นนำค่อนข้างยอดเยี่ยม งานเขียนลื่นไหลและไอเดียน่าสนใจจนทำให้อยากอ่านต่อ
“ข้อมูลคือทั้งหมดที่เรามี ข้อมูลคือสิ่งที่เราต้องแปลงเพื่อสร้างประสบการณ์ผู้ใช้ สิ่งที่อ่านเข้ามาเมื่อเปิดเอกสารก็คือข้อมูล กราฟิกบนหน้าจอ พัลส์จากปุ่มเกมแพด สาเหตุที่ทำให้ลำโพงสร้างคลื่นในอากาศ วิธีการเลเวลอัป วิธีที่ศัตรูรู้ตำแหน่งของคุณแล้วยิงใส่ ทั้งหมดก็คือข้อมูล เวลาที่ไดนาไมต์ใช้ในการระเบิด และจำนวนแหวนที่เสียไปเมื่อคุณตกลงบนหนามก็เป็นข้อมูล มันคือตำแหน่งและความเร็วปัจจุบันของทุกอนุภาคในฉากอันงดงามที่จบเกม และสิ่งที่ถูกอ่านจากดิสก์เข้าสู่ชีวิตของคุณนั้นคือผลลัพธ์จากการเปลี่ยนรูปผ่านซอร์สโค้ดที่ป้อนให้คอมไพเลอร์ คำสั่งที่แอสเซมเบลอร์สั่งไว้ และเครื่องจักรที่ขับเคลื่อนด้วยคำสั่งที่ถูกถอดรหัสแล้ว”
มันอาจมีประโยชน์ในฐานะ “การอาบน้ำเย็น” เพื่อปูฉากและดึงให้หลุดจากวิธีคิดแบบ abstraction ของ object-oriented แต่ถ้านอกเหนือจากนั้นแล้ว ผมมองว่ามีประโยชน์พอ ๆ กับวิศวกรที่พูดว่า “มองไปรอบตัวสิ! ทุกอย่างประกอบด้วยอะตอม! โดยพื้นฐานแล้ววิศวกรรมคือการย้ายอะตอม!”
มันไม่ได้ผิด แต่ก็ไม่ได้ช่วยอะไรมากนักในการทำวิศวกรรมจริง ๆ