連載
» 2014年07月18日 12時40分 公開

第6回 ASP.NETによるWebアプリ開発(アプリケーションの開発 3)連載:ASP.NETによる軽量業務アプリ開発(3/3 ページ)

[arton, ]
前のページへ 1|2|3       

グローバルなJavaScriptオブジェクト

 前節で示したmembers.jsファイルでは、「Util」と「Dialog」という2つのユーザー定義のオブジェクトを参照した。

 以下にutilty.jsファイルとdialog.jsファイルで実装されているコード片を示す。utility.jsファイルは単なる関数の集合であり、dialog.jsファイルは初期化処理を伴う。utility.jsファイルを示す。

var Util = {                     (1)
  htmlEscape: function(s) {      (2)
    if (typeof s == 'string') {  (3)
      return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
    } else {
      return s;
    }
  },
  ……省略……
};

utility.jsファイル
  (1) Utilはグローバルなオブジェクト。
  (2) 複数の関数をグローバルに定義するのではなく、グローバルに定義したオブジェクトが複数の関数をプロパティとして持つようにすることで、ネームスペースの汚染を最小限にとどめる。
  (3) ある変数が文字列かどうかを判定するには、typeof演算子を利用して型名を取得し、それと'string'を比較する。

 グローバル変数の利用は避けることが原則だが、あまりに頻発する処理は関数としてまとめたくなる。そのような場合は、関数をまとめたオブジェクトを利用する。

 ここでは1つの変数Utilに1つのオブジェクトをまとめているが、ある程度の規模であれば、2レベルにする方がよい。以下に例を示す。

var ARTON = {};  ←トップレベルのオブジェクトを定義する
...
ARTON.util = { func: function() { ... } };  ←プロパティの追加として具体レベルのオブジェクトを持たせる
ARTON.dialog = { ... };

ARTONの下にutilとdialogの2つのオブジェクトを置き、ネームスペースのネストを実現する

 この例のようオブジェクトのツリー構造を利用することで、サードパーティライブラリとの名前競合をほぼ確実に避けることができる。と同時に「ARTON_utility_func1」のような無理矢理一意にしようとした長い名前の利用を回避できる*2

*2 このような命名方法を利用すると、どこかでスペルミスによって新たなwindowオブジェクトのプロパティが生成され、内容がnullのため例外となる。


 以下にdialog.jsファイルの実装を示す(抜粋)。

var Dialog = (function() {        (1)
  var bg = document.createElement("div");
  bg.style.position = "fixed";
 ……省略……
  return dialog;                  (2)
})();

dialog.jsファイル
  (1) Dialogは、無名関数の実行結果。
  (2) 無名関数内で作成したオブジェクトを返す。

 utility.jsファイルでは初期化処理が不要なため、直接オブジェクトを定義した。それに対してdialog.jsファイルでは初期化処理が必要なため、members.jsファイルと同様にロード時に無名関数を実行する。ただし、その結果をグローバル変数Dialogに保持させる。

[コラム]サードパーティJavaScriptフレームワークの利用について

 この記事の読者としては想定していないが、もし読者がインターネット上のBtoCサービスを提供しているのであれば、そのときそのときのはやりに合わせてサードパーティのUIフレームワークを利用するのは当然なので、以下の記述は無視すべきだ。

 そうでなければ、サードパーティJavaScriptフレームワークの利用は、可能な限り避けるべきだ。

 唯一の例外がjQueryだ。その理由は記述量を大幅に削減できることと、相当な範囲でWebブラウザーの互換性問題を解決してくれることにある。

 ところが、HTML5を前提できるようになり、IEもバージョン11が利用できるようになった現在は、XMLHttpRequestとJSONの2つのオブジェクトがWebブラウザー標準の組み込み機能となったために、jQueryの役割は便利なラッパー関数のみとなった。それはもちろん便利なのだが、次の点について考えることが必要だ。つまり、学習コストと維持コストである。開発者自身が特定のサードパーティフレームワークをすでに身に付けていれば学習コストはゼロだが、Webアプリを引き継いだ人がそのフレームワークのことを知らなければ、引き継いだ人の学習コストを維持コストに上乗せする必要がある。jQueryと似たような便利フレームワークであり一世を風靡(ふうび)したものとしてprototype.jsがあるが、今では誰もそういうものがあったことを忘れたかのようだ。

 これがUIフレームワークとなると、話はより極端なものとなる。

 UIははやりによって変わるため、UIフレームワークは死屍累々なのだ。筆者が付き合ったことがあるだけでもscript.aculo.us、moo、mochikitあたりはすぐに挙げられる。今はAngularJSが人気を持っているが、いつまで人気を保てるか(=開発者側が発展改良サポートのモチベーションを保てるか)は分からない。

 UIフレームワークには賞味期限がある。それはUIがはやりに左右されるから当然のことだ。問題は賞味期限が切れた後である。

 提供者がまじめにサポートをし続けるか、はやりに合わせた新しいバージョンを出すかは分からないが、いずれの場合であっても、利用者側もはやりに合わせた乗り換えを検討するか、急激に(UIのはやりから見て)劣化したUIを維持するか、といった選択が必要となる。どちらにしても新たな学習コストや維持コストは発生する。

 であれば、最も安上がりなのは、以下の方法だ。

 後者は半分冗談として、前者が結局一番得だ。基本を学習することのもう1つのメリットは、逆にUIフレームワークを次々と乗り換えるにしてもソースを読めることで、学習コストが桁違いに低くなることだ。

 というわけで、C#やASP.NETと同じく、Webアプリについてはクライアント側についても、まずは基本を押さえることが重要だという結論である。


