Home > Latest topics

Latest topics 近況報告

たまに18歳未満の人や心臓の弱い人にはお勧めできない情報が含まれることもあるかもしれない、甘くなくて酸っぱくてしょっぱいチラシの裏。RSSによる簡単な更新情報を利用したりすると、ハッピーになるかも知れませんしそうでないかも知れません。

萌えるふぉくす子さんだば子本制作プロジェクトの動向はもえじら組ブログで。

宣伝1。日経LinuxにてLinuxの基礎?を紹介する漫画「シス管系女子」を連載させていただいています。 以下の特設サイトにて、単行本まんがでわかるLinux シス管系女子の試し読みが可能! シス管系女子って何!? - 「シス管系女子」特設サイト

宣伝2。Firefox Hacks Rebooted発売中。本書の1/3を使って、再起動不要なアドオンの作り方のテクニックや非同期処理の効率のいい書き方などを解説しています。既刊のFirefox 3 Hacks拡張機能開発チュートリアルと併せてどうぞ。

Firefox Hacks Rebooted ―Mozillaテクノロジ徹底活用テクニック
浅井 智也 池田 譲治 小山田 昌史 五味渕 大賀 下田 洋志 寺田 真 松澤 太郎
オライリージャパン

Page 1/239: 1 2 3 4 5 6 7 8 9 »

Firefox 4: jar jar jar - Oct 06, 2010

この間悩まされたばかりのomnijarの話である、Taras’ Blog » Blog Archive » Firefox 4: jar jar jarの勝手翻訳です。分からない所が多かったので創作的意訳が多めですが気にしません。


ファイルを開く処理というものは、システムコールのための小さなオーバーヘッドや、ディスクからのデータの先読みによる大きなオーバーヘッドがある、比較的重たい処理です。データの物理的な配置の状態やディスクの種類によっては、この処理は今時の高速なCPUに対して、複数の異なるファイルそれぞれの全ての断片を先読みするためにディスク上をヘッドが激しく行き来する間、長々と無駄に暇をもてあまさせる事にもなり得ます。

最適化その1:裸のファイルをより少なくする

約2年前、私(訳注:元エントリの著者のTaras Glek)はディスク上にある裸のファイルを収集してjarファイルに詰め込む作業を始めました(例:bug 508421)。また、コードのクリーンアップやmmapへの移行などを通じて、私達はjarファイルの読み込み処理の効率も可能な限り改善しました。そして最終的には、通常の起動時にディスクから読み込まれていた、アプリケーションを構成するデータファイルの全てが、jarファイルの中に格納されるようになりました。しかし残念ながら、私達は4つのjarファイル(toolkit、chrome、そして2つのロケール用jarファイル)に構成ファイルをまとめる所までしか至れませんでした−−何ともマヌケな事ですけれども。またXPCOMの制限により、多数の裸のファイルがまだ、Firefoxのアップデートや拡張機能のインストールの度にディスクから読み込まれる状態となっていました。

最適化その2:全てを統べる1つのjarファイル

最近、Michael Wuがomnijarという滅茶苦茶にヤバい物を解き放ち非常に影響範囲の大きな変更を導入しました。これはAndroid用パッケージ作成での必要に迫られて行われた非常に大きな取り組みです。今や、アプリケーション起動時に必要なデータは常に単一のファイルから読み込まれるようになりました。これはデータの位置の集約化、ファイル走査の手間の短縮、そして待ち時間の短縮に繋がります。複数のファイルを1つに小さくまとめる事の1つの利点としては、OSがディスクからデータを読み込む際に、大抵の場合はアプリケーションが要求したよりも大きな単位で、投機的にディスクからデータを読み込む事も挙げられます。これにより、隣接するファイルの読み込みがより自由に行えるようになります。残念ながら、Firefoxを実際に実行せずにファイルアクセスの順番を予測するための良い方法がなかったため、ここにはさらなる改善の余地があります。

最適化その3:jarファイル内でのファイル配置の最適化

さて、今や全てのデータが1つのファイルの中に置かれましたので、論理的な次のステップは、それらをより賢く格納する事でした。それを行うための唯一の方法は、Firefoxの起動時の処理を分析して、jarファイル内のファイル配置をその結果に基づいて並べ替える事です。残念な事に、jarファイル内の全ての項目を連続的に配置するにあたって、私達はまだ次善の策を取っています。これは、ZIP(jarファイルの実態はZIPファイルです)のインデックスが伝統的にファイルの終端に配置されている事に依っています。Wikipediaの記事にこれを図示した物があります。

先読みの利点を最大限に活かし、ディスクの走査を最小限にするためには、格納されたファイルのインデックスがZIPファイルの先頭に置かれているのが望ましいです。そのため、私は私達のZIPファイル内のデータの配置を、

<項目1><項目2>…<項目N><インデックス><インデックスの終端>

から

<最初に読み込まれる、最後の項目の位置のオフセット値><インデックス><インデックスの終端><項目1><項目2>…<項目N><インデックスの終端>

に変更しました。

ここで私がやったのは、<インデックスの終端>のオフセット値を常に4になるようにした(どうでもいい事に拘るZIPアーカイバはインデックスのオフセットがNULLだとフリーズしてしまう事があるので、これは0にすることはできません)だけです。その際、インデックスは常に前のインデックスの終端に続けて配置されなければならないという仕様を満たすために、私は最初の物と全く同じ2つ目の<インデックスの終端>を加えました。また、私は、過度に用心深いZIPアーカイバによって強制された、どれだけのデータを最初に先読みしておく事ができるかを示す数値を格納するための追加の余白も利用する事にしました。

これによって、最適化されていないomnijarに比べてディスクI/Oの2〜3倍の削減を実現しました。これは裸のファイルをomnijarにすることで20〜100倍以上の高速化が実現できた事の最大の要因です。

私がZIPの仕様を読んでガッカリしたのは、ZIPアーカイバの中にはZIPファイルが仕様が許容しているよりもずっと厳格な形式になっている事を期待している物があるということです。以前のバージョンのFirefoxや、Microsoft WindowsのZIPサポート(訳注:圧縮フォルダ)、WinRAR、UNIXのZIPアーカイバなどは、私の最適化されたjarファイルを受け付けてくれますが、7-Zipや壊れたアンチウィルスソフト(スキャン対象を無闇矢鱈に限定する事はセキュリティ上危険です)はこれらを開く事ができません

豆知識:これは、受け付けるZIPファイルの内容を選り好みするソフトウェアのせいで困らされた最初のケースではありません。例えば、Android標準のAPK読み込み処理は、Android用のパッケージが0バイトの大きさの項目を含んだZIPファイルである場合に、いちいちしつこくそれを警告してきます。これは、APK形式のファイルをWindowsにおける自己解凍形式のEXEファイルのように使う事ができないということです。Michael Wuはこの問題を解決するための独自の読み込み用ライブラリを書いている所です。

最適化その4:さらなるomnijar

omnijarは十分に素晴らしいとはまだ言えないということで、Michael Wuはさらに先に進んで拡張機能をomnijar化しました(訳注:アドオンがXPIのままで認識されるようになった事を述べたエントリ)。ほとんどの拡張機能はXPIから裸のファイルに展開される必要が無くなる事でしょう。これは、拡張機能の作者が上記のような最適化されたjar形式を、Firefoxの起動を高速化するために利用できるという事を意味します。

その他のjarファイルの最適化

起動処理の高速化用のキャッシュをjarに切り替える事によって、私達は最初の起動処理をさらに最適化できるようになることでしょう。私が最適化されたjarファイルに加えた先読み用の情報を実際に利用する事によって、jarファイルのI/Oを半減できる可能性もあります。

元記事に寄せられたコメント

Benによるコメント(2010-09-23 05:32pm)

2点だけ:

1つ目。あなたがどのように言おうと、これらの「最適化された」jarファイルはもはやZIPファイルではありません。仕様は非常に明確で、インデックスはファイルの末尾になくてはなりません。

あなたがやった事に間違った点はありませんが、しかし、それらのファイルをZIPであるかのように偽ろうとした上で、ZIPを扱うアプリケーションがそれらに対して文句を言わないようになる事を望むというのは、良い事ではありません。それよりもあなたは、最適化されたファイルの拡張子を変更することにして、最適化とその解除を手動で行うためのツールを提供した方がよいでしょう。

私は、例えば7-Zipは仕様に対して非常に厳格に設計されているがために、これらのファイル形式をサポートする事はあり得ないだろうと確信しています。

2つ目。私はFirefoxのコールドスタート(訳注:キャッシュ等にファイルが読み込まれていない状態からの起動)が(特に他のブラウザと比べて)遅いということを体感して、少し調べてみる事にしました。新規作成したプロファイルであってもまだ起動は遅かったです。私は、Firefoxは起動時に18個ものDLL(それらは全て、Firefox/Minefieldのインストール先ディレクトリに置かれています)を読み込んでいるという事に気がつきました。これは非常に良くない事で、ファイルの数の問題だけでなく、Windowsではセキュリティ対策ソフト(既定の状態であればWindows Defender、大抵の場合は何らかのアンチウィルスソフト)においての問題もあります。

私のマシン上では、ファイルのスキャンは1つあたりだいたい50ミリ秒を要していますが、この処理時間はファイルサイズには影響を受けません。Firefoxの場合、起動に数秒を要してしまいます。セキュリティ対策のソフトが大抵の場合は必要が生じた際の動的なスキャンの結果をキャッシュしていて、再起動されるか定義ファイルが更新されるまでの間は再スキャンが行われないために、この問題がウォームスタート(訳注:ファイルがキャッシュ等に読み込まれた状態からの起動)の場合には起こらないという事には注意して下さい。

いくつかの他のブラウザは、起動時にDLLを2つだけ読み込んでいて、他は必要が生じた時(動画の再生、WebGLを使う場合など)に動的に読み込んでいます。これはFirefoxの場合よりもずっといい具合に動作しているように思われます。

検索してみた所、私はLinuxについてのこの件に対するバグをいくつか見つけましたが、Windowsについてのバグは見つかりませんでした。それらが1つの大きなDLL(xul.dll)とそれ以外の小さなDLL(それらは無条件に読み込まれる)となっているので、全てを1つのファイルにまとめるのは理にかなっていると思います。

Taras Glekによるコメント(2010-09-24 09:06am)

Ben、あなたが注目した多数のDLLを提供している点についてはあなたの指摘は的を射ています。それについてのバグは https://bugzilla.mozilla.org/show_bug.cgi?id=561842 です。残念ながら、私達はこの作業をFirefox 4のリリースには間に合わせられませんので、後のリリース版で反映される事でしょう。

私はアンチウィルスソフトが起動時の処理に与える影響についても、より詳しい情報を得たいです。

