Home > Latest topics

Latest topics > Firefoxアドオンの開発を通じて考えるようになったインタラクションデザイン

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

Firefoxアドオンの開発を通じて考えるようになったインタラクションデザイン - Jun 30, 2011

あかつかだいすけさんのご紹介で、6月27日に慶応大学湘南藤沢キャンパスでインタラクションデザインについての講義を1時間ほどやらせていただきました。その際の発表資料はいつもの通り「高橋メソッド in XUL Returns」で作ったのですが、Remote XULがデフォルトで禁止されるようになったFirefox 4以降だとこれを見るためには色々と面倒が多いので、代わりに講義の内容を思い出しながら資料を引用しながらエントリにまとめてみたいと思います。

事前に伺っていたオーダーは、これまでのアドオン開発の中でUIという点についてどういうデザインポリシーを持って開発してきたのかを、また、コンセプトを実装する際の経験から得られた知見を語るというものでした。今までにもこの場やTwitter等で断片的に語ってきている事ではありますが、改めて整理するいい機会になったと思います。

自己紹介

まず簡単に自分の事をお話ししておきましょう。

僕は大阪出身の28歳で、Firefoxのアドオンとの関わりは「Firefox」というプロダクトが世に出るより前からなので、もうそろそろ10年になろうとしています。アドオンをやり始めた頃は大学1年とか2年とかの頃だったと思いますので、講義を聴いていただいた皆さんくらいの年の頃からということになります。卒業制作(僕のいた学科では卒論ではなく卒業制作、しかも選択制だったのです……)もMozillaの拡張機能で「2次元的にWeb閲覧の履歴を表現する履歴表示UI・兼・Webブラウズ用UI」という物だったので、余計に感慨深い物があります。

そういう僕ではありますが、今はクリアコードという受託開発の会社でプログラマとして勤務しており、最近はRubyでWebサービスを作るといった案件に関わっています。仕事の上でインタラクションデザインの事を考える事は実際の所ほとんどなくて、そういう事を実践する機会趣味のアドオン開発の場面くらいしか無いというのが実情です。(きちんとインタラクションデザインの事について学んでいる人に比べると、おそらく物凄く初歩的な事しか理解していない、本来であれば人前でインタラクションデザインについて一席打っていいような立場ではないとは思っています。)

自分はこの何年かで数だけはやたら多くのアドオンを開発してきましたが、インタラクションデザインという観点から語りやすそうな物として、以下の4つを特に取り上げて語ってみたいと思います。

  • ツリー型タブ:タブバーをウィンドウの上ではなく左に移動して、タブを縦に並べて表示し、タブの親子お関係をインデント幅で表現する。
  • マルチプルタブハンドラ:複数のタブをドラッグで選択して、まとめて閉じたりリロードしたりと言った操作を可能にする。
  • Fox Splitter:Firefoxのウィンドウを複数の表示領域に分割し、複数のページを平行して閲覧できるようにする。
  • セカンドサーチ:FirefoxのWeb検索バーにおいて、文字を入力した後で実際に使う検索エンジンを選べるようにする。

自分がUIをデザインする時に気をつけている事

5W1Hで目的をはっきりさせる?

ニュース記事を書く時の5W1Hという原則をご存じでしょうか。

  • 誰が(Who)
  • いつ(When)
  • どこで(Where)
  • 何故、何のために(Why)
  • 何を(What)
  • どのようにしたのか(How)

これらをきちんと抑えた文章にする事で、一体何の記事なのか、どういう事が起こったのか、という事を読者に過不足無く伝えられるという原則が5W1Hです。

僕は、UIのデザインにおいてもこれらの5W1Hが重要だと思っています。

  • 誰が(Who)
  • どういう利用局面で(When、Where)
  • どういう目的で(Why)
  • 何を(What)
  • どのように操作するのか(How)

これらを満たす事のできるUIを考える、というのが出発点としては分かりやすいのではないか。闇雲に「何か新しいUIを」と考えるよりも、これらを意識した方がゴールを設定しやすいのではないか。という事です。

何事でも目的は大事です。特にソフトウェア開発では、無目的に「単に技術的に可能なので作ってみました」という風に生み出したプロダクトがあっても、自分で使わないし誰も使わないために、そのまま死んだプロジェクトになってしまう恐れがあります。

ただ、それとは逆の場合もあると僕は思っています。「単に技術的に可能なので作ってみました」という物を、試しに自分で使ってみたら案外使い勝手が良かった。常用するためにもっと改良したくなった。というケースが僕には実際にありました。ツリー型タブは、元を正せばそのようにして生まれたアドオンです。

ツリー型タブの誕生の経緯

かつて僕はタブブラウザ拡張(Tabbrowser Extensions、TBE)という、Mozilla SuiteやFirefoxの貧弱なタブブラウズ機能をなんとなくいい感じにパワーアップするというようなオールインワン型のアドオンを開発していました。

その頃既に僕は、10とか20とかの多数のタブを同時に開いてWebを閲覧するという使い方をしていました。そういう使い方だと、通常の横一列のタブバーだと、今見ているタブが画面外に吹っ飛んでしまったり、さっきまで見ていたタブがどこに行ってしまったのか分からなくなったり、という具合に色々困った事が起こります。それで僕は2つの機能をTBEに持たせていました。

  • タブバーを多段表示して、1度に多くのタブを見えるようにする。 (タブバーを多段表示した様子)
  • タブを色分け表示して、どのタブからどのタブを開いたのかという親子関係を色で示す。 (タブを色分け表示した様子)

「多段タブ」は、僕がWindows 95を使い始めた頃から時々見かけていたインターフェースでした。Windowsのコントロールパネルで多数の設定項目を持つ項目を開いた場合に、そのダイアログが多段タブになっている場合があったからです。タブが多ければ2段や3段に分けて表示すればいい、というのは日常的に使うWindows自体の一般的なUIを見ていれば自然と思い浮かぶ発想でしょう。

タブの色分け表示は、元々は何か他のブラウザがそういう機能を持っていたのを真似て実装したような記憶があります。親となるタブと子タブとを同じ色で表示しておけば、タブの親子関係が一目で分かるようになります。IE7でもリンクからタブを開くとそれと同じようにタブが色分け表示されるようになっていましたが、当時としては、これもまたそう珍しくない機能だったのでしょう。

そこにツリー表示機能を加えるきっかけになったのは、malaさんが自身のブログで紹介されていたiRiderというIEコンポーネントブラウザでした。

livedoor Readerの開発者として知られるmalaさんは昔からJavaScriptで変態的な、もとい、他の人が思い付いたり実践したりしていなかったような先進的な試みを色々とやっている方なのですが、そのmalaさんが2005年に2005年もパクられてこなかったもの私的まとめベスト3というエントリを書かれていた際に、iRiderというブラウザの名前を挙げておられました。今では配布元のドメインが失効していて百式のエントリにあるスクリーンショットくらいしか様子を窺える物が残っていないのですが、あのmalaさんが(「あの」って付けるくらいに、僕はmalaさんの着眼点はいつも鋭いと考えているのです)名前を挙げているくらいなのだからさぞかし凄い物に違いない!と思ったので、興味本位に加えて腕試しにという思いもあって早速TBEに「タブの親子関係を色分けだけでなくツリー表示というシルエットの変化で示す」という機能、あと、リンク先のエントリでも触れられている「撫でるインターフェース」も併せて実装しました(実はこれが現在のマルチプルタブハンドラの原型だったりもします)。

iRiderのツリー表示というのは、実を言えば、「タブのツリー表示」ではありませんでした。ウィンドウの左に表示されているのはあくまで2次元的に表現されたWebページの閲覧履歴であって、それらの履歴項目をドラッグしたりクリックしたりするとウィンドウの右側でページを見る事ができる、というのがiRiderの挙動です。ただ、当時既にTBEが持っていた「全てのリンクを新しいタブで開く機能」「リンクから開かれたタブを現在のタブの子タブとして扱う機能」にいくつかの機能を加えさえすれば、(メモリの消費量等の観点ではオーバーヘッドはあるものの)表面的にはiRiderと同じような挙動を示すようになるだろうという見通しは立っていました。

ちなみに、タブに相当する物をツリーで表示するブラウザというのは当時既にいくつか存在していたようですが、僕はそれらの事を意識していませんでした。というか、ツリー? 一体何がおいしいの? みたいな認識でした。そういうわけなので、この時はタブをツリー表示する拡張機能を作ったというよりも、iRiderの挙動をFirefoxで(無理矢理)再現するというのが、やった事の本質を正しく言い表しています。

そういう事でとりあえず技術的には可能だったから実装してみるだけしてみたのですが、タブを履歴の代わりに使うというのは当時の自分にはあまりに違和感が大きすぎましたし、iRiderの「履歴」と違ってMozillaのタブは開いていればその間ずっとメモリを消費する物であるという背景もあって、自分はこの時実装した機能のうち「タブをツリー表示する機能」だけを、せっかく実装したのだから……と、ずっと使い続けていました。

