SQLer 生島勘富 のブログ

RDB・SQLの話題を中心に情報発信をしています。

MVCがなぜ間違っているか?

WebシステムにMVCを適用するのは間違っています(正確にはインターフェースが足りません)。

paperface.hatenablog.com

このように思考停止したエンジニアにはわからないかもしれませんが、もう一度解説してみましょう。

目次

そもそもMVCとは?

f:id:Sikushima:20210622132734p:plain
MVCができた頃

MVCは、スタンドアロー向けのプログラムがあまりにぐちゃぐちゃだったので、「違う機能は疎結合にしよう!」という考えで作り出されました。 1980年代の頃のお話です。 それ自体は正しいです。

歴史を振り返ってみましょう

WebシステムでMVCを使おうと言われ出したのは2000年頃からです。

この辺りを理解するには、少し歴史を知る必要があります。

1995年頃(私の新人時代)にJavaが生まれましたが、当時はAppletでした(はっきり言って使い物になりませんでした)。 1995~2000年にかけて、Y2K2000年問題)が起きました。 COBOLでは、西暦を2桁で保存することが一般的だったため、「2000年以降システムが動かなくなる」という問題で、システムを改修するか、クラサバで作り直すか、いずれかが選択され、クラサバシステムがたくさん作られることになりました。 このときRDBMSがメジャーになり、人材が足りませんからCOBOLerが大量に流入してきました。

イベントドリブンが分からないCOBOLerが、仕様を決めたり、コードレビューをするような上の立場にいるわけです。 本当に混沌とした時代でした。

このときCOBOLer達は、「RDBMSはストレージ、SQLはファイルの読み書きをする方言」とやり過ごしました。

イベントドリブンが分からない上に、「俺が分からんから配列は禁止」とか言い出す人がたくさんいましたから、私たち分かっている世代は、まずはSQL以外の不毛なバトルを繰り広げる必要があり、SQLまで手が回らなかったのです。

結果、「RDBMSはストレージ、SQLはファイルの読み書きをする方言」というのが文化として残ってしまったのです。

2000年以前は、ブラウザがCSSに対応していませんでした。 HTML自体がデザインを分離できていませんでしたから、WebシステムでMVCを唱えることも事実上無理でした。

2000年になりドットコムバブルの中で、ServletJSPCSS(が使えるブラウザ)などが生まれます。

Viewを分離することができるようになって、「MVCにしようぜ」という流れができるのです。

この流れ自体は間違いではありませんが、残念ながら、「RDBMSはストレージ、SQLはファイルの読み書きをする方言」というCOBOLerの遺伝子は残ってしまいました。

インピーダンスミスマッチとORMの登場!

MVCを適用していく中で、「インピーダンスミスマッチ」ということが表面化されていきます。

f:id:Sikushima:20210622132742p:plain
インピーダンスミスマッチ

これを解決するために、ORMなるものが開発されました。

f:id:Sikushima:20210622132831p:plain
ORMができた

さて、この図をしっかり見てみましょう。Viewには、CSSJavaScriptなど、Webサーバ(ブラウザ)が管轄するものと、APサーバが管轄するものがあります。

Controlは、APサーバに限定されます。

Modelは、APサーバと、DBサーバに分かれますが、なぜかSQLはAPサーバの管轄になっています。 PHP(Eloquent)RubyActiveRecord)などで覆っても、私から見れば、オブジェクト指向言語的には「異物」以外に表現しようがありません。 ORMを使ったソースは、オブジェクト指向言語的にものすごく汚いソースにしか見えないのですが……。 それに、ORMの機能をViewに当てはめて考えれば、「PHPで書けばJavaScriptCSSを自動生成してくれる」ぐらい奇妙な構造になっています。

これを奇妙と思わない人は、「RDBMSはストレージ、SQLはファイルの読み書きをする方言」というCOBOLerが作った文化を引き継いでいるからです。

こうあるべきでしょう?

f:id:Sikushima:20210622132855p:plain
こうあるべき(APIが必要)

まったく逆のアーキテクチャであるSQLをModelに入れるということに無理がある。 オブジェクト指向を正しく理解していれば、「違った機能は疎結合にする」というMVCの理念を理解していれば、DBサーバにインターフェースを置く必要があると分かるはずです。

DBサーバにインターフェースを置くとして、RDBMSのメモリー空間でインターフェースとして扱えるのはストアドプロシージャになります。 つまり、「APIとしてストアドプロシージャを使うべき」という結論になる訳です。

そうならないのは自分のスキルで、「できる・できない」からスタートしているからですよね?

