591 คำ
3 นาที
IT Foundation EP.07 — Performance & Testing
สารบัญ

Series: IT Foundation — พื้นฐาน IT สำหรับยุค AI (ภาษาคน)

  1. EP.01 — รากฐานคอมพิวเตอร์
  2. EP.02 — พื้นฐาน Computer Science
  3. EP.03 — ซอฟต์แวร์ทำงานยังไง
  4. EP.04 — Architectures
  5. EP.05 — Web Technologies
  6. EP.06 — Security พื้นฐาน
  7. EP.07 — Performance & Testing ← คุณอยู่ตรงนี้
  8. EP.08 — Dev/Deploy/Ops
  9. EP.09 — Security ขั้นสูง
  10. EP.10 — Project Management

ผมชอบเปรียบเทียบแอปกับร้านอาหารครับ หกตอนที่ผ่านมาเราแต่งหน้าร้านสวย จัดครัวให้ดี ติดกล้องวงจรปิดกันโจร เรียบร้อยหมดแล้ว แต่ยังมีปัญหาอีกสองอย่างที่จะทำให้ลูกค้าหนีไม่กลับมา คือ “รออาหารนานเกิน” กับ “กินแล้วท้องเสีย” สองเรื่องนี้ดูเหมือนเรื่องเดียวกัน แต่จริงๆ เป็นคนละศาสตร์ เรื่องแรกคือ Performance เรื่องที่สองคือ Testing และทั้งสองต้องดูแลคู่กัน เพราะเร็วอย่างเดียวแต่พังตลอดก็ไม่มีใครใช้ ดีแต่ช้าก็ไม่มีใครรอครับ

Optimization — ทำยังไงให้แอปเร็วและประหยัด#

ก่อนจะเข้าเรื่องเทคนิค อยากให้จำตัวเลขนี้ไว้ก่อนครับ: เว็บที่โหลดช้าลง 0.1 วินาที ยอดขายอาจหายไปประมาณ 1% Amazon, Google, Walmart เคยพิสูจน์เรื่องนี้มาแล้วหลายรอบ ดังนั้นการรีดความเร็วไม่ใช่เรื่องเล่นๆ ของวิศวกร แต่คือเรื่องเงินตรงๆ

วิธีที่ “ถูกที่สุด” ในการทำให้แอปเร็วขึ้นเรียกว่า Caching แปลไทยง่ายๆ คือ “การจำ” ลองนึกถึงนักเรียนในห้องเรียน ถ้าครูถามคำถามเดิมทุกวัน แล้วนักเรียนต้องเปิดหนังสือหาคำตอบใหม่ทุกครั้ง มันช้ามาก แต่ถ้านักเรียนท่องจำได้แล้ว ตอบได้ทันที นี่แหละคือ Cache คอมพิวเตอร์ก็ทำแบบเดียวกัน เมื่อมีคนเข้าเว็บครั้งแรก ระบบจะดึงข้อมูลจากฐานข้อมูล ประกอบเป็นหน้าเว็บ ส่งให้ดู แล้วก็ “จำ” หน้าที่ประกอบเสร็จแล้วเอาไว้ พอมีคนที่สองเข้ามาก็ส่งของที่จำไว้ได้เลย ไม่ต้องประกอบใหม่ Cache มีหลายชั้น ตั้งแต่ Browser Cache (เบราว์เซอร์ของลูกค้าจำเอง), Server Cache (เซิร์ฟเวอร์เราจำ) ไปจนถึง Distributed Cache อย่าง Redis ที่เป็นเหมือนตู้ความจำส่วนกลางให้หลายเซิร์ฟเวอร์ใช้ร่วมกัน ทุก Cache จะมีค่า TTL (Time To Live) บอกว่าจำข้อมูลนี้ไว้นานแค่ไหนก่อนจะไปถามของใหม่

