ตั้งชื่อตัวแปรให้คนอ่านไม่ต้องเดา
เวลาเราพูดกันว่า "โค้ดอ่านง่าย" คนส่วนใหญ่นึกถึงการจัดย่อหน้า การแตกฟังก์ชัน หรือการเขียนคอมเมนต์ แต่จากประสบการณ์การนั่งอ่านโค้ดที่คนอื่นเขียนไว้ สิ่งที่ทำให้เหนื่อยที่สุดไม่ใช่โครงสร้าง แต่คือการต้องหยุดคิดทุกสองบรรทัดว่า ตัวแปรตัวนี้มันคืออะไรกันแน่
ชื่อที่ดีมีข้อได้เปรียบอย่างหนึ่งเหนือคอมเมนต์ คือมันโกหกไม่ได้นาน คอมเมนต์ที่เขียนไว้เมื่อปีที่แล้วอาจจะผิดไปแล้วโดยไม่มีใครรู้ แต่ชื่อตัวแปรถูกบังคับให้เปลี่ยนตามโค้ดเสมอ เพราะมันเป็นส่วนหนึ่งของโค้ดจริง ๆ
ชื่อที่ดีตอบคำถามว่า "ทำไม" ไม่ใช่ "อะไร"
ตัวแปรชื่อ list บอกเราว่ามันเป็นลิสต์ ซึ่งเป็นข้อมูลที่ตัวภาษาบอกเราอยู่แล้ว ชื่อนี้จึงไม่ได้เพิ่มอะไรเลย ส่วน activeSubscribers บอกทั้งว่ามันเป็นของหลายชิ้น เป็นคนประเภทไหน และผ่านเงื่อนไขอะไรมาแล้ว
| ชื่อที่ทำให้ต้องเดา | ชื่อที่อธิบายตัวเอง | ที่มันดีกว่าเพราะ |
|---|---|---|
| data | pendingInvoices | บอกว่าเป็นข้อมูลเรื่องอะไร และอยู่ในสถานะไหน |
| temp | originalPriceBeforeDiscount | บอกว่าเก็บไว้ทำไม ไม่ใช่แค่ว่าเก็บชั่วคราว |
| flag | hasVerifiedEmail | อ่านแล้วรู้ทันทีว่า true แปลว่าอะไร |
| result | matchedUserIds | บอกทั้งชนิดและความหมายของสิ่งที่ได้มา |
| d | daysUntilExpiry | หน่วยเวลาชัด ไม่ต้องไล่หาว่านับเป็นวันหรือวินาที |
boolean ควรอ่านเหมือนประโยคคำถามที่ตอบว่าใช่หรือไม่
ตัวแปรชนิด boolean เป็นจุดที่พลาดกันบ่อยที่สุด เพราะชื่อกลาง ๆ อย่าง status หรือ check ทำให้คนอ่านต้องไล่ย้อนไปดูว่า true หมายถึงสำเร็จหรือหมายถึงมีปัญหา ให้ขึ้นต้นด้วย is, has, can, should หรือ needs แล้วปัญหานี้จะหายไปเอง
// ต้องเดา: true แปลว่าปิดอยู่ หรือปิดไม่ได้?
if (order.close) { ... }
// อ่านเป็นประโยคได้เลย
if (order.isClosed) { ... }
if (order.canBeCancelled) { ... }
if (user.needsPasswordReset) { ... }ความยาวของชื่อควรแปรผันตามระยะที่มันมีชีวิตอยู่
นี่เป็นหลักที่ช่วยได้มากเวลาลังเลว่าจะตั้งชื่อยาวแค่ไหน ตัวแปรที่เกิดและตายภายในสองบรรทัด เช่นตัวนับใน loop ใช้ i ก็เพียงพอและอ่านง่ายกว่าด้วยซ้ำ แต่ตัวแปรที่ประกาศไว้ระดับโมดูลและถูกเรียกใช้จากอีกสิบไฟล์ ควรมีชื่อที่ยาวพอให้คนที่เปิดมาเจอครั้งแรกเข้าใจได้โดยไม่ต้องไล่หาที่มา
- ตัวแปรใน loop หรือ callback สั้น ๆ — สั้นได้เต็มที่
- ตัวแปรในฟังก์ชันยาวสามสิบบรรทัด — ควรบอกความหมายให้ครบ
- ค่าคงที่ที่ export ออกไปทั้งโปรเจกต์ — ยาวหน่อยไม่เป็นไร คนอ่านมากกว่าคนเขียน
ใส่หน่วยไว้ในชื่อ แล้วบั๊กจะหายไปหนึ่งประเภท
บั๊กที่เจ็บปวดและหายากหลายตัวเกิดจากการเข้าใจหน่วยผิด มีคนคิดว่า timeout เป็นวินาที อีกคนส่งมาเป็นมิลลิวินาที ระบบก็รอนานกว่าที่ตั้งใจไปพันเท่าโดยไม่มี error ใด ๆ ขึ้นให้เห็น
// คลุมเครือ
const timeout = 30;
const size = 5;
const price = 1200;
// ชัดเจน
const timeoutSeconds = 30;
const maxUploadSizeMb = 5;
const priceInSatang = 120000;ใช้คำเดียวกันตลอดทั้งโปรเจกต์
ถ้าในโค้ดฐานเดียวกันมีทั้ง fetchUser, getUser, loadUser และ retrieveUser คนอ่านจะเสียเวลาหาคำตอบว่าสี่คำนี้ต่างกันตรงไหน ทั้งที่ความจริงมันทำงานเหมือนกันหมด แค่คนเขียนคนละคนคนละเดือน
วิธีแก้ที่ได้ผลคือทำข้อตกลงสั้น ๆ ไว้ในไฟล์เดียวของทีม เช่น get ใช้กับการอ่านจากหน่วยความจำ fetch ใช้กับการเรียกข้าม network และ build ใช้กับการประกอบ object ขึ้นมาใหม่ ไม่ต้องยาว แค่มีให้อ้างอิงตอน review ก็พอ
มีอยู่สองเรื่องยากในวิทยาการคอมพิวเตอร์ คือการทำ cache ให้ถูกต้อง กับการตั้งชื่อสิ่งต่าง ๆ
สรุปสั้น ๆ ไว้ใช้ตอน review
- อ่านชื่อแล้วรู้ไหมว่ามันเก็บอะไร ถ้าไม่รู้ ให้เพิ่มคำที่บอกความหมายเข้าไป
- ถ้าเป็น boolean อ่านออกมาแล้วเป็นประโยคที่ตอบใช่หรือไม่ได้หรือเปล่า
- มีหน่วยหรือสกุลเงินเข้ามาเกี่ยวไหม ถ้ามีให้ใส่ไว้ในชื่อเลย
- คำที่ใช้ตรงกับคำที่โปรเจกต์ใช้อยู่แล้วหรือเปล่า
- ชื่อยาวสมดุลกับขอบเขตที่มันอยู่ไหม ตัวแปรอายุสองบรรทัดไม่ต้องยาวสามคำ
การตั้งชื่อเป็นงานที่ไม่มีใครชม เพราะเวลาทำได้ดีจะไม่มีใครสังเกตเห็น คนอ่านแค่รู้สึกว่าโค้ดนี้เข้าใจง่ายผิดปกติ แล้วก็ทำงานต่อไปได้เลย ซึ่งนั่นแหละคือผลลัพธ์ที่เราต้องการ
อยู่ในซีรีส์: ช่างฝีมือโค้ด
อ่านตอนต่อไป
ความคิดเห็น
กำลังโหลดความคิดเห็น