WebDB アプリの苦悩 -- HTTP と DB と OOP と --

pokarim さんの WebDB アプリの発言に対して cocoatomo が反応して始まった会話を載せてます. pokarim さんの問題意識: HTTP リクエスト ←(綺麗に対応しない)→ SQL クエリ ↓ cocoatomo の返答: OOP のメソッドで SQL クエリを包んだら? 続きを読む
3
pokarim @pokarim

WebDBアプリの記述はなぜ手続き的になるのか。なぜリクエストをクエリーに変換する関数とクエリー結果をレスポンスに変換する関数の2つで書けないのか。その理由は、一般的に1リクエストにつき複数のクエリーが必要で、その上あるクエリーの結果に基づいて別のクエリーを投げる必要があるから。

2010-07-10 11:38:19
pokarim @pokarim

WebDBアプリの記述はなぜ手続き的になるのか。なぜリクエストをクエリーに変換する関数とクエリー結果をレスポンスに変換する関数の2つで書けないのか。その理由は、一般的に1リクエストにつき複数のクエリーが必要で、その上あるクエリーの結果に基づいて別のクエリーを投げる必要があるから。

2010-07-10 11:38:19
pokarim @pokarim

WebアプリがHTTPとDBクエリーの相互変換で書けるならコードは副作用を扱わずに書け相当単純になる。関数型言語であるなしに関わらず副作用を多く含むプログラムは複雑になるし、そうでなければ比較的簡単にかける。

2010-07-10 12:09:36
pokarim @pokarim

ひとつのリクエストを処理するのに、DBに一発クエリーを発行して、その結果をもとに別のクエリーを出す必要がある。それを元にさらに別のクエリーを出す必要もあったりする。つまり副作用だらけ。こう考えるとWebアプリ開発の面倒さの本質が見えてくる。

2010-07-10 12:16:58
pokarim @pokarim

典型的なWebDBアプリでは変更可能な状態はDBにしかないわけで、原理的にはアプリサーバ部分のロジックは副作用を扱わずに書けるはず。それはRDBではできない。それはなぜか。それを可能にするようなDBモデルはどうしたら構築できるか。もちろんDB側の手続き的記述は無しの方向で。

2010-07-10 12:27:22
pokarim @pokarim

関数型言語界隈でも、GUIやシミュレーションなどの状態の変化や副作用の取り扱いが支配的なプログラムを宣言的に書けないものか、という問題提起はあってそれに対する答えのひとつがFRP(Functional Reactive Programming)。

2010-07-10 12:45:33
tomo🐧@learning @cocoatomo

1つには HTTP と HTML という仕組みの性質が「手続き型」を強要するからだと思う. >なぜ Web アプリは副作用だらけ? by @pokarim | メソッドより粒度の細かいHTTPリクエストと状態を保持するのが苦手なHTMLと更新速度が気になるRDBの合わせ技だと思う

2010-07-10 15:20:42
tomo🐧@learning @cocoatomo

Web アプリの元凶が前 Tweet の通りだとしたら, 1ページより大きく1セッションより小さいスコープ (メソッドサイズ) を作らないと. それと SQL バンバン飛ばすのは行儀良くないとされてるので, メソッドを抜けるごとに commit するような仕組みを作らないと.

2010-07-10 15:31:32
pokarim @pokarim

それもひとつの答えだが、状態がDBにしかないなら、HTTPリクエストからクエリー、クエリー結果からレスポンスの関数的な変換でアプリ部分はかけるはず。理論的には。 RT @cocoatomo: 1つには HTTP と HTML という仕組みの性質が「手続き型」を強要するからだと

2010-07-10 15:34:44
pokarim @pokarim

つまりHTTPだけが問題なのではなく、1HTTPリクエストが単純に1SQLクエリーに対応しないことが手続き的になる原因だと思う。 RT @cocoatomo: 1つには HTTP と HTML という仕組みの性質が「手続き型」を強要するからだと思う. >なぜ Web アプリは副作

2010-07-10 15:39:45
tomo🐧@learning @cocoatomo

なるほど, ここは納得. > 1HTTPリクエストが単純に1SQLクエリーに対応しないことが手続き的になる原因 by @pokarim

2010-07-10 15:42:08
tomo🐧@learning @cocoatomo