そしたら、これが案外便利だったんですね。

という事で自分自身がすっかりツリー機能に依存するようになってしまいました。その後メンテナンスしきれなくなったために僕はTBEの開発を中止しましたが、まずは「なでるインターフェース」の再現のために書いたコードを応用して、その機能だけを抽出して「タブを選択してから操作する」というコンセプトで再設計したマルチプルタブハンドラを公開し、さらに続いて、タブのツリー表示機能だけを抽出したアドオンをツリー型タブとして公開して、TBEの頃と同じような使い勝手を保ち続けて今に至っています。

自分が「良い」と思えるUIのデザインポリシーを逆算する

タブのツリー表示のどの点が便利だと感じたのか、自分自身でもそれと意識する事はなかったのですが、ツリー型タブをMozilla主催のアドオンコンテストに出品するにあたってアピール文を書こうとして、改めて「自分がツリー表示されたタブを使いやすいと感じた理由」を言語化してみる事にしました。

その時自分で分析して思いついた「使ってみて分かったツリー表示のいい所」は、以下のようなものでした。

  • 一覧性が高い。(多数のタブを開いていても、縦に重ねた表示形態であればまだ全体を見通せる。)
  • ページを閲覧してきた履歴がそのまま可視化される。(どのタブからどのタブを開いたのか、どのページからどのページへ遷移したのか、という事がツリーとして視覚的に、2次元的に表現される。)
  • タブが自分の存在を主張してくる。(ブックマークフォルダの奥にしまい込んだ時のように、存在を忘れてしまわないですむ。未消化のタスクがタブとして溜まっていくと、タブバーをだんだん圧迫してきて、「片付けなきゃ」という意識を僕自身に喚起させる。)

これらをもっと突き詰めて一言にまとめると、「ツリー表示であればうろ覚えでも使える」からこそ自分は利便性を感じたからなのではないか。それが自分の辿り着いた結論でした。

うろ覚えで使える、とはどういう事か。もう少し具体的に考えてみましょう。

  1. ボケーッとしてても使える。
    • どこに何があったんだっけ、という事を憶えてなくてもUIを見れば必要な情報がそこにある。
    • 且つ、それらがうるさく主張しすぎてもいないので、多すぎる情報を前にして迷う事がない。
  2. 考えなくても使える。さあこれからこのタスクをこなそう!といちいち気張らなくても使える。
  3. 初見でも使える。使い方を知らない状態で初めて使う時でも、戸惑わないで済む。
  4. 忘れても使える。使い方を忘れてしまって、初めて使う時の感覚に戻ってしまっても、初見と同じようにすぐ慣れる事ができる。
  5. 既存の物に似ている。それ自体の使い方を特別に覚えなくても、他の物からの類推で違和感なく使える。

1は、表示される情報が適切な量になっているという事だと言えると思います。2から5は、学習コストが低いという事です。どうやら僕は、これらの点を満たしている時に「良いUI」と感じているみたいです。

適切な情報量とは

この点はSFCでの講義では話せていなかった点ですが、このまとめでは書いておきます。

情報が適切に整理されている、という事は非常に重要です。例えばある家具屋さんの折り込みチラシを見てみましょう。 (チラシの画像。様々な商品の情報が所狭しと押し込まれている。) この種のチラシは「新春初売りセール開催中ですよ!」という事を顧客に告知して集客する事を第1の目的に、そして売り込みたい商品にどういう物があるのかをなるべく多く知らせる事を第2の目的にしていると考えられます。情報を見やすく整理するという事はあまり重視されていないので、余白を設けるよりも、少しでも多く情報を詰め込む工夫が為されています。顧客はこのチラシの中から目を皿のようにして安い商品を探す事になります。セールのチラシの場合は顧客には「そこにどんな情報があるのかをじっくり読み取る努力をするモチベーション」がありますから、多少の苦難は乗り越えられます。

しかしブラウザのUIは、使い手の側にそれほど強いモチベーションはありません。「さっきまで見ていたタブ」を見つけるためにいちいちこのようなゴチャゴチャした絵面の中を一生懸命探すのは、ただのストレスにしかならないでしょう。常用するUIがこんな感じではとても使えません。

視覚的な情報の量を調整するテクニックはいくつかあります。DTPのセオリーやWeb制作のセオリーなどを読んでもらうといいと思いますが、今自分でもぱっと思いつく物としては以下の4項目があります。

  1. 適切な余白を設ける。要素と要素を詰め詰めに配置しすぎない。(詰め詰めに配置すると、誤操作の元にもなり得る。)
  2. 同じ種類の要素は近くにまとめたり、同じ位置に揃えたりして、グループとして認識できるようにする。
  3. 色を整理する。バラバラの色を混在させないで、同じような物は同じような色でまとめておく。そうする事で、特別な場合にだけ色を変えるという事が「特別」として活きてくる。
  4. 色ではなくシルエットで判別させる。モノクロディスプレイだったり色盲だったりといった色の違いが分からない状況でも、シルエットの違いなら認識できる。また、一般的に色の違いよりも形の違いの方が人は認識しやすい(とどこかで聞いた気がする)。

ツリー型タブによる縦型タブバーの場合、2から4が特に顕著だと僕は考えています。

(ツリー型タブのスクリーンショット) スクリーンショットを見ると分かりますが、縦にUI要素が揃う事で、左にアイコン(とインデント)、真ん中にタイトル、右に「タブを閉じる」ボタンが集まっています。 (ツリー型タブと情報化タブの併用時のスクリーンショット) ここにサムネイルというUI要素が加わっても、縦に同じような位置に同じような物が並んでいるので、これはまとめて意識の外に置いておきやすいはずだ、と僕は思っています。実際、自分はこのようなタブバーの左の方を見ている時は右側を無視していますし、右側を見ている時は左側を無視している気がします。

逆に、横置きのタブバーでは、「アイコン、タイトル、クローズボックス、アイコン、タイトル、クローズボックス……」とそれぞれ異なるUI要素が一列に並んでいるので、「アイコンにだけ注目する」とか「クローズボックスにだけ注目する」という事がやりにくいと僕は思っています。

タブの親子関係は、タブの色分けではなく、インデント幅というシルエットの違いで表現されています。これなら、2段階以上のネストであっても状態を正しく把握できるでしょう。

視覚的な情報の整理の仕方はデザインの本を学ぶと色々と情報を得られると思います。自分は一時期Webデザイナーになりたいと考えていたので、DTP的な記事が多く載っていたWebデザイン雑誌も何度か目にしていたのですが、上記のような話はそういった所で仕入れた物のような気がします。

学習コストを低くするためには

ヒューマン・インターフェースのデザインのセオリーという物がいくつかありますが、それらはソフトウェアにおけるインターフェースのデザインにも適用できます。

見た目の工夫

何のための物か、何を表している物なのか、説明がなくても一目で分かるようなデザイン。形がそれ自身の役割を表す。これはUIのデザインでよく言われる事です。

ソフトウェアの場合は、まずそのOSにおける一般的なデザインの流儀に則ってUI要素をデザインしておけば、少なくとも「ここはクリックできる場所なのだな」といった事を伝えられます。その上で適切なアイコン画像を加えましょう。基本はやはり重要です。

見えているUI要素はそのまま使えるようにする、という事も大事です。「見えているのに使えない」「見た目通りには動かない」というのは、ユーザを惑わせるばかりの害悪です。例えば以下のような物は論外でしょう。

  • グレイアウトされていないのに、クリックしても何も反応しないボタン。
  • グレイアウトされているのに、クリックを受け付けるボタン。
  • いかにも押せそうな風に出っ張った視覚的なデザインであるにもかかわらず、ボタンになっていない。

基本的に、人は他の場面で憶えたやり方を別の場面でも使いたくなるものです。タブを掴んで移動できる、という体験をExcelでやった後であれば、Firefoxのタブも掴んで移動できると考えておかしくないでしょう。UIの基本的なルールを統一しておく事の意義はそこにあります。

ですので、奇をてらってワケの分からないUIにするよりも、まずは既存の類似のソフトウェアの挙動に合わせる事ユーザがこれまでに学習してきた事に反しないようにする事。これをまずは意識しておくのが大事です。AndroidアプリのUIガイドラインなど、各OSで何らかのデザインのガイドが提供されているのであれば、目を通しておいて損はないです。

ツリー型タブも、タブをドラッグ&ドロップした時の挙動はAdobe Illustratorのレイヤーの操作をモデルに整備しました。また、マルチプルタブハンドラも「Ctrl-クリックでタブの選択状態をトグルする」「Shift-クリックで複数のタブを一気に選択する」という、Windowsやなんかで一般的な操作で使えるようにしてます。こういうのも、既存の物に合わせている例ですね。

見た通りに使えるかどうか、という観点で「こりゃあかんわ、好きになれんわ」と自分が最近感じたUIは、以下の2つのアドオンです。

これらはいずれもFox Splitterと同ジャンルのアドオンで、Firefoxのブラウズ領域を複数に分割してそれぞれに別々のページを表示できるようにする物です。

