66 ポイント 投稿者 GN⁺ 2025-08-18 | 1件のコメント | WhatsAppで共有
  • 開発者がよく陥る直感的ではない落とし穴を整理し、発生しやすいバグの原因を紹介する
  • HTML、CSS、Unicode/テキストエンコーディング、浮動小数点、時間など、さまざまな技術で頻発する問題を扱う
  • 各言語やフレームワークでの 文法や挙動の微妙な違い によって、誤解やエラーが生じうることを強調する
  • 並行性、ネットワーキング、データベース などバックエンドの中核領域で、実運用環境で起こりうる落とし穴を例示して説明する
  • 多様なサンプルと参考リンクを通じて、問題状況と解決法、そして予期しない挙動の改善点を案内する

HTMLとCSS

  • Flexbox/Gridにおける min-width のデフォルト値

    • min-width はデフォルトで auto
    • min-width: auto はコンテンツサイズによって決まり、flex-shrinkoverflow: hiddenwidth: 0max-width: 100% より優先される
    • 推奨: min-width: 0 を明示する
  • CSSにおける横方向と縦方向の違い

    • width: auto は親の空間を埋めようとし、height: auto はコンテンツに合わせられる
    • inline、inline-block、float 要素の width: auto は拡張されない
    • margin: 0 auto は水平方向の中央揃え、margin: auto 0 では垂直方向の中央揃えはできない(ただし flex-direction: column では垂直中央が可能)
    • マージンの相殺は縦方向でのみ発生する
    • writing-mode: vertical-rl などでレイアウト方向が変わると挙動も反転する
  • Block Formatting Context (BFC)

    • display: flow-root で BFC を生成できる(そのほか overflow: hidden/auto/scrolldisplay: table などでも可能だが副作用がある)
    • 縦に隣接する兄弟要素のマージンが重なったり、子要素のマージンが親の外へ漏れたりする現象は BFC で防げる
    • 親が float 子要素しか含まない場合、高さが 0 に潰れる → BFC で修正可能
    • borderpadding がある場合、マージンの相殺は発生しない
  • Stacking Context

    • 新しい stacking context を作る条件
      • transformfilterperspectivemaskopacity などのレンダリング属性
      • position: fixed または sticky
      • z-index 指定 + absolute/relative の位置指定
      • z-index 指定 + flexbox/grid 内部要素
      • isolation: isolate
    • 特徴
      • z-index は stacking context の内部でのみ適用される
      • position: absolute/fixed の座標は最も近い positioned な祖先を基準にする
      • sticky は stacking context をまたいで動作しない
      • overflow: visible でも stacking context によって切り取られる
      • background-attachment: fixed は stacking context を基準に配置される
  • ビューポート単位

    • モバイルブラウザでは、アドレスバーやナビゲーションバーがスクロール時に画面から消えると 100vh の値が変わる
    • 最新の解決策: 100dvh を使う
  • Absolute Position の基準

    • position: absolute は親ではなく、最も近い relative/absolute または stacking context の祖先を基準にする
  • Blur の挙動

    • backdrop-filter: blur は周囲の要素を考慮しない
  • Float の無効化

    • 親が flex または grid の場合、子要素の float は効果がない
  • パーセント単位の width/height

    • 親のサイズが事前に決まっていないと動作しない(循環参照を避けるため)
  • Inline 要素の特性

    • display: inline では widthheightmargin-topmargin-bottom は無視される
  • Whitespace の扱い

    • デフォルトでは HTML の改行は空白として扱われ、連続する空白は 1 つに縮約される
    • `` は空白の縮約を防ぐが、先頭と末尾の挙動に癖がある
    • 多くの場合、コンテンツ先頭/末尾の空白は無視されるが、`` は例外
    • inline-block 間の空白や改行は実際の間隔として表示される(flex/grid では発生しない)
  • text-align

    • テキストおよび inline 要素の整列には適用されるが、block 要素の整列には適用されない
  • box-sizing

    • デフォルト値は content-box → padding/border は含まれない
    • width: 100% + padding を設定すると親領域をはみ出す可能性がある
    • 解決策: box-sizing: border-box
  • Cumulative Layout Shift

    • `` に widthheight 属性を指定しないと、画像読み込みの遅延によりレイアウトの揺れが発生する
    • 推奨: 属性を指定して CLS を防ぐ
  • Chrome におけるファイルダウンロードのネットワークリクエスト

    • DevTools のネットワークパネルには表示されない(別タブで処理される)
    • 分析が必要なら chrome://net-export/ を使う
  • HTML 内の JavaScript パース問題

    • console.log('') のような場合、最初の `` が終了タグとして認識される
    • 参考: Safe JSON in script tags