業務屋としては, DB に頻繁にクエリを投げるのはためらわれる. 計測などをしていなく不勉強なため, あくまで感覚的にしか言ってないが. AP に DB のキャッシュ機能があれば良さそう. そうかそれで結局 HTTP リクエストと DB クエリの対応の話になるのか.

2010-07-10 15:44:31
tomo🐧@learning @cocoatomo

HTTP ってシンプルすぎて拡張しようと思えない. それともともと Web 自体が静的コンテンツ (論文とか) の閲覧用だったから, 動的なものに弱いのはしょうがないのかな?

2010-07-10 15:47:41
pokarim @pokarim

メソッドの指すところを知りたい。あと1リクエストの処理につきSQLをばんばん飛ばすのは現状そうせざるを得ないような。 RT @cocoatomo: Web アプリの元凶が前 Tweet の通りだとしたら, 1ページより大きく1セッションより小さいスコープ (メソッドサイズ) を

2010-07-10 15:48:46
pokarim @pokarim

@cocoatomo DBクエリをキャッシュするかどうかはパフォーマンスの問題で、アプリ側のロジックの書き方には影響をあたえない。変更可能な状態がDBからキャッシュに移っただけだから。

2010-07-10 15:51:25
pokarim @pokarim

例えばひとつのHTTPリクエストを処理するために、まず権限チェックをして、バリデーションをして、業務ロジックのルールのチェックをして、それから複数のINSERT/UPDATE文にわけて書き込みして、さらに結果の画面をつくるためにも、複数のSELECT文を発行する必要があったり。

2010-07-10 15:55:09
tomo🐧@learning @cocoatomo

手続き型の関数や #OOP のオブジェクトの public メソッドというイメージ > メソッド | それくらいが1つの処理と呼ぶのにちょうど良い大きさだと思う. 「キャッシュ」は DB のデータのキャッシュのことです. まぁ一緒か. パフォーマンスも問題意識にあります.

2010-07-10 15:55:45
pokarim @pokarim

例えばDjango等だと1リクエストを1つの手続きで処理するけど、その手続きの中身が複雑な副作用だらけなことを問題視しています。複雑なままひとつにまとめても解決にはならない。 RT @cocoatomo: 手続き型の関数や #OOP のオブジェクトの public メソッド

2010-07-10 16:03:07
tomo🐧@learning @cocoatomo

なるほど, 理解しました. 難しいですね... RT @pokarim: 例えばDjango等だと1リクエストを1つの手続きで処理するけど、その手続きの中身が複雑な副作用だらけなことを問題視しています。…

2010-07-10 16:07:13
tomo🐧@learning @cocoatomo

DB からはクエリ, クライアントからは HTTP を通して, AP 上の #OOP にマップしても複雑さは減らないしなぁ. 仕組みが違うから複雑になるだけだし, 第一その AP 上の GC は誰が行うんだ?? ヤバい死ねる.

2010-07-10 16:08:45
pokarim @pokarim

本当は副作用ばかりで手続き的にしか書けないことが問題なのではない。副作用入りの手続きは、純粋な関数よりも、部品化や合成がしづらいために、目を細めて見れば同じような処理なのに、細部の違いのために毎度1から書きなおす必要があるのが問題。

2010-07-10 16:12:21
pokarim @pokarim

そう!"#OOP にマップしても複雑さは減らない" RT @cocoatomo DB からはクエリ, クライアントからは HTTP を通して, AP 上の #OOP にマップしても複雑さは減らないしなぁ. 仕組みが違うから複雑になるだけだし, 第一その AP 上の GC は誰が

2010-07-10 16:13:31
pokarim @pokarim

業務アプリだと、ある程度まじめに正規化していても、ほかの部分のデータから計算で求められるようなデータをどうしても永続化する必要がある。もちろん本質的にはパフォーマンスの問題だが、キャッシュでは解決できない種類の問題もある。

2010-07-10 16:17:39
tomo🐧@learning @cocoatomo

どっちかと言うと #OOP って複雑なものを上手く分類して複雑なまま扱うための仕組みだから, HTTP や RDB と相性悪いんだろうなぁ.

2010-07-10 16:19:53
pokarim @pokarim

たとえば何らかの集計値を格納しておきたい場合は多々あるが、単純に集計結果をキャッシュするだけでは更新時の処理がO(n)になってしまうため、更新時には集計結果をインクリメント・デクリメントする処理を書いてO(1)になるようにする必要があったりする。

2010-07-10 16:21:50