hkoba blog

プログラマーです。プログラミング言語ミーハーです。ツッコミ歓迎です。よろしくどうぞ(能代口調)

私信:CS にも過渡現象論みたいな位置づけの理論があると良いのかも?みたいな…

この記事は、この方のつぶやき

に対する、@pokarim さんの、

この辺りのツイートに、私がこう、ぽやん…

と感想をぶら下げて始まった対話の、お返事です。

ぽかりむさんへ

私の考えがどんなものか、なぜその考えに至ったか(特に Immutability についての考え方の由来)、それに基づいて行動した結果どんな経験を得られたか、少しお話させて下さい。(結論は無いです)

まず私の考えを改めて文章にしますと、

『電気工学では、定常状態の理論と、過渡現象の理論を別立てに分けている。この結果、それぞれ定常状態の理論は単純で初等数学でも理解しうるものになり、過渡現象の理論は複雑な現象を誤魔化さずに記述し切ることが可能になっている』

『同様の分け方が、プログラミングや計算機科学の世界にも、有って良いのではないか。何故なら、理論とはモデル化であり、人の理解を助けるためののものであるから。一つのモデルで最終状態と途中の変化を両方記述しようとして、かえってモデルが複雑化して理解しづらくなったら、本末転倒』

『特に、Immutable な世界と、State の Mutation を取り扱う世界に関して、理論を分けて持つことが、同様のメリットを生むのではないか』

です。

なぜこの考えに至ったか

源流らしきものは2つありました。

一つ目は25年ほど前、電気工学科の(落第寸前の)学生だった頃のこと。OPアンプの負帰還増幅回路の動作を習う時に、教授から示唆された仮説です。雑でおぼろげな記憶ですが、

『そもそも人間は時間変化する現象を(言葉だけで)イメージ化して理解することが苦手なのだ。負帰還増幅回路を理解しようとする時も、「入力が増えて、増幅された出力が出て、それが遅延されて入力に入って…」のように時間変化に沿って理解しようとすると、かえって難しくなるのだ。それよりも、「- 端子と + 端子の入力の値が最終的に一致するように動く」というゴール状態から理解する方が優しい』

といったものでした。(当時は、ほえ〜、そういうものか〜、たしかに逐次で追うのは大変そうだな〜、位の受け止め方でした) 最終状態の不変式で理解するのが楽だ、という考え方だったのかもしれません。

もう一つは院の輪講で、確か…タネンバウムの分散システム関連の書籍を学んだ際に触れた、Immutability の効能の話です。

(分散)並列計算をまともに(?)機能させるためには、レース状態の入り込む個所を減らす・無くすことが大事で、そのためには(並列システム間でやり取りされる)public/published な値を全て Immutable とするのが最も単純で効果的である…

みたいな議論だった気がします(用語や論旨は脳内で補っているので雑です。書籍にそう書いてあったかどうか自体、ちょっと怪しいです。輪講の中での議論で出た話題だったかもしれません)。値は Immutable にした上で、更新はディレクトリ(インデックス)上の参照の差し替えで表現する、分散ファイルシステムなどでオーソドックスなやり方の話です。(同時期にデータベースの授業でトランザクションの話も聞いていたので、その影響もありそうです)

どんな経験が得られたか

この 20年ほど、仕事で私がデータ保存を伴うプログラムを作る時は、原則として Immutable なレコードの追記型ストア+その上のインデックス、という構成を取ってきました。(と言っても、誇れるほどの仕事の幅はないのですが…) インデックスの貼り方に頭を使う必要はあるものの、大事な一次データが絶対に消えない(最悪人力でサルベージできるし、インデックスもログからリビルド出来る)安心感は、大きかったと感じています。ですから、(システムから観察できる published な) 値を Immutable にすることのメリットは大である、と考えます。

それに対して過渡的な現象、状態の変化の過程をどう記述するべきかですが、変化の記述にまで Immutability を追求すべきかどうかについては、正直、そんなに拘らなくても良いのでは?と感じております。(最初に挙げた、published な値を Immutable にすることの、実用的なメリットと比べて、です) マルチスレッドプログラムで言えば、スレッドのスタックに乗っているprivate で一時的な値と、そこから(共有メモリやチャネルを使って) 他のスレッドから見えるように公開した値では、扱いを変えてよいのでは、という考えです。

もちろん、プログラムのモジュール性を向上させるために一時的な値であっても破壊を避ける、読みやすさを助けるために変数の使い回しを避ける、という話はあるでしょう。しかし、いずれにせよ、マシンのレジスタは使いまわされているし、L1, L2.. キャッシュも使いまわしてこそ性能が出るものです。命令のスケジューリングと記憶域の使い回しを、人の書くプログラムから完全に捨象せんとする努力が、(尊いことでは有るけれども) メリットだけなのか (デメリットはないのか?) という、立ち止まって振り返ることも大事なのではないか、そのように考えています。

間接的なヒントとして…10年前の私は SQL を書くのが嫌いで、ORM を使うべきだと考えていました。その後、複雑なクエリを ORM に吐かせることに疲れ、かつ SQL を書く力も上がった今では、 ORM を使うより SQL を書くほうが手堅い、と感じるようになっています。

結論なしの尻切れトンボですが、あまりお待たせするのも申し訳ないので、このくらいで終わりにします。ぽかりむさんの考えとは違うところもありそうですが、何かのヒントにでもして頂ければ幸いです。ではでは〜♪