実際インストールして試してみると分かると思いますが、これらはどちらも、ウィンドウの上の方にあるタブバーやナビゲーションツールバーという操作UIが、タイル表示されたWebページの間で共有される設計になっています。下のペインで「戻る」操作をしたければ下のペインにフォーカスしてから上のツールバーの「戻る」ボタンをクリックする、という具合に、操作の対象と操作のために入力UIがバラバラに切り離されてしまっています。

また、タブと対応するWebページとが離れてしまっているのも問題です。どのタブをクリックしたらどのコンテンツ領域がフォーカスされるのか、どのコンテンツ領域をクリックしたらどのタブがフォーカスされるのか、今どのコンテンツ領域にフォーカスが当たっているのか(フォーカスされているコンテンツ領域の周りには枠が表示されますが、背景色によっては枠がとけ込んでしまう)、といった事を、このUIだとぱっと見て判断しにくいです。慣れれば使えるのかもしれませんが、これに慣れたくはないなあ、というのが僕の正直な感想でした。

UIが常時見えている事、表示UIが入力UIでもある事

入力UIが状態の表示のためのUIを兼ねる、というのもUIのデザインでよく言われるセオリーです。

  • 音量のボリュームをいじるダイヤルは、回した角度が入力となり、また、ボリュームの角度がそのまま音量を示すインジケータになる。
  • ガスコンロのつまみなら、回した角度が入力となり、同時にその角度が火の強さを示すインジケータになる。

ソフトウェアの場合もやはり同じ事が言えます。例えばクリックする度に機能の有効・無効を切り替えるトグル式のツールバーボタン(XULでは<toolbarbutton/>要素)であれば、これはチェックボックス型(<toolbarbutton type="checkbox"/>)としておきましょう。チェックボックス型のツールバーボタンは、1回クリックすると押し下げられたままの見た目で固定され、もう1度クリックすると出っ張った状態に戻ります。これは、入力装置であると同時に、見た目で今の状態を表すインジケータとなります。

ツリー型タブの場合も、タブという元々入力と状態の表示を兼ねたUIであった物を、そのまま少し形を変えて縦に並べています。

使用頻度の高いUIについては、常時見えている事も大事です。クリックしないと出てこない物は、そのワンステップが煩わしくてそのうち使われなくなってしまいます。Firefox 4から標準搭載されているPanoramaもこの問題を抱えていますし、Google Chrome版のTree Style Tab(※作者は僕ではないです)も、Chromeの拡張機能向けAPIの仕様上の制限でそのようになってしまっています。パネル型でもいいので、これを表示したままの状態に固定できるようにならないと、常用するUIとしてはちょっとキツいと自分は思います。僕が自分でツリー型タブをChrome向けに移植しないのは、この点をクリアする方法がまだないように見えるからという理由もあります。

カーソルを合わせたら自動で出てきて、カーソルを外したら自動で消える、という物は、場合によっては有用です。

  • 意図しないタイミングで出てきてしまえばストレスになる。
  • 出てきて欲しいのになかなか出てこない(例えば、表示するために1ピクセルの幅の領域の上を正確にポイントしないといけないとか)のもストレスになる。

「自動で隠す」系のUIは、WindowsのタスクバーやGNOMEのGNOMEパネルのような、画面全体の一番端に貼り付くUI以外ではあまり実用的ではないと僕には思えます。(余談ですが、UI要素は大きければ大きいほどそれを操作しやすく、画面の端であればどこでも反応するというボタンやUI要素は「無限の大きさを持っているに等しい」とよく言われます。Windowsでウィンドウを最大化した時に画面の右上にマウスのポインタを移動させてみれば、大雑把に指し示しただけで「閉じる」ボタンがハイライトされる事が分かると思います。)

モーダルよりもモードレス

これは1つ前の話とも少しかぶるのですが、「入力するモード」と「それ以外の操作をするモード」という風な排他的なモード切り替えは、極力避けるべきだというのが僕の考えです。設計を見直して、そもそもモードの切り替えが必要ないようにする、くらいに突き詰めていいと思います。

モーダルなUIは、ユーザの持つメンタルモデルの中にモードの違いがキッチリ組み込まれていればいいのですが、そうでない場合(ユーザのメンタルモデルの構築に失敗している場合)には混乱の元になります。いつもやっている操作を違うモードでやっても何も反応しない。でもユーザは、モードが違うせいでそうなっているという事に気付かない。「違うモードなのでその操作はできませんよ」と警告を出しても、根本的な解決にはなりません。

この観点で僕がどうしても好きになれないソフトウェアの代表例が、viとかvimとかVimperatorとかそのあたりという事になります。vi系のエディタはコマンドモードと編集モードを行き来しながら操作するという設計になっていて、この種のストレスを自分はしょっちゅう感じます。

単機能・明確なコンセプト

これは「UI」というよりも、もっと前の段階のテーマ決めの話になるかも知れません。

「何でもできる」という謳い文句は、「何をすればいいか分からない」という問題と表裏一体です。何をするための物なのかとか、どう使うべき物なのかとか、それを使う事で自分の生活がどう変わるのかとか、そういった事が伝わってこないとユーザは戸惑ってしまいます。先程、視覚的なデザインによって目に飛び込んでくる情報を制限して情報量を抑えるという事を述べましたが、コンセプトの設定にも同じ事が言えます。

「これができる」「これをする物だ」という事がはっきり見えていればいるほど、メリットが見やすくなるのと同時に、どういうデメリットがあるのかも見やすくなります。基本的にアドオンのインストールには多かれ少なかれデメリットがつきまとっていますが、そのデメリットを乗り越えてでも欲しい機能があるのだという人と、そういうデメリットがあるのであれば絶対に使いたくないという人とをきちんとスクリーニングできれば、ユーザを無駄に不幸にさせずに済むというのが僕の考えです。

カスタマイズ性の高い設計にしていたとしても、というか、カスタマイズ性が高い場合にこそ、既定の設定は重要です。第一に想定しているユーザ、この人にまずは使ってもらおうと思っている相手が、違和感なく使えるような設定をデフォルトにしておきましょう。インストールした後必ず自分に合わせた設定の変更を行わなくてはならないのでは、使い始める時の心理的コストが大きくなってしまいますし、そもそも、使う前から「どういう設定が望ましいか」をユーザが判断するというのが土台無理な話です。

また、最近はいろんな機能を1つのUIに統合する事が流行っているような感じがあると思いますが、「何でもできるUI」として1つのUIに2つも3つも機能を詰め込んでしまうと、実際の利用時に却って不便になる事もあります。

Firefoxのロケーションバーと検索バーを統合して「普通の単語を入力したらGoogleで検索して、URLっぽかったらタブを開いて……」という風な「文脈に応じた自動判別」を行うようにしたとして、「google.comという単語を検索したい」という意図をそのUIは正しく受け取れるでしょうか? 文脈の機械的な自動判別には今のところ限界があるので、誤判定、いわゆる「誤爆」の発生はゼロにはできません。

じゃあ考えられる候補をすべて一気に列挙してしまおう、というのも乱暴すぎる話です。入力欄に何か語句が入力されたら、検索結果を3件、その下に過去の履歴で入力とマッチした物を3件表示する、とした場合、ユーザが最初から「過去に見ていたページをもう一度見たくて」その入力を行っていたのであれば、最初に出てくる検索結果3件はただのノイズになってしまいます。ユーザがその時したい事に対して適切な結果が帰ってこないのは、単純にストレスですよね。

ある機能の利用頻度が特に高いのであれば、その機能には専用のUIを割り当ててやった方がいいです。よく使われている物を無理矢理他の物と統合するというのは、信頼性の低い自動判別を無駄に1枚噛ませるだけになったり、メニューを選ぶための手間を無駄に1つ増やすだけになったりという事になると思うので、僕はなるべくそういう事は避けたいと考えています。

Appleは、コンセプトをはっきりさせるという事を非常に強く実践しています。例えばiPodは非常に割り切った設計で「音楽を聴く」事に特化していて、関係ない要素をガンガン省いていました。それによって、「これは音楽を聴く物なのだ」という事が嫌でもユーザに伝わります。Appleの場合はスティーブ・ジョブズが「これがいい」と言った物を会社を挙げて製品にしており、製品の第1顧客はいつもスティーブ・ジョブズだと言えます。また、キングジム社のポメラも、会議の場で商品の企画が出た時にはほとんどの人が反対したけれど、1人だけ「買いたい」と言った人がいたので商品化できてヒットに繋がったといいます。(余談ですが、リンク先の記事によるとその1人というのは慶応大学の印南教授だそうです。何とも奇遇ですね。)

あらゆる人の方向を向こうとして誰の方向も向けないよりも、誰の方向を向いているのかがはっきり分かるようにした方がいい。100人を満足させようとしてみんなに「ふーん、悪くないね。まあ機会があれば試してみるかもね。」って言われて実際にはそのままスルーされてしまうよりも、99人にそっぽを向かれてもたった1人のユーザに「これすごくいい!!」と飛びついてもらえる、その人を確実に満足させられる方がいい。というのが今の自分の考えです。これだけ物や情報が溢れている世の中では、そうやって製品の特色をはっきりさせないと、評価してもらう前の段階で埋没してしまうのではないでしょうか。

