2015-11-22

オブジェクト指向UX、というアプローチ

オブジェクト指向UXという記事を見つけた。原文は Object-Oriented UX 、和訳がオブジェクト指向UX である。

この記事では UXデザインのときに、まず最初に、ユーザーのメンタルモデルを、オブジェクト指向的に分析・定義することを、提案してる。このアプローチを、OOUXアプローチと呼ぼう。

オブジェクト指向やUXの意味は、人によって地味に異なるので、OOUX という言葉は誤解を生むのかも知れない。

要件(と呼ばれるウィッシュリスト)から、ソフトウェアの仕様を定義する立場で仕事を請けているんだけれど、このアプローチは有効だと思った。

[エンジニアは]ワイヤフレームやプロトタイプを見た時に、デザインをリバースエンジニアリングしてオブジェクトを抽出します。そして彼らは、「オブジェクトXはオブジェクトYとどのように通信するのか。オブジェクトAは複数のオブジェクトBで構成されていのか。オブジェクトの属性は何か。このクラスのオブジェクトはあのクラスのオブジェクトを継承するのか。」と思うでしょう。
ユーザのメンタルモデルを模倣するオブジェクトを定義することで、チームのコミュニケーションの土台となります。共通言語を手に入れられるのです。

ソフトウェアが対象にするものが、技術的なレイヤーから見て高ければ高いほど、この種の作業は必要になる。OOUX は、このための共通言語の表記の仕方とアプローチの提案なのだ。

脱 UML


似たようなアプローチとして、ドメイン駆動設計がある。オブジェクト指向的に問題ドメインをとらえることで、要件が分かるしコミュニケーションとれる、という考え方だ。ドメイン駆動設計では UML っぽい図をつかって表記する。これは悪くはないんだけれど、うまく伝わらない感がある。記号にルールがあって説明が必要になるし、後述するけど multiplicity がうまくイメージしてもらえないときがある。

OOUX のアプローチ


手順としては、まず要件のリストのようなものから、オブジェクトを抽出する。たいていは名詞がオブジェクトになるんだけれど、暗黙に想定しているオブジェクトがあったりする。

次に、オブジェクトの属性を挙げていく。さらに、他のオブジェクトを参照するのであれば、それを書いておく。これらを優先順位付けしろ、話はそれからだ、という手順だ。

メソッドやメッセージのやりとりは、ここでは定義しないようだ。これは欲しいなぁと思うので、今後自分が使うときには、なんか記載するようにするかも知れない。

さて、このとき UML を使わない。


  • レシピ
    • 材料
    • 材料
    • 材用
    • ...
    • 手順

  • 材料
    • 名前
    • 説明


みたいに書く。

レシピには1以上の材料が必要だろうから、1..* とかって矢印を引きたくなるんだけど、そうしない。

本当はUMLとやってることは同じだ。けど、1..* よりも具体的に材料、材料、材料、...と書いておくほうがイメージが湧く。

設計するにあたって、あるいは、いざ実装し始めてから、以下の様な会話をして泣いたことが何度もある。

「ここって複数なんですか?」
「ほとんどは、1つしかないよ」
「3つっていうのは絶対にない?」
「たまにある」
「それは表示する必要がある?」
「もちろん」
「100個の場合も?」
「まあね。でも、ほとんどは1つだから、気にしなくていいよ。」

気にしますね。とっても、気にします。たとえ1ケースであっても、99999オブジェクトを参照する可能性があるなら、ちと考えたくなるものです。

SNS を使うようなのは、これがしょっちゅうある。ほとんどのユーザーのフォロワーは100人くらいで収まるけど、たとえば @takapon_jp には 14万人のフォロワーがいる。

UML の 1..* と書いてあるよりも、


  • レシピ
    • 材料
    • 材料
    • 材料
    • ... 最大1000 ...
    • 手順


のほうが、UMLに馴染みがない人にも、可視化できるというわけだ。

実装がオブジェクトになるかどうかは、また別の話。RDB で管理するとか、KVS とかは、今は別の話。開発の工数や、成果物の効果によって、つまり費用対効果を考えて、10個までに制限するとかいう議論はあるけど、今は、その前の話をしている。

発注側が意識しているかどうか別にして、現時点の想定では上限の無い 1..* が、まずは要件の草稿になっていることが明らかになるのだ。

さっそく使ってみた


マーケットプレース(楽天とかね)みたいなのを考えることがあった。このとき店舗オブジェクトを考える。この店舗にいくつか種類があって、abstract 店舗から、concrete 店舗を4種類派生させるような感じだった。けど、UMLにせずに、

通販店舗、デジタル商材店舗、...みたいにあえて、コピペで書いていった。そうしたら、どうもビジネス主体(会社とか)が、複数の店舗を持つことができて、かつ、ビジネス主体ごとに売上を管理する必要がある、みたいなことが明らかになった。最初のウィッシュリストには、どこにもそんなことは書かれていない。

