← Blog

บั๊กที่รอด QA เสมอ — เมื่อผลการค้นหาที่ช้ากว่ามาทับผลใหม่

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

แต่โค้ดครึ่งชั่วโมงนั้นมีบั๊กที่ไม่มีทางเจอตอนทดสอบในออฟฟิศ และจะโผล่ที่หน้างานลูกค้าเท่านั้น

ปัญหาจากหน้างาน

พนักงานคีย์ข้อมูลพิมพ์เร็ว บางคนพิมพ์ชื่อลูกค้าจบก่อนที่หน้าจอจะตามทัน และร้านค้าจำนวนมากใช้อินเทอร์เน็ตที่ไม่ได้เร็วเท่าออฟฟิศพัฒนาซอฟต์แวร์

อาการที่ลูกค้าแจ้งเข้ามาคือ “ค้นแล้วผลไม่ตรงกับที่พิมพ์” — พิมพ์คำหนึ่งอยู่ แต่ตารางแสดงผลของอีกคำหนึ่ง ต้องลบทิ้งแล้วพิมพ์ใหม่ช้า ๆ ถึงจะได้ผลที่ถูก

รายงานแบบนี้ไล่หายากมาก เพราะพอทีมงานลองทำตาม ก็ได้ผลถูกต้องทุกครั้ง

ทำไมถึงเกิด

เมื่อผู้ใช้พิมพ์คำว่า “สมชาย” ระบบจะยิงคำขอไปที่เซิร์ฟเวอร์หลายครั้งตามตัวอักษรที่พิมพ์

  1. คำขอที่ 1 — ค้น “สม”
  2. คำขอที่ 2 — ค้น “สมชาย”

โดยธรรมชาติเราคาดว่าคำตอบจะกลับมาตามลำดับ แต่เครือข่ายไม่รับประกันเรื่องนี้

คำขอที่ 1 ค้นด้วยคำที่สั้นกว่า จึงได้ผลลัพธ์จำนวนมากกว่า ข้อมูลที่ต้องส่งกลับก็ใหญ่กว่า และถ้าเน็ตช้า มันอาจกลับมาหลังคำขอที่ 2

ผลคือหน้าจอวาดผลของ “สมชาย” ก่อน แล้วถูกทับด้วยผลของ “สม” — ผู้ใช้เห็นผลที่ไม่ตรงกับสิ่งที่พิมพ์อยู่ตรงหน้า

ในออฟฟิศที่เน็ตเร็ว คำตอบกลับมาเร็วกว่าที่คนจะพิมพ์ตัวถัดไปเสมอ ลำดับจึงไม่มีวันสลับ บั๊กนี้จึงรอดการทดสอบทุกครั้ง

สิ่งที่เราทำ

เราไม่ปล่อยให้แต่ละหน้าจอแก้ปัญหานี้เอง แต่ทำเป็นชั้นกลางชั้นเดียวที่ทุกช่องค้นหาในระบบเรียกใช้ร่วมกัน โดยมีการป้องกันสามชั้นซ้อนกัน

ชั้นที่ 1 — หน่วงก่อนยิง

รอให้ผู้ใช้หยุดพิมพ์ประมาณ 300 มิลลิวินาทีก่อนค่อยยิงคำขอ ทำให้การพิมพ์คำหนึ่งยิงคำขอครั้งเดียวแทนที่จะยิงตามจำนวนตัวอักษร

ชั้นนี้ลดโอกาสเกิดปัญหา แต่ไม่ได้แก้ — ถ้าผู้ใช้หยุดคิดกลางคำแล้วพิมพ์ต่อ ก็ยังมีคำขอซ้อนกันได้อยู่ดี

ชั้นที่ 2 — ยกเลิกคำขอเก่า

ก่อนยิงคำขอใหม่ทุกครั้ง เราสั่งยกเลิกคำขอเดิมที่ยังค้างอยู่ ผ่านกลไกมาตรฐานของเบราว์เซอร์

นี่คือข้อที่ถูกมองข้ามมากที่สุด เพราะโค้ดที่ไม่มีบรรทัดนี้ก็ทำงานได้ปกติดี — จนกว่าจะเจอเน็ตช้า

