SumoSunday

ซีรีส์ เขียนโปรแกรมพื้นฐาน · ตอนที่ 2 จาก 7

อ่าน error ให้เป็น: ดู 3 อย่างก่อนส่งให้ AI แก้

16 ต.ค. 2569 · อ่าน 14 นาที

จอแดงเต็มหน้าไม่ได้แปลว่าโปรแกรมพังทั้งหมด error ส่วนใหญ่บอกไว้แล้วว่าเป็นปัญหาชนิดไหนและเกิดที่บรรทัดไหน สิ่งที่ยังขาดคือข้อมูลว่าคุณเพิ่งทำอะไรไป ตอนที่ 2 ของซีรีส์เขียนโปรแกรมพื้นฐานพาอ่าน error จริง 3 ตัวจาก Node.js และ Python ทีละส่วน พร้อมวิธีส่ง error ให้ AI แบบที่ได้คำตอบตรงจุด

บทความนี้เป็นตอนที่ 2 ของซีรีส์ "เขียนโปรแกรมพื้นฐาน" สำหรับคนที่ให้ AI เขียนโค้ดให้ แต่ไม่ได้เป็นโปรแกรมเมอร์

เมื่อกดรันโปรแกรมที่ AI เขียนให้ แล้วจอเต็มไปด้วยภาษาอังกฤษสิบกว่าบรรทัด หลายคนคัดลอกไปวางแล้วพิมพ์ว่า "แก้ให้หน่อย" บางครั้งก็ได้ผล แต่บางครั้ง AI แก้จนข้อความแจ้งข้อผิดพลาด (error) หายไป ทั้งที่ปัญหาจริงยังอยู่

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

ข้อมูล ณ ตุลาคม 2569 error ทุกตัวในบทความนี้เรารันจริงบนเครื่อง ด้วย Node.js 23.11 และ Python 3.13 ถ้าคุณใช้รุ่นอื่น ให้ดูที่ชนิดและตำแหน่งของ error เป็นหลัก

error คือรายงานว่าเกิดอะไรขึ้น ไม่ใช่คำตำหนิ

MDN (เว็บคู่มือสำหรับนักพัฒนาเว็บที่ Mozilla ดูแล) อธิบายว่า error ของ JavaScript ทุกตัวมี 2 ส่วน คือ ชื่อ ที่บอกชนิดของ error และ ข้อความ ที่อธิบายละเอียดขึ้น 2 ส่วนนี้รวมกันคือจุดเริ่มต้นของการเข้าใจและแก้ปัญหา

MDN ยังเขียนไว้ตรงๆ ว่า ปัญหาที่ error รายงาน ไม่ได้ชัดเจนทันทีเสมอไป นี่คือเหตุผลที่ต้องอ่าน error เป็น ไม่ใช่แค่คัดลอกส่งต่อ

3 อย่างที่ต้องหาในทุก error

ส่วนถามว่าหาที่ไหน
1. ชนิดปัญหาแบบไหนคำที่ลงท้ายด้วย Error เช่น TypeError และข้อความหลังเครื่องหมาย :
2. ตำแหน่งเกิดที่ไฟล์ไหน บรรทัดไหนชื่อไฟล์ของคุณที่มีเลขบรรทัดต่อท้าย
3. บริบทเกิดตอนทำอะไร อะไรเพิ่งเปลี่ยนไม่มีบนจอ คุณต้องเขียนเอง

ข้อ 1 และ 2 โปรแกรมบอกให้แล้ว ส่วนข้อ 3 มีแค่คุณที่รู้ และหลายครั้งข้อ 3 คือสิ่งที่ทำให้ AI แก้ได้ถูกจุด

ต่อไปลองดู error จริง 3 ตัว

ตัวอย่างที่ 1 (Node.js): ใบเสร็จออกได้ 2 ใบ แล้วพัง

สมมติ AI เขียนโปรแกรม receipt.js ให้ โปรแกรมนี้อ่านรายการออเดอร์จากไฟล์ orders.json แล้วพิมพ์ใบเสร็จทีละใบ เมื่อรัน ได้ผลดังนี้ เราย่อชื่อโฟลเดอร์ยาวๆ ข้างหน้าเป็น /…/ ให้อ่านง่าย ส่วนอื่นตรงตามที่ขึ้นจริง ยกเว้นจุดเดียวที่บอกไว้ใต้กล่อง