これらの点で僕が「駄目だなー」と思っているのが、かつてのTBETab Mix Plusといったオールインワン型の多機能アドオンです。メリットを一言で説明しにくいから紹介する側も「とりあえずこれ入れとけ」という風な言い方にならざるを得ず、紹介された側はどこが具体的にどう変わるのか・どのようなデメリットがあるのかをきちんと把握できず、それのせいでトラブルが起こったとしても「何をするためのアドオンを入れたからこうなった」という事が全く分からないから原因を切り分ける事もできず、という負の連鎖が起こってしまいます。

先に入力を受け付けておいて、どうするかは後で選べるようにする。思考を途切れさせない。

僕が持ってる携帯電話は、待ち受け状態で数字をぽちぽち入力すると、その数字を電話番号として電話をかける以外にも、電卓機能を起動したり、積算メモ(簡易家計簿)に記入したり、という風な事ができます。メニューから「電卓」を起動して数値を入力するのでも、積算メモ機能を起動してから金額を入力するのでもなく、数字をぽちぽち入力したら画面の中で「この数字を電卓に流し込みたい時はこっちのボタンを押す」「この数字を積算メモに記録したい時はこっちのボタンを押す」という誘導が行われるんですね。

僕はどうも、そういうUIが好きみたいです。セカンドサーチは、Web検索バーで文字を入力した時に「既定の検索エンジンで検索するの? Amazonで検索するの? それとも英和辞書?」という具合に利用できる検索エンジンをポップアップで列挙して、文字入力からそのままスムーズに検索エンジンの選択に移れるようにする……というアドオンですが、前述の携帯電話のUIと考え方は共通していると思います。(なお、僕がセカンドサーチを作ったのはこの携帯電話を使い始めるよりずっと前でした。)

思い返してみると、セカンドサーチを作った動機は、「検索エンジンを選んでから検索して、また元のGoogleに戻して、という操作が死ぬほどめんどくさい。やってらんない。」という不満からでした。

エンジンを切り替えるのが面倒だから、大抵既定の検索エンジンで済ませちゃう。たまに検索エンジンを切り替えて使うと、その後無意識のうちに既定のGoogleで検索したくなって、しかし検索エンジンを切り替えたという事実をすっかり忘れていて、うっかり別の検索エンジンで検索してしまう。そういうのが鬱陶しくて、僕は結局Googleしか使わなくなってしまいました。でも、せっかくOpenSearchとかで検索エンジンを追加登録できても、それらを使う機会が全く訪れないなんて、こんな勿体ない事があっていいはずがない。そう思って、「先に検索エンジンを選ぶのと、後で元に戻すのがめんどくさいんだ」と判断して、「後から検索エンジンを選べて、既定の検索エンジンに戻す必要がない」という操作ができるようにしてみたんですね。

こういう傍目から見てアホとしか思えない行動を取ってしまう人はけっこういるんです。Web検索バーに文字を入力する時には、入力しようと思っている語句に注意がいっているから、「どの検索エンジンが選択されてるか」という事に注意が向かないんですね。そういう風な思考ができあがっている時に、期待通りの結果が得られないと、「なんでやねん」とストレスを感じてしまうわけです。

そういうミスに対して「それはあんたの使い方が悪いんだ」と責める人もいるでしょうけど、道具は使う人のためにデザインされるべき物と考える限りにおいては、人がそういう行動を取ってしまうのなら、その行動に合わせて道具をデザインした方がいいと僕は思っています。

ユーザの行動や入力をトリガーにする

1つ前の話を別の観点からもう1回語ってみます。

金額の事だけで頭がいっぱいになっていて、とりあえず無意識に数字を入力し始めてしまう、という僕の行動をトリガーにして、僕の携帯電話はよさげな機能をサジェストしてくれるわけです。同じようにセカンドサーチも、頭の中が調べたい単語の事でいっぱいになっていてとりあえず無意識に単語だけ入力してしまうという僕の行動をトリガーにして、適切な検索エンジンを後から選べるようにサジェストしてくれます。このように、無意識の行動を起点にして各機能を呼び出せるようになっていると、「機能をどこから呼び出すのか」を改めて考えなくて済みます。

機能をどこから呼び出すのか、というのは結構重要な問題です。

メニューを何階層も辿った奥にある機能というのは使うのが億劫なので、だんだん使わなくなってしまいます。しかし、だからといって階層の浅い所にメニュー項目を増やしていったり、ツールバーのボタンをどんどん増やしていくと、機能が増えていった時に収拾が付かなくなってしまいます。

WindowsのコマンドプロンプトやLinuxやMac OS Xのターミナル(端末エミュレータ)のようにコマンドを入力させる形式なら表示領域を悔いませんが、今度は、ユーザが「どんなコマンドが使えるのか」という事を常に頭の中に入れておかないといけないようになってしまいます。コマンドだけじゃなく、今どこのディレクトリにいるのかとか、ログインしているユーザが誰なのかとか、いろんな「モード」を把握してないと使えません。僕はそんなの全部は覚えてられないので、CUIでコマンドライン入力というのは基本的に好きじゃないです。

表示領域も食わないし文字列のコマンド入力よりも直感的、という事でマウスジェスチャ(リンクをドラッグしたままマウスを上下左右に動かすと、その軌跡(ジェスチャ)がコマンドとして解釈される機能)はどうなんだ? っていう話になってきますけど、マウスジェスチャも「ジェスチャを覚えないといけない」という問題はやっぱりあります。上上下下左右……みたいなややこしいジェスチャを全部覚えてられるかというと、まあ無理な話です。実際、マウスジェスチャを使ってる人でも「憶えてるのは上下左右の各方向にマウスを動かす単純な動き程度でそれより複雑な物は全然使わない」と言ってました。

という話の中にも出てきていますが、ごく簡単なジェスチャだったらアリだと言えます。リンクを引っ掴んで適当にぽいっと投げたらそれをタブで開く、とか、その程度の大雑把さなら苦になりません。ただ、この場合は「ジェスチャを入力している」と言うよりも、「リンクというオブジェクトを掴んで何かしようとしている」という場面だと解釈した方が正しいでしょう。

僕が「ユーザの入力をトリガーにする」という言葉で表現したかったのはそういう事です。何かキー入力を始めたとか、何かオブジェクトがドラッグされたとか、そういう行為そのものをトリガーにするっていう事であって、「どういう文字が入力されたのか」とか「どういう風にマウスを動かしたのか」とかの細かい所を情報として使うという話ではないんです。もちろん、入力された内容にそぐわない機能を除外した上でサジェストする(例えば数字だけが入力されていたら英和辞書は候補に出さないとかの)工夫はあってもいいと思いますが。

「冷蔵庫に卵とトマトがある事を確認して、それからクックパッドで卵とトマトを使ったレシピを探そう」という風な理路整然とした行動計画を、現状から目指すゴールまでを最初から完全にきちんとイメージできる人ばかりではないんです。というか僕自身がそういう事ができない方なんですね。おなかすいてとりあえず冷蔵庫を開けてみたとか、そういう無駄な事をやってしまう方です。

そういう最初のアクションを無意識レベルで起こした結果、機能がサジェストされたり視覚的なフィードバックがあったりして、そこからさらに「そういえば自分はこういうことをしたいんだった」と次の行動が喚起される。(もっと言うと、その時の既定の挙動が一番利用頻度の高い物になっている。)という風な誘導がウザくないレベルで働くようなUIが、僕にとっての「良いUI」なんでしょうね。

ブラウザのUIはゲームのUIではない

ちょっと話はズレますが、ストリートファイターとかの対戦格闘ゲームを考えてみましょう。この種のゲームは、技を出すための複雑なコマンドを覚えたり、覚えたコマンドを適切なタイミングで正確に入力できるようになったり、という努力の末の「上達」が「勝利(報酬)」に結び付くというゲームのデザインになっています。勝てるようになれたら嬉しくて、負ければ悔しくて、なのでみんな必死になってコマンドを覚えるし、正確に入力できるようになろうとする、そういうモチベーションがある。

翻ってブラウザのUIという物を考えてみると、誰が好きこのんで複雑なコマンドを覚えたくなるの? ブラウザを上手く使えるようになる努力をして、上達して、それのどこが嬉しいの? って話なんですよ。普通のユーザにとって、ブラウザとかUIとかってそんな努力を費やす対象ではないです。勉強しないとまともに使えない斬新な文房具とか包丁とか、使いたくなりますか? なりませんよね。普通の人にとってのブラウザって、そういうレベルの物でしかない。

