ข้ามไปยังเนื้อหา
Tayakorn
· philosophy

เขียนกฎข้อเดียวกันสอง⁠ครั้ง ในงานที่ไม่รู้จักกัน

เว็บส่วนตัวกับท่อข้อมูลการเงินไม่มีอะไรเกี่ยวข้องกันเลย แต่ทั้งคู่ลงเอยที่กฎข้อเดียวกัน — ห้ามพิมพ์ตัวเลขลงไปตรง ๆ

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

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

ครั้งแรก เว็บเล่าเรื่องตัวเองไม่ตรงกับตัวเอง

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

แล้ววันหนึ่งบรรทัดนั้นบอกว่าสิบสองเล่ม ขณะที่ของจริงเดินไปถึงสิบสี่แล้ว

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

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

ครั้งที่สอง ตารางขยับ แต่ประโยคใต้ตารางไม่ขยับ

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

ที่มีปัญหาคือประโยควิเคราะห์ที่อยู่ข้าง ๆ ตาราง ประโยคพวกนั้นผมพิมพ์เอง เพราะมันเป็นภาษาคน ไม่ใช่ตัวเลข

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

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

สองงานนี้ไม่มีอะไรเกี่ยวกัน นั่นแหละคือประเด็น

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

แต่ทั้งคู่ลงเอยที่ข้อสรุปเดียวกันคำต่อคำ คือตัวเลขห้ามมีคนพิมพ์

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

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

แก้เรื่องเดียวกัน ไม่ได้แปลว่าต้องใช้ท่าเดียวกัน

ถึงกฎจะข้อเดียวกัน แต่สองระบบนี้บังคับมันคนละท่า และความต่างตรงนี้ผมว่าน่าสนใจกว่าความเหมือน

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

ผลคือด่านในท่อตั้งความเข้มไม่เท่ากันสองหน้าโดยเจตนา หน้าที่ผมเขียนใหม่ทั้งหน้าโดนกฎเต็ม เจอเลขพิมพ์ฝังเมื่อไหร่ท่อหยุดทันที ส่วนหน้าเก่ายังผ่อนผัน แต่ต้องรายงานจำนวนที่เจอให้เห็นทุกครั้งที่รัน

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

ด่านที่เข้มจนเจ้าของต้องปิด มีค่าเท่ากับไม่มีด่าน

ความล้มเหลวที่ไม่ส่งเสียง คือความล้มเหลวที่แพงที่สุด

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

ท่อของผมยัดค่าลงหน้าด้วยฟังก์ชันเล็ก ๆ ตัวหนึ่ง ข้างในเขียนประมาณว่า if (e) e.textContent = v แปลว่าถ้าหาช่องปลายทางไม่เจอ มันจะไม่ทำอะไรเลย ไม่มี error ไม่มีคำเตือน ไม่มีอะไรทั้งนั้น ค่าที่ควรขึ้นหน้าก็แค่หายไปเงียบ ๆ แล้วหน้านั้นก็ถูกส่งออกไปตามปกติ พร้อมช่องว่างที่ไม่มีใครสังเกต

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

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

และด่านของผมเองก็เคยตาบอดมาก่อน ตอนเขียนรอบแรกผมตัดส่วน <script> ทิ้งก่อนจะเริ่มนับ ด้วยเหตุผลที่ฟังขึ้นว่าตัวเลขในโค้ดมีเยอะและถูกต้องอยู่แล้ว ผลคือด่านมองไม่เห็นตัวเลขที่จาวาสคริปต์เขียนลงหน้า และตรงนั้นเองคือที่ที่ของผิดหนักที่สุดของรอบนั้นซ่อนอยู่ ด่านรายงานว่าสะอาด และมันก็รายงานตามที่มันเห็นจริง ๆ

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

ด่านรับประกันว่าตัวเลขมีต้นทาง ไม่ได้รับประกันว่าต้นทางถูก

ข้อจำกัดของกฎข้อนี้ชัดมาก และผมคิดว่าควรพูดให้ชัดกว่าที่มันชัดอยู่แล้ว

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

คนละคำถามกันโดยสิ้นเชิง และผมยังไม่มีคำตอบของคำถามที่สอง

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