ทำให้ชีวิตดีขึ้นด้วย Guard Clauses

Tae Keerati Jearjindarat
3 min readSep 12, 2021
https://unsplash.com/photos/mEVY5d_4BxQ

เคยเขียนโปรแกรมแล้วต้อง Validate Input หรือ Check Error กันไหมครับ ? ทุกวันนี้ทำยังไงกันอยู่ครับ แล้วกำลังใช้วิธีว่า โยน Error ที่บรรทัดสุดท้ายของ Method แล้วคนที่ต้องมาทำต่อจากเราใช้เวลาไล่ Error กัน 2–3 ชั่วโมงรึเปล่า ?

วันนี้จะมาแชร์เรื่องง่าย ๆ ที่ควรทำกัน และทำได้ทุกภาษาครับ (และขอสารภาพว่าดองไว้มานาน 55555)

ปัญหาที่พบเจอบ่อย ๆ

เอาจริงในหลายภาษา มักจะมี Compiler ตรวจสอบเบื้องต้นให้อยู่แล้วว่าโปรแกรมเราจะทำงานได้ปกติ เช่น มี Syntax ถูกต้อง หรือ Import แล้วไม่ได้ใช้ มี Variables ที่ไม่ได้ใช้ เป็นต้น

แต่ตัว Compiler จะไม่ตรวจสอบการทำงานแบบ Runtime ให้ ซึ่งเวลาเกิด Error ตอน Runtime เนี่ย นรกสุด ๆ เป็นสิ่งที่ทำให้หลาย ๆ คนเกลียด Java เพราะเรื่องนี้ ทำไมนะหรือ ? เพราะ Error ที่แดงๆ บน Console มันอ่านยากและยาวเหยียดยังไงล่ะ

Stack Trace หรือ Traceback แล้วแต่คนจะเรียก

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

Guard Clauses

Concept ง่ายมากครับ นั่นคือ Fail Fast หรือทำให้มันพังไว ๆ ให้เรารู้ข้อผิดพลาดของโปรแกรมไว ๆ ทั้งตอนที่โปรแกรมทำงานอยู่ตอน Runtime และตอนที่เรามาไล่อ่านโค้ดด้วย

Fail Fast ตอน Runtime

ใช้วิธีเขียนให้โยน Exception ออกไปก่อน โดย Exception ของเราต้องให้คนเข้าใจง่าย ทั้งคนที่เป็น User ใช้ App และ User ที่มาเรียกใช้ API ของเรา นั่นคือ Developer นั่นเอง ขอยกตัวอย่างเป็น ทำระบบ Login ด้วย Email Password แต่ใส่รหัสผิด

มุมที่ User มองเห็น

มุมที่ Developer มองเห็น

{
"response_code": "400",
"error_message": "The email and password you entered did not match our records. Please double-check and try again."
}

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

ตัวอย่างใน Java

จากโค้ดจะเห็นว่า เราโยน Exception ที่มี Message เหมือนกับที่ User เห็นเป๊ะๆ เลย และฝั่ง Developer ก็เห็น Message เหมือนกัน และยังเห็นกรณีที่ Fail ก่อนด้วยว่ามีโอกาสที่จะหา User ไม่เจอและโอกาสที่รหัสผ่านจะผิดพลาด

Fail Fast ตอนไล่โค้ด

จริง ๆ แล้ว Exception อันเมื่อกี๊ก็เป็น 1 ใน Fail Fast ตอนไล่โค้ดอย่างที่อธิบายว่า เราเจอ Exception ก่อนที่จะไปทำอย่างอื่น เช่น สร้าง session ให้ผู้ใช้ แต่ถ้ากรณีที่มันไม่ใช่ Error ของระบบล่ะ ?

เราสามารถจำแนกได้ 2 วิธีครับคือ

  1. ไม่ต้องทำอะไรต่อ หรือ Return Early
  2. กรณีที่เราเขียนให้มันไปทำงานอย่างอื่น หรือ Fallback Execution Code

Return Early

