1 คะแนน โดย GN⁺ 2026-02-02 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • กรณีศึกษาระหว่างการพัฒนาแอปพลิเคชันสร้างรายงานที่เพิ่มตัวเลือก –dry-run เพื่อให้สามารถจำลองผลลัพธ์การทำงานได้
  • ตัวเลือกนี้จะแสดงว่างานใดจะถูกดำเนินการบ้างโดยไม่มีการเปลี่ยนแปลงจริง ทำให้สามารถ ทดสอบได้อย่างปลอดภัยและรับฟีดแบ็กได้รวดเร็ว
  • นักพัฒนาสามารถใช้สิ่งนี้เพื่อตรวจสอบการตั้งค่า การเข้าถึง และสถานะของระบบได้ทันที และนำไปใช้เป็น เครื่องมือตรวจสอบประจำวัน
  • ข้อเสียที่กล่าวถึงคือ ความซับซ้อนที่เพิ่มขึ้นเล็กน้อย จากการต้องตรวจสอบแฟล็ก dryRun ภายในโค้ด
  • ในแอปพลิเคชันแบบสั่งงาน ฟังก์ชัน –dry-run มีประโยชน์มาก และยิ่งนำมาใช้ตั้งแต่ช่วงต้นของโปรเจ็กต์ ก็ยิ่งช่วยเพิ่มประสิทธิภาพการพัฒนา

ภูมิหลัง

  • แอปพลิเคชันสร้างรายงานที่กำลังพัฒนาใหม่ มีโครงสร้างการทำงานคือสร้างรายงานทุกวันในวันทำการ จากนั้นบีบอัดและอัปโหลดไปยังเซิร์ฟเวอร์ sftp ตรวจสอบการตอบกลับข้อผิดพลาด และส่งอีเมลแจ้งเตือน
    • ไฟล์ที่สร้างขึ้นและไฟล์ฟีดแบ็กในแต่ละขั้นตอนจะถูกย้ายไปยังไดเรกทอรีที่ต่างกันตามลำดับขั้น
  • ในช่วงเริ่มต้นการพัฒนา จึงนึกถึงตัวเลือก –dry-run ของ Subversion และคำสั่ง ลินุกซ์หลายตัว แล้วเพิ่มความสามารถแบบเดียวกันเข้าไป
    • ตัวเลือกนี้จะแสดงว่าเมื่อรันแล้วจะเกิดอะไรขึ้น โดยไม่มีการเปลี่ยนแปลงจริง
  • เมื่อรันด้วย –dry-run ระบบจะแสดงเป็นลำดับขั้นว่ารายงานใดจะถูกสร้าง รายงานใดจะถูกยกเว้น ไฟล์ใดจะถูกบีบอัดและย้าย และไฟล์ใดจะถูกอัปโหลดหรือดาวน์โหลดผ่าน sftp

การใช้งานและข้อดี

  • เป็นฟังก์ชันที่มีประโยชน์มากจนถูก ใช้งานทุกวันระหว่างการพัฒนาและทดสอบ
  • เมื่อนำมาใช้เพื่อตรวจสอบสถานะก่อนรัน จะสามารถยืนยันการตั้งค่า การเข้าถึง และสถานะของระบบได้ทันที
    • เนื่องจากไม่มีการเปลี่ยนแปลงจริง จึงสามารถรันได้อย่างปลอดภัย
  • หลังจากเปลี่ยนวันที่ในไฟล์สถานะของรายงาน ก็สามารถ ตรวจสอบได้ทันที ว่ารายงานนั้นจะถูกสร้างหรือไม่
    • การสร้างรายงานจริงใช้เวลา แต่ dry-run ให้ฟีดแบ็กได้อย่างรวดเร็ว
  • แม้ในการทดสอบระบบทั้งหมด ก็ยังช่วยให้มี วงจรการตรวจสอบที่รวดเร็ว

ข้อเสีย

  • เนื่องจากต้อง ตรวจสอบแฟล็ก dryRun ซ้ำๆ ภายในโค้ด จึงเกิดความรกของโค้ดขึ้นเล็กน้อย
    • ในแต่ละขั้นตอนหลักจะต้องตรวจสอบแฟล็กเพื่อแสดงเพียงล็อกแทนการทำงานจริง
  • อย่างไรก็ตาม การตรวจสอบนี้ไม่ได้ลึกมาก และไม่จำเป็นต้องมีการจัดการเพิ่มเติมภายในลอจิกการสร้างรายงาน
    • ตรวจสอบเฉพาะในขั้นตอนระดับบนที่ใช้ตัดสินใจว่าจะรันจริงหรือไม่

