ハイラムの法則とそれにまつわる私の経験

 ソフトウェア開発をしているとさまざまな法則を耳にする。有名どころで言えば、ブルックスの法則やコンウェイの法則などである。最近 Software Engineering at Google を少しずつ読んでいたらハイラムの法則 (Hyrum's Law) というのが紹介されており、聞いたことがなかったのでまとめておく。なお、この Hyrum とは何者かというと Software Engineer at Google の著者である。説明の動画もある。

ハイラムの法則

あるAPIに十分なユーザー数がいれば、契約で何をとり決めるかどうかは問題ではない。 システムにおけるすべての観測可能な動作は誰かに依存する。

 分かったような、分からないような内容である。私の理解でまとめると、『API を実装した設計者の望む振る舞いと利用者の期待する振る舞いに乖離が生じた場合、利用者の期待する振る舞いこそがシステムの動作を決めてしまう』である。

 利用者の期待する振る舞いが保証されていない偶然の動作に依存していると、予期せぬバグが発生する。そしてそれゆえに元のAPIに仕様上は問題ない変更(たとえば高速化や効率化)が暗黙の期待を裏切り、バグが発生、暗黙の期待が広範囲に及んでおりさらにはテストコードもないためメンテナンスも難しい。そんなことは日本のソフトウェア開発のそこかしこで起こっているのではないだろうか。

 Software Engineering at Google では HashSet にて要素を取り出す例が載っていた。

for i  in {"apple", "banana", "carrot", "durian", "eggplant"}: print(i)

 このような時にどのような表示がされるか? というのがお題である。この例では一緒であるがキーの入力した順に表示されるかもしれない。文字列をソートした順に表示されるかもしれない。全然わからない順番に表示されるかもしれない。 正解はどのような順番に表示されるかは決まっていない。 Python では 3.7 以降において dict 型では順序が保持されることが規定された [※1] 。 Go では、意図的に出力結果が毎回異なるようになっている [※2] 。ハッシュの内部の順番というが実装依存であるため、あえて毎回暗黙の前提を壊すようにしている。

 身近なところで見た似たような経験だと ORDER BY を記載していない SELECT 文を発行したが、結果に対し id 順に返ってくるのを期待しているコードを見たことがある。 テストコードも不十分だったのでコードはマージされたが検証環境で並び順がおかしいと気づいたと記憶している。

 偶々うまくいったことをそれがあたかも決まりであるかのように捉えてしまうことは割とよくある人間の認知のバグだと思う。そのため、仕組みでそれらを防げるようにすることは大事である。しかしながら、利用者というものは製作者の意図通りには動かないものである……。

脚注

※1 2017 年 12 月のメーリングリストに記載されている。Python 3.6 の段階で取り出す際の並び順が挿入順と等しくなったが、これは実装の詳細であるが依存するなという注意書きがある。なお、 Python には明確に並び順を規定した OrderedDict という型もある。余談であるが、  LRU キャッシュは OrderedDict で実装するのが効率が良い。 LRU キャッシュ自体 functools に用意されているので、自分で実装する機会はそんなにないだろうが内部の実装に関する知識を持っていて損はないかと思う。
※2 Go 1.3 のリリースノートに本記事に記載した理由が記載されている。 Rob Pike 先生など Go 作成陣はこのような予期せぬ依存での障害の経験があったのかなぁと思いを馳せている。

目に見える形でのおめぐみをいただけたら幸いです……。