prompt
ใบเสร็จ #1 คุณสมชาย ยอด 450 บาท
ใบเสร็จ #2 คุณสมหญิง ยอด 120 บาท
/…/demo/receipt.js:6
  console.log(`ใบเสร็จ #${order.id} คุณ${order.customer.name} ยอด ${order.total} บาท`);
                                                        ^

TypeError: Cannot read properties of undefined (reading 'name')
    at printReceipt (/…/demo/receipt.js:6:57)
    at Array.forEach ([anonymous])
    at Object.[anonymous] (/…/demo/receipt.js:9:8)
    at Module._compile (node:internal/modules/cjs/loader:1734:14)
    at Object..js (node:internal/modules/cjs/loader:1899:10)
    at Module.load (node:internal/modules/cjs/loader:1469:32)
    at Function._load (node:internal/modules/cjs/loader:1286:12)
    at TracingChannel.traceSync (node:diagnostics_channel:322:14)
    at wrapModuleLoad (node:internal/modules/cjs/loader:235:24)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:151:5)

Node.js v23.11.0

หมายเหตุ: ในข้อความจริง คำว่า anonymous (และ module ในตัวอย่าง Python) อยู่ในวงเล็บมุม หน้าเว็บนี้แสดงวงเล็บมุมไม่ได้ เราจึงเปลี่ยนเป็น [ ]

ชนิด: บรรทัด TypeError: Cannot read properties of undefined (reading 'name') แปลว่า โปรแกรมพยายามอ่านค่า name จากของที่ไม่มีอยู่ (undefined)

ตำแหน่ง: receipt.js:6 คือไฟล์ receipt.js บรรทัดที่ 6 ส่วนบรรทัดที่ขึ้นต้นด้วย at คือเส้นทางที่โปรแกรมเดินมาจนถึงจุดที่พัง ส่วนนี้มักเรียกว่า stack trace เอกสารของ Node.js อธิบายว่า error.stack ขึ้นต้นด้วยชื่อ error และข้อความ แล้วตามด้วยบรรทัด at ทีละจุดในโค้ดที่เรียกต่อกันมาจนเกิด error

บรรทัดที่มี node:internal เป็นโค้ดภายในของ Node.js เอง ไม่ใช่โค้ดของคุณ จึงข้ามไปได้ ให้มองหาชื่อไฟล์ของคุณแทน ในตัวอย่างนี้คือ receipt.js บรรทัด 6 และ 9

อย่ามองข้ามบรรทัดก่อน error: ใบเสร็จ #1 และ #2 พิมพ์ออกมาแล้ว แปลว่าโค้ดใช้ได้กับ 2 ออเดอร์แรก และพังที่ออเดอร์ถัดไป ในไฟล์ตัวอย่างของเรา ออเดอร์ที่ 3 ไม่มีข้อมูล customer เลย

บริบท (ข้อ 3) ทำให้ AI เสนอวิธีแก้ต่างกัน

เมื่อ 16 ตุลาคม 2569 เราลองส่ง error นี้ทั้งก้อนให้ Claude 2 แบบ

  • แบบแรก พิมพ์แค่ "แก้ error นี้ให้หน่อย": Claude บอกสาเหตุได้ถูก แต่วิธีแรกที่มันแนะนำคือให้โค้ด ใส่ชื่อสำรองว่า "ลูกค้าทั่วไป" เมื่อไม่มีชื่อ ส่วนการกลับไปแก้ที่ข้อมูลเป็นทางเลือกที่สอง
  • แบบที่สอง เพิ่มบริบทสั้นๆ ว่าเมื่อวานรันได้ปกติ และวันนี้เพิ่งเปลี่ยนไปใช้ไฟล์ออเดอร์ชุดใหม่ที่ export จากระบบหลังร้าน ซึ่งบังคับกรอกชื่อลูกค้าทุกออเดอร์ ครั้งนี้ Claude บอกว่าชื่อน่าจะยังอยู่ในไฟล์ แต่อยู่คนละที่กับที่โค้ดอ่าน จึงให้รันคำสั่งดูข้อมูลก่อน และเขียนเองว่าไม่ใช้วิธีใส่ค่าว่างแทน เพราะจะได้ใบเสร็จที่ไม่มีชื่อลูกค้าออกมาเงียบๆ

