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

Split Variable

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

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

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

// Before
function describe(height: number, width: number): string {
let temp = 2 * (height + width);
const out: string[] = [`Perimeter: ${temp}`];
temp = height * width;
out.push(`Area: ${temp}`);
return out.join('\n');
}
// After
function describe(height: number, width: number): string {
const perimeter = 2 * (height + width);
const area = height * width;
return [`Perimeter: ${perimeter}`, `Area: ${area}`].join('\n');
}
  1. หาการกำหนดค่าครั้งแรก แล้วเปลี่ยนชื่อตัวแปรให้อธิบาย เฉพาะความหมายแรก นั้น ถ้าภาษาอนุญาต ให้ทำเป็นค่าคงที่ไปเลย (const, let ที่ไม่ reassign หรือ := ที่ไม่เคยกำหนดค่าใหม่)
  2. เปลี่ยนทุกการอ้างอิงระหว่างการกำหนดค่าครั้งแรกและครั้งที่สองให้ใช้ชื่อใหม่
  3. รัน test
  4. ทำซ้ำที่การกำหนดค่าครั้งที่สอง: ประกาศตัวแปรใหม่ด้วยชื่อสำหรับความหมายที่สอง แล้วชี้การอ้างอิงหลังจากนั้นไปยังชื่อใหม่
  5. ทำต่อไปจนกระทั่งแต่ละจุดประสงค์ที่แตกต่างเป็นเจ้าของตัวแปรที่แยกกัน กำหนดค่าครั้งเดียว
  6. เมื่อตัวแปรที่แก้ค่าได้ตัวเดิมไม่เหลือคนอ่านแล้ว ให้ลบทิ้ง ส่วนใน Rust มักตัด mut ออกได้หมดเลย

ใช้ Split Variable ทุกครั้งที่ชื่อหนึ่งถูกกำหนดค่าใหม่เพื่อแทนของคนละอย่าง เพราะจะกำจัดบั๊กทั้งตระกูล “ตอนนี้ค่านี้คืออะไร” ออกไป และทำให้แต่ละบรรทัดเข้าใจได้ด้วยตัวเอง ท่านี้ยังเป็นจุดตั้งต้นของ Extract Function ที่พบบ่อย เพราะพอแต่ละค่าอยู่ในตัวแปรที่กำหนดค่าครั้งเดียวของตัวเอง ส่วนที่คำนวณค่านั้นก็ยกออกมาได้สะอาด

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

เมื่อใดที่คุณควรแยกตัวแปรออกเป็นสองตัว?
การกำหนดค่าซ้ำชนิดใดที่คุณไม่ควรแยก?
หลังจากแยกแล้ว แต่ละตัวแปรที่ได้ควรมี property ใด?
Split Variable มักเป็นจุดเริ่มต้นของการรีแฟคเตอร์ใด?