วิศวกรรม
ทำไมทุกยอดคงเหลือต้องมาจากบัญชีแยกประเภทแบบ double-entry
27 กรกฎาคม 2569 · 9 นาทีในการอ่าน · Coreza
ทุกระบบธนาคารมีตารางหนึ่งที่ตอบคำถามสำคัญที่สุดของผลิตภัณฑ์: ลูกค้าคนนี้มีเงินเท่าไร? การตัดสินใจเชิงออกแบบที่แยก core ที่เชื่อถือได้ออกจาก core ที่เปราะบางคือ ตัวเลขนั้นถูกเก็บไว้ — เป็นคอลัมน์ที่ใครสักคนอัปเดต — หรือถูกคำนวณขึ้น — จากผลรวมของบัญชีแยกประเภทแบบ append-only ฟังดูเหมือนรายละเอียดการอิมพลีเมนต์ แต่จริงๆ แล้วมันคือความแตกต่างระหว่างระบบที่พิสูจน์ยอดคงเหลือของตัวเองได้ กับระบบที่ทำได้เพียงยืนยันลอยๆ
นี่คือการตัดสินใจด้านสถาปัตยกรรมที่ส่งผลตามมามากที่สุดใน core ของฟินเทค และแทบมองไม่เห็นในการเดโม ผลิตภัณฑ์สองตัวอาจดูเหมือนกันทุกอย่างบนหน้าจอ ขณะที่ตัวหนึ่งอัปเดตคอลัมน์ยอดคงเหลือทับที่เดิม ส่วนอีกตัวคำนวณทุกยอดจากบัญชีแยกประเภทแบบ double-entry ความแตกต่างจะโผล่มาทีหลัง — ในยอดกระทบที่ไม่ตรงกัน ในทิกเก็ตซัพพอร์ตที่ไม่มีใครอธิบายได้ และในการตรวจสอบ
Double-entry หมายถึงอะไรในบริบททางวิศวกรรม
การทำบัญชีแบบ double-entry มีอายุห้าศตวรรษ แต่ในแบ็กเอนด์ธนาคาร มันไม่ใช่พิธีการทางบัญชี — มันคือ invariant ที่ฐานข้อมูลบังคับใช้ ทุกการเคลื่อนไหวของเงินคือธุรกรรมที่มีอย่างน้อยสองรายการ: บัญชีหนึ่งถูกเดบิต อีกบัญชีถูกเครดิต และรายการทั้งหมดรวมกันเป็นศูนย์ เงินไม่มีวันถูกสร้างหรือทำลายด้วยคำสั่ง UPDATE มันเพียงเคลื่อนที่ระหว่างบัญชี และการเคลื่อนที่นั้นเองคือหลักฐานบันทึก
ยอดคงเหลือของลูกค้าจึงเป็นเพียงภาพฉาย: ผลรวมของทุกรายการในบัญชีแยกประเภทที่เกี่ยวข้องกับบัญชีนั้น จะแคชไว้เพื่อประสิทธิภาพก็ได้ — แต่ต้องคำนวณใหม่ได้เสมอ และผลการคำนวณใหม่คือความจริง หากแคชกับบัญชีแยกประเภทขัดแย้งกันเมื่อใด บัญชีแยกประเภทชนะ และความขัดแย้งนั้นเองคือสัญญาณว่ามีบางอย่างต้องสอบสวน
Invariant ผลรวมเป็นศูนย์ให้คุณสมบัติที่การออกแบบแบบเก็บยอดคงเหลือไม่มีทางให้ได้: ทั้งระบบตรวจสอบได้ รวมทุกรายการของทุกบัญชี — กระเป๋าเงินลูกค้า รายได้ค่าธรรมเนียม บัญชีชำระดุลกับผู้ให้บริการ บัญชีพัก — แล้วผลรวมคือศูนย์ บั๊ก การแย่งกันเขียน หรือความล้มเหลวบางส่วนใดๆ ที่ทำเงินหาย จะทำลายสมการนี้และถูกตรวจพบได้ โดยปกติภายในวันเดียวกัน
ยอดคงเหลือที่เก็บเป็นตัวเลขคลาดเคลื่อนได้อย่างไร
โหมดความล้มเหลวของการออกแบบแบบคอลัมน์ยอดคงเหลือไม่ได้ดราม่า มันคือการคลาดเคลื่อนช้าๆ ที่เกิดจากทราฟฟิกโปรดักชันธรรมดา:
- ภาวะพร้อมกัน: การถอนสองรายการอ่านยอดเดียวกันในจังหวะเดียวกัน ผ่านการตรวจสอบทั้งคู่ เขียนทับทั้งคู่ เมื่อไม่มีบัญชีแยกประเภท ก็ไม่มีบันทึกว่ายอดที่ถูกต้องควรเป็นเท่าไร
- การลองซ้ำและความล้มเหลวบางส่วน: ผู้ให้บริการชำระเงิน timeout ฝั่งไคลเอนต์ลองซ้ำ แล้วเงินเข้าสองครั้ง — หรือระบบล่มระหว่าง "อัปเดตยอด" กับ "บันทึกธุรกรรม" ทำให้สองส่วนไม่สอดคล้องกันอย่างถาวร
- การดำเนินการด้วยมือ: วิศวกรซัพพอร์ตแก้เรื่องร้องเรียนด้วย UPDATE ตรงๆ ลูกค้าพอใจ แต่เงินที่โผล่มาไม่มีที่มา และไม่มีรายงานใดจะอธิบายมันได้ตลอดกาล
- ค่าธรรมเนียมและการปัดเศษ: ค่าธรรมเนียมที่คำนวณที่หนึ่งแต่เรียกเก็บอีกที่หนึ่ง การแปลงสกุลเงินที่ปัดเศษต่างกันคนละฝั่ง — เศษเสี้ยวของเซนต์ที่สะสมจนกลายเป็นผลต่างจริง
กฎที่บัญชีแยกประเภทบังคับใช้กับคุณ — ล้วนเป็นเรื่องดี
การยึดมั่นกับยอดคงเหลือแบบคำนวณสร้างวินัยให้ส่วนที่เหลือของ core ข้อจำกัดเหล่านี้ดูเข้มงวดในวันแรก แต่กลายเป็นเหตุผลที่ระบบยังคงถูกต้องในปีที่สาม:
- จำนวนเงินเป็นจำนวนเต็มในหน่วยย่อยที่สุด — เซนต์ ซาโตชิ wei — ไม่ใช่เลขทศนิยมลอยตัวเด็ดขาด float แบบไบนารีแทนค่า 0.10 ได้ไม่แม่นยำ บัญชีแยกประเภทที่ต้องรวมเป็นศูนย์สร้างบนตัวเลขที่บวกกันเกือบลงตัวไม่ได้
- รายการที่แก้ไขไม่ได้: รายการที่บันทึกแล้วจะไม่ถูกแก้ไขหรือลบ ความผิดพลาดถูกแก้แบบเดียวกับที่ธนาคารแก้มาตลอด — ด้วยรายการกลับรายการ (reversing entry) ที่ทิ้งทั้งข้อผิดพลาดและการแก้ไขไว้ในบันทึก
- Idempotency: ทุกการดำเนินการมีคีย์กำกับ คำขอที่ถูกลองซ้ำจึงบันทึกเพียงครั้งเดียว บัญชีแยกประเภททำให้รายการซ้ำมองเห็นได้ ส่วน idempotency ป้องกันไม่ให้เกิด
- Atomicity: การเดบิต การเครดิต และการเปลี่ยนสถานะทางธุรกิจ commit พร้อมกันหรือไม่เกิดขึ้นเลย ไม่มีเส้นทางโค้ดใดอัปเดตยอดนอกธุรกรรมของบัญชีแยกประเภท — รวมถึงการปรับยอดโดยแอดมิน ซึ่งกลายเป็นรายการปกติที่ระบุผู้กระทำได้ แทนการเขียนทับแบบเงียบๆ
การกระทบยอด: พิสูจน์กับโลกภายนอก
Invariant ภายในพิสูจน์ว่าระบบสอดคล้องกับตัวเอง การกระทบยอดพิสูจน์ว่ามันสอดคล้องกับความเป็นจริง core ของฟินเทคถือสถานะกับบุคคลภายนอก — ระบบธนาคาร ผู้ประมวลผลบัตร เครือข่ายบล็อกเชน — และแต่ละรายเก็บความจริงในเวอร์ชันของตัวเอง การกระทบยอดรายวันเปรียบเทียบใบแจ้งยอดของผู้ให้บริการทุกฉบับและทุกสถานะบนเชนกับบัญชีที่ตรงกันในบัญชีแยกประเภท และบังคับให้อธิบายทุกผลต่าง: การชำระดุลที่อยู่ระหว่างทาง ค่าธรรมเนียมผู้ให้บริการที่ยังไม่ได้บันทึก หรือความคลาดเคลื่อนจริงที่จะได้รับรายการพักและผู้รับผิดชอบภายในวันเดียวกัน
การกระทบยอดคือจุดที่สถาปัตยกรรมคุ้มค่าในตัวเอง เมื่อมีบัญชีแยกประเภทแบบ double-entry ความคลาดเคลื่อนคือการค้นหาที่มีขอบเขต: วันที่มันปรากฏ บัญชีที่มันแตะ รายการที่เกี่ยวข้อง แต่เมื่อเก็บยอดเป็นตัวเลข การสอบสวนแบบเดียวกันเริ่มจากตัวเลขที่ไม่มีประวัติ — นี่คือเหตุผลที่ผลต่างที่กระทบไม่ลงในระบบคอลัมน์ยอดคงเหลือมักถูกตัดจำหน่ายทิ้งแทนที่จะถูกคลี่คลาย
สินทรัพย์คริปโตยิ่งเพิ่มเดิมพัน ยอดบนเชนเป็นข้อมูลสาธารณะ: ใครก็เปรียบเทียบกระเป๋าเงินที่คุณควบคุมกับยอดที่คุณแสดงให้ลูกค้าเห็นได้ การทำ self-custody โดยไม่มีบัญชีแยกประเภทที่กระทบยอดกับเชนทุกวัน คือความคลาดเคลื่อนที่รอให้คนนอกบริษัทเป็นผู้ค้นพบ
ผู้ตรวจสอบและหน่วยงานกำกับดูแลถามอะไรจริงๆ
ไม่ช้าก็เร็ว ฟินเทคที่อยู่ภายใต้การกำกับดูแลจะเจอคำถามเดิมในสักรูปแบบ: จงพิสูจน์ว่ายอดคงเหลือของลูกค้าถูกต้อง คำตอบเชิงปฏิบัติคือห่วงโซ่หลักฐาน — ทุกยอดคำนวณจากบัญชีแยกประเภทแบบ append-only บัญชีแยกประเภทรวมเป็นศูนย์ กระทบยอดรายวันกับทุกสถานะภายนอก และบันทึกตรวจสอบที่แก้ไขไม่ได้และเชื่อมโยงด้วย hash chain บันทึกว่าใครเป็นผู้เริ่มการเคลื่อนไหวแต่ละครั้ง จากอุปกรณ์ใด ภายใต้การอนุมัติแบบไหน
ทีมที่สร้างบนการเก็บยอดเป็นตัวเลขตอบคำถามเหล่านี้ด้วยงานนิติวิทยาศาสตร์ — ปะติดปะต่อประวัติจากล็อกแอปพลิเคชันและไฟล์ส่งออกของผู้ให้บริการ ในเวลาที่แย่ที่สุด ภายใต้เส้นตาย ทีมที่มีบัญชีแยกประเภทตอบด้วยคิวรีเดียว การตรวจสอบไม่ได้สร้างข้อกำหนดขึ้นมา มันเพียงเผยว่าสถาปัตยกรรมทำตามข้อกำหนดนั้นมาตลอดหรือไม่
แบบทดสอบที่ควรใช้กับทุกแพลตฟอร์ม core banking
หากคุณกำลังประเมินแพลตฟอร์ม — หรือกำลังทบทวนระบบที่คุณสร้างเอง — คำถามเหล่านี้ใช้เวลาถามห้านาที และคำตอบปลอมได้ยาก:
- ตัวเลขบนหน้าจอของลูกค้ามาจากไหน? หากคำตอบคือคอลัมน์ยอดคงเหลือ ไม่ใช่ภาพฉายจากบัญชีแยกประเภท ที่เหลือทั้งหมดเป็นเพียงของประดับ
- เปลี่ยนยอดคงเหลือได้โดยไม่สร้างรายการในบัญชีแยกประเภทหรือไม่? ถามเจาะจงถึงเครื่องมือแอดมินและขั้นตอนซัพพอร์ต — นั่นคือที่ซ่อนของ UPDATE แบบเงียบ
- จำนวนเงินเป็นจำนวนเต็มในหน่วยย่อยที่สุดตลอดทั้งระบบหรือไม่ รวมถึงฝั่งคริปโต?
- ขอดูการกระทบยอดของเมื่อวาน: ทุกผู้ให้บริการ ทุกเชน ทุกผลต่างพร้อมคำอธิบาย แพลตฟอร์มที่แสดงสิ่งนี้ไม่ได้ ก็คือไม่ได้ทำ
- รายการที่บันทึกผิดถูกแก้อย่างไร? คำตอบที่ดีมีเพียงหนึ่งเดียว: รายการกลับรายการ ระบุตัวผู้ทำ อยู่หลังขั้นตอนการอนุมัติ
จุดยืนของ Coreza
Coreza สร้างบนเวอร์ชันเข้มงวดของการออกแบบนี้: ทุกยอดคงเหลือ — ทั้งเฟียตและคริปโต — คำนวณจากบัญชีแยกประเภทแบบ double-entry จำนวนเงินเป็นจำนวนเต็มในหน่วยย่อยที่สุดทั่วทั้งระบบ รายการที่บันทึกแล้วแก้ไขไม่ได้ โดยการแก้ไขทำผ่านรายการกลับรายการภายใต้การอนุมัติแบบ maker-checker และทุกอินสแตนซ์กระทบยอดรายวันกับผู้ให้บริการทุกรายที่เชื่อมต่อและทุกเชนที่ให้บริการ บันทึกตรวจสอบเป็นแบบ append-only และเชื่อมโยงด้วย hash chain บันทึกว่าใคร เมื่อไร และจากที่ไหน ของทุกการเคลื่อนไหว
ทั้งหมดนี้มองไม่เห็นในการเดโมผลิตภัณฑ์ และนั่นคือประเด็นของบทความนี้: บัญชีแยกประเภทคือส่วนของแพลตฟอร์ม core banking ที่คุณประเมินด้วยการดูหน้าจอไม่ได้ เวอร์ชันหนึ่งของ core นี้ประมวลผลลูกค้าจริงและเงินจริงที่ฟินเทคยุโรปภายใต้การกำกับดูแลมาตั้งแต่ปี 2024 — และคำถามห้าข้อข้างต้นคือคำถามที่เราแนะนำให้คุณถามทุกแพลตฟอร์ม รวมถึงของเราด้วย
พร้อมเห็นธนาคารของคุณทำงานจริงหรือยัง?
บอกเราเกี่ยวกับโปรเจกต์ของคุณ แล้วเราจะติดต่อกลับพร้อมการสาธิตแบบสดและใบเสนอราคาเฉพาะสำหรับตลาดของคุณ
นัดหมายพูดคุย