ต่อมาคือ Asset Optimization หรือการ “ลดน้ำหนัก” ของเว็บครับ สาเหตุอันดับหนึ่งที่ทำให้เว็บช้าคือรูปภาพ ลองคิดดูว่ารูปที่ถ่ายจากกล้องมือถือใบเดียวอาจหนัก 5MB พอโพสต์หลายๆ รูปในหน้าเดียวก็เป็นร้อยเมกะ ลูกค้าที่ใช้เน็ต 3G รออีกสิบวินาทีก็หนีไปเว็บคู่แข่งแล้ว เทคนิคที่นักพัฒนาใช้คือ Minification (บีบอัดโค้ดให้เล็กที่สุด ลบช่องว่างและคอมเมนต์ที่ไม่จำเป็น), Compression แบบ Gzip หรือ Brotli (บีบไฟล์ระหว่างส่งผ่านเน็ต), Lazy Loading (โหลดเฉพาะรูปที่อยู่ในหน้าจอตอนนี้ รูปข้างล่างรอจนลูกค้าเลื่อนลงถึงค่อยโหลด) และการใช้ฟอร์แมตรูปภาพสมัยใหม่อย่าง WebP ที่คุณภาพเท่าเดิมแต่ไฟล์เล็กกว่า JPEG ประมาณ 30% เปรียบเทียบง่ายๆ คือการส่งเฟอร์นิเจอร์แบบ IKEA Flat Pack ถอดชิ้นส่วนใส่กล่องแบนๆ ส่งไปประกอบที่ปลายทาง แทนที่จะขนโซฟาทั้งตัวไป

เมื่อลูกค้าเยอะขึ้นเรื่อยๆ เซิร์ฟเวอร์ตัวเดียวเอาไม่อยู่ ก็ต้องมี Load Balancing คือการกระจายงานไปยังเซิร์ฟเวอร์หลายเครื่อง ลองนึกภาพพนักงานต้อนรับหน้าร้านอาหารที่คอยมองว่าโต๊ะไหนว่าง แล้วพาลูกค้าไปนั่งโต๊ะนั้น แทนที่จะปล่อยให้อัดกันอยู่โต๊ะเดียว Load Balancer ทำงานแบบนี้เลยครับ มันจะตรวจสุขภาพเซิร์ฟเวอร์แต่ละตัว (Health Checks) แล้วใช้กฎอย่าง Round-Robin (ส่งเวียนไปทีละเครื่อง) หรือ Least Connections (ส่งไปเครื่องที่ว่างที่สุด) เพื่อกระจายโหลด ถ้าเครื่องไหนพัง ก็ตัดออกจากการใช้งานทันที ลูกค้าไม่รู้ตัวด้วยซ้ำ

แล้วถ้าลูกค้าอยู่คนละทวีปล่ะ? ต่อให้เซิร์ฟเวอร์เราเร็วแค่ไหน ข้อมูลก็ต้องวิ่งข้ามมหาสมุทรอยู่ดี ทางแก้คือ CDN (Content Delivery Network) หรือเครือข่ายกระจายคอนเทนต์ แนวคิดคือมีโกดังสำเนาเว็บของเราวางกระจายอยู่ทั่วโลก ลูกค้าที่กรุงเทพก็ดึงจากโหนดในกรุงเทพ ลูกค้าที่นิวยอร์กก็ดึงจากโหนดที่อเมริกา เปรียบเหมือนแทนที่จะต้องขับรถไปโรงงานที่กรุงเทพ ก็เดินไปร้านสะดวกซื้อสาขาใกล้บ้านได้ใน 5 นาที ผู้ให้บริการยอดนิยมก็มี Cloudflare, CloudFront ของ AWS พวกนี้ราคาไม่แพงมากแต่ช่วยเพิ่มความเร็วได้ชัดเจน