UIをデザインするんだ!って思って頑張る時に勘違いしてしまいやすいのはそこなんですよね。こんだけ頑張って斬新なUIを考えました、他に類を見ないUIになりました、ただし使うのにはそれなりに慣れが必要です、っていって作った物をユーザに見せても相手にされないですよ。そんなの作り手の自己満足でしかない。自分にとって物作りそれ自体が楽しくなってきた頃に犯しがちなミスです。

実用品のUIと、娯楽だったり趣味の物だったりのUIとは、別の物として考えて欲しいです。日常的な利用にゲーム性を加えてみましたとか、普段の利用がちょっと楽しくなりますとか、たまにありますけど、それで本来の用途に支障をきたしたりストレスが増したりするようになってしまっては本末転倒です。

自分の部屋とかキッチンとか

自分が生活する部屋や、日常的に使うキッチンの事を考えてみて下さい。

  • よく使うものは奥にしまわない。流しの下を開けたらすぐそこに包丁があるとか、毎日使う茶碗は引き出しの手前に入れておくとか、そういう風に自然となってる。逆に、奥の方にしまい込んだ鍋とかは、出すのが面倒でほとんど使わないという事も結構ある。
  • どこに何があるか、自分にとって分かりやすいような配置に落ち着いてるはず。
  • どこに何を置いたか、だいたいは把握できている。こういうことをしよう、と思った時にどこに手を伸ばせばいいかは無意識に判断できる。

ソフトウェアのUIも基本は同じだと思います。

よく使うものを手前に置くとかの話はここまでで述べた話に通じています。ここで新しく述べたいのは、「どこに何を置いたかだいたい把握してるはず」という部分です。

ロケーションバーと検索バーの統合という風に、最近は(主に表示領域を広く取るために)複数のUIを1つにまとめる風潮があるみたいなんですが、そうすると使う時に余計なステップが増えてしまいかねないというデメリットがあります。UIをどんどんまとめていくという事に固執しないで、時にはUIを分けるという判断も必要だと僕は思っています。「使い方を頑張って覚えなきゃいけない様なUIは駄目だ」という風な事を前述しましたが、並んでる物を使い分ける程度の事は大抵の人にはできるはずです。あんまりユーザをなめんなよ、ということですね。URLを入力したい時にはロケーションバーをクリックして、検索したい時は検索バーをクリックして、という事をユーザが無意識にできるのであれば、そこはUIの設計に組み込んで活かしてもいいはずです。

あと、キッチンに例えるついでに言うと、キッチンを清潔に保った方がいいのと同じでソースコードも清潔にした方がいいです。詳しくは実装の話で述べますが、生ゴミを放っておくと腐って虫が湧くように、汚いソースコードも放置すればバグの温床になりますので。

人は自分の行動パターンを変えようとしないという事

一般的に言って、フツーの人は「どうしても必要だ!」という強烈な動機がない限りは新しい物の使い方を積極的には覚えようとしませんし、いつも取っている行動のパターンも変えたがりません。というか、無意識のうちに同じ行動を取ってしまいます。そこから意識して外れようとすると、これはストレスになります。何度も述べていますが、「素晴らしいUIを作ったから、ユーザは使い方を覚えるために苦労してくれるはずだ」というのは作り手の傲慢なんですね。そんな物は、そのうち使われなくなってしまうのがオチです

ただ、あんまり人間の順応性をナメすぎてもいけません。最初は違和感があった「いつもと違う行動パターン」でも、そのうち慣れちゃうというのは結構あります。そこを考慮から外してしまうと、常用するのがウザいUI(例えば、いつまで経っても毎回馬鹿丁寧に「どうしますか?」と聞いてくるような)になってしまいます。

  • 今まで慣れ親しんできたものと同じ要領で使えるようにする。
  • 同じ要領では使えないものでも、なるべく早く慣れる事ができるようにする。
  • 慣れてしまった人に余計なストレスを与えないようにする。

これが大事なんだ、「どこまで丁寧にやってどこからはユーザの慣れに期待するか」のバランス感覚が必要だ、と僕は思っています。

この観点から、僕はKDEでのファイルのドラッグ&ドロップの操作は「馬鹿丁寧すぎ」の方に入るのかなーと思っています。Linuxのデスクトップ環境の1つであるKDEでは、ファイルを別の位置にマウスの左ボタンでドラッグ&ドロップすると、必ずメニューが出てきて「コピー」「移動」みたいなその時可能な操作を選べるようになっています。これ、最初はいいなって僕自身思ってたんですが、使ってるとだんだんうざく感じるようになってしまいました。「上の階層のフォルダにドロップしたんだから、コピーじゃなくて移動したいに決まっとるがな!」「新しくフォルダ作ってそこにドロップしたんだから、移動したいに決まっとるがな!」と、自分の場合は少なくとも、ファイルのドラッグ&ドロップは「移動」のためにやる場合が圧倒的に多かったんですね。それなのに毎回「コピーですか? 移動ですか?」って訊かれる。これがそんなにストレスになるとは、実際使い続けてみるまで僕には分かりませんでした。

なので、セカンドサーチは何も検索エンジンを選ばなければ既定の検索エンジンで検索しますし、マルチプルタブハンドラも、「グッ」と押し込む感じで敢えて長くタブの上でボタンを押し続けない限りはタブの選択操作が始まらないようになっています(このタブ選択操作の挙動はユーザからの提案で実装したものですが、採用して大正解だったと思ってます)。

ユーザの「言う事」に振り回されない・惑わされない

「ユーザからの提案を取り入れて正解だった」と書いた直後に述べるのも何ですが、ユーザの提案を何でもかんでも呑んでしまうのは避けた方がいいと僕は思ってます。

ユーザは基本的に自分の不満を素直に言ってくるもので、その提案を取り込んだ結果他のユーザにどういう影響があるかとか、実装がどう変わるかとか、そんな事までは考えてないと思っていいと思います。そういう提案をどんどん取り込んでしまうと、最初に定めたはずの「これは何をするためのソフトウェアだ」というゴール設定がブレてしまう事にもなりかねません。なので、僕はユーザからの提案に対しては、最初に決めたコンセプトに沿っているか・既存の物を壊してしまわないかという事をなるべく考えて、折り合いが付かなければ「それは取り込めない」と回答するようにしています。

タブブラウズの機能を何でもかんでも拡張するTBEというアドオンを作っていた時は、僕はわりと何でも提案を取り込んでしまってましたが、その結果どうなったかというと、ソフトウェアが肥大化するわUIが複雑化するわコードがごちゃごちゃになるわで散々でした。これは、当時の僕が名誉欲だとか人に感謝されたい欲だとかに突き動かされていたからという理由だけでなく、ソフトウェアのコンセプトが曖昧だったので、何を入れて何を外せばいいのかという判断がそもそもできなかったせいでもあるんじゃないかと、今では思ってます。

コンセプトがはっきりしていると、寄せられた意見を取捨選択しやすいです。意見を退ける時も、「それはコンセプトに合わないから」とはっきり言える。好き嫌いだとか意地悪だとかで言ってるんじゃないという、ある意味では言い訳を自分に対してできるんですね。八方美人タイプだと人の頼みを断る事自体がストレスになってしまいますが、こうすれば罪悪感を感じなくて済みます。

ということでNOと言う事の大事さを散々説いたのですが、かといって頑なになりすぎるのも良くないです。ユーザ1人だけが言ってきているのならまだしも、同じ要望・不満が別々のユーザ10人から飛んでくるようだと、これはユーザの使い方ではなくてUIの方が(ひょっとしたらコンセプトも)悪いという可能性を疑った方がいいでしょう。「なんでみんな理解してくれないんだ、こんなに素晴らしい物なのに!!」という思い上がりに囚われてしまってはいけません。

あと、意見を取り入れる時も、取り入れ方は工夫する必要があると思います。例えば「ここにこういうボタンが欲しい」という要望が来た時に、本当にそのまま言われた通りにボタンを追加する前に、なんでそこにボタンが欲しくなったんだろうかという事を考えるという事です。そこで考えた結果、やっぱりボタンを追加した方がいいという結論に辿り着くかも知れませんが、ボタンを追加しなくても別の方法で解決できるという事が分かるかも知れませんし、コンセプトの見直しを図るきっかけになるかも知れません。

余談ですが、Microsoftは製品を開発する時に、ユーザの言葉を聞くんじゃなくて、ユーザがその製品をどう使おうとしたかという様子を観察して製品にフィードバックするという事をやっている、という話を以前にどこかで読みました。ユーザ自身が自分の要望や不満を100%正しく言語化できるわけではない、ユーザ自身が気付いていない問題や視点があるのかも知れない、恥ずかしくて嘘をついているかも知れない、だから行動を見る……という話だったと思います。

Microsoftと同じ事をやるにはお金も手間もかかるのでそのままマネするのは難しいですが、そういう考え方は持っておいていいと思います。

セオリー

僕がここで述べた事は、多分UIのデザインのセオリーと言われるような事ばかりです。名前を挙げた自作のアドオンも、最初からそういう理屈を考えて作ったというよりも、試行錯誤してるうちに辿り着いた結果を後から分析してみたら案外セオリーに則っていた、という感じです。もっとちゃんと体系立ててUIのデザインの理論を勉強してから臨んでいたら、もっと少ない労力で答えに辿り着けたのかも知れないなあと思っています。