ASPXでローカル関数

 すでに説明したようにASPXは全体が1つのメソッドとして扱われるため、独自のメソッドやクラスは定義できない。しかしクラスについては前回説明した匿名クラスを利用できるように、メソッドについてもラムダ式を利用することで処理をパッケージ化することが可能だ。
 以下にentries.aspxファイルでの例を示す。

 このASPXの中では、慶弔金の幹事か対象者かによって、異なるメンバーオブジェクトを生成する。しかし、SQLの実行結果からレスポンス用のオブジェクト配列を生成する処理は共通だ。そのため、オブジェクトの生成部を、ラムダ式を利用して分けることで一種のポリモーフィズムを実現している。

  ……省略……
      Func<SqlDataReader, object> newObject = null (1)
  ……省略……
      if (Request.Params["creator"] != null) {
  ……省略……
        newObject = r =>                             (2)
          new { name = r["name"] as string, amount = r["amount"] as int? };
      } else if (Request.Params["owner"] != null) {
  ……省略……
        newObject = r => new {                       (3)
          name = r["name"] as string,
          zip = r["zip"] as string,
          address = r["address"] as string
        };
  ……省略……
      using (var reader = command.ExecuteReader())
      {
        while (reader.Read())
        {
          list.Add(newObject(reader));                 (4)
        }
      }
  ……省略……

entries.aspxファイル(抜粋)
  (1) ラムダ式の宣言。Func<T, TResult>型またはAction<T>型となる。
  (2) 幹事用にはメンバー名と金額をプロパティに持つ匿名クラスのオブジェクトを生成する。
  (3) 対象者用にはメンバー名、郵便番号、住所をプロパティに持つ匿名クラスのオブジェクトを生成する。
  (4) ループの内側では条件分岐をせずに、すでに場合分けして用意したラムダ式を実行する。

 C#はJavaScriptのように関数型(ここでは関数を引数や戻り値に自由に使えるプログラミング言語の意味)プログラミング言語ではない。しかし、ラムダ式を使うことで同じような効果を得られる。

まとめ

 今回はJavaScript側の記述方法について説明した。

 特に、企業システムのJavaScriptは20世紀の遺産がまだまだあるため、最近の変化への追随が遅れている様子を見ることがある。それが単なる「時代遅れなコーディングスタイル」という見てくれの問題ならばどうでもよいことだが、そうではなく、それが原因で明らかに開発効率が悪くなっている、端的にはバグを入れやすい方法にとどまっているとしたら改めた方がよいだろう。

 本連載では、テキストベースの開発、最小限のAPIといった方向でのWebアプリの開発について説明した。

 最小限といっても、実際には.NET FrameworkやC#の最新の機能をきちんと把握して、HTMLやJavaScriptの最新の動向をきちんと反映するだけでもそれなりの学習が必要となる。しかしそれによってよりよい開発(速く、バグが入りにくい)が可能となる。

 こういったことは、自分が直接開発するのではなく、他者に設計、開発してもらう場合でも押さえておくべきポイントだ。20世紀の技術にとどまった記法で新規のJavaScriptプログラムを開発しているようでは、そのプロジェクトは危ない。逆にjQueryなどのフレームワークを駆使して開発している場合であっても、それが状況を押さえた上での選択なのか、よく分かっていないままみんなが使っているから使っているのかによって完成後の保守性は異なってくる。

 そういう面からも、本連載で示したような基本要素だけで簡単なWebアプリを作ってみることは、現在の技術基盤となるリソースを把握する上で役に立つ。空いているWindowsサーバーがあるなら試してみることをお勧めする。

「連載:ASP.NETによる軽量業務アプリ開発」のインデックス

連載:ASP.NETによる軽量業務アプリ開発

前のページへ 1|2|3       

Copyright© Digital Advantage Corp. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。