株式会社クリアコード > ククログ

ククログ


ノータブルフィードバック8 - 要望が通らなかったときの振る舞い方

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の8つ目は、「こういうことはしないようにしましょう」という反面教師として、要望が通らない場面での望ましくない振る舞いが見られる実際のフィードバック事例をご紹介します。

(以下の引用部は、元々はすべて英語でなされたやり取りですが、原文と訳文を両方掲載すると長くなりますし、ここでは英語の表現自体を参考にするわけではないので、筆者による抄訳のみ掲載します。)

Firefoxのタブバーの位置の議論

最初に、経緯を簡単に説明しておきましょう。

Firefoxのタブバーは、当初は「戻る」「進む」などのボタンがあるツールバーの下に置かれていましたが、Google Chromeに合わせるようにFirefox 4でウィンドウの最上部へと変更され、その後元の位置に戻す設定も削除されたという歴史があります。

(Firefox 3.5では下にあったタブが、現在はウィンドウ最上部にある)

タブバーの位置がウィンドウ最上部で固定されるようになった直後から、「元の位置に戻せるようにして欲しい」という要望が寄せられ始めましたが、その当時はいくつかのアドオンを使ってタブバーの表示位置を変更できたことから、要望は却下されていました。しかし、その後のFirefoxの仕様変更により状況が変わったため、再びこの要望がクローズアップされた……というのがここで採り上げる報告の背景事情です

■タイトル

タブを(ツールバーの)下に置くモードの追加

■説明(要約)

この報告はBug #755593の複製として作られました。
その報告の最後のコメントでは、動作を元に戻すアドオンがあるので、この事はもはや問題ではないということになっていました。

最近のバージョンのFirefoxではアドオンでは実現できず、about:config(訳註:詳細設定の画面)でuserChrome.css(訳註:FirefoxのGUIを高度にカスタマイズする、上級者向けの設定ファイル)を有効化し特定のコードをそこに書くという手間が必要となっており、これは大多数の人にとって直感的ではない、と私は思います。

なお悪い事に、Mozillaはタブバーの移動のために必要なコードを変更させ続けており、平均的なユーザーまでもが手作業でそれに追従することを強いられています。

また、大多数の人が最上部にタブバーを置いたまま使っているのは、既定の設計がそう変わった後にただそれを受容したからであって、彼らが望んでそうしたわけではありません。

これに対し、とある開発者は以下の通りコメントし、この報告に「RESOLVED(解決済み)」「WONTFIX(対応しない決定をした)」という印を付けました。

私達はこれをやらないことにしました。
というのも、これを望む人の数が非常に少なく(あなたが述べている通り、ほとんどの人はタブバーの位置がどちらでも気にしていないようです)、「タブバーを下にする」モードを実装し維持するコストが不釣り合いな程に大きいからです。

ここで、開発者から判断の根拠が2つ示されていることに注目してください。このことから、「この機能は実装しない」という決定を覆すために必要なのは以下のことであると言えます。

  • 要望を寄せる人が多いという事実を示す。
  • 対応するコストは実際には小さいという事実を示す。

これに対して実際にどのようなコメントが行われたかを見てみましょう。

適切でない振る舞いの実例

開発者のコメントを受け、報告者以外の人達からは批判的なコメントが寄せられました。その中から2件を抜粋してみます。1件目はこちら:

私はこれが理由でFirefoxの使用をやめました。
あなた達がGoogle Chromeをコピーしたいなら、私はGoogle Chromeに移ります。
私はこの機能だけが理由でFirefoxを使っていました。
「みんな地獄に落ちろ」とあなた達が言っているということが私には信じられません。
地獄に落ちろとは言ってないと証明したいなら、この問題を修正して証明してください。

もう1件はこちら:

「この事を問題視している人は非常に少ない」と言うのは無意味です。
大多数のユーザーは「バグを報告する」ということ自体を知りません。
彼らはたとえ、困っていて深刻な影響を受けていても、それに甘んじて生活する事を学んだか、他のブラウザーに移ることを選びました。
このようなユーザー層からの声をあなた達はほとんど聞いていません。

そういう人の中で、実際に時間をかけてフィードバックする人はほとんどいません。
実際に報告している人は、その問題が彼らにとって本当に重要で、深刻な影響があるからこそしています。
そして、「WONTFIX(修正しない)」という解決を突きつけられ顔をドアにぶつける羽目になった人達がそこにいます。
彼らに大きな影響を与えた問題はまだ残ったままです。
繰り返しますが、それを受容して生きるか、ブラウザーを乗り換えるしかありません。
その中には、この問題について筆を執る時間をもう取らないと決めた人達もいます。
理由を考えてみてください。

この両者に共通しているのは。決定を覆すために必要なことを実施するというアクションは起こさず、悪く言えば、自分の主張が100%通るまでゴネることしかしていない、という点です。