เรารันคำสั่งดูข้อมูลที่ Claude ให้มา ได้ {"id":3,"total":300} แปลว่าออเดอร์ที่ 3 ไม่มีชื่อลูกค้าเลย ไม่ได้อยู่คนละที่อย่างที่ Claude เดา Claude เดาผิดส่วนหนึ่งเพราะบริบทที่เราให้ (ระบบบังคับกรอกชื่อ) ไม่ตรงกับความจริงของไฟล์นี้ บริบทจึงต้องเป็นเรื่องจริงที่เรารู้แน่ แต่การดูข้อมูลก่อนก็ทำให้รู้ว่าต้องกลับไปถามระบบหลังร้าน ไม่ใช่ออกใบเสร็จที่ไม่มีชื่อลูกค้า

error เดียวกัน แต่ได้คำแนะนำแรกต่างกัน แบบแรกทำให้ error หายไป แบบที่สองพาไปหาสาเหตุ สิ่งที่ต่างกันคือบริบทสั้นๆ ที่มีแค่คุณรู้

เราลองกับ Claude แบบละ 1 ครั้ง ด้วยข้อมูลสมมติที่เราแต่งขึ้นเอง

ตัวอย่างที่ 2 (Python): บรรทัดที่ error ชี้ ไม่ใช่บรรทัดที่ต้องแก้เสมอ

โปรแกรมนี้รวมยอดขายจากไฟล์ sales.csv ที่มียอดขาย 3 วัน คือ 1200, 950 และ 1430

โค้ด Python
import csv

def read_sales(path):
    with open(path, encoding="utf-8") as f:
        return [row["ยอดขาย"] for row in csv.DictReader(f)]

def total(amounts):
    result = 0
    for a in amounts:
        result += a
    return result

sales = read_sales("sales.csv")
print("ยอดรวม:", total(sales))

เมื่อรัน ได้ผลดังนี้

prompt
Traceback (most recent call last):
  File "/…/demo/total.py", line 14, in [module]
    print("ยอดรวม:", total(sales))
                     ~~~~~^^^^^^^
  File "/…/demo/total.py", line 10, in total
    result += a
TypeError: unsupported operand type(s) for +=: 'int' and 'str'

error ของ Python อ่านจากล่างขึ้นบนจะง่ายกว่า เพราะเอกสารของ Python อธิบายว่า บรรทัดสุดท้ายบอกว่าเกิดอะไรขึ้นและเป็น error ชนิดไหน ส่วนบรรทัดข้างบนคือเส้นทางที่โปรแกรมเดินมาจนถึงจุดนั้น เรียกว่า traceback

ชนิด: TypeError: unsupported operand type(s) for +=: 'int' and 'str' แปลว่า เอาตัวเลข (int) ไปบวกกับตัวหนังสือ (str) ไม่ได้

ตำแหน่ง: error ชี้บรรทัด 10 result += a แต่บรรทัด 10 ไม่ได้ผิด ที่มาของปัญหาคือบรรทัด 5 ที่อ่านยอดขายจากไฟล์มาเป็นตัวหนังสือ "1200" โดยไม่ได้แปลงเป็นตัวเลข

เอกสารของ Python เตือนไว้ในหัวข้อ error ไวยากรณ์ (SyntaxError) ว่าจุดที่ error ชี้ ไม่ใช่จุดที่ต้องแก้เสมอไป ตัวอย่างนี้แสดงว่าเรื่องเดียวกันเกิดกับ error ชนิดอื่นได้ด้วย

เราลองแก้บรรทัด 5 เป็น int(row["ยอดขาย"]) แล้วรันใหม่ ได้ ยอดรวม: 3580 ตรงกับที่คิดเลขเอง ถ้าไปแก้ที่บรรทัด 10 แทน error ก็น่าจะหายเหมือนกัน แต่ส่วนอื่นของโปรแกรมที่ใช้ sales จะยังได้ยอดขายเป็นตัวหนังสืออยู่ (ข้อนี้เราอ่านจากโค้ด ไม่ได้ลองรัน)

