สัปดาห์ที่ 05 · Code Literacy with AI

แก้ไข + ต่อยอดโค้ด AI

ตอนนี้คุณอ่านโค้ดได้แล้ว — สัปดาห์นี้คือ "แก้ทีละนิด" · เปลี่ยนเงื่อนไข, เพิ่มข้อมูล, รวมหลายโปรแกรม — เรียน syntax โดย ลงมือแก้จริง ไม่ใช่ท่องตำรา

เป้าหมายสัปดาห์นี้

🔒 ทำไม "การแก้โค้ด" คือทักษะที่ AI ทำให้คุณไม่ได้ AI แก้ให้ ได้ใน 5 วินาที · แต่ "ตัดสินใจว่าจะแก้อะไร / ตรวจว่า AI แก้ถูกมั้ย / รับ-ปฏิเสธ change" ต้องเป็นคุณ · ทุกครั้งที่ AI commit code = "คุณ commit code" เพราะคุณกด accept · ถ้าแก้พังในที่ทำงานจริง — บอกหัวหน้าไม่ได้ว่า "AI พัง" · ความรับผิดชอบเป็นของคนกด accept

🎯 Running Case — ต่อยอด Grading App ของพี่นัท

ใน W04 เราอ่าน code ของ Grading App แล้ว · สัปดาห์นี้ แก้ + ต่อยอด · ความจริงคือ — ในงานจริง 90% ของเวลาคุณใช้แก้ code ที่มีอยู่ ไม่ใช่เขียนใหม่

📊 4 ระดับของการแก้โค้ด (Modification Pyramid)

ไม่ใช่ทุกการแก้ "ยากเท่ากัน" · จัดเป็น 4 ระดับ — เริ่มจากระดับต่ำสุด ปลอดภัยที่สุด · ไต่ขึ้นเมื่อมั่นใจ

flowchart TB L4["Level 4: แก้ Behavior
เปลี่ยนวิธีคำนวณ · เปลี่ยน format
⚠️ ต้อง regression test"] L3["Level 3: รวมหลาย program
function + list + dict + loop ผสมกัน
เริ่มซับซ้อน"] L2["Level 2: เพิ่ม case / field
เพิ่ม condition · field ใหม่ใน dict
ปานกลาง"] L1["Level 1: เปลี่ยนค่า / ข้อความ
เลข · string · ไม่แตะ logic
✅ ปลอดภัยสุด"] L1 --> L2 --> L3 --> L4 classDef safe fill:#064e3b,stroke:#34d399,color:#fff classDef mid fill:#3d2c1a,stroke:#ffd43b,color:#fff classDef risky fill:#3b2962,stroke:#8b5cf6,color:#fff classDef dangerous fill:#5c1818,stroke:#ef4444,color:#fff class L1 safe class L2 mid class L3 risky class L4 dangerous

🟢 Level 1 = แก้ไม่พลาด · 🔴 Level 4 = ต้องทดสอบหนัก เพราะอาจพังของเดิม

หลักคิด — "Small Steps, Always Working"

กฎสำคัญที่นักศึกษาปี 1 มักทำผิด: "พยายามแก้หลายอย่างพร้อมกัน" · ผลคือ code เสีย แล้วไม่รู้ว่าตรงไหน · กฎคือ:

กฎ Small Steps 1) แก้ 1 อย่าง · 2) รัน · 3) ถ้าได้ผล → commit · 4) ถ้าไม่ได้ → undo (Ctrl+Z) · 5) แล้วค่อยแก้อันถัดไป
ทุก commit คือ save point ที่ปลอดภัย — ย้อนกลับได้เสมอ

🟢 Level 1 — เปลี่ยนค่า / ข้อความ

เริ่มจากการแก้ที่ ปลอดภัยที่สุด — เปลี่ยน string หรือเลข · ไม่แตะ logic

ตัวอย่าง: เปลี่ยนเกณฑ์ + เพิ่มเกรด A+

def calc_grade(score): if score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" else: return "F"
def calc_grade(score): if score >= 85: return "A+" elif score >= 75: return "A" elif score >= 70: return "B+" elif score >= 60: return "C" else: return "F"

ดู diff ทางขวา — เปลี่ยนแค่ "เลข + ข้อความ" · structure ของ if/elif เหมือนเดิม

def calc_grade(score): if score >= 85: return "A+" elif score >= 75: return "A" elif score >= 70: return "B+" elif score >= 60: return "C" else: return "F" score = int(input("คะแนน: ")) print(f"เกรด: {calc_grade(score)}")

การเปลี่ยนแค่ค่าตัวเลขกับข้อความ — "ทำไม่พลาด" · เริ่มฝึก git commit ตรงนี้

🟡 Level 2 — เพิ่ม case / field ใหม่