悪い例の1つめは、以下のように分析できます。

  • 開発者の感情を逆撫でする、捨て台詞じみたことを言っている。
  • 私に見捨てられたくなければ私の要求に応じろ、という恫喝的な言い方をしている。
  • 「○○していないことを証明せよ」という不可能な要求をしている(悪魔の証明)。その「証明」の方法として、自分の要望を実現することを唯一受け入れ可能な答えとして示しており、それ以外の解決策は拒否する姿勢を取っている。

悪い例の2つ目は、以下のように分析できます。

  • 自分がいかに困っているかを説明することに終始して、開発者の翻意を迫る以外の事をしていない。
  • 開発者が聞く耳を持っていないと決めつけている(実際には、聞いた上での議論の末に決定が下っている)。
  • 原文では「they do it BECAUSE the problem IS important ...」のように一部のフレーズを大文字にして強調している(英語の文章では、このような表現は 「声を荒げる」 ということに相当する)。

これらの例は、OSSプロジェクトの行動規範(Code of Conduct)において 「容認されない行動の例」として挙げられることの多い「荒らし・煽り、侮辱的・軽蔑的なコメント」に該当する と筆者には思えます。

開発者は、寄せられる要望のすべてには応えられません。矛盾する要望同士には応えられませんし、プロジェクトとして「これはやらない」と敢えて決定する(スコープを明確にする)こともあります。仮にスコープ内だとしても、人的・金銭的リソースが足りないため実現できないということもあります。

判断を覆すための材料を提示する責任は、基本的に、判断に異を唱える側の方で負うことになります。それは、判断の元になった前提を崩す新しいデータを示すことかもしれませんし、あるいは、リソース不足が原因なのであれば、それを補うリソースを提案者が提供する(寄附、コードでのコントリビュートなど)ことかもしれません。

そう考えると、悪い例に共通しているのは、そのような責任を回避して、すべてをプロジェクト運営者側に押しつける姿勢だと言えるでしょう。

要望が通らなくても、建設的な議論はできる

一方、報告者自身も一旦は感情的になった様子ではありながら、こちらはもう少し建設的なコメントをしていました。

(訳註:開発者からの「他のブラウザーではそもそもCSSでそのようなカスタマイズをすることすら不可能なので、今でも恵まれた状況だということを分かって欲しい」というコメントを受けて)
確かにありがたいことですが、この方法はいつまで利用可能と思えばいいでしょうか?
Firefox側で絶えず行われる変更に対し、この回避策を使いたい人はその都度追従しなくてはならず、このような事実は間違いなく、Firefox開発者たちがこの回避策自体をぶっ壊してしまおうとしているような印象を与えます。
実際に彼ら開発者は、WebExtensionsへの移行によって多くのUIカスタマイズ性を失わせ、私がFirefoxを好きだった理由の多くを吹き飛ばしてしまいました。

これに端を発して、2人の開発者から以下のような状況説明のコメントがなされました。

開発者たちはFirefoxのUIをHTMLで書き直すことに忙しいだけです。
CSSでのカスタマイズ性自体はどこにも行っていません。(中略)userChrome.cssの機能は非常に単純です。
機能のメンテナンスに要するMozilla側のコストは非常に小さいと言えるので、機能が消えることはまずないでしょう。

いえ、CSSでのカスタマイズ性がどこにも行っていないというのは真実ではありません。
Firefox 69ではuserChrome.cssは設定で有効化しないと使えなくなっています。
(中略)
userChrome.cssはユーザーが自己責任で使う機能なのに、色々な問題の報告がなされる原因となっているため、ベンダーにとってブランド価値に対する脅威となっています。
(中略)
ともかく、私はここがuserChrome.css自体の将来についての議論に相応しい場とは思いません。
本題と関係ない話をしてしまったことを、長大なCcのリストに含まれている人々にお詫びします。
(訳註:Bugzillaでは興味がある報告に自分のメールアドレスを登録し、コメントが付くごとにそれをメールのカーボンコピーのように受け取れるようになっている)

ここでの報告者のコメントで注目したいのは、「回避策が将来的に使えなくなってしまうことを心配している」という、今まで言語化されていなかった新たな懸念点を説明している、という点です。

報告者の側は「相手は開発者で専門家なんだから、このくらい当然知ってるだろう、察してくれるだろう」という期待を持ちがちでしょう。しかし、OSSでは(実際にはOSSに限りませんが)開発者といえどもすべてのことを把握しているとは限りません。この事例でも、1人目の開発者は「代替の手段もなくなりそうになっている」という事実を正確には把握していなかったようです。