セオリーにはセオリーと呼ばれるだけの理由がちゃんとあると思いますので、我流で突っ走る前に一応は基本を抑えておくといいんじゃないでしょうか。

実装上の工夫やテクニック、コンセプトを具現化する時の注意点

プログラムとしての作りやすさに引きずられない

人にやさしい・使いやすいUIを実現するためには、プログラムとしては複雑な物になってしまいがちです。逆に、プログラムとして簡単な物にしようと思うと、エンドユーザにとっての使いやすさが犠牲になってしまいがちです。

「Now Loading…」系の物なんかは、その代表例ですよね。プログラムを作る側としては、必要なデータが全部揃うまで待ってから最後に一気に処理した方が、コードとしてはシンプルに書けます。しかし、これではエンドユーザは待たされている間何もできません。今では考えられない事でしょうが、昔のブラウザもまさにそういう設計でした。ページの内容を全部インターネット経由でダウンロードしてくるまで、ページの描画をしてくれなかったのです。

今のブラウザはそんなことは無いですよね。読み込みが少しずつ進行するに従って、ダイナミックに表示を更新して、現在までに読み込みが完了した部分から順次表示してくれます。多少作るのが面倒であっても、こういう風な設計を心がける事はとても大事だと思います。

ただ、そのようにユーザにとっての使いやすさを追求するために、プログラムとしてのコードの綺麗さを犠牲にしすぎるのも良くないです。コードの見通しが悪くなってしまうと、いざ挙動がおかしい所を見つけたとしても、どこをどのように直せば良いのか見当が付かなかったり、ある所を変更したせいで別の所に意図しない影響が発生してしまったりするため、それ以上コードに変更を加えられない(ちょっとでも変更したらぶっ壊れてしまう)、みたいな事になってしまいます。

ユーザにとっての使いやすさを大事にする事と、プログラムとしての見通しの良さを高く保ってメンテナンスしやすくしておく事は、頑張り次第で両立できます。そのためのノウハウを、ここで少しだけご紹介しようと思います。

Firefoxのアドオン開発における、避けるべきパターン

Firefoxのアドオン開発では、XMLとJavaScriptの組み合わせで「要素の振る舞い」を定義しておくXBLという技術によって「独自のタグ」のようなものを定義できます。しかし、メンテナンス性を高く保つという観点からは、XBLの利用はあまりお勧めできません。使い所をわきまえればXBLはそれなりに便利な技術ではあるのですが、「Firefoxのアドオン」の開発においては、便利さよりもデメリットの方が大きいと僕は思っています。

実際、僕は上述したアドオン「Fox Splitter」の旧バージョンをXBLを多用して開発してきましたが、XBLのせいで全体として見通しが悪くなってしまっていたり、開発時の構成に強く依存したコードがJavaScriptとXBLに散らばっていたせいで調べなければいけないコードの範囲が無駄に広がってしまったりしていたせいで、ドツボにハマってもはや自力ではメンテナンスできなくなってしまい、1年半もの間完全に放置することになってしまいました。

前述した話ともかぶりますが、不必要な多機能化も避けた方がいいです。ある機能Aと別の機能Bとで共通の処理があるから、AとBと共通の処理を1つのアドオンにまとめておこう、という風な考えに至るのはごく自然な発想だと思いますが、しかしAとBがそれぞれ全然関係の無い機能なのであれば、共通の処理を2回書く事になったとしても、AとBは別々のアドオンとして分けて開発する事を僕は強くお勧めします。

今はAとBで共通の処理を使っているとしても、Aの機能とBの機能のそれぞれのコンセプトを突き詰めていくと、共通の処理にできる部分はほとんどなくなってしまうかもしれません。にもかかわらず、「AとBとそれらの共通部分」という構成のコードがあると、この構成を維持する事に発想が囚われてしまって、AもBもコンセプト的に中途半端なままになってしまうのではないでしょうか。別々のアドオンに分けて開発していれば、そういう風に今ある実装に引きずられないで、コンセプトを突き詰めた開発をしやすいと僕は思っています。

他に思いつく事としては、ありきたりですが、プログラミングにおいて一般的なアンチパターン(これはマネしちゃいけない、という反面教師的なパターン)を避ける事がやはり大事だと思います。

例えば、1つのクラスに2つも3つも関係のない機能をまとめてしまうと、これは先ほど述べた「アドオンの多機能化」と同じような問題に繋がりかねません。それを避けるには、個々のクラスの実装が受け持つ機能の範囲を定める形で、実装を適切な粒度に分けておく事が大事です。

また、3項演算子や、論理演算子の優先順位を逆手に取ったプログラミングなどのトリッキーな書き方も、あまり多用するべきではないです。トリッキーなコードは芸術的で見ていて美しいものですが、あまりに芸術的すぎるコードは、非常に限定された条件下でしか正しく動かず、手を少し加えただけで動かなくなってしまう事もあったりして、その後の機能拡張やメンテナンスに対して脆弱になってしまいます。芸術品を作るのではなくて、実用品を作ろうとしているのだ、という事を常に念頭に置いておく事を僕はお勧めしたいです。

1年後の自分が読んでも意味が分かるようなコードにする事を心がける

1つのプログラムを1人で集中して開発している時は、プログラムの全体像が頭に入っていますから、多少読みにくいコードでも開発する事ができます。

しかし、誰かに手伝ってもらうとしたらどうでしょうか。あるいは、1年間そのプログラムの事を全く考えずにいて、1年後に急に開発を再開する事になったとしたら(1年後の自分なんて、はっきり言って他人も同然です)。読みにくいコードになっていると、「この関数は何のための物なんだろう……」とか「なんでこんな設計になっているんだろう……」といった感じで、全体像を把握できなくて何も手出しできなくなってしまいます。また、そういう状態で不用意に既存のコードを書き換えると、思わぬ副作用が発生して、今まで動いていたものが全く動かなくなってしまうかも知れません。これでは開発になりません。

前述した「1つのクラスに2つも3つも機能が入ってしまっているコード」や「あまりに芸術的すぎるコード」も、そういう問題を引き起こしがちです。そういった問題を避けるための、「1年後の自分が読んでも分かるようなコードにするテクニック」をいくつか紹介しましょう。

変数名やメソッド名、クラス名を分かりやすくする

変数やメソッド、クラスの名前は、それが何を表しているのか・何をするための物なのかをきちんと表す物にしましょう。例えば以下のようなコードは最悪ですね。

var bool = true; // 変数名が「真偽値である事」だけしか表していない

function f() { ... } // 関数に適切な名前が付いていない

これは、以下のような書き方をした方がいいです。(これはあくまで例です。表す内容がこれとは違う場面であれば、その都度適切な名前を付けましょう。)

var enabled = true; // 変数名から「何かの機能が有効か無効かを示すものだ」という事が分かる

function openTabAndInitialize() { ... } // 関数名が処理の内容を表している

ただ、名前に動詞や形容詞、前置詞などが2つも3つも入ってくるようだと、いくら処理の内容をきちんと言い表していても駄目です。関数や変数に簡潔明瞭な名前を付けられないのは、そもそも設計が悪いからと考えられます。きちんと設計してあれば、関数や変数には大抵の場合、ちゃんと簡潔明瞭な名前を付けられるのです。ですから、この例のopenTabAndInitialize()だと以下のように設計し直す事になるでしょう。

function openTab() { // 2つの小さな処理単位からなる、1つの大きな処理単位
  var tab = openNewTab();
  initializeTab(tab);
}

function openNewTab() { ... } // 新しいタブを開く、という1つの小さな処理単位

function initializeTab(aTab) { ... } // タブを初期化する、という1つの小さな処理単位

Rubyというプログラミング言語の開発者のMatz氏の言う「名前重要」というスローガンは、この事を指しています。変数や関数に名前を付ける時はちゃんと考えてから付けないと駄目で、名前付けに困る時は設計を見直す事も視野に入れるべき、という事ですね。

データに意味を持たせない。

データを表す時に、配列の1個目の要素が名前で、2個目の要素がデータの数を表して、3個目の要素がアイコンのサイズを表して……という風な作りにしてしまう事があります。

var data = ["foo", 11, 32];

こういうデータの設計はやってはいけません。「何番目のデータがこういう意味である」という風な、データの順番などがそのまま意味を表すような設計だと、順番をいちいち細かく覚えてられませんから、うっかりミスで間違えてしまいやすいです。また、こういうデータの設計だと、データ構造も変えにくいです(最後にどんどん新しい情報を付け足すというような、やっつけ仕事の解決策しか取れない)。

こういう物は、連想配列とかハッシュとか言われる形式でデータを表現する方がよいです。

var session = {
      title     : "foo",
      tabsCount : 11,
      size      : 32
    };

連想配列やハッシュであれば、ハッシュのキーがその値の意味を表すメタ情報になります

引数の多い関数を作らない