ส่วนที่คนมองข้ามบ่อยคือ Database Tuning ครับ ฐานข้อมูลคือคอขวดที่ซ่อนอยู่ของแอปส่วนใหญ่ ลองนึกถึงห้องสมุดที่ไม่มีบัตรรายการ ถ้าอยากหาหนังสือเล่มหนึ่งต้องเดินไล่ดูทีละชั้นทีละเล่ม ศัพท์เทคนิคเรียกว่า Full Table Scan ช้ามาก วิธีแก้คือการทำ Index ซึ่งก็คือบัตรรายการนั่นเอง บอกว่าคำค้นอะไรอยู่ที่ไหน ดึงข้อมูลจากล้านรายการได้ในเสี้ยววินาที นอกจาก Index แล้วยังมีเรื่อง Joins Optimization (รวมตารางข้อมูลหลายตารางให้ฉลาด) และ Pagination (ไม่ดึงข้อมูลทีละล้านรายการ แต่แบ่งเป็นหน้าละ 20-50 รายการ) สิ่งที่ควรให้ทีมทำสม่ำเสมอคือการดู Explain Plan ของคำสั่งช้าๆ เพื่อดูว่าฐานข้อมูลวิ่งเส้นทางไหน แล้วปรับให้มันวิ่งเส้นที่สั้นกว่า

สุดท้ายของส่วนนี้คือ Web Vitals ที่ Google ใช้เป็นคะแนนวัดความเร็วจริงจากมุมลูกค้า ตัวสำคัญคือ LCP (Largest Contentful Paint วัดว่าเนื้อหาหลักของหน้าปรากฏใน 2.5 วินาทีแรกหรือไม่), FID (ตอบสนองเร็วแค่ไหนเมื่อลูกค้าคลิก) และ CLS (หน้าเว็บขยับไปมาทำให้กดผิดตำแหน่งไหม) คะแนนพวกนี้ส่งผลต่อ SEO โดยตรง เว็บที่ Web Vitals ดีกว่าจะได้อันดับสูงกว่าในผลค้นหา

Testing — กันไว้ดีกว่าแก้#

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

Unit Testing คือการตรวจชิ้นส่วนเล็กๆ ทีละชิ้น เหมือนโรงงานผลิตรถที่ตรวจน็อตและเกลียวว่าได้มาตรฐานไหมก่อนนำไปประกอบ ในโลกโค้ด Unit Test จะทดสอบฟังก์ชันเล็กๆ เช่น ฟังก์ชันคำนวณภาษีมูลค่าเพิ่มรับอินพุตเป็นราคาก่อนภาษี ต้องได้เอาต์พุตเป็นราคาหลังบวก 7% ถ้าเปลี่ยนกฎหมายหรือมีคนเผลอแก้โค้ดผิด การทดสอบนี้จะแจ้งเตือนทันที เครื่องมือยอดนิยมคือ Jest กับ Mocha ในฝั่ง JavaScript ศัพท์ที่ได้ยินบ่อยคือ Mocks (การจำลองสิ่งที่ยังไม่มีจริง เช่น จำลองว่าฐานข้อมูลส่งคำตอบแบบนี้) และ Code Coverage (โค้ดของเราถูกทดสอบไปกี่เปอร์เซ็นต์)

Integration Testing คือขั้นต่อมา ทดสอบว่าเมื่อเอาชิ้นส่วนหลายชิ้นมาประกอบกันแล้วยังทำงานเข้ากันได้ไหม เปรียบเหมือนการเอาเครื่องยนต์ไปใส่ในตัวถัง แล้วลองสตาร์ทดูว่าติดไหม ในทางเทคนิคคือการทดสอบว่า API ของเราคุยกับฐานข้อมูลได้ถูกต้อง หรือระบบส่งอีเมลคุยกับผู้ให้บริการ SMTP ได้จริงไหม มี Contract Testing ที่ใช้เช็คว่า API ทั้งสองฝั่ง (คนเรียกและคนตอบ) ยังเข้าใจกันตามสัญญาที่ตกลงไว้หรือเปล่า

