秋月 巌 AKIZUKI,Iwao
| なぜDelphiではなく,Visual Basicなのか |
|---|
最近,Visual Basicを見直している.私は本誌に記事を書いているために,Visual Basicで長くプログラミングをしているように思われがちだが,Visual Basicを使いだしたのはMicrosoft Visual Basic 4.0の発売後である.データベースシステムの開発者である私は,オリジナルでデータベースアクセス機能を搭載していない,それ以前のバージョンには興味がなかったのである(Visual Basic 3.0のデータベースアクセスサポートは極めて貧弱だった).
Borland Delphiの最初のバージョンが発売されたのは,Visual Basic 4.0が発売される少し前である.単行本にする原稿を書こうと思い立った私は,手元にあったDelphiを使ったデータベースプログラミングの本を執筆するつもりであった.しかし私が実際に書き始めたのはVisual Basicを使ったプログラミングの本だった.Delphiの本では,出版社が採用してくれないのではないかと心配したのである.今思えばそれは杞憂だった.その後にDelphiの本が多数出版されたことを考えれば,私がDelphiの原稿を書いたとしてもおそらく出版されただろう.
| 古き良き時代 |
|---|
今ではCorelに里子に出されてしまったParadox for Windowsを気に入っていた私がDelphiに注目したのは,当然のことだったといえる.Delphiの標準データベースエンジンであるBorland Database Engineは,Paradox for Windowsのエンジンなのである.それは,Visual Basicの標準データベースエンジンであるJetデータベースエンジンがMicrosoft Accessのエンジンであるのと同様の構図である.
当時,Visual Basicは本命であったとはいえ,C/Sシステム開発ツール戦争の一参加者に過ぎなかった.時代としては,Gupta社(現Centura Software社)のSQL Windowsが最先行していたように思う.逃げるSQL Windowsと,Visual Basic.僅差で追走するPowersoft PowerBuilder,後発ながら圧倒的な品質で追い上げるDelphi,一方でParadoxやAccessがファイル共有型のデータベース開発ツールとして存在していた.すばらしい時代である.すべてのツールが未熟であり,帯はおろかたすきにするにも短かかった.
当時,マシンのパフォーマンスはWindows 3.1を動作させるには十分でなく,わずかな機能の有無やパフォーマンスの差が採用の可否を決していた.その頃もっとも私が肩入れしていたのは,DelphiでもVisual Basicでもなく,Computer Associates社のVisual Objectsである.この製品はxBaseコンパイラとして米国で一世を風靡したClipperの後継製品である.予告の広告ではVisual Clipperと呼ばれていたが,発売時にこう改名された.Watcom SQL(現Sybase SQL Anywhere)がバンドルされているもっとも低価格な製品であった(要するに私はデータベースサーバーが欲しかったのだ).Visual Objectsは,Clipper伝統のネイティブコンパイラと美しい開発環境を誇っていたが,Ver2はアナウンスがされただけでリリースされることはなかった.
その頃,VBキラーとしてもっとも注目されていたのは,Oracleが開発を進めていたProjectXと呼ばれるプロダクトである.このツールは,のちにOracle Power Objectという名称で発売されるが,期待に応えるだけの普及はしなかった.数多くの開発ツールが記憶から薄れてゆき,十分な成果をもって残ったのは,Visual Basic,Delphi,PowerBuilder,Accessであるといえるだろう.
| 時代を生き抜いたその理由は… |
|---|
ではこれらのツールが他製品と比べて優れていたかといえば,そんなことはない.
Visual BasicやDelphiは汎用言語の限界で,データベースへのアクセス機能や,ユーザーインターフェイスの表現力は不十分だったし,PowerBuilderは,その高機能ゆえに当時のバージョンではバグに悩まされた.Accessは多大な可能性を持つツールだが,やはり,障害の多さとリモートデータベースへの接続機能の貧弱さは問題だった.
もちろんパフォーマンスと機能のバランスで傑出していたのはDelphiである.またPowerBuilderのデータウィンドウはデータベースプログラム開発者にとっては,福音ともいえる機能だった.
ではVisual Basicは,果たして何が優れていたのだろうか? 個人的な意見としては,少なくとも国内におけるVisual Basicの最大の魅力は,酒井法雄氏が中心になって執筆していた本誌の存在だった.もし翔泳社がDelphi Magazineを発刊し,その記事を酒井氏が執筆していたならば,日本におけるVisual BasicとDelphiの関係は大きく変わっていたに違いない.
| 最新のC++開発ツール |
|---|
この一年間で,Powersoft Power++とBorland C++Builder3という,すばらしいC++開発ツールがリリースされた.データベースシステムの開発ツールとして圧倒的なアドバンテージを持つPower++と,全体のバランスとクオリティにおいて,現在,最高のWindowsアプリケーション開発ツールであるC++Builderは,開発ツールの総合的な能力としてVisual Basicを大きくリードする.とくにC++Builder3は,ほとんどすべての点のおいてVisual Basicより優れている上,なおかつMFCをサポート(その方法は洗練されていないとはいえ)することで拡張性をも確保している.
この最新のC++Builderを評価した私は,それ以降作成するアプリケーションのすべてをこのツールで作成しようと思った.ATLやActiveXコントロールの作成機能を備えたC++Builder3でできなくて,Visual Basicでできることなど何もないのである.また,開発効率も大きな差はでないだろう.C++言語だからといって別にクラスを作ってオブジェクト指向にしなくてもいいのである.それに,C++言語はDelphiのObject Pascalのように将来が不透明な言語ではない.
| けれどVisual Basicでも… |
|---|
そう考えているうちに,Visual Basicでは作成が困難なプログラムを作成する必要に迫られた.当然私はC++Builderの採用を検討する.しかし念のため,Visual Basicで作成する方法に関しても調査を進める.調査には,市販のコントロールの採用も含まれる(最近の私の仕事の多くはコンポーネントの評価なのだ).
すると,結局は,Visual Basicでできるという結論にいつも到達してしまう.もちろん,C++Builder3でもできるのだが,いかに優れたツールとはいえ,とりあえずプログラムを作るならば使い慣れたツールの方が楽なのである.それに障害の発生する場所も想像がしやすい.
Visual Basicでできて,C++Builder3でできないアプリケーションは確かにないが(おまけに性能もはるかに優れている),C++Builder3で開発できるアプリケーションの90%はVisual Basicでも作成できるのである.そして,残りの10%のプログラムを作らなければならない機会はあまり多くない.
「うーん,Visual Basicでも,まっ,いいか」
これが最近の感想なのである.他のツールを使っても,Visual Basicならばよく知っていることを実現するのに,意外に苦労してしまったりする.考えてみれば,Visual Basicで最初に作成するときに苦労した部分である.
| つまらない時代 |
|---|
だから,これから新しくプログラミング言語を学習しようと考えている人に,私はC++Builder3を強くすすめる.データベースシステム開発に限るならば,若干安定性の不安は残るとはいえ,Power++をすすめる.PowerBuilderゆずりのデータウィンドウを搭載したこのツールで,一度データベースシステムを開発したら,他のツールで作るのが苦痛になるだろう.それに値段もProfessional版ならば,Visual BasicのEnterprise版と比べて決して高価ではない.
Visual Basicの次のバージョンでは,DHTMLの開発機能が追加されるようだが,私はこの機能にあまり魅力を感じない.現在の開発ツールは,すでに十分な能力を備えており,今後の新しい機能の拡張に大きな進歩は見られなくなるだろう.ようするに,今後は開発ツールも言語も何でもいいのである.マシンパフォーマンスが向上したため,ネイティブのコンパイラであるか,中間言語のコンパイラであるかも重要な問題ではない.Javaも性能が問題にされているが,ハードウェアの進化によって問題でなくなる日は遠くない.
こういった現状は,とても,つまらない.よりよいプログラム(あるいは今まで作成できなかったプログラム)を作成するために,使い慣れないツールや言語を習得しなければならなかった,あの緊迫感はもうどこにもない.Visual Basicでも,何でも,したいことは大概できてしまうのである.
そろそろ本題に入って原稿を書き上げないといけない.さて,私は一昨日から自分個人宛のメールと電話には応答していない.つまり一昨日が予告されていたデッドラインだったのだ.担当編集者であるフミッチーは,若い美人編集者の多くがえてしてそうであるように,忍耐力に欠けるところがある.彼女が顧客を偽って私をつかまえに来たら,どうなるか? それに対してはまだ対策ができていない.私は早急に声紋鑑定のプログラムを作成しなければならないかもしれない.音声のようなサイズの大きなデータをリアルタイムで解析するならば,やはり,ネイティブコンパイラのパフォーマンスが要求されるだろう.ここは,C++Builderの出番かもしれない.
| Type4 DB Server |
|---|
先月号でType4 DB Serverのセットアップ方法まで解説した.このデータベースサーバーは,今まで課題にしてきたことの多くが実現されている.パフォーマンスは十分に高速だし,マルチユーザーに対して非同期で動作する.ただし,動作のメカニズムはかなり複雑である.しかし,トリッキーなことはしていないので動作は安定している.間違ったSQL文を実行するとクラッシュしてしまうのは,単にエラーハンドラーを実装していないからである.設計に堅牢性が不足しているというわけではない.
Type4 DB Serverはユーザーのデータベースへの接続を管理するマルチユーザーマネージメントサーバー(DBsvrRB.vbp)とDBアクセスサーバー(DBsvr.vbp)によって構成されている.DBアクセスサーバーは機能的にはType3 DB Serverと同等の機能を有している.つまり,ユーザーが発行するSQL文を受け取って検索結果をクライアントに戻すのは,DBアクセスサーバーの仕事である.Type3 DB Serverはマルチユーザーで使用することはできるが,複数のクエリーを並行処理することはできなかった.つまり,先に実行した人のクエリーが終了するまでは次の人のクエリーは待機される.マルチユーザーデータベースとしては,この制限は致命的である.Type4 DB Serverはこの問題を回避するために開発されたのである.
| マルチユーザーマネージメントサーバーとDBアクセスサーバー |
|---|
それを実現しているのが,マルチユーザーマネージメントサーバーである.データベースにアクセスするユーザーは,まず,最初にマルチユーザーマネージメントサーバーに接続にする.マルチユーザーマネージメントサーバーは,接続してきたユーザーのために,DBアクセスサーバーを起動する.DBアクセスサーバーはActiveX.EXEとして実装されており,インスタンスを作成することで起動処理が行なわれる.次にマルチユーザーマネージメントサーバーは,DBアクセスサーバーのConnCliメソッドを呼びだし,サーバー側のホスト名,クライアントのホスト名,ODBCのデータソース名といった情報をDBアクセスサーバーに渡す.
| クライアントとデータベースの接続 |
|---|
ここで問題になるのは,マルチユーザーマネージメントサーバーとクライアントは接続が確立されているが,DBアクセスサーバーとクライアントは接続されていないことである.この問題を解決するには,いくつかの方法がある.マルチユーザーマネージメントサーバーはDBアクセスサーバーのActiveXクライアントなので,この二者は通信が可能である.だから,マルチユーザーマネージメントサーバーをDBアクセスサーバーとの中継に使うこともできるはずだ(図1).
しかし,この方法にはいくつかの問題がある.まず,ユーザー数に対応する複数のDBアクセスサーバーを起動することで,クエリーの並行処理が可能になるとしても,その結果マルチユーザーマネージメントサーバーを中継してやりとりしたのでは最終的にシングルスレッドで動作することになる.また,DBアクセスサーバーは別プロセスで起動されるActiveX.EXEなので,プロセス間通信のオーバーヘッドも発生することになる.もっとも,これらが問題になるのは,ユーザーが巨大な結果セットをクライアントとサーバー間でやりとりする場合のみである.巨大な結果セットを受け取るようなデータベースプログラム自体に問題があるので,致命的な問題だというわけではない.しかしもちろん,結果の大小にパフォーマンスが影響をうけない方が好ましい.
図1:ユーザーマネージメントサーバーを中継してデータベースにリクエストを発行する方法(未採用)

