オブジェクト解放(デリゲートによる参照)

Visual Basic 6など、COMでは参照カウントによってオブジェクトの解放を管理していました。オブジェクトに参照カウントを持たせておき、代入などにより参照されるときにカウントアップ、Nothingや別のオブジェクトの代入、オブジェクト変数のスコープが外れたときなど参照されなくなったときにカウントダウンし、参照カウントが0になったときに、どこからも参照されていないから不要と見なして解放する仕組みです。参照されている限りオブジェクトは解放されないので破棄されたオブジェクトにアクセスしてエラーが発生することはありません。参照カウントの仕組みは単純なオブジェクトではうまく動作しメモリ管理を楽にしてくれました。

しかしオブジェクトが循環参照を持つ場合にはいつまでもオブジェクトが解放されず、不必要なメモリを消費したりエラーの原因となったりしました。この場合、どのオブジェクトが循環参照を生じているのか解析しながら注意深く循環参照の連鎖を切る必要があり、面倒な作業を強いられました。

一方Net Frameworkでは、オブジェクト解放の仕組みが変わりガーベジコレクタが使われるようになりました。ガーベジコレクタはルートオブジェクトからたどって参照されているオブジェクトを有効と見なすので、循環参照が生じてもルートからたどれなくなっていれば解放されます。このため循環参照を気にする必要がなくなり管理がずいぶんと楽になりました。ガーベジコレクタはプログラマが明示しなくても適当なタイミングで実行されますがGC.Collect()によっても明示的に実行させることができます。

オブジェクトの解放と関連して、Net FrameworkにはIDisposableインタフェースを備えたクラスがあります。WindowsアプリケーションではControl、Formなどがそうです。これらのDisposeメソッドを呼び出すと、アンマネージリソースの解放、該当オブジェクトが参照しているオブジェクト変数へのNothingの代入が行われます。注意点としてマネージリソースは即時解放されるのではなくて次回ガーベジコレクタが働いたときに他のオブジェクトから参照されていなければ解放されること、Disposeメソッドが呼び出されたオブジェクトが解放されるわけではないということです。しかしDisposeが呼び出されたオブジェクトはまともに動作する状態ではありませんので再び必要になれば改めて生成する必要があります。Dispose呼び出し済かどうかはControlのIsDisposedメソッドで確認できます。

既定の動作ではフォームを閉じたときにはDisposeメソッドが呼び出されます。フォームを参照している変数がないと仮定して、フォームが閉じた後にGC.Collectを呼び出せばフォームおよびフォームが所有していてたオブジェクトは完全に解放されるはずです。しかし、フォームを解放したはずなのに解放したフォームが所有しているオブジェクトが解放されずにエラーが発生することがありました。

状況としては呼び出し元フォームをForm1、呼び出し先フォームをForm2として、Form2の所有するオブジェクトEventSinkTestがForm1のイベントを補足するためForm1への参照を持っています。具体的にはClickイベントを補足して、Form1がクリックされればメッセージが表示されるようになっています。Form2を閉じるとDisposeメソッドが呼び出され使用できない状態になります。さらに、GC.Collect()を呼べばEventSinkTestも解放されることを期待しますが、そのようにはならず、依然としてEventSinkTestがForm1のイベントを補足し続けます。

この状況でForm1からForm2のEventSinkTestへの参照がないと考えたのが間違いのようでした。イベントソース(この場合Form1)からイベントシンク(EventSinkTest)への参照はデリゲートを介して存在しており、構文上気がつきにくいオブジェクト図の波線で表した参照があることでEventSinkTestが解放されなかったのです。

これを回避するためFormがDisposeされるときEventSinkTestからForm1への参照もなくしてしまうと、期待通りイベントの発生が止まりました。実際にEventSinkTestが解放されるのはガーベジコレクションのときですがイベントはすぐに止まります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
'呼び出し元フォームのコード
Public Class Form1

Private Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim Form2 As New Form2
Form2.Show()
Form2.Initialize(Me)
End Sub

Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
GC.Collect()
End Sub
End Class