End-to-End Testing (E2E) คือการจำลองลูกค้าจริง เปิดเว็บ คลิกปุ่มสมัครสมาชิก กรอกฟอร์ม จ่ายเงิน ไปจนถึงได้อีเมลยืนยัน ทั้งหมดทำโดยโปรแกรมอัตโนมัติครับ เปรียบเหมือน Mystery Shopper ที่จ้างมาลองใช้บริการร้านจริงๆ ดูว่าทุกขั้นตอนราบรื่นไหม เครื่องมือยอดนิยมคือ Cypress กับ Selenium ข้อดีคือมั่นใจว่าระบบทั้งระบบใช้งานได้จริง ข้อเสียคือช้ากว่า Unit Test มาก และบำรุงรักษายาก

ถามว่าต้องทำทั้งหมดไหม? คำตอบคือใช่ แต่สัดส่วนต่างกัน ทฤษฎี Test Pyramid บอกว่าควรมี Unit Test เยอะที่สุด (ฐานพีระมิด) มี Integration Test พอประมาณ และ E2E Test น้อยที่สุด (ยอดพีระมิด) เพราะ Unit Test เขียนง่าย รันเร็ว จับบั๊กได้ตั้งแต่ต้น ส่วน Coverage Metrics จะช่วยบอกว่าโค้ดเราถูกทดสอบครอบคลุมแค่ไหน Line Coverage บอกว่ารันโค้ดกี่บรรทัด Branch Coverage บอกว่าครอบคลุมทุกเงื่อนไข if-else ไหม ทีมส่วนใหญ่จะตั้ง Thresholds ไว้ที่ 70-80% เป็นขั้นต่ำ ถ้าต่ำกว่านั้นระบบ CI จะไม่ให้เอาโค้ดขึ้น Production

Testing เป็นประกันครับ ทีมที่เขียน Test ดีๆ จะประหยัดเวลาแก้บั๊กในอนาคตมหาศาล บั๊กที่เจอตอนเขียนโค้ดแก้ใช้ 1 ชั่วโมง บั๊กที่เจอตอนเทสต์ใช้ 1 วัน แต่บั๊กที่เจอตอนขึ้น Production แล้วลูกค้าใช้งานจริง อาจใช้เวลา 1 สัปดาห์ ยังไม่นับชื่อเสียงที่เสียไป

Scalability — รองรับคนล้านคนทำยังไง#

เวลาธุรกิจโต คำถามที่ตามมาทันทีคือ “ระบบเรารับไหวไหมถ้าลูกค้าเพิ่มสิบเท่า ร้อยเท่า” นี่คือเรื่องของ Scalability ซึ่งมีสองทางเลือกหลัก

Vertical Scaling หรือ Scale Up คือการอัปเกรดเซิร์ฟเวอร์ตัวเดิมให้แรงขึ้น เพิ่ม CPU เพิ่ม RAM ใส่ SSD ที่เร็วกว่า เปรียบเหมือนการซื้อรถ Ferrari ให้ขับเร็วขึ้น ข้อดีคือทำง่าย ไม่ต้องแก้โค้ด ข้อเสียคือมีเพดาน เซิร์ฟเวอร์แรงสุดในโลกก็ยังรับโหลดจำกัด แถมราคาเพิ่มแบบไม่เชิงเส้น จากเครื่อง 100k ไป 200k อาจจะแรงขึ้นไม่ถึง 2 เท่า ที่สำคัญคือตอนอัปเกรดมักจะต้อง Downtime ซึ่งยอมรับไม่ได้ในธุรกิจใหญ่