เป็นกรณีที่ไม่ต้องทำอะไรต่อครับให้ return ดื้อ ๆ เลย ตัวอย่างที่จะเห็นบ่อย ๆ ก็คือ ตอนเราเช็คค่า Null เช่น สมมติว่าในระบบอยากให้มีการโยน Event ที่ชื่อว่า UserLoginEvent เมื่อมีการ Login สำเร็จ เพื่อให้คนที่ Subscribe Event สามารถต่อยอด Feature อื่นได้ เช่น แจ้งเตือนการเข้าสู่ระบบ

จากโค้ดเรา Return Early โดยการเช็คค่า null ของ event เพื่อป้องกันคนที่มาใช้แบบมั่ว ๆ โดยส่ง null มาให้เรา โดยการไม่ทำอะไร สั่งให้ return ออกไปดื้อ ๆ เลย ทำให้เรามั่นใจว่า method onLogin ของเราจะไม่พัง NullPointerException แน่นอน

รวมถึงกรณีที่คนส่ง Event ดันลืมใส่ Email มาให้เราด้วย เนื่องจากเราต้องใช้ Email ในการส่งแจ้งเตือนใน Email ทำให้เราจำเป็นต้องเช็คค่า null ก่อนที่จะนำมาใช้งาน ซึ่งใช้วิธี Early Return เหมือนกันนั่นเอง

และขอเสริมว่าจริงๆ throw Exception ก็เป็น Return Early นะครับ แต่เป็นการ return Exception แทนที่จะเป็นการไม่ทำอะไร

Fallback ไปใช้ Execution code ชุดอื่น

เป็นกรณีสุดท้าย คือในบางระบบถ้า interface ที่เราพยายามเรียกใช้มีปัญหา เราอาจจะต้องทำให้มัน Fail Fast โดยสั่งให้โปรแกรมเราไปทำงานอย่างอื่นแทน โดยคำนึงถึง User Friendly เป็นหลัก

ตัวอย่างเช่น ถ้าเป็นระบบปัจจุบันที่เป็น Client — Server อาจจะต้องมีการยิงข้าม Service แต่อีก Service ดันพัง ทำให้การส่ง Request และ Response ของโค้ดเราผิดพลาด แต่เราไม่อยากให้ User เจอ Error เราจึงทำการแสดงหน้าจอน่ารัก ๆ ให้ User เห็นและใจเย็นลงแทน

สมมติว่าเราอยู่ในระบบ e-commerce เจ้านึงที่ User ใช้งานจนถึงหน้าสรุป Order แต่ตอนสรุปออเดอร์ของ User คนนั้น ๆ ดันเกิดปัญหาที่ ตัว Service ของ Order ดันพังทำให้ยิง Request ไปหา Server ไม่ติด ทำให้เราเขียนโค้ด Frontend เพื่อให้ User ทดลองอีกครั้งในภายภาคหน้าได้ดังนี้

จากที่เห็นในโค้ดคือ ในมุมมองของ Frontend ที่เขียนด้วย JS ที่จะเขียนและดัก Error อย่างเรียบร้อย และนำ Error นั้นไปแสดงหน้าจอที่เป็นมิตรต่อ User แทนที่จะโชว์ว่าระบบเกิด Error โดยใช้ข้อความจาก Server อย่างเดียวเหมือนกรณี Login ผิดพลาดนั่นเอง โดยนับเป็น execution code อื่น เพราะตัวระบบ Frontend ไม่ได้มี Error อะไรเลย และโค้ดทำงานปกติดี เพราะที่พังคือฝั่ง Server เฉย ๆ

สรุปสั้น ๆ

Fail Fast ทำให้ชีวิตดีขึ้นทั้งในมุมคนใช้จริงๆ และมุม Developer ด้วยกัน ทั้งป้องกันบัค เพิ่ม User Experiences และ Developer Experiences ที่สามารถทำได้ง่ายมาก ๆ โดย มี 3 กรณีหลักคือ

  • ส่ง Human Readable Error
  • Return แบบไม่ต้องทำอะไร
  • Return Execution Code Fallback

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

--

--

Tae Keerati Jearjindarat

Hi, I'm Tae, Associate Engineering Manager at LINEMAN Wongnai. Thanks for following <3