'呼び出し先フォームのコード
Public Class Form2
Public Class EventSinkTest
Dim WithEvents _form As Form

Public Property Form() As Form
Get
Return _form
End Get
Set(ByVal value As Form)
_form = value
End Set
End Property

Private Sub _form_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles _form.Click
MsgBox("Form_Click")
End Sub
End Class

Dim es As EventSinkTest

Public Sub Initialize(ByVal form As Form)
es = New EventSinkTest()
es.Form = form
End Sub

Private Sub Form2_Disposed(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Disposed
'オブジェクトを解放するためには以下の行を追加する。
'es.Form = Nothing
End Sub
End Class

コントロール既定値設定

アプリケーション開発において、各画面で意匠に統一性を持たせることは要求仕様なることが多いと思います。例えばラベルの色を統一することもその一つでしょう。多くの画面で使用するすべてのラベルについて、プロパティウィンドウで色を設定していく作業は結構な手間になります。また、別の色に変えたいときにも同じ作業が発生してしまいます。Webサイトの意匠設計ではスタイルシートを使って色などを一カ所で設定することが可能になります。このようなことができないでしょうか。

NET Frameworkでは出来合いのコントロールから継承して新たなカスタムコントロールを作ることができます。そこでカスタムコントロールのコンストラクタでBackColorプロパティに望みの色を設定するようにすれば良さそうです。しかしそれだけではコンストラクタとInitializeComponentメソッドで2回設定され無駄が生じますしIDE操作の上でも望ましいと言えません。これを解決するためにはBackColorプロパティにDefaultValue属性を設定します。

属性による既定値設定
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
Public Class MyLabelDesigner
Inherits System.Windows.Forms.Design.ControlDesigner

Public Overrides Sub InitializeNewComponent(ByVal defaultValues As IDictionary)
MyBase.InitializeNewComponent(defaultValues)
With Cast(Of MyLabel)(Control)
.AutoSize = False
.Text = Nothing
End With
End Sub

Private Sub SetDefaultValue(Of componentType, propertyType) _
(ByVal properties As IDictionary, ByVal propertyName As String, ByVal value As String)
properties(propertyName) = TypeDescriptor.CreateProperty(GetType(componentType), _
Cast(Of PropertyDescriptor)(properties(propertyName)), _
New DefaultValueAttribute(GetType(propertyType), value))
End Sub

Protected Overrides Sub PreFilterProperties(ByVal properties As IDictionary)
MyBase.PreFilterProperties(properties)
SetDefaultValue(Of MyLabel, Color)(properties, "BackColor", "FloralWhite")
SetDefaultValue(Of MyLabel, BorderStyle)(properties, "BorderStyle", "Fixed3D")
End Sub
End Class

<Designer(GetType(MyLabelDesigner))> _
Public Class MyLabel
Inherits Label

Public Sub New()
MyBase.New()
BackColor = Color.FloralWhite
BorderStyle = BorderStyle.Fixed3D
End Sub
End Class

素直にDefaultValue属性を設定する例はMSDNを参照してください。この方法をそのまま当てはめた場合の問題は属性を設定するためにわざわざプロパティをオーバーライドまたはシャドウしなければならないことです。属性が必要なのはデザイン時だけですから別の方法で属性を設定する方法を考えてみました。

MyLabelのBackColorプロパティとBorderStyleプロパティにDefaultValue属性を設定するのにMyLabelDesignerクラスを使用します。MyLabel本体はコンストラクタのオーバーライドだけになっています。SetDefaultValueはMyLabelDesignerのメンバーとしていますが汎用的に作ってあるので他のModuleのPublicメソッドにしても問題有りません。Castメソッドはジェネリックのページで例示した物ですが一般的にはCTypeを使えばよいでしょう。上記程度のサンプルにはジェネリックを使う必要はありませんがそのまま残してあります。InitializeNewComponentはなくてもかまいませんが、Textプロパティにコントロール名が設定されるのは便利とは言い難いので空白になるようにしているのとAutoSizeがTrueになることを防いでいます。サンプルコードを試される方はSystem.Design.dllへの参照をプロジェクトに追加してください。

MSDNを見るとメモ : このメソッドは、.NET Framework version 2.0 で新しく追加されたものです。と書いてあるのを見かけます。カスタムコンポーネントを作っていると新しく追加されたメソッドをよく使っています。version 1.Xを使っていたら結構不便に思ったかもしれないです。

ジェネリック

Net Framework 2.0ではジェネリックが搭載されました。ジェネリックについては以前に型総称性で紹介しました。このときにはC++でテンプレートが使えたもののJava Genericは搭載されたばかりで盛んに使われている状況にはありませんでした。今ではNet Frameworkに当然のようにクラスライブラリに使われ、アプリケーションプログラマにとっても身近な存在になったと感じています。

コレクションなどで提供されているジェネリックライブラリを使うことはそれほど難しいことではないと思います。一方メソッドやクラスを作るのにもジェネリックを使うと今までにないものができます。

単純な例でVisual BasicのIIf関数のジェネリック版です。

1
2
3
Public Function IIf(Of T)(ByVal expression As Boolean, ByVal truePart As T, ByVal falsePart As T) As T
If expression Then Return truePart Else Return falsePart
End Function

(Of T)のTは型引数と呼びます。上記IIfを使うとReturn値のデータ型が、引数に合致したものと型推論されるので、以下のように文字列変数に代入するときにもいちいち型キャストする必要がなくなります(Strict
Onでも)。

1
Dim s As String = IIf(True, "True", "False")

型推論を使わずにIIf(Of String)と明示的に型を指定してもOKです。
つぎにキャストを行う関数を作ってみました。

1
2
3
Public Function Cast(Of Destination)(ByVal Source As Object) As Destination
Return CType(Source, Destination)
End Function

こうなるとただのシンタックスシュガーなのですが次のような使い方ができます。

1
Dim s As String = Cast(Of String)(123)

型引数を持ったクラスを作ることもできます。C++のテンプレートはプリプロセッサで実現されているので、型引数が指定(実体化)されないかぎりコンパイルチェックが掛かりません。それに対しNet Frameworkではジェネリッククラスそのものにコンパイルチェックが掛かり、型引数に対して定義されていないメソッドやプロパティの呼び出しはできません。それは安全性が増していて、生成されるコードも小さくなることを意味します。型引数にはどんな型が指定されるかわからないのにどうしてメソッドやプロパティを呼び出せるのかとの疑問がわきます。実際上記のIIfでは関数内でtruePartやfalsePartに対するメソッド・プロパティ呼び出しはすべてのデータ型の基底型であるObjectのメソッドしか使用することができません。

そこで使用するのが型制約です。型制約は型引数に指定できる型を制限する代わりに制約に指定した型のメソッド・プロパティを呼び出せるようにする物です。型制約は(Of T As Control)のようにAsを使って指定します。

以下余談、Visual Basicに有ったらいいなと思うもの、無名メソッド(C#)・typedef(C#)・プロパティによるインタフェース委任(Delphi)・メソッド解決節(Delphi)。

Net Frameworkとは関係のない余談ですが、Delphi for Win32にはクラス参照と呼ばれる、型を変数として扱えるものがあります。これとジェネリックを組み合わせると非常に柔軟なプログラミングができるような気がします。

データアクセス(ADO.NET)

当方では従来データベース応用システムはAccessを使っていましたが、今年からVisual Basic 2005(以後VB2005と記述)に置き換えています。置き換えには当初の想定よりも手間取りました。言語の違いは本格的なオブジェクト指向の機能を備えたVB2005になれるのにそれほど時間は掛かりませんでしたが、ライブラリの違いにはなかなかなれることができませんでした。

Accessでは、フォームにRecordsetの機能が最初から備わっているなど、思い切った割り切りによってデータベース処理に特化しているのですが、VB2005というかNET
Framework 2.0ではデータアクセスのパーツが細かく分かれていてこれらパーツの関連を把握するのに時間が掛かりました。

右の図は私が把握しているデータベースアクセスクラスの関連を表しています。XXDataTableとXXTableAdapterはIDEが生成するクラスです。

AccessやCOMベースのADOとの最も大きな違いはデータベースエンジンとの接続のあり方でしょう。従来はアプリケーションの実行開始から終了まで接続状態でデータアクセスするスタイルでしたが、ADO.NETではDataTableに一気に読み込んでから、処理を行い、結果を戻すスタイルが標準的な動作になります。接続は読み込みと結果を戻すときだけ行います。

Web開発ではこのような接続方法が求められるのですが、これをクライアント/サーバに応用した場合には次の得失がありそうです。

Accessではユーザインタフェース上でデータを変更したら即座にデータベースも変更されます。そのため「保存」「取消」ボタンを作ろうとすれば一旦ワークテーブルにデータを読み込んでワークテーブルに対して編集を行うようにするなどの一工夫が必要になります。それに対してADO.NETではユーザインタフェース上での変更はオンメモリのDataTableが変更されるだけで、データベースへの変更はXXTableAdapterのUpdateメソッドで一気に行われるため、「保存」「取消」ボタンを簡単に実装できます。

それに対してスクロールしながら一覧表示するような画面ではメモリ上に一気に読み込むことからデータ量が多い場合のメモリ使用量・パフォーマンスに別の配慮が必要になります。

UML

数年前SI様からプログラムの構造をドキュメント化するのにクラス図をご要望されたのをきっかけにUMLの使用を始めました。UMLについては既に広く知られていると思うので解説はしませんが、当方がどのように使っているかを紹介します。

UMLのツールは無償の物から大変高価なものまでいろいろとありますが、ここ2年ほどメインに使っているのは SparxSystems JapanのEnterprise Architectです。これ以外にJude Communityという無償のツールもお客様の指定がある場合に使用します。いろいろな図をサポートしていることDelphiのリバース・フォワードができること、表現力が豊かであること、価格面からEnterprise Architectの導入を決めました。ライセンス体系は独特でサポートに重点を置いています。返事が早いこと、問い合わせにより挙がった修正項目に丁寧に対応し修正が早いことなどサポートの質は高く、機能が改善・強化された物がダウンロードできますので、合理的なライセンス体系であると判断しています。

UMLはいろいろな図があります。講習を受けたときよく使う重要な図はクラス図シーケンス図と教えられたのですが、その当時はシーケンス図の必要性が理解できなかったのです。なぜならば当時携わっていたプロジェクトではクラスとクラスの呼び出し関係が単純でわざわざシーケンス図を描くほどのこともなかったからです。Accessなどのツールに組み込まれているGUI部品を使ってアプリケーションを開発する場合にはシーケンス図は要らないと思いますが、GUIそのものを作るような開発に着手したとき必要性を痛感しました。

シーケンス図が必要かどうかの分岐点のひとつはコールバックがあるかどうかによると思います。単純にメソッドを呼び出すだけのシーケンスではそれぞれのメソッドの役割だけを理解して中身をブラックボックスと見なすことができるので、そこからどのクラスのメソッドが呼ばれようと考慮する必要がないと理解することもできます。しかし、呼び出し元に返ってくる場合はそうはいかなくなります。相互に状態変化をもたらすのでどのような状況で呼ぶのか細かく制約されるからです。

Visitorパターンや、フォームとコントロールのように親子関係のあるクラスが相互に連係しながら動作する場合には、このような状況が現れます。

当方は通常分析段階からシステム構築をしていますので、アプリケーションの大まかなフローを描くのにアクティビティ図、業務フローを描くのにBPMN(UMLではない)、ユーザの分類と使用する機能の関係を表すのにユースケース図、コンピュータやプログラムの配置を表すのに配置図を使っています。一つのシステムをいろいろな角度から俯瞰できますので、単にヒアリングした項目を列挙するだけの場合に比べて抜けが少なくなります。Enterprise Architectで作成した図をWordに貼り付けて提案資料としてお打ち合わせ時に使っています。

Linux(Ubuntu,Fedore Core 6)

LinuxはWebアプリケーションを構築するときに開発環境として使用しています。実行環境ではレンタルサーバを使用してバックアップ・ウィルスチェックなど管理をプロバイダに任せられるところを選んできました。 最近ではグループウェアを所望されるお客様の声が増えてきました。その場合レンタルサーバではなく自社内にサーバを持ちたいとの意向もあるかと思います。私が今まで手がけてきた小規模業務システムではせいぜい5、6端末でしたのでお客様の事務所にサーバを導入する場合はWindows2003サーバを使用していました。しかしグループウェアとなると担当者1人に1台と考えると端末数は増えてCAL(クライアントアクセスライセンス)費用が大きくなります。

そこでLinuxをお客様に導入することも想定して、改めてLinuxディストリビューションを見直すことにしました。当方の場合はSI様を通じてシステムを導入しますので、SI様にわかりやすいインストール手順、管理用ユーザインタフェースが必要です。またオンラインバックアップが行えること、ファイヤーウォールなどのセキュリティが設定しやすいことも重要です。Fedora Core 6とUbuntuをインストールしてみました。使い込んだわけではなくインストールしてみた印象ととらえてください。

項目 Fedora Core 6 Ubuntu 6.10 desktop-ja
OSインストール ウィザード形式で難しくはない ウィザード形式で難しくはない
CDからOSを起動してインストーラを実行
試したユーザインタフェース GNOME
GNOME
バックアップ インストール時にLMVの選択がある Alternate版にしないとLVMが選択できない
パーティション構成によってはAlternate版でもLVMにならない
セキュリティ ファイヤーウォールが設定しやすい
調査中、Fedora Coreよりアクセス制御が難しそうな印象あり
その他 パッケージの更新が素直に実行できなかった(更新通知サービスを止める必要があった) Widowsを含め他のパーティションを自動マウント
SAMBA(Windows共有)が容易に導入できる
サーバソフトに使用するデーモン自動起動の設定に多少癖がある(aptを使わなかった場合に引っかかった)
デフォールトでインストールされるパッケージが少ないのでソフトをインストールするときに依存するパッケージを追加インストールする必要があった。

Ubuntuのデフォールト環境は結構良くできている印象がありました。しかしサーバとしての細かい設定となると強力なGUIやaptによるインストールは役に立たない気がしました。細かい設定を行わなければならないソフトはそんなに多くはないのでそれ以外のソフトをaptに任せてしまうと良さそうです。

Ubuntu, Fedora Core 6

アーキテクチャーパターン

帳票フォーム編集用のパッケージソフトウェアを開発しています。

フォーム上にコントロールを配置したり、プロパティを設定したりするもので、GUI統合開発環境と同様の機能が必要とされ、ソフトウェアとしては複雑な部類になると思います。言語はDelphi7を使用しました。

フォームやコントロールはライブラリに用意されているGUI部品を継承して作りました。Drag&Dropによるコントロールの移動・サイズ変更・プロパティエディタによる編集などGUIらしい機能ができました。そして、ツールバーによる編集やフォームに表示しないコントロールに対応しようと考えました。ツールバーではプロパティエディタと同じプロパティを編集するため連携しなければなりませんが、既にできあがってしまったプロパティエディタはそのような配慮はしていなかったため連携への対応は難しく、やり遂げたとしても場当たり的なコーディングになってしまいそうです。またコントロールはGUI部品を使ったためフォームに表示しないコントロールには対応できません。簡単に乗り越えそうにできない壁に当たってしまいました。

敗因は内部状態を表すオブジェクトとGUI部品を一体にしてしまったことにあるようです。以前からMVCと言う言葉は見かけていましたが、MVCが問題を解決する物ではないかと考えて情報を集めました。MVCで対応できそうと確信して、大変でしたがコードを書き換えていきました。ツールバーや非表示コントロールを実現するまでには至っていませんが簡単に対応できる仕組みは用意できました。

MVCにもバリエーションがあるようで、私が採用した物はDocument-Viewパターンに分類されるようです。MVCはControl(入力) - Model(処理) - View(出力)と機能を分けるのですが、Windowsに備わっているControlは入力イベント処理と表示が一体になっていますのでこれを素直に利用するとVCが一体の構造になり、M→Document、VC→Viewと言う対応になります。VC(View)が発行したコマンドをModel(Document)が処理し、Modelでの処理結果をViewに表示します。DocumentとViewは1対多の対応になっていてObserverパターンにより処理が終わったことをViewに通知して表示を行います。Model(Document)は処理を行うだけでなく処理結果を保持します。VC一体とするデメリットはView毎に入力イベント処理を記述しなければならず共通化しにくいことです。しかしながらプロパティエディタとGUIフォームで入力イベント処理の共通部分はありませんのでこの場合には問題となることもなさそうです。

MVCもパターンの一つですがデザインパターンと言うには適用範囲が広すぎます。MVCのようにプログラム全体の構成を表すパターンを「アーキテクチャーパターン」と呼ぶそうです。ソフトウェアアーキテクチャー - ソフトウェア開発のためのパターン体系F.ブッシュマン他にアーキテクチャーパターン・デザインパターンが紹介されています。この中にReflectionパターンが紹介されていてこれも早速適用しました。

デザインパターンを学習したときにも感じたことですが自己流だけでは限界があります。アーキテクチャーパターンを学習してまた一つできることが増えました。

参照

Reflectionパターン考察

アーキテクチャパターンで触れたように帳票フォーム編集パッケージにReflectionパターンを採用しました。

フォーム上のテキストボックスでは、Caption, FontName, FontSizeなどのプロパティを持たせて、これらプロパティに応じた印刷を行うようにします。これらのプロパティはプログラム上もクラスのプロパティとしてインプリメントしています。このような仕組みで印刷を行う処理は問題なく書けます。今回はこれらのプロパティを編集できるようにしなければなりません。プロパティ毎にSetter, Getterを呼んでいてはプロパティエディタの機能は到底作れないのでDelphiに備わっている実行時型情報(RTTI)を利用して、オブジェクト・プロパティ名文字列・値を指定してプロパティを設定・取得する汎用的なメソッドを定義しました。

キーになるのがプロパティ名なので、プロパティのコレクションを扱ったりプロパティの値を列挙したり、Undo, Redoを実現したりといったことがやりにくく似通った処理の記述が増えてリファクタリングが必要になってきました。そこでプロパティを一つのオブジェクトして扱うように改めました。プロパティを表すオブジェクトは実行時型情報から作り出します。このようにすることでプロパティのコレクション・列挙を扱うのに通常のクラスライブラリが使えるようになり、文字列解析処理も減りました。冗長な記述もなくなって結果的にプログラムがすっきりしたと思います。

実行時型情報などのメタデータを使って汎用性を持たせるパターンをReflectionパターンと呼びます。

Reflectionパターンについて別の例で考察してみました。販売管理を考えてみると、伝票番号・商品・数量・単価・金額などが伝票の属性として必要になります。これをシステムにインプリメントするとき、2つのアプローチがあると思います。一つは伝票をクラスとし伝票番号などの属性をクラスのプロパティにするものです。もう一つは伝票をコレクションとして扱い、個々の属性は属性名をキーとするコレクションの要素として扱うものです。

クラスプロパティによる表現では業務分析により導出したモデルがそのまま設計上のクラスになります。金額の計算は金額=数量*単価といった具合に直感的な記述ができるのです。デメリットは汎用的に属性を扱うことができなくなることです。コレクション要素による表現では汎用的に属性を扱うことができますが、属性相互の関係式はItem['金額'].Value=Item['数量'].Value*Item['単価'].Valueといった風に冗長な記述になってしまうデメリットがあります。

オブジェクト指向ではこの2つの表現に関わる矛盾を解決してくれません。Reflectionパターンは一つの解決策なのです。これ以外に言語仕様でカバーできる物もあります。私が扱った言語の中で、JavaScriptは連想配列の要素はそのまま属性になります。Perl,
Rubyもクラス属性とコレクション要素を簡単に変換できる機能を備えています。Accessではほとんどの局面で属性をコレクション要素として扱いますが、フォームではフィールド名・コントロール名がそのままフォームのプロパティ名になります。使ったことはありませんがO/Rマッピングも同様の問題を解決するための物でしょう。

クラスプロパティ表現とコレクション要素表現の矛盾、決定打がないためにあちらこちらでいろんな解決策が模索されている状態ととらえられそうです。

現在はIDEの機能を利用することを前提にクラスのプロパティ表現としています(IDEとアーキテクチャ参照)。

Google検索:Reflection パターン, ドメインモデル, O/Rマッピング

Ajax

Google mapを見たときは感動しました。Webのシステムでここまでできるのだと。Google mapに代表されるような、クライアント側の処理により、ページを遷移することなくサーバ側と通信しながら動きのあるサイトを構築する技術をAjax(Asynchronous
JavaScript and XML)と呼ぶそうです。

最近構築したシステムではAjaxに習って一部導入してみました。例えば、伝票入力画面で商品のアイテム数が少ないのであればSELECT要素を使って選択すればよいのですが、アイテム数が多いとHTMLがふくれあがりますし、オペレータが商品を選ぶのも難しくなります。そこでコードを入力すればそれに相当する品名を横に表示すると言うことを隠しフレームを使ってやってみました。スピードが遅くならないかと心配しましたが十分実用的なスピードでレスポンスが帰ってきました。

Ajaxを全面的に使用すれば、最初に表示枠となるHTMLとJavaScriptをクライアントに送り、クライアント側のJavaScriptからクエリーを発行してデータベースを読む。編集後保存ボタンを押したら、保存用のクエリーを発行してサーバ側で保存処理する。このような処理の流れとなり、この間ページ遷移が一切起こらないと言ったことも可能になります。サーバ側の処理は軽く単純になります。

問題点もあります。

  • JavaScriptで作成するスクリプトが大きくなることや、ロード時の処理が重くなるので最初にページを読むときに時間がかかる。(IEはDOMノードをたどる処理を行うと遅いようです、Opera8.54は早いです)
  • JavaScriptのデバッグを効率化しなければならない(FirefoxのJavaScript Debugger活用)
  • ブラウザの機能に大きく依存するためクロスブラウザ開発が難しくなる

IEはバージョン6では、ActiveXを使ってサーバへの通信要求XMLHttpRequestを発行できますが、バージョン7ではネイティブ対応するそうです。機会があればAjaxを全面的に採用したWebサイトの構築をやってみたいと思います。

現在、派手さはありませんがデータの更新等の処理にAjaxを使っています。ブラウザの戻るボタンで戻っても不自然でない動きをします。(2011年8月9日)

キーワード:Ajax, XMLHttpRequest, prototype.js

ruby

データベース連携のWebシステム開発には今までPerlを使ってきました。文字コードをutf8で統一するということがあり、運用を行うレンタルサーバのPerlのバージョンが古いためスクリプトをutf8で書けないので、今回はrubyを使ってみました。

開発する過程で感じた特長をあげてみます。

  • 最初からオブジェクト指向で言語設計されているため、オブジェクト指向による開発が行いやすい
  • Perlに比べてすっきり書ける(basic的、pascal的制御構文)
  • 不定個数引数が自然にインプリメントされている
  • ブロック(イテレータ)を活用するプログラミングスタイルが根付いている
  • ライブラリが充実している
  • 統合開発環境RDEがあり、インテリセンスにも対応している
  • メーリングリストでの情報交換が盛んで、言語設計者自身も丁寧にフォローしている(私の質問にもお返事いただけました)

気になる点もありました。

  • 型チェックが甘いため、タイプミスに気がつきにくい
  • 変数宣言がないのでスコープを明示できない
  • データベース連携のためのライブラリDBIに関する情報が少ない

総じて使いやすい言語で、テンプレートライブラリや、データアクセスライブラリなどのライブラリ化を進めることができました。そのため細かいところまでフォローしたシステムが構築できたと思います。