← Blog

ค่าหนึ่งค่ามี 4 หน้าที่ — มาตรฐานการแทนค่า เก็บ · ส่ง · คำนวณ · แสดง

ตอนที่เราไล่แก้เรื่องวันที่ทั้งระบบ เราพบว่ากำลังแก้อาการ ไม่ใช่โรค

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

โรคที่แท้จริง

ค่าหนึ่งค่าในระบบไม่ได้ทำหน้าที่เดียว แต่ทำ 4 หน้าที่ ที่ต้องการรูปแบบต่างกัน

หน้าที่ คืออะไร กฎ
① เก็บ รูปแบบจริงในฐานข้อมูล ตายตัว · ไม่กำกวม · เรียงได้ · หนึ่งความหมายหนึ่งรูปแบบ
② ส่ง รูปแบบตอนวิ่งข้ามระบบ รูปแบบเครื่องอ่าน ไม่ใช่ภาษาคน
③ คำนวณ / ตรวจ สูตร ปัดเศษ ตรวจความถูกต้อง ที่เดียวเท่านั้น
④ แสดง รูปแบบให้มนุษย์อ่าน ที่ขอบเท่านั้น · ตามค่าตั้งของลูกค้าแต่ละราย

ความกำกวมและบั๊กเกิดขึ้นเมื่อรูปแบบของหน้าที่หนึ่งรั่วไปอีกหน้าที่

ตัวอย่างที่เห็นภาพที่สุด — เก็บค่าที่จัดรูปแบบไว้แล้วลงฐานข้อมูล เช่นเก็บ “1,234.50” เป็นข้อความแทนที่จะเก็บตัวเลข ผลคือบวกไม่ได้ เรียงไม่ได้ และเปลี่ยนรูปแบบการแสดงทีหลังไม่ได้

ประโยคที่เป็นเส้นแบ่ง

หลังบ้าน (เก็บ · ส่ง · คำนวณ) = ตายตัวแบบเดียว
หน้าบ้าน (แสดง) = ลูกค้าตั้งค่าได้ เป็นเครื่องสำอางที่ขอบ ห้ามไหลย้อนกลับ

วิธีทดสอบว่าทำถูกหรือยังง่ายมาก — เปลี่ยนค่าตั้งการแสดงผล แล้วตัวเลขในฐานข้อมูลต้องไม่ขยับแม้แต่นิดเดียว

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

กับดักที่อันตรายที่สุด — ปัดเพื่อแสดง ไม่เท่ากับ ปัดเพื่อเก็บ

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

กรณีที่ 1 — ทศนิยมที่ลูกค้าเลือกได้

ลูกค้าเลือกได้ว่าอยากเห็นราคาต่อหน่วยกี่ตำแหน่ง สองตำแหน่งหรือสามตำแหน่ง

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

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

กรณีที่ 2 — ยอดที่ต้องจ่ายจริง

ยอดที่ลูกค้าต้องจ่าย ยอดที่ลงบัญชี และยอดบนใบกำกับภาษี เป็นคนละเรื่องโดยสิ้นเชิง

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

สรุปเป็นประโยคเดียวที่เราใช้ตัดสินทุกครั้ง

ลูกค้าเลือกได้ว่าเห็นกี่ตำแหน่ง แต่เลือกไม่ได้ว่าต้องจ่ายเท่าไร

สองอย่างนี้ดูคล้ายกันมากบนหน้าจอ แต่อยู่คนละชั้นและปฏิบัติต่างกันสิ้นเชิง

ค่าทั้ง 7 ตระกูลที่เราวางมาตรฐานไว้

เราเริ่มจากวันที่เพราะมันพังชัดที่สุด แล้วใช้มันเป็นแม่แบบให้ตัวอื่นตามมา

1. วันที่และเวลา

เก็บเป็นชนิดข้อมูลวันที่จริงหรือเวลามาตรฐานสากล · แสดงตามที่ลูกค้าตั้ง (พ.ศ. หรือ ค.ศ. รูปแบบ และเขตเวลา)

กฎที่สำคัญที่สุดของตระกูลนี้คือแยก “วันที่เชิงธุรกิจ” ออกจาก “เวลาที่เกิดขึ้น” — อย่างแรกห้ามแปลงเขตเวลา อย่างหลังต้องแปลง

2. จำนวนเงิน

เก็บเป็นชนิดทศนิยมที่แม่นยำ ความละเอียด 4 ตำแหน่ง · แสดง 2 ตำแหน่ง มีคั่นหลักพัน มีสัญลักษณ์สกุลเงิน และแสดงค่าติดลบในวงเล็บตามธรรมเนียมบัญชี

ห้ามใช้ทศนิยมลอยเก็บเงินเด็ดขาด — เราเจอมาแล้วในข้อมูลเงินเดือนและภาษีหัก ณ ที่จ่ายที่เก็บเป็นทศนิยมลอย ทำให้ยอดสุทธิเพี้ยนได้

2b. ชื่อฟิลด์เงินต้องบอกว่าใครจ่าย

มาตรฐานนี้แปลกกว่าตัวอื่นเพราะไม่ได้เกี่ยวกับรูปแบบข้อมูล แต่เกี่ยวกับชื่อ

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

ซึ่งเป็นคำถามที่ตอบผิดแล้วบัญชีผิดทันที

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

3. รหัสและธงแบบเก่า

ระบบเดิมที่เรารับช่วงมาเก็บ “ชนิด สถานะ ธง” เป็นตัวอักษรเดียว