Unicodeとテキストエンコーディング

  • コードポイントと書記素クラスター

    • 書記素クラスターは GUI における「文字単位」
    • 可視 ASCII 文字は、コードポイント 1 個 = 書記素クラスター 1 個
    • 絵文字は、複数のコードポイントで構成された 1 つの書記素クラスターである場合がある
    • UTF-8 ではコードポイントは 1〜4 バイトで、バイト数とコードポイント数は一致しない
    • UTF-16 ではコードポイントは 2 バイトまたは 4 バイト(サロゲートペア)
    • 標準ではクラスター内のコードポイント数に制限はないが、実装では性能上の制限がある
  • 言語ごとの文字列挙動の違い

    • Rust: 内部文字列は UTF-8 を使用し、len() はバイト数、直接インデックス参照は不可、chars().count() はコードポイント数、UTF-8 の妥当性を厳格に検証する
    • Golang: 文字列は事実上バイト配列で、長さとインデックス参照はバイト単位、主に UTF-8 を使用する
    • Java, C#, JS: UTF-16 ベースで、長さは 2 バイト単位で測定され、インデックス参照も 2 バイト単位、サロゲートペアが存在する
    • Python: len() はコードポイント数を返し、インデックス参照では 1 つのコードポイントを含む文字列を返す
    • C++: std::string にはエンコーディング制約がなく、バイトベクターのように動作し、長さ/インデックス参照はバイト単位
    • 挙げられた言語の中で、書記素クラスター単位で長さやインデックス参照を行う言語はない
  • BOM (Byte Order Mark)

    • 一部のテキストファイルは BOM を持つ。例: EF BB BF → UTF-8 エンコーディングを示す
    • 主に Windows で使われ、Windows 以外のソフトウェアでは BOM を処理できないことがある
  • その他の注意点

    • バイナリデータを文字列に変換する際、壊れた部分は � (U+FFFD) に置き換えられる
    • Confusable characters が存在する(互いによく似て見える文字)
    • 正規化(Normalization): 例) é は U+00E9(単一コードポイント)または U+0065+U+0301(2つのコードポイント)で表現可能
    • Zero-width characters および Invisible characters が存在する
    • 改行コードの違い: Windows は CRLF \r\n、Linux/MacOS は LF \n
    • 漢字統合(Han unification): 言語ごとに字形が少し異なる文字が同じコードポイントを使う
      • フォントが言語別の異体字を含めて適切にレンダリングする
      • 国際化では正しいフォントバリアントの選択が必要

浮動小数点 (Floating point)

  • NaN の性質

    • NaN は自分自身を含むどの値とも等しくない(NaN == NaN は常に false)
    • NaN != NaN は常に true
    • NaN を含む演算結果はたいてい NaN として伝播する
  • 特殊な値

    • +Inf と -Inf が存在し、NaN とは異なる
    • -0.0 は +0.0 と区別される値
      • 比較演算では同一だが、一部の計算では異なる動作をする
      • 例: 1.0 / +0.0 == +Inf, 1.0 / -0.0 == -Inf
  • JSON との互換性

    • JSON 標準では NaN と Inf は許可されない
      • JS JSON.stringify は NaN、Inf を null に変換する
      • Python json.dumps(...) は NaN、Infinity をそのまま出力する(標準違反)
        • allow_nan=False オプション指定時は NaN/Inf があると ValueError が発生する
      • Golang json.Marshal は NaN/Inf が存在するとエラーを返す
  • 精度の問題

    • 浮動小数点の直接比較は失敗する可能性がある → abs(a - b) < ε 形式を推奨
    • JS はすべての数値を浮動小数点として扱う
      • 安全な整数範囲は -(2^53 - 1)2^53 - 1
      • この範囲を外れると整数表現が不正確になる
      • 大きな整数には BigInt の使用を推奨
      • JSON に安全範囲を超えた整数が含まれると、JSON.parse の結果値は不正確になる可能性がある
      • ミリ秒単位のタイムスタンプは 287,396 年先まで安全だが、ナノ秒単位では問題が発生する
  • 演算法則が成り立たない

    • 演算順序による精度損失のため、結合法則や分配法則は厳密には成り立たない
    • 並列演算(行列積、総和など)は非決定的な結果を生むことがある
  • 性能

    • 除算は乗算よりはるかに遅い
    • 同じ数で何度も割る場合は、逆数を先に求めて掛ける形に最適化できる
  • ハードウェアによる違い

    • FMA(Fused Multiply-Add) 対応の有無: 一部のハードウェアでは中間計算をより高精度で行う
    • Subnormal range の処理: 最新ハードウェアは対応しているが、一部の旧世代では 0 として扱う
    • 丸めモードの違い
      • RNTE(最も近い偶数への丸め)、RTZ(0 方向への切り捨て)などがある
      • x86/ARM ではスレッドローカルな mutable 状態として設定可能
      • GPU では命令単位で丸めモードが異なる
    • 三角関数、対数など数学関数の動作差
    • x86 にはレガシーな 80 ビット FPU と per-core rounding mode が存在する → 使用非推奨
    • このほかにもさまざまな要因で、ハードウェアごとに浮動小数点の結果が変わりうる
  • 精度向上の方法

    • 計算グラフを浅く構成する(乗算が連続する構造を減らす)
    • 中間値が極端に大きい、または極端に小さいケースを避ける
    • FMA のようなハードウェア演算を活用する

