JavaScript 2.0
根拠
バージョン管理
previousupnext

10/09/2001 (Tue)

動機付け

パッケージのバージョンアップに伴い、大抵の場合エクスポート済みインターフェイスに変更が必要になる。このような変更には (トップレベルやクラスのメンバの) 定義の削除や名前の変更も含まれるが、ほとんどは新しい定義の追加である。全ての JavaScript ソースが同じソースから構成されるような単一の環境ではこれは問題ではないが、パッケージが複数のソースから動的にリンクされる場合はおそらくバージョン管理の問題が発生するだろう。

最もよく知られた問題に定義の衝突がある。この問題を解決しない限り、ライブラリの作者はそのライブラリの将来のバージョンに新しい定義を1つも追加できない。これは新しい定義名が既にクライアント、或いはクライアントがリンクしている他のライブラリで使われているかもしれないからである。この問題はグローバルスコープ、クライアントが継承可能なクラススコープの両方で起こる。

以下はこのような衝突がいかにして起こるかを示す例である。或るライブラリの作者がクラス Data をエクスポートするライブラリ BitTracker を作成したとしよう。このライブラリの出来は素晴らしいものであったので BrowsersRUs 社全てのウェブブラウザに搭載されることとなった:

package BitTracker;

public class Data {
  public field author;   // 訳注: field は今は使われていない古いメンバ修飾子である
  public field contents; // 以下の method も同様
  function save() {...}
};

function store(d) {
  ...
  storeOnFastDisk(d);
}

今誰か他の人間が BitTracker を使ったウェブページ W を書いている。クラス PictureData から派生したもので、2つのメンバを追加している。その内 size というメソッドは画像の寸法を返す:

import BitTracker;

class Picture extends Data {
  public method size() {...}
  field palette;
};

function orientation(d) {
  if (d.size().h >= d.size().v)
    return "Landscape";
  else
    return "Portrait";
}

BitTracker ライブラリの作者は W を見ておらず、顧客の要求に応える形で Data オブジェクトデータのバイト長を返す size というメソッドの追加を決めてしまう。彼は改良した新しい BitTracker ライブラリをリリースし、BrowsersRUs は最新のブラウザ NavigatorForInternetComputing 17.0 にこのライブラリを組み込む:

package BitTracker;

public class Data {
  public field author;
  public field contents;
  public method size() {...}
  function save() {...}
};

function store(d) {
  ...
  if (d.size() > limit)
    storeOnSlowDisk(d);
  else
    storeOnFastDisk(d);
}

何も知らないユーザ U は手持ちの BrowsersRUs の古いブラウザを最新の NavigatorForInternetComputing 17.0 にアップグレードするが、その1週間後 W が動かないのを見てがっかりする。U の孫娘 Alyssa はコンピュータ使いであり、size メソッドで名前の衝突が起こったことを U に説明するが、U には何のことだか分からない。UW の作者に連絡しようとするが、彼女は自己発見の伝道のためにサハラ以南のアフリカに行ってしまっている。結局 U は BrowsersRUs に文句を言い、その怒りの矛先は BitTracker の作者に向けられることとなる。

解決策

BitTracker の作者はどうすればこの問題を避けることができたのだろうか? 単純に size 以外の名前を選択してもうまくいかない。他のページ W2 がその新しい名前と衝突する可能性があるのである。考えられるアプローチとしては次のようなものがある:

最後のアプローチは、使用するパッケージをインポートするだけかインポート文で現在のバージョンしか指定しない腰掛け気分のユーザの負荷を最小にするため最も望ましいものである。パッケージの開発者は更新したパッケージをリリースする際に、以前のバージョンでアクセス可能な定義セットを乱さないように注意すべきである。しかし動的リンクが可能なパッケージの作者には言語の上級ユーザが多く、更新されたパッケージの構成を自動的にチェックするツールを使うのかもしれないが。

JavaScript 2.0 におけるバージョン管理

JavaScript 2.0 では安全なバージョン管理のために名前空間を使う。1つのパッケージは複数の名前空間をエクスポートでき、パッケージの内容についてそれぞれ異なるアクセス性を提供する。各名前空間はパッケージ API の1つのバージョンに対応する。

用語

バージョンはパッケージの API を表す。リリースとはコードも含めたパッケージ全体を指す。1つのリリースはその API の複数のバージョンをエクスポートできる。パッケージの開発者は、バージョン V をエクスポートするパッケージの複数のリリースが、バージョン V において同じ定義セットを正しくエクスポートするかどうかを確認すべきである。

例としてソートのためのパッケージ Sorter を書いている開発者がいるとしよう。このパッケージの最初のバージョンには sortmerge という関数が含まれており、バブルソートを使っていた。次のリリースでプログラマは stablesort という関数を追加し、バージョン V2 に含めた。次の V3 リリースでは sort のアルゴリズムをクイックソートを使ったものに変更し stablesort をサブルーチンとして呼び出すようにした。また permute という関数も追加した。このパッケージの最終リリースは次のようになるだろう:

package Sorter {
  explicit namespace V2;
  explicit namespace V3;
  internal const V2and3 = V2 V3;

  public var serialNumber;

  public function sort(compare: Function, array: Array):Array {...}
  public function merge(compare: Function, array1: Array, array2: Array):Array {...}
  V2and3 function stablesort(compare: Function, array: Array):Array {...}
  V3 function permute(array: Array):Array {...}
}

ここでいずれも Sorter をインポートするクライアントパッケージ C1C2 が現れたとする。実行される Sorter のインスタンスは1つだけ — つまり最終リリースのものだけである。デフォルトでは C1C2 はいずれも Sorter の最初の API にしかアクセスできない。しかし C2Sorter が拡張されたことを知っており、新しい機能も使いたいという場合は Sorter をインポートした後に次のようなおまじないを使う。

use namespace(Sorter.V2);

これで C2 からは stablesort 関数にもアクセスできるようになる。この例では両方のクライアントは同じ sortmerge 関数と、同じ変数 serialNumber にアクセスできる (C1serialNumber を書き換えると C2 からも値が変更されたことが分かる) が、stablesort 関数にアクセスできるのは C2 だけだということに注意していただきたい。2つのクライアントは両方ともクイックソートを使った sort のリリースを得る。仮に C1 が自身で stablesort という関数を定義しても Sorterstablesort とは衝突しない。また、Sortersort はその内部サブルーチン呼び出しで Sorterstablesort を参照し続ける。

Sorter の最初のリリースしか利用できなければ Sorter.V2 は未定義となり、C2 ではエラーが発生する。sort はクイックソートではなくバブルソートを使うのだがそれでも C1 は正常に動く。

この例ではパッケージのグローバルメンバに対するバージョン管理について示した。このテクニックは既存のクラスにメンバを追加するのにも使用でき、より有用なものととなる。


Waldemar Horwat
最終更新: 2001年10月9日 (火)
previousupnext
訳者: exeal <exeal@student.interq.or.jp>
このドキュメントのオリジナルは mozilla.org において英語で公布されています。
この和訳は、利用者の利便のために Mozilla Japan 翻訳部門 によって提供されています。
内容に関してご不明な点がありましたら webmaster までお問い合わせください。