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

ククログ


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

ノータブルフィードバック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

ノータブルフィードバック7 - 開発者の環境では必要ない改善の提案

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の7つ目は、前回フィードバック対象となったMouse Dictionaryに対して筆者が別に行った、連続した一連のフィードバックです。

実際の報告

最初に行ったのは、前回のフィードバックで表示されるようになった初期設定の案内文の内容が、Firefoxでの実際のUIに整合しない状態だったために行ったフィードバックです。

■タイトル

初回使用時の案内がFirefoxでの状況にマッチしていない

■説明

初回使用時に辞書が未設定だと、ページ内に開いたポップアップの中に「初めに辞書データをロードしてください(拡張のアイコンを右クリック→「オプション」)」という案内のメッセージが表示されます。
しかしながら、Firefoxにはこのメニュー項目がありません。実際には、

  • アイコンを右クリック→「拡張機能を管理」を選択→「...」をクリック→「オプション」を選択

とする必要があります。

初回使用時に戸惑ったため、メッセージを各実行環境向けに変えることが望ましいと思われます。

このイシューに対応するプルリクエストは以下の内容でした。

■タイトル

Show initial setup guide for Firefox
≪Firefox用の初期設定案内を表示する≫

■説明

#32 に対する実装の提案となります。
こんな感じでいかがでしょうか?

■変更内容

メッセージの定義部にFirefox用のメッセージを追加し、実行環境によってメッセージを切り替えるようにした。

そのレビューの中で「コーディングスタイルをprettier準拠に揃えて欲しい」という指摘を受けたのですが、それをきっかけに作成した別のプルリクエストが、次の物です。

■タイトル

Add prettier
≪prettierを追加する≫

■説明

#33 でコーディングスタイルのご指摘をいただきましたが、コーディングスタイルもlintの一環とすることでコーディングスタイルの揃え忘れを減らせるのではないかと思いました。
いかがでしょうか?

変更内容:
package.jsonの文法チェック用の指定に変更を加え、コーディングスタイルをチェックするようにした。

注目したい点

状況に合わせたフィードバックの仕方

コミットメッセージから自動的に埋められたプルリクエストのタイトルを除いて、英語と日本語の併記ではなく、日本語だけでの報告となっています。これは、

  • プロジェクトオーナーが日本語話者だと分かっている。
  • 小規模な問題で、すぐにプルリクエストを出して問題を解消するつもりなので、イシューが長期に渡って残ることをあまり考慮しなくてもよさそう。

という前提があったためです。また、説明文については、「再現手順」「実際の結果」「期待される結果」を見出しを立てて強調するということもなく、自然文の中に入れてサラッと流してしまっています。これも、「初回起動時の一幕」という前提があるため、要点さえ押さえておけば伝わるだろう、という判断に基づいています。

フィードバックの経験が少ない状況では、どの情報を含めてどの情報を省略するべきかということの判断基準が不足していますので、下手をすると「その情報じゃなくて、こっちをむしろ残すべきだった」というような情報を省略してしまいかねません。そのため、「これでできる! はじめてのOSSフィードバックガイド」では「情報不足よりは情報過多の方がよい」という考えに基づいて、基本的な報告のフォーマットを紹介しています。

そのような取捨選択の感覚は、恐らく、報告をする立場だけだとあまり身に付きません。というのも、フィードバックは 「フィードバックを受ける側(開発者)にとって助けとなる内容」であること が望ましく、「どういう報告なら開発者は嬉しいか」ということは、突き詰めると開発者でなければ分からないからです。筆者の場合は、自分自身が開発者としてフィードバックを受ける機会が重なる中で、「こういう場面では、この情報をもらっても開発者の自分はあまり嬉しくない」という経験を得ており、それが取捨選択の判断基準になっています。

フィードバックの連鎖と、開発者以外の人に役立つフィードバック

また、もう一つ注目して欲しいのは、「プルリクエストに対するレビューを受けたときに気が付いたことを、別のプルリクエストで即座に(カジュアルに)フィードバックしている」という点です。1つフィードバックをすると、それがまた次のフィードバックにつながるということは、非常によくあります。

そうして行った2つ目のプルリクエストは、実はプロジェクトオーナーの方にとっては直接的には必要のない変更です。筆者は特に文法チェックや整形などの開発支援の仕組みを持たないテキストエディタを使っていますが、プロジェクトオーナーの方ご自身は、コーディングスタイルの整形はVSCodeの設定でファイルの保存時に行うようにされているからです。

このようなときには、自分が使っているテキストエディタの設定を変更したり、そのような設定がなければ別のテキストエディタへ乗り換えたりと、自分の手元の環境の範囲で改善を図る方が多いでしょう。しかしここでは、それを 「個人の環境設定の問題」とは捉えず、「プロジェクトオーナーがプルリクエストの内容を一々チェックしないといけないという、プロジェクトの問題」と捉え 、それを解消するプルリクエストを出したのでした。「問題をプロジェクトの問題だと捉えると、フィードバックできる点になる」ということの実例と言えるでしょう。

まとめ

ノータブルフィードバックの7回目として、フィードバックの連鎖の中で行った、「開発者の方にとって直接的には役には立たないけれども意味のある改善」の例をご紹介しました。

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

2020-03-27

ノータブルフィードバック6 - 初回使用時のつまずきを減らす提案

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の6回目として、今回は、[株式会社アカツキさんの社内で実施したOSS Gateワークショップ][20190529]の中で実際に行われた、Webページ上でマウスカーソル(ポインタ)をかざした位置の語句を辞書で引いて結果をポップアップ表示する「Mouse Dictionary」というGoogle Chrome/Firefox用の拡張機能での、「初回使用時にポップアップが真っ白になってしまう」という現象に対するフィードバックをご紹介します。

実際の報告

■タイトル

White screen shown in the first boot

■説明

Steps to Reproduce

  1. Install Chrome (ver. 72.0.3626.109 Official Build 64bit) into MacOSX 10.14.3 .
  2. Install Mouse Dictionary (ver. 1.1.9) from Chrome Web Store.
  3. Click extension icon of Mouse Dictionary, and open the popup window.
  4. Point any English term.

Expected Result

  • Shown translated sentence of English term in the popup window.

Actual Result

  • White screen shown in the popup window.

Suggestion

  • Add how to installation (ex. "Open option menu on the first boot.") in the store page.
  • Or, add description (ex. "Not initialized. Please open option menu.") in the not initialized popup window.

