ที่ Riiid ซึ่งให้บริการ Santa TOEIC มีการใช้งาน gRPC/Protobuf อย่างเข้มข้นมาก
ไม่นานหลังจากที่ผมเข้าทำงานที่ Riiid ก็ได้รับแจ้งว่าในอนาคต API ทั้งหมดที่ทีมแบ็กเอนด์ส่งมอบให้ฝั่งฟรอนต์เอนด์ (มือถือ/เว็บ) จะถูกรวมให้เป็น gRPC ทั้งหมด
หากต้องการใช้สแตก gRPC/Protobuf บนเว็บฟรอนต์เอนด์ เดิมทีมีวิธีอย่างการต่อปลั๊กอิน JS/TS เข้ากับ protoc หรือใช้ Protobuf.js
ปลั๊กอิน JS อย่างเป็นทางการของ protoc มีปัญหาตรงที่สร้างโค้ดในสไตล์ที่เก่ามาก ส่วนปลั๊กอินใน ecosystem เองก็ยังไม่สามารถตอบโจทย์ความต้องการของเราได้ทั้งหมด อีกทั้งยังมีความไม่สะดวกจากการต้องพึ่งพา native binary (protoc) ด้วย (ทุกวันนี้ยังมีปัญหาว่าติดตั้ง protoc บนอุปกรณ์ M1 ได้ยากด้วย)
เราใช้ Protobuf.js สร้างผลิตภัณฑ์หลายตัวมาโดยตลอด แต่เมื่อบริษัทใช้ Protobuf กับทุกอินเทอร์เฟซที่ใช้สื่อสารข้ามแพลตฟอร์มในทุกผลิตภัณฑ์ที่พัฒนาขึ้น ก็พบว่า Protobuf.js ยังไม่ mature ในระดับที่เราต้องการ
มีปัญหาหลายอย่าง เช่น ถ้าชื่อ message เหมือนกัน บางครั้งจะเข้าใจผิดว่าเป็น message ที่อยู่ใน namespace อื่น หรือถ้ามีการประกาศ message ต่อจาก enum ใน global namespace ก็จะไม่สร้างโค้ดประเภท message ให้ หรือ type definition ของ TypeScript ที่สร้างออกมาก็ไม่ตรงกับพฤติกรรมของ JS ที่ถูกสร้างขึ้น เป็นต้น
ระหว่างกระบวนการนี้ เพื่อสร้างระบบที่คัดเฉพาะ protobuf schema ที่จำเป็นต่อแต่ละผลิตภัณฑ์มาทำบิลด์ เราจึงสร้างตัวจัดการแพ็กเกจ protobuf ชื่อ pollapo ขึ้นมา
(ตอนนั้นมีตัวจัดการ dependency ของ protobuf อื่นอยู่บ้าง แต่มีทั้งปัญหา bug หรือไม่รองรับ nested dependency เป็นต้น นอกจากนี้ฟังก์ชันจัดการแพ็กเกจของ buf ในเวลานั้นยังมีเพียงบล็อกโพสต์ที่บอกว่ากำลังพัฒนาอยู่ และกว่าจะถึงตอนที่เราสร้าง pollapo และทำ internal migration เสร็จ ก็ยังไม่เสร็จสมบูรณ์)
ด้วย pollapo เราลดจำนวน schema ที่ต้องบิลด์ต่อผลิตภัณฑ์ลงได้มาก และลด bug ที่เกิดจากชื่อ message ซ้ำกันได้ แต่ถึงอย่างนั้นก็ยังมี bug และปัญหาในการบิลด์อยู่ เราจึงสร้างคอมไพเลอร์ protobuf to typescript ขึ้นมาเองเพื่อแก้ปัญหาเหล่านี้
ปัจจุบัน Santa TOEIC ได้ถอด protobuf.js ออกทั้งหมดและเปลี่ยนมาใช้ pbkit เรียบร้อยแล้ว
แอปที่พัฒนาที่ Riiid รวมถึง Santa TOEIC ใช้งานเว็บวิวอย่างมาก
เว็บวิวต้องสื่อสารกับ native เพื่อดึงข้อมูลอุปกรณ์/ผู้ใช้ หรือข้อมูลคอนเทนต์ที่กำลังแสดงอยู่ และอินเทอร์เฟซในส่วนนี้ก็กำหนดด้วย Protobuf service schema เช่นกัน
pbkit มีอินเทอร์เฟซที่ทำให้ตอนสร้าง service code สามารถสลับ network layer จาก gRPC ไปเป็นโปรโตคอลอื่นได้
วิศวกรเว็บฟรอนต์เอนด์ที่ใช้ pbkit compiler จึงไม่จำเป็นต้องรู้ว่าเวลาสื่อสารกับ mobile native นั้นกำลังส่งคำขอผ่าน gRPC หรือผ่าน App Bridge protocol ที่ตกลงไว้กับวิศวกรมือถือ
และเพราะเราได้พัฒนาส่วนขยาย Chrome ขึ้นมาเองด้วย จึงสามารถตรวจสอบเนื้อหาการสื่อสารกับมือถือได้อย่างสะดวกในแท็บ pbkit ของ Chrome DevTools ราวกับดูที่แท็บ Network
เนื่องจากเราสร้าง protobuf schema compiler ขึ้นมาเอง จึงคิดว่าน่าจะทำฟีเจอร์อย่าง Go to Definition ในตัวแก้ไขโค้ดได้อย่างรวดเร็ว เลยทำส่วนขยาย VSCode ขึ้นมาด้วย
ก่อนหน้านี้ส่วนขยาย protobuf สำหรับ VSCode ที่มีอยู่มักให้ความสามารถแค่ syntax highlighting แต่ pbkit vscode extension มีฟีเจอร์ Go to Definition ที่ทำงานได้อย่างถูกต้องรวมอยู่ด้วย
ต่อจากนี้เรามีแผนจะพัฒนาการรองรับภาษาอื่นอย่าง swift/kotlin/python, รองรับ use case ฝั่งเซิร์ฟเวอร์, เครื่องมือสร้างเอกสาร, เครื่องมือ linting/formatting เป็นต้น
และเราก็กำลังมองหาวิศวกรที่จะมาร่วมพัฒนาเครื่องมือเหล่านี้ด้วย: https://riiid.com/ko/career/dx-software-engineer
ขอฝากไว้ในความสนใจด้วย
คลังเก็บ pbkit: https://github.com/pbkit/pbkit
ส่วนขยาย vscode: https://marketplace.visualstudio.com/items?itemName=pbkit.vscode-pbkit
ส่วนขยาย Chrome: https://chrome.google.com/webstore/detail/pbkit-devtools/fjacmiijeihblfhobghceofniolonhca
8 ความคิดเห็น
ที่บริษัทของพวกเรา เมื่อหลายปีก่อนตอนชั่งใจระหว่าง gRPC ก็ได้เลือก Thrift ไปครับ/ค่ะ Thrift เองก็มี JS generator ที่ยังไม่สมบูรณ์ เลยต้องแก้ไขกันเอง และก็ได้ตระหนักว่านี่เป็นงานที่ไม่ควรทำเลย เลยแอบคิดว่าน่าจะเลือก gRPC ตั้งแต่แรกหรือเปล่า แต่ดูเหมือนว่าทางนั้นเองก็ใช่ว่าสถานการณ์จะดีนัก
หลังจากนั้นพวกเราเลือก GraphQL และส่วนตัวผม/ฉันก็พอใจกับมันอยู่ครับ/ค่ะ บางครั้งก็แอบกังวลเรื่อง communication overhead แต่ก็คงใช้โปรโตคอลแบบไบนารีไม่ไหวจริง ๆ
ที่ Karrot Market ใช้งานกันได้ดีมากเลยครับ!! ( _ _ )
กำลังพยายามเอาไปใช้ให้คุ้มสำหรับ API mesh ภายในอยู่ครับ 555
ว่าแต่ถ้าในบริษัทใช้ถึงขั้น production กันแล้ว ก็น่าจะเลิกใช้เวอร์ชันที่ดูเป็น pre-alpha อย่าง v0.0.44 ได้แล้วนะครับ
ดูแค่เลขเวอร์ชันอย่างเดียวก็น่าจะมีคนที่ไม่กล้าใช้เหมือนกัน T_T
ว้าว คุณสร้างคอมไพเลอร์ขึ้นมาเองเลยสินะ สุดยอดมาก! (ผมสงสัยอยู่เหมือนกันว่าโค้ด golang ถูกสร้างออกมาอย่างไร แต่ตอนนี้ดูเหมือนว่าจะรองรับแค่ deno กับ node.js เท่านั้น) ปกติผมมักใช้ protoc หรือ buf ร่วมกับ ts-proto เลยอยากรู้ว่าระหว่างโค้ด ts ที่ถูก generate ออกมากับของ ts-proto นั้นมีความแตกต่างกันอย่างไรบ้างครับ
เหมือนจะรู้สึกว่าอ้อมไปอ้อมมานะ https://github.com/trpc/trpc
คุณ bichi / ถ้า API ของเซิร์ฟเวอร์ถูกให้บริการด้วยโปรโตคอล gRPC กรณีแบบนี้ tRPC ก็คงไม่ได้มีไว้เพื่อรองรับสิ่งนั้นใช่ไหมครับ~?
ผมเห็นด้วยว่าการใช้สแตก gRPC/Protobuf ไม่ได้เป็นทางเลือกที่เหมาะที่สุด (ไม่ใช่ว่าผมอยากใช้เอง แต่ใช้เพราะข้อจำกัดของบริษัท)
อย่างไรก็ตาม trpc กำหนดอินเทอร์เฟซด้วย zod จึงน่าจะเหมาะอย่างยิ่งเมื่อใช้ TypeScript บนทุกแพลตฟอร์ม
แต่สำหรับสภาพแวดล้อมของเราที่เขียนเซิร์ฟเวอร์ด้วย kotlin ก็ดูเหมือนว่าจะใช้งานได้ยาก และในกรณีที่ต้องสื่อสารกับโมบายเนทีฟ (swift, kotlin) ก็ดูไม่ค่อยเหมาะเช่นกัน
ว้าว มีถึงส่วนขยาย VS/Chrome ในโค้ดด้วย.. เจ๋งมากครับ!! เป็นกำลังใจให้ครับ
เขียนบทแนะนำได้ดีมาก ๆ จนดูเหมือนว่าคนที่เข้ามาผ่าน GeekNews จะได้ข้อมูลมากกว่าคนที่เข้าไปดูที่ Repo ตรง ๆ เสียอีก ^^;
ถ้าตอนนี้มีใครใช้งาน Protobuf อยู่แล้วมาคอมเมนต์ไว้ น่าจะช่วยได้มากเลยครับ