แบ็กเอนด์ใหม่ของ TSBOARD ตัวสร้างคอมมูนิตี้โอเพนซอร์ส: GOAPI
(github.com/sirini)เมื่อประมาณ 7 เดือนก่อน ผมได้แนะนำโปรเจ็กต์ TSBOARD เป็นครั้งแรก
ตอนนั้นทั้งฟรอนต์เอนด์และแบ็กเอนด์เขียนด้วย TypeScript และใช้ Bun runtime ในการรันแบ็กเอนด์
แต่ด้วยหลายเหตุผล จึงต้องสร้างแบ็กเอนด์ขึ้นมาใหม่ และนำมาเผยแพร่ใน GitHub repository ที่แยกออกจากโปรเจ็กต์ TSBOARD เดิม แบ็กเอนด์ใหม่นี้เขียนด้วยภาษา Go และจะถูกรวมมาในรูปแบบไบนารีกับ TSBOARD เวอร์ชันทางการ
ทำไมถึงสร้างแบ็กเอนด์ใหม่?
- Bun runtime แสดงประสิทธิภาพที่ยอดเยี่ยมจริง ๆ แต่แม้จะถูกแนะนำว่าเป็น all-in-one toolkit ระบบจัดการแพ็กเกจก็ยังตาม npm ไม่ทัน
- ด้วยเหตุนี้ หากจะใช้ TSBOARD จึงจำเป็นต้องมี runtime อยู่ 2 ตัวคือ Node.js และ Bun ทั้งยุ่งยากและไม่สะดวกสำหรับผู้ใช้
- แม้ตอนนี้จะแก้ไขแล้ว แต่ในช่วงแรกมีปัญหาที่ทำงานบน virtual CPU ไม่ได้ จนแม้แต่ผมซึ่งเป็นผู้พัฒนาก็ไม่สามารถนำมันขึ้นไปรันบนเซิร์ฟเวอร์อื่นได้ สถานการณ์นี้ถือว่าร้ายแรงมาก
- แม้จะมีคนชี้ให้เห็นว่าแก้ได้ด้วย orchestration แต่ผมก็อยากก้าวข้ามข้อจำกัดโดยกำเนิดของ JS runtime ที่เป็น single thread และอยากใช้หลายเธรดให้ได้
- ผมต้องการ type ที่มากกว่านี้ TypeScript เพียงอย่างเดียวไม่สามารถตอบโจทย์ความกระหายนี้ได้
ทำไมถึงเลือกภาษา Go?
- แบ็กเอนด์ใหม่นี้ต้องมีคุณสมบัติ 1) คอมไพล์ได้ 2) จัดการหน่วยความจำให้อัตโนมัติได้จะดีมาก และ 3) ไม่ควรต้องติดตั้งอะไรอย่าง runtime เพิ่มเติม
- หลังจากชั่งใจระหว่าง Rust, Kotlin, Python, PHP และ Go สุดท้ายผมจึงเลือกภาษา Go ซึ่งตอบครบทั้ง 3 เงื่อนไข และสำหรับผมก็เป็นภาษาใหม่ด้วย (ขอโทษนะ PHP)
- สิ่งที่ชอบที่สุดคือความเรียบง่ายของ Go และความคล้ายกับ TypeScript ก็เป็นอีกปัจจัยสำคัญในการตัดสินใจ เหนือสิ่งอื่นใด ผมคิดว่าในแง่ของการจัดการ concurrency และ memory มันเป็นตัวเลือกที่ดีกว่าทางเลือกอื่น
พอได้ลองใช้ Go แล้วเป็นอย่างไรบ้าง?
- ผมได้ตระหนักว่า Go ก็พิสูจน์เหมือนกันว่าไม่มีภาษาไหนในโลกที่มีแต่ข้อดี
if err != nil { }จำเป็นก็จริง แต่ก็น่ารำคาญมากจริง ๆ มีหลายครั้งที่คิดถึง try catch finally - น่าจะเป็นปัญหาของ
go-mysql-driverแต่ในสภาพแวดล้อมการพัฒนาจริงที่มีคอขวดอย่าง DB I/O มันไม่ได้ทำงานเร็วขนาดนั้น (ดูโพสต์ที่ลงใน GeekNews นี้: https://th.news.hada.io/topic?id=18048) - การใช้ interface แบบ implicit ก็ยังรู้สึกแปลกอยู่ดี หรือว่าไม่อยากใช้คีย์เวิร์ดอย่าง implements หรือ extends กันนะ?
- ผมชอบ pointer มาก โดยเฉพาะตรงที่ไม่ต้องกังวลเรื่องจังหวะการคืนหน่วยความจำ!
- type ที่หลากหลาย, struct ที่เรียบง่ายแต่ทรงพลัง, และ slice คือของโปรดเลย จำนวนคีย์เวิร์ดก็น้อย ทำให้เรียนรู้และนำไปใช้ได้เร็ว ซึ่งเป็นข้อดีที่สุด
- แค่ใช้คีย์เวิร์ด
goก็สามารถใช้ lightweight thread ได้เหมือนเวทมนตร์...! มีความสุขมาก!
ความเห็นหลังเปลี่ยนแบ็กเอนด์จาก JS runtime มาเป็น Go...?
- เรื่องแบบนี้ครั้งเดียวก็เกินพอแล้ว
- ผมลองทำการทดสอบหลายอย่างพร้อม benchmark ส่วน DB I/O แล้ว แต่ถ้ามองในแง่ประสิทธิภาพจริง ๆ ก็ยากจะรู้สึกถึงความต่างมากนักระหว่าง JS runtime กับ Go binary ตัวอย่างเช่นไลบรารีภาพที่นิยมใช้ในฝั่ง JS อย่าง
sharpก็ใช้ไลบรารีlibvipsเหมือนกัน และไม่มีเว็บแอปพลิเคชันไหนที่ไม่มี DB I/O อยู่แล้ว - ถึงอย่างนั้น แม้ว่าผมจะเหนื่อยอย่างหนัก แต่ก็คิดว่าเปลี่ยนได้ดี และจากนี้ไปตั้งใจจะใช้ภาษา Go สำหรับแบ็กเอนด์ต่อไปเรื่อย ๆ
- การใช้หน่วยความจำลดลงอย่างมีนัยสำคัญจริง ๆ แน่นอนว่าถ้าพัฒนาด้วย Rust ก็อาจ optimize ได้มากกว่านี้ แต่เมื่อเทียบกับการได้ใช้ GC แล้ว ระดับนี้ก็ถือว่าน่าพอใจมากแล้ว
- ความเรียบง่ายของตัวภาษานั้นสุดยอดจริง ๆ คีย์เวิร์ดที่ต้องจำก็น้อย รูปแบบการใช้งานส่วนใหญ่ก็ชัดเจนตายตัว จึงเรียนรู้ได้ง่าย (แน่นอนว่าใช้ให้เก่งเป็นอีกเรื่องหนึ่ง) ผมชอบมากที่มี primitive type ให้ใช้อย่างหลากหลาย
- เหนือสิ่งอื่นใด จุดที่น่าพอใจที่สุดคือหลังคอมไพล์แล้ว แค่มีไบนารีก็รันได้เลย ผมไม่อยากกลับไปสู่การต้องติดตั้งอะไรเพิ่มเพื่อให้แบ็กเอนด์ทำงาน แล้วเอาสิ่งนั้นมารันโค้ดอีกต่อไปแล้ว
ใช้อย่างไร?
- น่าเสียดายที่ยังไม่รองรับสภาพแวดล้อม Windows ให้รันไบนารีบน Linux/Mac แทน
- เซิร์ฟเวอร์ที่ใช้งานต้องติดตั้งไลบรารี
libvipsไว้ล่วงหน้า เพราะไบนารีจะใช้ความสามารถของไลบรารีนี้ในการประมวลผลภาพ - รายละเอียดเพิ่มเติมอธิบายไว้ในไฟล์
README.md
ตอนนี้ยังมีหลายอย่างที่ยังขาดอยู่ และผมก็ยังรอรับฟังความเห็นอันมีค่าจากนักพัฒนาท่านอื่น ๆ อยู่เสมอ ถึงขั้นรู้สึกโทษตัวเองที่ตอนงาน Geeknight กลับพูดได้ไม่เต็มที่ ไม่ว่าจะเป็นการแจ้งบั๊ก ข้อเสนอเพื่อปรับปรุง หรือมุมมองแปลกใหม่แบบไหนก็ยินดีต้อนรับทั้งหมด
ปีนี้เดือนธันวาคมหนักหนาเป็นพิเศษ แต่ก็ยังหวังว่าในปีใหม่จะมีอนาคตที่ดีกว่านี้ ขอบคุณที่อ่านบทความยาว ๆ จนจบ สุดท้ายขอแชร์ลิงก์ release note ของ TSBOARD v1.0.0 ไว้ด้านล่าง
12 ความคิดเห็น
ไปอ่านมาจาก Damong ครับ
เป็น CMS ที่น่าจับตามากครับ ขอบคุณครับ
ผมเองก็ตกใจเหมือนกันที่มีคนใน Damoang ยังจำผมได้ครับ 555 จะพยายามให้มากขึ้นเพื่อให้สมกับความคาดหวังครับ! 😊
มีประโยชน์มาก!
ขอบคุณสำหรับคอมเมนต์นะครับ! 😃
มันมีทั้งข้อดีและข้อเสีย แต่ในแง่ข้อดี สิ่งที่ผมมักรู้สึกว่าดีก็คือ โดยไม่ต้องแก้ไขโค้ดของไลบรารีมาตรฐานหรือไลบรารีภายนอก เราสามารถใช้ implementation ที่คนอื่นสร้างไว้ แล้วมองบางส่วนของมันเป็น interface ที่ผมสร้างเองได้ คล้ายกับ
FunctionalInterfaceของ Java หรือเหมือนกับการนำ duck typing มาใช้กับภาษาแบบคอมไพล์ ในทางกลับกัน ถ้าเป็นวิธีที่ต้องประกาศimplements/extendsไว้เสมอ เวลาอยากเอามาเชื่อมกับ interface ที่ผมสร้าง ก็ต้องคั่นด้วยการทำ Adapter ขึ้นมาสักตัวก่อนส่วนข้อเสียคือ เวลาเพิ่ม/ลบ/เปลี่ยนเมธอดใน interface ตำแหน่งที่แสดง error จะต่างจากภาษา static typing อื่น ๆ เลยทำให้ไม่ค่อยสะดวกครับ
อ๋อ อย่างนี้นี่เอง! มีข้อดีแบบที่ผมนึกไม่ถึงด้วยนะครับ โชคดีที่ข้อความ error น่าจะเป็น
goplsใช่ไหม? ส่วนขยายภาษา Go ของ vscode จับได้ดีมาก เลยหาส่วนที่ตกหล่นหรือที่ implement ผิดได้เร็วครับ ถ้าคุ้นเคยมากขึ้นอีกหน่อย สักวันผมก็น่าจะใช้มันได้เก่งขึ้นเหมือนกันครับ 555 ขอบคุณที่มาอธิบายในคอมเมนต์นะครับ! สวัสดีปีใหม่ ขอให้โชคดีมาก ๆ ครับ~!เหนื่อยมากเลยนะครับ! ผมก็จะลองเอาไปลงบนเซิร์ฟเวอร์ทดสอบเหมือนกัน! ขอให้ประสบความสำเร็จต่อไปในช่วงปีใหม่ 2025 ด้วยนะครับ!
ขอบคุณครับ! ลองทดสอบดูได้เลยนะครับ แล้วถ้ามีอะไรที่ใช้งานไม่ได้ดีหรือมีข้อสงสัย ก็แจ้งมาได้ทุกเมื่อครับ! สวัสดีปีใหม่ครับ~!
ขอเป็นกำลังใจให้ครับ~ 👍🏻
ขอบคุณสำหรับกำลังใจครับ!!! สวัสดีปีใหม่ ขอให้โชคดีตลอดปีนะครับ~!
ขอเป็นกำลังใจให้ครับ!
ขอบคุณมากครับ/ค่ะ!!! สวัสดีปีใหม่ ขอให้มีความสุขมากๆ นะครับ/คะ!!