時間 (Time)

  • うるう秒(Leap second)

    • Unix タイムスタンプはうるう秒を無視する
    • うるう秒が発生すると前後の区間で時間を伸縮させることがある(Leap smear)
  • タイムゾーン(Time zone)

    • UTC と Unix タイムスタンプは世界共通
    • 人間が読む時刻は地域ごとのタイムゾーンに依存する
    • DB にはタイムスタンプを保存し、UI で変換する方式を推奨
  • サマータイム(DST)

    • 一部地域では夏季に時計を 1 時間調整する
  • NTP 同期

    • 同期の過程で時刻が「後戻りする」状況が発生しうる
  • サーバーのタイムゾーン設定

    • サーバーは UTC に設定することを推奨
    • 分散システムでノードごとにタイムゾーンが異なると問題が発生する
    • システムのタイムゾーン変更後は DB の再設定または再起動が必要
  • ハードウェアクロック vs システムクロック

    • ハードウェアクロックにはタイムゾーンの概念がない
    • Linux: ハードウェアクロックを UTC として扱う
    • Windows: ハードウェアクロックをローカル時刻として扱う

Java

  • == はオブジェクト参照の比較であり、オブジェクト内容の比較には .equals を使う必要がある
  • equalshashcode をオーバーライドしないと、map/set ではオブジェクト同一性が参照ベースで判断される
  • map の key オブジェクトや set の要素オブジェクトの内容を変更すると、コンテナの動作が壊れる
  • List を返すメソッドは、場合によって mutable な ArrayList または immutable な Collections.emptyList() を返し、後者を変更すると UnsupportedOperationException が発生する
  • Optional を返すメソッドが null を返すことがある(推奨されない)
  • finally ブロックで return すると、try または catch で発生した例外が無視され、finally の戻り値が適用される
  • interrupt を無視するライブラリが存在し、IO を含むクラス初期化の過程が interrupt によって壊れることがある
  • スレッドプールで .submit() に渡した task の例外は、デフォルトではログに出力されず future でしか確認できないため、future を無視すると例外を確認できない
    • scheduleAtFixedRate の処理は例外が発生すると静かに停止する
  • 数値リテラルが 0 で始まると 8 進数として扱われる(0123 → 83)
  • デバッガはローカル変数の .toString() を呼び出すため、一部クラスでは toString() に副作用があり、デバッグ時にコードの動作が変わることがある(IDE で無効化可能)

Golang

  • append() は capacity に余裕があるとメモリを再利用し、subslice への append で親のメモリまで上書きすることがある
  • defer は関数の return 時に実行され、ブロックスコープ終了時ではない
  • defer は mutable な変数をキャプチャする
  • nil 関連
    • nil slice と empty slice は異なる
    • string は nil にできず、空文字列のみ存在する
    • nil map は読み取りは可能だが書き込みはできない
    • interface nil の特殊な動作: data pointer が null でも type info が null でなければ nil と等しくない
  • Dead wait: Go には実際の並行性バグ事例が存在する
  • Timeout の種類 は多様で、net/http で詳しく扱われている

