เมื่อวันที่ 10 พ.ย. 2565 มีการจัดงาน “Seven Peaks Speaks: การเพิ่มศักยภาพให้กับ Node.JS Backend ของคุณ” ที่ออฟฟิศของ Seven Peaks ซึ่งทีม backend developer ของเราได้ร่วมจัดงานนี้เพื่อนำเสนอสิ่งที่คุณควรรู้เกี่ยวกับการเขียนโปรแกรมสำหรับ backend และวิธีใช้ Node.JS เพื่อพัฒนา backend ให้กับโปรเจกต์ใหม่ๆ ของคุณอย่างมีประสิทธิภาพ
ในงานนี้ เรามีคุณ Sijan Shrestha ซึ่งเป็น Senior Full-Stack Developer ของเราทำหน้าที่เป็นวิทยากรท่านแรก ส่วนท่านที่สองคือคุณ Denis Pshenov Tech Lead ของเราผู้เชี่ยวชาญเรื่อง Node.JS
สำหรับคนที่เพิ่งเริ่มทำงานเป็น backend developer นั้น การทำความเข้าใจเรื่องของ serverless เป็นสิ่งสำคัญมาก
serverless คือโมเดลการพัฒนาแบบ cloud-native ที่ทำให้นักพัฒนาสามารถสร้างและเปิดตัวแอปพลิเคชันได้โดยไม่ต้องมานั่งกังวลเรื่องการบริหารจัดการเซิร์ฟเวอร์
ก่อนหน้านี้ ฟังก์ชันใน Amazon Web Services (AWS) นั้นเป็นวัตถุประสงค์หลักของมัน แต่ตอนนี้มันเป็นเพียงฐานข้อมูล, ข้อความ (SQS และ SNS), และที่จัดเก็บข้อมูลเท่านั้น
ประโยชน์ของ serverless ก็คือมันเป็นโมเดลที่สะดวกรวดเร็วสำหรับนักพัฒนาที่สามารถเลือกจ่ายเฉพาะบริการที่พวกเขาอยากใช้งานได้ ซึ่งเป็นการประหยัดต้นทุน
นอกจากนั้นมันยังพร้อมใช้งานอยู่เสมอ เนื่องจากมันไม่ได้ถูกเก็บไว้ที่เซิร์ฟเวอร์ต้นทางที่ใดที่หนึ่ง ดังนั้น จึงสามารถ deploy โค้ดของแอปพลิเคชันได้จากทุกที่
ข้อสุดท้ายคือ แอปพลิเคชันที่มีโครงสร้างสถาปัตยกรรมพื้นฐานแบบ serverless นั้นสามารถปรับขนาดได้อัตโนมัติเมื่อฐานผู้ใช้เพิ่มขึ้นหรือมีการใช้งานมากขึ้น
Lambda คือบริการ virtual function ที่ช่วยให้คุณสามารถสร้างแอปพลิเคชันที่ตอบสนองต่อเหตุการณ์หรือข้อมูลใหม่ๆ ได้อย่างรวดเร็ว
มันเป็นบริการที่คอยบริหารจัดการสิ่งต่างๆ ได้อย่างเต็มรูปแบบ ซึ่งจะทำหน้าที่ตอบสนองความต้องการทุกอย่างของคุณในด้านสถาปัตยกรรม ดังนั้น มันจึงไม่ใช่แค่ช่วยให้คุณประหยัดเวลาในการจัดการ task ต่างๆ แต่ยังคิดค่าบริการในระดับที่จับต้องได้อีกด้วย
พูดง่ายๆ ก็คือ เมื่อมีการ invoke ฟังก์ชันนี้ มันจะสร้างพื้นที่เฉพาะขึ้นมาเพื่อรันโค้ดและสแกนโดยอัตโนมัติ
หนึ่งในวิธีที่ง่ายที่สุดในการ deploy โค้ดสักชุดหนึ่งก็คือการเข้าไปที่ AWS console โดยตรงและใช้งาน IDE (integrated development environment) ที่อยู่ในระบบ อย่างไรก็ตาม นี่เป็นวิธีที่เราไม่แนะนำ
มีแนวทางอื่นมากมายในการ deploy โค้ดที่ดีกว่านั้น ยกตัวอย่างเช่น ใช้ IaC (infrastructure as a code) ซึ่งเครื่องมือ IaC ที่นิยมใช้กันมากที่สุดก็คือ Terraform
เครื่องมือ IaC อีกตัวคือ Serverless Application Model (SAM) ซึ่งมีให้ใช้ใน AWS โดย SAM นั้นเป็นเฟรมเวิร์กที่เปิดให้ใช้ฟรีสำหรับพัฒนาแอปพลิเคชันแบบ serverless
มันมี shorthand syntax ในการ express ฟังก์ชัน, ฐานข้อมูล, API, และการ mapping ของ event source
SAM เป็นเครื่องมือที่ช่วยให้คุณสร้างแอปพลิเคชัน serverless ได้เร็วขึ้น เนื่องจากมันขยายและปรับเปลี่ยน syntax ของตัวมันเองเป็น syntax ของ AWS CloudFormation ได้ในระหว่างที่ทำการ deploy
อย่างไรก็ตาม มันก็ยังไม่ค่อยเป็นมิตรกับนักพัฒนาและใช้งานยากอยู่ดี ดังนั้นคุณ Sijan จึงแนะนำว่า Serverless Framework เป็นตัวเลือกที่ดีกว่า
Serverless Framework คือเว็บเฟรมเวิร์กที่ทำงานบน Node.js ซึ่งไม่ใช่แค่เป็นโอเพนซอร์ส แต่ยังฟรีอีกด้วย มันเป็นเฟรมเวิร์กแรกที่สร้างขึ้นมาเพื่อพัฒนาแอปพลิเคชันบน AWS Lambda โดยเฉพาะ
CloudFormation คือเครื่องมือที่ช่วยในการสร้างโมเดลและติดตั้งทรัพยากรของ AWS บนเทมเพลตของตัว CloudFormation เอง
ดังนั้น คุณจึงสามารถใช้เวลาโฟกัสกับการพัฒนาแอปฯ ที่รันบน AWS ได้มากขึ้น และเสียเวลาบริหารจัดการทรัพยากรเหล่านั้นน้อยลง
นอกจากนั้น AWS ยังเข้าใจการทำงานของ CloudFormation ได้ในระดับ native ซึ่งเป็นการสร้างโครงสร้างพื้นฐานขึ้นมาจากไฟล์ ถ้าจะให้อธิบายแบบลงลึกหน่อยก็คือ Serverless Framework นั้นใช้ไฟล์ yaml ที่อ่านได้ง่ายๆ มาแปลงเป็นเทมเพลตของ CloudFormation ที่ AWS เข้าใจนั่นเอง
สามารถดูตัวอย่างของ CloudFormation และ Serverless Framework ได้ข้างล่างนี้
เมื่อนำ Node.js มาใช้งานในโปรเจกต์พัฒนา backend นั้น Middy คือ middleware engine อันเรียบง่ายที่ช่วยให้คุณแปลงโค้ด AWS Lambda ให้อ่านง่ายมากขึ้นได้
ไม่ว่าคุณจะเคยมีประสบการณ์ใช้งานเว็บเฟรมเวิร์กอย่าง Express มาก่อนหรือไม่ คุณก็จะรู้สึกคุ้นเคยกับคอนเซปต์ของ Middy และเริ่มใช้งานมันได้อย่างรวดเร็ว
middleware engine ช่วยให้คุณโฟกัสกับ business logic ที่สำคัญของ Lambda จากนั้นเพิ่มส่วนเสริมเข้าไป เช่น การยืนยันตัวตน, การตรวจสอบข้อมูล, การให้อนุญาต, และ serialization เป็นต้น ด้วยการเสริมแต่ง business logic ที่สำคัญในแนวทางที่แยกย่อยออกเป็นโมดูลและสามารถนำกลับมาใช้ใหม่ได้
ในทีมงานขนาดใหญ่ แนวทางการ deploy หลายๆ service เข้าไปใน repository เดียวนั้นถือว่าเป็นเรื่องปกติมากๆ
วัตถุประสงค์ของ Serverless Framework Compose คือการทำให้การ deploy และบริหารจัดการ service ที่มีหลากหลายนั้นง่ายขึ้น ด้วยการทำสิ่งต่อไปนี้
นักพัฒนามักจะแนะนำให้ใช้ Serverless Framework Compose เพราะต้องการหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นขณะที่กำลังรอการ deploy ให้เสร็จสิ้น
ในฐานะที่คุณ Sijan ก็เป็นนักพัฒนาคนหนึ่ง เขาก็เสนอให้ใช้ปลั๊กอินที่ใช้บ่อยอย่าง serverless-webpack, serverless-offline, และ serverless-api-gateway-caching
JavaScript เป็นภาษาแบบ untyped ซึ่งเปิดโอกาสให้เกิดปัญหา type safety ที่มีการใช้ unknown type ได้
ตัวอย่างต่อไปนี้คือการลองเพิ่มตัวเลขลงไปใน string และคาดหวังว่าจะได้ผลลัพธ์เป็นตัวเลข
ระบบ JavaScript-type safety ที่ทำงานบน JavaScript พื้นฐาน จะทำหน้าที่เป็นเลเยอร์เสริมของ syntax
ดังนั้น เพื่อให้แน่ใจว่า type assertion ที่ทำไปในโค้ดจะทำตามคำสั่งและตรวจจับบั๊กได้ โดยมีการใช้งาน compiler หรือ checker บางชนิด
การกำหนดจุดจบเพื่อให้เกิด type safety แบบครบวงจรนั้นเริ่มด้วยฝั่ง client ซึ่ง client จะมาจากแพลตฟอร์มไหนก็ได้ ไม่ว่าจะเป็นเว็บเบราว์เซอร์ หรือแอปพลิเคชันมือถือ
client จะเรียกใช้ API ที่เป็นเซิร์ฟเวอร์ในการตอบสนองการทำงานบางอย่าง ดังนั้น คุณก็จะมีครบทั้ง request และ response
หมายความว่า คุณมีฐานข้อมูลอยู่ที่ไหนสักแห่งและมี request–response นั่นเอง
กฎของ Conway คือ
“องค์กรใดก็ตามที่ออกแบบระบบขึ้นมา จะมีดีไซน์ที่โครงสร้างเหมือนกับโครงสร้างการสื่อสารขององค์กรนั้น”
นี่คือโครงสร้างที่คุณจะใช้ในโปรเจกต์ที่มีขนาดใหญ่ขึ้น โดยจะมีทีม backend ที่สร้าง API และฐานข้อมูล มีทีมเว็บที่รับผิดชอบในการดูแลเว็บไซต์ และทีม Android ที่พัฒนาแอปพลิเคชัน รวมทั้งทีม service ที่รับผิดชอบในการดูแล microservice
ทีมที่กล่าวถึงข้างต้นนั้นจำเป็นต้องสื่อสารกัน ทีนี้ คำถามก็คือ พวกเขาจะสื่อสารกันอย่างไร จะอธิบายกันและกันอย่างไร โครงสร้างของ request และ response เป็นอย่างไร และนี่คือ pain point ที่คุณอาจจะต้องเจอ
โซลูชันแบบดั้งเดิมที่ใช้แก้ปัญหาดังกล่าวก็คือแนวทางการทำงานแบบ “เน้นดีไซน์เป็นหลัก” ซึ่งคุณต้องออกแบบและจัดทำเอกสารคู่มือของ API ขึ้นมาก่อนด้วยการเขียนและแบ่งประเภทของเอกสาร จากนั้นจึงนำเอกสารดังกล่าวไป implement กับ server และ client
เครื่องมือที่มักนำมาใช้กันคือเครื่องมือของ OpenAPI อย่าง Swagger ที่ช่วยให้คุณเขียนเอกสารคู่มือ API และรายละเอียดดีไซน์ของ API ในไฟล์ YAML
จากนั้นคุณก็จะมีเว็บไซต์ที่คุณสามารถแชร์เอกสารคู่มือนี้แล้วส่งให้กับทีมงานได้
ช่วยให้ทีมงานของคุณสามารถนำคู่มือไปใช้ implement กับ client และ server ได้ ดังนั้น เราจึงสามารถแก้ pain point แรกเกี่ยวกับเรื่องการสื่อสารที่ไม่มีประสิทธิภาพระหว่างทีมงานด้วยกันได้
อย่างไรก็ตาม บั๊กก็ยังคงอยู่และไม่มี type ดังนั้น คุณจึงต้องเขียน manual types ขึ้นมาโดยอ้างอิงจากคู่มือที่คุณสร้างขึ้นก่อนหน้านี้
เหตุผลที่คุณจำเป็นต้องทำแบบนี้ก็เพื่อให้การ deploy เป็นไปอย่างราบรื่น รวมถึงได้รับ cookie request, cookie response, และอื่นๆ
Typed Client นั้นปกติแล้วจะเป็นแผนที่ช่วยให้ฟังก์ชันของ cookie ทำงานได้ปกติ รวมถึง request และ response ด้วย จากนั้นคุณก็จะสามารถ fetch ข้อมูลบางอย่างมาจาก API ของ cookie คุณได้
การทำแบบนี้ช่วยให้คุณแก้ไขปัญหาที่สอง ในเรื่องของบั๊กและประสบการณ์ที่ไม่ดีของนักพัฒนาที่เกิดจากการขาดแคลน type ที่จำเป็นได้
อย่างไรก็ตาม สิ่งหนึ่งที่คุณควรพิจารณาก็คือการทำให้ types ของ server และ สอดคล้องกัน นี่คือไอเดียบางอย่างที่วิทยากรท่านที่สองของเรา คุณ Denis ฝากไว้ให้
สำหรับเวิร์กโฟลว์ สิ่งแรกก็คือการตรวจสอบว่าแนวทางแรกนั้นเหมาะสมหรือไม่ ด้วยขั้นตอนต่อไปนี้
อีกตัวเลือกคือการเขียนโค้ดขึ้นมาหรือรัน server ด้วยขั้นตอนเหล่านี้
สิ่งเหล่านี้จะทำให้คุณสามารถแก้ไข pain point ที่เหลืออยู่ได้ ซึ่งก็คือความแตกต่างระหว่าง client และ server types และการเสียเวลาซ้ำซ้อนในการพิมพ์ข้อมูลแต่ละ client แบบแมนวล
GraphQL เป็น query language และ server-side runtime สำหรับ API โดยเป้าหมายสำคัญของมันคือการทำให้ client มีแค่ข้อมูลที่ต้องการใช้งาน และไม่มีอะไรมากไปกว่านั้น
gRPC คือ RPC (Remote Procedure Call) framework ที่เชื่อถือได้ นำไปใช้เพื่อสร้าง API ที่มีความคล่องตัวและปรับขนาดได้ มันช่วยให้การพัฒนาระบบเน็ตเวิร์กที่มีการสื่อสารระหว่างแอปพลิเคชันและ client นั้นมีความโปร่งใส ตรวจสอบได้มากขึ้น
tRPC เป็นไลบรารีขนาดเล็กที่ช่วยให้คุณพัฒนา typesafe API ได้อย่างเต็มรูปแบบ โดยไม่ต้องใช้ schema หรือ code generation
ทำให้เกิดการแชร์ type ระหว่าง server และ client และจะ import type เท่านั้น ไม่ใช่โค้ดจริงๆ จาก server ดังนั้นจึงไม่สามารถเข้าถึง frontend ของโค้ดจาก server ได้
คุณจึงสามารถตรวจจับปัญหาระหว่าง frontend และ backend ได้ในตอน compile และ build ด้วย type safety แบบครบวงจร
CodeDeploy คือเครื่องมือที่ทำให้การ deploy โค้ดไปยัง instance และ on-premises server นั้นสามารถทำได้โดยอัตโนมัติ ทำให้คุณสามารถควบคุมทุกอย่างได้จากที่เดียวและลดเวลา downtime ลง
Zodios คือ REST API toolbox ที่มี type safety แบบครบวงจร พร้อมด้วย declarative syntax ที่เข้าใจง่าย โดยสามารถนำไปใช้ในการพัฒนา REST API ได้
แม้ว่ามันจะทำงานได้ดีที่สุดกับ TypeScript แต่เราก็ยังสามารถนำมันไป deploy กับ JavaScript แบบมาตรฐานได้
นี่คือประโยชน์ข้ออื่นๆ ของการใช้ Zod
ในแง่ของ type safety แบบครบวงจรนั้น ฐานข้อมูลคือสิ่งหนึ่งที่อยู่ในวงจรดังกล่าว ในมุมมองของคุณ Denis แล้ว มีฐานข้อมูลที่แนะนำให้ใช้อยู่สองแบบ ได้แก่
แบบแรกคือ Prisma ซึ่งมีฟังก์ชันที่ทำให้คุณมีประสบการณ์ในการพัฒนาที่ยอดเยี่ยมด้วย super typesafe
อีกแบบคือ MikroORM ซึ่งมีความซับซ้อนในการใช้งานมากกว่า แต่มีฟีเจอร์เกี่ยวกับความปลอดภัยที่ดี
คุณ Sijan และคุณ Denis แสดงให้เห็นว่าพวกเขามีความรู้เกี่ยวกับ Node.JS สำหรับการพัฒนา backend ที่ลึกซึ้ง ในสมัยก่อนเรามีเพียงชุดของไฟล์ JavaScript ที่กระจัดกระจาย ปัจจุบันนี้โลกของนักพัฒนามีความสะดวกสบายมากขึ้น มีเฟรมเวิร์กและเครื่องมือมากมายให้ใช้ในการสร้างโปรเจกต์ ทำให้งานมีคุณภาพมากขึ้น, พึ่งพาตัวเองได้, เข้าถึงง่ายขึ้น, และนักพัฒนาได้รับประสบการณ์ที่ดียิ่งขึ้น