การเรียนรู้แบบอินเทอร์แอคทีฟด้วย Yjs
(learn.yjs.dev)- ขณะนี้ learn.yjs.dev หยุดการเผยแพร่ชั่วคราว จึงไม่สามารถดูเนื้อหาการเรียนรู้ได้
- บนหน้าเว็บไม่มี สาเหตุของการหยุด ระบุไว้ นอกเหนือจากสถานะ
This deployment is temporarily paused - ยังไม่มีการเปิดเผยเวลาหรือกำหนดการที่จะกลับมาเผยแพร่อีกครั้ง
- ขณะนี้ไม่สามารถตรวจสอบโครงสร้าง ฟีเจอร์ หรือ例อย่างของเนื้อหาการเรียนรู้ Yjs จากหน้าเว็บได้
- สิ่งที่ตัดสินได้ในตอนนี้มีเพียง learn.yjs.dev อยู่ในสถานะ หยุดชั่วคราว เท่านั้น
1 ความคิดเห็น
ความคิดเห็นบน Hacker News
Hey HN! ผมเป็นนักพัฒนาจาก Jamsocket ที่ทำสิ่งนี้ขึ้นมา ถ้าไม่คุ้นกับ Yjs ให้มองว่าเป็น ไลบรารี CRDT สำหรับสร้างแอปแบบทำงานร่วมกันและ local-first
ถ้าไม่เคยจัดการสถานะแบบกระจายมาก่อน เส้นโค้งการเรียนรู้จะค่อนข้างชัน และแม้แต่การเพิ่มค่าตัวนับแบบ “hello world” ในเดโมเฟรมเวิร์ก JavaScript ก็ยังยุ่งยากเมื่อมีไคลเอนต์หลายตัวเข้ามาเกี่ยวข้อง
บทสอนจำนวนมากเป็นแนว “ติดตั้งไลบรารีนี้กับการผสานรวม text editor แล้วแอปก็เสร็จ” จึงไม่ได้ให้ mental model ว่าจริง ๆ แล้วเกิดอะไรขึ้น
เลยสร้าง Learn Yjs ซึ่งเป็นบทสอน Yjs แบบอินเทอร์แอ็กทีฟ และใส่เดโมที่สำรวจได้กับแบบฝึกเขียนโค้ดไว้มากมาย เพื่อให้คนที่เพิ่งเริ่มพัฒนาแบบ local-first เข้าใจได้อย่างเป็นธรรมชาติ
WebSocket ก็ดูเหมือนจะหาโฮสติ้งฟรีได้ยากขึ้นนิดหน่อย และบทสอน CRDT ที่มีอยู่ก็ช่วยได้มากเหมือนกัน
ตอนนี้กำลังทำด้วย HTML/JS ล้วนและ Alpine และอยากรู้ด้วยว่าในแอปแบบนี้จะใช้ Yjs ได้ไหม
และอยากรู้ว่า Y-Sweet ทำงานกับไลบรารี CRDT อื่น ๆ อย่าง Automerge หรือ Loro ด้วยไหม หรือเฉพาะ Yjs เท่านั้น
โครงสร้างการส่งไฟล์ไบนารีไปมากันดูคล้ายกัน เลยสงสัยว่า Y-Sweet เข้ากันได้กับการใช้งาน CRDT แบบคล้าย ๆ กันได้แค่ไหน
[0] https://github.com/y-crdt/y-crdt
Yjs ดี และทำให้ได้ผลลัพธ์แบบ P2P ได้ง่าย
แต่แบ็กเอนด์ของ Yjs, persistence, การแก้ความขัดแย้งขั้นสุดท้าย (กรณีมี editor คนหนึ่งออฟไลน์นานเกินไป) และการย้อนประวัติ ดูเป็นโจทย์วิศวกรรมที่แก้ยาก
เคยอยากได้ประสบการณ์ที่ดีใน block editor อย่าง Platejs https://platejs.org/ อยู่เสมอ
โซลูชันอย่าง Liveblocks https://liveblocks.io/text-editor ที่พยายามทำให้ประสบการณ์นักพัฒนาง่ายขึ้นนั้นดี แต่ส่วนใหญ่ต้องยอมสละ สิทธิ์ควบคุมข้อมูล ไปบางส่วน
เวลาค้นคีย์เวิร์ด CRDT บน HN ก็มักเห็นผลลัพธ์ดี ๆ และความสนใจอยู่เสมอ แต่ฝั่งแบ็กเอนด์โอเพนซอร์สดูไม่ค่อยมีตัวเลือกดี ๆ เคยเช็กมาหลายครั้งแล้ว ถ้ามีอะไรที่ผมพลาดไปก็อยากให้บอก
https://hn.algolia.com/?dateRange=pastYear&page=0&prefix=tru...
คนส่วนใหญ่คาดหวังอย่างน้อยให้ทำงานเหมือน Google Docs หรือ Notion และจากมุมมองนักพัฒนา ก็อยากให้จัดเก็บแบบ private ในรูปแบบคล้าย Postgres JSONB ได้ โดยไม่ต้องขุดรายละเอียดการ implement ลึกเกินไป
เคยอยากใช้ Y.js ในแบ็กเอนด์ Go หลายครั้ง แต่หา implementation อ้างอิงแบบง่าย ๆ ได้ยาก เลยต้องยอมแพ้ทุกครั้งเพราะข้อจำกัดด้านเวลา
เช็กซ้ำมาหลายปีแล้ว นอก Node.js ก็ยังดูยากอยู่ดี
เคยใช้ Yjs ใน side project เล็ก ๆ มาก่อน ฝั่งไคลเอนต์เรียนและใช้งานค่อนข้างง่าย
ฝั่งเซิร์ฟเวอร์อยาก deploy เป็นไบนารีเดี่ยว แต่ตัวอย่างภาษาที่ไม่ใช่ Node เช่นตัวอย่าง Yrs ซึ่งเป็นพอร์ต Rust แทบจะไม่มีเลย
สุดท้ายจึงปรับ https://github.com/yjs/y-websocket เล็กน้อยและใส่ persistence บน LevelDB เข้าไป ซึ่งในมุมผมไม่ใช่ทางเลือกที่เหมาะที่สุด
สงสัยว่ามีเอกสารดี ๆ สำหรับ implement ฝั่งเซิร์ฟเวอร์ที่รวม persistence ด้วยภาษาอย่าง Rust ไหม
เท่าที่จำได้ เอกสารฝั่งไคลเอนต์ที่มีอยู่ค่อนข้างเอนเอียงไปทางการผสานรวม text editor ดังนั้นบทสอนนี้จึงมีประโยชน์มากจริง ๆ เพราะไม่ได้ใช้การผสานรวม text editor เลยต้องคลำทางเอง
ใช้ S3 หรือระบบไฟล์ในเครื่องเป็น storage และคอมไพล์เป็นไบนารีขนาดไม่กี่ MB ที่ลิงก์กับ musl
https://github.com/jamsocket/y-sweet
เขาบอกว่าเป็น “เทคนิค fractional indexing ที่ใช้อินเด็กซ์เป็นเศษส่วนแทนที่จะเป็นจำนวนเต็ม” แต่สงสัยว่าต้องใช้ได้กี่ครั้งถึงจะไม่หยุด
โค้ดทดสอบมีดังนี้:
let left = 0, right = 1
let rightPrevious = 2
let counter = 0;
while (right > left && right < rightPrevious) {
rightPrevious = right;
right /= 2;
counter++
}
console.log(counter)
ผมดู repository แบบเร็วมาก ๆ แต่ไม่พบว่าปัญหานี้ถูกจัดการตรงไหน และไม่มีเวลาขุดลึก ถ้าเป็น issue จริงก็อาจช่วยแก้ได้
ตอนนี้กำลังใช้ Yjs ขณะสร้างแอปที่ต้อง ทำงานแบบออฟไลน์
จริง ๆ แล้วไม่ใช่แอปทำงานร่วมกันแบบเรียลไทม์ แต่ถ้ามองว่าเซิร์ฟเวอร์เป็นผู้ร่วมงานคนหนึ่ง และแอปเป็นผู้ร่วมงานอีกคน ก็จะนึก use case ได้ง่าย
จุดที่ผมยังข้ามผ่านไม่ได้ใน Yjs คือ เมื่อพยายามทำให้ตัวอย่างการย้ายรายการในแอปสิ่งที่ต้องทำของบทเรียนนี้ใช้ได้ทั่วไป มันจะซับซ้อนเร็วเกินไป
พอมีหลายอ็อบเจกต์ที่มีความสัมพันธ์กัน ก็อยากใส่ไว้ใน Document เดียวกัน และการรักษาความสัมพันธ์นั้นให้อยู่ในสถานะซิงก์ก็มีหลุมพรางมากมาย เช่น fractional indexing ในบทเรียน
แล้วเมื่อมีรายการสะสมจนมีขนาดระดับฐานข้อมูล โมเดลของเล่นที่เอาทุกอย่างใส่ไว้ในเอกสารเดียวก็หมายความว่า ฝ่ายใดก็ตามที่ต้องการอ่านรายการใด ๆ ต้องได้รับทั้ง DB ทั้งหมดและประวัติของมันไปด้วย
สุดท้ายก็ต้องแยกรายการออกเป็นอ็อบเจกต์ต่างหากและทำ persistence เอง แต่เอกสารมีแค่บทเรียนนี้ [0] เท่านั้น และถ้าจะสปอยล์ก็คือมันเป็นหน้าเปล่าที่ขึ้นว่า “Work in Progress - come back later” มาหลายปีแล้ว
ดังนั้นต่อให้พยายามสร้าง Provider มาจัดการเอง สถานการณ์ของเอกสารก็เหมือนเดิม [1]
พอเจอ Subdocuments ก็เลยดีใจคิดว่าอาจมีวิธีแก้ปัญหาทั่วไปนี้ [2] แต่ Provider บางตัวจัดการความสัมพันธ์ระหว่างเอกสารย่อยไม่ได้ และ Provider บางตัวก็ไม่รองรับเอกสารย่อยเอง สุดท้ายก็ต้องสร้าง Provider เองอยู่ดี แล้วก็วนกลับมาที่ปัญหาไม่มีเอกสาร
ถ้าลองอ่านโค้ด ก็จะพบว่าแก่นของ Yjs จริง ๆ คือ โปรโตคอล แต่โปรโตคอลนั้น ซึ่งเป็นสาระสำคัญของ Yjs ก็ไม่ได้ถูกจัดทำเอกสารไว้อย่างสมบูรณ์ และกระจัดกระจายอยู่ในโค้ดหลายจุดที่ค่อนข้างเฉพาะตัว เว้นแต่ว่าจะนับเปเปอร์เมื่อ 10 ปีก่อนที่อธิบายว่าเวอร์ชันก่อนหน้าของ Yjs ทำงานอย่างไรเป็นเอกสาร
ไม่ได้ตั้งใจจะเขียนเป็นคำบ่น แต่ตลอดหลายปีมานี้ผมใช้เวลามากเกินไปในการพยายามทำให้มันใช้งานได้จริง และช่องว่างระหว่างเดโมของเล่นแบบ “มันทำงานได้เหมือนเวทมนตร์!” กับสิ่งที่ใช้จริงได้นั้นกว้างเกินไป เอกสารส่วนนั้นว่างเปล่ามา 10 ปีแล้ว นอกจากคำว่า “Work in Progress”
หวังว่าบริษัทที่พยายามหารายได้จาก Yjs เหมือนผู้เขียนบทความนี้จะช่วยเติมช่องว่างนั้นได้
[0] https://docs.yjs.dev/tutorials/persisting-the-document-to-a-...
[1] https://docs.yjs.dev/tutorials/creating-a-custom-provider
[2] https://docs.yjs.dev/api/subdocuments
[3] ตอนเขียนสิ่งนี้ ผมหวังว่าสถานการณ์จะเปลี่ยนไปแล้ว แต่เอกสารทั้งหมดดูเหมือนยังอยู่ระหว่างดำเนินการเหมือนเมื่อ 5 ปีก่อน และการรองรับเอกสารย่อยก็ดูเหมือนกัน
ในเดโมแบบอินเทอร์แอคทีฟ แถบเลื่อน latency ทำงานเหมือนบัฟเฟอร์ debounce ไม่ใช่ ความหน่วงของเครือข่าย เลยทำให้งง ไม่เข้าใจว่าทำไมถึงทำแบบนี้
ข้อดีของวิธีนี้คือทำได้โดยไม่ซ่อนสถานะใด ๆ จากผู้อ่าน แผนภูมิวงกลมแสดงสถานะภายในเพียงอย่างเดียวที่มีอยู่ตรง ๆ
เป้าหมายไม่ใช่การจำลองเครือข่ายอย่างแม่นยำ แต่คือการสร้างสัญชาตญาณความเข้าใจ
เดโมแบบอินเทอร์แอคทีฟสวยมาก อยากรู้ว่าใช้ไลบรารีอะไรทำ
เดโมรัน Yjs อยู่ข้างในจริง ๆ “ไคลเอนต์” แต่ละตัวมีเอกสารของตัวเอง และเมื่อผู้ใช้คลิก ก็จำลองความหน่วงด้วย
setTimeoutแล้วค่อยรวมเอกสารเข้าหากันแบบแมนนวล ยังมีเอกสารที่สามสำหรับไทม์ไลน์ตรงกลางด้วยนอกจากนั้น ใช้ dnd kit [1] สำหรับ drag and drop ในเดโมสิ่งที่ต้องทำ, Motion [2] สำหรับแอนิเมชัน และ CodeMirror [3] สำหรับตัวแก้ไขข้อความ
[1] https://dndkit.com
[2] https://motion.dev
[3] https://codemirror.net
เกมรูปแบนเนอร์ดูงี่เง่าแต่สนุกดี
Team purple ftw:
https://imgur.com/a/Oxc6jUA
ในที่สุดก็ทำโคลเวอร์สี่แฉกได้แล้ว แต่ผ่านไปประมาณ 2 นาทีมีคนมาทำพัง
แก้ไข: เดี๋ยวนะ ทุกคนหายไปไหนกันหมด? ดูเหมือนเราทำมันพังหรือไม่ก็ผมโดนบล็อก แต่ยังไงก็ขอปรบมือให้คนทำ ของเจ๋งมาก
อนึ่ง ยังมี อีโมจิลับ อีกสองตัว