C/C++

  • std::vector の要素ポインタを保存した後に vector が grow すると再割り当てが発生し、ポインタが無効化される
  • リテラル文字列から生成された std::string は一時オブジェクトである可能性があり、c_str() 呼び出し時に危険
  • 反復中にコンテナを変更すると iterator の無効化が発生
  • std::remove は実際の削除ではなく要素の再配置であり、削除には erase が必要
  • 数値リテラルが 0 で始まると 8 進数として扱われる (0123 → 83)
  • Undefined behavior (UB): 最適化の過程で UB は自由に変化し得るため、依存すると危険
    • 初期化されていないメモリへのアクセスは UB
    • char* を struct ポインタに変換する場合、オブジェクト寿命の開始前アクセスにより UB となるため、memcpy による初期化を推奨
    • 不正なメモリアクセス(null ポインタなど)は UB
    • 整数の overflow/underflow は UB(unsigned は 0 未満への underflow が可能)
    • Aliasing: 異なる型のポインタが同じメモリを参照すると strict aliasing rule により UB が発生
      • 例外: 1) 継承関係にある型 2) char*, unsigned char*, std::byte* への変換(逆変換には適用されない)
      • 強制変換には memcpy または std::bit_cast を推奨
    • Unaligned memory へのアクセスは UB
  • メモリ Alignment
    • 64 ビット整数はアドレスが 8 で割り切れる必要がある
    • ARM では unaligned access でクラッシュする可能性がある
    • バイトバッファを struct として直接解釈すると alignment 問題が発生
    • alignment は struct padding を生み、メモリの無駄につながることがある
    • 一部の SIMD 命令(AVX など)は整列されたデータしか処理できず、通常は 32 バイト alignment が必要

Python

  • 関数のデフォルト引数は呼び出しのたびに新しく生成されず、最初の値がそのまま保持される

SQL Databases

  • Null の扱い

    • x = null は動作せず、x is null を使う必要がある
    • Null は自分自身と等しくない(NaN に似ている)
    • Unique index は Null の重複を許容する(ただし Microsoft SQL Server は例外)
    • select distinct における Null の扱いは DB ごとに異なる
    • count(x)count(distinct x) は Null 値がある行を無視する
  • 一般的な動作

    • 日付の暗黙変換は timezone に依存する場合がある
    • 複雑な join + distinct は入れ子クエリより遅い場合がある
    • MySQL(InnoDB) で string フィールドが utf8mb4 でない場合、4-byte UTF-8 文字を挿入するとエラーが発生
    • MySQL(InnoDB) はデフォルトで 大文字小文字を区別しない
    • MySQL(InnoDB) は暗黙変換を許容する: select '123abc' + 1; → 124
    • MySQL(InnoDB) の gap lock は deadlock を引き起こす可能性がある
    • MySQL(InnoDB) では group by と select カラムが一致しない場合、非決定的な結果を返す
    • SQLite では strict でなければフィールド型にはあまり意味がない
    • Foreign key は暗黙の lock を発生させ、deadlock を引き起こす可能性がある
    • Locking は DB によっては repeatable read isolation を破る可能性がある
    • 分散 SQL DB は locking をサポートしていない、または特異な動作をする可能性がある(DB ごとに異なる)
  • 性能/運用

    • N+1 query 問題は各クエリが高速であるため、slow query log には現れない
    • 長時間実行されるトランザクションは lock 問題などを引き起こすため、トランザクションは素早く終えることが推奨される
    • テーブル全体 lock の事例
      • MySQL 8.0+ では unique index/foreign key の追加時、多くの場合は並行処理が可能
      • 古い MySQL バージョンではテーブル全体 lock が発生する可能性がある
      • mysqldump--single-transaction オプションがないと、テーブル全体に read lock がかかる
      • PostgreSQL で create unique indexalter table ... add foreign key はテーブル全体の read lock を引き起こす
        • 回避策: create unique index concurrently を使用
        • foreign key は ... not valid の後に validate constraint を使う方法を利用
  • Range クエリ

    • 重ならない範囲:
      • 単純条件 p >= start and p file 2>&1 → stdout+stderr の両方がファイルへ、cmd 2>&1 > file → stdout のみファイルへ、stderr はそのまま
  • ファイル名は 大文字小文字を区別 する(Windowsとは異なる)

  • 実行ファイルには capability システムが存在する(getcap で確認)

  • 未設定変数の危険性: DIR が unset の場合、rm -rf $DIR/rm -rf / 実行の危険 → set -u で防止可能

  • 環境の反映: スクリプトを現在の shell に反映するには source script.sh を使う → 永続的に反映するには ~/.bashrc に追加

  • Bash は コマンドをキャッシュする: $PATH 内のファイル移動時に ENOENT が発生 → hash -r でキャッシュ更新

  • 変数を引用せずに使うと改行が空白として扱われる

  • set -e: スクリプトでエラーが起きると即時終了するが、条件文の内部(||, &&, if)では動作しない

  • K8s livenessProbe とデバッガの衝突: ブレークポイントデバッガはアプリ全体を停止させ、health check 応答に失敗 → Pod が終了する可能性がある