問題の種類によっては、開発者より外部の人の方が詳しいということはざらにあります。開発者は「ソフトウェアを開発する技術の専門家」ですが、「その問題について研究する専門家」とは限らないのです。判断材料になりそうなのにまだ議論のテーブルに載せられていない情報を持っているのなら、報告者の側から積極的に情報をテーブルに載せていくことが大事です。

また、もう一つこの報告者のコメントで注目したいのは、主観と客観を区別しているという点です。

前出の良くないコメントの例はどちらも、「開発者たちはこう考えている」という、文の主語が発言者自身ではなく開発者となる書き方をしています。本人の考えを勝手に代弁するのは、端的に言えば「相手の考えを決めつける」ことです。このような言われ方をすると、言われた側は「いやそんなことは言っていない」と反論したくなるものです。

それに対し、報告者のコメントでは「~な印象を与えます*1」という書き方をしています。これは、受け取り手の側(自分)はこう感じたという、間接的にではあるものの自分が主語となる言い方です。このような書き方であれば、言われた側も「そうか、あなたはそう思ったのか」と、抵抗なく発言内容に耳を傾けることができます(ここで「いや、あなたがそう感じるのは勘違いだ」などと反論しだせば、それこそ、その方が決めつけになってしまいます)。

このイシュー自体は、「議論が過熱して罵倒合戦になる」恐れがあるということで、それ以上コメントできないように開発者によって制限が設定されました*2。しかし、userChrome.cssという機能が廃止されたとするとこのようなニーズに影響が出る、という情報が示されたことによって、プロジェクトにとっては機能の存続の判断材料が増えたと言えるのではないでしょうか。

まとめ

ノータブルフィードバックの8回目として、Firefoxに行われた実際のフィードバックの中で見られた「要望が通らなかったときにするべきでない、望ましくない振る舞い」の例をご紹介しました。

このような失敗事例の紹介も交えながら、「身近なところで遭遇したつまずきをOSS開発プロジェクトにフィードバックする」ということをテーマに、まだOSSにフィードバックをしたことがない人の背中を押す解説書 「これでできる! はじめてのOSSフィードバックガイド ~ #駆け出しエンジニアと繋がりたい と言ってた私が野生のつよいエンジニアとつながるのに必要だったこと~」を、同人誌としてリリースしました。本記事の内容はこの本からの抜粋となっています。4月5日までオンライン開催されている「技術書典 応援祭」内のマーケットにて紙版+電子書籍(または電子書籍のみ)を購入頂けますので、ゆっくりオフラインで読みたい方はぜひチェックしてみて下さい。

*1 原文では「it definitely gives the impression that~」となっています。

*2 原子力発電所の設置の可否のような難しい問題の議論にはあまり人が参加せず、自転車置き場を設置するかどうかのような身近で些細な問題の議論にはなぜか人が集まってきて加熱するという、いわゆる「自転車置き場の議論」を避けるために、OSSのイシュートラッカーではこのような措置が執られることがあります。

2020-04-02

Groongaの単語抽出演算子を使ったタグの付与

Groongaにはタグ検索という機能があります。

例えば、動画共有サイトであれば、登録されている動画に、その動画の特徴を表す短いキーワード(「スポーツ」、「カバディ」など)が含まれています。
これらの短いキーワードをタグといいます。
このタグで検索することで、動画のタイトルだけではなく、動画の特徴による検索ができ、より良い検索結果を提供できます。

上記の動画の例で言えば、動画のタイトルによる検索では自分が検索時に見たいと思った動画しか検索できませんが、タグ検索をすると、
検索時には意識していなかった興味のある動画を見つけることができます。

Groongaの公式ドキュメントの例は小規模なためデータにタグを人力で付与してデータを登録することができますが、実際に使用するケースではデータはもっと巨大です。
巨大なデータに人力でタグを付与するのは、とても困難な作業です。

データ登録時にユーザーにタグを指定してもらうインターフェースにするというのも解決策の一つです。
しかし、既にあるデータに対してタグ検索をしたいという要件が後から追加された場合は、上記の案では解決できません。
既に登録されたデータにタグとなるキーワードが含まれているかどうかを確認し、含まれているキーワードをタグとして登録する必要があります。
このような作業は人力ではなくコンピュータに任せたいところです。

Groongaでは、単語抽出演算子という演算子があり、これを使うことであらかじめ登録しておいた単語を抽出できます。
あらかじめタグとして使用するキーワードを登録しておき、タグを付与する対象のデータにこれらのキーワードが含まれていれば、そのキーワードを抽出できます。
したがって、この単語抽出演算子を使って抽出したキーワードをそのレコードのタグとして登録することで、検索用のタグを付与できます。

具体的には以下のように使用します。

まず、以下のようにタグとして抽出したいキーワードを_keyとして登録したテーブルを用意します。
抽出したいキーワードはテーブルのキーとして登録される必要があります。
また、抽出したいキーワードを登録するテーブルは、TABLE_PAT_KEYTABLE_DAT_KEYである必要があります。

