Notes & software courses · Free to learn
Aph's Blog
On this page

หลักการออกแบบโค้ดที่ดี

👋 อ่านฟรีทั้งหมดบน Aph's Blog — เนื้อหาภาษาไทย ทำตามทีละหน้าใน sidebar ได้เลย หากมีข้อเสนอแนะหรืออยากให้เพิ่มหัวข้อไหน บอกได้เสมอ

DRY, Single Responsibility, KISS, ตั้งชื่อให้ดี และเมื่อไหร่ควร (หรือไม่ควร) ใช้ OOP

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

DRY — Don't Repeat Yourself

อย่าเขียนโค้ดซ้ำ ถ้าเห็นโค้ดเหมือนกันหลายที่ ให้แยกเป็นฟังก์ชันหรือ class เพราะถ้าต้องแก้ จะได้แก้ที่เดียว ไม่ใช่ไล่แก้ทุกที่ (และเสี่ยงลืม)

python
# แย่: คำนวณภาษีซ้ำหลายที่
price1 = 100 + 100 * 0.07
price2 = 250 + 250 * 0.07

# ดี: แยกเป็นฟังก์ชัน แก้สูตรที่เดียว
def with_vat(price):
    return price + price * 0.07
print(with_vat(100), with_vat(250))

Single Responsibility — หนึ่งหน้าที่ต่อหนึ่งสิ่ง

แต่ละฟังก์ชัน/class ควรทำหน้าที่เดียวและทำให้ดี ฟังก์ชันที่ทำหลายอย่างปนกันจะทดสอบยากและแก้ยาก ถ้าอธิบายฟังก์ชันแล้วต้องใช้คำว่า "และ" หลายครั้ง อาจถึงเวลาแยก

python
# แย่: ฟังก์ชันเดียวทำทั้งคำนวณ แสดงผล และบันทึก
# ดี: แยกหน้าที่
def calculate_total(items):
    return sum(items)

def format_receipt(total):
    return f"ยอดรวม: {total:,} บาท"

def save_to_file(text):
    pass   # บันทึกลงไฟล์

total = calculate_total([100, 250, 80])
print(format_receipt(total))

KISS — Keep It Simple

เลือกวิธีที่เรียบง่ายที่สุดที่แก้ปัญหาได้ก่อน อย่าออกแบบซับซ้อนเกินจำเป็นเผื่ออนาคตที่ยังไม่มาถึง (over-engineering) โค้ดที่เรียบง่ายอ่านง่าย บั๊กน้อย และแก้ง่ายกว่า

ตั้งชื่อให้สื่อความหมาย

โค้ดถูกอ่านบ่อยกว่าถูกเขียน ชื่อที่ดีคือเอกสารในตัว ลดความจำเป็นในการเขียนคอมเมนต์อธิบาย

แย่ดี
ddays_since_login
calc()calculate_total_price()
temp / data / xuser_input / filtered_users
flagis_active / has_permission

เมื่อไหร่ควร (และไม่ควร) ใช้ OOP

OOP ไม่ใช่คำตอบของทุกอย่าง สคริปต์สั้น ๆ เขียนเป็นฟังก์ชันก็เพียงพอและอ่านง่ายกว่า OOP เปล่งประกายเมื่อโปรแกรมมีหลาย "สิ่ง" ที่มีทั้งข้อมูลและพฤติกรรม และมีหลายประเภทที่คล้ายกัน

  • ใช้ OOP: ระบบจัดการผู้ใช้, เกม (ตัวละคร/ศัตรู/ไอเทม), ระบบที่มีหลายชนิดของวัตถุคล้ายกัน
  • ไม่ต้อง OOP: สคริปต์คำนวณสั้น ๆ, แปลงไฟล์ครั้งเดียว, งานที่ฟังก์ชันไม่กี่ตัวก็จบ

สรุปบทที่ 5

  • DRY: อย่าเขียนซ้ำ แยกเป็นฟังก์ชัน/class แก้ที่เดียว
  • Single Responsibility: แต่ละส่วนทำหน้าที่เดียว
  • KISS: เรียบง่ายที่สุดเท่าที่แก้ปัญหาได้ เลี่ยง over-engineering
  • ตั้งชื่อให้สื่อความหมาย = เอกสารในตัว
  • ใช้ OOP เมื่อมีหลาย "สิ่ง" ที่มีข้อมูล+พฤติกรรม ไม่ใช่ทุกงาน
แบบฝึกหัด

1) หาโค้ดซ้ำในโปรแกรมเก่าของคุณ แล้วแยกเป็นฟังก์ชัน (DRY) 2) เปลี่ยนชื่อตัวแปร x, d, temp ให้สื่อความหมาย 3) แยกฟังก์ชันที่ทำหลายอย่างออกเป็นฟังก์ชันย่อย 4) ตัดสินใจว่าโปรแกรม To-do list ควรใช้ OOP ไหม เพราะอะไร

จบบทที่ 5

ตอนนี้คุณจัดระเบียบโค้ดด้วย OOP และยึดหลักการออกแบบที่ดีได้แล้ว บทสุดท้ายจะเชื่อมทุกอย่างเข้ากับโลกจริง: เว็บ, API และฐานข้อมูล