ストアドプロシージャにすることに問題はないの?

もちろん、問題はあります。 すべてストアドプロシージャにするには、現状の一般的なエンジニアが持っているSQLを書くスキルでは全く足りません。

ほとんどのエンジニアは、SQLにおいてStaticおじさんよりひどいからです。

sikushima.hatenablog.com

この問題はSQLのスキルを端的に測れます。 基本構文の問題ですから、これを間違う人でRDBMSに係ってプロとしてお金を貰うのは詐欺と言っても良いけれど、いろんなところでやってもらいましたが正解率は5%ぐらいです。Staticおじさんを批判している本人が、Staticおじさんよりはるかに問題の「LEFT JOIN決め打ち」をやっています。

sikushima.hatenablog.com

世界10億サイト(ページじゃないよ)で使われているWordPressの変換を見ても分かる通り、日本だけではなく世界的に分かっていません。

Fetch してグルグルしない

スキルが足りない人にとっては、ストアドプロシージャにすると言うと、

「ストアドプロシージャみたいな完成度の低い言語(めっちゃ低い)で Fetch してグルグルしたらめっちゃ大変……」

と考えるのでしょう。

スキルが足りない人が、「Fetch してグルグルする」ようなことをしたらシステムは一瞬で破綻します。

もちろん、まったくFetchしないわけではありませんが、弊社で基幹システムを丸ごとストアドプロシージャで作ってもFetchするのは1%ぐらいです。

例えば、基幹システムでFetchする機能には、請求書を作る機能があります。 と言っても、得意先コードを指定して請求書を作る処理はFetchする必要はありません。 しかし、締め日を指定して一括で請求書を作る場合、指定された締め日の得意先の一覧を取得し、先ほどの得意先コードを指定して請求書を作るストアドプロシージャにFetchして渡します。

そういうものを数えても1%ぐらいです。

「得意先コードを指定して、1件分の請求書を作るだけならFetchしないでSQLで処理できる」

というスキルが必要です。 そのスキルが猛烈に高いかというと、現状では高いでしょう。 しかし、弊社のセミナーでは、プログラミング未経験の事務員さんが3日もあればできるようになります

文字列連結は要らない

「ストアドプロシージャみたいな完成度の低い言語(めっちゃ低い)で文字列連結してSQLを構築するなんて……」

と思う人もいるのでしょう。 先ほどの請求書を作成するSQLなど、とても複雑な処理をしていますが、文字列連結でSQLを構築することは弊社ではほぼありません。 こちらに詳しく書きました。

sikushima.hatenablog.com

どちらが極端ですか?

「すべてストアドプロシージャにするべき」というと、極端だと言われますが、どちらが極端ですか?

まったく真逆のアーキテクチャーであるSQLを、オブジェクト指向言語の中で動的生成する。 冷静に考えれば、そんな極端なことはありません。

ほとんどのRDBMSは、オブジェクト指向言語C++で書かれています。 CPUはSQLなんて理解できませんから、オブジェクト指向言語で書かれたRDBMSが翻訳をしているのです。

翻訳された結果は、「実行計画」として見ることができます。

同じSQLでも、実行計画が変わるSQLの例。

f:id:Sikushima:20210622144219p:plain
実行計画1
f:id:Sikushima:20210622144310p:plain
実行計画2

実行計画をオブジェクト指向言語に直すとこんな感じになります。

f:id:Sikushima:20210622144330p:plain
Javaにすると

SQL → 実行計画 → オブジェクト指向言語

という変換ができるようになれば(というか、それができない人がエンジニアで良いのか?)

オブジェクト指向言語SQL(自動生成)→ オブジェクト指向言語(自動生成)

という、実行時に「車輪の再開発」が起きていても「便利だ」と極端なことを考えるはずがないです。 そんなことを考えてしまうのは、「SQLのスキルが圧倒的に足りない」ことを証明しているだけの話です。

分離開発するべき

SQLオブジェクト指向言語は、真逆のアーキテクチャです。 私はどちらも同じにできますが、それでも同時に考えるのは困難です。

これだけSQLができないエンジニアがいるのですから、SQLを担当するエンジニアと、オブジェクト指向言語を担当するエンジニアを分けた方がよい。 ストアドプロシージャにすればそれが可能になるのです。

SQLと、オブジェクト指向言語を担当するエンジニアが分かれれば、オブジェクト指向言語を担当するエンジニアはSQLを知る必要もない。

現状では、全員がSQLを理解している必要がある。 そんな極端なことはやめた方が良いでしょう。