以下の例では、Groonga, Mroonga, PGroonga, RroongaRuby, PostgreSQL, MySQL, Fulltextをタグとして使用するキーワードとして登録します。

table_create Words TABLE_PAT_KEY ShortText --normalizer NormalizerNFKC121
load --table Words
[
  {"_key": "Groonga"},
  {"_key": "Mroonga"},
  {"_key": "PGroonga"},
  {"_key": "Rroonga"},
  {"_key": "Ruby"},
  {"_key": "PostgreSQL"},
  {"_key": "MySQL"},
  {"_key": "Fulltext"}
]

単語抽出演算子の構文は_key *T "document"です。
documentの部分には、抽出対象のデータそのものをいれます。例えば、"Groonga is the successor project to Senna."という文書から上記で登録したキーワードを抽出したい場合は以下のようなクエリーを実行します。

select \
  --table Words \
  --filter '_key *T "Groonga is the successor project to Senna."' \
  --output_columns _key
[
  [
    0,
    1587435831.615494,
    0.003186702728271484
  ],
  [
    [
      [
        1
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "groonga"
      ]
    ]
  ]
]

この文書には、タグとして抽出したいキーワードのGroongaが含まれているので、上記のクエリーでGroongaが抽出されています。
抽出結果が"groonga"と小文字になっているのは、Wordsテーブルに指定しているNormalizerNFKC121がキーワードを正規化しているためです。
キーワードを正規化するのは、大文字/小文字の区別なくヒットさせるためです。
この抽出されたキーワードをタグとして登録します。

それではまず、説明のためタグを付与する前のデータを登録します。

table_create --name FullTextSearchEngines --flags TABLE_HASH_KEY --key_type UInt32
column_create --table FullTextSearchEngines --name name --flags COLUMN_SCALAR --type ShortText
column_create --table FullTextSearchEngines --name description --flags COLUMN_SCALAR --type ShortText

load --table FullTextSearchEngines
[
  {
    "_key":1,
    "name":"Groonga",
    "description":"Groonga is a fast and accurate full text search engine based on inverted index. One of the characteristics of Groonga is that a newly registered document instantly appears in search results. Also, Groonga allows updates without read locks. These characteristics result in superior performance on real-time applications."
  },
  {
    "_key":2,
    "name":"Mroonga",
    "description":"Mroonga is a storage engine for MySQL. It provides fast fulltext search feature for all languages including Chinese, Japanese and Korean to all MySQL users. Mroonga was called Groonga storage engine"
  },
  {
    "_key":3,
    "name":"PGroonga",
    "description":"PGroonga is a PostgreSQL extension to use Groonga as the index.PostgreSQL supports full text search against languages that use only alphabet and digit. It means that PostgreSQL does not support full text search against Japanese, Chinese and so on. You can use super fast full text search feature against all languages by installing PGroonga into your PostgreSQL!"
  },
  {
    "_key":4,
    "name":"Rroonga",
    "description":"Rroonga provides Groonga's DB-API layer features to Ruby. Features specialized to Web applications built on Rroonga are provided by ActiveGroonga. Convenience features for search Web applications are provided by racknga. All of them have the same merit that you can use Groonga features via Rubyish useful API. "
  },
  {
    "_key":5,
    "name":"Droonga",
    "description":"Droonga is a distributed full-text search engine, based on a stream oriented processing model. In many operations (searching, updating, grouping, and so on), Droonga processes various data by pipeline. As the result, Droonga has large potential around its flexibility and extensibility. Moreover, those features provide high availability for people who develop any data processing engine based on Droonga. You can process complex operations by mixing operations, and you can add custom operations to Droonga via plugins written as Ruby-scripts."
  }
]

上記の通り、全文検索エンジンの説明をデータとして登録しました。
nameが全文検索エンジンの名前、descriptionが全文検索エンジンの説明を表しています。
今回はこのdescriptionからキーワードを抽出して、タグとして書くレコードに付与します。

次は、単語抽出演算子を使ってタグとして使用するキーワードを抽出します。

select \
  --table Words \
  --filter '_key *T "Groonga is a fast and accurate full text search engine based on inverted index. One of the characteristics of Groonga is that a newly registered document instantly appears in search results. Also, Groonga allows updates without read locks. These characteristics result in superior performance on real-time applications."' \
  --output_columns _key
[
  [
    0,
    1587436031.572823,
    0.001593351364135742
  ],
  [
    [
      [
        1
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "groonga"
      ]
    ]
  ]
]

select \
  --table Words \
  --filter '_key *T "Mroonga is a storage engine for MySQL. It provides fast fulltext search feature for all languages including Chinese, Japanese and Korean to all MySQL users. Mroonga was called Groonga storage engine"' \
  --output_columns _key