| サーバーがクライアントにコールバックする |
|---|
結果として採用したのは,起動されたDBアクセスサーバーがクライアントに対して再接続する方法である(図2).この接続には別ポートを使用し,完全に別のセッションとして扱うのである.処理のフローとしては,次のようにイメージしてもらえばわかるだろう.
| 1 | 依頼人のAさん(クライアントプログラム)は,仕事を頼むために受付のBさん(マルチユーザーマネージメントサーバー)に電話をする |
| 2 | 受付のBさんは,担当者であるCさん(DBアクセスサーバー)に内線で電話をして,依頼人のAさんの電話番号を通知する |
| 3 | 担当のCさんは,依頼人のAさんに電話をかけなおし,実際の依頼内容(SQL)を受け取り,結果を応答する |

図3:完全に接続が完了した状態のType4 DB Server

| データベースとクライアントの関係 |
|---|
DBアクセスサーバーとクライアントの接続が完了した後では,クライアントとデータベースは,DBアクセスサーバーだけを経由してデータベースのアクセスを行なう.この構図はType3 DB Serverと同様だが,Type3 DB ServerがひとつのDBアクセスサーバーでマルチユーザーに対応しなければならないのに対して,Type4 DB Serverではひとつのクライアントに対して,ひとつのDBアクセスサーバーが起動されることである(図4).1人のユーザーに対してひとつのデータベースエンジンをロードするこの方法は,ファイル共有型であるJetデータベースエンジンがデータベースファイル(MDB)にアクセスする上での,正しいアクセス形態である.にも関わらず,クライアント側にビジネスロジックを実装すれば,一般的なC/Sシステムとして動作するし,DBアクセスサーバーにビジネスロジックを記述すれば3階層システムとして動作することも可能である.その場合,クライアントはプレゼンテーション層を担当することになる.
図4:ひとつのクライアントに対して,ひとつのDBアクセスサーバーが起動される