ตัวอย่าง: เพิ่มเกรด "I" สำหรับคะแนนติดลบ

def calc_grade(score): if score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" else: return "F"
def calc_grade(score): if score < 0: return "I" elif score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" else: return "F"
⚠️ สังเกตการเปลี่ยนที่ "เนียน" if บรรทัดแรกของ Before กลายเป็น elif ใน After · ถ้าลืมเปลี่ยนตัวนี้ — code จะรันได้ "แต่ผลผิด" เพราะ score >= 80 ก็จะเป็น A แม้คะแนน < 0 (ตรวจไม่เจอ I) · นี่คือเหตุที่ต้องใช้ Diff Viewer ดูทุก change

ตัวอย่าง: เพิ่ม field "email" ใน student dict

student = { "name": "Ploy", "id": "640001", "scores": [85, 72, 91], } print(f"นักศึกษา: {student['name']}") print(f"รหัส: {student['id']}")
student = { "name": "Ploy", "id": "640001", "email": "ploy.k@ubu.ac.th", "scores": [85, 72, 91], } print(f"นักศึกษา: {student['name']}") print(f"รหัส: {student['id']}") print(f"อีเมล: {student['email']}")

🟣 Level 3 — รวม 2 โปรแกรม

เอา grade_calc.py มารวมกับ pass_count.py — สร้างโปรแกรมที่:

def calc_grade(score): if score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" elif score >= 50: return "D" else: return "F" scores = [85, 72, 45, 91, 60, 33, 78] # นับเกรด — ใช้ dict grade_count = {"A": 0, "B": 0, "C": 0, "D": 0, "F": 0} for s in scores: g = calc_grade(s) grade_count[g] += 1 # พิมพ์ผล for grade, count in grade_count.items(): print(f"{grade}: {count} คน")

ตรงนี้คุณ ผสม 4 อย่างแล้ว: function, list, dict, loop · นี่คือ "Level 3"

🔴 Level 4 — แก้ behavior

ขั้นนี้ ยากที่สุด เพราะต้องเข้าใจ flow จริง — เช่น เปลี่ยนวิธีคำนวณ, เปลี่ยน output format

ตัวอย่าง: ใช้ค่าเฉลี่ยถ่วงน้ำหนัก

def calc_grade(score): if score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" elif score >= 50: return "D" else: return "F" scores = { "homework": 78, "midterm": 65, "final": 82, } weights = { "homework": 0.30, "midterm": 0.30, "final": 0.40, } total = 0 for key in scores: total += scores[key] * weights[key] print(f"คะแนนรวมถ่วงน้ำหนัก: {total:.2f}") print(f"เกรด: {calc_grade(int(total))}")

⌨️ Cursor Ctrl+K — ให้ AI แก้ Inline (Level 1-2 ของ AI-assisted edit)

Cursor มี shortcut พิเศษ Ctrl+K (Mac: Cmd+K) ที่ "แทรก AI ที่ตำแหน่ง cursor" — แทนที่จะ copy-paste ใน chat → ทำงานเร็วกว่าเดิม 5 เท่า

Workflow แนะนำ

  1. เลือก code ที่อยากแก้ — ไฮไลต์บรรทัดที่ต้องการแก้ใน editor
  2. กด Ctrl+K — กล่อง prompt จะลอยขึ้นมาเหนือ selection
  3. พิมพ์ instruction สั้น ๆ — เช่น "เพิ่ม A+ สำหรับ ≥ 85" หรือ "แก้ให้รับ float ด้วย"
  4. กด Enter — รอ AI AI จะแสดง "diff overlay" (เขียว/แดง) แสดงสิ่งที่จะเปลี่ยน
  5. กด Accept (✓) หรือ Reject (✗)"อ่าน diff ให้ละเอียดก่อนรับเสมอ" · นี่คือจุดที่คุณรับผิดชอบ
  6. รัน + commit — ถ้าใช้ได้ → git commit · ถ้าพัง → Ctrl+Z ทันที
⚠️ จุดที่นักศึกษาพลาด — กด Accept โดยไม่อ่าน diff AI อาจ "แก้เกิน" — เปลี่ยน format เดิมโดยไม่ขอ, ลบบรรทัดที่คุณตั้งใจไว้ · นิสัย "อ่าน diff ก่อนรับ" เป็นกฎเหล็ก

✅ Regression Test — เช็คว่าของเดิมยังทำงาน

Regression = "ถอยหลัง" · Regression test = ตรวจว่า "feature เก่ายังทำงาน" หลังจากเพิ่ม feature ใหม่ · ทุกครั้งที่แก้ code ต้องถามตัวเอง: "input ที่เคยได้ผลถูก ตอนนี้ยังถูกอยู่มั้ย?"

วิธีง่ายที่สุด — เขียน test list ก่อนแก้

