บทความและข่าวสาร | Seven Peaks Insights

คู่มือการใช้งาน Node.JS เพื่อพัฒนา backend สำหรับมือใหม่

เขียนโดย Seven Peaks - 11 ธ.ค. 2021, 10:12:00

เมื่อวันที่ 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

Serverless คืออะไร?

สำหรับคนที่เพิ่งเริ่มทำงานเป็น backend developer นั้น การทำความเข้าใจเรื่องของ serverless เป็นสิ่งสำคัญมาก

serverless คือโมเดลการพัฒนาแบบ cloud-native ที่ทำให้นักพัฒนาสามารถสร้างและเปิดตัวแอปพลิเคชันได้โดยไม่ต้องมานั่งกังวลเรื่องการบริหารจัดการเซิร์ฟเวอร์

ก่อนหน้านี้ ฟังก์ชันใน Amazon Web Services (AWS) นั้นเป็นวัตถุประสงค์หลักของมัน แต่ตอนนี้มันเป็นเพียงฐานข้อมูล, ข้อความ (SQS และ SNS), และที่จัดเก็บข้อมูลเท่านั้น

ประโยชน์ของ serverless ก็คือมันเป็นโมเดลที่สะดวกรวดเร็วสำหรับนักพัฒนาที่สามารถเลือกจ่ายเฉพาะบริการที่พวกเขาอยากใช้งานได้ ซึ่งเป็นการประหยัดต้นทุน

นอกจากนั้นมันยังพร้อมใช้งานอยู่เสมอ เนื่องจากมันไม่ได้ถูกเก็บไว้ที่เซิร์ฟเวอร์ต้นทางที่ใดที่หนึ่ง ดังนั้น จึงสามารถ deploy โค้ดของแอปพลิเคชันได้จากทุกที่

ข้อสุดท้ายคือ แอปพลิเคชันที่มีโครงสร้างสถาปัตยกรรมพื้นฐานแบบ serverless นั้นสามารถปรับขนาดได้อัตโนมัติเมื่อฐานผู้ใช้เพิ่มขึ้นหรือมีการใช้งานมากขึ้น

Lambda คืออะไร?

Lambda คือบริการ virtual function ที่ช่วยให้คุณสามารถสร้างแอปพลิเคชันที่ตอบสนองต่อเหตุการณ์หรือข้อมูลใหม่ๆ ได้อย่างรวดเร็ว

มันเป็นบริการที่คอยบริหารจัดการสิ่งต่างๆ ได้อย่างเต็มรูปแบบ ซึ่งจะทำหน้าที่ตอบสนองความต้องการทุกอย่างของคุณในด้านสถาปัตยกรรม ดังนั้น มันจึงไม่ใช่แค่ช่วยให้คุณประหยัดเวลาในการจัดการ task ต่างๆ แต่ยังคิดค่าบริการในระดับที่จับต้องได้อีกด้วย

พูดง่ายๆ ก็คือ เมื่อมีการ invoke ฟังก์ชันนี้ มันจะสร้างพื้นที่เฉพาะขึ้นมาเพื่อรันโค้ดและสแกนโดยอัตโนมัติ

แล้วคุณจะ deploy โค้ดอย่างไร?

หนึ่งในวิธีที่ง่ายที่สุดในการ 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

Serverless Framework คือเว็บเฟรมเวิร์กที่ทำงานบน Node.js ซึ่งไม่ใช่แค่เป็นโอเพนซอร์ส แต่ยังฟรีอีกด้วย มันเป็นเฟรมเวิร์กแรกที่สร้างขึ้นมาเพื่อพัฒนาแอปพลิเคชันบน AWS Lambda โดยเฉพาะ

AWS CloudFormation

CloudFormation คือเครื่องมือที่ช่วยในการสร้างโมเดลและติดตั้งทรัพยากรของ AWS บนเทมเพลตของตัว CloudFormation เอง

ดังนั้น คุณจึงสามารถใช้เวลาโฟกัสกับการพัฒนาแอปฯ ที่รันบน AWS ได้มากขึ้น และเสียเวลาบริหารจัดการทรัพยากรเหล่านั้นน้อยลง