アドオンマネージャの歴史 - Sep 22, 2010

History of the Add-ons Managerのオレオレ翻訳です。誤訳がありそうですが気にしません。


Firefox 4用の新しいアドオンマネージャのために行ってきた作業を通じて、これは興味深い話題だろうと思ったので、Firefoxのアドオンマネージャについてのこれまでの歴史と今後についてざっとまとめてみました。

Phoenix 0.2

Firefoxの最初期のバージョンにおいても、拡張機能は古いXPInstall形式のパッケージの仕組みを用いてサポートされていました。拡張機能の削除や無効化のための仕組みがFirefox自体に含まれていなかったため、これらの初期のアドオンマネージャは根本的な部分でいくつか問題がありました。また、あなたが初めてアドオンをインストールした後に目にするような拡張機能マネージャのウィンドウもありませんでした。拡張機能とテーマの一覧がFirefoxに初めて追加されたのはバージョン0.2の時で、その頃はこの製品はPhoenixと呼ばれていました。それは非常に基本的なUIで、設定ウィンドウの中に表示されていました。

(Phoenix 0.2の「拡張機能」のスクリーンショット) Phoenix 0.2の「拡張機能」(2002年)

Firebird 0.6

製品がFirebirdという新しい名前を得た後、拡張機能マネージャは設定ウィンドウ内の「テーマ」と「拡張機能」という個別のペインとして生まれ変わりました。

(Firebird 0.6の「拡張機能」のスクリーンショット) Firebird 0.6の「拡張機能」(2003年)

Firefox 0.9

Firefox 0.9ですべてが変わりました。拡張機能マネージャは個別のウィンドウとなり、今日こんにち使われているアドオンのパッケージと原則的に変わらない、新しいinstall.rdfパッケージが導入されました。

(Firefox 0.9の拡張機能マネージャのスクリーンショット) Firefox 0.9の拡張機能マネージャ(2004年)

テーマと拡張機能はそれぞれ別々のウィンドウで表示され、基本的な自動更新のための仕組みが搭載されました。これらはFirefox 1.0に向けたバックエンドのコードにおいて改良されることになっていました。この最初のバージョンは主にBen Goodgerによって書かれました。

Firefox 1.5

Firefox 1.5では拡張機能マネージャの表面的な部分について、ほんの少しだけ違いが見られます。このバージョンではFirefoxの他の部分の外観のスタイル付けに合わせるためにごくわずかな変更が行われました。

(Firefox 1.5の拡張機能マネージャのスクリーンショット) Firefox 1.5のスクリーンショット(2005年)

この舞台裏で、Darin Fisherは大きな変更を行いました。彼は拡張機能マネージャに対して、Windowsのレジストリを含む、システム上の異なる場所から拡張機能を読み込むことを可能にしたのです。彼はまた、拡張機能をプロファイルフォルダ内に抽出することを可能にし、次にFirefoxが起動された時に自動的にそれらを認識できるようにもしました。この時、リリースに向けて拡張機能マネージャを安定させるために、Rob Strongがモジュールオーナーの権限を引き継ぎました。また、このバージョンには拡張機能マネージャに対する私(※訳註:原文の著者のDave Townsend氏)の最初のパッチも含まれています――bug 307925においての物で、ごく小さな物ですが。

Firefox 2.0

Firefox 2.0では最終的に、分割されていた拡張機能とテーマのウィンドウが一つのアドオンマネージャに統合されました。

(Firefox 2.0のアドオンマネージャのスクリーンショット) Firefox 2.0のアドオンマネージャ(2006年)

水面下では、ユーザにとって危険と判断された拡張機能をMozillaの手で外部から無効化する事を可能にするためのブロックリスト機能の最初のバージョンを含む、さらに多くの変更が行われていました。この機能が作られて以来、私たちはこの機能を本当にごく希にしか使っていませんが、セキュリティ上の弱点やクラッシュを防ぐ際の助けとなってきました。

Firefox 3.0

Firefox 3において、私たちはプラグインをアドオンマネージャの中に含めるようにし、また初めての利用において皆さんがアドオンマネージャを使ってaddons.mozilla.orgからアドオンを直接ダウンロードしてインストールできるようにしました。これは私(※訳註:原文の著者のDave Townsend氏)がFirefoxにおいて作業した最初の大きな機能で、この機能がどれだけ使われているかをアドオンチームから聞く度に、私はいつも非常に嬉しい気持ちになります。

(Firefox 3.0のアドオンマネージャのスクリーンショット) Firefox 3.0のアドオンマネージャ(2008年)

内部的には、ブロックリスト機能はプラグインをブロックできるように拡張され、Windows以外のプラットフォームにおいてもシステム上の他のアプリケーションとの連携に対応するためにインストール対象となるファイルの置き場所が新しく追加されました(※訳註:bug 311008)。

Firefox 3.5と3.6

Firefox 3.5と3.6においては視覚的な変更点は全くありませんでしたが、Firefox 3.5ではブロックリスト機能がいくつかの異なる重要度のレベルに対応できるように再度改良され、Firefox 3.6ではシステム上にあるアップデートが必要なプラグインについてユーザに警告を行う機能への対応に加えて、Firefoxのメインウィンドウの単調な背景を簡単に切り替えられるようにする、産まれたばかりのペルソナがアドオンマネージャに搭載されました。

Firefox 4.0 beta

Firefox 4では、再起動が不要な拡張機能への対応の追加や、ユーザの操作をより妨げない自動的な更新のための仕組み、そして新しいアドオンに出会うためのより便利な方法などを含む、アドオンマネージャの全面的な再設計が見られます。

(Firefox 4 betaのアドオンマネージャのスクリーンショット) Firefox 4 betaのアドオンマネージャ(2010年初頭)

裏側においては、新しいアドオンマネージャは新しい種類のアドオンを、これまでよりもさらに簡単に管理できるようになっています。

Firefox 4.0

ユーザ・エクスペリエンスチームは、Firefox 4のリリース版でアドオンマネージャがどのように見えるようになるかの最終的なデザインを作成するために、一生懸命働いています。あくまで仮の物ですが、これは彼らが行おうとしていることのスケッチです:

(Firefox 4最終版用に検討中のデザインのスクリーンショット) Firefox 4最終版用に検討中のデザイン(2010年末頃?)

将来的に、私たちはさらに多くの種類のアドオンをこのマネージャの中に持ち込むことを計画しています。現在はそれ用の独自のウィンドウで管理されている検索プラグインなどのような物は、ここにうまく収まるでしょう。また、私たちは皆さんが拡張機能をより単純な形でカスタマイズするようにしたいとも考えています。可能性は低いですが、私たちは拡張機能の開発者達に対して、独自の設定ウィンドウを作る事を許容するのをやめて、新しいウィンドウを開くことを必要とせずに、単純な設定をアドオンマネージャの中で直接変更できるようにする機能を加える事を検討しています。私たちは、皆さんがインストール済みのプラグイン――それは時にセキュリティ上の問題や、安定性を損なう問題の元になります――を自動的に更新する方法を実現できたらと考えていますし、テーマの選択について、どんなテーマが利用可能かを見たり、それらを切り替えたりするのを、より簡単に行えるよう大幅な改良を行いたいとも考えています。

これらのことのうちのいくつかはFirefox 4.0までの時間で実際に行われるかもしれませんが、最終的なリリースの前に新しい物を取り入れるには、時間は残り少ないです。

Google Chrome Extensions - Dec 16, 2009

GoogleChromeの拡張を作る上でFirefoxアドオン作者が知っておくべきやればできること « kuFirefoxアドオンの自由度は奇跡的です。millennium | Google Chrome Extensionsを読んでその奇跡を噛み締めましょう。と紹介されていたエントリを勝手に翻訳してみました。原文の著者は、Firefoxの初期開発チームの一員で、今はGoogleに転職してGoogle Chrome開発チームの一員となっているBen Goodger氏です。


Chromeチームは今日(※訳注:2009年12月8日)、Mac OS XとLinux、そして拡張機能に対応した最初のバージョンをリリースしました。これは、非常に多くの人達の1年間にわたる作業の完成を意味しており、私は開発チームがこの目標を達成できたことを誇らしく思っています。そこで、拡張機能について少し語る機会を設けることにしました。

Chrome拡張機能APIはユーザと開発者に対して、Chromeの核となる原則である「速度」「安定性」「安全性」そして「シンプルさ」を保ちながらブラウザをカスタマイズする能力を提供します。

Google Chromeの拡張機能には以下のようなことができます。

  • JavaScript、HTML、CSSなどの一般的なWeb技術によって簡単に開発できます。
  • それぞれ別々のプロセスで実行されるため、ブラウザ全体の動作を遅くさせるような問題は起こりません。
  • 限定的なAPIを持っており、各拡張機能はブラウザのタブと同様のサンドボックス内で実行されます。
  • Chrome自身と同様の自動アップデートの仕組みを使うため、開発者は彼らのソフトウェアの新しいバージョンを容易に公開することができ、ユーザは何もしなくても、最新・最高・最も安全なバージョンにアップデートし続けることができます。

Google Chrome拡張機能についての動画はここで見られます。

私はここしばらくの間、ブラウザの開発に関わり続けてきました。私の話を興味深く思う人もいるでしょうから、拡張機能の歴史について少しお話ししましょう……

かつてNetscapeがNetscape 6(ブラウザ、メールクライアント、ページ作成ツール、そしてIMクライアントのセット)を開発していた頃の要求仕様の1つとして、メールクライアント、IMクライアント、ページ作成ツールといった「選択式の」コンポーネントを含めずにブラウザだけをインストールできるようにする、というものがありました。それらのコンポーネントをインストールした場合は、メールクライアントやIMクライアント等を起動できるようにするために、ブラウザのUIに「追加の項目(メニュー項目、ツールバー上のボタンなど)」が表示されることになります。

NetscapeのフロントエンドはクロスプラットフォームなUI言語であるXULによって実装されていました。選択式のコンポーネントは、それらがインストールされている場合に「追加の項目」を加えられるよう、「オーバーレイ」と呼ばれるファイルを含んでいました。選択式のコンポーネントはそれ自身のオーバーレイや他のロジックを「XPI」ファイルの中にパッケージングされていて、インストールエンジンによってインストールされるようになっていました。