1つ前の話と同じ事なのですが、以下のように関数の引数が3つも4つもあるような関数は作るべきではないです。関数を呼び出す時に、何番目にどの情報を渡せば良いのかを間違えやすくなってしまいます。

function load(uri, title, size,
              referrer, ...)

こういうものは、ハッシュを1つだけ引数に取り、そのハッシュの値が個々のパラメータを表すという設計にしておきましょう。

load({
  title    : "foo",
  uri      : "http://...",
  size     : 32,
  referrer : null
})

このようになっていれば、引数の順番を意識しなくて済みます。

自動テストを作っておく

自動テストとは、ある関数や機能について「どういう呼び出し方をした時に、どういう結果が返ってくるか」という事を確認するためのプログラムです。具体的には、以下のような「テスト関数」が沢山連なったものが「自動テスト」というプログラムになります。

function test_getMessage() {
  // 実装を実際に呼び出してみる
  var result = getMessage();
  // 返り値は期待値と一致しているか?
  assert.equal('expected message', result);
}

ある機能Aがあって、そのAに依存するBという機能があって、Bに依存するCという機能がある時に、Cが正しく動かなかったら、さてどこに問題があると考えれば良いでしょうか。Aが壊れているのかも知れないし、Bが壊れているかも知れないし、Cが壊れているのかも知れない、このままだと何が原因なのかは分かりません。

しかし、機能AとBは自動テストでちゃんと期待通りの動作をする事を保証されていて、今まさにCを開発している場面なのだとしたら、これはCに問題がある可能性が高いと言えます。このように、自動テストがある事で複雑なプログラムであっても一歩一歩着実に開発を進められるのです。

また、自動テストは、その関数や機能が期待通りに動くかどうかを検証するものであると同時に、その機能はどのようにして使う物なのか、どういう結果が返ってくる物なのか、といった事の例にもなります。

遅延処理、非同期処理

プログラムは、上から順に1行ずつ読んで処理の流れを把握できるようになっている物ばかりではありません。ユーザの入力を待ってから次の処理を行うとか、読み込みが完了するまでの間別の処理を走らせておいて読み込みが完了したら画面を切り替えるとか、このような「人にやさしい挙動」を実現しようと思うと、上から順に1行ずつ読んだのでは処理の流れを追う事ができないような、分かりにくいコードになってしまう事を避けられません。

Firefoxのアドオン開発の場合は言語はJavaScriptを使う事になりますが、JavaScriptでは非同期処理や遅延処理が関係する場面だとコールバック関数(ある処理を呼び出す際に、その処理が終わった後で実行されるべき処理を関数として定義して渡すという物)を使わざるを得ません。そのような処理を2つも3つも連携させようとすると、コールバック関数を何十にも重ねる事になってしまいがちです。

例えば「新しいウィンドウを開いて、そのウィンドウの読み込みが完了したらコールバック関数を実行する」という例は以下のように書けます。

function openAndWait(aCallback) {
  var win = window.open(...);
  win.addEventListener('load', function() {
    win.removeEventListener('load', arguments.callee, false);
    aCallback(win);
  }, false);
}

これを使って「ウィンドウを1つずつ500ミリ秒おきに順番に3つ開いていく」という処理を書こうとすると、以下のようにコールバック関数をどんどんネストしていかないといけません。

openAndWait(function(aWindow) {
  aWindow.move(...);
  window.setTimeout(function() {
    openAndWait(function(aWindow) {
      aWindow.move(...);
      window.setTimeout(function() {
        openAndWait(function(aWindow) {
          aWindow.move(...);
          ...
        });
      }, 500);
    });
  }, 500);
});

2階層や3階層ならまだしも、これが10階層や20階層も重なると、インデント幅が増えすぎてワケが分からなくなってしまいます。また、開き括弧と閉じ括弧の間に沢山のコードが入るため、コード全体の見通しも悪くなります。

このような問題に対処するための機能が、jQueryにはdeferredという名前で搭載されていますし、同様の機能だけを提供するJSDeferredという軽量なライブラリもあります。ここではJSDeferredの使い方を少しだけ解説したいと思います。

JSDeferred

先の openAndWait() という関数は、ウィンドウの読み込みが終わった後に次の処理としてコールバック関数を実行する物でした。これをJSDeferredを使って書き換えてみた物が、以下の例です。

function openAndWait() {
  // (1) Deferredクラスのインスタンス(Deferredオブジェクト)を作る。
  var deferred = new Deferred();

  var win = window.open(...);
  win.addEventListener('load', function() {
    win.removeEventListener('load', arguments.callee, false);
    // (3) 読み込みが終わったら、返したDeferredオブジェクトの
    //     call()メソッドを呼ぶ。
    deferred.call(win);
  }, false);

  // (2) Deferredオブジェクトを返り値として返す。
  return deferred;
}

このように書き換えた関数は、以下のようにして「次の処理」を記述できるようになります。

openAndWait()
  .next(function(aWindow) {
    aWindow.moveTo(...);
  });

それどころか、さらにその先にもまだまだ「次の処理」を続けて記述できます。

openAndWait()
  .next(function(aWindow) {
    // 読み込みが終わったら実行
    aWindow.moveTo(...);
  })
  .wait(0.5) // 500ミリ秒待つ
  .next(function() {
    // 次のウィンドウを開く
    return openAndWait();
  })
  .next(function(aWindow) {
    // 読み込みが終わったら実行
    aWindow.moveTo();
  })
  .wait(0.5) // 500ミリ秒待つ
  ..

JSDeferredを使うと、何個も処理を重ねる場合でもコード上のネストがあまり深くなりません。また、コールバック関数を重ねる場合と異なり、コードを読む時に上と下を行ったり来たりする必要もありません。コールバック関数を1個目の引数に受け取るのか2個目の引数に受け取るのか、といったインターフェースの違いも意識しなくて済みます(全ての非同期処理を統一的なインターフェースで利用できるようになる、とも言えます)。

詳しい事はJSDeferred開発者のcho45氏自身による解説を読んで下さい。JSDeferredを使いこなせるようになると、表現の幅がぐっと広がります。

先に名前を挙げたアドオンFox Splitterも、JSDeferredに強く依存しています。Fox Splitterは新しいウィンドウを開いて位置や大きさを制御するという事をやっていますが、ウィンドウが開かれるのを待って次の処理に進んだり、ウィンドウの位置が確定するのを待って他のウィンドウの位置を調整したり、といった感じで「前の処理の完了を待ってから次の処理を行う」場面が非常に多いです。僕はJSDeferredのおかげで、そういった処理の前後関係を意識しないで複数の機能と機能を連携できるようになったために、Fox Splitterを無事完成させることができました。

前述した「ユーザの入力を一旦受け取って、入力が完了した後に次に進む」というような事も、JSDeferredを使えば比較的簡単に処理を記述できるでしょう。人にやさしいUIを作る上で、JSDeferredのようなライブラリは非常に役立ちます。

とりあえず作ってみるという事

UIのアイディアを思いついたら、あれこれ計画を練って検討するのもいいですが、さっさと実際にプロトタイプを作ってみることを僕はお勧めしたいです。

コンセプトを形にする事は重要です。形にして実際使ってみて初めて分かる事もあります。プランを練っている時には「素晴らしい」と思っていても、実際使ってみると「アレ?」って事はよくあります。手早くプロトタイプを形にして、コンセプトが正しかったかどうかを初期段階で確認して軌道修正をするのが、後で痛い目を見ないで済むようにするコツです。問題点の発覚が遅れれば遅れるほど、取り返しが付きにくいです。

ブラウザのアドオンは、そういう意味では格好の実験場だと僕は思っています。

これは、大学の卒業制作でMozillaの拡張機能として「こんなUIがあってもいいんじゃないか?」という物を作った時に考えた理屈なのですが、ブラウザのアドオンとしてプロトタイプを作る事にはいくつかのメリットがあります。

  • 既にあるソフトウェア資産を流用できる。いちから自分でブラウザを作るのは大変だが、アドオンとして作るのなら、ネットワークの通信だとかそういった部分を考えなくても済む。
  • ユーザに使ってもらう時の障壁を低くできる。今まで使ってきたWebブラウザの延長線上として、全く新しい別の物を使い始めるのに比べれば少ない学習コストで使ってもらえる。

Firefoxのアドオンの場合、ソースコードがオープンソースなライセンスで公開されている場合が多いというのもいい所です。分からない所があれば、やりたい事に近い事をやっているソフトウェアのソースコードをそのまま参考資料として参照できますし、ライセンスが定める条件に従ってさえいれば、そのままソースコードを流用する事すらできます。

ちなみに、「オープンソースの物を流用したら、その成果もいきなり全世界に公表しないといけないんでしょ? それじゃ秘密裏に実験的な事ができないじゃないか」という風に思う人がいるかもしれませんが、それは誤解です。例えばGPLなどのライセンスでは、ソースコードを流用して作ったソフトウェアのユーザに対してソースコードを開示する義務はあっても、ソフトウェアを渡されてもいなければ存在も知らないような人相手にまでソースコードを開示する義務はありません。安心して下さい。

