プログラミングにおける偶然
「書いたとおりにしか動かない」プログラミングにおいて、それでも何かが「偶然」起きてしまうことはある。それが「偶然」であったことは、失ったときにはじめて気づくことが多い。(起こり得ることは起こる) 偶然性の類型
時限型
「今はたまたま噛み合ってる」ってやつ
「それ仕様変わったらどうすんの?」的なツッコミが入る
確率型
うまくいかない確率が極端に低いやつ
軽視されていたり、そもそも気づかれていなかったり
頻度だけで軽視されたリスクが実際に発生するとめちゃくちゃ深刻なこともある
自覚して割り切れてるならそれでいい
結局はリスクヘッジ。コスパが悪いと判断してあえて対応しないことも多々ある
/icons/hr.icon
互換性の偶然
2つの型が「偶然」一致していた
TypeScriptのような構造的部分型の言語でよくある例
fnA(fnB())
A、Bを書いている人はこれらが組み合わせて使われるとは思っていない
複数のライブラリをまたいでいるときに顕著
たまたま互換性のある型で、たまたま相互運用できていたライブラリAとB
どちらかのアップデートで簡単に世界は壊れる
BufferとかStreamとかNodeとか、そういう根底の型と関わって発生することが多い
制御の偶然
問題のあるコードが「偶然」実行されていなかった
通っていない条件分岐
その条件に分岐したら壊れるコードなのに、いままで偶然その条件になってなかったとか
例外処理のコードに問題があるのに、いままで偶然一度も例外が発生していなかったとか
特定の環境(端末、OS、ブラウザなど)では問題があるのに、いままで偶然その環境のユーザーがいなかったとか
順序の偶然
並列に動くコードが「偶然」噛み合っていた
実は順序に依存している並列処理だが偶然常に同じ順番で動いていたとか
仕様上は順不同なはずのデータが常に同じ順序で与えられていて、偶然ソート処理なしでうまく動いていたとか
タイミングの偶然
暗黙のレイテンシによりユニーク性を獲得していたとか
プログラムの実行が偶然遅かったので今まで同一タイムスタンプのレコードが生まれていなかったとか
パフォーマンスが上がったことでマイクロ秒レベルで一致してしまい順序が壊れるとか
並列化したことで同一タイムスタンプがありえるようになるとか
マイクロサービスのデプロイタイミングが偶然いつもほぼ同じだったとか
デプロイ時間に差が出るとそのスキマ時間に生まれたデータが致命的に不整合だったとか
フォーマットの偶然
「偶然」データのフォーマットが限られていた
たとえば文字列とか
タイトルテキストがいままで偶然10文字以内だったから一行で表示できていたとか
長いテキストが入って折り返されるのか途切れるのか ... になるのか挙動を自覚していないケース
いままで偶然2バイト文字だけだったとか
サロゲートペアで壊れたり、絵文字で壊れたり
たとえば画像ファイルとか
画像サイズがたまたま小さくてアップロードできていたとか
たまたま今まで向きが揃っていたとか
たとえば時間とか
タイムゾーン考慮してなかったが、日本在住のユーザーしかいなくて偶然うまく動いていたとか
海外在住の日本人が使ったときにデータの整合性が壊れたとか
端末の時刻設定に依存していたが、偶然どのユーザーも時刻設定が正しくてうまく動いていたとか
常にネットワーク同期されてるとは限らない
時計がずれた端末から作られたデータで整合性が壊れるとか
識別子の偶然
識別子が偶然一致していた
Enum的な値に対して自由形式の文字列で参照しているとか
文字列に対して正規表現で種別を判断してるとか
メッセージの正規表現でエラー種別を判定する /bad request/i.test(error.message) 的な所業
「判定に使ってるその文字列、フリーテキスト部分じゃないの?」ってツッコミを入れるところ
オーディエンスの偶然
オーディエンスの偏りから偶然求められていなかった
Right-to-Left言語への対応とか
アクセシビリティとか
キーボードでの操作とか
テキスト読み上げとか
権限の偶然
権限が必要な処理が、偶然許可されていた
ローカルマシンだと問題ないのにコンテナ環境で実行したら権限が足りなかったとか