何年か後、Netscapeの後継者であるFirefoxの人気が高まると同時に、開発者達は、前述のようなコンポーネントのインストールのための仕組みを、ブラウザに対して他の機能を追加するためにも利用できるという事に気がつきました。この機能自体はNetscapeの自社製品以外が使うことを全く想定せずに作られていたので、ブラウザのUIの中でどんなAPIが公開される必要があるのかといったことに対しては十分な注意が払われていませんでした。本当に単なる内部的なAPIでしかなかったのです。そのため、人々がFirefox用の「拡張機能」の開発を始めたばかりの頃は、Firefoxに何か変更が行われるとその度に拡張機能のせいでブラウザが起動しなくなるというのが日常茶飯事でした。Firefoxの初期の頃には、ある拡張機能(※訳注:多分タブブラウザ拡張のことじゃないだろうか。というのは自意識過剰?)をインストールしていたユーザにとっては、Firefoxの新しいバージョンにアップグレードする度に「ブラウザにXBLのバインディングが適用されていません」というエラーにぶつかる、といったことも珍しくありませんでした。

Firefoxがバージョン1.0に達する前にこの問題を解決しなければならないのは明らかでしたので、私は拡張機能マネージャをFirefoxに加えることにしました。これは、インストールやアンインストールのためのやっかいなコードを書かなくても済むようにすると同時に、より重要な点として、バージョン管理のための仕組みを提供するものでした。安定したAPIが無い以上、システムは単純に、ブラウザのそのバージョンに対して互換性があると明記されていない拡張機能を無効化します。これは開発者達にとって、新しいバージョンのFirefoxがリリースされるごとに毎回、彼らの拡張機能の動作を保証しなければならないということを意味します。この仕組みは完璧でもないし、煩わしいものでしたが、しかしそれなりにうまくいったため、私達はひとそろいのAPIを凍結させなくてもよかったのです。APIの凍結を急かされていたら、まず間違いなくそれはおざなりな物になってしまっていたでしょう。

Firefoxの拡張機能は常に諸刃の剣です――それは計り知れない柔軟性を提供しますが、その引き替えに、ブラウザがアップデートされるごとに毎回動作確認を取らなければいけないというコストを開発者に対して強います。開発者の動作確認が遅れた場合、ブラウザの新バージョンがでてすぐにアップグレードしたユーザは、しばらくその拡張期能なしで過ごさなければならないか、あるいは、互換性の確認の過程を自己責任で無効化する必要があります。

私はこの歴史についての覚え書きには、面白いというだけでなくケーススタディとしても価値があると考えています。もし、Netscapeのコンポーネント式のインストールのおかげでこのブラウザのカスタマイズのための「裏口」が存在していなかったら、Firefoxに拡張機能の存在自体が全く無かったかもしれないのです。考えてみて下さい。その機能がユーザに愛されたために、Firefoxは成功したのです。これは驚異的な事です。この前例があって、ユーザが拡張機能を愛しているということが分かったので、私達Google Chromeチームは今、カスタマイズ性とChromeの核となる原則とを両立させる最良の物を作るべく、新しいAPIをゼロから作るという贅沢が許されているのです。

Firefoxでの体験は計り知れないほど有益な物でした。私は、Google Chromeの拡張機能の開発に個人的に寄与した数多くの技術者達のうちの1人ではありませんが、しかし、機能をどのように実現するかを検討する事については十分な戦歴があります。私はChrome拡張機能のチームがこのアプローチを取ることを決定した事をとても嬉しく思います。最初のマイルストーンへと私達を導いてくれた彼らに賞賛を!

拡張機能におけるeval()の5つの間違った使い方 - Nov 28, 2009

以下、Adblock Plus and (a little) more: Five wrong reasons to use eval() in an extensionのいいかげんな訳です。XUL/Migemoのバージョンアップ時のエディタによるレビューのコメントで「今回は公開を承認するけど、次からはeval()はなるべく減らすように。詳しくはこれを読んで。」と指摘されたので、自分が読むために訳してみました。誤訳があったら指摘して。一部のサンプルコードは見やすさのためにインデントを勝手に加えてます。

ちなみに、僕は5番目の点(こういう用途でeval()を使うなという話)については反対の立場です。拡張機能同士を協調して動作させたいなら、むしろeval()を使って関数を書き換えるやり方を使う方が望ましいとすら考えています。なので参考のために、似たような立場と思われるSimon氏・Dorando氏のコメントも訳しています。

2010年2月8日追記。このエントリで述べられている内容に対する反論を公開しました。できればそちらも併せてご覧下さい。


過剰に使われているJavaScriptの機能のひとつに、eval()関数があります。私はそれが非常に多くの拡張機能で利用されているのを見てきましたが、そのうちのごく一部だけが正しい使われ方をしています。ですので、eval()のすべての間違った使い方について説明したいと思います。

1. JSON形式のデータのパースのため

今日において、JSONはデータを保存するためのポピュラーな形式となっています。その最大の特長は、パースが非常に簡単であるということです。単に data = eval(json) という風に書けば、それだけで事足ります。

うまい話には裏があるんじゃないの? その通り。このjsonという変数は {foo: "bar" + alert(Components.classes)} のような内容が含まれるかもしれず、このようなJavaScriptのコードを実行してしまうと、あなたが意図していなかった結果になってしまうでしょう。このように、信頼できない情報源からやってきたデータをJSONとしてパースする用途にはeval()は全く不向きです。それがFirefoxの拡張機能であるなら、どんなWebサーバから送られてくるデータも信頼できません。もしそれがあなたのWebサーバであっても、ハックされて(※訳註:原文ではhacked)いるかもしれませんし、ユーザへの通信経路上で情報が改竄されているかもしれません(特に、暗号化されていない接続では)。あなたは、ユーザを危険な状況に晒したくはないでしょう。

それだけではありません。そのデータが拡張機能自身によって(例えば、ブラウザ終了時の状態を保存するためなどの目的で)書き出されたデータであっても、常に信頼できるとは限りません。その中にはひょっとしたら、Webから受け取ったデータが含まれるかもしれません。もしJSONを書き出す処理にバグがあって、JavaScriptの文字列として書き出すべき物が文字列になっていなければ、それをJSONとして解釈しようとした時、知らない間にJavaScriptのコードとして実行されてしまうでしょう。これが、JSON処理専用の機能を必ず使うようにした方が良い理由です。JSON処理専用の機能は、不正なデータを受け取った時にもJavaScriptのコードとして実行してしまわないので安全です。

2. プロパティ名が動的に変化する時に、そのオブジェクトのプロパティにアクセスするため

obj.fooNNnという変数の値である、というプロパティにアクセスしたいとき、どんなコードを書けばよいでしょうか? これは、あなたがアクセスしなければいけないプロパティの名前が事前には分からなくて、動的に決定されるものであるという場合のことです。拡張機能の中には、これを eval("obj.foo" + n) のようなやり方で解決しているものがあります。この時、その拡張機能はnの値の中に危険な内容が含まれていないかを検証する必要があるでしょう――でも、どうやって?

幸いにも、この質問の答えを考える必要はありません。もっといい方法があります。JavaScriptではすべてのオブジェクトが連想配列である(※訳註:原文ではassociative arrays)ことを思い出してください。言い換えると、obj.fooobj["foo"] は全く同じ意味で、すべてのプロパティは配列の要素としてアクセスできるのです。ですから、前述のような問題を解決するには単に obj["foo" + n] とだけ書けばよく、この操作は、何も他の余計なことをすることなく常にそのプロパティにアクセスするでしょう。

では、メソッド(関数)の場合は? JavaScriptではメソッドも、値が関数オブジェクトであるという違いがあるだけのただのプロパティです。その関数を this が正しい値を示すようにして呼び出すために、Function.call() というメソッドが利用できます:

var method = obj["foo" + n];
method.call(obj, param1, param2);

あるいは簡潔にこう書くこともできます:

obj["foo" + n](param1, param2);

同じアプローチが、グローバル変数やグローバルな関数に対しても使えます。「グローバルオブジェクト」のすべてのプロパティはwindowのプロパティとして参照できます。window.foowindow["foo"] は、グローバル変数fooの値を返すでしょう。(※訳註:JavaScriptコードモジュールなどwindowが使えない変数スコープでも、 (function() { return this; })() とすればその実行時の変数スコープのグローバルオブジェクトを取得できます。)

3. 関数に対して、その関数が処理を終えたあとに何をするべきかを示すため

私が時々見かけるひとつのパターンは、このような関数の呼び出し方です:

foo("window.close()");

その関数は他の場面で、異なるJavaScriptのコードをパラメータとして渡されていました。そして関数が処理を終えた後で、パラメータとして渡された内容を動作の指定として eval() で実行するようになっていました。

どう見ても、ここにはセキュリティ上の問題はありません(※訳註:もちろん、パラメータで渡す内容にWebから取ってきたデータが含まれる可能性がある時は問題外ですよ!)。では、このアプローチの一体どこが間違っているのでしょうか? 実際には、以下のような問題があります:

  • このコードはeval()が呼ばれるまでコンパイルされないでしょう。これは、それ以外の部分のコードについてはスクリプトが読み込まれた時にすぐにJavaScriptインタープリタが文法エラーを報告するのに対して、関数のパラメータとして渡されたコードの文法エラーは後になってからしか報告されないため、そのコードが実行されるような経路を辿る操作をあなたがテストしなかった場合に、問題が見過ごされてしまうだろうということを意味します。
  • もう1つの問題は、そのコードの中で起こったエラーに対して、JavaScriptインタープリタが正しいソースファイルと行番号を報告することができず、どこで問題が起こったのかを知ることができないという点です。このようなエラーのデバッグはとても面倒です。
  • 付け加えると、foo()に対して実行して欲しいコードをパラメータとして渡すというのは普通のやり方ではなく、見苦しい回避方法を色々と必要とします。(※訳註:ダブルクォーテーションをエスケープしないといけない、など。)

幸いにも、クロージャを使うことによってそれらの問題は解決できます(※訳註:この例はクロージャではなく関数リテラルとか関数オブジェクトとかその辺の話だと思うんですが……)。以下は、前述のコードを少し書き換えた例です:

foo(function(error)
{
  alert(error);
  window.close();
});

そしてfoo()という関数の内容は以下のようになるでしょう:

function foo(callback)
{
  ...
  callback("Full success");
}

4. HTMLやXULにインラインで記述されたイベントハンドラを実行するため

以下のようなボタンがあると仮定しましょう:

<button id="button" oncommand="doSomething();"/>

このイベントハンドラを実行するために eval(document.getElementById("button").getAttribute("oncommand")) としてはいけないのは何故でしょうか? その要素が実際にクリックされたなどの場合以外の所でイベントハンドラを実行するための方法として、拡張機能の中ではしばしばこのようなやり方が用いられます。しかしながら実は、commandイベントを生成する方法のほうがもっと簡単で、しかもイベントハンドラがどのように定義されていようとも正常に動作することが期待できます:

document.getElementById("button").doCommand();