ตัวอย่างที่ 3 (Python): โค้ดเดิม ไฟล์เดิม แต่พัง

ใช้โปรแกรมเดียวกับตัวอย่างที่ 2 และไฟล์ sales.csv ยังอยู่ที่เดิม แต่คราวนี้เปิดหน้าต่างพิมพ์คำสั่ง (terminal) ใหม่ แล้วรันจากโฟลเดอร์อื่น ได้ผลดังนี้

prompt
Traceback (most recent call last):
  File "/…/demo/total.py", line 13, in [module]
    sales = read_sales("sales.csv")
  File "/…/demo/total.py", line 4, in read_sales
    with open(path, encoding="utf-8") as f:
         ~~~~^^^^^^^^^^^^^^^^^^^^^^^^
FileNotFoundError: [Errno 2] No such file or directory: 'sales.csv'

ชนิด: FileNotFoundError แปลว่า หาไฟล์ sales.csv ไม่เจอ

ตำแหน่ง: บรรทัด 4 ที่เปิดไฟล์

ถ้าอ่านแค่ 2 ข้อนี้ ข้อสรุปที่ง่ายที่สุดคือ "ไม่มีไฟล์" แต่คุณรู้ว่าไฟล์มีอยู่ บริบทในกรณีนี้คือ "รันจากในโฟลเดอร์นั้นได้ แต่รันจากที่อื่นแล้วพัง" บริบทนี้ชี้ไปที่สาเหตุจริง คือชื่อไฟล์ "sales.csv" ที่ไม่มีที่อยู่เต็มจะถูกหาจากโฟลเดอร์ที่ terminal เปิดอยู่ ไม่ใช่โฟลเดอร์ที่โปรแกรมอยู่

เราลองแล้ว เมื่อรันจากในโฟลเดอร์ที่มีไฟล์ โปรแกรมทำงานปกติ เมื่อรันจากโฟลเดอร์อื่น ได้ error ข้างบน

ส่ง error ให้ AI ใน 4 ขั้น

1. อ่านเองก่อน 1 นาที

หาชนิดและตำแหน่งของ error แม้จะอ่านไม่ออกทั้งหมด แค่รู้ว่าพังที่ไฟล์ไหน บรรทัดไหน ก็พอจะเช็กได้ว่า AI แก้ตรงจุดหรือไม่ หรือไปแก้ไฟล์อื่นที่ไม่เกี่ยวข้อง

2. คัดลอก error มาทั้งก้อน ไม่ตัดส่วนใดออก

คัดลอกบรรทัดที่ขึ้นก่อน error มาด้วย เช่น ใบเสร็จ 2 ใบในตัวอย่างที่ 1 ซึ่งบอกว่าพังที่รายการไหน ถ้าตัดเหลือแค่บรรทัดเดียว AI จะเห็นแค่ชนิด แต่ไม่เห็นตำแหน่งและเส้นทาง

มีข้อยกเว้นเดียว คือถ้าใน error มีรหัสผ่าน กุญแจ API หรือข้อมูลลูกค้าปรากฏอยู่ ให้แทนด้วย [ลบแล้ว] ก่อนวาง

3. เขียนบริบท 3 บรรทัด

ตอบ 3 คำถามนี้สั้นๆ

  • กำลังทำอะไรตอนเกิด
  • เคยใช้ได้ไหม
  • อะไรเปลี่ยนไปก่อนเกิด ถ้าไม่รู้ให้เขียนว่าไม่รู้ อย่าเดา

4. สั่งให้อธิบายก่อนแก้

ให้ AI อธิบายก่อนว่า error แปลว่าอะไร แล้วค่อยเสนอวิธีแก้ และให้บอกด้วยถ้าวิธีแก้แค่ทำให้ error หายไป แต่ไม่ได้แก้ที่ต้นเหตุ อย่างการใส่ชื่อสำรองในตัวอย่างที่ 1

คำสั่งสำเร็จรูปสำหรับส่ง error ให้ AI