# ก่อนแก้ — บันทึก expected behavior
calc_grade(85)  → "A"
calc_grade(75)  → "B"
calc_grade(45)  → "F"
calc_grade(0)   → "F"

# หลังแก้ Level 2 (เพิ่ม case I) — ต้องผ่านเดิม + case ใหม่
calc_grade(85)  → "A"    ✅ ของเดิมยังถูก
calc_grade(75)  → "B"    ✅
calc_grade(45)  → "F"    ✅
calc_grade(0)   → "F"    ✅
calc_grade(-5)  → "I"    ✅ ของใหม่ใช้ได้
def calc_grade(score): if score < 0: return "I" elif score >= 80: return "A" elif score >= 70: return "B" elif score >= 60: return "C" else: return "F" # Regression tests — ทำเสมอหลังแก้ tests = [ (85, "A"), (75, "B"), (45, "F"), (0, "F"), (-5, "I"), ] for score, expected in tests: got = calc_grade(score) status = "✅" if got == expected else "❌" print(f"{status} calc_grade({score}) = {got!r} (expected {expected!r})")

กฎเหล็ก: ก่อน commit ทุกครั้ง — รัน test ทุกตัวที่เคยมี · ถ้ามีตัวไหนพัง = "คุณทำของเดิมพังโดยไม่รู้ตัว"

🕵️ จับ AI เมื่อมัน "แก้เกิน" (Over-modification)

AI ชอบช่วย "เกินที่ขอ" · ขอแก้บรรทัดเดียว — มันเปลี่ยน 5 อย่าง · Diff Viewer คือเครื่องมือจับ

ตัวอย่าง: ขอ AI แก้ "เพิ่ม case I" แต่ AI ทำเกิน

def calc_grade(score): if score >= 80: return "A" elif score >= 70: return "B" else: return "F"
def calculate_grade_letter(score: int) -> dict: if score < 0: return {"grade": "I", "valid": False} elif score >= 80: return {"grade": "A", "valid": True} elif score >= 70: return {"grade": "B", "valid": True} else: return {"grade": "F", "valid": True}
❌ ทำไมถึงไม่ดี
  • Rename function — ทุกที่ที่เรียก calc_grade() จะพังหมด
  • เปลี่ยน return type จาก string → dict — caller ที่คาด string ก็พัง
  • เพิ่ม type hints — ไม่ได้ขอ · ถ้าอยากได้ ค่อยขอแยก
Reject → ขอใหม่: "แก้แค่เพิ่ม case I · อย่าเปลี่ยน function name · อย่าเปลี่ยน return type"

5 pattern ของ AI ที่ "ทำเกิน"

Patternวิธีจับ
Rename ตัวแปร / functionดู diff — ชื่อเปลี่ยนทุกที่
เปลี่ยน return typeดูบรรทัด return — type เดิมกับใหม่ตรงกัน?
เพิ่ม import / libraryดูส่วนบน — import ใหม่โผล่มั้ย
เพิ่ม error handling ที่ไม่ขอดู try/except ที่ไม่เคยมี
Refactor structureดูถ้าจำนวน function เพิ่ม / ลด

🐞 อ่าน Error Message ให้เป็น — Error Anatomy

หลีกเลี่ยงไม่ได้ — เมื่อแก้ code คุณจะเจอ error · มันไม่น่ากลัวถ้าอ่านเป็น

กายวิภาคของ Python Error

Traceback (most recent call last):    ← ② "เกิด error ที่ขั้นไหน"
  File "grade.py", line 12, in <module>
    print(scor)                          ← ③ บรรทัด code ที่พัง
NameError: name 'scor' is not defined ← ① "ชนิด error" + "รายละเอียด"

วิธีอ่าน:

  1. อ่านบรรทัดสุดท้ายก่อน — บอก type + reason
  2. ดูชื่อ error — NameError / TypeError / SyntaxError ฯลฯ
  3. ดู file + line — ตามขึ้นไปดู code ที่บรรทัดนั้น
  4. เข้าใจ "ทำไม" — error message มักบอกตรง ๆ ถ้าอ่านช้า ๆ

5 Error ที่นักศึกษาเจอบ่อยที่สุด

Errorแปลว่าตัวอย่างวิธีแก้
NameError ใช้ตัวแปรที่ยังไม่ได้สร้าง print(scor) ทั้งที่ตัวแปรชื่อ score เช็ค typo · ดูว่าตัวแปรประกาศก่อนใช้
TypeError ใช้ type ผิด "5" + 3 (str + int) แปลง type ก่อน: int("5") + 3
SyntaxError เขียนผิดไวยากรณ์ ลืม : หลัง if ดูบรรทัดที่ Python ชี้ · ปกติคือลืม : / ) / "
IndentationError เยื้องผิด code ใน if ไม่เยื้อง เยื้อง 4 space (กด Tab) · ห้ามผสม tab + space
KeyError คีย์ใน dict ไม่มี student["age"] ไม่มี field age ใช้ .get("age") · หรือเช็ค "age" in student