doCommand()というメソッドは、すべてのXUL要素で利用可能です。他のイベントに対しては、document.createEvent()を使って本当のイベントオブジェクトを生成する方がよいでしょう――何故なら、イベントハンドラがそれを期待しているでしょうから。例えば:

var event = document.createEvent("MouseEvents");
event.initMouseEvent("click", true, true, window,
                     0, 0, 0, 0, 0,
                     false, false, false, false,
                     0, null);
document.getElementById("button").dispatchEvent(event);

では、あなたが「onfooaction」という風な独自の属性を定義していて、それがいかなる実際のイベントとも関連付けられていない場合には? このような場面でも、eval()を使うのは最良の選択とは言えません。何故なら、eval()を呼び出した関数の実行コンテキストにおいてコードが実行されてしまうからです。もしそのイベントハンドラがfooというグローバル変数を参照したとして、あなたがそのイベントハンドラを呼んでいる関数の中にfooという名前のローカルな変数があったら――そのイベントハンドラは意図しないままにそのローカル変数にアクセスしてしまうでしょう。そしてもちろん、その時イベントハンドラに対してパラメータを渡すこともできません。よりベターな解決策は、そのイベントハンドラのための関数を作る事でしょう:

var handler = new Function("param1", "param2",
                           document.getElementById("button")
                                   .getAttribute("onfooaction"));
handler("foo", "bar");

このシナリオでは、このイベントハンドラは「foo」をparam1という名前の引数として、「bar」をparam2として受け取るでしょう。(これは、よくあるインラインで記述されたイベントハンドラに対してeventというパラメータを渡す時にも使えます。)

5. ブラウザの関数を書き換えるため

以下のようなことをしているコードをよく見かけます:

gBrowser.foo = eval(gBrowser.foo
                            .toString()
                            .replace("foo", "bar"));

このようなやり方でブラウザの関数を書き換えている人は、公の場所でおしりペンペンされることをお勧めします。それは、ブラウザの関数を新しい関数で単に置き換えてしまうだけの拡張機能に比べてほんのちょっとだけマシであるに過ぎません。どちらの場合も、書き換えられようとしているコードが変化しないことを前提にしていますが――しかし、もしそれが起こったら? 最良のケースでは、その拡張機能は大きな損害を与えることなく単に動作しなくなるでしょう。しかしひょっとすると、ブラウザを壊してしまうかもしれません。あるいは、ブラウザのその関数がセキュリティ上の問題の修正のために書き換えられたとしたら、その拡張機能は同じセキュリティ上の問題をまた持ち込んでしまうかもしれません。

言い換えると――この使い方はしてはいけません。ほとんどの場合で、このアイデアはブラウザの関数の動作を変えるのではなく、その関数の前後に追加の処理を挿入するために使われています。幸いなことに、それをするためのもっと危険でないやり方として、ここでもクロージャを使えば元の関数を単純にあなたの関数で包み込むことができます:

var origFoo = gBrowser.foo;
gBrowser.foo = function(param1, param2)
{
  if (param1 == "top secret")
    doSomethingBeforeFoo();
  var result = origFoo.apply(this, arguments);
  if (result == null)
    doSomethingAfterFoo();
  return result;
}

元の関数にすべてのパラメータを渡すためにFunction.apply()を使うことに注意してください。その関数が今現在2つだけパラメータを受け取っているとしても、将来のバージョンのブラウザでは変わるかもしれません。あなたの拡張機能は新しいパラメータに対して何をすればよいのか知っているかもしれませんが、元の関数の動作を壊さないために、それらの新しいパラメータはそのまま元の関数へ引き渡しましょう。

eval()の正しい使い方とは?

私は、eval()関数の有効な使い方はそれほど無いと思っています。拡張機能の中にはユーザに対して、評価可能なJavaScriptのコードを入力させることを許しているものもあります。そのスクリプトが関数のパラメータとして値を受け取る必要があり、関数を作り変数を渡すのにFunction()コンストラクタを使うことが依然として望ましいとしても、これはeval()の妥当な使い方でしょう。

もう1つのeval()の使い方として、状況に応じて定数を宣言するためにも使えます:

if (typeof MY_CONSTANT == "undefined")
  eval("const MY_CONSTANT = 'foo'");

こうすることによって、もし他のスクリプトで同じ名前の定数が定義されていても、あなたは文法エラーを目にしなくて済むでしょう。しかしながら、私はこれはその場しのぎのやり方だと思います。もし同じ名前空間で実行される未知のスクリプトと衝突することを恐れているのなら、あなたは他のスクリプトが使わないような一意な名前を定数(グローバル変数も)に与えるように気をつけるべきです。また、あなた自身のスクリプトについても、定数宣言を含んでいるスクリプトを複数回読み込まないように気をつけてください。

最後に、実行時にそれ自身のコードを生成するためにeval()を大量に使う、分かりにくい・「圧縮」されたスクリプトもあります。Webにおいては「圧縮された」スクリプトに価値があることは認めますが、拡張機能の中で同じ事をやることにはほとんど意味がありません。拡張機能は1度だけしかダウンロードされませんから、ダウンロードにかかる時間をたった2秒だけ節約できても、誰も喜ばないでしょう。また、「圧縮」されたスクリプトはロードされ実行される度に毎回、処理に余計な時間を食うことでしょう。

エントリにつけられたコメント

1. Simonによるコメント

5番目について。関数の中のコードに手を入れる(単にコードの前後に処理を付け加えるだけでは実現不可能で、関数全体を書き換えないといけないような場合)方法として、どんなやり方なら勧められるというのでしょうか? また、ある1つの拡張機能があなたの推奨しているやり方を実行したら、関数の中身を書き換えるタイプの他のすべての拡張機能の動作が妨げられ、それらの拡張機能はすべてのコードを書き直すことを強いられるので、拡張機能同士が円満に共存できなくなるでしょう。

私は元々はあなたが勧めているようなやり方を取っていましたが、しかしeval()を使うことによってしか解決できないような非互換性の問題に何度か遭遇してきました。より良いやり方があるのなら私は喜んでそれを採用するつもりですが、残念ながら、私にはあなたが勧めているやり方が問題を解決してくれるようには見えません……

4番目について。new Function("some code")eval("some code")と比べてどのように安全なのでしょうか? bug 477380であなたはeval()を禁止することを提案していますが、new Function()も禁止しないと無意味なのではないでしょうか。

Wladimir Palantによる返信:

あなたが書いたわけではない関数の中身に対して変更を行う事は、一般的に言ってよいアイデアではありません。あなたがどんな風にそれをやったとしても、必ず酷い結果になるでしょう。他の手段(例えばObject.watch()など)であなたがやりたいことを実現できないのであれば、多分あなたはそれをするべきではないのでしょう。

new Function()について。それはeval()に比べて本質的に安全であるとは言えませんが、それはたいていの場合静的なコードのために使われ、それほど多くの問題を持ち込みません。これは、トラブルを抱え込まないようにするための良いコーディングの習慣ということです。

2. Mookによるコメント

特権が無いWebページの場合でも同じ事が言えるのでしょうか? Gecko 1.9.1はグローバルなJSONオブジェクトを実装するそうですが、evalInSandboxと同等のものはあるのでしょうか?

evalInSandboxを使うためにUniversalXPConnect権限が必要なのは困ります……

Wladimir Palantによる返信:

クロスサイトスクリプティングを防ぐことについて話しているのだと思いますが――スクリプトのためのサンドボックスは十分な対策とは言えません。これについてはbug 341604(※訳註:IEの独自拡張であるiframe要素のsecurity属性の実装についてのバグ)とWHATWGのWeb Appsの仕様のiframe要素のsandbox属性を参照してください。

5. Dorandoによるコメント

5番目について、例えば元の関数 gBrowser.foo について以下の場合を仮定しましょう(似たようなコードはMozillaのコードベースから簡単に見つけられます。例えばtabbrowser.xmlで「.isTrusted」や「permitUnload」を検索してみてください):

gBrowser.foo = function(param1, param2)
{
  if(!gBrowser.isItSaveToDoSomethingBeforeFoo())
    return;

  if (param1 == "do_nothing")
    return;

  var color = "red";
  doSomething(color, param2.length);

  if (param2 == "some_extensions_want_to_prevent_this")
    doSomethingAnnoying("dark"+color);
}
  1. 関数内でdoSomething()が実行された時に、常にdoSomethingAfterFoo()を実行するようにしたい、という時はどうすればいいのでしょうか?
  2. 関数内でdoSomething()が実行されるであろう時に、常にdoSomethingBeforeFoo()を実行するようにしたい、という時はどうすればいいのでしょうか? 元のコードのうちいくらかを複製することはできますが、それは既に修正されたセキュリティの問題をまた持ち込みかねず、関数を単に書き換えるだけにしない事のメリットを打ち消してしまいかねません。関数に対して行われる変更を常に参照し続けることは、いくつかのシチュエーションでは上手く行くでしょうが、私に言わせてもらうとそれは大変すぎます。(そしておそらくコードをいくらか遅くさせるでしょう。)
  3. gBrowser.foodoSomethingAnnoying()を実行するのを食い止めたい時はどうすればいいのでしょうか?
  4. gBrowser.fooが使う色をgreenに変えたい時はどうすればいいのでしょうか? 追加の関数を置き換えてその呼び出し元関数を確認するようにするという手もありますが、私にとってはそれは何かを壊してしまう可能性を増大させるものでしかないです。関数に本来の処理を行わせた後でその変更を後から取り消すというやり方も、可能ではありますが、良いユーザ体験をもたらすものとは思えません。

どちらの場合も、書き換えられようとしているコードが変化しないことを前提にしていますが――しかし、もしそれが起こったら?

maxVersionはそのために存在しています。

あるいは、ブラウザのその関数がセキュリティ上の問題の修正のために書き換えられたとしたら、その拡張機能は同じセキュリティ上の問題をまた持ち込んでしまうかもしれません。

isItSaveToDoSomethingBeforeFooが導入されて、doSomethingBeforeFoo();eval()でパッチを当てられた場合と同様の内容を含むようになったとしたら、(※訳註:ここで推奨されているやり方の方の)関数の置き換えでも同じ問題が起こり得ます。

その一方で、拡張機能の作者はeval()によって、(セキュリティに関するものも含めて)バグがFirefox本体側で修正されるよりも前にパッチを適用することができます。そのバグが本体側で修正された後は、書き換え対象のコードが見つからなくなるので、eval()によるパッチ適用は望ましい形で失敗する(※訳註:何の変化ももたらさず悪影響も及ぼさないということ)でしょう。

あなたが書いたわけではない関数の中身に対して変更を行う事は、一般的に言ってよいアイデアではありません。

もちろんです、それは組み込みのどんな機能の挙動を変えることについても常に言えることです。しかし拡張機能の作者にとっては、やりたいことを実現するための組み込みのインターフェースや関数が存在しない時に、それを実現するための唯一の手段がこれであるという場合もあります。

