4 điểm bởi GN⁺ 2025-08-08 | 1 bình luận | Chia sẻ qua WhatsApp
  • Danh sách chia sẻ các kiến thức bị nguyền rủa thu thập được trong quá trình phát triển Immich
  • Tổng hợp các vấn đề bất ngờ gặp phải trong nhiều môi trường phần mềm và hạ tầng khác nhau
  • Nêu ra các điểm khó với siêu dữ liệu EXIF, xử lý khoảng trắng YAML, PostgreSQL và công cụ/ngôn ngữ
  • Một số vấn đề liên quan trực tiếp đến bảo mật, khả năng tương thích nền tảng, phụ thuộc nguồn mở
  • Tập trung vào trường hợp thực tế và nguyên nhân mà nhà phát triển cần lưu ý

Tổng quan

Đội ngũ phát triển Immich đã công bố các kiến thức bị nguyền rủa mà họ từng trải qua trong quá trình làm dự án, những thứ không muốn gặp lại. Đây là danh sách các bẫy và vấn đề bất ngờ mà họ đã trực tiếp gặp trong quá trình phát triển và vận hành dịch vụ thực tế trên nhiều công cụ, ngôn ngữ và nền tảng khác nhau.

Danh sách kiến thức bị nguyền rủa

  • 4 tháng 6 năm 2025

    • Actions của Zitadel là một tính năng gây rắc rối
    • Tính năng scripting tùy chỉnh mà Zitadel cung cấp dựa trên JS, nhưng lại không hỗ trợ nhóm bắt tên của regex, nên bộc lộ rõ giới hạn
  • 30 tháng 5 năm 2025

    • Microsoft Entra hỗ trợ PKCE, nhưng không ghi nhận điều này trong tài liệu phát hiện OpenID
    • Do đó, một tính năng tồn tại nhưng lại không được client phát hiện
  • 5 tháng 5 năm 2025

    • Kích thước trong siêu dữ liệu EXIF mô tả hình ảnh có thể không khớp với hình ảnh thực tế
    • Sự khác biệt này gây ra lỗi trong cropresize
  • 1 tháng 4 năm 2025

    • Xử lý khoảng trắng của YAML thường hoạt động không như mong đợi
    • Nhạy cảm với định dạng, nên có nguy cơ diễn giải nội dung sai so với ý định
  • 20 tháng 9 năm 2024

    • Tệp ẩn của Windows không mở được bằng cờ w
    • Khi kết hợp với tùy chọn hide dot files của SMB, dễ gây rối loạn lớn trong duyệt và xử lý tệp
  • 7 tháng 8 năm 2024

    • Script Bash có thể gặp vấn đề CRLF
    • Nếu Git tự chuyển đổi tự động từ LF sang CRLF khi checkout, có thể gây lỗi khi thực thi script
  • 7 tháng 8 năm 2024

    • fetch trên Cloudflare Workers mặc định dùng http ngay cả khi đã chỉ định https
    • Điều này có thể gây lỗi mạng như vòng lặp chuyển hướng
  • 21 tháng 7 năm 2024

    • Chia sẻ GPS trên thiết bị di động có thể âm thầm bị xóa khỏi ảnh nếu app không có quyền vị trí
    • Tác động đến độ chính xác của dịch vụ vị trí và quyền riêng tư
  • 3 tháng 7 năm 2024

    • NOTIFY của PostgreSQL chỉ hoạt động trong transaction
    • Khi dùng với socket.io + postgres-adapter, ghi WAL mỗi 5 giây có thể gây tăng tải
  • 3 tháng 7 năm 2024

    • Mỗi lần chạy script npm đều gửi request đến npm registry qua HTTP
    • Vì vậy, dùng script để health check là không hiệu quả
  • 28 tháng 6 năm 2024

    • Trong cộng đồng JavaScript, một số người đã ép thêm 50 gói phụ thuộc cho lý do tương thích ngược
    • Tất cả các gói này đều do một người dùng đó quản lý
  • 25 tháng 6 năm 2024

    • Triển khai bcrypt chỉ sử dụng 72 byte đầu tiên của chuỗi
    • Các ký tự phía sau bị bỏ qua, khiến mật khẩu dài trở nên vô nghĩa
  • 31 tháng 1 năm 2024

    • Đối tượng Date của JavaScript đánh chỉ số năm và ngày từ 1, tháng từ 0
    • Là một cấu trúc dễ gây nhầm lẫn
  • 9 tháng 1 năm 2024

    • Trước Node.js v20.8, trong dự án CommonJS sử dụng tùy chọn --experimental-vm-modules, khi ESM nạp lại module CommonJS
      • xảy ra lỗi segfault và làm Node.js crash
  • 28 tháng 12 năm 2023

    • Giới hạn tham số của PostgreSQL là 65.535
    • Trong bulk insert tập dữ liệu lớn, giới hạn này gây ra vấn đề hiệu năng
  • 26 tháng 6 năm 2023

    • Một số Web API chỉ có thể dùng trong Secure Contexts
    • Chẳng hạn API clipboard chỉ hoạt động ở môi trường https hoặc localhost
  • 23 tháng 2 năm 2023

    • Cài đặt remove của TypeORM ảnh hưởng trực tiếp đến dữ liệu đầu vào
    • Nó xóa luôn cả thuộc tính id của đối tượng gốc