React

  • レンダリングコードで state を直接変更
  • Hook を if/loop の中で使用 → ルール違反
  • useEffect の dependency array に必要な値が不足
  • useEffectクリーンアップ(clean up)コードの漏れ
  • Closure trap: 古い state をキャプチャしてバグが発生
  • 間違った場所でデータを変更 → 不純なコンポーネント
  • useCallback の使用漏れ → 不要な再レンダリングが発生
  • メモ化されたコンポーネントに 非メモ化の値を渡す と memo 最適化が無効になる

Git

  • Rebase は履歴の書き換え

    • rebase 後に通常の push をすると衝突 → 必ず force push が必要
    • remote branch の履歴を変更した場合、pull も --rebase を使用
    • --force-with-lease は一部のケースで他の開発者の commit の上書きを防げるが、fetch だけして pull していないと保護されない
  • Merge revert の問題

    • Merge revert は効果が不完全 → 同じブランチを再度 merge しても変化がない
    • 解決策: revert の revert を実行する、またはクリーンな方法(backup → reset → cherry-pick → force push)
  • GitHub 関連の注意事項

    • API キーのような secret を commit した後、force push で上書きしても GitHub には記録が残る
    • private repo A を fork した B が private でも、A が public になると B の内容も公開される(削除後もアクセス可能)
  • git stash pop: conflict 発生時、stash は drop されない

  • .DS_Store は macOS が自動生成 → .gitignore**/.DS_Store の追加を推奨

Networking

  • 一部の ルーター・ファイアウォールはアイドル状態の TCP 接続を静かに切断する → HTTP クライアント・DB クライアントのコネクションプールが無効化される可能性 → 解決策: TCP keepalive を設定
  • traceroute の結果は 信頼性が低い → 場合によっては tcptraceroute のほうが有用
  • TCP slow start はレイテンシ増加の原因 → tcp_slow_start_after_idle を無効化して解決可能
  • TCP sticky packet 問題: Nagle アルゴリズムはパケット送信を遅延させる → TCP_NODELAY を有効にして解決可能
  • Nginx の背後にバックエンドを配置する場合、コネクション再利用の設定が必要 → 未設定だと高負荷環境で内部ポート不足により接続失敗
  • Nginx はデフォルトで パケットをバッファリングする → SSE(EventSource) の遅延が発生
  • HTTP 標準は GET・DELETE リクエストの body を禁止していない → body を使う例もあるが、多くのライブラリ・サーバーは対応していない
  • 1つの IP で複数の Web サイトをホスティング可能 → 振り分けは HTTP Host ヘッダと TLS の SNI が担当 → 単純な IP アクセスでは表示できないサイトが存在
  • CORS: 異なる origin へのリクエスト時、ブラウザはレスポンスへのアクセスを遮断 → サーバー側で Access-Control-Allow-Origin ヘッダの設定が必要
    • Cookie 送信を含む場合は追加設定が必要
    • フロントエンドとバックエンドが 同一ドメイン・同一ポート なら CORS の問題はない

Other

  • YAML の注意点

    • YAML は 空白に敏感key:value はエラー、key: value が正しい
    • 国コード NO は引用符なしで書くと false と解釈される問題が発生
    • Git commit hash を引用符なしで書くと数値に変換される可能性がある
  • Excel の CSV 問題

    • Excel は CSV を開くと 自動変換を行う
      • 日付変換: 1/2, 1-22-Jan
      • 大きな数値の不正確な変換: 1234567890123456789012345678901234500000
    • 原因は Excel が内部的に数値を floating point として扱うため
    • この問題により、遺伝子名 SEPT1 が誤って変更された事例がある