デバイスの進歩について

質疑応答で少し話しましたが、ソフトウェアのUIとハードウェアの進歩は切っても切れない関係にあると思います。

「複雑なマウスジェスチャは覚えられないから使い物にならない、シンプルな動き以外はまともに使えない」という風な事を前述しましたが、MacやiPhone、iPadで可能な2本指・3本指でのジェスチャ(マルチタッチ)は、その制限を乗り越える技術です。指2本を開くような動き(ピンチアウト)で画面の拡大、指2本を閉じるような動き(ピンチイン)で画面の縮小、という風に、簡単でありながら表現力豊かなジェスチャ操作が可能です。これはハードウェア側のサポート無しには成り立たないUIです。

Panoramaはモーダルなせいでいまいち使いづらいですが、これはPCの画面が狭いという現在のデバイスの制約による所が大きいと僕は思っています。もしPCの画面が物凄く広ければ、あるいは、画面の外に空中に映像を投影するような技術があれば、Panoramaはモーダルにしないで常時表示しておけるかもしれません。

今あるハードウェアの限界の中で使いやすいUIを考える事も大切ですが、できない事はやっぱりできないので、そこは潔く諦めてハードウェアの進歩を待つといった判断も必要では無いかと僕は思います。あるいは、ハードウェアの制限に合わせる形でもっと別のUIを考えてみるとか。いずれにしても、今あるハードウェアの上では使いにくいと言わざるを得ない物を「理論的には使いやすいはずなんだ」みたいな感じでごり押しするような事はしないで、柔軟に考えるようにして下さい。

ターゲットユーザを誰にするのかという割り切り

僕の場合は、今は自分自身が第1のターゲットユーザだと考えています。自分自身が常用するものだからこそ、クオリティを維持して快適な状態を保ちたいと思える。というのが今の僕の考えです。

自分以外の人をターゲットユーザに想定するのもありだとは思いますが、僕の場合は既に20を超えるアドオンを開発していて、それぞれにバグ報告が来て修正のためにてんてこ舞いになっているというのが実情で、自分で使う物についてすら十分なメンテナンスをできていない状態にあります。自分自身を第1のターゲットユーザとして考えるというのは、コンセプトをブレさせないための方法論でもありますが、ユーザから寄せられる大量の要望から距離を置いて自分の身(精神)を守るための手段でもあるんですね。

誰をターゲットにする場合であっても、基本的な所はセオリー通りにやる事が大事なのだと僕は思っています。その上で、例えばお年寄りのための物にするなら文字を大きくするとか、使う言葉を平易にするとか、応用を組み合わせていく事になるのだ……と、僕は思っています。

道具を自分に合わせないと我慢できない人と、道具に自分を合わせるのが苦にならない人がいる(11時20分追記)

カスタマイズ性の高いブラウザだからみんなカスタマイズしたくなるかというと、そうとも言えません。統計として、Firefoxのユーザの全員がアドオンを使っている訳ではなく、また、アドオンを使っている人でもインストールしているアドオンの数は片手で数えられる程度である場合がほとんどだというデータが、過去のMozillaの調査で出ていました。カスタマイズ性の高い設計になっている事と、実際にカスタマイズして使われる事とは、あくまで別の事なんですね。(この調査結果は、Firefoxの初期状態が普通の人にそれなりに使いやすい形になっている事の顕れと言えるとも思います。)

僕自身は、ペンタブレット(ペン型の入力装置を使って、ペンで字や絵を描くのと同じ感覚で入力を行えるデバイス)を使う時に、指に当たって痛いなーと思ったらペンの軸に何か巻いてみたりプロテクターのような物を作って付けてみたりと、DIYで「カスタマイズ」して使っています。漫画家の人の中には、ペンの軸が長すぎるからとノコギリでぶった切って使っている人もいるそうです。

でも、そういう風にしない人もいるんですよね。使いやすいと思えるありものの製品を別に探したり、使いにくいから使うのをやめてしまったり。そもそも、自分が使いやすいと思うようにカスタマイズするという発想が無いという人もいるのだと思います。

僕自身、あまり拘りを持っていない分野ではそういう行動を取っている気がします。僕は料理をする事が好きで好きでたまらないという人ではないので、調理器具は買ってきた物をそのまま使っていますし、少々使いにくいと思っても面倒だからそのまま放置しています。カスタマイズしてでも使い続けるかどうかは、「なんでもカスタマイズしたがる性格」の有無以外にも、使いにくさを乗り越えてでもそれを使い続けるに足る動機があるのかどうか、どれだけそれを切実に必要としているのか、という事も影響しているのかもしれません。

そう考えると、カスタマイズ性を高くしておきさえすれば万事オッケーとは言えないのだと思います。僕自身、車や自転車にそれほど強い関心があるわけではないので、「タイヤをこれに替えるともっと快適だよ」と言われても「ふーん、そうなんだ。まあ面倒だから僕はそのまま使い続けますよ。」って思ってしまいますし、そのまま使い続けるのが辛いくらいに合わなければ、カスタマイズを検討する前に他の車や自転車に乗り換えてしまうのではないかと思います。同じように、Webを見る事に対してそれほど切実な動機を持っていない人に「カスタマイズすればもっと使いやすくなるよ」と言っても、「面倒だし別にいいよ」って多分言われてしまうでしょうし、その人が「なんかこれ使いにくい」って言ってる時に「カスタマイズすれば解消できるよ」と言っても、「自分で手を入れなきゃ使いやすくならないの? そうなんだったらもう最初から使わないでいいや……もっと別の物を探すよ」と言われてしまうと思います。

ほとんどの「ユーザ」はそういう物だ、と僕は考えるようにしています。だからこそ、デフォルト設定を使いやすくした方がいいとか、初見で使えるようにした方がいいとか、そういう事を言ってるんですね。

ブラウザのアドオン、である理由

今プログラマ的にアツい分野というとHTML5とかWebサービスとかクラウドとかっていう話になると思うんですが、僕がWeb開発じゃなくブラウザのアドオンの開発をやり続けてる理由は、インターフェースとして、より人に近い部分で動く物を作れるからなんだと思います。

ユーザの何気ない無意識での入力をトリガーにして適切な次の処理をサジェストするというのは、普通のWebページやWebアプリの枠を超えた部分の話です。サジェストされる選択肢の1つとしてWebサービスに誘導するのはもちろんアリだと思いますが、起点になるのは特定のWebサービスの画面ではなくて、ブラウザのUIだったりスマートフォンのホーム画面だったりという、もっとユーザに近い部分になるはずです。

そこの所への関心が強いから、僕はWebアプリよりもアドオンを作るのが好きなんでしょうね。

分類:Mozilla > XUL, , , , , , , 時刻:04:48 | Comments/Trackbacks (3) | Edit

Comments/Trackbacks

no title

とても興味深く拝読させていただきました
自分もいわゆる「お腹が空いたらまず冷蔵庫を開ける」型の人間で、
ああなるほど、と優れていると感じるUIのイメージを的確に言語化された思いです
未だに機能に惹かれ導入してみると何だこの挙動、といったアドオンも少なく無いですが
一方でスマートな思想は洗練を重ねつつ広く長く愛されますし、
(好みの差異はどうあれ)「UIデザインを考察する」動きが連鎖していけば決して未来は暗くない
…のではないかなあと愚行したりいたします

Commented by eoh at 2011/06/30 (Thu) 11:25:11

ロケーションバーと検索バー

ロケーションバーと検索バーをくっつけてセカンドサーチみたいに後からURLとして開くか検索エンジンで開くかを選ぶほうが、「URLを入力したい時にはロケーションバーをクリックして、検索したい時は検索バーをクリックして、という事」をするよりも、「先に入力を受け付けておいて、どうするかは後で選べるようにする」やり方に近いような気がしました。

Commented by kou at 2011/07/02 (Sat) 20:27:46

no title

> ロケーションバーと検索バーをくっつけて...

ロケーションバーはURLの入力装置であると同時に、現在閲覧しているページの位置を示すインジケータでもあると自分は考えているのですが、そうすると、「既に今のページのURLが表示されている所に別の検索語句を入力する」という操作は、なんとなく違和感があります。
常にロケーションバーが空っぽで純粋な入力装置なのであれば、統合しても違和感はないかも知れないんですが……

Commented by Piro at 2011/07/03 (Sun) 02:04:13

TrackBack ping me at


の末尾に2020年11月30日時点の日本の首相のファミリーネーム(ローマ字で回答)を繋げて下さい。例えば「noda」なら、「2011-06-30_ui.trackbacknoda」です。これは機械的なトラックバックスパムを防止するための措置です。

Post a comment

writeback message: Ready to post a comment.

2020年11月30日時点の日本の首相のファミリーネーム(ひらがなで回答)

Powered by blosxom 2.0 + starter kit
Home

カテゴリ一覧

過去の記事

1999.2~2005.8

最近のコメント

最近のつぶやき