Simonが既に指摘していることの繰り返しになりますが、関数へパッチを当てるのではなく関数を丸ごと置き換えるという(※訳註:ここで推奨されている)やり方は、私が述べたようなことをやろうとしているすべての拡張機能に対してそれを完全に妨げてしまいます。ですからどうか、あなたが代替になる方法を提案できないのなら、このような手法を推奨しないでください。

あなたがどんな風にそれをやったとしても、必ず酷い結果になるでしょう。

(以下翻訳中)

今まで私がみてきた限りでは、ほとんどの最小の変更がそれを壊しうるという事実にもかかわらず、(APIの変更を含む)他の種類の変更によってコードが動かなくなるケースの方が、eval()によるパッチの適用が原因で動かなくなるケースよりも多く見られました。

Wladimir Palantによる返信:
  1. あなたはgBrowser.foowindow.doSomethingの両方を拡張する必要があります。gBrowser.fooの開始時にフラグ変数をfalseにセットして、window.doSomethingがそれをtrueにする、doSomethingAfterFooはそのフラグ変数がtrueになった時にだけ呼ばれる、という具合です。
  2. 私はあなたが、予知能力を持ったモジュールを必要としているとは思いません――あなたがやりたいのは、gBrowser.foowindow.doSomethingを呼んだ時にdoSomethingBeforeFooを呼ぶ、という事でしょう(window.doSomethingが他の場所から呼ばれた場合を除いて)。このような場合、やはり両方の関数を拡張するべきです。gBrowser.fooの開始時にフラグ変数をtrueにセットして、終了時にそれをfalseにセットする。window.doSomethingの開始時に、そのフラグ変数の値がtrueであるならdoSomethingBeforeFooを実行する。という具合です。
  3. bのやり方と同じ手法でgBrowser.fooを拡張し、doSomethingAnnoyingについてもそのフラグ変数がtrueな時は何もしないように拡張することで、可能でしょう。ただし、あなたが本当にそれをする必要があって、それが何をどのように壊すのかについては、改めてよく考えてください。
  4. bのやり方と同じ手法でgBrowser.fooを拡張し、doSomethingについてもそのフラグ変数がtrueで且つarguments[0]"red"である場合にarguments[0]"green"に置き換えるように拡張すれば、それも可能でしょう。ただしその場合も、やる前にその影響をよく考えてください。

maxVersionの仕組みについては、大抵の拡張機能は「バージョン3.0.*に対して互換性がある」という風に指定されているので、セキュリティの修正やマイナーリリースでの変更をキャッチアップしてくれません。

その一方で、拡張機能の作者はeval()によって、(セキュリティに関するものも含めて)バグがFirefox本体側で修正されるよりも前にパッチを適用することができます。――このような方法でバグにパッチを当てるのは、実に宜しくないアイデアです。Bugzillaにバグを報告して、ちゃんとしたパッチを書いてください。それが確かに明らかにバグで、安全に修正できるのであれば、その修正はマイナーリリースに取り込まれるでしょう。もしあなたが間違ったことをしていれば、フィードバックを得られるでしょう――それは、誰にも何も尋ねずに「パッチ適用」をしてブラウザの機能を壊してしまうよりも良いことです。

6. Dorandoによるコメント

doSomething(あるいは他の関数)は、 Components.classes[""].createInstance().doSomething(); という風な(※訳註:置き換え不能なネイティブのメソッドを呼ぶ)コードかもしれませんし、関数ではなくべた書きされたコードのブロックかもしれませんし、あるいは、その処理がとても頻繁に呼ばれる機能である場合は置き換え後の関数によって度し難いほどの余計な処理時間がかかるかもしれません(特に、複数の拡張機能がそういうことをするのなら)。

maxVersionの仕組みについては、大抵の拡張機能は「バージョン3.0.*に対して互換性がある」という風に指定されているので、セキュリティの修正やマイナーリリースでの変更をキャッチアップしてくれません。

これは「必ず酷い結果になる」という未来予測への反論ですよ。あなたが言っているのは実際には拡張機能の作者の過ちです。また、私に言わせれば、既存のコードを動かなくしてしまうような変更がMozillaのセキュリティアップデートで行われることがあまりに多すぎます(私が知っている最近の例はBug 442333(※訳註:eval()の第2引数の廃止を決定したバグ)です)。

このような方法でバグにパッチを当てるのは、実に宜しくないアイデアです。Bugzillaにバグを報告して、ちゃんとしたパッチを書いてください。

既にBugzillaに報告されていたり、次のメジャーリリースに修正が取り込まれることが確定していたりするなら、同じコードを使えるでしょう。そのバグが外部の(※訳註:拡張機能などの)コードに対してのみ影響を与えるものである場合は特に、(パッチが提出されていても)そのバグが実際に修正されるまでには何ヶ月もかかることがあります。

それが確かに明らかにバグで、安全に修正できるのであれば、その修正はマイナーリリースに取り込まれるでしょう。

その修正が次のマイナーリリースに取り込まれたと仮定しても、それには最低でも1ヶ月はかかります。その修正内容をバックポートすることはそれほど害を及ぼさないでしょう。

~誰にも何も尋ねずに「パッチ適用」をしてブラウザの機能を壊してしまうよりも良いことです。

もしその拡張機能の意図するところが、そのシチュエーションにおいて行われる通常の挙動を変更する事なのであれば、それは初期状態の挙動を壊してしまおうとするもののように見えるでしょう。

7. Simonのコメント

ちなみに、異なる実行コンテキストでコードを動的に実行することは、eval()のもう1つの妥当な使い方です。

eval("code to inject", context);

あるいは

domWindow.eval("code to inject");

これらは、コードを一時ファイルに書き出して、サブスクリプトローダーで読み込ませ、一時ファイルを削除する、という風なやり方によってのみ置き換えることができます。なぜなら、サブスクリプトローダーは依然としてdata: URIの読み込みを許可していないからです。(この回避策は実に面倒です。テンポラリファイルを使うことは他の問題を引き起こしかねませんから。)

Wladimir Palantによる返信:

「異なる実行コンテキスト」というのは、「特権がないコンテキスト」という意味ですか? それは別物です、そのコードはChrome権限を得ることはないでしょう。

8. Simonのコメント

「異なる実行コンテキスト」というのは、「特権がないコンテキスト」という意味ですか?

そうとは限りません。nsIWindowMediatorによって返されたDOMWindowのコンテキストは、Chrome権限のあるオブジェクトと同じになり得ます。(サブスクリプトローダーを使って読み込ませたスクリプトや、XBLのバインディングの中に書かれたスクリプトのようにwindowオブジェクトを汚染することなく動的に使われるスクリプトにおいては。)

最初の影響を見るには、以下のコードをエラーコンソールで実行してみてください:

Components.classes["@mozilla.org/appshell/window-mediator;1"]
          .getService(Components.interfaces.nsIWindowMediator)
          .getMostRecentWindow("navigator:browser")
          .eval("location");

ブラウザのタブの改革 - Firefox.nextへの道:タブをより良くする。 - Jul 30, 2009

Mozilla Corporationの中の人であるAlexander Limi氏次世代のFirefoxのタブインターフェースをどのように改善するかについての議論の叩き台となるエントリを6月に公開されている。その中にツリー型タブへの言及もあった。だからというわけでもないけど、英辞郎とExcite翻訳に頼りながらどうにかこうにか日本語に訳してみた。誤訳があったらごめん。

なお、翻訳を公開することについてはご本人の許諾を得ております。


ブラウザのタブの改革 - Firefox.nextへの道:タブをより良くする。

よく知られた技術ニュースサイトのスクリーンショットから話を始めましょう。「Digg」ボタンを押したくなる気持ちはよく分かりますが、押さないように。何も起こりませんからね。

(スクリーンショット:mashable.comの「40+ Add-Ons for Managing Firefox Tabs」という記事に474のdiggが付いている)

さて、ここで何が起こっているか? 以下のようなことが言えます:

  • ブラウザ上で複数のページを扱うための現在の手法は、十分であるとは言えません。少なくとも、先進的なユーザ以外にとっては。
  • 複数のページを一度に開いて操作するのに「これさえあれば十分」と言えるアドオンは無いようで、タブの挙動を変えるために途方もない数のアドオンが存在しています。

タブがブラウザの中に登場した時――OperaとFirefoxがその急先鋒だったわけですが――、Web(とコンピュータも)は今とは非常に異なった状態にありました。人々は1つのウィンドウの中だけで6つか7つほどのページを同時に扱えるというだけでも、ことのほか幸せでした。

2009年に時計の針を進めると、多くのユーザが、一度にいくつのページを開けるかという点でブラウザの限界を打破しようとしています。この新たな試みは大量のメモリ容量とCPUパワーを必要とします――しかし、ユーザーインターフェースにおいて、これよりも明らかな課題はありません。大量のタブを扱う方法については、複数行表示(Opera)から現在開かれているタブのプルダウンリスト(FirefoxやSafari)まで、ブラウザごとに色々な方法がとられています。これらのアプローチのいずれも、いまいち上手く機能していません。これが、今Mozillaが複数のページを管理するための別のアプローチを探している理由です。

目次

長大な投稿ですので、あなたが興味がある所から読めるように、節ごとのリンクを用意しました:

壊れていないのなら、直さない

私たちはタブ機能こそが、多くの人々がFirefoxに乗り換えた最大の理由であることを認識しています。私たちが別のアプローチを探しているということを明らかにした時、人々が最初に言うのはだいたいこういう事です。「でも、私はタブが好きだ。タブ機能をなくさないでくれ!」

ですので、はっきりとこう言っておきましょう。私たちは、タブは未だ健在だと思っており、タブをなくそうとは考えていません。タブは現在の物と似た形で残り続けるでしょう。なぜなら、ほとんどの人にとってタブは大変有効に働いているからです。ユーザの大多数はタブについて特に問題意識を持ってはおらず、あなたがタブの限界に挑もうとしない限り、タブは複数のページを扱うための非常に自然且つエレガントな解決策と言えます。

その上で私たちがしたいのは、多数のページを管理するのに現在タブを使っていて不満を感じていたり不幸せになっていたりする人々のための、より良い解決策を見つけ出すことです。タブに関して、この議論のために、ユーザをいくつかの大まかなグループに分類しましょう:

初心者
このグループはタブを全く使っていません。これらの人々は、私の祖母に似ています。技術に精通したおばあちゃんでも、彼女は4つか5つほどのWebサイトしか訪れておらず、タブは全く使っていません。
中級者
このグループの人達は、現状のタブに満足しているユーザです。彼らはたいてい5~10個前後のタブを開いています。
上級者/パワーユーザ
このグループのユーザは多数のタブを開いています。ブラウザの中で100を超えるタブを開いており、ページを全く閉じないで、代わりに新しいタブを開いていく、というタイプの友人を誰もが持っています。あるいはあなたがまさにその人かもしれません。