1年ほど前に、似たような状況でUMLを使って説明し、ほんとにこういうの要らないの?と確認したときた時には、完全にスルーされた。あとから会社単位の売上管理が必要だと言い始める、という、だるい展開だった。

1年前と先週の違いは、図の描き方だけではないので、必ずしもOOUXのアプローチの優位性を示さない。けれど、よさそう、という印象を持った。機会があれば、かつ適切そうであれば、今後もこのアプローチを使っていこうと思う。

OOUX が目指していないであろうこと


原文ページのコメント欄や、SNS での言及をみていると、OOUX のスコープを把握できない人がいるように見える。

前提として、この記事は、同じ種類のコンテンツが大量にあるような、ウェブサイトの見え方/体験の設計という意味で、UX デザインという言葉を使っている。選挙(選挙区ごとに結果が出ますね)、レシピ、DIY とか。この種のウェブサイトのコンテンツでは、クラスとインスタンス、という考え方が比較的あてはめやすい。

20年ほどの昔、オブジェクト指向で要求を分析し、オブジェクト指向で設計し、オブジェクト指向で実装すると、分析・設計・実装で共通のオブジェクトを使える、という夢を見ていたことがありました。が、実際には、そうはいかない。

OOUX もドメイン駆動開発も、メンタルモデルをオブジェクトにマッピングしましょう、という考え方だ。決して、いきなり実装しようとはしていない、と私は解釈している。実装するときのモデルとは大きく異なることがあるだろう。

さらに、単純にマッピングできないこともあると思う。当初は想定さえしていなかったような、暗黙のコンセプトが、オブジェクトとして浮き彫りになることもある。

「それは 0以上なのか、1個なのか、N個なのか?」が自分には分からないが、知らなければならないとき、OOUXで紹介された記述の仕方が使えるのだ。

2015-11-16

カレンダーアプリに JavaScript for Automation でアクセスすると遅い

JavaScript for Automation を使って、OS X の Calendar アプリにアクセスするコードを書いているのだけれど、期待より遅い。

var event = Application("Calendar").calendars[0].events[0];
event.summary();

1行目で、カレンダーの予定を取得している。これは、一瞬で終わる。

2行目では、予定の件名を取得している。.summary は参照だけしていて、値であるところの文字列はまだ分からない。summary() で、Calendar アプリと通信をして取得する。これが30秒くらいかかる。

今回は、カレンダーから、どの仕事に何時間使ったかを抽出しようとしている。カレンダーアプリに直接アクセスせずに、ical フォーマットのファイルを直接読み込んで処理することにした。

2015-11-08

OS X の JavaScript for Automation で、外部ライブラリを読み込む

OS X Yosemite 以降オートメーションのスクリプトをApple Script ではなくてJavaScript でも書けるようになった JavaScript for Automation または JXA と呼ぶらしい

単純な自動化だとシェルスクリプトなり Python なりで書けばいいんだけどアプリケーションと通信するときにはオートメーションを使えると便利だたとえばカレンダーアプリや iTunes の API にアクセスするようなとき

今回、JXA で日付文字列のパースやフォーマットがしたくなった。Node.js なんかだと、moment.js なるライブラリがある。

JXA で外部ライブラリを取り込むには、いくつかやりかたがあるらしいけれど、browserify を使うことにした。

手順


まず、browserify と、取り込むライブラリをインストールする。

npm install -g browserify
npm install moment

moment.js を使うコードを書く

// main.js
var moment = require("moment");
console.log(moment().format('MMMM Do YYYY, h:mm:ss a'));
browserify を使って出力したコードを、JXA 環境で実行する。

$ (echo 'window = this;'; browserify main.js; echo ';ObjC.import("stdlib");$.exit(0)') | osascript -l JavaScript
2015-11-08T16:26:55+09:00

実行コードをファイル保存


エラーが出たりすると、どの行だよ!ってなるので、browserify の出力をファイルにする。Makefile で。cake や gulp じゃなくてすみません。

bundle.js: *.js
    (echo 'window = this;'; browserify main.js; echo ';ObjC.import("stdlib");$$.exit(0)') > bundle.js

run: bundle.js
    osascript -l JavaScript bundle.js

JXA 環境特有の調整


Node.js と JXA との環境の違いを吸収するため、 browserify の出力前後に、数行追加してある。

JXA には window がない。ただし、this でグローバルなオブジェクトにアクセスできる。window = this することで、window オブジェクトが使える風にする。今回のスクリプトでは不要。

browserify で生成した関数を実行すると最後に評価された式の値がプリントされる結果を標準出力に出してパイプでつなぐような用途だと困る

ObjC.import("stdlib");
で、なんかライブラリを読み込む。らしい。ObjC.foo または $.foo で、読み込んだ関数にアクセスできる。というわけで、
$.exit(0);
して、何も表示させずに終了している。