- พร้อมกับการเปิดตัว Dagger Cloud v3 ทาง Dagger ได้เขียน UI ใหม่ด้วย WebAssembly(WASM) และ Go
- โดยทั่วไป Go ไม่ค่อยถูกใช้สำหรับพัฒนาเว็บ UI แต่เลือกแนวทางนี้เพื่อ "รวมโค้ดเบสและปรับจูนประสิทธิภาพ"
- บทความนี้แบ่งปัน "เบื้องหลังการตัดสินใจ ความท้าทายระหว่างการพัฒนา และผลลัพธ์สุดท้าย"
ปัญหาเดิม: ความไม่มีประสิทธิภาพจากการมีโค้ดเบสสองชุด
- Dagger ทำงานบนพื้นฐานของ DAG(Directed Acyclic Graph) และแสดงผลภาพผ่านทั้ง TUI(เทอร์มินัล UI) และ เว็บแดชบอร์ด(Dagger Cloud)
- เดิมที TUI พัฒนาด้วย Go ส่วนเว็บ UI พัฒนาด้วย React/TypeScript
- แต่การซิงก์ระหว่าง UI ทั้งสองทำได้ยาก และโดยเฉพาะเว็บ UI มีปัญหาด้านประสิทธิภาพเมื่อต้องประมวลผลข้อมูลจำนวนมากแบบเรียลไทม์
- ระหว่างจัดการสตรีมอีเวนต์ OpenTelemetry ที่ซับซ้อนซึ่งมีสแปนหลายแสนรายการ ประสิทธิภาพและความเร็วของ React UI ลดลงอย่างชัดเจน
- ต้องพัฒนาฟังก์ชันเดียวกันซ้ำสองครั้ง ซึ่งเป็น ภาระการพัฒนาที่หนักสำหรับทีมขนาดเล็ก
- ดังนั้นจึงเริ่มมองหาแนวทางใหม่โดยมีเป้าหมายคือ รวมโค้ดเบสและปรับปรุงประสิทธิภาพ
ทางออกที่เลือก: Go + WebAssembly
- รวมโค้ดเบสด้วย Go
- เนื่องจาก TUI ถูกพัฒนาด้วย Go อยู่แล้ว หากเว็บ UI ก็พัฒนาด้วย Go ก็จะสามารถนำโค้ดกลับมาใช้ซ้ำได้
- ในทีมมีนักพัฒนา Go จำนวนมาก จึงช่วย เพิ่มประสิทธิภาพการทำงานของทีมและทำให้ดูแลรักษาได้ง่ายขึ้น
- ใช้ WebAssembly(WASM)
- นำ WebAssembly มาใช้เพื่อให้สามารถรันโค้ด Go ในเบราว์เซอร์ได้โดยตรง
- อย่างไรก็ตาม Go + WASM ยังมีระบบนิเวศที่ไม่สุกงอมเต็มที่ จึงมีความท้าทายอยู่บ้าง:
- ไลบรารีคอมโพเนนต์มีน้อย → ต้องสร้าง UI เอง
- ข้อจำกัดหน่วยความจำ WASM ของเบราว์เซอร์ (2GB) → ต้องปรับจูนเมื่อจัดการข้อมูลปริมาณมาก
- แต่การปรับจูนหน่วยความจำก็สามารถเป็นประโยชน์ได้ทั้งกับ TUI และเว็บ UI
กลยุทธ์ลดความเสี่ยงของโปรเจ็กต์
- ใช้เฟรมเวิร์ก Go-app
- เลือกเฟรมเวิร์กที่พัฒนาด้วย Go สำหรับการสร้าง PWA(Progressive Web App)
- ให้โมเดลแบบคอมโพเนนต์คล้าย React จึงย้ายมาใช้งานได้ไม่ยาก
- สร้างและตรวจสอบโปรโตไทป์
- นำ UI เดิมมาสร้างใหม่ด้วย Go-app ให้มากที่สุดเพื่อระบุประเด็นสำคัญ
- WASM เป็นมาตรฐานเปิดที่มีเอกสารรองรับอยู่แล้ว และคำถามหลักส่วนใหญ่หาคำตอบได้จากเอกสารของ Go-app
- ปัญหาใหญ่ที่สุดคือข้อจำกัดด้านการใช้หน่วยความจำ ซึ่งต้องอาศัยการออกแบบและการปรับจูนเพื่อแก้ไข
ขั้นตอนเปลี่ยนจากโปรโตไทป์สู่โปรดักชัน
กลยุทธ์การปรับจูนประสิทธิภาพ
- ปรับจูนการเรนเดอร์ล็อกขนาดใหญ่
- เมื่อต้องจัดการข้อมูลล็อกมากกว่า 200,000 บรรทัด จำเป็นต้องปรับปรุงประสิทธิภาพการเรนเดอร์
- เพื่อสิ่งนี้จึงปรับจูนไลบรารีเรนเดอร์เทอร์มินัลเสมือน(midterm)
→ ทำให้ทั้ง TUI และเว็บ UI เร็วขึ้น
- เพิ่มความเร็วในการพาร์ส JSON
- Go WASM พาร์ส JSON ได้ช้า → จึงออกแบบสมาร์ตแบ็กเอนด์ที่ทำงานบน WebSocket
- ใช้
encoding/gob ของ Go เพื่อปรับจูนการส่งข้อมูล
- ปรับขนาดไฟล์ WASM
- ขนาดไฟล์ WASM เริ่มต้น: 32MB
- ใช้การบีบอัด Brotli → ลดลงเหลือ 4.6MB
- เนื่องจาก CDN จัดการการบีบอัดได้ยาก จึงบีบอัดโดยตรงในกระบวนการบิลด์
การปรับปรุงอื่น ๆ
- นอกจากปัญหาหน่วยความจำที่คาดไว้แล้ว ความกังวลส่วนใหญ่กลายเป็นเรื่องเกินจริง
- การเขียน UI คอมโพเนนต์ไม่ได้ยาก และ การเชื่อมต่อกับบริการอื่น ๆ (Tailwind, Auth0 ฯลฯ) ก็ไม่มีปัญหา
- สามารถใช้แพ็กเกจ NPM จากใน WebAssembly ได้ → ทำงานร่วมกับ JavaScript ได้
- Go-app มีความยืดหยุ่นในการอัปเดตคอมโพเนนต์มากกว่า React ทำให้มีอิสระในการปรับจูนมากกว่า
- สามารถวิเคราะห์ประสิทธิภาพได้ด้วยเครื่องมือโปรไฟล์ของ Go(pprof) และโปรไฟเลอร์ในตัวของเบราว์เซอร์
- ด้วย การรองรับ PWA จึง รันเป็นแอปเดสก์ท็อป/มือถือได้ และเปิดใช้งานแอปได้โดยไม่ต้องเปิดเบราว์เซอร์
ข้อดีที่ได้หลังการเปลี่ยนผ่าน
- ความสม่ำเสมอของ UI ดีขึ้น
- เมื่อ TUI และเว็บ UI ใช้โค้ดเบสเดียวกัน จึงมอบ UX ที่สอดคล้องกันมากขึ้น
- ประสิทธิภาพและการใช้หน่วยความจำดีขึ้น
- เมื่อต้องจัดการข้อมูลจำนวนมาก ความเร็วในการเรนเดอร์ดีขึ้นและใช้หน่วยความจำน้อยลง
- ประสิทธิภาพการทำงานของทีมสูงขึ้น
- เดิมทีต้อง ปรับจูนเว็บ UI และ TUI แยกกัน
ตอนนี้ ปรับจูนครั้งเดียวแล้วใช้ได้กับทั้งสองอินเทอร์เฟซพร้อมกัน
- ส่งผลให้ โฟกัสกับการพัฒนาฟีเจอร์ใหม่ได้มากขึ้น
ควรเปลี่ยนมาใช้ Go + WASM หรือไม่?
- โดยทั่วไปไม่แนะนำ แต่ในบางเงื่อนไขอาจมีประโยชน์:
- ทีมที่มีนักพัฒนา Go จำนวนมาก
- UI ที่ซับซ้อนและ TypeScript/React เริ่มติดข้อจำกัดด้านประสิทธิภาพ
- ต้องการแชร์โค้ดระหว่าง TUI และเว็บ UI
- อยู่ในสภาพแวดล้อมที่ต้องเร่งความเร็วการพัฒนาให้สูงสุด
- หากตรงกับเงื่อนไขข้างต้น Go + WASM อาจเป็นทางเลือกที่ดี
อย่างไรก็ตาม ในกรณีส่วนใหญ่เทคโนโลยีเว็บแบบเดิม(React, TypeScript ฯลฯ) ยังเหมาะสมกว่า
6 ความคิดเห็น
เหมือน GWT สมัยก่อนหรือเปล่าครับ?
อืม... ก็สงสัยอยู่ว่ามันจะทำให้การพัฒนาที่ปลอดภัยด้านชนิดข้อมูลมากกว่า TS หรือเปล่า
ไม่ว่าจะมองยังไง ก็เหมือนกำลังทำโจทย์ง่าย ๆ ให้ยากขึ้น...
การทำฟรอนต์เอนด์ด้วย Go มีประสิทธิภาพกว่าที่คิด เห็นได้ชัดว่าเหตุผลที่กรณีการใช้งานเพิ่มขึ้นนั้นมีอยู่จริง
แต่ก็ยังอยากลองทำดูนะ
ความคิดเห็นจาก Hacker News
มีความเห็นว่าทีมขนาดเล็กจำเป็นต้องปล่อยใช้งานให้เร็ว
พวกเขามีทีมวิศวกร Go ที่แข็งแกร่ง และมี UI ที่ซับซ้อนซึ่งขยายต่อด้วย TypeScript/React ได้ยาก
มีความกังวลว่าอาจเป็นเฟรมเวิร์กที่ "render ลง canvas" แต่จริง ๆ ไม่ใช่
พวกเขาตัดสินใจใช้ <a href="https://go-app.dev/" rel="nofollow">https://go-app.dev/</a> เพื่อสร้างฟรอนต์เอนด์
มีความเห็นว่า Go ไม่เหมาะกับงานลักษณะนี้
คงน่าสนใจถ้ามีรายงานติดตามผลในอีกไม่กี่เดือนว่า การย้ายจากสแตกที่หนักกว่าไปสู่สแตกที่ประสิทธิภาพดีกว่าแต่ค่อนข้างแปลกนั้นให้ผลเชิงบวกหรือไม่
ผู้สร้าง go-app มาเจอโพสต์นี้เข้าและรู้สึกประหลาดใจ พร้อมอวยพรให้ผลิตภัณฑ์ประสบความสำเร็จ
Go WASM parse JSON ได้ช้าจนทำให้ต้องเปลี่ยนสถาปัตยกรรมและสร้าง "smart backend" สำหรับการโหลดข้อมูลแบบค่อยเป็นค่อยไปผ่าน WebSockets
มีความเห็นว่า WASM เหมาะกับงานเฉพาะทางบางอย่าง แต่ไม่เหมาะกับการสร้างเว็บแอปทั่วไป
มีความเห็นว่าการใช้ภาษาเดียวกันกับทุกองค์ประกอบ (ฟรอนต์เอนด์/แบ็กเอนด์/แอป) มีคุณค่ามาก