ลองรัน + แก้ error ด้วยตัวเอง

code นี้มี 3 error · ลอง Run → อ่าน error → แก้ → Run อีก จนผ่าน

def calc_grade(score) if score >= 80: return "A" elif score >= 70: return "B" else: return "F" score = input("คะแนน: ") print(grad(calc_grade(score)))
🔓 เฉลย (พยายามแก้เองก่อน!)
  1. def calc_grade(score) ขาด : ท้ายบรรทัด → SyntaxError
  2. else: ตามด้วย return "F" ที่ไม่เยื้อง → IndentationError (ต้องเยื้อง 4 space)
  3. print(grad(...)) ใช้ grad แทน calc_grade · จริง ๆ ไม่ต้อง wrap → print(calc_grade(int(score)))
กฎทอง — ส่ง Error ให้ AI อย่าจ้องอ่านเอง 10 นาที · copy error ทั้งก้อน → paste ใน Cursor chat → ถาม "error นี้แปลว่าอะไร และจะแก้ยังไง?" AI ตอบได้ใน 5 วินาที · แล้วจึง เข้าใจ มัน

🧪 Workshop — 15 การแก้ใน 1 สัปดาห์

เอา 4 โปรแกรมจาก W04 มา แก้ทั้งหมด 15 ครั้ง · commit ทุกครั้งที่ทำสำเร็จ

  1. grade_calc.py — แก้เกณฑ์เป็น A+/A/B+/B/C+/C/D/F (8 ระดับ แทน 5 ระดับ)
  2. grade_calc.py — เพิ่ม case "I" สำหรับคะแนน < 0
  3. grade_calc.py — แสดง emoji 🎉 ถ้าได้ A/A+
  4. grade_calc.py — รับคะแนนหลายตัวคั่นด้วยจุลภาค (เช่น "85, 72, 91") แล้วคำนวณ avg
  5. pass_count.py — เปลี่ยน threshold ผ่านเป็น 60
  6. pass_count.py — เพิ่มการรายงาน "คะแนนสูงสุด" และ "คะแนนต่ำสุด"
  7. pass_count.py — เพิ่ม category "เกียรตินิยม" สำหรับ ≥ 80
  8. student_dict.py — เพิ่ม field "email" และ "year"
  9. student_dict.py — เก็บ list ของ student (3 คน) แทน 1 คน
  10. student_dict.py — print เรียงตามคะแนนเฉลี่ย
  11. login.py — เปลี่ยน max_attempts เป็น 5
  12. login.py — เพิ่ม username ด้วย (ต้องตรงทั้งคู่ถึงเข้าได้)
  13. login.py — print เวลาที่ login ได้สำเร็จ (ใช้ from datetime import datetime ขอ AI ช่วยถ้าไม่รู้)
  14. รวม grade_calc + pass_count — ตามตัวอย่าง "ระดับ 3" ด้านบน
  15. เพิ่มถ่วงน้ำหนัก — ตามตัวอย่าง "ระดับ 4" ด้านบน

🐙 ฝึก Git Commit

Cursor มี git ในตัว — เปิด Source Control ที่ sidebar (icon รูปสาขา)

  1. เปิด terminal ใน Cursor → git init ใน folder โปรเจกต์
  2. สร้าง .gitignore ใส่ __pycache__/, *.pyc, .venv/
  3. หลังแก้แต่ละข้อ + รันได้Source Control → กรอกข้อความ → Commit
  4. ข้อความ commit ที่ดี สั้น + verb + noun เช่น "เพิ่ม case I สำหรับคะแนนติดลบ"
  5. หลังจาก 15 commits → push ขึ้น GitHub (W14 จะลงลึก)

ข้อผิดที่พบบ่อย

แก้หลายอย่างพร้อมกัน + พังพร้อมกัน — 1 commit = 1 การเปลี่ยน · ถ้าพังจะรู้เลยว่าตรงไหน
เห็น error → ลบ code ทิ้ง → ขอ AI ใหม่ อย่าทำ! · พยายามอ่าน error · ถ้าไม่เข้าใจ → ถาม AI ให้อธิบาย · จะได้เรียน
ไม่ commit ระหว่างทาง เมื่อพังจะกลับไปจุดที่ทำงานไม่ได้ · commit = save point

ส่งงานสัปดาห์นี้

Reference จาก slide เดิม

ครอบคลุม Topic 5 (Conditions), Topic 6 (Repetition), Topic 7 (Functions) ผ่านการแก้โค้ดจริง