再現手順

  1. MacOSX 10.14.3 に、Chromeのバージョン:72.0.3626.109(Official Build)(64 ビット)をインストールする
  2. chromeウェブストアから Mouse Dictionary (バージョン:1.1.9) を拡張機能としてインストールする
  3. 拡張機能一覧から Mouse Dictionary のアイコンをクリックして、ポップアップウィンドウを立ち上げる
  4. ポップアップウィンドウが立ち上がった状態でウェブページ内の任意の英単語にマウスカーソルを合わせる

期待する結果

  • Mouse Dictionary のポップアップウィンドウに、翻訳結果が表示される

実際の結果

  • ポップアップウィンドウ内は白紙のまま、何も表示されない

提案

  • 最初にオプションメニューを開くことが必須ということを、ストアページの説明文に記載してはどうでしょうか
  • もしくは、辞書情報が登録されていないのでオプションメニューを開かなければならない旨を、ポップアップウィンドウに表示してはどうでしょうか

注目したい点

日本語でも書く

OSS Gateワークショップの中で行ったフィードバックなので、報告の仕方は「再現手順、期待する結果、実際の結果」という基本のフォーマットに則っています。

ここで注目したいのは、本文を英語と日本語の2パターンで書いているということです(ここに掲載するために翻訳したのではなく、元々の報告の時点で両方載っています)。これは、説明文からリンクされている開発者の方による解説記事が日本語で書かれており、作者の方が日本語話者の方だということが分かっていたためです。

OSSへのフィードバックは、書ける場合は英語で書いておいたほうが望ましいです。というのも、英語を読み書きできる人と日本語を読み書きできる人とでは前者の方が圧倒的に数が多く、日本語だけで報告を書いていると、同じ問題に遭遇した人が「既存の同様の報告」にたどり着けない恐れがあるからです。

とはいえ、英語を書くことに不慣れな人は、自分の伝えたかったことをきちんと英語で表現できているか不安なものです。この事例のように作者の方が日本語話者と分かっている場合には、両方の言語で報告を書いておくことで、万が一の場合の誤解を防げるという安心感を持って報告できるでしょう。

使い始めのつまずきを報告している

第1回でとりあげたOCamlへのフィードバックでは、インストール後のバージョン確認の手順の間違いをフィードバックしましたが、今回もそれと同様に、初めて使うときにつまずく人の多そうな点をフィードバックしています。

一般ユーザーでも開発者でも、「説明書を読まずに使い始める」人は一定数います(筆者もそうです)。そのような人にとっては、説明を読んで使うことが前提のツールは使い始めていきなり「詰んで」しまう、ということになりがちです。初期化用のウィザードやチュートリアルはその最も丁寧な対応の例ですが、そこまで凝った対応でなくても、この提案のように「案内のメッセージを出す」だけでも、ほとんどのユーザーにとっては大きな助けになるでしょう。

提案も書く

また、報告の最後に 「提案」として改善案を示している ところもポイントです。操作に対する「期待される結果」は「翻訳結果が表示されること」なのですが、初回使用時という場面では、初期設定なしにそのような結果を得るのは難しいです。そこで、この報告では次善の策として、ユーザーがしなければならないことの案内を明示するのはどうか、と提案しています。

開発者側で気を回して「こうなっているといいのでは」と推測して実装した結果が、実際のユーザーのニーズに合致していなかった、ということは度々あります。ユーザー自身が「どうなっていると嬉しい」という内容を詳しく伝えることで、そのような無駄足を踏まずに済むと言えます*1

まとめ

ノータブルフィードバックの6回目として、Google Chrome/Firefox向け拡張機能の初回使用時の動作についてのフィードバックをご紹介しました。

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

*1 ただ、開発者側の視点では、ユーザーから寄せられた提案にそのまま従うことが必ずしも正解とは限らない、ということも言えます。というのも、ユーザー自身の発想が特定の場面やそれまでの経験に囚われている場合、言葉として表現された物が本来のユーザー自身のニーズからかけ離れてしまっていることがあるからです。開発者はユーザーからの提案を判断材料の一つとしつつ、その提案が発せられた背景をきちんと分析し、常に最適な解決策を考えるよう努める必要があります。

2020-03-23

ノータブルコード5 - Lispとシェルスクリプトのキマイラ

今回紹介するコードは、エディンバラ大学が開発した音声合成ライブラリFestivalからのコードです。このライブラリには、テキストファイルを音声に変換する「text2wave」という実行ファイルが付属しています。このファイルの冒頭部分を引用すると次のようになっています。

#!/bin/sh
"true" ; exec /bin/festival --script $0 $*
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-*-mode:scheme-*-
;;                                                                       ;;
;;                Centre for Speech Technology Research                  ;;
;;                     University of Edinburgh, UK                       ;;
;;                       Copyright (c) 1996,1997                         ;;
;;                        All Rights Reserved.                           ;;
...

;;; Because this is a --script type file I has to explicitly
;;; load the initfiles: init.scm and user's .festivalrc
(load (path-append libdir "init.scm"))