คำสั่งนี้รวม 4 ขั้นข้างบนไว้ในที่เดียว เติมข้อความในวงเล็บเหลี่ยมให้ตรงกับงานของคุณ

prompt
error นี้เกิดตอน: [กำลังทำอะไร เช่น สั่งพิมพ์ใบเสร็จ]
ก่อนหน้านี้เคยใช้ได้ไหม: [ได้ / ไม่เคยได้เลย]
สิ่งที่เปลี่ยนไปก่อนเกิด: [เช่น เปลี่ยนไฟล์ข้อมูล อัปเดตโปรแกรม / ไม่รู้]
ที่ฉันอ่านเอง: ชนิด = [...] · ตำแหน่ง = ไฟล์ [...] บรรทัด [...]

ช่วยอธิบายเป็นภาษาง่ายๆ ว่า error นี้แปลว่าอะไร และน่าจะเกิดจากอะไร ก่อนเสนอวิธีแก้
ถ้าต้นเหตุไม่ได้อยู่บรรทัดที่ error ชี้ ให้บอกว่าอยู่ตรงไหน
ถ้าวิธีแก้แค่ทำให้ error หายแต่ซ่อนปัญหาไว้ เช่น ใส่ค่าว่างหรือค่าสำรองแทน ให้บอกตรงๆ

"""
[วาง error ทั้งก้อน ไม่ตัด]
"""

แต่ละส่วนของคำสั่งช่วยอะไร

  • 3 บรรทัดแรกคือบริบทที่ AI เดาเองไม่ได้
  • "ที่ฉันอ่านเอง" ทำให้คุณได้ฝึกอ่าน error
  • การให้อธิบายก่อนแก้ ทำให้ตรวจเหตุผลได้ก่อนรับโค้ด
  • ข้อสุดท้ายป้องกันวิธีแก้แบบกลบอาการ

ถ้าอยากได้ฉบับเต็มที่ให้ AI ตั้งสมมติฐานหลายข้อ พร้อมวิธีพิสูจน์แต่ละข้อก่อนแก้ ดูได้ที่ prompt ฟรี: หาต้นตอของ Bug จาก Error โดยตรวจสอบให้แน่ใจก่อนลงมือแก้ (สำหรับสมาชิกฟรี)

3 เรื่องที่ควรรู้เพิ่มเติม

  • ข้อความ error ต่างกันตามโปรแกรม MDN ยกตัวอย่างว่า ความผิดพลาดแบบเดียวกัน โปรแกรมที่ใช้ V8 (เช่น Chrome และ Node.js) และ Firefox จะขึ้นว่า ReferenceError: "x" is not defined แต่ Safari จะขึ้นว่า ReferenceError: Can't find variable: x ชนิดของ error จึงเชื่อถือได้มากกว่าถ้อยคำ
  • บางครั้งเส้นทางไม่มีไฟล์ของคุณเลย เช่น โปรแกรมพังข้างในโปรแกรมเสริมที่ติดตั้งมา กรณีนี้ข้อ 3 (บริบท) สำคัญที่สุด ให้บอกว่าคุณกดอะไรหรือสั่งอะไรก่อนเกิด error
  • AI ก็อ่าน error ผิดได้ ถ้า AI ไปแก้ไฟล์หรือบรรทัดที่ไม่ตรงกับที่คุณอ่านเจอ ให้ถามว่าทำไมก่อนรับโค้ด

สรุป

error มี 3 ส่วนที่ต้องหา คือ ชนิด ตำแหน่ง และบริบท 2 อย่างแรกอยู่บนจอ อย่างที่ 3 อยู่ในหัวคุณ ก่อนส่งให้ AI ให้อ่านเองก่อน 1 นาที คัดลอกมาทั้งก้อน เขียนบริบท 3 บรรทัด แล้วให้ AI อธิบายก่อนแก้

ตอนถัดไปในซีรีส์ว่าด้วย Git ซึ่งเป็นเหมือนจุดเซฟเกมของคนเขียนโค้ด ถ้าแก้ตาม AI แล้วพังกว่าเดิม Git ช่วยให้ย้อนกลับไปจุดที่ยังใช้ได้

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

อาทิตย์ละสกิล เดี๋ยวก็เก่ง