| サーバーとクライアントの逆転 |
|---|
実装時に気をつけなければいけないのは,この方法だとコールバック時には,Socketのサーバーとクライアントの関係が入れ替わることである.つまり,コールバックするDBアクセスサーバーがSocketクライアントであり,クライアントアプリケーションがSocketサーバーということになる.当然,クライアントアプリケーションには,2つのWinsockコントロールが配置されることになる(図5).
図5:2つのWinsockコントロールが配置されたクライアントプログラム

この方法の最大の問題点は,サーバーマシンのSocketポートが動的に割り当てられる点である.これではサーバーマシンのSocketポートを管理することは難しく,セキュリティ上の問題が発生する可能性がある.また,クライアントマシンはSocketサーバーとして動作するので,1台のクライアントマシンに複数のクライアントアプリケーション起動することはできない.これは,実運用時にはあまり問題が出ないと思うが,少ないマシンで開発しているときにマルチユーザー接続のテストができないのが欠点である.
| 各フォームと動作 |
|---|
サーバーからクライアントへの接続が確立されれば,残りの動作は先月解説したType3 DB Serverと違いはない(図3参照).サーバーはクライアントが発行するSQLを受け取り,RDOを経由してデータベースエンジンにアクセスする.データベースエンジンはODBCドライバさえあれば,サーバーデータベースでもファイル共有型のデータベースでも,クライアント/サーバー型のデータベースとして機能する.そして先にも述べたように,DBアクセスサーバーにビジネスロジックを実装すれば,3階層システムの構築も可能である.
Type4 DB Serverの各フォームと機能の対応を示したのが,図6である.それぞれのフォームが別々のプロジェクトに属していることに注意してほしい.
図6:Type4 DB Serverの各フォームと機能の対応