[
  [
    0,
    1587436162.267088,
    0.0009558200836181641
  ],
  [
    [
      [
        4
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "mroonga"
      ],
      [
        "mysql"
      ],
      [
        "fulltext"
      ],
      [
        "groonga"
      ]
    ]
  ]
]

select \
  --table Words \
  --filter '_key *T "PGroonga is a PostgreSQL extension to use Groonga as the index.PostgreSQL supports full text search against languages that use only alphabet and digit. It means that PostgreSQL does not support full text search against Japanese, Chinese and so on. You can use super fast full text search feature against all languages by installing PGroonga into your PostgreSQL!"' \
  --output_columns _key
[
  [
    0,
    1587436237.72361,
    0.001041412353515625
  ],
  [
    [
      [
        3
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "pgroonga"
      ],
      [
        "groonga"
      ],
      [
        "postgresql"
      ]
    ]
  ]
]

select \
  --table Words \
  --filter '_key *T "Rroonga provides Groonga\'s DB-API layer features to Ruby. Features specialized to Web applications built on Rroonga are provided by ActiveGroonga. Convenience features for search Web applications are provided by racknga. All of them have the same merit that you can use Groonga features via Rubyish useful API. "' \
  --output_columns _key
[
  [
    0,
    1587436322.47859,
    0.0007700920104980469
  ],
  [
    [
      [
        3
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "rroonga"
      ],
      [
        "groonga"
      ],
      [
        "ruby"
      ]
    ]
  ]
]

select \
  --table Words \
  --filter '_key *T "Droonga is a distributed full-text search engine, based on a stream oriented processing model. In many operations (searching, updating, grouping, and so on), Droonga processes various data by pipeline. As the result, Droonga has large potential around its flexibility and extensibility. Moreover, those features provide high availability for people who develop any data processing engine based on Droonga. You can process complex operations by mixing operations, and you can add custom operations to Droonga via plugins written as Ruby-scripts."' \
  --output_columns _key
[
  [
    0,
    1587436396.106364,
    0.0008873939514160156
  ],
  [
    [
      [
        1
      ],
      [
        [
          "_key",
          "ShortText"
        ]
      ],
      [
        "ruby"
      ]
    ]
  ]
]

これで各レコードが持つキーワードが抽出できました。
次は、抽出したキーワードをタグとして登録します。

以下では、既に作成したFullTextSearchEnginesテーブルにtagsカラムを追加しています。
tagsカラムはTagsテーブルへの参照になっており、Tagsテーブルは、tagsカラムに登録した文字列をキーとするレコードが作られます。
また、Tagsテーブルはtagsカラムに対するインデックスをindex_tagsカラムに格納してます。これにより、タグの全文検索を高速に実行できます。

table_create --name Tags --flags TABLE_HASH_KEY --key_type ShortText --normalizer NormalizerNFKC121
column_create --table FullTextSearchEngines --name tags --flags COLUMN_VECTOR --type Tags
column_create --table Tags --name index_tags --flags COLUMN_INDEX --type FullTextSearchEngines --source tags

load --table FullTextSearchEngines
[
  {
   "_key":1,
   "name":"Groonga",
   "description":"Groonga is a fast and accurate full text search engine based on inverted index. One of the characteristics of Groonga is that a newly registered document instantly appears in search results. Also, Groonga allows updates without read locks. These characteristics result in superior performance on real-time applications.",
   "tags":,["groonga"]
  },
  {
    "_key":2,
    "name":"Mroonga","description":"Mroonga is a storage engine for MySQL. It provides fast fulltext search feature for all languages including Chinese, Japanese and Korean to all MySQL users. Mroonga was called Groonga storage engine",
    "tags":["mroonga" ,"mysql" ,"fulltext", "groonga"]
  },
  {
    "_key":3,
    "name":"PGroonga",
    "description":"PGroonga is a PostgreSQL extension to use Groonga as the index.PostgreSQL supports full text search against languages that use only alphabet and digit. It means that PostgreSQL does not support full text search against Japanese, Chinese and so on. You can use super fast full text search feature against all languages by installing PGroonga into your PostgreSQL!",
    "tags":["pgroonga", "groonga", "postgresql"]
  },
  {
    "_key":4,
    "name":"Rroonga",
    "description":"Rroonga provides Groonga's DB-API layer features to Ruby. Features specialized to Web applications built on Rroonga are provided by ActiveGroonga. Convenience features for search Web applications are provided by racknga. All of them have the same merit that you can use Groonga features via Rubyish useful API."
    "tags":["rroonga","groonga", "ruby"]
  },
  {
    "_key":5,
    "name":"Droonga","description":"Droonga is a distributed full-text search engine, based on a stream oriented processing model. In many operations (searching, updating, grouping, and so on), Droonga processes various data by pipeline. As the result, Droonga has large potential around its flexibility and extensibility. Moreover, those features provide high availability for people who develop any data processing engine based on Droonga. You can process complex operations by mixing operations, and you can add custom operations to Droonga via plugins written as Ruby-scripts."
    "tags":["ruby"]
  }
]