これらの分類のためにありがちな名前を使っていることについてはご容赦下さい。みんな十人十色で、人によっては「うちのおばあちゃんは……」と言いたくなるかもしれませんが――これらは単に議論を分かりやすくするための分類です。

現存しているアプローチ

当然ながら――先ほどのスクリーンショットが示しているように――タブ周りの状況を改善するための試みについては、様々な努力がすでにあります。Mozilla LabsでもSummer 2009 Design Challengeという企画を主催しており(Reinventing Tabs in the Browser)、1つ前のSpring 2009 Design Challengeでは、可能な限りの最小のユーザーインターフェースでどのようにWebブラウズを行うかを思い描いてもらいました。

最近パワーユーザの間で評価されているFirefox用アドオンの1つが、ツリー型タブアドオンです。

(ツリー型タブのスクリーンショット。タブバーがコンテンツ領域の左横に表示されており、Googleの検索結果から開かれたタブがインデント表示されている)

人気の理由は分かりやすく、このアドオンはパワーユーザの要求によく合っています:

  • このアドオンはタブを、水平表示の代わりにサイドバー風の縦長表示で表示します。その結果、見えるタブの数が最大化されます。
  • ワイドスクリーンのモニタが新製品の主流になってきているために、より多くのユーザが水平方向の画面スペースを利用できるようになってきていますが、このアドオンはその水平方向のスペースを活用します。(例えば、2006年第1四半期のノート機向け出荷台数では、ワイドスクリーンモニタの出荷台数は普通のモニタを超えました。)
  • このアドオンは、そのタブがどこから開かれたかに基づいてタブを自動的にグループ化します。例えばあなたがGoogleの検索結果から別れる形で新しいタブを開いたのなら、そのタブは上のスクリーンショット内の「Apple」タブのように、入れ子の形で表示されます。現在、他のブラウザを使っている人々は、関連するタブをグループ化するために異なるウィンドウや色分けされたタブを使っています――そして、望んだとおりのグループ分けを行うためにウィンドウの間でタブをドラッグ&ドロップしています。この解決策は、それよりもエレガントです。
  • このアドオンは、ホイールスクロールというほとんど労力のいらない操作によって、画面に収まりきらないタブをより簡単に操作できるようにします

もう1つの注目に値するアプローチは、Safariでタブを操作するためのSafariStandアドオンが取っている道です。

(SafariStandのスクリーンショット。コンテンツ領域の左横にサムネイルが縦に並んでいる。) SafariStandが提供する機能の一部は以下のようなものです:

  • ツリー型タブと同じように、このアドオンは画面の中に収まりきらないほどのタブがある時に、ホイールスクロールによって多数のタブを簡単に扱えるようにします。
  • タブは非常に視覚的で、簡単に識別できます。
  • タブはクリックに反応する大きな領域を持っています。
  • 最も重要な事として、SafariStandは、私たちがMozillaにおいて部分的サムネイルと読んでいる機能を含んでいます。

ページのほとんどがテキストである場合には特に、ページ全体のスクリーンショットのサムネイルはページを識別するためにはそれほど便利ではありません。ページの左上の角(ロゴとページのタイトルの一部を含むのに十分な大きさの領域)のスクリーンショットを取ることによって、部分的サムネイルはあなたがページを探すために識別する上で、飛躍的により便利になります。上のスクリーンショットでは、もしあなたが他に3つほどWikipediaのページを開いていたとしても、「User Interface」のWikipediaのページを識別することができます。


先のアプローチが正しいことを検証するために、Opera 10ベータ版の場合を見てみましょう。このブラウザはタブを表示する方法として似たアプローチを取っていますが、しかし他の物に比べて、この実装には色々と問題があります:

(Opera 10のスクリーンショット。コンテンツ領域の上にタブが並んでおり、各タブにはスクリーンショットが表示されている)

  • あなたはここで、ページ全体のサムネイルが何故使いにくいのかを示すいい例を見ることができます。このスクリーンショットでは、サムネイルにおいて、あるWikipediaのページは他の異なるWikipediaのページと見分けることができません。
  • サムネイルを横ではなく上に置くことによって、タブがコンテンツ領域からより多くのスペースを奪っています。Chromeや――最近までの――Safari 4がウィンドウ枠自体をタブを表示するための追加のスペースとして使っている(それによってWebページのためにより多くのスペースを確保している)ように、あなたはすでに、ウィンドウの上の部分を可能な限り細くしたいと望んでいるでしょう。
  • ここでは見えてこない問題が1つあります。もしあなたが多数のタブを追加すると、サムネイルはタブの幅に合わせて縮んでしまい、あなたが探しているタブを見つけ出す上での視覚的な材料としては役に立たなくなってしまいます。
  • この実装があなたに対して、マウスのホイールを使うことで横方向にスクロールできる機能を――あなたが40個のタブを開いた時に、サムネイルが2ピクセルの幅になってしまう代わりに――提供していたとしても、多くの人はそれを試しすらしないでしょう。縦方向のホイールスクロールを横方向のスクロールのために使うでしょうか?

あなたが見たとおり、Operaは既存のいくつかのアドオンが取っているアプローチに似た試みをしていますが、残念ながら、それらのアドオンの便利さの元となっている多くの細かいポイントを見落としています。

念のために言っておきますが、私はOperaの長年の大ファンです。私の近しい友人の一人はつい最近までリードUIデザイナーとしてOperaで働いてすらいました。私はここでOperaのあら探しをしているのではなく、単にこの議論の実によい例示だったから挙げただけなのです。

測定についての覚え書き

私たちが検討したいと思っているいくつかの話題に移る前に、調査と統計の側面から以下のことについて手短に述べておきます:

タブについて考えるためには、タブの利用のされ方のデータが多ければ多いほど助かります。幸いなことに、Mozilla LabsのTest Pilot測定プロジェクトが、実際にどれだけの数の人がFirefoxを使っているのかを計測するためにブラウザに測定ツールを取り付けるという目標において先行しています。

このツールを使って、私たちは有益な数字――どれだけの人々が2~5個/10~20個/50個以上のタブを使っているのかという風な、Test Pilotのユーザの間でのタブの使われ方の分布などのような――を得ることができます。私は、5~10個よりも多くのタブを開いているユーザはそう多くないと確信していますが――しかしもちろん、50個以上のタブを開いている人達が本当にFirefoxに最初の段階で乗り換えてきたパワーユーザであって、私たちは彼らの生産性が高まるようにするべきとも考えています。

あなたは実際に、Jetpack用のアドオンであるTab Grapherを使うことによって、利用時間の経過に応じてあなた自身のタブの利用状況をグラフ表示することができます。あなたがタブの利用頻度の上記の尺度の中のどの位置にいるのかを知りたければ、この拡張機能を使うことは、それを明らかにする面白い方法となるかもしれません。

データは多ければ多いほどよいです。近い将来により多くのデータを収集するために、Firefoxをより良くするためにすべての人が私たちの助けになってくれることを願っています。

提案:Firefoxのためのいくつかの調査のステップ

上記の通り、あらゆる種類のユーザのためにタブの欠点を解消するたった1つのアプローチというものはありません。私たちがするべき事は、あなたが好みのタイプの操作方法を選べるようにして、それらの間をシームレスに移行できるようにすること、そして、以下に詳しく述べるような自然な移行のポイントを提供することです。

また、今はバージョン3.5の出荷を間近に控えている(訳注:元文書が書かれた日付はFirefox 3.5正式版リリースの直前にあたる2009年6月16日)状況なので、これは私たちがこれからFirefox.nextに向けて今後の数ヶ月の間により詳細に描き出していく予定の非常に大きな絵のうちの、小さな一部分に過ぎないということを心に留めておいてください。その時には、この最初の投稿よりもはっきりとした提案が世に出ていることでしょう。

初心者/中級者向け:サムネイルの見直し

既存のタブインターフェースが中級者のユーザに適しているのであれば、何故それにも関わらずインターフェースを変える必要があるのでしょうか? 主な理由は、この中間層のグループに分類される人々は、ユーザとしてどんどん注文が厳しくなってくるからです。彼らはより多くのタブを使い始め、そして彼らのうちの半数以上はすぐに、私たちが数年前にパワーユーザと定義した領域に突入します。

これは、タブのUIを自動的に移行するより良い方法、もしくは、最低でもせめて人々に対して以下のようなインターフェースの間を可能な限りシームレスに移行できるようにするオプションを、私たちは必要としているということです。

初心者中級者の理想的なインターフェースは、以下の特徴を持つことでしょう:

  • ごくわずかなWebサイトとほんの2~3のタブだけを使うユーザのために、良い体験を提供する。
  • 1つのタブだけを使っている状態を卒業して複数のタブを使うようになるのが、現在のそのステップよりももっと容易である。
  • 最近のワイドスクリーンのディスプレイを効率的に利用しつつ、低解像度のディスプレイのためのオプションも有している。
  • そのインターフェースで扱うことのできるタブの数を超えようとした時、次のレベルのUIに切り替える手段を提供する。

今までの所私たちが検討してきた解決策の中では、サイドバーベースの解決策が新しいオプションとその可能性を示しています。

固定されたサイドバーというアプローチが有効でない人もいる――画面上のあまりに多くの領域を占めてしまうために――ということには気をつける必要があります。これに対する1つの解決策となり得るのが、Mozilla Labsでプロジェクトの1つであるJetpackの一部として検討されており、また現在FennecモバイルブラウザのUIとして利用されている、スライドバーというコンセプトです(「サイド(side)」ではなく「スライド(slide)」であることに注意してください)。基本的なコンセプトは通常のサイドバーと同じですが、スライドバーの場合は常時表示されるのではなく、画面の端を使って、パネル自体を内容と一緒に横にずらして見えなくすることができます。これはあなたが低解像度の環境を利用している場合には良い解決策となり得ます。他の似た解決策がOperaのサイドバーに見られ、こちらはクリックされた時に展開されます。いずれにしても、サイドバーを一時的に隠すための方法には様々な可能性があります。