1件のコメント

 
GN⁺ 2025-08-18
Hacker Newsのコメント
  • 一部のルーターやファイアウォールは、アプリケーションに何のシグナルも送らずにアイドル状態のTCP接続を静かに切断してしまうことがある。HTTPクライアントライブラリやデータベースクライアントのようにTCPコネクションプールを維持するコードでは、その結果、何の警告もなく接続が無効化される問題を経験する。これを解決するには、システムのTCP keepaliveを設定するか、HTTPであれば Connection: keep-alive, Keep-Alive: timeout=30, max=1000 ヘッダーを使う方法がある。TCPコネクションは一度接続されると中間ルーターには状態が残らない。問題はファイアウォールやNATのセッションタイムアウトで、このときRSTパケットも来ない。K8s環境では conntrack モジュールの設定が低すぎた問題に遭遇したことがある。HTTP Keep-Aliveを使っても接続の再利用にしか効果がなく、ネットワーク上の接続そのものを維持するわけではない(説明リンク)。HTTP Keep-Aliveは実際にはパケットを発生させず、単に終了を先延ばしにするだけである。一方、TCP Keep-Aliveは定期的にパケットを発生させてタイマーをリセットする

    • TCP Keep-Aliveはモバイル機器ではうまく動作しないことがある。モバイルOSはアプリケーションレベルで発生するkeep-aliveパケットだけを個別に追跡・管理できる場合があるが、TCP Keep-Aliveはアプリケーションレベルより下で動作するため、状況によっては無効化されることがあり、その間もアプリは依然としてアクセス可能である
  • Optional<T> を返すメソッドが null を返すことがある。こういう慣行はあまりにも混乱を招く。感情的に余裕があれば、@java.lang.NonNullReference のようなアノテーションを導入するJEPを出していたと思う。このアノテーションで型を宣言すると、コンパイラが null の代入をエラー扱いするようにしたい。たとえばAlphaは null の代入が可能だが、Betaではエラーになるような形で。javac でもdead code eliminationが実際にどうなっているか仕様を見直す必要がありそうだ。たとえば if (true)b = null する部分は実際にはelidedされ、法的には許可されるコードなのかもしれない

    • Kotlinではすでにこのようなケースはコンパイルエラーになる。わざわざアノテーションは不要である

    • null のある言語で Optional<T> をあえて使う必要があるのか疑問だ。Pythonで関数の戻り値をOptionalオブジェクトではなく単に T | None と書くのと同じように、結局チェックが必要ならフレームワークとしての差別化が曖昧になる。特別なモナドスタイルを使わない限り、結局チェックは同じである

  • Java、C#、JSがインメモリ文字列をUTF-16系でエンコードしていると言っていたが、Javaについては誤りであり、C#やJSも同様かもしれない。どの言語でも文字列型が十分に不透明なら、インメモリ表現方式は実装詳細である。Javaでは9以降その点が明確になった(関連JEPリンク)。FFIがある場合に実装詳細の変更が難しい理由でもある。また、JSの数値についてmax accurate integerが 2^53−1 だと言われるが、実際には 2^100 のようなより大きい整数も正確に表現できる。2^53−1 というのは n-1, n, n+1 がすべてIEEE doubleで正確に表現されるという意味であり、したがって n == n-1, n == n+1 はどちらも false になる

    • C#はインメモリ表現がかなり固定されている。ReadOnlySpan<char> や生の char* でバッファに直接アクセスすることが多いため、char はUTF-16コードポイント型である。JSは何とか回避できるかもしれない

    • max accurate integerという表現より、max safe integerと言いたい

    • (Base64エンコーディング関連)Java、C#、JSのインメモリ文字列がUTF-16系ではないという点について、技術的には正しいかもしれないが、もしUTF-8ベースの言語で文字列をBase64エンコードしてからJavaでデコードすると、JavaのUTF-16表現のせいで問題が発生するケースがある

  • マニュアル形式のTipsや情報は、すでに知っていることやほぼ知っていたことほど理解が早く進むように思える。ほとんどのマニュアルは学習そのものより、整理や復習に効果的で、まったく知らない人に教えるには非効率である

    • マニュアルとは本質的に、記憶だけに頼らず記録を残すために存在するものである。たいていのUnixマニュアルはこの形だ。あるソフトウェアが何をするものかはすでに知っているが、具体的な使い方があやふやなときにマニュアルを引く。一方、完全な初心者が概念を学ぶにはチュートリアルやガイドが必要である。マニュアルは、より良い質問をするための準備物のような役割を果たす
  • 「Traceroute Isn’t Real」(トレースルートは本当ではない)という記事をとても興味深く読んだ。これまでトレースルートのデータが非常に不正確だったり意味がないように見えたりすることを実感していたが、その理由が分かって助かった(原文リンク)。もし最新情報があれば教えてほしい

  • この記事は実際の落とし穴やトラップというより、筆者が経験的に学んだ小さなTipsを集めたリストである。多くの内容は特定の狭い文脈でしか適用されないことがあるのに、その文脈が明確でなく、一部は誤情報のようにも見える。だから、記事全体をあまり額面どおりに受け取る必要はなく、一種の思考の流れやメモ程度に見るのがよい

  • Pythonでデフォルト引数の値は呼び出しごとに新しく生成される値ではなく、保存された値だという話は、datetime 変数を使うときにぜひ知っておくべきポイントである

    • Pythonを普段使う開発者ではなかったが、今週はデフォルト引数の値が保存されるという理由で本当に苦労した。引数にsetを渡さなければ空のsetを割り当てようとしていたのに、そのsetが再利用されてバグになった。理由を把握するまでかなり時間がかかった
  • ページ最初の「トラップ」で min-width: auto はコンテンツに応じて最小幅が決まると言っていたが、flex/gridでない場合は実際にはそうではない。MDNによれば、block、inline、tableなどでは auto は0に補正される(公式文書リンク

    • 本当の最初のトラップは、「どんなCSSプロパティも切り離して読むことはできない」ということだ。プロパティ名どおりcascading(カスケーディング)であり、デフォルト値と複数のルールの結果がどこかで合成されるので、文書全体の文脈が重要になる

    • CSSのテキストプロパティ側のcascade(継承)はまだ理解できる。しかしCSSレイアウトは、ページデザイナー、実装者、ユーザー、どの視点から見ても理解するのがあまりに難しい。いったい誰のためのデザインなのか共感できない

  • 全体としては悪くないリスト記事で、いくつか意見がある。

    • Unicode統合について、複数の言語で同じ意味の文字が同じコードポイントを使い、フォントによって異なって表示されることはトラップではない。提示された例のような漢字は中日両方でほぼ同じように使われ、どちらの言語の利用者も別の字形を同じ概念の文字として認識する。筆者は、あたかも英語の A とフランス語の A を別々に定義すべきだと言っているようなものだ。実際にはそうではない。Han unification の項目を参照
    • -0.0+0.0(負の0、正の0)は浮動小数点比較では等しいものとして扱われるが、区別する方法はある。それぞれのビットパターンや、1.0/-0.0 = -∞, 1.0/0.0 = +∞ という結果で確認できる
    • サーバーのタイムゾーンをUTCにそろえろという助言には強く同意する。サーバー、ログ、写真保存など、保存価値があったり正確なタイムスタンプが必要だったりするあらゆる場所でUTCを使い、ローカルタイムは会話にだけ使うべきである
    • 整数で (low + high) / 2 はオーバーフローの危険があるので low + (high - low) / 2 を使えと言っていたが、lowhigh が負になり得るなら、オーバーフローの範囲を移しているだけかもしれない。一般的な二分探索で重要な問題である
    • C/C++で整数型および演算を正しく使うことも大きな落とし穴である。関連ガイドリンク
    • rebaseがhistoryを変えることがあると言っていたが、rebaseとはそれ自体がhistoryを書き換えるcommandである
    • 両言語の利用者が概念的には同じ文字として認識するとしても、単なる「フォントの変形」程度に片付けてはいけない。Unicodeコードポイントが同じだからといって安全に文字置換できるわけではない。日本のユーザーの立場では、このような置換が製品利用を拒む理由になり得る

    • 実際、英語のAとフランス語のAは区別しないが、А(キリル文字)と A(ラテン文字)のように見た目が同じでも実際には別のコードポイントとして存在するものがある。Han統合も、外見がかなり異なる文字をひとつにまとめる場合が多く、日本語や中国語の学習者なら実際に混乱を経験しうる。たとえば (drink)という字は リンク のように表示によってかなり違って見える。コピーしてみると、その場ですぐ形が変わることさえあり、処理方式がかなり複雑である。Han unificationは現実的にかなり厄介なテーマだ

  • numpyとpytorchの間に微妙な違いがあると言及していたが、具体例の説明なしではあまり有用ではなく、情報も不足しているので、現実的な落とし穴とは感じられない