これで、既存のデータにタグを付与し、タグ検索をする準備が整いました。
後は、以下のクエリーを実行すればタグによる検索が実行できます。

select --table FullTextSearchEngines --query tags:@Groonga --output_columns _key,name

上記では、Groongaというタグを持つレコードを検索しており、結果は以下のようになります。

[
  [
    0,
    1587436478.485265,
    0.002483844757080078
  ],
  [
    [
      [
        4
      ],
      [
        [
          "_key",
          "UInt32"
        ],
        [
          "name",
          "ShortText"
        ]
      ],
      [
        1,
        "Groonga"
      ],
      [
        2,
        "Mroonga"
      ],
      [
        3,
        "PGroonga"
      ],
      [
        4,
        "Rroonga"
      ]
    ]
  ]
]

無事にGroongaをタグに持つレコードが検索できました。

今回は、Groongaの単語抽出演算子を使って既存のデータにタグを付与してタグ検索をする方法を紹介しました。
既にあるデータにタグ検索機能を追加する場合には、この単語抽出機能の使用を検討してみてはいかがでしょうか。

タグ: Groonga
2020-04-21

Gecko Embedded 68ESR対応

はじめに

クリアコードでは Gecko(Firefox)を組み込み機器向けに移植する取り組みを行っています。
ククログ記事を長らく書いていませんでしたが、68ESRに移植する取り組みを行っていましたので、紹介します。

この対応にあたっては OSSystems/meta-browser というYoctoレイヤをフォークして作業を行っていますが、対応が落ちついたバージョンについてはアップストリーム(OSSystems/meta-browser)に成果をフィードバックしています。68ESR対応では、Firefoxをビルドするためのコンパイラがgccからclangに変更となったため、meta-clangというclangを提供するレイヤーを新たに使う必要がありました。
また、68ESRではAArch64のJITの対応が進み、JavaScriptの実行速度が大幅に高速化しました。

meta-clangへの依存

60ESRから68ESRに更新するのにあたって、Firefoxをビルドするためのコンパイラがgccからclangに変更となりました。
clangをビルドのツールチェインとして使用するYoctoのレシピが公開されていたため、これを使うことになりました。
clangはLLVMをベースのインフラとして使用するコンパイラです。LLVMはモジュール化が進められており、再利用が可能なコンポーネントを目指して開発が進められています。

また、C++のランタイムについては、gcc由来のものを使うビルド設定でもビルドを確認しています。

RenesasのRZ/G2Eのリファレンスボード(ek874)では、以下の設定をlocal.confに入れることでgcc由来のC++のランタイムライブラリ(libstdc++)をリンクすることになります。*1

TARGET_CXXFLAGS_remove_toolchain-clang = " --stdlib=libc++"
TUNE_CCARGS_remove_toolchain-clang = " --rtlib=compiler-rt --unwindlib=libunwind --stdlib=libc++"
TUNE_FEATURES_remove_toolchain-clang = "cortexa57-cortexa53"

これらの設定を入れない場合はclang由来のC++ランタイムライブラリ(libc++)がリンクされることになります。

68ESRへのバージョンアップ

Geckoのベースバージョンを60ESRから68ESRに上げるにあたって、障害となるのはmeta-clangへの依存の組み込みでした。
この問題に関してはmeta-clangを使うことによりクリアできました。

また、組み込みGeckoではWayland/EGLの問題に度々直面してきました。
これらの問題に対処するためクリアコードでは、問題を見つけたら開発元で直す開発プロセスを実行しており、
Gecko 60ESR時点で見つかった問題に対応するパッチを開発元に報告できるものは最大限報告をしました。
このため、60ESRから68ESRにGeckoのベースバージョンを上げる時に組み込みGeckoで当てているパッチの量を減らすことができました。

当プロジェクトが作成した以下のパッチは68ESR時点では取り込まれています。

組み込みGeckoが使用しているGeckoのYoctoレシピの開発元で当てているWayland、EGLのパッチは4個まで減っています

現在のステータス

前回からの改善点は以下の通りです。

  • AArch64向けのJavaScriptのJITが強化され、JavaScriptの実行速度が高速化された
  • e10sが有効化され、APZによるタッチイベントが有効化された
  • e10s有効化時にEGLを有効化するとContentプロセスがSEGVする問題が解消された
  • Stylo(Quantum CSS)がデフォルト有効化された

現状では、以下の制限があります。

  • 60ESRでは効いていたGLスクリーンバッファが効かず、Wayland/EGL環境ではWebGLの性能が落ちている。そのためフレームレートが30fps近辺をウロウロする。

