Doubt-Driven Development
เช็กลิสต์ของ Fame ที่ตั้งบนความจริงข้อเดียว: โค้ดที่ รันได้ ไม่ได้แปลว่า ถูก ยิ่ง AI ช่วยเขียนเร็วขึ้นเท่าไหร่ ความสงสัยที่ถูกจุดก็ยิ่งสำคัญขึ้นเท่านั้น ก่อนจะมั่นใจว่าเสร็จ ให้สงสัยสี่จุดนี้ก่อนทุกครั้ง
- 01
Imports
การ import ที่ผิดเงียบ ๆ
“ฉันแน่ใจหรือว่า import ตัวที่ใช้อยู่ คือตัวที่คิดว่าใช้”
อาการimport มาผิดโมดูล, import ชื่อชนกัน, หรือ import ของที่ deprecated โค้ดรันได้แต่พฤติกรรมไม่ตรง โดยเฉพาะเมื่อ AI เดาชื่อ package ขึ้นมาเอง
สิ่งที่ต้องตรวจเปิดดูว่า symbol ที่ใช้มาจากไหนจริง ๆ ตรวจว่า package มีอยู่และเวอร์ชันตรง อย่าเชื่อว่าชื่อที่ดูคุ้นคือตัวที่ถูก
imports.pyPython1# AI มักเดาชื่อฟังก์ชันที่ "ฟังดูถูก" แต่ไม่มีจริง2# ❌ from utils import parse_amount # ฟังก์ชันนี้มีจริงไหม3# ❌ import pandas as np # alias สลับ จะพังลึก ๆ45# ✅ ยืนยันที่มาก่อนใช้6from decimal import Decimal # มาจาก stdlib แน่นอน7from app.parsers import parse_amount # path จริงในโปรเจกต์เรา89assert callable(parse_amount), "import ผิดตัวแล้ว" - 02
Path Traps
กับดักของ path
“path นี้ยังถูกอยู่ไหม ถ้ารันจากที่อื่น หรือบน server จริง”
อาการrelative path ที่อิงกับ current working directory พังทันทีเมื่อรันจากโฟลเดอร์อื่น, ใน container, หรือใน worker ที่ cwd ต่างจากตอน dev
สิ่งที่ต้องตรวจอิง path กับตำแหน่งไฟล์เสมอ ไม่ใช่ cwd ใช้ absolute path ที่คำนวณจาก __file__ / import.meta.url และตรวจว่าไฟล์มีจริงก่อนใช้
path-traps.pyPython1from pathlib import Path23# ❌ พังเมื่อ cwd ไม่ใช่ราก project4# config = open("config/banks.json")56# ✅ อิงตำแหน่งไฟล์นี้ ไม่ใช่ cwd7BASE_DIR = Path(__file__).resolve().parent8config_path = BASE_DIR / "config" / "banks.json"9assert config_path.exists(), f"ไม่พบไฟล์: {config_path}"10config = config_path.read_text(encoding="utf-8") - 03
Async Mismatch
async ที่ใส่ไม่ครบ
“ฉันลืม await ตรงไหนไหม กำลังปน sync กับ async อยู่หรือเปล่า”
อาการลืม await ทำให้ได้ coroutine object แทนผลจริง, เรียกฟังก์ชัน blocking ใน event loop, หรือ mix sync client กับ async framework จน latency พุ่งหรือค่าผิดเงียบ ๆ
สิ่งที่ต้องตรวจทุก call ที่เป็น async ต้องมี await, งาน CPU/blocking ต้องไปอยู่ใน executor หรือ worker, และอย่าเรียก sync DB client ใน async handler
async-mismatch.pyPython1# ❌ ลืม await - ได้ coroutine ไม่ใช่ผลลัพธ์2# result = fetch_slip(job_id) # <coroutine object ...>3# if result.amount > 0: ... # AttributeError ลึก ๆ45# ✅ await ให้ครบ6result = await fetch_slip(job_id)78# ✅ งาน blocking ย้ายออกจาก event loop9import asyncio10loop = asyncio.get_running_loop()11hashed = await loop.run_in_executor(None, compute_phash, raw_bytes) - 04
Env Ghost
ผีของ environment variable
“ค่านี้มีจริงตอน production ไหม หรือมีแค่บนเครื่องฉัน”
อาการโค้ดทำงานบนเครื่อง dev เพราะมี .env แต่พังบน production เพราะ env var ไม่ถูก set ค่าเป็น None/empty แล้วลามไปทั้งระบบ - ตัวร้ายที่สุดเพราะ 'รันได้บนเครื่องฉัน'
สิ่งที่ต้องตรวจตรวจ env var ที่จำเป็นตอน startup ให้ fail-fast พร้อมข้อความชัดเจน อย่าใช้ค่า default เงียบ ๆ สำหรับ secret และห้าม commit ค่าจริง
env-ghost.pyPython1import os23REQUIRED = [4 "DATABASE_URL", "REDIS_URL",5 "DISCORD_WEBHOOK_URL", "MODEL_API_KEY",6]78def assert_env() -> None:9 missing = [k for k in REQUIRED if not os.environ.get(k)]10 if missing:11 # fail-fast ตอน boot ดีกว่าพังกลางทางบน production12 raise RuntimeError(f"ENV หาย: {', '.join(missing)}")1314# เรียกตอน startup ก่อนรับ traffic15assert_env()
เมื่อผ่านทั้งสี่จุดแล้ว คุณยังไม่ได้พิสูจน์ว่าโค้ดถูก คุณแค่ลดโอกาสที่มันจะผิดในแบบที่พบบ่อยที่สุด ความสงสัยไม่ใช่ความไม่มั่นใจ มันคือวินัย รันเทสต์ อ่าน log จริง แล้วค่อยบอกว่าเสร็จ
กลับไปเรียนต่อ