ชั้นที่ 3 — เลขลำดับกำกับ

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

ชั้นนี้มีไว้เผื่อกรณีที่เบราว์เซอร์หรืออุปกรณ์เครือข่ายระหว่างทางยกเลิกคำขอไม่ทันจริง ๆ ซึ่งเกิดขึ้นได้

ตัวเลือกที่เราตัดออก

ทางเลือกที่ง่ายกว่าคือให้เซิร์ฟเวอร์ส่ง JSON กลับมาแล้ววาดตารางด้วย JavaScript ฝั่งหน้าเว็บ แต่เราเลือกขอ HTML ก้อนเดิมที่เซิร์ฟเวอร์เรนเดอร์อยู่แล้วกลับมาสลับทั้งก้อนแทน

เหตุผลคือกฎการแสดงผลของระบบมีเยอะกว่าที่คิด — รูปแบบตัวเลข รูปแบบวันที่ตามการตั้งค่าของแต่ละกิจการ ป้ายสถานะ ลำดับคอลัมน์มาตรฐาน 10 คอลัมน์ ถ้าย้ายไปวาดที่ฝั่งหน้าเว็บ กฎเหล่านี้จะถูกคัดลอกไปอยู่สองที่ แล้ววันหนึ่งจะไม่ตรงกัน

อีกจุดที่จงใจออกแบบคือ สลับทั้งบล็อกผลลัพธ์ ไม่ใช่แค่ตาราง เพราะตัวนับ “พบ N รายการ” กับตัวแบ่งหน้าต้องเปลี่ยนพร้อมตารางเสมอ ไม่งั้นจะเกิดสภาพที่ตารางเหลือ 3 แถวแต่ด้านบนยังเขียนว่า “พบ 2,778 รายการ · หน้า 1/93”

วิธีที่ทำให้ลืมไม่ได้คือให้ทั้งสามอย่างอยู่ในก้อนเดียวกันแล้วสลับทีเดียว ไม่ใช่ต้องอาศัยความจำของคนเขียนว่าต้องอัปเดตทีละชิ้น

และถ้าไม่มี JavaScript

ทั้งหมดนี้เป็นชั้นเสริมที่วางทับฟอร์มค้นหาแบบธรรมดา ถ้าสคริปต์โหลดไม่สำเร็จ ผู้ใช้กด Enter แล้วหน้าเว็บโหลดใหม่พร้อมผลการค้นหาที่ถูกต้องเหมือนเดิม ไม่มีอะไรพัง

ทำไมเราถึงเล่าเรื่องนี้

เพราะมันเป็นตัวอย่างที่ดีของงานประเภทที่ลูกค้าไม่มีทางเห็นว่าเราทำ

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

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

Freeable

บริหารจัดการข้อมูลในองค์กร ครบในที่เดียว

ดูรายละเอียด →

อ่านต่อ

Freeable

บั๊กที่เกิดบ้างไม่เกิดบ้าง — เราไม่เพิ่มเวลา เราเอาเวลาออก

เทสต์ของ Freeable แดงหนึ่งครั้งแล้วเขียวตลอด — บันทึกการไล่หาสาเหตุแบบ investigate-first ที่จบลงด้วยการเอานาฬิกาออกจากเทสต์ แทนที่จะเพิ่มเวลาให้มัน

Freeable

ทำไม AI ถึงตอบคำถามธุรกิจของคุณไม่ได้ — บันได 5 ขั้นของการถามข้อมูลเป็นภาษาคน

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

Freeable

backup ที่รายงานว่าสำเร็จ 1,769 ไฟล์ แต่ป้องกันอะไรไม่ได้เลย — 3-2-1 ไม่พอแล้ว

เราเปิดงานสำรองไฟล์เอกสารภาษี มันคัดลอกครบ 1,769 ไฟล์ รายงานล้มเหลว 0 เขียวสนิท แล้วเราพบว่าปลายทางอยู่ดิสก์เดียวกับต้นฉบับ บทความนี้รวมรูปแบบ backup ที่ใช้จริงนอกจาก 3-2-1 และเล่าว่าทำไม "เขียว" ถึงเป็นสิ่งที่ต้องระวังที่สุด