また、68ESRでは以下の機能が廃止されました。

  • 68ESRではCanvasのハードウェアアクセラレーション

この廃止に至った事情は以下が詳しいです。

メンテナンスコストを勘案し、ハードウェアアクセラレーションが必要なほど性能を要求するコンテンツについてはWebGLの使用を推奨するというMozillaの公式見解が出されています。

まとめ

GeckoEmbeddedプロジェクトのESR68の状況について紹介しました。
ESR68対応がひと段落しているものの、マイナーバージョンアップ対応をどのように対処するかなどまだまだ手が足りていない状況です。
ぜひ当プロジェクトに参加して頂ければ幸いです。

*1 https://github.com/webdino/meta-browser/wiki/Build-RZ-G2#localconf-%E3%81%AE%E7%B7%A8%E9%9B%86

タグ: Mozilla
2020-04-22

Firefox 74以降でのアドオンのサイドローディングの代替

Mozillaの公式なアナウンスにある通り、Firefox 74以降のバージョンではアドオンの「サイドローディング」ができなくなりました。この変更は次のESR版であるESR78にも影響するので、主に企業ユーザー向けの情報として、対策・代替運用の情報をご紹介します。

サイドローディングとは何? なぜ廃止されたの?

まず用語の説明をします。

「サイドローディング」とは、通常の一般的なインストール手順を経ずに、FirefoxやThunderbirdにアドオンをインストールする方法です。Norton Internet Securityなどのソフトウェアをインストールすると、自分でインストールした覚えがないのにFirefoxやGoogle ChromeにNorton Internet Securityとの連携用ツールがインストールされることがありますが、これがサイドローディングです。

一般ユーザーにとっては、サイドローディングはセキュリティ上の脅威やユーザー体験の劣化に繋がるリスクがあります。悪意あるアドオンがサイドローディングされると、機密情報や個人情報の漏洩に繋がりかねません。また、サイドローディングでインストールされたアドオンは一般ユーザー権限では削除できず、Firefoxのアドオンマネージャ上に「削除できないアドオン」として居座り続けることになります。無効化はできますが、それでも毎回の起動時に不要なファイルが多数読み込まれると、起動にかかる時間の増大は避けられません。これらが、Firefox 74で公式にサイドローディングが廃止されるに至った背景です。

ESRでのサイドローディング

先に紹介したMozillaの公式のアナウンスには、「Additionally, Firefox Extended Support Release (ESR) will continue to support sideloading as an extension installation method.(ESR版では引き続きサイドローディングが使えます)」と書かれています。企業ではアドオンを社内のセキュリティ施策の実現のために使っている事例があるなど、アドオンが業務と密接に関わることがあり、このような判断がなされたようです。

法人利用での目下の課題は、現在の所ESR78のベータ版や開発版ではサイドローディングを使った運用の検証ができないという点です。

サイドローディングの有効・無効の切り替えは現在の所ビルドオプションで行われており、更新チャンネルがESRと指定されている場合にON、そうでなければOFFになるという設計になっています。そのため、更新チャンネルがESRではない開発版やベータ版ではサイドローディングが無効化されたままとなります。ESR78でアドオンをサイドローディングさせた状態の運用を検証するためには、正式版リリースを待つか、ソースコードをダウンロードしてきてESR版として自分でビルドするしかありません*1

このような問題があることに加え、サイドローディングには、ESRであってもいつまで利用できるかは不透明であるという懸念があります。今の所、明確に「ESRでも廃止する」というアナウンスは出されていませんが、将来的には廃止される可能性がある機能と思っておいた方が安全でしょう。

将来のESRやESR78の検証段階ではアドオンをサイドローディングできなくなる事を前提に考えて、企業の情シスご担当の方は、今のうちにアドオンの管理はポリシー設定で行う運用に移行するのがおすすめです。

サイドローディングを使わずに、システム管理者がアドオンのインストール状況を管理する

Firefox内蔵のポリシー設定機能は順調に拡充が進み、企業でのアドオン運用でよく見られるパターンであれば、以下のようなポリシーでおおむね要求事項をカバーできるようになっています。

以下、運用上の各場面での設定例をご紹介します。

導入時

Firefoxの運用を開始する時点で上記の例に対応するポリシー設定は、以下のようになります。

{
  "policies": {
    "Extensions": {
      "Install": [
        "\\\\fileserver\\shared\\addon-x-1.0.xpi",
        "\\\\fileserver\\shared\\addon-y-1.0.xpi"
      ],
      "Locked":  [
        "addon-x@example.com",
        "addon-y@example.com"
      ]
    },
    "InstallAddonsPermission": {
      "Default": false
    },
    "BlockAboutAddons": true,
    "ExtensionUpdate": false
  }
}