Horizontal Scaling หรือ Scale Out คือการเพิ่มเซิร์ฟเวอร์เป็นหลายๆ ตัวทำงานพร้อมกัน เปรียบเหมือนแทนที่จะจ้าง Ferrari คันเดียว ก็จ้างมอเตอร์ไซค์วิน 100 คันช่วยกันส่งของ ข้อดีคือขยายได้แทบไม่จำกัด ต้องการโหลดเพิ่มก็เพิ่มเครื่องอีก แถมถ้าเครื่องหนึ่งพัง เครื่องอื่นยังวิ่งได้ ไม่ล่มทั้งระบบ ข้อเสียคือโค้ดต้องออกแบบให้รองรับ โดยเฉพาะต้องเป็นแบบ Stateless คือไม่เก็บสถานะไว้ในเครื่องตัวเอง (เพราะคำขอถัดไปอาจไปลงเครื่องอื่น) ข้อมูลต้องเก็บในฐานข้อมูลกลางหรือ Cache กลาง บริการคลาวด์สมัยใหม่มี Auto-Scaling Groups ที่เพิ่ม-ลดเครื่องอัตโนมัติตามโหลด ช่วงกลางวันคนเยอะก็มี 20 เครื่อง กลางคืนเหลือ 3 เครื่อง ประหยัดค่าเซิร์ฟเวอร์ได้เยอะ

Load Balancing ที่พูดถึงไปแล้วเป็นเพื่อนคู่กายของ Horizontal Scaling ครับ เพราะพอมีหลายเครื่อง ต้องมีคนคอยควบคุมจราจรให้ส่งคำขอไปกระจายตัวเท่าๆ กัน เรื่อง Sticky Sessions ก็มาตรงนี้ บางแอปต้องการให้ลูกค้าคนเดียวกันไปที่เครื่องเดิมตลอด (เช่น ระบบที่เก็บตะกร้าสินค้าไว้ใน Memory ของเครื่องนั้น) Load Balancer จะจำและส่งกลับเครื่องเดิมให้

สุดท้ายคือ Sharding หรือการแบ่งเค้กข้อมูล สำหรับธุรกิจที่ข้อมูลใหญ่มากจนเครื่องเดียวเก็บไม่ไหว ก็ต้องแบ่งข้อมูลเป็นหลายส่วนเก็บไว้หลายเครื่อง เปรียบเหมือนตู้เอกสารที่แบ่งเป็นตู้ A-M และตู้ N-Z ลูกค้าชื่อขึ้นต้นด้วย K ก็ไปหาในตู้แรก ส่วน Y ก็ไปตู้ที่สอง กุญแจสำคัญคือ Shard Key หรือเกณฑ์ที่ใช้แบ่ง ต้องเลือกให้ข้อมูลกระจายเท่าๆ กันและไม่กระจุกอยู่ตู้เดียว เรื่องนี้ซับซ้อนและมักทำเมื่อถึงขนาดระดับ Facebook, LINE ไม่ใช่สิ่งที่ธุรกิจเล็กต้องคิดเป็นอันดับแรก

Recap — ความเร็วและคุณภาพ#

ลองมองภาพรวมเป็นพีระมิดสามชั้นนะครับ ฐานคือ Code ที่ดีและ Database ที่มี Index ชั้นกลางคือ Caching และ Asset Optimization ชั้นบนสุดคือ CDN และ Load Balancing ทุกชั้นเสริมกัน แต่ลำดับสำคัญ — อย่าพยายามเอาชั้นบนมาปิดบังปัญหาชั้นล่าง เพราะโค้ดที่ไม่ดีต่อให้ใส่ CDN ก็ยังช้าอยู่ดี

สิ่งที่ผู้นำธุรกิจต้องจำสองประโยคคือ Latency = Revenue Lost เว็บช้าลง 0.1 วินาที ยอดขายอาจหายไป 1% และ Testing is Insurance Test ที่เขียนวันนี้ประหยัดเวลาแก้บั๊กในอนาคตมหาศาล ถ้าทีมบอกว่าไม่มีเวลาเขียน Test ให้ถามกลับว่ามีเวลาตอนบั๊กขึ้น Production ตอนตีสามไหม

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

EP.08 — Dev/Deploy/Ops