私は、ユーザー・エクスペリエンス設計者としての役割の中で、自分が設計に関与した製品を人々がどのような動機で使用しているのかを理解する必要があります。製品のユーザー・エクスペリエンスが適切に設計されていると、その分野における製品の競争力を向上させることになります。
そこで私は、ソーシャル・メディアから特定のユーザー・ベースの特徴を調べてみようと考えました。方法としては、製品の Twitter アカウントからユーザーのツイートとプロフィールの自己紹介文をサンプリングすることにしました。その目的は、フォロワーがどのように自己紹介しているかを調べ、その情報が製品を利用する動機を理解する上で役立つかどうかを判断することです。
“今日、人々が [ソーシャル・メディア上で] 行っていることについて考えてみてください・・・彼らはそこで自分自身のイメージとアイデンティティーを構築しています。それは、ある意味、彼らのブランドと言えます。そして彼らは、つながりたいと思う相手とつながっています。”
Mark Zuckerberg 氏
いくつかのプロフィールを概観した私は、サンプリングした自己紹介文の詳細から、このアイデアは間違っていないと勇気づけられました (ただし、サンプリングを手作業で行うとしたら、ひと握りのフォロワーしかサンプリングできないため、そこから描けるのは一般的なイメージでしかありません)。このアイデアは期待できるような気がしました ― それは、自己紹介文は公開されており、ユーザーを洞察に満ちた興味深い形で明らかにすることや、優れた分析の結果を示すことができるからです。しかし、ソーシャル・メディアという鏡に映し出された自分を見つめて、自分が他人にどう映っているのかを理解するために利用できるツールはほとんどないようです。
私が目指したワード・クラウドは、千人ぐらいのフォロワーの自己紹介文で最も頻出する単語を明らかにするというものです。しかし、自己紹介文からワード・クラウドを生成するためのツールとして無料で入手できるものは見つかりませんでした。
私のフォロワーの自己紹介文から最も多く出現する上位 5 つの単語をリストアップする市販のツールは見つかりましたが、それを使うには料金を支払う必要があり、しかも私が望んでいたことを完全に実現してくれるわけではありません。というのも、私は、それほどよく出現しない単語にも価値があるのではないか、そして広範なデータからパターンが出現する可能性があるのではないか、と考えていたからです。
そこで私は、このデータを説明するのに役立つアプリケーションを、IBM Bluemix クラウド・プラットフォーム上で作成しました。このアプリケーションからの出力例を以下に示します。これは、私のフォロワーのプロフィールに書かれている自己紹介文の中で最も頻出する単語から生成されたワード・クラウドです。これと同じアイデアを用いて、製品の Twitter アカウントのフォロワーに関して、プロフィールに書かれている自己紹介文と、ツイートをサンプリングすることができます。
ワード・クラウド・ツールは、以下の目的で使用することができます。
- 自分自身のアイデンティティーを確認および調整する
- 競合する製品や人物のフォロワーを比較する
- 新しいフォロワーやフォロー対象の候補を評価する
読む:Scott Rich 氏による「Node.js、Express、sentiment、ntwitter を使用して感情分析アプリケーションを作成する」
上記の素晴らしい記事で、Scott Rich 氏は Bluemix 上で Node.js、express、Twitter からなる土台を作成する方法を説明しています。私のアプリケーションの土台は Scott が作成したものと似ていますが、Node.js での基本的な Twitter アプリケーションをさらに拡張して、Twitter 認証を使用し、Mongo データベースを統合し、ロー・データをより高度な情報画像に変換しています。
このチュートリアルには、Mongo と Node を統合するための一般的なステップと、その統合をセットアップすることだけを目的とした単純なプロジェクトへのリンクを含めていますが、私が作成したワード・クラウド・アプリケーションにリンクすれば、Mongo と Node が統合されている実例を確認することができます。
同様のアプリケーションを作成するために必要となるもの
これは複雑なアプリケーションです。このチュートリアルのステップは、中級の開発者が認証済み Twitter アプリケーションを Node 上で作成して PaaS にデプロイする方法を学ぶ上で役立ちますが、このチュートリアルに従うには、いくつかのコンポーネントとステップが必要です。
私の手法は、Mongo と Node でローカル環境を作成し、変更を Git にプッシュすると、DevOps Services の自動デプロイ機能によって Bluemix にデプロイされるようにするというものです。
ローカルでの開発用にインストールしたサーバー・サイドの Node.js モジュールとクライアント・サイドの JavaScript は以下のとおりです。
- サーバー・サイドの Node.js モジュール:
- クライアント・サイドの JavaScript ライブラリー:
上掲の「コードを入手する」ボタンをクリックすると、package.json ファイルをダウンロードすることができます。
{ "name": "ProfileWords", "version": "v0.0.1", "description": "A tool for analyzing Twitter accounts, using follower's bios", "dependencies": { "mongodb": "*", "express": "*", "twit": "~1.1.11", "cookie-parser": "*", "express-session": "~1.0.3", "errorhandler": "*", "morgan": "*", "request":"*", "multiparty":"*", "oauth": "*" }, "engines": { "node": ">=0.10.0" }, "repository": {} }
このパッケージ・ファイルにも、Mongo と OAuth が依存するいくつかのパッケージが含まれています。
すべてのコードは従来の MEAN スタック技術を使用して開発し、Bluemix 上で実行されるように設計しました。また、以下で紹介するステップには、Bluemix 上で MongoLabs サービスをセットアップするためのステップが含まれています。
視覚的な Twitter マッシュアップを作成する方法を学習するために、以下の手順を踏みました。
- Scott の記事の説明に従いました。
- Mongo をローカルにインストールしました。
- Twitter 開発者向けサイトから Twitter アプリケーションを作成しました。
- Twitter 認証に対応するように構成をセットアップしました。
- 実行場所となる基本的な Mongo アプリケーションを作成しました。
- 基本的な Twitter 認証を追加し、土台を完成させました。
- Twitter API を呼び出すためのコード、データベースに書き込むためのコードの作成に取り掛かりました。
- 可視化ライブラリー (この例の場合は D3) を組み込みました。
ステップ 1. 環境に構成を保管する
最新式のソフトウェアを開発するための 12 の要素のうちの 1 つは、環境に構成を保管することです。こうすることで、API key (およびその他のデータ) が公開されないようにすることができます。
このプロジェクトでは Twitter API を使用するため、コードを実行するための新しい Twitter アプリケーションを作成する必要があります。新規 Twitter アプリケーションを作成すると、app.js ファイルで認識しておく必要がある Twitter 用キーがいくつか提供されます。これらのキーが app.js ファイルに認識されていない場合、Twitter はアプリケーションで使用される API への呼び出しを拒否します。詳細については、私のアプリケーションの README.MD ファイルを参照してください。
私の app.js ファイルでは、以下のコード行によって、認証用の Consumer key (API key) オブジェクトをセットアップしています。
var consumer = new oauth.OAuth( "https://twitter.com/oauth/request_token", "https://twitter.com/oauth/access_token", process.env.TWITTER_CONSUMER_KEY, process.env.TWITTER_CONSUMER_SECRET, "1.0A", _callBackPage, "HMAC-SHA1"); app.use(errorHandler({ dumpExceptions: true, showStack: true })); app.use(logger()); app.use(cookieParser()); app.use(session({ secret: "very secret" }) );
上記のリストに示されているストリング値 process.env.TWITTER_CONSUMER_KEY
および process.env.TWITTER_CONSUMER_SECRET
は、私のアプリケーション用に Twitter から提供される値になります。新しい Twitter アプリケーションを作成し、皆さんのアプリケーションのページで、以下の画像に示す「API Keys (API キー)」タブに切り替えてください。このタブで、皆さんの環境用のキーを定義します。私のアプリケーションは「ProfileWords」という名前ですが、皆さんのアプリケーションには独自の名前を付けて構いません。
Mac ユーザー: 皆さんの環境用のキーを定義する方法は、以下のとおりです。
- ターミナル・ウィンドウを開きます。
- 以下のコマンドを実行します。
sudo vi /etc/launchd.conf
- launchd.conf ファイルを編集して、以下の行を追加します。
setenv TWITTER_CONSUMER_KEY YOUR-STRING setenv TWITTER_CONSUMER_SECRET YOUR-STRING setenv TWITTER_ENDPOINT YOUR-ENDPOINT
アプリケーションのページの「Settings (設定)」タブをクリックします。このタブで、名前、説明、Web サイトの URL、コールバック URL を指定します。「Allow this application to be used to Sign in with Twitter (Twitter でのサインインに、このアプリケーションの使用を許可する)」チェック・ボックスに、チェック・マークを付けてください。
システムを再起動します。Node アプリケーションが実行されると、Node アプリケーションからユーザー用の固有のストリングにアクセスできるようになります。
Windows ユーザー: シェルから以下のコマンドを実行します。
SET TWITTER_CONSUMER_KEY=YOUR-STRING
読む:User-Provided Services Instances
ステップ 2. DevOps Services からプロジェクトをフォークする
- Bluemix にログインして、MongoLab サービス・インスタンスを追加します。インスタンスはアンバインドのままにして、名前 (例えば、MongoLab_profilesExample) を設定し、その名前をメモしておきます。
- DevOps Services で、私の profiles プロジェクトをクリックし、「EDIT CODE (コードの編集)」、「FORK (フォーク)」の順にクリックして、フォークされるプロジェクトに名前を付けます。これにより、DevOps Services がプロジェクト構造を自動的にコピーします。
- 目的のデータベースにリンクするように manifest.yml ファイルに変更を加え、このファイルの中で皆さんのアプリケーションに固有の名前を設定します (以下のコード・リストを参照)。
applications: - services: - MongoLab-profilesExample disk_quota: 1024M host: myprofilesapp name: myprofilesapp command: node app.js path: . domain: mybluemix.net instances: 1 memory: 512M
- 皆さんのアプリケーションを Bluemix にデプロイして実行する前に、いくつかの環境変数を設定する必要があります。
- 皆さんの新規アプリケーションの「Runtime (ランタイム)」セクションを表示します。Bluemix はこのセクションに、環境ストリングを設定するための便利な UI を提供しています。この UI を使用すれば、キーを入力する際に一般の目に触れるという事態がなくなるため、キーの秘密が保護され、コードを安全にコミットできるようになります。
以下の画像に示されているように、「Environment Vriables (環境変数)」セクションの「USER-DEFINED (ユーザー定義)」タブにアクセスしてキーを追加します。
- Bluemix からアプリケーションを再起動します。これで、次のステップに進む準備ができました。
ステップ 3. 認証をセットアップし、ユーザーごとの回数制限の使用を指定する
Twitter の API には回数制限があります。この制限は、ある特定の時間内にユーザーが実行できるリクエストの数を設定することで、サーバー上で対処しきれないほどの要求が発生するのを防いでいます。Twitter では、カスタム・アプリケーションをプログラミングする際には、単一のアカウント (アプリケーション開発者のアカウントなど) からアプリケーションが実行されるようにするのではなく、アプリケーションのユーザーに割り当てられたアカウントを使用してアプリケーションが実行されるようにすることで、ユーザーごとの回数制限が適用されるようにすることを推奨しています。
例えば、私の ProfileWords アプリケーションは、ユーザーがフォロワーの名前を入力すると、フォロワーのリストを要求するリクエストを送信します。このアプリケーションでは、このリクエストによって最大 1000 のアカウント名が返される可能性があります。Twitter の回数制限では、そのようなリクエストは 15 分間で 15 回まで許可されます (プロフィールの調査を担当しているとしたら、この制限の値は小さいように思えるかもしれませんが、人生とはそんなものです)。
最初のステップで行うことは、ユーザーの認証です。これにより、API を呼び出して、該当するユーザー個人の回数制限の範囲内で処理することが可能になります。
私は数時間かけて、Node を使用して Twitter に対する認証を行う方法を調べました。これは一般的なタスクとは言え (多くのサービスではオープン認証を使用します)、Node テクノロジーは急速に変化しているため、私が見つけたサンプルは最新の Node OAuth モジュールでは動作しませんでした。
そこで、OAuth を使用して Twitter に接続する方法をシェアする目的で、独立したプロジェクトを開発しました。そのプロジェクトに含まれる README ファイルに、このアプリケーションを複製して Twitter 開発者独自の情報を追加するステップが詳細に説明されています。
次に記載するコード・リストでは、以下の一般プロセスを用いています。
- ユーザーがアプリケーションの URL を入力すると、Twitter を介してログインするよう促されます。
- ユーザーが「Login (ログイン)」をクリックすると、Twitter 認証ページにリダイレクトされます。
- Twitter にログインした時点で、ユーザーはあらかじめプログラミングされたコールバック・ページ (この例の場合は、ワード・クラウド・ページ) にリダイレクトされます。コールバック URL は、サブプロジェクトの server.js ファイルにプログラミングされています。
このスケルトン・コードを独自の Twitter 認証に使用するためのステップについては、このプロジェクトの README ファイルで概説しています。/sessions/connect パスは、ユーザーのセキュア Web サイト上に Twitter ログイン・ダイアログ・ボックスを表示した後、/sessions/callback パスにユーザーをリダイレクトします。指示されているとおり、自分自身の Twitter 資格情報を使用することが極めて重要です。
ProfileWords プロジェクトには、これと同じ認証手法を採用して app.js ファイルに組み込んであります。
ユーザーの認証が完了すると、そのユーザーに関する追加情報を Twitter から引き出すことができます。ユーザーのユーザー名、地理的位置情報、ユーザーが自分の Twitter ページのデザインで選んだ色など、豊富な情報を入手することができます。
必要不可欠な情報は、ユーザーの秘密鍵です。Twitter に対する以降の問い合わせでは、その秘密鍵を使用しなければなりません。以下のコード・リストに、ユーザーの秘密鍵が示されています。このデータは、後でユーザーに代わって使用できるように Mongo データベースに保管します。
app.get('/profilewords.html', function(req, res){ var twitterVerification = "https://api.twitter.com/1.1/account/verify_credentials.json"; var token = req.session.oauthAccessToken; var secret = req.session.oauthAccessTokenSecret; consumer.get( twitterVerification, token, secret, function (error, data, response) { if( error ){ console.log( 'Twitter verification error\n' ); console.log( error ); res.redirect('/sessions/connect'); } else { var parsedData = JSON.parse(data); var person = ( {'name':parsedData.screen_name, 'oauth_access_token': req.session.oauthAccessToken, 'oauth_access_token_secret': req.session.oauthAccessTokenSecret } ); var collection = followersDatabase.collection( 'tokens' ); collection.remove( { 'name':parsedData.screen_name }, errorHandler ); collection.insert( person, {safe:true}, errorHandler ); res.sendfile('profilewords.html'); } }); });
ステップ 4. Mongo に接続する
Node サーバー・コードは、Twitter API へリクエストを送信する際に、ユーザーの Twitter 秘密鍵を含めることができなければなりません。Twitter へのリクエストには、公開鍵と秘密鍵の両方が必要です。
私は公開鍵を、秘密鍵を見つけるためのデータベース・ハンドルとして使用しています。ProfileWords アプリケーションでは複数のユーザーを同時にサポートできるようにしたいので、複数のユーザーに代わって、それぞれのユーザー固有の Twitter 資格情報を使用して、リクエストを受け入れて編成できる必要があります。
ユーザーが認証を行うと、Twitter はそのユーザーの秘密鍵を提供します。この秘密鍵はデータベースに保管されます。それ以降はユーザーがリクエストを発行すると、アプリケーションが、Web ブラウザーに保持されてリクエストと一緒に送信される公開鍵の対として保管されている秘密鍵を探します。
このシーケンスを以下に示します。
Mongo はコネクション・プールと連動します。私の Node アプリケーションは、起動時にコネクションを作成します。
mongo = { "hostname":"127.0.0.1", "port":27017, "username":"", "password":"", "name":"", "db":"db", "url":"mongodb://127.0.0.1:27017/db" }; path = mongo.url; MongoClient.connect( path, function(err, followersDatabase) {
私の Node アプリケーションのすべては、このコネクションの中で実行されるので、コネクションが作成された後は、followersDatabase
式を使用するだけでデータベースを参照することができます。
Mongo の多くの例では、リクエストが実行されるたびに新しいコネクションが作成されます。私は経験から、この手法は PaaS ランタイムにデプロイすると、すぐにうまくいかなくなることを学びました。Mongo のドキュメント (MongoClient.connect
について学んだドキュメント) では、コネクション作成済みのセッションを使用してリクエストを実行するように推奨しています。それが、私が行った方法です。
私は、Mongo のいくつかの基礎を理解するためのリファレンスとして、専用の単純なデータベース接続プロジェクトを作成しましたが、app.js の中でも、私がどのように Mongo を使用しているかを調べることができます。
例えば、以下のコードは Twitter にリクエストを送信できるようにするために、シークレット・トークンを探します。
app.param('id', function(req, res, next, id){ res.setHeader( 'Content-Type', 'application/json' ); if( req.headers['oauth_token'] ){ var token = req.headers['oauth_token']; var cloudType = req.headers['cloudtype']; var collection = followersDatabase.collection( 'tokens' ); collection.findOne( { 'oauth_access_token': token }, function( err, item ) { var config = { consumer_key: 'YOUR CONSUMER KEY', consumer_secret: 'YOUR CONSUMER SECRET', access_token_secret: item.oauth_access_token_secret, access_token: item.oauth_access_token } console.log( 'account: ' + item.name ); retrieveProfiles( config, res, id, cloudType ); var requests = followersDatabase.collection( 'requests' ); var date = new Date(); var request = ( { 'twitterId':id, 'timeStamp': date, 'account': item.name } ); requests.insert( request, {safe:true}, errorHandler ); }); } next(); }); app.get( "/words/:id", function(req, res ){ } );
アナリティクス・データをデータベースに保存する機会は山ほどあります。例えば、ユーザー別に各リクエストをカウントすることや、ワード・クラウドのカラー・テーマの選択内容を記録することができます。アプリケーションが現在行っている反復処理では、データベースを使用して、複数のユーザーのトークン・アクセスを管理します。
この時点で、Node と express を使用して次に行うステップ (Mongo の使用、認証の処理など) を網羅しました。他のソーシャル・メディア・マッシュアップでも、同じビルディング・ブロックを使用することができます。これらのビルディング・ブロックは大いに役立つはずです。
以上の知識を積み上げるには少し時間がかかったものの、私はそのプロセス (問題を解決して学習するプロセス) にすっかり病みつきになりました。これらの有用な Node パッケージが、しっかりとした土台となります。
ステップ 5. D3 で出力を可視化する
独自にハードコーディングした Twitter 認証を使用してデータを取得するアプリケーションをハードコーディングするには数時間かかりましたが、私はすぐに JavaScript によるワード・クラウドを見つけ、私のアイデアの基本的な部分は有効であることがわかりました。
その後の話です。このアプリケーションをどのように拡張するかについて、次から次へとアイデアが浮かんできましたが、それには多用途の可視化ライブラリーが必要でした。つまり、グラフや円グラフなどといった他の形でデータを表示する方法が必要だったのです。そのようなライブラリーの調査を開始した後、ほどなくして D3 を見つけました。
Jason Davies 氏は D3 JavaScript ライブラリーを拡張してワード・クラウドを作成しており、優れたサンプルと説明も付属しています。何度も試した末、私はクラウド内の単語をそれぞれ異なる色に置き換える方法を突き止めました (ワード・クラウドの美しい色の組み合わせを探したところ、サンプルがなかなか見つからなかったため、試行錯誤で魅力的な色の組み合わせを作り出すことにしたのです)。
私はテーマの配列を作成し、単語を描画するたびにテーマからランダムに色を選択する小さなルーチンをプログラミングしました。実験してみて、テーマには最大 5 色の補色を含めるのが良いと判断し、テーマを選択するための小さな UI コンポーネントを組み込みました。人々がワード・クラウドをダウンロードして文書に含められるように、例えば従来の新聞のようなテーマを提供したいと思っていました。そうすれば、モノトーンのテーマを用意できる一方、他の色も使用することができます。私が気に入っているのは、前に示したオレンジ色のテーマです。
データについては、自己紹介文を収集して最も頻出する単語を解析する Node.js コードをサーバー上でプログラミングしました。試行錯誤の結果、データをバランス良く分布させて、しかも単語が過剰な数にならないようにするには、70 の単語が見た目に魅力的だと感じました。サーバーからこのデータが渡されて、ワード・クラウドが描画されます。
function draw(data, bounds) { statusText.style("display", "none"); scale = bounds ? Math.min( w / Math.abs(bounds[1].x - w / 2), w / Math.abs(bounds[0].x - w / 2), h / Math.abs(bounds[1].y - h / 2), h / Math.abs(bounds[0].y - h / 2)) / 2 : 1; words = data; var text = visualisation.selectAll("text") .data(words, function(d) { return d.text.toLowerCase(); }); text.transition() .duration(1000) .attr("transform", function(d) { return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; }) .style("font-size", function(d) { return d.size + "px"; }); text.enter().append("text") .attr("text-anchor", "middle") .attr("transform", function(d) { return "translate(" + [d.x, d.y] + ")rotate(" + d.rotate + ")"; }) .style("font-size", function(d) { return d.size + "px"; }) .on("click", function(d) { load(d.text); }) .style("opacity", 1e-6) .transition() .duration(1000) .style("opacity", 1); text.style("font-family", function(d) { return d.font; }) .style("fill", customFill) .text(function(d) { return d.text; }); var exitGroup = background.append("g") .attr("transform", visualisation.attr("transform")); var exitGroupNode = exitGroup.node(); text.exit().each(function() { exitGroupNode.appendChild(this); }); exitGroup.transition() .duration(1000) .style("opacity", 1e-6) .remove(); visualisation.transition() .delay(1000) .duration(750) .attr("transform", "translate(" + [w >> 1, h >> 1] + ")scale(" + scale + ")"); }
まとめ
私のコードには、複雑な部分が数多く含まれています。このコードは、一般の人々が利用できる純粋なアプリケーションとなることを目指しています。したがって、私はエラー・ケースを扱い、認証トークンを管理し、個人がフォローしているユーザーとそのユーザーのフォロワー、ツイート、お気に入りのリストの表示を切り替えられるようにしています。また、携帯電話でページがロードされる場合にも対応するなど、その他多くの機能を提供しています。
このチュートリアルでは、同様のアプリケーションを作成するための基礎を学んでもらうために、いくつかの重要なビルディング・ブロック (データベースへのポインター、認証、可視化) にフォーカスしました。これ以外のビルディング・ブロックに興味がある場合は、コードの中にその詳細が記述されています。
私の関連記事「What twitter followers tell me about my election candidates」では、最近のオンタリオ州の選挙における候補者のプロフィールを調べるために、このツールを使用しています。
ソーシャル・メディアでのアイデンティティーは、興味をそそる話題です。このソフトウェアの実験には他にも多くの要素を盛り込んで、徐々に拡張していくつもりです。