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

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
- การดึงข้อมูล WebSocket แบบแสดงทุกระดับราคาทำให้แอปค้างช่วงชั่วโมงเร่งด่วน
- การใช้ Diffable Data Source ไม่ช่วยแก้ปัญหาเพราะข้อมูลส่งมาเป็นชุดใหญ่ทั้งหมด
- การคำนวณใน Computed Properties สะสมจนบล็อกเมนเทรดภายใต้โหลดสูง
- ย้ายการคำนวณไปทำที่ Background Thread ช่วยให้แอปกลับมาลื่นไหลได้
การทำงานในบริษัทเดิมสอนบทเรียนสำคัญให้ผมหลายอย่าง โดยเฉพาะความเข้าใจที่ว่าเทคโนโลยีใหม่ไม่ได้ตอบโจทย์เสมอไป และการทำงานที่ดูเหมือนใช้ทรัพยากรน้อยอาจกลายเป็นปัญหาใหญ่ได้เมื่อระบบเติบโตขึ้น เรื่องราวนี้เกิดขึ้นเมื่อผมได้รับมอบหมายให้จัดการข้อมูลราคาหุ้นเรียลไทม์ผ่านเว็บโซเก็ต ซึ่งบนกระดาษแล้วฟีเจอร์นี้ดูเหมือนจะทำได้ง่ายมาก แทนที่จะจำกัดการแสดงผลแค่ 10 ระดับราคาตามเดิม ทีมงานต้องการขยายให้แสดงผลครบทั้งหมด ซึ่งมีตัวเลขไต่ระดับตั้งแต่ 80 ไปจนถึง 137 ระดับราคาขึ้นอยู่กับหุ้นแต่ละตัว
ผลลัพธ์ที่ตามมาคือหน้าจอแสดงผลที่เคยตอบสนองได้ดีกลับเกิดอาการค้างอย่างกะทันหันในช่วงชั่วโมงการซื้อขายหนาแน่น ผู้ใช้งานไม่สามารถเลื่อนหน้าจอขึ้นลงได้ น่าเสียดายที่ปัญหานี้เกิดขึ้นเฉพาะช่วงเวลาพีคเท่านั้น ทำให้มันเล็ดลอดสายตาจากกระบวนการตรวจสอบคุณภาพหรือ QA ไปได้ ผมจึงคิดว่าเทคโนโลยีสมัยใหม่อย่าง Diffable Data Source น่าจะเข้ามาช่วยแก้ปัญหานี้ได้ โดยผมตัดสินใจนำมาใช้งานร่วมกับข้อมูลที่ผูกไว้กับ UUID แต่ปรากฏว่ามันกลับทำให้สถานการณ์แย่ลงกว่าเดิม

ภาพประกอบจากคลังภาพสต็อก ไม่ใช่ภาพจากเหตุการณ์จริง
สาเหตุหลักมาจากข้อมูลที่ส่งมาไม่ใช่ภาพรวมของการเปลี่ยนแปลงแบบทีละส่วน แต่เป็นรายการระดับราคาแบบเต็มจำนวน การทำ Diff ข้อมูลทั้งหมดในทุกครั้งจึงกลายเป็นภาระงานประมวลผลที่สูญเปล่าโดยไม่มีการอัปเดตบางส่วนมาช่วยลดทอนภาระ ในกรณีนี้การใช้งาน tableView.reloadData() กลับทำงานได้รวดเร็วกว่าด้วยซ้ำ ทำให้ผมต้องตัดสินใจเรียกใช้งานเครื่องมือโพรไฟเลอร์เพื่อค้นหาคอขวดที่แท้จริงของระบบ
ผลลัพธ์จากการตรวจสอบสร้างความประหลาดใจไม่น้อย คุณสมบัติที่ถูกคำนวณไว้ล่วงหน้าอย่าง Computed Properties เช่น การกำหนดสีสำหรับราคาขึ้นลงและการจัดรูปแบบตัวเลข กลายเป็นตัวการสำคัญที่เข้าไปอุดตันเมนเทรด การคำนวณเหล่านี้อาจดูเหมือนใช้ต้นทุนต่ำในภาวะปกติ แต่เมื่อต้องเผชิญกับแพ็กเกจข้อมูลจำนวน 30 ชุดต่อวินาที โดยแต่ละชุดขนส่งระดับราคาทั้งหมดมาด้วย ต้นทุนที่เคยต่ำจึงไม่ใช่เรื่องเล็กอีกต่อไป แม้กระทั่งการแปลภาษาหรือ Localisation ที่เรามองข้ามไปก็สามารถทำให้เมนเทรดหยุดชะงักได้เช่นกัน
"การคำนวณราคาและสีดูเหมือนเป็นเรื่องเล็ก แต่เมื่อเจอ 100 ระดับราคาคูณด้วย 30 อัปเดตต่อวินาที มันคือความตายของ UI"
นักพัฒนาซอฟต์แวร์
ในทางวิศวกรรมซอฟต์แวร์ ปรากฏการณ์ที่เรียกว่า Death by a Thousand Cuts หรือความตายจากแผลเล็กๆ มักเกิดขึ้นบ่อยกับระบบเรียลไทม์ การกระทำที่ดูไม่มีพิษภัยอย่างการเรียกใช้ฟังก์ชันจัดรูปแบบสตริงใน UI Thread จะสะสมเป็นวิกฤตเมื่อเจอความถี่สูง การแยกตรรกะทางธุรกิจออกจากชั้นการแสดงผลหรือ View Layer จึงเป็นหัวใจสำคัญที่สถาปนิกซอฟต์แวร์ต้องคำนึงถึงเสมอ
แนวทางการแก้ไขปัญหาดังกล่าวมีความชัดเจนและตรงไปตรงมา นั่นคือการยุติการคำนวณใดๆ บน Computed Properties โดยเด็ดขาด เปลี่ยนเป็นการคำนวณคุณสมบัติทั้งหมดในแบ็กกราวด์ทริดในขณะที่กำลังแปลงข้อมูลจากเว็บโซเก็ตให้กลายเป็นข้อมูลสำหรับมุมมอง ส่งผลให้ส่วนของวิวกลายเป็นเพียงตัวอ่านค่าจากข้อมูลที่เตรียมไว้เรียบร้อยแล้วเท่านั้น หลังจากการปรับเปลี่ยนนี้ แอปพลิเคชันก็สามารถประคับประคองตัวเองผ่านช่วงเวลาซื้อขายที่หนาแน่นพร้อมกับการเลื่อนหน้าจอที่ราบรื่นได้สำเร็จ ทำให้ทีมงานตระหนักรู้ได้ทันทีว่าควรเริ่มต้นตรวจสอบจุดใดก่อนเมื่อเผชิญกับปัญหาด้านประสิทธิภาพในอนาคต
ที่มา: Dev.to
พบข้อมูลผิดพลาดในบทความนี้? แจ้งปัญหาบทความนี้
ความคิดเห็น
แสดงความคิดเห็น