นอกจากนั้น AWS ยังเข้าใจการทำงานของ CloudFormation ได้ในระดับ native ซึ่งเป็นการสร้างโครงสร้างพื้นฐานขึ้นมาจากไฟล์ ถ้าจะให้อธิบายแบบลงลึกหน่อยก็คือ Serverless Framework นั้นใช้ไฟล์ yaml ที่อ่านได้ง่ายๆ มาแปลงเป็นเทมเพลตของ CloudFormation ที่ AWS เข้าใจนั่นเอง

สามารถดูตัวอย่างของ CloudFormation และ Serverless Framework ได้ข้างล่างนี้

คำแนะนำเกี่ยวกับ Node.JS ในการพัฒนา backend

เมื่อนำ 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 ที่มีหลากหลายนั้นง่ายขึ้น ด้วยการทำสิ่งต่อไปนี้

  • deploy หลาย service พร้อมๆ กัน
  • สร้าง service หลายๆ ตัวตามลำดับที่ต้องการได้
  • รันคำสั่งข้าม service ที่แตกต่างกันได้
  • แชร์ผลลัพธ์จาก service หนึ่งไปยังอีก service หนึ่งได้

นักพัฒนามักจะแนะนำให้ใช้ Serverless Framework Compose เพราะต้องการหลีกเลี่ยงปัญหาที่อาจเกิดขึ้นขณะที่กำลังรอการ deploy ให้เสร็จสิ้น

ในฐานะที่คุณ Sijan ก็เป็นนักพัฒนาคนหนึ่ง เขาก็เสนอให้ใช้ปลั๊กอินที่ใช้บ่อยอย่าง serverless-webpack, serverless-offline, และ serverless-api-gateway-caching

  • Serverless-webpack ใช้สำหรับแปลงโค้ด
  • Serverless-offline ใช้รันโค้ดแบบ local
  • Serverless-api-gateway-caching ใช้เพื่อทำ caching โค้ด

JavaScript Type Safety

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

Pain Points

ทีมที่กล่าวถึงข้างต้นนั้นจำเป็นต้องสื่อสารกัน ทีนี้ คำถามก็คือ พวกเขาจะสื่อสารกันอย่างไร จะอธิบายกันและกันอย่างไร โครงสร้างของ request และ response เป็นอย่างไร และนี่คือ pain point ที่คุณอาจจะต้องเจอ

  • การสื่อสารระหว่างทีมที่ขาดประสิทธิภาพ
  • บั๊กและประสบการณ์ในการทำงานที่ไม่ดีของนักพัฒนาอันเนื่องมาจากการขาด type ที่จำเป็น
  • ความแตกต่างระหว่าง client และ server type
  • การเสียเวลาซ้ำซ้อนในการพิมพ์ข้อมูลแต่ละ client แบบแมนวล

แนวทางการทำงานที่เน้นดีไซน์เป็นหลัก

โซลูชันแบบดั้งเดิมที่ใช้แก้ปัญหาดังกล่าวก็คือแนวทางการทำงานแบบ “เน้นดีไซน์เป็นหลัก” ซึ่งคุณต้องออกแบบและจัดทำเอกสารคู่มือของ API ขึ้นมาก่อนด้วยการเขียนและแบ่งประเภทของเอกสาร จากนั้นจึงนำเอกสารดังกล่าวไป implement กับ server และ client

เครื่องมือที่มักนำมาใช้กันคือเครื่องมือของ OpenAPI อย่าง Swagger ที่ช่วยให้คุณเขียนเอกสารคู่มือ API และรายละเอียดดีไซน์ของ API ในไฟล์ YAML

จากนั้นคุณก็จะมีเว็บไซต์ที่คุณสามารถแชร์เอกสารคู่มือนี้แล้วส่งให้กับทีมงานได้

ช่วยให้ทีมงานของคุณสามารถนำคู่มือไปใช้ implement กับ client และ server ได้ ดังนั้น เราจึงสามารถแก้ pain point แรกเกี่ยวกับเรื่องการสื่อสารที่ไม่มีประสิทธิภาพระหว่างทีมงานด้วยกันได้

Manual Types

 

อย่างไรก็ตาม บั๊กก็ยังคงอยู่และไม่มี type ดังนั้น คุณจึงต้องเขียน manual types ขึ้นมาโดยอ้างอิงจากคู่มือที่คุณสร้างขึ้นก่อนหน้านี้

