Inline Function
จุดประสงค์
หัวข้อที่มีชื่อว่า “จุดประสงค์”แทนที่การเรียก function เล็ก ๆ ด้วย body ของ function นั้น แล้วลบ function ทิ้ง ใช้ตอนที่ชื่อไม่ได้เพิ่มอะไรจากที่ body บอกชัดอยู่แล้ว
Code Smell
หัวข้อที่มีชื่อว่า “Code Smell”นี่คือวิธีรักษา needless indirection บางที helper เคยมีเหตุผลในอดีต แต่หดเหลือบรรทัดเดียวที่ไม่สำคัญ หรือไม่ชื่อก็แค่พูดซ้ำสิ่งที่ statement เดียวข้างในทำ การไล่ตามชื่อไปยังนิยามที่บอกอะไรไม่มากกว่าจุดที่เรียก คือความเหนื่อยเปล่าของคนอ่าน inline ตัดการกระโดดนั้นทิ้งไป และยังใช้เป็นขั้นตอนล้างบ้านได้ด้วย คือยุบ helper เล็ก ๆ ที่พันกันยุ่งมารวมไว้ที่เดียว แล้วค่อย extract ตามขอบเขตที่ดีกว่าออกมาใหม่
ก่อน → หลัง
หัวข้อที่มีชื่อว่า “ก่อน → หลัง”helper ที่แค่ส่งต่อไปยังการตรวจสอบบรรทัดเดียว เพิ่มชั้นขึ้นมาโดยไม่ได้อะไรกลับมา inline ทิ้งไปเลย
// Beforefunction deliveryFee(driver: Driver): number { return moreThanFiveTrips(driver) ? 2 : 5;}
function moreThanFiveTrips(driver: Driver): boolean { return driver.trips > 5;}
// Afterfunction deliveryFee(driver: Driver): number { return driver.trips > 5 ? 2 : 5;}# Beforedef delivery_fee(driver): return 2 if more_than_five_trips(driver) else 5
def more_than_five_trips(driver): return driver.trips > 5
# Afterdef delivery_fee(driver): return 2 if driver.trips > 5 else 5// Beforefunc DeliveryFee(driver Driver) int { if moreThanFiveTrips(driver) { return 2 } return 5}
func moreThanFiveTrips(driver Driver) bool { return driver.Trips > 5}
// Afterfunc DeliveryFee(driver Driver) int { if driver.Trips > 5 { return 2 } return 5}// Beforefn delivery_fee(driver: &Driver) -> i32 { if more_than_five_trips(driver) { 2 } else { 5 }}
fn more_than_five_trips(driver: &Driver) -> bool { driver.trips > 5}
// Afterfn delivery_fee(driver: &Driver) -> i32 { if driver.trips > 5 { 2 } else { 5 }}กลไกการทำงาน
หัวข้อที่มีชื่อว่า “กลไกการทำงาน”- เช็กว่า function ไม่เป็น polymorphic เพราะ method ที่ subclass override ไว้ inline ไม่ได้
- หาจุดที่เรียกให้ครบ ถ้ามีเยอะให้คิดใหม่ เพราะ inline จะง่ายที่สุดตอนจุดเรียกมีไม่กี่จุด
- แทนที่การเรียกแต่ละครั้งด้วยสำเนาของ body แล้วปรับให้เข้ากับ argument จริง
- รัน test หลังแทนที่ทุกครั้ง
- พอไม่เหลือจุดเรียกแล้ว ก็ลบ function เดิมทิ้ง
- รันชุด test ทั้งหมดอีกรอบ เพื่อยืนยันว่าไม่มีใครอ้างถึง function นั้นแล้ว
ใช้เมื่อไหร่ / ข้อแลกเปลี่ยน
หัวข้อที่มีชื่อว่า “ใช้เมื่อไหร่ / ข้อแลกเปลี่ยน”inline เมื่อ body ชัดเจนอย่างน้อยเท่ากับชื่อ เมื่อกลุ่ม helper ที่จัดโครงสร้างมาไม่ดีควรรวมร่างก่อนแยกใหม่ หรือเมื่อ indirection มาขวางทางคนอ่าน แต่ อย่า inline function ที่ถูกเรียกจากหลายที่ หรือ function ที่ชื่อจับแนวคิดคลุมเครือไว้ได้จริง ๆ เพราะกรณีนั้นชื่อคือเอกสารที่ควรเก็บไว้
ท่าตรงข้ามคือ Extract Function สองท่านี้เป็นคู่หูกัน inline เพื่อยุบโครงสร้างที่ไม่ดี แล้ว extract เพื่อประกอบโครงสร้างที่ดีกว่าขึ้นมาใหม่
เนื้อหาที่เกี่ยวข้อง
หัวข้อที่มีชื่อว่า “เนื้อหาที่เกี่ยวข้อง”| ใช้ Inline Function เมื่อ | หลีกเลี่ยงเมื่อ |
|---|---|
| ชื่อ function ไม่ได้บอกอะไรมากกว่า body | function ถูกใช้งานหลายที่ |
| function แค่ delegate ต่อไปยังอีก function | body ซับซ้อนกว่าชื่อ — ชื่อยังมีประโยชน์ |
| กำลังจัดระเบียบใหม่ และอยากรวม logic ก่อนแบ่งใหม่ | ต้อง override ใน subclass |
⚠️ ไม่ควร Inline Function เมื่อ:
- function นั้นซ่อน complexity จริง ๆ — inline แล้ว code จะอ่านยากขึ้น
- เป็น API ที่ external caller ใช้อยู่
- ต้องใช้ trace ตอน debug — ชื่อ function ช่วยให้อ่าน stack trace ออก