| マルチユーザーマネージメントサーバー |
|---|
マルチユーザーマネージメントサーバー(図7)の全ソースコードがリスト1である.決して複雑な構造でないことがわかるだろう.このプログラムは起動時にWinsockコントロールのListenメソッドを実行し,クライアントからの待機状態に入る.
Private Sub Winsock1_ConnectionRequest _ (ByVal requestID As Long) If Winsock1.State <> sckClosed _ Then Winsock1.Close Winsock1.Accept requestID End Sub
Winsock1.GetData strData, vbString intStr = InStr(1, Trim(strData), ",") txt_host.Text = Left(Trim(strData), _ intStr - 1) txt_dsn.Text = Mid(Trim(strData), _ intStr + 1, Len(Trim(strData)))
Set DBaccessObj = New DBsvr.clsDBaccess sKey = strData DBaccessObj.ConnCli txt_host, txt_dsn, _ LOCAL_HOST, sKey

リスト1:マルチユーザーマネージメントサーバー(DBsvrRB.vbp)の全ソースコード
Option Explicit Private Const LOCAL_HOST As String = "localhost" Private Sub Form_Load() ' httpcliからの接続要求待ちにする Winsock1.Listen End Sub Private Sub Winsock1_Close() If Winsock1.State <> sckClosed Then Winsock1.Close ' httpcliからの接続要求待ちにする Winsock1.Listen End Sub Private Sub Winsock1_ConnectionRequest(ByVal requestID As Long) ' クライアントからの接続要求時によびだされるプロシージャ ' 接続処理の完了 If Winsock1.State <> sckClosed Then Winsock1.Close Winsock1.Accept requestID End Sub Private Sub Winsock1_DataArrival(ByVal bytesTotal As Long) ' クライアントからデータを受信 Dim DBaccessObj As clsDBaccess Dim strData As String Dim intStr As Integer Dim sKey As String ' データの取得 Winsock1.GetData strData, vbString intStr = InStr(1, Trim(strData), ",") ' 接続クライアント名 txt_host.Text = Left(Trim(strData), intStr - 1) ' ODBCデータソース名 txt_dsn.Text = Mid(Trim(strData), intStr + 1, Len(Trim(strData))) Set DBaccessObj = New DBsvr.clsDBaccess sKey = strData ' clsDBaccessクラスのConnCliメソッドを実行 DBaccessObj.ConnCli txt_host, txt_dsn, LOCAL_HOST, sKey Set DBaccessObj = Nothing End Sub |
| まとめ |
|---|
今回はType4 DB Serverの,ユーザーのデータベースへの接続を管理するマルチユーザーマネージメントサーバー(DBsvrRB.vbp)を中心に説明した.次号では,ActiveX.EXEとして実装されたDBアクセスサーバー(DBsvr.vbp)を解説する.データベースアクセスのメカニズムとしてはType3 DB Serverと同じなので,ActiveXコンポーネントとして作成する上での注意点を中心に説明する.
この連載において,何度かJetデータベースエンジンをマルチスレッドで使用することの不安と,Visual Basicでマルチスレッドプログラムが作成できないことに言及した.しかし,Jetデータベースエンジンの最新のODBCドライバでは問題なく動作するようだし,Visual Basicでマルチスレッドプログラムを作成する方法もわかってきた.冒頭でVisual Basicを見直したと書いたのは,そのためである.私の手元にあるプロトタイプでは,Visual Basicだけで書かれたマルチスレッドプログラムが快調に動作している.このプロトタイプを作るにあたってW.Stealride氏のサジェスチョンを受けたが,彼が以前,本誌に書いた記事ような際どい方法ではない.若干トリッキーとはいえ,制御可能な原子炉である.