4 คะแนน โดย GN⁺ 2025-08-08 | 1 ความคิดเห็น | แชร์ทาง WhatsApp
  • เป็นการแบ่งปันรายชื่อ ความรู้ต้องสาป ที่เกิดขึ้นในกระบวนการพัฒนา Immich
  • สรุป ปัญหาที่ไม่คาดคิด ที่พบในซอฟต์แวร์และสภาพแวดล้อมโครงสร้างพื้นฐานที่หลากหลาย
  • กล่าวถึงปัญหากับเครื่องมือและภาษาเช่น เมตาดาต้า EXIF, การจัดการช่องว่างของ YAML และ PostgreSQL
  • บางเรื่องเชื่อมโยงกับ ความปลอดภัย, ความเข้ากันได้ของแพลตฟอร์ม, และการพึ่งพาซอฟต์แวร์โอเพนซอร์ส โดยตรง
  • มุ่งเน้นที่ กรณีจริงและสาเหตุ ที่นักพัฒนาควรระวัง

ภาพรวม

ทีมพัฒนา Immich เปิดเผยรายการ ความรู้ต้องสาป ที่ไม่อยากเจออีกครั้งจากประสบการณ์ในระหว่างพัฒนาโปรเจกต์ ซึ่งเป็นการเก็บรวบรวม กับดักและปัญหาที่ไม่คาดฝัน ที่พบจากการใช้งานเครื่องมือ ภาษา และแพลตฟอร์มหลากหลายขณะพัฒนาและดำเนินงานบริการจริง

รายการความรู้ต้องสาป

  • วันที่ 4 มิถุนายน 2025

    • ฟีเจอร์ของ Zitadel Actions เป็นความรู้ที่เป็นอุปสรรค
    • ฟังก์ชัน custom scripting ของ Zitadel อิงเครื่องยนต์ JS แต่ ไม่รองรับ named capture group ของ regular expression ทำให้มีข้อจำกัดที่ชัดเจน
  • วันที่ 30 พฤษภาคม 2025

    • Microsoft Entra รองรับ PKCE แต่ไม่ได้ระบุไว้ในเอกสาร OpenID discovery
    • ส่งผลให้ความสามารถนี้ ไม่ถูกตรวจจับโดยไคลเอนต์
  • วันที่ 5 พฤษภาคม 2025

    • ข้อมูลขนาดใน EXIF metadata ของรูปภาพอาจต่างจากขนาดจริงของไฟล์รูปจริง
    • ความคลาดเคลื่อนนี้นำไปสู่ข้อผิดพลาดในงาน crop และ resize
  • วันที่ 1 เมษายน 2025

    • การจัดการ ช่องว่างของ YAML มักทำงานต่างจากที่คาด
    • เนื่องจากไวต่อการจัดรูปแบบ ทำให้มีความเสี่ยงที่เนื้อหาถูกตีความไม่ตรงตามเจตนา
  • วันที่ 20 กันยายน 2024

    • ไฟล์ซ่อนของ Windows ไม่สามารถเปิดด้วยแฟล็ก w
    • เมื่อรวมกับตัวเลือก SMB hide dot files จะทำให้เกิดความสับสนมากขึ้นในการเข้าถึงและประมวลผลไฟล์
  • วันที่ 7 สิงหาคม 2024

    • สคริปต์ Bash อาจเกิดปัญหา carriage return (CRLF)
    • หาก Git แปลง LF เป็น CRLF โดยอัตโนมัติระหว่าง checkout อาจทำให้สคริปต์ทำงานผิดพลาด
  • วันที่ 7 สิงหาคม 2024

    • ใน Cloudflare Workers, การเรียก fetch ใช้ http เป็นค่าเริ่มต้นแม้จะระบุ https ไว้
    • ส่งผลให้เกิดปัญหาเครือข่ายเช่น redirect loop
  • วันที่ 21 กรกฎาคม 2024

    • การแชร์ GPS บนมือถือ จะแบบเงียบๆ ลบข้อมูลตำแหน่งออกจากรูปเมื่อแอปไม่มีสิทธิ์เข้าถึงตำแหน่ง
    • ส่งผลต่อความแม่นยำของบริการพึ่งพาตำแหน่งและเรื่องความเป็นส่วนตัว
  • วันที่ 3 กรกฎาคม 2024

    • PostgreSQL NOTIFY ทำงานได้เฉพาะภายใน transaction
    • หากใช้ร่วมกับ socket.io postgres-adapter จะเกิดการเขียน WAL ทุกๆ 5 วินาที ทำให้เกิดภาระสูงขึ้น
  • วันที่ 3 กรกฎาคม 2024

    • การรันสคริปต์ npm จะส่งคำขอ http ไปยัง npm registry ทุกครั้ง
    • ดังนั้นการทำ health check ด้วยสคริปต์จึงไม่ค่อยมีประสิทธิภาพ
  • วันที่ 28 มิถุนายน 2024

    • ในชุมชน JavaScript มีผู้ใช้บางราย บังคับเพิ่มการพึ่งพาแพ็กเกจกว่า 50 ตัว โดยอ้างเหตุผลเรื่อง "ความเข้ากันได้ย้อนหลัง"
    • แพ็กเกจทั้งหมดถูกดูแลโดยผู้ใช้นั้นเพียงคนเดียว
  • วันที่ 25 มิถุนายน 2024

    • การใช้งาน bcrypt รองรับเฉพาะ 72 ไบต์แรกของสตริงเท่านั้น
    • ตัวอักษรที่เหลือจะถูก ข้าม ทำให้รหัสผ่านที่ยาวกว่านี้ไม่มีความหมายเพิ่ม
  • วันที่ 31 มกราคม 2024

    • JavaScript Date object จะแสดงค่าปีและวันที่ด้วย index เริ่มจาก 1 แต่เดือนเริ่มจาก 0
    • โครงสร้างนี้ทำให้สับสนได้ง่าย
  • วันที่ 9 มกราคม 2024

    • ใน Node.js ก่อน v20.8 หากโครงการ CommonJS ใช้ตัวเลือก --experimental-vm-modules แล้วโมดูล ES โหลดโมดูล CommonJS กลับเข้าไป
      • เกิดปัญหา segfault ทำให้ Node.js ล้มเหลว/Crash
  • วันที่ 28 ธันวาคม 2023

    • ขีดจำกัดพารามิเตอร์ของ PostgreSQL คือ 65,535
    • เป็นข้อจำกัดด้านประสิทธิภาพในงาน bulk insert ของชุดข้อมูลขนาดใหญ่
  • วันที่ 26 มิถุนายน 2023

    • มี Web API บางตัวที่ใช้ได้เฉพาะใน Secure Contexts เท่านั้น
    • ตัวอย่างเช่น Clipboard API จะทำงานได้เฉพาะบนสภาพแวดล้อม https หรือ localhost
  • วันที่ 23 กุมภาพันธ์ 2023

    • การทำงานของ remove ใน TypeORM มีผลต่ออินพุตที่ส่งเข้าไป
    • มันอาจลบ คุณสมบัติ id ของอ็อบเจกต์ต้นทาง ไปด้วย