Kết luận

Những kiến thức bị nguyền rủa như vậy thường xuất hiện trong phát triển và vận hành dịch vụ thực tế. Việc nhận diện trước các ràng buộc và vấn đề tiềm ẩn theo từng công cụ, ngôn ngữ và môi trường giúp nhà phát triển cải thiện khả năng khắc phục sự cố và phát triển dịch vụ ổn định hơn.

1 bình luận

 
GN⁺ 2025-08-08
Bình luận Hacker News
  • Tôi thích bài này ngay từ lần đầu xem. Sau khi xem commit mẫu (ở đây), tôi càng thấy hợp. Việc ghi lại “kiến thức bị nguyền rủa” cùng cách giải quyết bằng code là điểm rất hay. Ý nghĩ đầu tiên của tôi là tính năng này nên có ở mọi dự án. Nhật ký không chỉ là một thứ giải tỏa, mà còn biến các vấn đề đau đầu thành trải nghiệm học tập tích cực. Nếu chia sẻ ra ngoài, có thể đồng cảm với người từng gặp cùng vấn đề và nó có thể thành công cụ giúp dự đoán, phòng ngừa lỗi sau này.

    • Tôi thường ghi trực tiếp những thông tin như vậy trong commit message. Khi ai đó nhìn một dòng code và nghĩ “Sao viết tóm tắt như vậy? Chẳng phải chỉ cần ___ là xong sao?”, thì có ngay lời giải thích rất hữu ích.
  • Khi đọc phần “không thể bind 65.000 placeholder của PostgreSQL trong một truy vấn”, tôi đã khá ngạc nhiên. Thật ra đây vốn không phải ý tưởng hay, nên khó mà đổ hết lỗi cho PostgreSQL. Trong comment trên issue GitHub thì thấy họ đã refactor ORM để chia query lớn thành nhiều query nhỏ hơn, đây là hướng tiếp cận hợp lý. Cá nhân tôi thấy khoảng 3.000~5.000 hàng cho mỗi truy vấn là ổn.

    • Có người góp ý rằng đưa dữ liệu lên bảng TEMP trước rồi join sau, đặc biệt là cú pháp [COPY … FROM], có thể cho hiệu năng tốt hơn, nhưng đó là thay đổi code quá lớn nên cuối cùng họ đã bỏ chiến lược đó. Nói chung đây là một kho kinh nghiệm rất hay, hữu ích như một cảnh báo.

    • Tôi đồng ý với “cố gắng như thế này đã là ý tưởng bị nguyền rủa”. Đọc hết danh sách thì “danh sách bị nguyền rủa” có cảm giác giống những bẫy thực sự trong thiết kế, hơn là một thứ khác. Dù mức độ hoàn thiện mỗi mục khác nhau và có thứ chưa kết thúc, nếu nhìn như nhật ký kinh nghiệm cá nhân trong engineering thì giá trị của nó còn cao hơn.

  • Cảm giác giống như xử lý mọi tên file trong file system bằng xargs hay tool tương tự mà không phân tách bằng ký tự NUL. Nếu có tên file lạ/lỗi, hoặc RAM không đủ, sẽ rất khó. Nên dùng find -print0 cùng parallel -0/xargs -0. Và cũng nên cẩn thận khi dùng sed, grep… nếu không đặt LC_ALL=C sẽ dễ gây lỗi chuỗi đa-byte.

  • Tôi đã từng tự gặp lỗi upsert hàng loạt qua ORM với 65.000 bind. Đặc biệt khi bảng có cột kiểu SQL array, mỗi bản ghi chèn phải bind nên biến bind dao động. Vì thế dù chạy hai lần vẫn thấy số hàng/cột như nhau, số biến cần bind lại khác nhau, tạo ra tình huống không ổn.

  • Một hướng khác là truyền giá trị dạng argument mảng (như text[] hay int[]). PostgreSQL xử lý việc này tốt. ANY() hơi chậm hơn IN() một chút, nhưng gom được nhiều ID trong một tham số. Có thể ORM đã chưa hỗ trợ cách này.

  • Tôi cũng thấy điểm này. Binding quá nhiều parameter như vậy đúng là cách bị nguyền rủa. Với xử lý hàng loạt thì phần lớn nên dùng COPY. Nhân tiện thêm một ví dụ Postgres bị nguyền rủa: tên prepared statement bị cắt im lặng đúng độ NAMEDATALEN-1 (NAMEDATALEN là 64). Điều này đã có từ năm 2001, và thực ra còn trước đó. Các ORM bắt buộc phải nắm rõ việc này. Việc dev dùng tên chuẩn bị dài quá 60 ký tự là hiếm, nhưng ORM thì không.

  • Mục “cài thêm 50 package” thật sự gây choáng. Tác giả package ấy chắc đã đẩy rất nhiều lượt tải lên. Với lượng băng thông và dung lượng đĩa bị lãng phí trên toàn cầu, thấy thật đáng tiếc. Không biết có phải vì muốn gây tiếng tăm hay không.

    • Người maintain package bị điểm tên trong “kiến thức bị nguyền rủa” này là thành viên TC39. Anh này thường gây tranh cãi trong nhiều dự án JavaScript nổi tiếng. Có từng có giả thuyết về động cơ tài chính quanh một polyfill issue cụ thể, nhưng vì thu nhập từ GitHub Sponsor hay Tidelift không lớn nên tôi nghĩ có thể họ thực sự đặt sự tương thích lên hàng đầu. Tính đến 2025, suy nghĩ của tôi về người này đã đổi chút ít: họ đang duy trì bảo trì quan trọng ổn định, và vai trò cứ liên tục phát biểu quan điểm trái chiều trong cộng đồng cũng có lẽ vẫn cần thiết.

    • Có thể là danh tiếng hay tính cách riêng, nhưng cũng có cách diễn giải cực đoan cho rằng đây là tiền đề cho một cuộc tấn công chuỗi cung ứng phần mềm quy mô lớn.

    • Tác giả gần như chắc chắn là ljharb.

  • NTFS Alternate Data Streams (ADS) của Windows cho phép giấu vô hạn file ẩn trong một file hiện hữu.
    macOS mặc định cũng tạo rất nhiều file ẩn/tạm trên mọi volume gắn ngoài, gồm data fork, xattr, index Spotlight(md). Cách xử lý: mdutil -X /Volumes/path/to/vol
    Và có quá nhiều điểm opt-out telemetry (go, yarn, meilisearch, homebrew, vcpkg, dotnet, Windows, VS Code, Claude Code, macOS, Docker, Splunk, OpenShift, Firefox, Chrome, flutter, và nhiều chỗ khác) mà đều có nguy cơ xâm phạm riêng tư.

    • opt-out telemetry: với go, telemetry mặc định chỉ lưu local. Chỉ khi user bật thì mới upload một phần dữ liệu đã được phê duyệt lên telemetry.go.dev. Có thể bật upload bằng “go telemetry on”, tắt hoàn toàn bằng “go telemetry off” (xem tài liệu).

    • Chỉ có telemetry kiểu opt-out mới là telemetry thực sự hữu ích.

  • Với report “mỗi lần chạy npm script đều gửi request HTTP đến npm registry”, tôi tự hỏi liệu có đúng không. Nếu đúng thì với một package manager thì hành vi đó thật vô lý.

    • Có thể là bước kiểm tra bản cập nhật npm hay không. Dùng bản cũ thường có thông báo cập nhật.

    • Tôi đoán cũng là vì kiểm tra cập nhật, vì đôi khi banner cập nhật hiện lên.

  • Cảm giác có vẻ bỏ sót một phần. Chuyện xử lý ngày giờ trong EXIF metadata đã là tranh luận rất lâu rồi
    Tham khảo issue 1, Tham khảo issue 2, Tham khảo issue 3

    • Chính bản thân ngày giờ cũng dễ bị “khó chịu”. Ngay cả khi chạy ổn, các tính năng liên quan luôn có thể đẩy bug ra bất cứ lúc nào, đặc biệt khi có múi giờ hoặc DST.
  • Nhắc đến tài liệu “Madness beyond the gates” về Hadoop và Kerberos (liên kết). Nhờ bài này, mình đã được cứu khỏi chỗ điên loạn mấy lần. Muốn gửi lời cảm ơn đến Steve. Không biết đã vất vả bao nhiêu mới có được “kiến thức bị nguyền rủa” này.

  • Ý tưởng gom tất cả “kiến thức bị nguyền rủa” vào một chỗ rất hay. Quả thật những vấp ngã chỉ thấy khi đi sâu vào dự án. Tôi sẽ nghĩ đến việc làm danh sách như vậy cho từng project.

  • Mục này không phải kiến thức bị nguyền rủa, mà là vấn đề bảo mật và riêng tư về quản lý quyền trên mobile OS.

  • Ý tưởng hay! Tôi tò mò không biết ai cũng muốn chia sẻ “kiến thức bị nguyền rủa” của mình như thế không. Theo kinh nghiệm của tôi, tên file trên macOS cũng là một curse:

  1. Mặc định, macOS không phân biệt hoa/thường tên file (file.txt và FILE.txt là cùng tên)
  2. Lúc lưu tên file ở NFC trên macOS, đôi khi có thể chuyển thành NFD
  • Năm 1995 khi ra mắt bản beta Windows 95, lần đầu mình làm CDDB. Mình gom tên track của đĩa CD rồi phát hành thành file .ini, nhưng bị dừng dự án vì giới hạn kích thước 64KB của file .ini.

  • Đúng vậy. Nếu tạo system hoặc data volume trên APFS hay HFS+ ở chế độ case-sensitive thì sẽ mắc lỗi.

  • Mục “1” chỉ là mặc định. Cả HFS và APFS đều có tùy chọn case-sensitive. NTFS cũng hoạt động tương tự. Các file system này là case-retentive nên có thể viết như sau

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

Vấn đề thật sự là Steam từ chối cài đặt trên file system case-sensitive (mặc dù vẫn có bản Linux)