ヘルプの憂鬱
複雑なシステムにはオンラインヘルプやマニュアルが用意されているものですが、パソコンやアプリケーションの解説本が大量に売られているところを見ると、ヘルプやマニュアルは十分役にたってはいないようです。
ヘルプが利用されない最大の理由は必要な項目が見つからない ことでしょう。たとえばMacを米国時間に設定したいと思って「米国時間」で検索すると図1 が表示されます。
図1 米国時間で検索すると……
これではわけがわからないので「時間」で検索すると、より多くの項目が表示されますが(図2 ) 、米国時間の設定には関係なさそうです。
図2 さらに「時間」で検索すると……
「時刻」や「時計」で検索すれば「日付と時刻」環境設定」という項目が見つかりますが、これで米国時間に設定できるのかはよくわかりませんし、そもそも「米国時間」や「時間」でも検索できるべきではないでしょうか。
必要な項目が見つかった場合でも、そこに記述されている方法は自分で実行する必要があります。ユーザはMacを米国時間に設定したいだけであり、時刻やタイムゾーンを設定する方法を知りたいわけではないのに、ヘルプシステムは一般的なやり方しか教えてくれませんから、ユーザは自分で環境設定パネルを開いて、米国時間に設定する必要があります。
このように、たいていのヘルプシステムは、
という問題があることになります。一方で、最近は普通にWeb検索すればそれなりに有用情報が見つかることが多いため、ヘルプシステムへの期待が低くなってしまっているのだと思われます。
ExpandHelp
Web検索に苦労することが少なくなってきたのは、検索エンジンの性能が向上したこともさることながら、情報の量がすごい勢いで増えてきたことによる影響も大きいでしょう。どこかのブログに「Macの時計を米国時間に設定する方法」という記事があれば、普通に「Mac 米国時間」で検索すれば見つかる可能性が高いと思われますが、さまざまな表現で情報が表現されていれば検索に成功する可能性が高くなる と言えるでしょう。
Generate and Filter
パズルを解く方法として「Generate and Test 」と呼ばれるアルゴリズムがあります。たとえば「数独」を解こうとする場合、理屈で推論して空きを埋めていくのではなく、あらゆる数字の組み合わせを生成 して順番に試して みれば、時間はかかるかもしれませんが必ず最終的に答が見つかるはずです。これはひどく効率が悪いやり方に見えますが、明らかに間違っている組み合わせを早目に無視するような工夫をすれば、このような簡単なアルゴリズムでもうまくパズルを解くことができる場合があります。
ヘルプの検索でもこれに似た方法を使うことができます。ヘルプデータやWebをキーワード検索する場合、検索対象は固定であり、それを検索するためのキーワードをユーザが工夫するのが常識になっています。たとえば「時間」というキーワードを使って、米国時間に関連した情報を探すことに失敗した場合は「時刻」や「タイムゾーン」のような別のキーワードで再検索を試みるのが普通でしょう。これは結果的に「(時間¦時刻¦タイムゾーン)
」のような正規表現で検索したのと同等ですから、ユーザにとっては面倒な話ですが、Web検索でもファイル検索でもこういうやり方があたりまえになっているので、これをとくに苦痛だと思っていない人も多いかもしれません。
しかし本当にユーザにとって便利なヘルプ情報を提供しようとするならば、ユーザに検索語を工夫させるのではなく、「 米国時間にセット」でも「タイムゾーンを設定」でもヘルプエントリを検索できるように、あらゆる表現でデータを用意しておくほうが親切です。たとえばヘルプシステム側に「タイムゾーンを(米国¦英国)(時間¦時刻)に(設定¦セット¦変更)
する」のような正規表現を用意しておき、これを使ってあらゆるヘルプ表現の組み合わせを生成 し、ユーザの与えた検索語でフィルタリング することにすれば、「 米国時間にセット」でも「タイムゾーンを設定」でもヘルプが見つかるようになるはずです。
Generate and Test であらゆる解の候補を生成してから解のチェックをするのと同じ要領で、あらゆる説明文字列のパターンを生成 しつつ、その中でユーザの検索文字列とマッチするものでフィルタリング を行う「Generate and Filter 」方式を使えば、ユーザはキーワードについて頭を使うことなく検索に成功する可能性が高まります。このような手法をExpandHelp と呼ぶことにします。
展開されたデータは巨大になってしまう可能性がありますが、最近のパソコンでは多少大きなデータを利用しても問題ありませんし、Generate and Testの場合と同じように実装を工夫すれば、実際にすべての文字列を展開せずに検索を行うこともできます。
ヘルプ項目の実行
ヘルプ項目の検索に成功した場合、記事を参照しながらユーザが自分で操作を行う必要があります。この手間をなくすには、ユーザが指定した検索キーワードを基にして、ユーザの意図に合致する操作コマンドをシステムが生成して実行できる ようにすれば良いでしょう。
「米国時間」でヘルプ検索に成功してユーザの意図どおりの結果が出た場合、ユーザの意図は正しく検索システムに伝わっていることになりますから、そのままシステムに実行を指示できます。タイムゾーンを設定するtimezone
というコマンドが存在したとすると、「 米国」のようなパラメータを使って、「 timezone 米国
」を起動できます。
Mac版ExpandHelp
このような考えに基づいて、Mac版のExpand Helpを試作してみました。MacのExpandHelpはメニューバーに常駐するアプリケーションで、キーワードを入力するとそれに関連したヘルプが表示されます(図3 ) 。たとえば「3:45」と入力すると、3:45という時刻に関連するコマンドがメニューに表示されます(図4 ) 。
図3 Mac版ExpandHelpの起動
図4 関連するコマンドが表示される
ここで「時刻を3:45にセットする」を選ぶとdate コマンドが実行されて、システムの時刻が3:45にセットされます。
ExpandHelpのヘルプデータは図5のような配列として表現されています。
図5 ExpandHelpのヘルプデータの構造
「(時計¦時間¦時刻)を(0¦1¦2¦3¦4¦5¦6¦7¦8¦9¦10¦11¦12):(0¦1¦2¦3¦4¦5)(0¦1¦2¦3¦4¦5¦6¦7¦8¦9)(AM¦PM)に(セットする¦設定する¦あわせる)
」を展開したパターンのうち3:45にマッチするものが表示され、「 時刻を3:45にセットする
」を選択するとsetdate(3,4,5)
が実行されます。
GitHelp
Mac版のExpandHelpは毎日使うようなものではないにもかかわらずヘルプデータの用意は面倒なので、結局あまり使わなくなってしまいました。万人向けの一般的なヘルプデータを用意するのはたいへんですが、自分が毎日のように使う複雑なシステムの利用を助けてくれるシステムならばもっとうれしいだろうと考え、Gitのヘルプシステム「GitHelp」を作ってみました。
バージョン管理システム「Git」は、最近プログラマの間で広く使われていますが、基本概念もコマンド構成も複雑なのが難点です。Gitには100個以上のサブコマンドが存在するうえに各サブコマンドの仕様も複雑です。バージョン履歴のログを表示する「git log
」コマンドのマニュアルページは2,000行近くもあり、これだけでも機能を理解するのは困難になっています。
Gitのコマンドに詳しいユーザでも、ちょっと標準と異なることをやりたい場合には、Gitの機能をどう組み合わせて使えば良いのか悩むことがあります。ユーザのさまざまな要求に対して良い解決手順を記述しておき、ExpandHelpの要領で検索できるようにしておけば便利です。GitHelpはGitに関するExpandHelpをコマンドラインから使えるようにしたシステムです。
たとえば「昨日のREADME.mdを見たい」と思っても、標準的なGitコマンドや引数でこれを実行することは簡単ではありません。git log
コマンドでREADME.mdの編集履歴を参照し、昨日のコミットIDを見つけて「git cat-file-p (コミットID):README.md
」のようなコマンドを起動すれば良いのですが、これはなかなか面倒な作業ですし操作を覚えるのはたいへんです。実はコミットIDを取得しなくても「git cat-file-p "@{yesterday}":README.md
」というコマンドで実行できるのですが、こういうマイナーな機能があることを知っているユーザは多くないでしょう。
GitHelpでは、「 昨日の(#{pat})
ファイルを表示する」という説明パターンと「git cat-file-p "@{yesterday}":#{$1}
」というコマンドパターンのペアを用意しておくことにより、「 昨日」「 README」のようなキーワードを指定するだけで 必要なコマンドを検索してリストできます。
$ githelp 昨日 AD
[0] 昨日の「README.md」ファイルを表示する
% git cat-file -p "@{yesterday}":README.md
[1] 昨日の「data/adddelete.rb」ファイルを表示する
% git cat-file -p "@{yesterday}":data/
adddelete.rb
[2] 昨日の「data/afteradd.rb」ファイルを表示する
% git cat-file -p "@{yesterday}":data/
afteradd.rb
$
ここではコマンドの候補がリストされているだけですが、-x
オプションを指定すると候補を選択して実行させることができます。
$ githelp 昨日 AD -x0
# GitHelp
**Gitのコマンドの使いこなしを支援**
### 解決したい問題
...
GitHelpのヘルプデータはリスト1 のような配列になっています。各配列要素の1行目がヘルプ文字列のパターンになっており、2行目がそれを実行するためのコマンド文字列になっています。
リスト1 GitHelpのヘルプデータ
[
[
"昨日の「(#{files.join('¦')})」ファイルを(表示する¦見る)",
'git cat-file -p "@{yesterday}":#{$1}'
],
[
"「(#{files.join('¦')})」ファイルを (#{numbers.join('¦')})日前の (もの¦バージョン)と比較する",
'git diff HEAD "@{#{$2} days ago}" #{$1}'
],
[
"「(#{files.join('¦')})」ファイルをひとつ前のコミットと比較する",
'git diff HEAD^ #{$1}'
],
[
"(#{numbers.join('¦')})日前から(変化した¦変わった¦変更された)ファイルをリストする",
'githelp-changed \'#{$1} days ago\''
],
README.md、Rakefile、...
のようなファイルがGitに管理されている環境において、ユーザが「githelp 昨日 AD
」を実行すると、files()
の結果が['README.md', 'Rakefile', ...]
のような値になるので、最初のパターンは"昨日の「(README.md¦Rakefile¦...)」ファイルを(表示する¦見る)"
のようになります。この正規表現を展開した結果得られる文字列の中の「昨日のREADME.mdファイルを表示する
」という文字列がユーザの与えたキーワード「昨日
」「 AD
」とマッチするので、それに対応するコマンド「git cat-file-p "@{yesterday}":README
」を実行できるようになります。
このようにGitHelpでは、やりたいことの一部を示すだけでヘルプ情報を検索し、実行まで行うことができることがわかります。
ExpandHelpの実装
今回はRubyで正規表現展開ライブラリre_expand
をまず実装し、それを使ってExpandHelp
を実装しています。
ExpandHelpはアイデア自体は単純なのですが、正規表現の展開が必要なのでre_expand
も含めると残念ながら実装はちょっと複雑になってしまいました。しかし、ヘルプなどの検索を行うときにGenerate and Testのような方法が有効だということに気づいたのはコロンブスの卵的だと思っています。GitHelpは実際毎日のGit活用に有用なので、ヘルプデータをもっと整備して毎日使っていこうと考えています。
GitHelpはhttps://github.com/masui/GitHelp
で公開しており、「 gem installgithelp
」で簡単にインストールできるので、ぜひご利用ください。
第1特集
MySQL アプリ開発者の必修5科目
不意なトラブルに困らないためのRDB基礎知識
第2特集
「知りたい」「 使いたい」「 発信したい」をかなえる
OSSソースコードリーディングのススメ
特別企画
企業のシステムを支えるOSとエコシステムの全貌
[特別企画]Red Hat Enterprise Linux 9最新ガイド
短期連載
今さら聞けないSSH
[前編]リモートログインとコマンドの実行
短期連載
MySQLで学ぶ文字コード
[最終回]文字コードのハマりどころTips集
短期連載
新生「Ansible」徹底解説
[4]Playbookの実行環境(基礎編)