สรุป

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

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

 
GN⁺ 2025-08-08
ความคิดเห็นจาก Hacker News
  • ตั้งแต่แรกที่เห็นก็ชอบมาก หลังจากไล่ดู commit ตัวอย่าง (ที่นี่) แล้วยิ่งชอบขึ้น โดยเฉพาะจุดที่บันทึก “ความรู้ต้องสาป” ไว้พร้อมกับโค้ดที่ใช้แก้ปัญหา สิ่งนี้ทำให้คิดทันทีว่าฟีเจอร์แบบนี้จำเป็นในทุกโปรเจกต์ ข้อมูลในล็อกไม่ใช่แค่การระบายอารมณ์ แต่มันช่วยเปลี่ยนปัญหาหัวทิ่มให้กลายเป็นประสบการณ์การเรียนรู้เชิงบวกได้ เมื่อเปิดเผยต่อสาธารณะจะช่วยให้คนที่เจอปัญหาเดียวกันรู้สึกเชื่อมโยงกันได้ และอาจกลายเป็นเครื่องมือป้องกันปัญหานี้เกิดซ้ำในอนาคตด้วย

    • โดยปกติผมชอบเขียนข้อมูลพวกนี้ไว้ตรงๆ ใน commit message เวลาคนไหนอ่านโค้ดเพียงแค่ดูไม่กี่บรรทัดแล้วคิดว่า “ทำไมเขียนลวกๆ ขนาดนี้นะ? ทำแค่อย่างนั้นก็พอไม่ใช่เหรอ?” การมีคำอธิบายไว้ตรงๆ ทันทีก็ช่วยได้มาก
  • ตอนที่เห็นว่า “ไม่สามารถ bind PostgreSQL placeholder ได้ถึง 65,000 ตัวใน query เดียว” แล้วตกใจมาก ที่แรกๆ นี้ไม่ใช่ความคิดที่ดีอยู่แล้ว จึงแทบไม่ควรโทษ PostgreSQL เลย จากคอมเมนต์ issue ใน GitHub ดูเหมือนว่าพวกเขาทำ ORM ให้รีแฟกเตอร์ โดยแบ่ง query ใหญ่เป็นหลาย query เล็กๆ ซึ่งเป็นทางเลือกที่สมเหตุสมผล สำหรับผมแล้วรู้สึกว่าแต่ละ query ควรมีประมาณ 3,000~5,000 แถวก็พอแล้ว มีคนแนะนำว่าวิธีอัปโหลดข้อมูลลง TEMP table ก่อน แล้วจึง join ทีหลัง (โดยเฉพาะ COPY … FROM) จะเร็วกว่า แต่การเปลี่ยนโค้ดมากเกินไปจึงทำให้สุดท้ายยกเลิกกลยุทธ์นั้นไปได้ง่ายๆ โดยรวมแล้วผมคิดว่าเป็นโมดูลที่ดีมากที่รวบรวมเรื่องราวจากประสบการณ์จริง ได้ประโยชน์มาก เหมาะเป็นกรณีเตือนความเสี่ยง

    • พอเห็นว่ามีคนพูดว่า “ตัวความพยายามเองก็คือไอเดียที่ต้องสาป” ผมก็เห็นด้วย เมื่ออ่านครบทั้งลิสต์แล้วรู้สึกว่า “รายชื่อความรู้ต้องสาป” นี่ไม่ใช่แค่จุดตันหรือกับดักทางสถาปัตยกรรม แต่เป็นบทเรียนที่ผู้พัฒนาทดสอบผ่านการชนเข้ากับปัญหาไปเอง คำอธิบายแต่ละชิ้นอาจไม่สมบูรณ์เท่ากัน และบางอย่างยังคงเป็นกระบวนการต่อเนื่องอยู่ แต่ถ้าเข้าใจว่าเป็นบันทึกประสบการณ์ในวิศวกรรมส่วนตัว มันจะมีคุณค่ามากขึ้น

    • รู้สึกคล้ายกับการพยายามประมวลผลชื่อไฟล์ทุกไฟล์ในระบบไฟล์ด้วยเครื่องมืออย่าง xargs ตอนที่ไม่มีตัวคั่น NUL พร้อมกันครั้งเดียว ถ้าชื่อไฟล์มีความประหลาดหรือเสียหาย และ/หรือหน่วยความจำไม่เหลือพอ ก็จะมีปัญหา ดังนั้นควรใช้ find -print0 และเครื่องมืออย่าง parallel -0/xargs -0 แทน นอกจากนี้ sed, grep ถ้าใช้โดยไม่ตั้ง LC_ALL=C ก็ต้องระวังความผิดพลาดจากลำดับอักขระ multibyte ได้เช่นกัน

    • ผมเคยเจอ error เรื่องการ upsert records จำนวนมากด้วย ORM และก้อน binding 65,000 ตัวด้วยตัวเองเลย โดยเฉพาะเมื่อมีคอลัมน์ SQL array ในตาราง เราต้อง bind ค่าในแต่ละรายการที่ insert ทำให้จำนวนตัวแปรที่ต้อง bind แกว่งไปมาได้ จึงเกิดสถานการณ์ที่แม้รันสองครั้ง ตัวแถว/คอลัมน์ดูเหมือนเท่ากัน แต่จำนวนตัวแปรที่ต้อง binding กลับต่างกัน

    • อีกทางเลือกคือส่งค่าผ่านพารามิเตอร์แบบ array (เช่น text[] หรือ int[]) PostgreSQL ก็รองรับได้ดี แม้ ANY() จะช้ากว่า IN() เล็กน้อย แต่ช่วยเก็บหลาย ID ไว้ใน parameter เดียวได้ อาจเป็นได้ว่า ORM อาจไม่รองรับวิธีนี้

    • จุดนี้ก็สะดุดผมเหมือนกัน การผูกพารามิเตอร์จำนวนมากแบบนั้นชัดเจนว่า “ต้องสาป” สำหรับงานปริมาณมากโดยทั่วไปน่าจะต้องใช้ COPY เกือบทุกครั้ง ถ้าจะเพิ่มกรณี Postgres ที่ต้องสาปอีกอย่าง คือชื่อ prepared statement ถูกตัดอย่างเงียบๆ ให้เหลือแค่ NAMEDATALEN-1 (NAMEDATALEN คือ 64) เรื่องนี้มีมาตั้งแต่ปี 2001 และก็มีมาก่อนหน้าแล้วด้วย ORMs ต้องเข้าใจจุดนี้ให้ครบ ผู้ใช้ทั่วไปแทบไม่ค่อยตั้ง prepare name เกิน 60 ตัวอักษร แต่ ORM ไม่เหมือนคนทั่วไป

  • การเพิ่มแพ็กเกจอีก 50 แพ็กเกจเป็นเรื่องช็อกมาก ตัวผู้ดูแลแพ็กเกจนั้นคงยกระดับจำนวนดาวน์โหลดขึ้นมามหาศาลมาก คิดแล้วเสียดายมากสำหรับ bandwidth และพื้นที่ดิสก์ที่ถูกใช้อย่างเปล่าฝั่งโลก หวังว่าไม่ได้ทำเพื่อการสะสมชื่อเสียงเกินไป

    • ผู้ดูแลแพ็กเกจที่ถูกชี้ว่าเป็นตัวอย่าง “ความรู้ต้องสาป” ในกรณีนี้เป็นสมาชิก TC39 และเป็นคนที่หลายครั้งอยู่กลางกระแสถกเถียงในโปรเจกต์ JavaScript ที่มีชื่อเสียง มีข้อเสนอมาว่าเค้าคิดเรื่องเงินในประเด็น polyfill บางส่วน แต่รายได้จาก GitHub Sponsor หรือ Tidelift ไม่มากพอ จึงนึกว่าคนนี้คงยึดแนวคิดเรื่องความเข้ากันได้จริงๆ ตอนปี 2025 ฉันคิดเรื่องนี้ต่างออกไปแล้ว เขาดูแลงาน maintenance ที่สำคัญต่อเนื่อง และยังมีบทบาทในการยืนหยัดเสนอแนวคิดที่สวนกระแสในชุมชน ซึ่งบางครั้งก็จำเป็น

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

    • ผู้เขียนคนนั้นแทบแน่ชัดว่าคือ ljharb

  • NTFS Alternate Data Streams (ADS) ของ Windows ทำให้ซ่อนไฟล์ได้ไม่จำกัดในไฟล์เดิมได้ macOS ก็สร้างไฟล์ซ่อนและไฟล์ชั่วคราวจำนวนมากอยู่ดี โดยเฉพาะบนสื่อถอดได้ทุกดิสก์ ผ่าน data fork, xattr และการ index ด้วย Spotlight (md) วิธีแก้: mdutil -X /Volumes/path/to/vol แล้วก็มี telemetry แบบ opt-out จำนวนมหาศาลในที่ต่างๆ (go, yarn, meilisearch, homebrew, vcpkg, dotnet, Windows, VS Code, Claude Code, macOS, Docker, Splunk, OpenShift, Firefox, Chrome, flutter ฯลฯ) จนเกิดความเสี่ยงเรื่องความเป็นส่วนตัวแทบทุกที่

    • opt-out telemetry: ในกรณีของ go ข้อมูล telemetry จะถูกเก็บในเครื่องเป็นค่าเริ่มต้น และอัปโหลดได้ต่อให้ผู้ใช้กำหนด โดยส่งได้เฉพาะข้อมูลที่ได้รับการอนุมัติบางส่วนไปยัง telemetry.go.dev ควบคุมได้ด้วย “go telemetry on” สำหรับเปิดอัปโหลด และ “go telemetry off” สำหรับปิดทั้งหมด (ดูได้จาก เอกสาร)

    • telemetry แบบ opt-out เท่านั้นที่เป็น telemetry ที่มีประโยชน์จริง

  • เรื่องแจ้งว่า “npm script ทุกครั้งที่รันจะมีการส่ง HTTP request ไปยัง npm registry” อยากทราบว่าเป็นความจริงหรือไม่ ถ้าใช่ ถือว่าพฤติกรรมที่ไม่สมเหตุสมผลสำหรับ package manager

    • น่าจะเป็นขั้นตอนเช็กว่า npm มีอัปเดตไหม เพราะเมื่อใช้เวอร์ชันเก่ามักจะขึ้นเตือนการอัปเดตอยู่เสมอ

    • คาดว่าเป็นเพราะเช็กอัปเดตเหมือนกัน เวลาไหนเวลาหนึ่งก็มีการโชว์แบนเนอร์อัปเดต

  • รู้สึกว่ามีบางส่วนที่หลุดจากรายงานไป เรื่องการจัดการวันเวลาใน EXIF metadata ถือว่าเป็นประเด็นที่ถกเถียงกันมานาน อ้างอิง issue 1, อ้างอิง issue 2, อ้างอิง issue 3

    • ตัววันเวลาเองก็เป็นสิ่งที่ต้องสาปได้ง่าย สิ่งที่ดูเหมือนทำงานได้ดีก็ยังอาจแตกได้ตลอดเวลา โดยเฉพาะเมื่อมีข้อมูล timezone หรือ daylight saving time ร่วมด้วย
  • อ่านแล้วนึกถึง “Madness beyond the gates” ที่เกี่ยวกับ Hadoop และ Kerberos (ลิงก์) ได้เสมอ เลยได้รอดจากหลายครั้งเมื่อเกือบวิ่งเข้าเส้นวิบัติโดยไม่ตั้งใจ บอกเลยว่าอยากขอบคุณ Steve ที่เขียนเอกสารนี้ มนุษย์คงลำบากมากแค่ไหนถึงจะสกัดเอาความรู้ที่ต้องสาปออกมาได้

  • แนวคิดการรวมความรู้ที่ต้องสาปไว้ที่เดียวแบบนี้สุดยอดมาก และเข้าใจตรงกับความรู้สึกที่การลองผิดลองถูกแบบนี้บางอย่างเกิดขึ้นได้เมื่อเข้าไปมีส่วนร่วมลึกในโปรเจกต์จริงๆ ผมตั้งใจว่าต่อไปแต่ละโปรเจกต์จะทำรายการลักษณะนี้ไว้บ้าง

  • หัวข้อนี้ ไม่ได้เป็นเรื่องความรู้ที่ต้องสาป แต่เป็นประเด็นความปลอดภัย/ความเป็นส่วนตัวที่เกี่ยวกับการจัดการสิทธิ์บนระบบปฏิบัติการมือถือ

  • ไอเดียเยี่ยมมาก! อยากรู้ว่าคนอื่นๆ มีความคิดอยากแชร์ความรู้ที่ต้องสาปของตัวเองเหมือนกันหรือเปล่า ประสบการณ์ของผมก็พบว่า ชื่อไฟล์ใน MacOS ก็เป็นความสาปเช่นกัน:

  1. โดยค่าเริ่มต้น MacOS จะไม่แยกความแตกต่างตัวพิมพ์ใหญ่-เล็กในชื่อไฟล์ (file.txt และ FILE.txt ถือว่ามันเดียวกัน)
  2. เมื่อเก็บชื่อไฟล์เป็น NFC ใน MacOS อาจเปลี่ยนเป็น NFD ได้บางครั้ง
  • ผมเคยทำ CDDB ครั้งแรกในช่วง beta ของ Windows 95 ในปี 1995 ตอนรวบรวมชื่อแทร็กอัลบั้ม CD แล้วแจกจ่ายเป็นไฟล์ .ini และโปรเจกต์ต้องหยุดไปเพราะข้อจำกัดขนาดไฟล์ .ini ที่ 64KB

  • ใช่แล้ว เมื่อสร้าง system หรือ data volume ที่เป็น APFS หรือ HFS+ แบบ case-sensitive จะเจอปัญหาแน่นอน

  • ข้อ 1 คือค่าเริ่มต้นเท่านั้น ทั้ง HFS และ APFS มีตัวเลือก case-sensitive และ NTFS ก็ทำงานคล้ายกัน ระบบไฟล์เหล่านี้เป็น case-retentive จึงสามารถใช้งานได้แบบนี้

 $ echo yup > README.txt
 $ cat ReAdMe.TXT
 yup
 $ ls
 README.txt

ปัญหาจริงคือ Steam จะปฏิเสธการติดตั้งบนไฟล์ระบบที่เป็น case-sensitive แม้จะมีเวอร์ชัน Linux ก็ตาม