กฎของเราคือ รหัสดิบคือความจริงในฐานข้อมูล ห้ามแปลง ส่วนคำแปลภาษาไทย ไอคอน และสี ให้แปลที่ทะเบียนกลางที่เดียวตอนแสดงผล

ถ้าปล่อยให้แต่ละหน้าจอแปลเอง สุดท้ายสถานะเดียวกันจะถูกเรียกคนละชื่อในคนละหน้า ซึ่งเราเคยเจอมาแล้ว

4. ข้อความภาษาไทย

สามข้อที่ต้องแยกให้ชัด

  • ข้อความไทยเป็นยูนิโคดทุกชั้น ทั้งในฐานข้อมูลและตอนส่ง
  • ชื่อไฟล์บนดิสก์เป็นอักขระอังกฤษล้วน ส่วนชื่อไทยเก็บแยกในฐานข้อมูล — บทเรียนนี้มาจากอีกผลิตภัณฑ์ที่เจอปัญหาชื่อโฟลเดอร์ภาษาไทยจนไฟล์วิดีโอหาย
  • ข้อความเก่าที่เพี้ยนจากการเข้ารหัสคนละแบบ ให้ซ่อมที่เดียวตอนอ่าน ไม่ใช่ไล่ซ่อมทีละหน้า

5. ตัวเลขที่ไม่ใช่เงิน

จำนวน เปอร์เซ็นต์ ตัวคูณ อัตราแลกเปลี่ยน และหน่วยนับ

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

เราตัดสินว่าเก็บเป็นจำนวนเปอร์เซ็นต์ คือ 7 แล้วเขียนไว้ในเอกสารกลาง

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

6. ที่อยู่

เก็บแยกเป็นบรรทัดและรหัสไปรษณีย์ · แสดงเป็นบรรทัดเดียวด้วยลำดับมาตรฐานผ่านตัวประกอบกลาง

เราทำเป็นสองเฟสอย่างตั้งใจ — เฟสแรกใช้โครงง่าย ๆ ที่มีอยู่ เฟสสองค่อยแยกเป็นตำบล อำเภอ จังหวัด ตามมาตรฐานเอกสารภาษี เพราะการแยกโครงต้องย้ายข้อมูลเดิมทั้งหมดซึ่งเป็นงานคนละขนาด

7. รหัสอ้างอิง

เลขประจำตัวผู้เสียภาษี เลขที่เอกสาร รหัสลูกค้าและสินค้า

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

ข้อสุดท้ายสำคัญเพราะเลขผู้เสียภาษีที่มีขีดคั่นสวยงามในฐานข้อมูลคือเลขที่ค้นไม่เจอ

เหตุผลที่ต้องมี “ที่เดียว” สำหรับการคำนวณ

ชั้นคำนวณเป็นชั้นที่คนมักมองข้าม แต่เป็นชั้นที่ผิดแล้วเสียหายเป็นเงิน

ถ้าปล่อยให้แต่ละหน้าคำนวณส่วนลดหรือภาษีเอง ผลคือจะมีสูตรหลายชุดที่เกือบเหมือนกัน ต่างกันที่ลำดับการปัดเศษ แล้วยอดจะต่างกันไม่กี่สตางค์

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

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

บังคับใช้อย่างไรไม่ให้กลับไปเป็นเหมือนเดิม

มาตรฐานที่อยู่แต่ในเอกสารจะถูกลืมภายในไม่กี่เดือน เราจึงใช้สามอย่างประกอบกัน

  1. ชุดเครื่องมือกลางที่ใช้ง่ายกว่าการทำเอง — ถ้าเรียกใช้ตัวกลางง่ายกว่าเขียนเอง คนจะเลือกทางที่ง่าย
  2. ด่านตรวจอัตโนมัติ — เช่นด่านที่ไม่ยอมให้จัดรูปแบบวันเวลาดิบ ๆ ในหน้าจอ ทักท้วงตั้งแต่ก่อนโค้ดถูกรวมเข้าระบบ
  3. เอกสารที่บอกเหตุผล ไม่ใช่แค่บอกกฎ — กฎที่ไม่มีเหตุผลกำกับจะถูกยกเลิกโดยคนถัดไปเสมอ

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

ทำไมเรื่องนี้ถึงสำคัญกับลูกค้า

เรื่องทั้งหมดในบทความนี้เป็นเรื่องภายในที่ลูกค้าไม่เห็น แต่ผลของมันลูกค้าเห็นทุกวัน

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

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

เราเลือกลงแรงกับเรื่องนี้ตั้งแต่ยังแก้ได้ง่าย เพราะรู้ว่ามันแก้ยากขึ้นทุกเดือนที่ปล่อยไว้

Freeable

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

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

อ่านต่อ

Freeable

เวลาในระบบมีหลายชั้น และมันไม่ตรงกัน — บทเรียนจากบั๊กที่ไล่ 8 วันแล้วสรุปผิดหลายรอบ

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

Freeable

ระบบเฝ้าระวังข้อผิดพลาดที่ใช้งานได้จริง — บทเรียนจากข้อความที่หายวันละ 113 ฉบับ

ติดตั้งระบบเฝ้าระวังแล้วไม่ได้แปลว่าจะเจอปัญหา บทความนี้เล่าเคสที่ error หนึ่งกินไป 88% ของทั้งหมดแต่ไล่ไม่เจอ 9 วันเพราะชื่อของมันเดาสาเหตุผิด และเล่าว่าเราจัดการเสียงรบกวนอย่างไร

Freeable

ตั้งรหัส error อย่างไรให้ใช้งานได้จริง — รหัสสองประเภทที่ทำงานคู่กัน

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