;;; Process command line arguments
(define (text2wave_help)
  (format t "%s\n"
  "text2wave [options] textfile
  Convert a textfile to a waveform
  Options

最初の2行を見て「ああこれはシェルスクリプトなんだな」と思っていると、突然3行目から Lisp/Scheme のコードが始まってビックリさせられます。それ以降のコードはSchemeのプログラムになっていて、シェルスクリプトの面影は影も形もなくなってしまいます。上の抜粋からも、ごく普通のシェルスクリプトの書き出しから、シームレスにSchemeのS式の世界に突入していることがご確認いただけると思います。

これはどういう仕組みで動いているんだろう?というのが、今回の記事のテーマです。

シェルスクリプトとしての実行プロセス

この謎を解き明かすカギは、最初の2行にあります。このスクリプトを「/bin/text2wave test.txt」として実行した時の流れを追ってみましょう。

#!/bin/sh
"true" ; exec /bin/festival --script $0 $*

まず、オペレーティングシステムのプログラムローダーは最初の1行目を見て「これは/bin/shで実行するコードだ」と判断します。ですので、このファイル全体が(最初の見立て通り)まずはシェルスクリプトとして解釈されることになります。

そこで2行目に目を移すと、シェルスクリプトではセミコロン ; はコマンドの区切りを示すので、この行は2つのコマンドから構成されていることが分かります。このうちの、前半部分は特に何もせず成功ステータスコードを返すtrueコマンドなので*1、実行だけされて次に移ります。

これに対して、後半部分にはもっと意味のありそうなコマンドが書かれています。まずこのコマンドの中のシェル変数に注目すると $0 は実行されているプログラムを表すので「/bin/text2wave」に、$* はコマンドライン引数を表すので「test.txt」にそれぞれ置換されます。いいかえると、この部分は次のようなコマンド行に展開されることになります。

exec /bin/festival --script /bin/text2wave test.txt

冒頭のexecはシェル標準のコマンドで、指定した実行プログラムで実行中のプロセスの内容を置き換えます。ですので、このコマンドが実行されると、シェルスクリプトとしての実行はひとまず終了になります。

Schemeスクリプトとしての評価

シェルスクリプトの最後で実行された /bin/festival に着目しましょう。これは、音声合成ライブラリの実行バイナリで、引数「--script」で与えられたファイルをSchemeスクリプトとして処理します。ここでは /bin/text2wave を指定しているので、最初にシェルスクリプトとして評価したスクリプトが(今度はSchemeのスクリプトとして)再び頭から解釈されることになります。

このSchemeインタプリタによる実行評価は次のように進行します。

  • まず、大抵のLisp処理系は#!をコメント行として扱います。
    • これは言語の仕様ではありませんが、スクリプト言語としての用途を考慮して、そのように実装されていることが多いです。
    • FestivalのSchemeインタプリタも同様の振る舞いをするので、1行目はコメントとして無視されます。
  • 2行目の前半部分については、Schemeでは"true"は文字列リテラルなので、評価だけして素通りします。
  • 2行目の後半部分は重要なポイントで、実はSchemeではセミコロンはコメントの開始を表します。 従って、execから行末までの部分はコメントとして無視されます。

そこから後の部分は普通のSchemeプログラムなので、普通に実行されることになります。

話をまとめると、このスクリプトは (1) シェルスクリプトとして実行することもできるし、(2) Schemeスクリプトとしても実行できるという実に不思議なプログラムなのです。この特筆すべき性質によって、Schemeとシェルスクリプトというまったく性質の異なる言語が、1つのファイルの中でなめらかに共存できているのです。

なぜこんなことをしているのか?

「確かに面白いテクニックだけど、なぜこんなことをしているの? 普通に最初の行で#!/bin/festival --scriptと指定するだけではダメなの?」というのは当然思い浮かぶ疑問です。このFestivalのコードは20年以上前のコードで、すでに実装の背景は分からなくなってしまってるのですが、この構成を採用するメリットは少なくとも2つあります。

  1. システム互換性の問題を回避できる。 Unixでは一般に「#!/path/to/program」という一行をスクリプトの冒頭につけることで、実行するプログラムを指定できますが、実は、この仕組みには明確な仕様がなく、具体的な振る舞いはシステムによってまちまちです(例えば、古いOSだと実行ファイルのパスの後に引数を指定できなかったりします)。この方式だと#!/bin/shさえ上手く解釈されれば、あとはシェルスクリプトで呼び出しを制御するので、非常に広い範囲のUnixシステムでポータブルに動作することが期待できます。
  2. 実行プログラムに渡す引数を柔軟に調整できる。 最終的に本体ファイル /bin/festival を呼び出すのはシェルスクリプトなので、実行時のパラメータをいかようにも制御できます。シェルの制御構文を使えば、条件分岐で与える引数を動的に変えることもできます。これは通常のやり方では実現できないポイントです。

まとめ

今回は音声合成ライブラリのFestivalから、Lispとシェルがなめらかに統合された、ギリシャ神話の怪物キマイラのようなコード(頭部はシェルスクリプトで胴体はSchemeです!)をご紹介しました。

皆さんはこのコードを読んでどのような感想を抱きましたか? ノータブルコードのコーナーでは皆さんの寄稿も受け付けていますので、ご意見や「これをぜひ紹介したい」というコードがあれば、ぜひともお寄せください。

*1  (3/17追記) 最初の公開版では「単なる文字列リテラルで、特に変数に代入もされていないので」と説明していましたが、コメントの指摘の通り、誤りのため修正しています。ご指摘ありがとうございます!

2020-03-10

ノータブルコード4 - NULLよりも名前付きの番兵オブジェクト

MroongaというMySQLのストレージエンジンを開発している須藤です。MySQLのAPIはよく変わるのでMroongaの開発をしているとMySQLのソースコードを読む機会がよくあります。今日、MySQLのコードを読んでいて「お!」と思うコードがあったので4回目のノータブルコードとして紹介します。

MySQLは基本的なデータ構造も独自に実装していることが多いです。今日紹介するListも独自に実装しています。

多くの場合、リストは次のように「要素データへのポインタ」と「次の要素へのポインタ」を持つ構造をつなげて実装します。

struct List {
  void *data;
  List *next;
};

そして、リストの終端にNULLを置いてリストの終わりを表現します。

if (list->next) {
  printf("have more elements\n");
} else {
  printf("no more elements\n");
}

MySQLのリストの実装はNULLではなくリストの終端を示す番兵オブジェクトを使っていました。

extern MYSQL_PLUGIN_IMPORT list_node end_of_list;

class base_list {
  inline void empty() {
    elements = 0;
    first = &end_of_list;
    last = &first;
  }
};

私が「お!」と思ったのはGDBでデバッグしていたときです。GDBではpで出力したアドレスが既知のグローバル変数や関数などの場合はその名前も出力してくれます。ここでend_of_listという名前が出てきたのです。

(gdb) p (((const Item_cond *)select_lex->where_cond())->argument_list()->first->next->next
$1 = (list_node *) 0x555557f77550 <end_of_list>
(gdb) p (list_node *)0x555557f77550
$2 = (list_node *) 0x555557f77550 <end_of_list>

->nextとしたらNULLが返ってきても「あぁ、ここでリストは終わりなんだな」ということはわかるのですが、end_of_listという名前が見えてもたしかにリストが終わりだとことがわかるなと思いました。リストのときはNULLで十分だとは思いますが、もう少し複雑なもののときはNULLよりもなにか名前が付いた番兵オブジェクトを使うとデバッグが捗るときがあるんじゃないかと思いました。このテクニックを使う機会を見つけることが楽しみです。

今回はMySQLのリスト実装のコードで「お!」と思った名前付きの番兵オブジェクトを紹介しました。みなさんもNULLではなく名前付きの番兵オブジェクトを使った方がよさそうなケースがないか考えてみてください。

ところで、そろそろみなさんも自分が「お!」と思ったコードを「ノータブルコード」として紹介してみたくなってきませんか?ということで、このブログへの寄稿も受け付けることにしました。まだ仕組みは整えていないのですが、とりあえず、 https://gitlab.com/clear-code/blog/issues にMarkdownっぽいマークアップで書いた原稿を投稿してもらえばいい感じに調整してここに載せます。寄稿したいという人がたくさんいるならもう少しちゃんとした仕組みを整えようと思っていますので、興味のある人はご連絡ください。寄稿してもらった記事の著作者は作者本人のままですが、ライセンスはCC BY-SA 4.0GFDL(バージョンなし、変更不可部分なし、表表紙テキストなし、裏表紙テキストなし)のデュアルライセンスにしてください。参考:ククログのライセンス

それでは、次のノータブルコードをお楽しみに!

2020-03-03

ノータブルフィードバック5 - 開発者が把握していない使い方についての報告と、そこからのプルリクエスト

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の5つ目は、当社の畑ケさん*1meta-clangというプロジェクトに対して行ったフィードバックです。

実際の報告

■タイトル

meta-clang's llvm-config is not compatible with MULTILIBS
≪meta-clangのllvm-configが、MULTILIBSと互換性がない≫

■説明

≪不具合の説明≫
One of the our target boards(RZ/G2E)'s Yocto default conf/local.conf specifies MULTILIBS = "multilib:lib32" and DEFAULTTUNE_virtclass -multilib-lib32 = "armv7vethf-neon" to be able to run 32bit ARMv7 binaries.
≪私達が開発している対象のボード(RZ/G2E)の一つのYoctoレシピの既定のconf/local.confには、32bit ARMv7バイナリを動かすために、 「MULTILIBS = "multilib:lib32"」と「DEFAULTTUNE_virtclass-multilib-lib32 = "armv7vethf-neon"」という設定が含まれています。≫
So, built binaries will be installed in /usr/lib64/ instead of /usr/lib.
≪そのため、ビルドされたバイナリは/usr/libではなく/usr/lib64/の中にインストールされます。≫

Because our SDK environment does not assume /usr/lib for library installation directory.
≪なぜなら、私達のSDKの環境は/usr/libをライブラリのインストール先ディレクトリーとして想定していません。≫
Instead, /usr/lib64 is used for 64bit libraries and shared object. And /usr/lib32 is used for 32bit objects.
≪その代わりに、/usr/lib64は64bitライブラリと共有オブジェクトに使われます。また、/usr/lib32は32bit版オブジェクトに使われます。≫

ref: https://llvm.org/docs/CMake.html#frequently-used-cmake-variables

To Reproduce
≪再現するには≫

Steps to reproduce the behavior:
≪この動作を再現するための手順:≫

  1. Specify MULTILIBS = "multilib:lib32" and DEFAULTTUNE_virtclass-multilib-lib32 = "armv7vethf-neon" in local.conf
    ≪「MULTILIBS = "multilib:lib32"」と「DEFAULTTUNE_virtclass-multilib-lib32 = "armv7vethf-neon"」をlocal.confの中で設定する≫
  2. Add meta-clang layer
    ≪meta-clangレイヤを追加する≫
  3. bitbake clang-cross-aarch64
    ≪bitbake clang-cross-aarch64を実行する≫
  4. add meta-browser and meta-rust layer
    ≪meta-browserとmeta-rustのレイヤを追加する≫
  5. bitbake firefox
    ≪bitbake firefoxを実行する≫
  6. See error
    ≪エラーが表示される≫

Error
≪エラー≫

≪実際に出力されたエラーの全文が貼り付けられているが、ここでは省略。≫

Expected behavior
≪期待される挙動≫

meta-clang's llvm-config can work with DEFAULTTUNE_virtclass-multilib-lib32 specified environment.
≪meta-clangのllvm-configが、「DEFAULTTUNE_virtclass-multilib-lib32」が指定された環境で動作すること。≫

llvm-config points to ${RECIPE_SYSROOT}/usr/lib/clang/8.0.1/lib/linux/ but actual libclang libraries are put in ${RECIPE_SYSROOT}/usr/lib64/clang/8.0.1/lib/linux/
≪llvm-configは「${RECIPE_SYSROOT}/usr/lib/clang/8.0.1/lib/linux/」を指定しますが、実際のlibclangライブラリは「${RECIPE_SYSROOT}/usr/lib64/clang/8.0.1/lib/linux/」に置かれます。≫

LLVM insists that using LLVM_LIBDIR_SUFFIX to control installation directory suffix such as lib64 or lib32.
≪LLVMでは、インストール先ディレクトリーの末尾をlib64やlib32のように変えたい場合、LLVM_LIBDIR_SUFFIXを使う必要があります。≫

We should handle library directory glitch it llvm-config with LLVM_LIBDIR_SUFFIX.
≪私達はLLVM_LIBDIR_SUFFIXを伴ったllvm-configのライブラリーの配置先ディレクトリーのずれに対処するべきでしょう。≫

Desktop (please complete the following information):
≪ビルド環境のデスクトップ機(以下の情報を埋めてください)≫

  • OS: Ubuntu
  • Version 16.04.6 LTS

Additional context
≪追加の情報≫

(Updated) I'd encountered this issue during meta-browser's firefox recipe building.
≪(追記)私はこの問題に、meta-browserのFirefoxのレシピを使ってのビルド作業中に遭遇しました。≫

フィードバックの経緯

組み込み機器向けにカスタマイズしたLinuxディストリビューションを作成するためのツールセットの一種であるYoctoでは、そのLinuxディストリビューションに組み込めるパッケージが多数公開されています。その中で、C言語のコンパイラであるclangを組み込むための設定ファイルやスクリプトを提供しているのが、meta-clangというプロジェクトです。畑ケさんがとある組み込みボード*2用にFirefoxをビルドしようとして、Firefoxのビルドに必要なmeta-clangを構成に入れたところ、ビルド結果が想定通りにならず、Firefoxパッケージをビルドできないという状況に遭遇しました。

この時点で原因がmeta-clangにあるということは明らかだったため、畑ケさんは手元でとりあえずの回避策を講じた上で、問題に遭遇したということをmeta-clangにフィードバックしました。すると、その報告に対してプロジェクトオーナーから「Can you cook up a patch?(パッチを作ってもらえませんか?)」とコメントが返ってきました。そこで、畑ケさんは「I'm cooking up patches....(今パッチを作成中です……)」とコメントした上で、手元で行っていた暫定的な回避策を一般公開できるようにより洗練させ、プルリクエストにしました

その後パッチがマージされたことで、この報告もクローズされています。

注目したい点

これも、「自分の手元でなんとかして動くようにした」というところで終わらせないで、開発元にエスカレーションした事例です。

最終的にプルリクエストを出すところにまで至っていますが、畑ケさんは当初はそこまでするつもりはありませんでした。しかし 「パッチを作ってもらえませんか?」と逆に依頼された ことがきっかけとなり、プルリクエストの作成に至りました。フィードバックは「自分にできることをまずはやる」所から始めるとよいですが、やろうと思っていなかったことに挑戦する機会にもなるということの好例と言えるでしょう。

この報告はプロジェクトのイシューテンプレートに基づいて書かれていていますが、「To Reproduce」には再現手順と実際の結果が、「Expected behavior」には期待される結果が書かれており、問題の報告の基本の3要素がきちんと含まれていることが分かります。

フィードバックする前の予備調査の時点で、畑ケさんはこの作者の人が、ここで使おうとしている「MULTILIBS」という機能を使っていないようだ、ということを把握していました。そのため、再現手順や環境の作り方をより細かく具体的に書き、作者が容易に現象を確認できるようにすることを意識したそうです。CJKの言語に特有の事情を詳しく説明した前回の例と、考え方は同じです。

文中に登場している「glitch」という単語は、辞書では「故障」「誤動作」「異常」といった意味と出ますが、語源は「slip(滑る)」や「slide(ずらす)」と同じで、ニュアンスとしては「本来の正常な状態からずれてしまっている」状態を表すそうです。インデントのずれや画像の位置ずれなどにも使える表現ということで、覚えておくとよいでしょう。

ところで、この例も報告文の中にミスタイプがあります。

We should handle library directory glitch it llvm-config with LLVM_LIBDIR_SUFFIX.

この文の「it」は誤記で、「in」が正しいです。先の筆者の例と併せて見ると、誤記はありふれたものだということをなんとなく感じて頂けるのではないでしょうか*3

まとめ

ノータブルフィードバックの5回目として、開発者が想定していない使い方での不具合を報告するフィードバック例をご紹介しました。

このような「身近なところで遭遇したつまずきをOSS開発プロジェクトにフィードバックする」ということをテーマに、まだOSSにフィードバックをしたことがない人の背中を押す解説書 「これでできる! はじめてのOSSフィードバックガイド ~ #駆け出しエンジニアと繋がりたい と言ってた私が野生のつよいエンジニアとつながるのに必要だったこと~」を、電子書籍としてリリースしました。本記事の内容はこの本からの抜粋となっています。ダウンロード購入のチャンネル、紙媒体版などの詳細については、「ノータブルフィードバック」第4回目の記事を併せてご参照下さい。

*1  「はたけ」と読む珍しい名字のため、社内でもよく「ケ」が行方不明になりがちです。

*2 複合機やカーナビなどの制御に使われるコンピューター。

*3 畑ケさん本人にこの事を知らせると「やっちまったぁぁ」と恥ずかしがっておられましたが、本書でフィードバック初心者の方に勇気を持ってもらうための礎になっていただきました。合掌。

2020-03-02

ノータブルフィードバック4 - 開発者が知らない言語圏に固有の問題の報告

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の4つ目は、筆者がチャットツールのZulipに対して行ったフィードバックです。

実際の報告

■タイトル

typeahead: "keydown" events for Enter and Arrow keys should be ignored while "composition"
≪インクリメンタル検索: Enterキーと矢印キーのkeydownイベントは「コンポジション」の最中は無視されるべき≫

■説明

First, I describe what is the "composition".
≪最初に、「コンポジション」とは何かを説明します。≫

In CJK language regions, people use some software named "IM" (input method) to input heir local language text. For example, when I search a Japanese term "日本語" (means "Japanese language") in a Zulip instance with Firefox, I need to do:
≪CJK(中国語・日本語・韓国語)の言語の地域では、人々は彼らの地域言語のテキストを入力するために「IM(インプットメソッド)」と呼ばれるソフトウェアを使っています。たとえば、私が日本語の単語「日本語」をFirefoxで表示したZulipで検索するとき、私は以下のような操作をする必要があります:≫

  1. Click the search field.
    ≪検索欄をクリック。≫
  2. Activate the IM. The "composition" session starts.
    ≪IMを有効化する。「コンポジション」のセッションが始まる。≫
  3. Type keys: n, i, h, o, and n. (in a composition session)
    ≪(コンポジションのセッションの中で)n, i, h, o, nとキーを入力する。≫
  4. Hit the Space key to convert the text to Japanese term. "日本" is suggested. (in a composition session)
    ≪(コンポジションのセッションの中で)テキストを日本語の単語に変換するために、スペースキーを押す。「日本」が提案される。≫
  5. Hit the Enter key to determine the text "日本". (in a composition session)
    ≪(コンポジションのセッションの中で)「日本語」というテキストを確定するために、Enterキーを押す。≫
  6. Type keys: g, and o. (in a composition session)
    ≪(コンポジションのセッションの中で)g, oとキーを入力する。≫
  7. Hit the Space key to convert the text to Japanese term. "語" is suggested. (in a composition session)
    ≪(コンポジションのセッションの中で)テキストを日本語の単語に変換するために、スペースキーを押す。「語」が提案される。≫
  8. Hit the Enter key to determine the text "語". (in a composition session)
    ≪(コンポジションのセッションの中で)「語」というテキストを確定するために、Enterキーを押す。≫
  9. Deactivate the IM. The "composition" session ends.
    ≪IMを無効化する。「コンポジション」のセッションが終了する。≫
  10. Hit the Enter key again to search "日本語" on Zulip.
    ≪「日本語」をZulipで検索するために、Enterキーをもう1度押す。≫

While the composition session, "keydown" events for special keys (Enter and Arrow) are handled by the IM to choose a term from variations >or determine the choice. Thus I hit the Enter key three times in this case. The first time and the second are notified only to IM, so Zulip receives only the third time.
≪コンポジションのセッション中は、(Enterや矢印などの)特別なキーに対するkeydownイベントは、IMによって、複数の候補の中から単語を選択したり選択を確定したりするために使われます。そのため、私はEnterキーをこの例では3回押しています。1回目と2回目はIMに対してのみ通知されるため、Zulipは3回目のみを受け取ります。≫

And, there is one problem on lately development build of Firefox.
≪そして、最近のFirefoxの開発者向けビルドでは一つ問題があります。≫

  • 1446401 - Start to dispatch keydown/keyup events even during composition in Nightly and early Beta
    https://bugzilla.mozilla.org/show_bug.cgi?id=1446401
    ≪1446401 - Nightlyと初期ベータ版で、コンポジション中のkeydownとkeyupイベントを通知するようにする≫
  • Intent to ship: Start to dispatch "keydown" and "keyup" events even if composing (only in Nightly and early Beta) - Google Group
    https://groups.google.com/forum/#!topic/mozilla.dev.platform/oZEz5JH9ZK8/discussion
    ≪リリースしようとしているもの: Nightlyと初期ベータ版のみにおいて、コンポジション中にkeydownとkeyupイベントが通知されるようになります≫

Due to the change, now development build of Firefox (aka Nightly) notifies "keydown" events to the webpage, for all keyboard operations while "composition" sessions. As the result, the search field shows suggested results while I'm typing alphabet keys. This is good improvement, but there is one new problem: when I hit the Enter key to determine a chosen term, it is also notified to Zulip. Thus, when I just determine the first part term "日本" of the joined term "日本語", Zulip unexpectedly handles the Enter key to search the part "日本" and I cannot input following part "語" anymroe.
≪この変更のため、Firefoxの開発版ビルド(別名Nightly)は「コンポジション」セッション中の物も含めすべてのキーボード操作に対し、keydownイベントをWebページに通知します。その結果、検索欄は私がアルファベットのキーを入力している最中に候補を表示します。これは良い改善ですが、しかし新たに1つの問題が発生しています:選択を確定するために私がEnterキーを押したとき、それがZulipにも通知されます。そのため、私が「日本語」という複合語の一部として「日本」を確定しようとしたときにまで、Zulipは意図せずそのEnterキーの操作を「日本」という単語を検索するための物として取り扱い、続く「語」という単語を私は入力することができません。≫

To fix this problem, Zulip need to ignore keydown events for Enter and Arrow keys while the composition session. While a composition session, all keydown events have the isComposing (https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/isComposing) property with true value, so you just need to return when the property is true. Could you apply this change to Zulip?
≪この問題を直すためには、ZulipはEnterと矢印キーのkeyダウンイベントをコンポジションのセッション中は無視する必要があります。コンポジションのセッション中は、すべてのkeydownイベントがisComposingというプロパティをtrueという値を伴って持っています。そのため、そのプロパティの値がtrueであるときはすぐに処理をリターンする必要のみあります。この変更をZulipに反映してもらえませんか?

Environment:
≪環境≫

  • Zulip 1.8.0
  • Mozilla Firefox Nightly 62.0a1
  • Ubuntu 16.04LTS + IIIMF ATOK X3

フィードバックの経緯

筆者の所属会社では、社内のチャットとしてSlackではなく独自にサーバーを立てたZulipを使っています。その運用中に、Firefoxの開発版で問題になる箇所があることに気付いたため、開発元にフィードバックしたという事例です。

日本語のようにキーボードのキーの数よりも入力したい文字の種類が圧倒的に多い言語では、文字入力専用のソフトウェアを介して文字を入力するのが一般的です。また、日本語の文章では単語間にスペースが入らないのが一般的です。このような言語には他に中国語と韓国語もあり、テキストデータやその入力、文字コードの取り扱いの文脈ではこれらの言語がよく話題に挙がるため、3つをひっくるめて 「CJK」 *1と呼ぶことがあります。

CJKを想定していない機能とCJKの言語はあまり相性が良くない傾向にあり、「インクリメンタル検索」もその一例です。英語のようにキーと入力したい文字とがほぼ1対1で対応している言語では、文字を入力したそばから検索が進行するインクリメンタル検索が好まれます。しかし、CJKの言語では「入力中の文字が最終的に入力したい文字とは異なっている(未確定である)」という状態があります。この状態を考慮していない実装でインクリメンタル検索が発動すると、日本人にとっては文字入力がそもそもできないという困った事態になります。

この報告を行った前後の時期には、Firefoxの仕様変更でこの種の問題が起こりやすくなっていたため、Mozillaからもソフトウェア開発者やWeb制作関係者向けに公に注意が呼びかけられていました。報告の中で紹介している記事が、まさにそれです。

注目したい点

CJKを母語としない開発者にはこういった事情がなかなか分からないらしく、「そもそもどういう前提があるのか」ということから詳しく説明しないと、問題に対処してもらえないということも珍しくありません。そのためこの報告では、CJKの言語ではどうやって文字を入力するのか、その中でこの問題がどういう影響を及ぼすのか、ということを詳しく述べました。その後のコメントで実装の改修案を併せて示したこともあってか、開発者の方には問題をスムーズに認識してもらうことができ、迅速に解決してもらえました。

言語のように自分の生活と密接に結び付いた領域の話は、報告者にとってもあまりに当たり前のことすぎて、明確に言葉で説明するのが逆に難しいものです。報告者が「なんでこれが問題だと分かってくれないんだ!?」とフラストレーションを感じる一方で、その報告内容は、報告を受けた側から見ると「要領を得ない言葉足らずのもの」となっていることも多く、何が問題なのかを理解できないために、うっかり適切でない判断をしてしまうことがあります。そのような悲しいすれ違いを避けるためにも、報告者は自分の状態を「自明のもの」と考えず客観視して、どこが相手からは見えていない部分なのかを探り、自分から情報を積極的に開示する姿勢を保つことが望ましいです。

なお、同様のことがアラビア語などの書字方向がRTL(右から左に文字が流れる)の言語にも言えるようです。LTR(左から右)の言語だけを想定したソフトウェアは(特にGUIが)、RTLの言語で使うと悲惨なことになりがちなようです。皆さんがOSSを公開したら、もしかするとそういった言語圏の方から逆にフィードバックを受けることになるかもしれませんので、そのときはぜひ耳を傾けてください。

ところで、以下の文のおかしいところに皆さんは気が付かれましたか?

In CJK language regions, people use some software named "IM" (input method) to input heir local language text.

実はこの文の「heir」は誤記で、「their」が正しいです。ベテランでもこのようなミスタイプが残ったまま報告してしまうことがある*2と思うと、皆さんも、英語の間違いを過度に恐れる必要はないのだなと勇気づけられるのではないでしょうか。

まとめ

ノータブルフィードバックの4回目として、開発者が日本語に詳しくないときに日本語入力の場面に固有の不具合を報告するフィードバック例をご紹介しました。

このような「身近なところで遭遇したつまずきをOSS開発プロジェクトにフィードバックする」ということをテーマに、まだOSSにフィードバックをしたことがない人の背中を押す解説書 「これでできる! はじめてのOSSフィードバックガイド ~ #駆け出しエンジニアと繋がりたい と言ってた私が野生のつよいエンジニアとつながるのに必要だったこと~」を、本日付けでリリースしました

本記事の内容はこの本からの抜粋となっています。全文を読む方法には以下の選択肢があります。

  • EPUB/PDF形式の電子書籍データは、現時点では結城が個人的に運営しているBOOTHおよびAmazon Kindleダイレクト・パブリッシングでご購入いただけます。
  • 紙媒体版は、「技術書同人誌博覧会」や今後の「技術書典」に持ち込ませて頂く予定です。他には、同人誌書店での委託販売・通販なども検討中ですが、具体的な予定はまだありません。
  • 本の原稿のリポジトリでは全文を読めるほか、リポジトリをcloneしてビルドすると、これらのチャンネルで頒布している物と同等のデータをお手元で作成できます。腕に自信のある方はチャレンジしてみてもいいかもしれません。(そういうわけなので、有料の販売については投げ銭もしくはビルド作業の手間賃と考えて頂ければ幸いです)

*1 そのまま「Chinese, Japanese and Korean」の略です。

*2 ちなみに筆者は、コミットログのメッセージでもよくミスタイプをしていますが、そのままpushしてしまっています(pushした後で気が付くことが多い)。

2020-02-29

ノータブルフィードバック3 - リリースマネージメントの見落としの報告

結城です。

ノータブルコードに便乗して、実際のOSSのフィードバックを見て「ノータブルフィードバック」と題してお届けする記事の3つ目は、当社の足永さんがcollectdというソフトウェアに対して行った、リリースマネジメントに関するフィードバックです。

実際の報告

■タイトル

The source packages of collectd-5.9.2 aren't generated by the formal procedure
≪タイトル:colelctd-5.9.2のソースパッケージが通常の手順で生成されない≫

■説明

Version of collectd: collectd-5.9.2 on git
≪collectdのバージョン:git上のcollectd-5.9.2≫

Expected behavior≪期待される結果≫:
version-gen.sh script should generate "5.9.2" on collectd-5.9.2 tag.
≪version-gen.shスクリプトがcolelctd-5.9.2タグに基づいて「5.9.2」を生成する。≫

Actual behavior≪実際の結果≫:
version-gen.sh script generates "5.9.1.7.gdfb9dd0 on collectd-5.9.2 tag.
≪version-gen.shスクリプトがcolelctd-5.9.2タグに基づいて「5.9.1.7.gdfb9dd0」を生成する。≫

Steps to reproduce≪再現手順≫:
$ git clone https://github.com/collectd/collectd.git
$ cd collectd
$ git checkout collectd-5.9.2
$ ./version-gen.sh

Cause of the issue≪問題の原因≫:
collectd-5.9.2 tag isn't annotated.
≪collectd-5.9.2タグに注記が付いていない。≫

フィードバックの経緯

足永さんがとある案件でcollectdの独自改修版を作成して、お客さん向けに提供するためのパッケージを所定の手順で作成しようとしたところ、当時の最新リリース版である「5.9.2」からの派生版なので「5.9.2.(リビジョン番号)」というバージョン番号が自動生成されるはずが、なぜか「5.9.1.(リビジョン番号)」というバージョン番号になってしまう、という現象に遭遇しました。

この原因を足永さんが調べたところ、以下のことが分かりました。

  • パッケージ作成用のスクリプトは、Gitリポジトリに対して打たれたタグのメッセージが特定の形式に則って書かれている場合にのみ、それを正常なバージョンとして認識するようになっている。
  • バージョン5.9.2のタグのメッセージは、その形式に則っていなかった。

実際に、公開されているcollectdに対して何も変更を行っていない状態でパッケージを作成しようとしても、やはり同様の現象が発生する状態でした。そのため、足永さんはこの問題をcollectdプロジェクトで解決されるべき物として、調査結果を踏まえてフィードバックしました。

報告の後のコメントのやり取りの中では、collectdプロジェクトにおいてリリース作業の担当者が今回から変わっていたことと、前任者から手順が正しく引き継がれていなかったためにタグのメッセージが適切に設定されていない状態だったということが分かりました。その後、問題の状態は解消され、この報告もクローズされています。

注目したい点

「作成されたパッケージのバージョン番号が違っている」というつまずきに遭遇したときには、暫定的な回避として「できたファイルのバージョン番号の部分をとりあえず書き換えて済ませる」というような対策を取ることが多いでしょう。そういったその場しのぎだけで終わらせずに開発元にフィードバックすると、同じ問題につまずく人が減ります。

この報告には、問題報告の基本の3要素である「再現手順」「期待される結果」「実際の結果」が揃っていて、再現手順には実際に操作したコマンド列もそのまま記載されています。文章で長々と説明しなくても、要点を押さえてあれば適切に伝わるということがよく分かります。

「期待される結果」「実際の結果」の説明文の英語の表現にも着目してください。

version-gen.sh script should generate "5.9.2" on collectd-5.9.2 tag.

「パッケージ作成手順に従って作業したら5.9.2というバージョンが付くべき」ということを言い表すのに、リポジトリに含まれているパッケージ作成用のスクリプトを主語にして「このスクリプトはこのような事をするべき」という書き方をしています。日本語で言いたいことを余すことなくすべて英語で言い表そうとしなくても、無生物を動作の主体として明記することで簡潔に表現できるという好例でしょう。

このフィードバックの面白いところは、ソフトウェアそのものの不具合というよりも、プロジェクトのリリースマネジメントへのフィードバックとなっているという点です。プロジェクトにおいて作業を複数人で分担している場合に、そのときの作業者の属人的な知識に依存したまま体制が組まれてしまっていると、他の人に作業が引き継がれた後にこのような形でトラブルが起こる場合があります。このフィードバックがなされていなければ、新しい担当者は次のリリースで同様の問題に遭遇し、原因の究明に奔走する羽目になっていたかもしれません。

まとめ

ノータブルフィードバックの3回目として、コードでもドキュメントでもない部分へのフィードバック例をご紹介しました。

このような「身近なところで遭遇したつまずきをOSS開発プロジェクトにフィードバックする」ということをテーマに、まだOSSにフィードバックをしたことがない人の背中を押す解説書 「これでできる! はじめてのOSSフィードバックガイド ~ #駆け出しエンジニアと繋がりたい と言ってた私が野生のつよいエンジニアとつながるのに必要だったこと~」を、2月29日に電子書籍としてリリースします。本記事の内容はこの本からの抜粋となっています。ダウンロード購入のチャンネル、紙媒体版などの詳細については、は前々回記事を併せてご参照下さい。

書評のご紹介

前回記事に続き、筆者が個人的にご縁のあった関係で、イラストレーター業とWebデザイナー業を並行しておられるえす吉さんより書評を頂きましたのでご紹介します。ありがとうございます!

全体を通して豊富な実例とあわせた解説がされていて、最後まで詰まることなく読み進められました!

初心者が不安に感じる箇所を章ごとに丁寧に解消してくれるので、読み終わる頃には、この本を片手にまずは身近な問題に一歩踏み出してみよう、と思える内容だと感じました。

実際にそのOSSを切実に必要としている人からのフィードバックは、OSSの使い勝手やドキュメントの質の向上のために非常に重要です。また、Webサイトの「アプリ化」がめざましい昨今では、Web制作とOSSの関係性はより密になってきています。えす吉さんのようにWeb制作の現場でOSSをユーザーとして利用される立場の方からもOSSへフィードバックすることのハードルが下がって、仕事環境や成果物が改善されていくことに繋がれば何よりです。

2020-02-28

Firefoxでデフォルト有効化されるかもしれないDNS over HTTPSへの企業での対応について

昨日、Firefoxの米国エリアユーザーに対して段階的に「DNS over HTTPS」の有効化が反映されていくことになった、という話がニュースになっていました。

DNS over HTTPSとは?

今までの名前解決との違い

DNSとは、www.clear-code.comのようなドメイン名の文字列を153.126.132.63のようなIPアドレスに解決する(名前解決をする)という、インターネットにおけるかなり根幹の部分を支えている仕組みです。

この問い合わせ・応答の通信は特に暗号化も認証もなされていないため、問い合わせ内容の盗聴や応答の偽装が技術的には可能となっています。身近な場面では、空港や飲食店などのパブリックWi-Fiでそのような攻撃を受ける恐れがあるほか、地域によっては政府主導で盗聴・検閲が行われているケースもあるといいます。DNS over HTTPSは、このような脅威からユーザーを守る技術であるとされています。

ただし「DNS over HTTPSであれば何もかもが安全になる」というわけではないことに注意が必要です。DNS over HTTPSで安全になるのは全体の中のごく一部のやり取りのみで、それ以外の部分については別の技術的手段での保護が依然として必要です。また、組織内のみのドメインが名前解決できなくなるようなトラブルや、CDN*1の性能が発揮されないといった問題が起こる場合もあります。

具体的にDNS over HTTPSによって何が守られて何が守られないのかについては、ISP*2であるIIJの技術者向けブログの以下の記事に詳しい解説がありますので、ぜひご参照下さい。

FirefoxでのDNS over HTTPS

Firefoxはセキュリティやプライバシーの保護を理由として、DNS over HTTPSを推進していくことを以前から発表しています。今回行われたのは「米国地域内のユーザーに対して、DNS over HTTPSをデフォルト有効にする」という変更でした。

Firefox上でDNS over HTTPSを使用する場合の注意点・無効化の方法などは、以下の公式のサポート情報に記載があります。

企業運用においてFirefoxのDNS over HTTPSを強制的に無効化するには

Firefoxを企業内で運用する場合、現時点で直接的に影響を受けるのは米国地域内の拠点だけということになります。しかし、今後DNS over HTTPSが全世界で有効化されていく可能性はありますし、また、現時点でもユーザーが任意に機能を有効化できます。使われると企業内のセキュリティポリシーを守れない、などのさまざまな理由から、社内ではDNS over HTTPSを使わせたくないということもあるでしょう。

そのような場合、以下の方法でDNS over HTTPSを無効に固定する(ユーザーが任意に有効化できなくする)ことができます。

Windows Server 2008以降のバージョンでActive Directoryによるドメイン管理が行われている場合
  1. .admx形式のグループポリシーテンプレートと言語リソースをダウンロードする。ここでは policy_templates_v1.13 をダウンロードしたと仮定する。
  2. ダウンロードしたファイルの名前を変更し、末尾に.zipを付ける。
  3. ファイルをZIPアーカイブとして展開し、windows フォルダ内のすべてのファイルを、ドメインコントローラの C:\Windows\SYSVOL\domain\Policies\PolicyDefinitions に設置する。
  4. グループポリシーの管理画面を開き*3、「コンピューターの構成」の「ポリシー」→「管理用テンプレート」→「Mozilla」→「Firefox」で「Configure DNS Over HTTPS」をダブルクリックする。
  5. ポリシーを「有効」にし、以下の通り設定する。
    • 「Enable DNS over HTTPS.」のチェックを外す。
    • 「Don't allow DNS over HTTPS preferences to be changed.」のチェックを入れる。

このように設定しておくことで、そのドメインに参加しているWindows端末上で動作するFirefoxでは常にDNS over HTTPSが無効となります。

macOSの場合
  1. 端末を開く。

  2. 以下の3つのコマンド列を順番に実行する。

    sudo defaults write /Library/Preferences/org.mozilla.firefox EnterprisePoliciesEnabled -bool TRUE 
    sudo defaults write /Library/Preferences/org.mozilla.firefox DNSOverHTTPS__Enabled -bool FALSE 
    sudo defaults write /Library/Preferences/org.mozilla.firefox DNSOverHTTPS__Locked -bool TRUE 
    

このように設定しておくことで、そのマシン上で動作するFirefoxでは常にDNS over HTTPSが無効となります。

それ以外の場合(Windows、Linux)
  1. Firefoxのインストール先(Firefoxの実行ファイルがあるフォルダ)に distribution という名前でフォルダを作成する。

  2. 以下の内容のプレーンテキストファイルを作成し、policies.jsonという名前で1のフォルダ内に設置する。

    {
      "policies": {
        "DNSOverHTTPS": {
          "Enabled": false,
          "Locked": true
        }
      }
    }
    

このように設定しておくことで、その位置にインストールされているFirefoxでは常にDNS over HTTPSが無効となります。

この方法は、Active Directoryを運用していない場合や、シンクライアント端末からWindows Serverにリモートデスクトップ接続してFirefoxを使用する場合などに有用でしょう。

Canary Domainを利用する方法

ポリシー設定を使う方法とは別のやり方として、Canary Domainを使用する方法があります。具体的には、use-application-dns.net について NXDOMAIN を返すようにそのネットワーク内のDNSを設定しておくことにより、Firefoxはそのことを検出し、自動的にDNS over HTTPSを使用しなくなります。

これについての詳しい解説は、以下の記事をご参照ください。

社外に持ち出して使用することがある端末(ラップトップPCなど)が存在していて、社内ではDNS over HTTPSを無効化したいが、社外ネットワークでの利用に関しては特に制御したくない、という場合には特にこの方法が有用でしょう。

まとめ

DNS over HTTPSの概要と、ポリシー設定等を使って企業内でFirefoxのDNS over HTTPS動作を常に無効化する方法をご紹介しました。

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

*1 Content Delivery Network。動画などのネットワーク転送負荷が高いデータについて、名前解決時にホストをネットワーク的な距離が近いホストに解決することで、ネットワーク負荷を下げたりデータ転送にかかる時間を短縮したりするための仕組み。

*2 Internet Service Provider。インターネット接続事業者。

*3 Windows Server 2008では「Active Directory ユーザーとコンピュータ」を開き、ドメイン名を右クリックし「プロパティ」をクリックして、「グループポリシー」タブで「編集」ボタンをクリックする。Windows Server 2012では「グループ ポリシーの管理」を開いて「Default Domain Policy」を右クリックし「編集」を選択する。

タグ: Mozilla
2020-02-27

最新記事
タグ:
年・日ごとに見る
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|