(「展開」モードのサイドバー) これらのワイヤーフレームは様々な機能について検討しています:

  • 開いている複数のページの間を切り替えるための主な方法として、サイドバー内に表示される部分的サムネイルによるSafariStand風のインターフェースを取っかかりとしています。
  • TVの「チャンネル選択」とコンセプト上の類似点があります――初心者はおそらく、彼らの好みのサイトをサイドバーに常時表示させておくだけの使い方をするでしょう。そのページがまだ開かれていない場合はそのページを開き、すでに開かれている場合はタブを切り替える、という物になるでしょう。
  • RSSアイコンやスターなど、いくつかのインジケータやボタンがサムネイルの中に追加され得ます――とはいえ私たちはそれを最小限にとどめるべきでしょう。
  • そこには大きな空のタブがあり、それによって、新しいタブをどうやって開けばよいかに気付きやすくします。
  • また、新しいタブには、タブから直接検索を実行して、タブが有効化される時に検索結果のページに切り替わるというオプションもあります。
  • (「閉」モードのサイドバー) 一旦、開かれているページの数が、部分的サムネイルを表示するのにもはや適切でないという閾値に達した時には、ツリー型タブのファビコン+タイトルというアプローチに遷移します。これにより、次のレベルのタブの管理の仕組みに気付きやすくなります。
  • もちろん、最上部に表示されるモード切り替えのUIによって、明示的にモードを切り替えることもできます。
  • 表示されるタブのリストをページのタイトルや内容によって絞り込むことができる、検索ボックス状の「タブを絞り込む」UIが備わっています。
  • 同様に、あなたの環境が低解像度であるなら、サイドバーの挙動をスライドバーへ任意に変更することができます。画面の横端をポインタでタップすることによって、ページ全体の表示がスライドアウトするでしょう。Fennecがそうしているように、これは小さな画面のデバイス向けの既定の挙動となると考えられます。

おっと、私たちはこのワイヤーフレームの中に戻る/進むボタンやアドレスバーなどを敢えて描きませんでしたが、もちろんそれらは引き続き存在し続けるでしょう。私たちはこれらの部分についていくらか変更を加えるつもりで、それについては今後の記事の中で詳細を語っていく予定なので、問題をややこしくしないためにこのワイヤーフレームからは除外しました。

このことから1つの素晴らしい結論を導き出せます。それは、開いている複数のページ――「タブ」――とブックマークは、シンプルな利用のされ方においては同じ物となり得るということです。Mac OS XのDockはアプリケーションが現在起動しているかどうかを気にせずに利用できますが、それに似ています。この話題も私たちが今後の記事の中でさらに語っていくであろう話題の中の1つですが、議論に集中するために、今はテーブルの上に載せたままにしておきます。

私たちは、私の祖母のような人達のためにほぼ確実に、既存のインターフェースよりもより良い形へと切り詰められており、また、タブの数が8~10個ほどという限界を超えようとした時には次の段階へシームレスに移行することができる、というインターフェースを持っています。

上級者向け:QuicksilverとFirefoxの出会い

私たちがパワーユーザを観察していて気がついたパターンとして、彼らはブラウズ用のインターフェースを可能な限り多く取り除く傾向があります。彼らはしばしば、すべてのツールバーやボタンを隠します――それらはすべて、ページの内容を表示するためにより広い領域を確保し、邪魔な物を最小限にするためです。なぜなら、彼らはほとんどすべてのことをキーボードショートカットを使って行うからです。彼らはブラウザの機能を示す物理的なリマインダ(ツールバーのボタンやタブなど)が全く無くても困らず、ただページの内容を表示するためのスペースを可能な限り広く取ることを望んでいます。

あなたがアプリケーションランチャ(※Mac用のQuicksilverやLaunchBarのようなツール、OS X(のSpotlight)やWindows Vistaの物のようなアプリケーションの起動と検索が一体化したインターフェース、あるいはLinuxにおける様々なアプリケーションランチャ)を使ったことがあれば目にしたことがあるかもしれませんが、もう1つの興味深いパターンとして、パワーユーザは彼らのファイルやアプリケーションがコンピュータ内のどこかにあるということだけを覚えていて、それらが実際にはどこに置かれているかについては気にしないでいても不満を感じない、ということをあなたはおそらく知っているでしょう。

この事は、以下のようなことを示しています:

  • パワーユーザは、UIが「脇に寄っていて」可能な限り最小限であることを好む。
  • パワーユーザは、どのページで何をしていたのかの詳細を彼らの頭の中で記憶しておくことが苦痛でなく、それらを保持しておくためのUIを必要としない。

手元にある情報に基づいて、私たちはパワーユーザ向けあるいはフルスクリーン表示用のインターフェースをこのように想像することができます:

(パワーユーザが使用している環境のイメージ)

  • あなたが新しいURLを入力するためにCtrl-Lまたは⌘-Lキーを押すまで、そこには全くUIがありません。タブもボタンもありません。
  • Ctrl-Lまたは⌘-Lキーを押すと、アドレスバーが出現します(もちろん、Ctrl-スペースまたは⌘-スペース、あるいはそれに似た別のショートカットを指定する方法も存在するべきです)。
  • すでに開かれているページは項目の横にインジケータが表示されており、プルダウンリストからその項目を選択すると、現在のタブにそれを読み込む代わりに、そのタブへジャンプします。
  • そこには選択されたページを新しいタブで開くための簡単な方法もあります。

これによってパワーユーザは、何百というページを一度に開いてブラウズするのに素晴らしいUIを手に入れ、同時に私たちはフルスクリーン表示――TVやプロジェクタなど――でWebブラウズするための良いUIを手に入れます。

開かれているタブの間の切り替えは、このように動作するでしょう:

  1. Ctrl-Lまたは⌘-Lキー(あるいは、自分で定義したショートカット、ウィンドウ上部におけるスライドバーのようなジェスチャなど)を押してアドレスバーを出現させ、
  2. タブの名前をアドレスバーに入力し始め、
  3. あなたが入力した内容に該当する開かれているタブがアドレスバーのプルダウンリストの最初の結果として提示され、
  4. その項目を選択するとそのタブに切り替わる。
  5. または、普段そうしているように、Ctrl-Tまたは⌘-Tによって新しいタブが開かれる。

どのようにしてパワーユーザ向けのモードを有効にすればよいのでしょうか? そこにはモードの切り替えという概念は無く、単にページ上であなたにとって不要な要素の表示をオフにするだけでよいでしょう。もしあなたがアドレスバーの表示をオフにしたら、ワイヤーフレームで描かれているような形で機能するようになるでしょう。

今すぐパワーユーザ向けのUIを試す

だいたいの所を把握するために、これがどのように機能するのか――「UI無しでのブラウズ」――を実際に試してみるには、Firefox 3.5を使って以下のようにして試してみることをお勧めします:

  1. すべてのツールバーを「表示」メニューからオフにする。
  2. ステータスバーを非表示にする。
  3. 新しいURLを入力するためにCtrl-Lまたは⌘-Lを使い、新しいタブを開くためにCtrl-Tまたは⌘-Tを使う。

現在のバージョンのFirefoxにおいて、私たちがパワーユーザとフルスクリーンモード向けに使いやすくするために修正するべきである、現状において欠けている点は以下の通りです:

  • 現状では、あなたはタブバーを隠すことができません。これは可能になっているべきです。
  • フルスクリーンモードはMac OS Xでは動きません。これは修正される必要があります。
  • (訳注:フルスクリーンモードにおいて)新しいURLを入力するためにCtrl-Lまたは⌘-Lを使った時、アドレスバーはURLの入力が終わった後も残り続けます。つまり、もう一度手動でそれをオフにする必要があるということです。これは、元の状態を覚えておいて、それが隠れていた状態であったのなら自動的に再び隠れるようになっているべきです。追記:これはFirefox 3.5で動きますが、Firefox 3.0では動きません――フル機能のスマートロケーションバーの代わりに小さなダイアログを得るにも関わらず。それでも、さしあたって実験の上では(訳注:その小さなダイアログは)十分よく働き、将来のバージョンでは可能であれば、スマートロケーションバーの全機能をあなたに提供するようになるでしょう。
  • アドレスバーはすでに開かれているタブの名前にも反応するべきです。これは大きな問題です。もしこの機能を加えることができればすぐに、あなたはSlashdotを表示したタブがどこにあるのかを気にしなくても良くなり、タブの名前を入力し始めるだけで、Firefoxばブラウザ上であなたが開いている200以上のタブからそれを見つけ出し、それに切り替えるでしょう。

組み合わせ

絶対に明らかなことがあります:あなたは上で述べられている可能性の中であなたのブラウジングスタイルに合う物を任意に選ぶことができます。

  • パワーユーザだが、開いているページの一覧を常に表示させておきたい、という場合には? LOLcat(訳注:lolcat翻訳機などを参照のこと)の200個のタブを一覧表示するための「閉」モードのサイドバーを除いて、他の物を非表示にするといいでしょう。
  • 4つのサイトしか見ないおばあちゃんのようなユーザのために設定をしたい時は? URLバーを隠して4つのサイトをサイドバーに置いておけば、おばあちゃんはそれをテレビのように使えるでしょう。

……などなど。ここに見られるように、これらの改善はあなたのWebブラウズ用ツールに対して強力な新しい機能と能力を加えます。

議論に参加する方法

Mozillaプロジェクトは、あなたの参加を歓迎します。私たちはその向こうに多くの素晴らしいアイデアが生まれてくると確信しています。私はAlex Payneの彼のブログにおける方針と同じ理由で、個人的にこのブログ(訳注:原文が掲載されているAlexander Limiのブログ)のコメント機能を有効にしていませんが、議論に参加するための最良の方法としては以下の物があります:

  • Firefoxのタブがどのように働くべきとあなたが考えているかについての記事を書いて、あなた自身のWebサイトに載せて下さい。あなたが私のサイト(訳注:原文が掲載されているAlexander Limiのサイト)へリンクし、私宛に言及していれば、私はそれを見つけて読むでしょう。いや、本当に。私の前の雇用主はGoogleで、物事を探すことは私たちがしていたことです。
  • Mozilla LabsのSummer 2009 Design Challenge(Reinventing Tabs in the Browser)に参加して下さい。
  • コメントが短いのであれば、あるいは書かれたことに対して単に何かを付け加えたい場合は、dev.apps.firefox Google Groupでそれらを投稿したいと思うかもしれません――Usenetのニュースグループ古典的なメーリングリストの形でも。
  • もしあなたが何らかのモックアップやワイヤーフレーム、あるいはこの議論に関連する図を作成したなら、FlickrやTwitter、あるいはその他のサービスにおいてmozconceptタグを付けてください。私たちはそれを見るでしょう。
  • もしあなたが誰もが見ることのできる場所で意見を公開することを望まないのなら――もしくは単に、Firefox User Experience Teamから私が新しいウェルカムパッケージとして受け取った新しい難燃性スーツを試してみたいなら――limi@mozilla.com宛にメールを送って下さい。

聞いて下さってありがとうございます! 次世代のFirefoxのタブをより良い物とするために皆さんがどんなアイデアを思いつくのか、楽しみにしています。

