呪われた知識
(immich.app)- Immich の開発過程で得た 呪われた知識 の一覧を共有します
- 様々なソフトウェアおよびインフラ環境で見つかった 予期しない問題 を整理しました
- EXIF メタデータ、YAML の空白処理、PostgreSQL など、ツールと言語ごとの問題点に言及しています
- 一部の問題は セキュリティ、プラットフォーム互換性、オープンソース依存 と直接つながっています
- 開発者が注意すべき 実例と原因 に焦点を当てています
概要
Immich 開発チームは、プロジェクトを進める中で再び知りたくない 呪われた知識 を公開しました。これは、実際のサービス開発・運用の中で、さまざまなツール、言語、プラットフォームにおいて直接経験した 予期しない落とし穴と問題 を列挙したものです。
呪われた知識一覧
-
2025年6月4日
- Zitadel の Actions は呪われた機能です
- Zitadel が提供する カスタムスクリプト 機能は JS エンジンベースですが、正規表現のネーミングキャプチャグループをサポートしていないため限界が明らかになりました
-
2025年5月30日
- Microsoft Entra は PKCE をサポートしていますが、OpenID discovery ドキュメントに明記されていないため、
- そのため、この機能がクライアントで検出されない問題が発生しました
-
2025年5月5日
- 画像を説明する EXIF メタデータのサイズ情報 は、実際の画像と異なる場合があります
- この差分により、クロップとリサイズ処理でエラーが発生しました
-
2025年4月1日
- YAML の空白処理 は想定と異なる動作をすることが多いです
- フォーマットに敏感で、意図と異なる内容として解釈されるリスクがあります
-
2024年9月20日
- Windows の隠しファイルは "w" フラグで開かれません
- SMB の "hide dot files" オプションと組み合わせると、ファイル探索と処理の混乱 が拡大します
-
2024年8月7日
- Bash スクリプトでは キャリッジリターン(CRLF) 問題が発生する可能性があります
- Git がチェックアウト時に自動で LF を CRLF に変換すると、スクリプト実行でエラーを引き起こします
-
2024年8月7日
- Cloudflare Workers の fetch は https を明示しても、デフォルトは http になります
- これにより リダイレクトループ などのネットワーク関連問題が発生します
-
2024年7月21日
- モバイルの GPS 共有 は、アプリに位置情報権限がない場合、画像から GPS 情報を静かに削除します
- 位置ベースサービスの精度とプライバシーに影響します
-
2024年7月3日
- PostgreSQL の NOTIFY はトランザクション内でのみ動作します
- socket.io の postgres-adapter と組み合わせて使用すると、5秒ごとに WAL ログ が記録され、負荷を発生させます
-
2024年7月3日
- npm スクリプトを実行するたびに npm レジストリへ HTTP リクエストを送信します
- したがって、スクリプトでヘルスチェックを行うのは非効率です
-
2024年6月28日
- JavaScript コミュニティ内の一部ユーザーが、「下位互換性」 を理由に 50 以上のパッケージ依存を強制追加しました
- これらのパッケージはすべてそのユーザーが管理しています
-
2024年6月25日
- bcrypt 実装 は文字列の最初の 72 バイトだけを使用します
- それ以降の文字は 無視されるため、長いパスワードは意味を持ちません
-
2024年1月31日
- JavaScript Date オブジェクトは年と日付は 1 から、月は 0 からインデックス付けされます
- 混乱しやすい構造です
-
2024年1月9日
- Node.js v20.8 以前、--experimental-vm-modules オプションを使用する CommonJS プロジェクトで ES モジュールが CommonJS モジュールを再度読み込む際に
- segfault(セグメンテーション違反)で Node.js がクラッシュする問題が発生します
- Node.js v20.8 以前、--experimental-vm-modules オプションを使用する CommonJS プロジェクトで ES モジュールが CommonJS モジュールを再度読み込む際に
-
2023年12月28日
- PostgreSQL のパラメータ制限は 65,535 個です
- 大量データセットのバルクインサートで性能上の限界を引き起こします
-
2023年6月26日
- Secure Contexts でのみ使用できる Web API があります
- 代表例として clipboard API などは https または localhost 環境でのみ動作します
-
2023年2月23日
- TypeORM の remove 実装は入力値に直接影響します
- 元のオブジェクトの id プロパティまで削除してしまいます
結論
このような 呪われた知識 は、実際のサービス開発と運用環境で頻繁に遭遇し得る落とし穴です。開発者は、各ツール、プログラミング言語、環境ごとに潜在する制約や問題を事前に把握することで、効率的なトラブルシューティングと安定したサービス開発に役立ちます。
1件のコメント
Hacker Newsのコメント
これを最初に見た時から本当に気に入っていました。例のコミット(こちら)を確認したところ、さらに気に入るようになりました。問題解決のためのコードと一緒に「呪われた知識」が記録される点が特に良いです。こうした機能はすべてのプロジェクトに必要だと真っ先に思いました。ログはただのカタルシスではなく、悩ましい問題を前向きな学習経験に変えてくれます。外部に公開すれば、同じ問題を経験した人たちと共感でき、将来の発生を防ぐツールにもなり得ます。
「PostgreSQLでプレースホルダー6万5千個を1クエリでバインドできない」というところに驚きました。そもそもこれはあまり良い考えではないので、PostgreSQL側を責めるのは難しいです。GitHubのIssueコメントを見ると、ORMをリファクタリングして巨大なクエリを複数の小さなクエリに分割する合理的なアプローチを取っていました。個人的には1クエリあたり3,000〜5,000行程度が適当な感覚です。誰かがTEMPテーブルに先にデータを上げて、あとでJOINする方法(特にCOPY … FROM)が性能上より良いと助言していましたが、コード変更が大きすぎて、その戦略は最終的に見送られました。全体的に、良い経験談が集まった有益なコレクションだと思います。警告的な事例として役立ちます。
「この種の試行自体が呪われたアイデア」だと思います。リストを全て読んでみると、「呪いリスト」というのは、行き詰まりや設計の落とし穴というより、実際の開発者がぶつかって体得した教訓のように感じます。もちろん情報ごとに完成度は異なり、進行中のものもありますが、エンジニアリングログ内の個人的な経験談として捉える方が価値が高いです。
ファイルシステムの全ファイル名をNUL文字なしでxargsのようなツールを使って一度に処理しようとするのと似ています。特殊・破損したファイル名があったり、メモリが十分でない場合には厄介です。find -print0やparallel -0/xargs -0などのツールを使うのがよいです。そしてsedやgrepなども、LC_ALL=Cを付けずに使うとマルチバイト文字列のシーケンスエラーが起きるので注意が必要です。
実際にORMでレコードを大量upsertしている最中に、6万5千個バインドのエラーを実体験しました。特にテーブルにSQL配列型カラムがある場合、挿入する項目ごとにバインドしないといけないため、バインド変数数が変動します。なので2回実行しても行数/列数は同じに見えるのに、バインドが必要な変数数は異なる不安定な状況になります。
別の戦略として、値を配列引数(text[]やint[]など)で渡す方法もあります。PostgreSQLはこれをうまく処理します。ANY()演算はIN()よりわずかに遅いですが、1パラメータ内に複数IDを格納できます。おそらくORM側でそれがサポートされていなかったのかもしれません。
その点は自分も気になっていました。これほど多くのパラメータをバインドするのは確かに呪われたやり方です。大規模処理なら通常COPYを使うべきです。さらに呪われたPostgres事例をもう1つ追加すると、prepared statement名はNAMEDATALEN-1だけ静かに切り詰められます(NAMEDATALENは64)。これは2001年からの仕様で、実際には以前からありました。ORMはこの点を必ず認識するべきです。60文字を超えるprepare名を人が使うのは稀ですが、ORMは例外です。
「パッケージを50個追加インストールする」という項目は本当に衝撃的です。そのパッケージ作成者はダウンロード数を大幅に上げたのでしょう。世界中で浪費される帯域幅とディスク容量を考えると本当に勿体ないです。もしかしたら名声を上げようとしているのではないかと思われます。
この『呪われた知識』で指摘されたそのパッケージのメンテナーはTC39メンバーです。複数の有名なJavaScriptプロジェクトでしばしば論争になっていた人物です。特定のpolyfill問題に関して金銭的動機があるという主張もありましたが、GitHub SponsorやTideliftの収益は大きくないため、本人は本当に互換性を信念として重視しているのではないかと考えます。2025年時点では、それに対する考えが少し変わりました。重要な保守を継続的に行っており、コミュニティ内で誤った見解を発言し続ける役割も、むしろ必要かもしれないと思います。
名声や奇妙な性質が原因かもしれませんが、巨大規模のソフトウェアサプライチェーン攻撃への前提準備という極端な解釈もあります。
その作者はほぼ間違いなくljharbです。
WindowsのNTFS Alternate Data Streams(ADS)は、既存ファイルに無制限にファイルを隠せる機能です。 macOSは、data fork、xattr、Spotlight(md)インデックス作成まで、全てのリムーバブルボリュームに多数の隠し・一時ファイルを標準で作成します。解決策:
mdutil -X /Volumes/path/to/volそして、opt-outテレメトリがあまりにも多すぎます(go、yarn、meilisearch、homebrew、vcpkg、dotnet、Windows、VS Code、Claude Code、macOS、Docker、Splunk、OpenShift、Firefox、Chrome、flutterなど、あらゆる場所でプライバシー侵害の懸念がある)。opt-outテレメトリ: goの場合、デフォルトではテレメトリデータはローカルにのみ保存されます。ユーザーが必要とする時のみ、一部承認されたデータをtelemetry.go.devへアップロードできます。アップロード有効化は「go telemetry on」、完全無効化は「go telemetry off」で調整できます(ドキュメント参照)。
opt-outテレメトリだけが本当に有用なテレメトリです。
「npmスクリプトが実行されるたびにnpmレジストリへHTTPリクエストを送る」という報告について、本当なのか疑問です。もしそうなら、パッケージマネージャとしてはあり得ない動作です。
おそらくnpm更新の有無を確認する工程です。古いバージョンを使っていると、更新案内が表示されることもあります。
おそらく更新確認のためでしょう。時々更新バナーが表示されます。
1つ見落としているようです。EXIFメタデータの日付・時刻処理に関するラウンドはかなり古くからの議論です。 参考 issue1, 参考 issue2, 参考 issue3
HadoopとKerberosに関する『Madness beyond the gates』(リンク)を思い起こさせます。この文章のおかげで、狂気に追い詰められそうになったときに何度も救われたことがあります。著者のSteveに感謝したいです。呪われた知識を獲得するまでにどれだけ苦労したか、想像もできません。
このような『呪われた知識』を一箇所にまとめるという考え方はとても良いです。実際、プロジェクトに深く入って初めて経験する試行錯誤だという点にも共感できます。今後、プロジェクトごとにこのようなリストを作っておこうと思います。
この項目は呪いではなく、モバイルOSの権限管理に関するセキュリティ/プライバシー問題です。
素晴らしいアイデアです!他の方々もそれぞれの『呪われた知識』を共有したいと思っているか気になります。 私の経験上、MacOSのファイル名も呪いです:
1995年、Windows 95のベータ版でCDDBを最初に作成しました。CD音源のトラック名をまとめて.iniファイルで配布していましたが、64KBという.iniファイルサイズ上限のためプロジェクトは中断しました。
その通りです。システムやデータボリュームにcase-sensitiveなAPFSやHFS+ボリュームを作ると必ず問題が起きます。
「1番目」の項目はデフォルト設定にすぎません。HFS、APFSの両方に大文字小文字を区別するオプションがあります。NTFSも同様に動作します。これらのファイルシステムはcase-retentiveであるため、以下のように書けます。
本当の問題は、Steamがcase-sensitiveファイルシステムではインストール自体を拒否してしまうことです(Linux版もあるのに)。