บทสรุป

  • แอปพลิเคชันที่ทำงานแบบสั่งการและสร้างผลลัพธ์ขึ้นมานั้น เหมาะกับตัวเลือก –dry-run มาก
    • ในทางกลับกัน แอปพลิเคชันเชิง reactive ที่รอข้อความเข้ามาไม่เหมาะกับแนวทางนี้
  • การเพิ่มฟังก์ชันนี้ตั้งแต่ช่วงต้นของโปรเจ็กต์ ช่วยเพิ่มประสิทธิภาพการพัฒนาได้มาก
  • แม้จะไม่ใช่ฟังก์ชันที่จำเป็นในทุกสถานการณ์ แต่ก็ถือเป็น เครื่องมือที่มีประโยชน์มากเมื่อใช้ถูกกรณี

1 ความคิดเห็น

 
GN⁺ 2026-02-02
ความคิดเห็นจาก Hacker News
  • เมื่อโต้ตอบกับระบบที่มีสถานะ --dry-run ก็อาจเกิด race condition ได้
    เครื่องมือจะแสดงว่า “จะทำอะไร” ตามสถานะปัจจุบัน แต่เมื่อถึงเวลารันจริง สถานการณ์อาจเปลี่ยนไปแล้ว
    เพราะแบบนี้ฉันจึงชอบแนวทาง โหมด “plan” ของ Terraform มากกว่า โหมดนี้จะสร้างแผนที่นำไปใช้รันได้จริง และถ้าสมมติฐานตอนวางแผนเปลี่ยนไป ก็สามารถหยุดหรือ rollback ได้
    อีกทั้งยังไม่ต้องใส่ if dry_run: กระจายไปทั่วโค้ด และสามารถแยกการวางแผนกับการรันออกจากกันให้เรียบง่ายเป็นรูปแบบ execute(plan())

    • เคยมี กรณีระบบ DNS ของ AWS ล่ม ที่มีสาเหตุคล้าย race condition แบบนี้
      เกิดปัญหาเรื่องจังหวะเวลาระหว่าง DNS Planner กับ Enactor จนแผนเก่าไปเขียนทับแผนใหม่ล่าสุด
      มีการพูดถึงเรื่องนี้ใน เธรด HN ก่อนหน้า ด้วย
    • ถ้าทำแบบนี้ สุดท้ายก็เหมือนกำลังสร้างทั้ง compiler (สเปก→แผน) และ virtual machine (แผน→การรัน)
    • แนวทางนี้เหมาะมากกับเครื่องมือโครงสร้างพื้นฐานอย่าง Terraform หรือ Ansible แต่สำหรับเครื่องมือรายงานแบบง่าย ๆ อาจทำให้เกิด ความซับซ้อนเกินจำเป็น
      เพราะการทำโหมด plan ต้องมีภาษาเฉพาะโดเมนหรือโครงสร้างข้อมูลรองรับ
    • ฉันเองก็กำลังทำสคริปต์ที่แก้ไขไฟล์สำคัญอยู่ และใช้แนวทางนี้เช่นกัน
      (1) จับสถานะของระบบไฟล์แล้วบันทึกแผน → (2) ตรวจว่าสถานะยังไม่เปลี่ยนก่อนรันและบันทึกล็อก → (3) เปรียบเทียบกับสถานะก่อนหน้าเพื่อตรวจสอบว่ามีการสูญหายของข้อมูลหรือไม่
      ตอนนี้แยกสามขั้นตอนนี้เป็นสคริปต์หรือแฟล็กคนละตัว
    • ถ้าอย่างนั้นก็น่าสงสัยว่าจะเอาโหมดวางแผนแบบนี้ไปใช้กับคำสั่ง rm ได้อย่างไร
  • ถ้าเครื่องมือไหนไม่มี --dry-run บางครั้งก็ทำขึ้นมาใช้เอง
    ตัวอย่างเช่น ก่อนรันคำสั่ง sed ที่ซับซ้อน จะใช้ diff เปรียบเทียบการเปลี่ยนแปลงล่วงหน้า
    สามารถดูความต่างได้ด้วยคำสั่งอย่าง diff -u <(echo "hello") <(echo "hello" | sed "s/hello/hi/g")
    ฉันรวบรวมเรื่องนี้ไว้ใน บล็อกของฉัน

  • ฉันชอบแพตเทิร์น --dry-run แต่ โค้ดในเส้นทาง dry ต้องทำงานเหมือนกับเส้นทางจริง
    ถ้าแค่พิมพ์ว่า “จะทำอะไร” แล้วข้าม logic จริงไป ก็อาจพลาดบั๊กตอนรันจริงได้
    ควรให้ทำงานเหมือนกันทั้งหมดจนถึงก่อนการเขียนฐานข้อมูลหรือการเรียก API

    • แต่บางคนมองว่านี่คือการ สับสนระหว่าง integration test กับ dry run
      dry run มีไว้เพื่อแสดงว่า “จะเกิดอะไรขึ้น” ส่วนการทดสอบจริงเป็นอีกเรื่องหนึ่ง
  • ในทางกลับกัน ฉันชอบใช้แฟล็ก --commit หรือ --execute แล้วให้การรันปกติเป็นแบบ อ่านอย่างเดียว (dry) มากกว่า
    แบบนี้จะลดโอกาสที่เผลอทำการเปลี่ยนแปลงจริงโดยไม่ตั้งใจ

    • ฉันใช้วิธีนี้มา 8 ปีแล้ว และมันปลอดภัยดีเพราะต้องระบุ --commit อย่างชัดเจนถึงจะมีการเปลี่ยนแปลง
      ตรงกันข้าม เคยมีหลายครั้งที่ลืมใส่ --dry-run แล้วเกิดปัญหา
    • เครื่องมือลบข้อมูลซ้ำในไดเรกทอรี ของฉันก็ใช้แพตเทิร์นนี้
      ค่าเริ่มต้นจะเปรียบเทียบอย่างเดียว และต้องใส่ --execute ถึงจะเปลี่ยนเป็น hard link จริง
    • เครื่องมือบางตัวที่ฉันเคยใช้ ยังต้องให้พิมพ์ข้อความเฉพาะก่อนรันจริงด้วย
      ขั้นตอนยืนยันแบบนี้ช่วยลดความผิดพลาดได้มาก
    • ส่วนตัวฉันยังชอบแฟล็กอย่าง --wet-run ด้วย บางสถานการณ์แฟล็กที่มีความหมายตรงข้ามกลับเข้าใจง่ายกว่า
    • สคริปต์ที่เพิ่งทำล่าสุดก็ตั้งค่าเริ่มต้นเป็นอ่านอย่างเดียว และถ้าจะลบบัญชีจริงต้องพิมพ์ DELETE-ACCOUNT เอง
      จนถึงตอนนี้ยังไม่เคยลบบัญชีผิดพลาดเลยสักครั้ง
  • ถ้าอยากหลีกเลี่ยงการทำให้โค้ดปนเปื้อน ควรแยก persistence ออกมาเป็นกลยุทธ์ที่ inject ได้
    การใส่ if dry_run: กระจายไปทั่วไม่ใช่แนวทางที่ดี
    อันที่จริง การบังคับให้รัน production แบบชัดเจนด้วย --wet-run อาจปลอดภัยกว่า

    • ถ้าสร้างแบบจำลอง พฤติกรรมของแอปพลิเคชันอย่างชัดเจน และจัดการสิ่งนี้จากศูนย์กลาง ก็จะดีมาก
      แบบนี้จะตัดสินเรื่อง dry run ได้จากจุดเดียว — เป็นสไตล์ “functional core, imperative shell”
    • แต่การต้องพิมพ์อะไรอย่าง rm --wet-run tempfile.tmp ทุกครั้งก็ค่อนข้างน่ารำคาญ
      อาจดีกว่าถ้าให้ค่าเริ่มต้นเป็นรันจริง แล้วมีตัวเลือก --undo ไว้ย้อนงานล่าสุด
    • ฉันไม่ค่อยชอบชื่อ --wet-run เท่าไร แต่ก็เคยใช้วิธีตั้งค่าเริ่มต้นเป็น dry-run แล้วต้องระบุ --no-dry-run ถึงจะมีการเปลี่ยนแปลงจริง
      ถ้าเป็นบริการ ระบบควรเลือก safe mode ให้อัตโนมัติตามสภาพแวดล้อมที่รันอยู่ เช่น dev/prod
    • ในกรณีแบบนี้ การใช้ design pattern จะช่วยให้โครงสร้างสะอาดขึ้น
  • ในบทความมีประโยคว่า “เพิ่ม --dry-run ไว้ตั้งแต่แรก แล้วพบว่ามีประโยชน์เกินคาด”
    จริง ๆ แล้วแฟล็กแบบนี้มักเป็นสิ่งที่ AI coding agent (เช่น Claude) เสนอให้อัตโนมัติบ่อยมาก
    ทุกวันนี้ที่เครื่องมือ CLI หลายตัวมีแพตเทิร์นคล้ายกัน อาจเป็นผลจาก การลู่เข้าของโค้ดที่ขับเคลื่อนโดยเอเจนต์ ก็ได้

    • แต่ผู้เขียนก็ระบุเองชัดเจนว่าได้แรงบันดาลใจจาก --dry-run ของ Subversion ดังนั้นก็ถือว่าเป็นเหตุผลที่น่าเชื่อถือมากพอ
  • ฉันมักเพิ่มแฟล็ก --really ให้กับยูทิลิตี CLI และตั้งค่าเริ่มต้นเป็นอ่านอย่างเดียว
    จุดประสงค์คือให้มี ขั้นตอนยืนยันโดยเจตนา เพื่อป้องกันความผิดพลาด

    • ฉันเคยมีคำสั่งที่ใช้แฟล็ก --i-meant-that มาก่อนด้วย
      มันเป็นคำสั่งลบเครื่องระยะไกล โดยค่าเริ่มต้นจะรอ 10 วินาทีเพื่อเปิดโอกาสให้ยกเลิก
      โชคดีที่ไม่เคยมีใครใช้แฟล็กนี้ผิดเลย
  • ข้อดีอย่างหนึ่งของ PowerShell คือแค่เพิ่ม [CmdletBinding(SupportsShouldProcess)] เพียงบรรทัดเดียว
    ก็จะได้ฟีเจอร์ dry run ผ่าน -WhatIf โดยอัตโนมัติ เป็น ความสามารถที่สะดวกมาก

    • นอกจากนี้ -Confirm ก็จะถูกเปิดใช้งานด้วย และสามารถโต้ตอบกับ เกณฑ์การยืนยันของผู้ใช้ ผ่านฟังก์ชัน ShouldProcess ได้ด้วย เป็นการออกแบบที่ยอดเยี่ยมมาก
  • ใน CLI ภายในที่ฉันดูแล ฉันจะใส่ if not dry_run: ไว้ ภายในส่วนเรียก REST API
    แบบนี้แทนที่จะยิงคำขอจริง ก็จะเก็บ ล็อกคำสั่ง CURL ไว้ให้ดูว่า request ไหนจะถูกส่งออกไป
    แต่ถ้าการเชื่อมต่อกันระหว่าง API ซับซ้อนขึ้น การจำลองก็จะยากขึ้นและซับซ้อนกว่า if not dry_run: ธรรมดามาก

    • ถ้าจัดโครงสร้างให้มี จุดเดียวที่ทำงานจริง ได้มากที่สุด ก็จะช่วยไม่ให้โค้ดปนเปื้อน
      ฉันดูแล CLI สำหรับ automation pipeline อยู่หลายตัว และใช้แพตเทิร์นนี้กับแทบทุกเครื่องมือ
    • แต่ก็มีความเห็นว่าการใช้ REST มากเกินไปในเครื่องมือคอนโซลนั้นไม่มีประสิทธิภาพ
      สิ่งสำคัญคือควรทำเครื่องมือโลคัลให้ดีตั้งแต่แรก
  • ถ้าแฟล็ก --dry-run กระจายอยู่ทั่วทั้งโค้ดเบส ควรใช้ แพตเทิร์น state machine เพื่อแยกแต่ละขั้นตอนให้ชัดเจน