この例では、アドオンのインストールパッケージがSambaサーバーの共有ディレクトリ上に置かれており、UNCパス \\fileserver\shared でファイルの位置を参照できる場合を想定しています。JSONファイル内ではバックスラッシュはエスケープ文字となるため、UNCパス内の区切り文字のバックスラッシュがすべて二重になっていることに注意して下さい。Fx Meta Installerを使ってXPIパッケージをローカルに配置するインストール方法を使っている場合や、何らかの資材管理ツールを使っている場合には、以下のように通常のローカルファイルパスを指定することもできます。

{
  "policies": {
    "Extensions": {
      "Install": [
        "C:\\distributed-files\\addon-x-1.0.xpi",
        "C:\\distributed-files\\addon-y-1.0.xpi"
      ],
      ...
    },
    ...
  }
}

Active Directoryのグループポリシーを使う場合、.admx形式のポリシーテンプレートをドメインコントローラに読み込ませます。ポリシーテンプレートの使い方は先日のDNS over HTTPSに関する解説記事で詳しく述べていますので、併せてご参照下さい。

また、macOSではdefaultsコマンドの書き込み対象plistファイルに/Library/Preferences/org.mozilla.firefoxを指定して、以下の要領で設定します。

$ PLIST=/Library/Preferences/org.mozilla.firefox
$ sudo defaults write $PLIST EnterprisePoliciesEnabled -bool TRUE
$ sudo defaults write $PLIST Extensions__Install -array /distributed-files/addon-x-1.0.xpi /distributed-files/addon-y-1.0.xpi
$ sudo defaults write $PLIST Extensions__Locked -array addon-x@example.com addon-y@example.com
$ sudo defaults write $PLIST InstallAddonsPermission__Default -bool FALSE
$ sudo defaults write $PLIST BlockAboutAddons -bool TRUE
$ sudo defaults write $PLIST ExtensionUpdate -bool FALSE
アドオンの更新

Firefoxは、ポリシー設定のExtensions.Install似記述されたURLまたはパスが変更されていれば、そのアドオンを再インストールするようになっています。ファイル名にバージョン番号が含まれていれば、以下のように設定を更新するだけで、次回起動時にアドオンが更新される結果となります。

{
  "policies": {
    "Extensions": {
      "Install": [
        "\\\\fileserver\\shared\\addon-x-1.1.xpi",
        "\\\\fileserver\\shared\\addon-y-2.0.xpi"
      ],
      ...
    },
    ...
  }
}

言い換えると、このように管理者側でアドオンを更新することを考慮すると、アドオンのインストールパッケージはファイル名にあらかじめバージョン番号を含めた状態にして設置する必要があるということになります。

macOSでdefaultsコマンドを使用する場合は、配列の要素を削除する機能が無いため、以下の要領で配列の値すべてを置き換える必要があります。

$ sudo defaults write $PLIST Extensions__Install -array /distributed-files/addon-x-1.1.xpi /distributed-files/addon-y-2.0.xpi
アドオンの削除

アドオンの運用を終了する場合は、Extensions.InstallExtensions.Lockedから項目を削除し、Extensions.Uninstallに削除対象のアドオンのIDを列挙します。

{
  "policies": {
    "Extensions": {
      "Install": [
      ],
      "Uninstall":  [
        "addon-x@example.com",
        "addon-y@example.com"
      ],
      "Locked": [
      ]
    },
    ...
  }
}

macOSでdefaultsコマンドを使用する場合の注意事項は前項と同様です。すべての項目を削除して配列を空にする場合は、-arrayを指定して値を省略します。

$ sudo defaults write $PLIST Extensions__Install -array
$ sudo defaults write $PLIST Extensions__Uninstall -array addon-x@example.com addon-y@example.com
$ sudo defaults write $PLIST Extensions__Locked -array

まとめ

Firefox 74でのアドオンのサイドローディング廃止と、法人運用でのその影響、および、サイドローディングを使わずにポリシー設定でアドオンを運用する手順についてご紹介しました。

当社では、お客さまからの技術的なご質問・ご依頼に有償にて対応するFirefoxサポートサービスを提供しています。企業内でのFirefoxの運用でお困りの情シスご担当者さまやベンダーさまは、お問い合わせフォームよりお問い合わせください。

*1 アドオンが認識された状態での動作を検証するだけならユーザーインストールでも構いません。ここでは「Firefoxを初めて起動した時点でアドオンが読み込まれていること」のように、サイドローディングの性質が重要となる場面の検証を想定しています。

タグ: Mozilla
2020-04-24

«前月 最新記事 翌月»
タグ:
年・日ごとに見る
2008|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|12|
2019|01|02|03|04|05|06|07|08|09|10|11|12|
2020|01|02|03|04|05|06|