กดส่งแล้วเงียบ ควรกดซ้ำไหม? — สถานะที่ชัด ส่งซ้ำได้ ไม่สร้างรายการซ้ำ

กรอกข้อมูลครบแล้ว กดส่ง ปุ่มเปลี่ยนเป็นวงกลมหมุน รอสักพักก็ยังเหมือนเดิม

กดอีกครั้งดีไหม? รีเฟรชแล้วข้อมูลจะหายหรือเปล่า? หรือรายการถูกส่งไปแล้ว แต่หน้านี้ยังไม่รู้?

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

ลองใช้ระบบจองห้องประชุมเป็นตัวอย่างสมมติ ผู้ใช้ต้องการห้องหนึ่งห้องในช่วงเวลาหนึ่ง และควรรู้ว่าการจองครั้งนั้นได้ผลอย่างไร

ปุ่มหมุนอยู่ แต่ข้อมูลอาจถูกบันทึกแล้ว

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

ถ้าหน้าจอบอกว่า “จองไม่สำเร็จ กรุณาส่งใหม่” ทันที คนใช้อาจสร้างคำขออีกครั้ง ทั้งที่รายการแรกมีอยู่แล้ว

การไม่ได้รับคำตอบจึงยังสรุปไม่ได้ว่างานไม่เกิดขึ้น ฝั่งหน้าจอควรบอกตามสิ่งที่ตรวจได้ เช่น “ยังตรวจสอบผลการจองไม่ได้” แล้วให้ทางไปตรวจรายการเดิม แนวคิดเรื่องผลข้างเคียงจากการลองใหม่อธิบายไว้ใน Amazon Builders’ Library

ข้อความบนปุ่มกับพฤติกรรมของระบบต้องตกลงกันตั้งแต่ต้น จะได้ไม่ผลักภาระการตัดสินใจไปให้คนใช้ในจังหวะที่ระบบมีปัญหา

แยกให้ชัดว่ากำลังส่ง สำเร็จ หรือยังไม่รู้ผล

ฟอร์มเดียวอาจต้องสื่อสารมากกว่าคำว่า “สำเร็จ” กับ “ผิดพลาด” ลองกำหนดข้อความจากเหตุการณ์ที่เกิดขึ้นจริง:

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

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

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

ส่งซ้ำได้ ต้องจำได้ว่าเป็นคำขอเดิม

การปิดปุ่มระหว่างส่งช่วยลดการกดติดกัน แต่ยังมีการรีเฟรช เปิดหลายแท็บ และคำขอที่มาถึงพร้อมกัน ฝั่งเซิร์ฟเวอร์จึงต้องรับผิดชอบการป้องกันรายการซ้ำด้วย

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

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

สำหรับบริการภายนอก ต้องอ่านเงื่อนไขของบริการนั้นด้วย ตัวอย่างเช่น Stripe กำหนดการใช้ idempotency key ไว้เฉพาะ และตรวจว่าพารามิเตอร์ของคำขอซ้ำตรงกับครั้งแรกหรือไม่ รหัสเดิมไม่ได้ใช้แทนการตรวจสิทธิ์ และไม่ควรถูกนำไปผูกกับรายการใหม่ที่เปลี่ยนข้อมูลแล้ว

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

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

Clean Code เริ่มจากชื่อที่บอกความหมายของงาน

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

ชื่ออย่าง requestAccepted, bookingConfirmed และ resultUnknown ช่วยให้การคุยเรื่องพฤติกรรมชัดขึ้น แต่ชื่อที่ดีต้องมาพร้อมเงื่อนไขที่แยกกันจริง ไม่ใช่เปลี่ยนชื่อแล้วปล่อยให้ทุกสถานะทำงานเหมือนเดิม

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

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

ทดสอบวันที่อินเทอร์เน็ตไม่เป็นใจด้วย

ก่อนเปิดใช้ ลองเดินผ่านเหตุการณ์เหล่านี้กับทีม:

  1. กดส่งติดกันสองครั้ง — การดำเนินการเดิมต้องไม่เพิ่มเป็นสองรายการ
  2. บันทึกสำเร็จ แต่คำตอบกลับไม่ถึงหน้าจอ — ผู้ใช้ต้องตรวจพบรายการเดิม และข้อความต้องไม่รีบสรุปว่าล้มเหลว
  3. คนสองคนจองเวลาเดียวกันพร้อมกัน — ผลต้องเป็นไปตามกติกาที่ตกลงไว้ ไม่ใช่ขึ้นอยู่กับว่าใครเห็นหน้าจอก่อน
  4. แก้ห้องหรือเวลาแล้วส่งใหม่ — ระบบต้องแยกคำขอใหม่ออกจากการลองซ้ำของครั้งก่อน
  5. ไม่มีสิทธิ์จอง หรือบริการภายนอกไม่พร้อม — ปฏิเสธอย่างถูกต้อง เก็บข้อมูลที่ควรเก็บ และบอกขั้นตอนถัดไปโดยไม่เปิดเผยข้อมูลภายใน

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

เกณฑ์รับงานควรเขียนเป็นผลที่ตรวจได้ เช่น “ส่งคำขอเดิมพร้อมกันสองครั้งแล้วมีการจองเพียงรายการเดียว” ทีมจะมีจุดตรวจที่ชัดกว่าคำว่า “ระบบต้องไม่พัง”

เริ่มปรับจากแบบฟอร์มเดียว

เลือกแบบฟอร์มที่ทีมใช้บ่อย แล้วถามสามเรื่อง: กดส่งแล้วระบบบอกอะไร หากไม่ได้คำตอบจะตรวจต่อที่ไหน และส่งซ้ำแล้วเกิดอะไรขึ้น

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

อ่านต่อเรื่อง ระบบที่คนอื่นรับไปดูแลได้ หรือใช้ Checklist เตรียมโปรเจกต์ จดขั้นตอนที่อยากปรับ ก่อน คุยกับทีม INTECH

← บทความทั้งหมด

จัดทำโดย

INTECH

ทีมพัฒนาซอฟต์แวร์ INTECH

เราออกแบบและพัฒนาเว็บไซต์กับระบบงาน บทความนี้ชวนคุยเรื่องที่ควรตกลงกันก่อนเริ่มพัฒนา

รู้จักทีม INTECH