เหตุผลที่คุณจำเป็นต้องทำแบบนี้ก็เพื่อให้การ deploy เป็นไปอย่างราบรื่น รวมถึงได้รับ cookie request, cookie response, และอื่นๆ

Typed Client นั้นปกติแล้วจะเป็นแผนที่ช่วยให้ฟังก์ชันของ cookie ทำงานได้ปกติ รวมถึง request และ response ด้วย จากนั้นคุณก็จะสามารถ fetch ข้อมูลบางอย่างมาจาก API ของ cookie คุณได้

การทำแบบนี้ช่วยให้คุณแก้ไขปัญหาที่สอง ในเรื่องของบั๊กและประสบการณ์ที่ไม่ดีของนักพัฒนาที่เกิดจากการขาดแคลน type ที่จำเป็นได้

การทำให้ types นั้นสอดคล้องกันอยู่เสมอ

อย่างไรก็ตาม สิ่งหนึ่งที่คุณควรพิจารณาก็คือการทำให้ types ของ server และ สอดคล้องกัน นี่คือไอเดียบางอย่างที่วิทยากรท่านที่สองของเรา คุณ Denis ฝากไว้ให้

  • expose types ผ่านทางแพ็กเกจ npm
  • ใช้ monorepo
  • generate types จาก OpenAPI

เวิร์กโฟลว์

ตรวจสอบการใช้แนวทางแรก

สำหรับเวิร์กโฟลว์ สิ่งแรกก็คือการตรวจสอบว่าแนวทางแรกนั้นเหมาะสมหรือไม่ ด้วยขั้นตอนต่อไปนี้

  1. เขียนรายละเอียดของ OpenAPI
  2. generate types, clients, และ server
  3. ใช้ types เพื่อนำไป implement server

แนวทางเน้นโค้ดเป็นหลัก

อีกตัวเลือกคือการเขียนโค้ดขึ้นมาหรือรัน server ด้วยขั้นตอนเหล่านี้

  1. implement หรือ stub server
  2. generate รายละเอียดของ OpenAPI
  3. generate client จาก OpenAPI

สิ่งเหล่านี้จะทำให้คุณสามารถแก้ไข pain point ที่เหลืออยู่ได้ ซึ่งก็คือความแตกต่างระหว่าง client และ server types และการเสียเวลาซ้ำซ้อนในการพิมพ์ข้อมูลแต่ละ client แบบแมนวล

GraphQL

GraphQL เป็น query language และ server-side runtime สำหรับ API โดยเป้าหมายสำคัญของมันคือการทำให้ client มีแค่ข้อมูลที่ต้องการใช้งาน และไม่มีอะไรมากไปกว่านั้น

gRPC

gRPC คือ RPC (Remote Procedure Call) framework ที่เชื่อถือได้ นำไปใช้เพื่อสร้าง API ที่มีความคล่องตัวและปรับขนาดได้ มันช่วยให้การพัฒนาระบบเน็ตเวิร์กที่มีการสื่อสารระหว่างแอปพลิเคชันและ client นั้นมีความโปร่งใส ตรวจสอบได้มากขึ้น

tRPC

tRPC เป็นไลบรารีขนาดเล็กที่ช่วยให้คุณพัฒนา typesafe API ได้อย่างเต็มรูปแบบ โดยไม่ต้องใช้ schema หรือ code generation

ทำให้เกิดการแชร์ type ระหว่าง server และ client และจะ import type เท่านั้น ไม่ใช่โค้ดจริงๆ จาก server ดังนั้นจึงไม่สามารถเข้าถึง frontend ของโค้ดจาก server ได้

คุณจึงสามารถตรวจจับปัญหาระหว่าง frontend และ backend ได้ในตอน compile และ build ด้วย type safety แบบครบวงจร

Zodios

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 ที่กระจัดกระจาย ปัจจุบันนี้โลกของนักพัฒนามีความสะดวกสบายมากขึ้น มีเฟรมเวิร์กและเครื่องมือมากมายให้ใช้ในการสร้างโปรเจกต์ ทำให้งานมีคุณภาพมากขึ้น, พึ่งพาตัวเองได้, เข้าถึงง่ายขึ้น, และนักพัฒนาได้รับประสบการณ์ที่ดียิ่งขึ้น