アドオンのレビューのガイドライン - Jul 10, 2009

レビューガイドライン :: Firefox Add-onsが日本語に訳されてなかったのでがっくり来て、なんとか読み解いてみた。

最後まで読んでみて思ったこと:誰もガイドライン守ってなくね?

レビューのガイドライン

アドオンのレビューは、アドオンサイト(AMO)のユーザがインストールして使っているアドオンについて、意見を共有するための手段です。編集者(エディタ)は、このガイドラインに従っていないレビューを拒否したり削除したりする権限を持っています。

良いレビューを書くためのいくつかのtips

するべき事:

  • そのアドオンであなたがどのような体験をしたかを、友達に語るように書きましょう。
  • 簡潔で分かりやすいレビューを書くよう心がけましょう。
  • 明瞭且つ有用な詳細を書きましょう。例:
    • そのアドオンはあなたが期待したとおりに動きましたか?
    • あなたが好きな、あるいは嫌いな機能は何ですか?
    • 便利でしたか?
    • 簡単に使えましたか?
    • そのアドオンを使い続けたいと思いましたか?
  • 恥ずかしいミスタイプや文法のミスを公にしてしまわないように、レビューを送信する前にきちんと時間を取って読み返しましょう。
  • レビューは長期間にわたってサイト上に掲載され続ける可能性があります。時事的な話題への言及は避けましょう。

してはいけない事:

  • 「すごい!」「素晴らしい!」「使えない」などのような、説明がなされていない短いレビューは投稿しないで下さい。
  • バグや障害のレポートをレビューに含めないで下さい。代わりに、それぞれのアドオンのサポート用連絡先を使って下さい。
  • 個人的に使ってもいないアドオンのレビューを書かないで下さい。
  • 罵倒、性的な言葉、人を不快にさせるような言葉を使わないで下さい。
  • HTML、悪意のあるソフトウェアへのリンク、ソースコードやコード片をレビューに含めないで下さい。レビューには文章だけを書いて下さい。
  • 嘘、アドオンの作者への罵倒、個人への侮辱を書かないで下さい。
  • 特定のFirefoxのバージョンや他のアプリケーションへの対応を要求するための場としてレビューを使用しないで下さい。
  • あなたのメールアドレス、電話番号、あるいはその他の個人情報を書かないで下さい。
  • あなた自身やあなたが所属する組織が提供しているアドオンにレビューを書かないで下さい。

アドオンの評価のガイドライン

アドオンの評価は、公正で且つ、総合的な品質と便利さを示すための指標を示す物であるべきです。そのアドオンが単に好きだから5つ星を付けたり、単に嫌いだから星を1つだけ付けたり、といった評価をしないで下さい。あらゆるレビューにおいて、一貫した評価付けは重要な点です。

  • 5つ星:非常に素晴らしい場合。説明されている特徴がすべて動くだけにとどまらず、他の多くのアドオンに比べて際立って便利である。このアドオンは自分にとって常用に足るもので、他の人にも強くお勧めできる。
  • 4つ星:良くできている場合。特別に凄いわけではないけれども。便利で、簡単に使うことができる。このアドオンはお勧めできるが、人によってはよりお勧めなアドオンがあるかもしれない。
  • 3つ星:可もなく不可も無しという場合。不足している機能があったり、設計に問題があったりするかもしれない。既知の問題はそのアドオンを使わないことを強く勧めるほどの重大なものではなく、それでもなお便利に使えるという人もいるかもしれない。その機能を必要としていて、試してみることを厭わない人には、お勧めできる。
  • 2つ星:あまりできが良くない場合。そのアドオンは完成度が低いか、使いにくいか、または、説明でうたわれていることを実際にはできない。それでも、ごく少数の人達にとってはそれでも使う価値がある場合には、お勧めすることができる。
  • 1つ星:駄目な場合。そのアドオンは正常に動作しないか、全く役に立たない。使ってみる価値があるような重要な理由は無いと考えており、完全に避けることをお勧めする。

完全な、あるいは非常に詳細なレビューを書くことがどうしてもできないのでなければ、何故その評価を下したのかを示して下さい。何も説明が付いていないと、評価の星は何の意味も持ちません。

レビューについてのよくある質問

問題のあるレビューはどうやって報告すればよいですか?
疑わしいレビューについては、「このレビューを報告」をクリックして、フラグを立てて報告して下さい。報告の内容は編集のためにサイトに送られます。エディタはそのレビューを削除するか、それとも元に(サイト上に表示される状態へ)戻すかを判断するために、このレビューガイドラインを用いるでしょう。
私はアドオンの作者ですが、レビューに返信してもよいですか?
はい。アドオンの作者は1つのレビューにつき1つの返信を書くことができます。それ以上の議論やフォローアップは、サポートフォーラムや議論のためのグループに移動するべきです。
私はアドオンの作者ですが、好ましくないレビューや評価を削除してもよいですか?
一般的には、駄目です。しかし、上述したガイドラインに則っていないレビューに遭遇した場合は、「このレビューを報告」をクリックして、エディタに報告することはできます。もしそのレビューが、あなたのアドオンの新しいバージョンですでに解消された問題についての苦情を含んでいる場合、私たちはそのレビューを削除するかもしれません。詳細な説明込みでの削除要求は amo-editors@mozilla.org へ送って下さい。

なぜOperaはオープンソースでないのか - Feb 29, 2008

OperaのTetzchner CEOへのインタビュー記事(英語)について、冒頭の Opera をオープンソースにしない理由などだけでも目を通すと良いかもとあったので、頑張って読んでみたよ。誤読してたらすんません。

(質問)Operaをオープンソースでリリースするのに何が必要ですか? 私はあなたが過去すでに、オープンソース化はあなたに何の利益ももたらさないと述べたことを知っていますが、その考えに変化があったかどうかに関係なく、私はただ確認をしたいのです。私は、オープンソース化がLinuxとBSDでのすべてのユーザを幸せにするだろうと確信しています。

(回答)本当の質問は、なぜそう考えるのか、そして、それは本当に重要なのかということです。私たちの世界観では、オープンスタンダードこそが重要な物と考えます。オープンスタンダードとオープンソースとを選べるのなら、私達は必ずオープンスタンダードの方を選びます。幸いにも、多くの場合オープンソースの企業は実際にはオープンスタンダードによってうまくいっていますので、それ自体は問題ではありませんが、しかし、私達が重要だと信じているのはあくまでオープンスタンダードです。なぜなら、その時あなたは選択肢を持てるからです。あなた自身の考える優先順位に基づいて、使う製品を切り替えることができるという事ですね。

そして、オープンなコミュニティの問題があります。私達はとてもオープンなコミュニティを持っていて、非常に多くの人達と働いています。私達が企業として歩む道は色々な意味で、オープンソースの企業のそれに似ていると、私は考えています。今現在、コミュニティの人達は私達の製品のソースコードにアクセスする事ができませんが、しかし、彼らは私達とコミュニケーションを取り、フィードバックをしてくれて、私達の製品を試してくれています。私達はとてもオープンな仕事のやり方を、コミュニティの人達としているのです。そこでの疑問は、なぜ私達がその上でさらにオープンソースの活動をやらないといけないのか、それが私達にどんな利益をもたらすのか、という事です。

ちなみに、私は自分自身でオープンソースの活動をしたことがあり、Telenor Researchであるプロジェクトを作りました。私はFrameMakerのコンテンツを読み込んでHTMLに完全に変換するプログラムを作りました。そして、私はそれをオープンソースでやりました。また、それは実に見事に動作しました。しかし、同時に、私がそのプロジェクトの仕事をやめた(関わらなくなった)途端、プロジェクトは死んでしまいました。みんながそれを使っていたのにも関わらずです。それはFrameMakerの文書をHTMLに変換するための、最もポピュラーな方法でした。それは非常に強力なツールで、FrameMakerブックの全体を、章や複数の文書を、画像、文書間のリンク、索引も含めて、何もかもを完全にHTMLに変換することができました。しかし、私がそのプロジェクトに関わらなくなった途端に、状況は変わってしまいました。

私の考えでは、もし私達がOperaをオープンソース化していたら、ある種の人たちは私達のソースコードを見ることができて、私達をもしかしたら助けることができたかもしれませんが、依然として大部分の作業は私達自身がやることになっていただろうと思います。これは実際の所、他の有名なオープンソースプロジェクトと全く同じです。もしあなたがオープンソースプロジェクトの一つに参加しようとしても、実際にはそれはそんなに簡単な話ではありません。なぜなら、そこにはプロジェクトの主導権を握っている門番のような誰かがいるからです。ですから私は、オープンソース化していたらそれによって多くの物を得られただろうという考えには確信を持てませんし、人々が私達のコードを見るだけ見ておいしい所だけ持っていってしまう危険性もあっただろうと思っています。

まあOperaはプロダクトや技術それ自体を売ることでお金を得るビジネスモデルだから、Operaがそういう営利企業である以上は、オープンソース化しても大して嬉しい結果にはならないだろうなあ。Mozilla Corporationなんて、非営利団体が唯一の株主で、営利目的では活動しませんって明言しちゃってるし。あそこの目的は金を稼ぐことではなく社会貢献することの方が優先順位が高いと見て間違いは無かろう。そんな所とOperaを一緒くたにして語られても、テッちゃん困っちゃうよね(←なぜ馴れ馴れしい)

Firefoxで独自プロトコルを定義する方法 - Mar 26, 2007

独自のプロトコルというか独自のスキーマを使えるようにしたくてやり方を調べてみたら、あちこちでAdding a New Protocol to Mozillaという文書が紹介されてたんだけど、日本語訳が無かったのでとりあえず気合いと勘で訳してみた。誤訳があったらゴメンナサイ。

続きを表示する ...

Firefoxで独自プロトコルを定義する方法 - Jan 01, 1970

独自のプロトコルというか独自のスキーマを使えるようにしたくてやり方を調べてみたら、あちこちでAdding a New Protocol to Mozillaという文書が紹介されてたんだけど、日本語訳が無かったのでとりあえず気合いと勘で訳してみた。誤訳があったらゴメンナサイ。

続きを表示する ...

Firefoxで独自プロトコルを定義する方法 - Jan 01, 1970

独自のプロトコルというか独自のスキーマを使えるようにしたくてやり方を調べてみたら、あちこちでAdding a New Protocol to Mozillaという文書が紹介されてたんだけど、日本語訳が無かったのでとりあえず気合いと勘で訳してみた。誤訳があったらゴメンナサイ。

続きを表示する ...

Page 1/239: 1 2 3 4 5 6 7 8 9 »

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のつぶやき

オススメ

Mozilla Firefox ブラウザ無料ダウンロード