« 2006年11月 | メイン | 2007年1月 »

2006年12月27日

1人のエンジニアがフォト蔵リニューアルを通して学んだこと(後編)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

naoya です。
今回は、前回からかなり間が空いてしまいましたが、フォト蔵のリニューアルを通して学んだことの後編についてエントリします。

第三章:リニューアル直前

いよいよ、フォト蔵リニューアルまで、後一ヶ月となったところで、かなり厳しい状況になってきました。
そんな状況のため、フォト蔵チームで相談して、細かいバグフィックスは重要なものに絞って、チーム全員でリニューアルを仕上げることに方針を変更しました。
あわせて、harukさんkomagataさんが入社されたことも、当時はとても大きかったです。

これで、リニューアル直前(2006年10月頃)は、次のような人員体制に変更になりました。

・リーダー:1人
・デザイナー:1人
・エンジニア:5人(フォト蔵チームのエンジニア全員)

人員が増えたことにより、今まで僕が1人でやっていたロジックとビュー部分のコード変更をエンジニア5人で分業することにしました。
このころは、ほとんどデザイン部分の変更は終わっていたので、比較的分業しやすかったです。

基本的には、僕が一番フォト蔵のソースコードを理解していたという背景もあったので、ロジック部分は主に僕が変更するようにしました。ビュー部分については、それぞれのページごとに各エンジニアで変更してもらいました。このときのタスク管理には、BTSを使って BTS案件として、このページを作るという案件をたくさん作成しました。当時の、BTS案件の合計数が約150件近くありました。

このときに一番大きな問題となったのは、ロジック部分の変更による思わぬエンバグでした。リニューアル開始直後はかなり急ぎで変更していたため、所々コードが整理されていない部分があったのが原因でした。
このとき、時間をかけて最初にじっくりと自分が理解していないコードをしっかりと理解して、整理することが大事だと実感しました。最初に手を抜いても、結局最後には自分に返ってくることを、まさに体験した出来事と言えるでしょう。

こうして、いよいよリニューアルの直前となったのですが、大幅にデザインが切り替わるため、すでにフォト蔵を利用しているユーザが混乱しないように半月の試用期間を設けることにしました。

リニューアル開始時は、試用期間を設けるところまで考えていませんでしたが、念のため従来のデザインにすぐに戻せるコードにしておいたのが功を奏しました。
ウェブサイトのリニューアルの時には、必ず元のデザインに戻せるような仕組みは、必ず用意した方がいいと思います。
試用期間を設けることにあたり、急遽検討してもらう作業が発生したため、この作業はエンジニア1人に一任しました。

従来のデザインにすぐに戻せるようにはなっていたのですが、細かいところでいろいろな変更がありました。

こうして、いよいよフォト蔵をリニューアルすることになりました。


最終章:デザインリニューアル

こうして、11月1日フォト蔵のデザインリニューアルの試用期間を開始しました。
簡単にデザインリニューアルを試用してもらうため、切り替えボタンを押すだけですぐにデザインを切り替えられるようにしました。
また、フォト蔵コミュニティ専用トピックを設けました。
約半月の試用期間中に、たくさんのフォト蔵ユーザからフィードバックをいただきながら、試用期間中は主にデザインの調整や変更を重点的に行いました。


本当にたくさんのフィードバックをいただいたので、とてもやりがいのある仕事になりました。
今日現在も、たくさんのフォト蔵ユーザからフィードバックをいただいて、デザインの調整や機能追加などを行っている毎日です。
ウェブサービスを開発している醍醐味は、やはり使ってくださるユーザからフィードバックが来ることにつきると思います。


というわけで、二回に分けて僕が体験したウェブサイトのリニューアルを通じて、体験したこと、学んだことを書きました。


今後とも、フォト蔵をよろしくお願いいたします!

2006年12月26日

マインドマップの手法を取り入れてより充実したテストシナリオを作成する
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは! 
やまもと@テスト番長改め、やまもと@ 'Morpheus' テスト番長です。

最近ウノウに加入したgotandajin氏が極度のマトリックス好きということが判明したので、少々調子を合わせてみました。どうやらウノウでキャスティングを考えると僕はモーフィアス役らしいです。(顔写真参照)

さてさて、それでは今回も赤いピルをお届けしましょうか。

QAのブログをぶらぶら覗いていたら、ちょっと面白いエントリーを見つけました。
Jonathan Kohlさんの'Modeling Test Heuristics'という記事で、Mike Kellyさんの'Touring Heuristic'というウェブアプリケーションのシナリオパターンの暗記術についての記事から発展させて、マインドマップを使用してテストシナリオを作成する方法を紹介しています。

mind map
mind map posted from フォト蔵


テストシナリオを作成するとき、文章や一覧表の形で作成することが多いわけですが、
ここではマインドマップのパターンを使用して、視覚的に認識しやすい資料を作っています。
更に色分けを工夫したり、図で表現したりすると、暗記術で得られるパターンとはまた違った多くのシナリオが浮かんでくる、という訳です。

色々なアプローチ法を用意しておくことで、
更に深いテストシナリオの作成が出来そうですね。


Collaborative Software Testing

testingReflections.com

2006年12月25日

DRBDによるコンテンツの相互バックアップ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは satoです。
DRBDは誤解を恐れないで、簡単に言ってしまうと、ネットワーク越しにRAID1を構築できるオープンソースのソフトウェアです。

DRBDには以下の特徴があります。
・カーネルモジュールで動作し、有償でサポートが受けられます
・電源等が壊れても、ソフトウェアRAIDやPICカード型のRAIDと違ってサービスを続けることができます
・heartbeat等と組み合わせて、HAなシステムを構築できます
・secondary(slave、待機系)はマウントすることができません。

DRBDの設定から使用までを簡単に解説しようと思います。また待機系が必要なのですが、待機だけではもったいないので、相互に違う領域をバックアップ(s1のsda3のバックアップ先は s2のsda3、s2のsda4のバックアップ先はs1のsda4)をしてみました。

構成

s1.unoh.net 10.1.0.1
+-------------
| sda3 (drbd0 master)
+-------------
| sda4 (drbd1 slave)
+-------------

s2.unoh.net 10.1.0.2
+-------------
| sda3 (drbd0 slave)
+-------------
| sda4 (drbd1 master)
+-------------
uname -a
Linux s1.unoh.net 2.6.18-1.2200.fc5smp #1 SMP Sat Oct 14 17:15:35 EDT 2006 i686 i686 i386
GNU/Linux

インストール

必要なものを yum でインストールします。

yum install kernel-devel
yum install hardlink
yum install rpm-build

最新のソースをDLします。
wget http://oss.linbit.com/drbd/0.7/drbd-0.7.22.tar.gz

ソースからRPMをビルドします。

tar zvxf drbd-0.7.22.tar.gz
cd drbd-0.7.22
make rpm
cd dist/RPMS/i386/
rpm -ivh drbd-0.7.22-1.i386.rpm
rpm -ivh drbd-km-2.6.18_1.2200.fc5smp-0.7.22-1.i386.rpm

設定

/etc/drbd.conf を編集します。無い場合は作成します。
resource drbd0 {
# 同期プロトコル A, B, C のいずれかを選択
# A:リモートのディスクへの書き込み要求が完了した時点
 # B:リモートのディスクのバッファキャッシュ書き込みが完了した時点
# C:リモートのディスクへの書き込みが完了した時点
protocol B;
incon-degr-cmd "halt -f";

syncer { # 同期の速度
rate 200M;
}
disk { # エラーが起こったときの処理
# pass_on:上位レイヤに通知, panic:カーネルパニックになる, detach:ディスクレスモードで動作
on-io-error pass_on;
}
net { # 接続が切れた場合の処理
# reconnect:再接続,stand_alone:1台だけで継続,freeze_io:IOを止める
on-disconnect reconnect;
}

# 1番目のノードを定義
on s1.unoh.net {
device /dev/drbd0;
disk /dev/sda3;
address 10.1.0.1:7789;
# メタデータの定義
meta-disk internal;
}

# 2番目のノードを定義
on s2.unoh.net {
device /dev/drbd0;
disk /dev/sda3;
address 10.1.0.2:7789;
# メタデータの定義
meta-disk internal;
}
}
resource drbd1 {
 # drbd0 と違うところだけ記述
# 1番目のノードを定義
on s1.unoh.net {
device /dev/drbd1;
disk /dev/sda4;
address 10.1.0.1:7790;
# メタデータの定義
meta-disk internal;
}

# 2番目のノードを定義
on s2.unoh.net {
device /dev/drbd1;
disk /dev/sda4;
address 10.1.0.2:7790;
# メタデータの定義
meta-disk internal;
}
}

DRBDをスタートします
/etc/init.d/drbd start
以下のような状態 Inconsistent(同期がとれていない状態) になります
cat /proc/drbd
version: 0.7.22 (api:79/proto:74)
0: cs:Connected st:Secondary/Secondary ld:Inconsistent
ns:71984032 nr:0 dw:71984032 dr:52390757 al:169318 bm:0 lo:0 pe:0 ua:0 ap:0
1: cs:Connected st:Secondary/Secondary ld:Inconsistent
ns:45988528 nr:0 dw:45988528 dr:91767569 al:185559 bm:0 lo:0 pe:0 ua:0 ap:0

本来ならここでprimaryモードに移行するために

drbdadm -- --do-what-I-say primary drbd0

と行うのですが、これを行うと、一旦ディスクを同期するため、
サイズによってはかなりの時間がかかってしまいます。

この作業をスキップするために以下のスクリプトを使用します。

wget http://svn.drbd.org/drbd/branches/drbd-0.7/testing/read_gc.pl
wget http://svn.drbd.org/drbd/branches/drbd-0.7/testing/write_gc.pl

read_gc.pl resource_name
write_gc.pl resource_name 1

/etc/init.d/drbd restart

プライマリーに移行します
s1.unoh.net にて drbdadm primary drbd0
s2.unoh.net にて drbdadm primary drbd1

cat /proc/drbd

version: 0.7.22 (api:79/proto:74)
0: cs:Connected st:Primary/Secondary ld:Consistent
ns:71984032 nr:0 dw:71984032 dr:52390757 al:169318 bm:0 lo:0 pe:0 ua:0 ap:0
1: cs:Connected st:Secondary/Primary ld:Consistent
ns:45988528 nr:0 dw:45988528 dr:91767569 al:185559 bm:0 lo:0 pe:0 ua:0 ap:0

Consistent となって同期がとれていることがわかります

mkfs.ext3 /dev/drbd0
mount /dev/drbd0 /mnt/drbd0
とするとファイルシステムを作成し、デバイスをマウントすることができます

テスト

s1.unoh.net で適当なファイルを作成します。
cd /mnt/drbd0
touch hoge
ls -la
-rw-rw-r-- 1 unoh unoh 0 12月 25 14:39 hoge
デバイスをアンマウントしてセカンダリーに移行します
cd ..
umount /mnt/drbd0
drbdadm secondary drbd0

s2.unoh.net でプライマリーにして、デバイスをマウントします。

drbdadm primary drbd0
mount /dev/drdb0 /mnt/drbd0

作成したファイルがあるか確認します

cd /mnt/drbd0
ls -la
-rw-rw-r-- 1 unoh unoh 0 12月 25 14:39 hoge


DRBDの設定のために 以下の書籍を参考にしました。
Linuxアドバンストネットワークサーバ構築ガイド HAサーバ構築編
デージーネット
秀和システム
売り上げランキング: 14319
おすすめ度の平均: 4.5
5 ミッションクリティカルなサーバを構築するなら
3 構築から運用まで担当する方向け
5 高度だが説明はわかりやすい

2006年12月21日

JavaScriptでクリップボードを使う(IE/Firefox)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、さかとくです。師走で忙しいですね。今回は、JavaScriptでクリップボードを使うプログラムを作ってみます。IEとFirefoxで動く簡単なライブラリを作ってみましたので、参考にしてください。

IEだけで動かすのは、簡単なのですが、FireFoxではクリップボードを操作する方法がありません。そこで、FireFoxでも使えるようにFlashを使って工夫してみます。

まず、参考までにIEでクリップボードを扱うJavaScriptを見てみましょう。IEなら以下のように一行書くだけです。
// クリップボードに Helloと書き込む(IEのみ)
clipboardData.setData("Text", "Hello");

FireFoxでコピーするためには、Flashを使います。Flashでは以下のように書くと、"Hello"という文字列をクリップボードに書き込みます。Flashなら、IEだろうが、FireFoxだろうが動きますので、これを利用します。
// クリップボードに Helloと書き込む(Flash)
System.setClipboard( "Hello" );

Flash Player8以降では、JavaScriptからFlashを自由に操作するExternal APIというものがあります。これを利用すれば、JavaScriptから、クリップボードを操作することができます。

MTASCというフリーのFlashコンパイラを使うと以下のように書けます。
import flash.external.ExternalInterface;
class clipbrd {
 static function main () { var clip = new clipbrd(); }
 function clipbrd() {
  ExternalInterface.addCallback("copyText", this, copyText);
 }
 function copyText(s:String) {
  System.setClipboard(s);
 }
}
これで、バッチリですね! コンパイルした完成品を以下においておきます。
ファイルをダウンロード
このライブラリの使い方を以下に書いておきますので、使ってみてください。

■[使い方]

(1) 以下のファイルをHTMLと同じフォルダか参照できるところにコピー
-clipbrd.swf
-clipbrd.js
-swfobject.js

(2) 以下のコードをHTMLに貼り付ける
--- ここから ---
<script type="text/javascript" src="swfobject.js"></script>
<script type="text/javascript" src="clipbrd.js"></script>
--- ここまで ---

(3) クリックしたらコピーするようにする場合には以下のように記述

--- ここから ---
clipbrd.copyText("hogehoge");
--- ここまで ---

2006年12月20日

五反田人がウノウの本棚で見つけた三冊の書籍紹介。
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

今月入社のgotandajin@待っていたよアンダーソン君。です。
テスターとして採用されましたが、まだまだ全然見習いでして、モーフィアス番長に日々ビシバシ鍛えられております。よろしくお願いします。

さて、unohのオフィスにはこんな感じの小さな本棚があるのですが、

CIMG0418.JPG
CIMG0418.JPG posted by (C)フォト蔵

ITベンチャーらしくIT系の技術書はもちろんのこと、新書や雑誌、ホットペッパーなど色々置いてあります。
そして今回は本棚の中にあったもののうち、最近ご献本頂いた3冊ほどをピックアップしてご紹介させて頂こうと思います。


それでは早速。

まずは、高林哲さんから頂いたBinary Hacks ―ハッカー秘伝のテクニック100選です。

Binary Hacks ―ハッカー秘伝のテクニック100選
高林 哲 鵜飼 文敏 佐藤 祐介 浜地 慎一郎 首藤 一幸
オライリー・ジャパン
売り上げランキング: 477

「カユいところに手の届く良書です。
例えば#78「シグナルハンドラからプログラムのコンテキストを書き換える」は、私が以前調べて結局分からず終いだったテクニックでした。
UNIXのシグナルを扱った書籍、Webサイトは数多くありますが、ここまで深く掘り下げて解説しているものはまず見つからないでしょう。」
~~某U社スタッフhiracchiさん談~~



次に、有限会社アートライの坂井恵さんから頂いた超・極める!MySQLです。

超・極める!MySQL
超・極める!MySQL
posted with amazlet on 06.12.21
坂井 恵 志村 和彦 ひろせ まさあき 松信 嘉範
翔泳社
売り上げランキング: 11762

「この本が出た時点では、たぶん、MySQLについての最もフレッシュでマニアック、かつ実践的な内容が載っている本です。
MySQLを使おうとする人は、自分の知らなかったことが書かれてあったりすることも多いかと思うので、一回は読んでおくといいと思います。
個人的には、最近では資料がそろってきた文字コード関連の問題についての記事が参考になりました。」
~~某U社スタッフkeitaさん談~~



最後に、サイボウズラボの秋元裕樹さんから頂いたPHP×WebサービスAPIコネクションズです。

PHP×WebサービスAPIコネクションズ
秋元 裕樹
ソフトバンククリエイティブ
売り上げランキング: 9691

「これからPHPでAPIを扱いたい、また、マッシュアップ的なシステムを構築してみたいと考えている人にとっては有益だと思います。
APIに関しての基礎知識的なものについての記述が多いですし、
サンプルコードを使って、諸API(AmazonWebサービス、del.isio.usAPIs、livedoor番組表、YouTubeデベロッパーAPIなど、全26種と多彩)との連携について、サンプルコードを交えて実例解説してくれているのでAPI初心者にとってはとっつきやすいと思います。」
~~匿名neo氏談~~



・・・と、どれも必携の良書ですね!
本屋さんにお立ち寄りの際は是非手にとってみてください。

今回ウノウラボ初の試みとして、ご紹介した3冊の本のアフィリエイトを貼ってみました。
といっても営利目的ということではなくて、もし収入があれば
社外に対して還元できる形で、面白いことできないかな?とみんなで話しています。
例えばunohが普段使っているオープンソースプロジェクトへの寄付金に充てたりすると良さそうですよね!

実際に行動することが出来た時は、またここで皆さんにご報告させていただきますね。

2006年12月19日

Mac OS Xで携帯サイトの開発環境を整える
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

尾藤正人(マカー3号)です。

家でも会社でも MacBook を使うようになって、名実共にマカーの仲間入りをしました。

最近はずっと携帯サイトの開発をやっているのですが、MacよりもWindowsの方が携帯サイト開発用のツールは充実してます。 携帯サイトを開発しているMacユーザの方で、本当はWindowsは使いたくないんだけど、Windowsマシンを使ってたり、Parallels Desktop使ってる方は多いんじゃないでしょうか。

新しいParallels Desktopでは、Coherenceモードを使えばWindows上のアプリがMac上のアプリかのように使えるので、大きな問題はないのかもしれませんが、やはりMacネイティブでできるようにしたいものです。

というわけでMacで携帯サイトの開発環境を整えてみたので、何をやったのかを具体的に書いてみたいと思います。

Macで絵文字を表示できるようにする

ピクチャ 1
ピクチャ 1 posted from フォト蔵

下記の記事を参考にしました。やってることは全く同じです。

imode用携帯サイトを開発する場合のメモ

  • i絵文字をダウンロードする。
  • Windowsの実行形式になってますが、LHAで解凍します。
  • mv iemoji.tte $HOME/Library/Fonts/iemoji.ttf
  • 各アプリで使用するフォントをi絵文字(i-emozi)を選択します。

これで Cocoa アプリで絵文字が表示できるようになります。 手元ではMac標準のテキストエディタでは問題なく絵文字を表示できましたが、Safariでは絵文字が化けて表示されます。 ブラウザでの表示の確認には未だにWindowsを使っているので、この辺の詳しい情報お持ちの方いたら、よろしくお願いします。

Macで絵文字を入力する

ピクチャ 2
ピクチャ 2 posted from フォト蔵

絵文字の表示ができるようになったので、次は入力です。 エモジモ2というソフトウェアを使うと絵文字の入力ができます。 普通にインストールして起動するとアプリが起動するので、後は入力した絵文字をテキストエディタまでドラッグアンドドロップするだけ。

まとめ

Macでも頑張れば、絵文字の表示、入力ができるようになります。 残念なのはブラウザでの表示ができないことです。 これができれば、ほぼ完全にMacだけで開発ができるのですが...

2006年12月18日

JavascriptライブラリをJSANへアップする手順
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

komagataです。

最近、色々なソースを読んでJavascriptの勉強をしているんですが、その中で比較的ソースが短く、シンプルなものが多いのでJSANのライブラリを参考にさせてもらっています。出来てから1年以上経ってるのにイマイチ使われていないような気がしますが、勉強ついでに以前作ったpprompt.jsというライブラリをJSAN用に変更してアップしてみました。

jsan logo
jsan logo posted from フォト蔵

そもそもJSANとはJavaScript Archive Networkの略で、要はTeXのCTAN、PerlのCPAN、PHPのPEARみたいなライブラリをアップしたりできるところだそうです。(アップに際して厳密な投票プロセスなどは無いのでPEARとは少し違うかもしれません)

JSANライブラリの使い方は長くなるので下記等を参照していただいて、早速アップするモジュール作成していきます。

Collection & Copy - JSAN-0.10 - ドキュメント
http://d.hatena.ne.jp/brazil/20050911/1126388204

アップの仕方はJSANのサイトの下記に書いてあります。
http://master.openjsan.org/documentation/dists.html

まず、ココからモジュールの雛形をダウンロードします。

pprompt.jsという名前だったものをルールに従ってDialog.jsに変更して、lib/Widgetディレクトリに置きました。

Widget.Dialog-0.01/
 tests/
 lib/
  Widget/
   Dialog.js
 README
 MANIFEST

そしてDialog.js自体をExample.jsを参考にしながら変更します。といっても変更点はそれほどありませんでした。

Widget.Dialog.VERSION = '0.01';
Widget.Dialog.EXPORT = ['alert', 'confirm', 'prompt', 'close'];

バージョン番号と、JSAN.useなどでexportできる関数を指定するぐらいです。そして、Perlで良く使われるPOD(Plain Old Document)形式で各種コメントを書いておきます。

/*
 
=head1 NAME
 
Widget.Dialog - Simple Dialog Library
 
=head1 SYNOPSIS
 
// Functional Example
Widget.Dialog.alert('Alert!!!');
Widget.Dialog.confirm('Confirm!!!');
Widget.Dialog.prompt('Prompt!!!');
 
(略)
 
=cut
 
*/

次にテストを書きます。JSANには便利なテスト用のライブラリが揃っていて、使い方は見た感じ簡単そうです。(というか難しい機能は分かってない)

var test = new Test.Builder();
test.plan({tests: 1});
 
Widget.Dialog.alert('Alert dialog');
test.ok(document.getElementById('dmsg').innerHTML == 'Alert dialog', 'open alert dialog');
Widget.Dialog.close();

Test.Builderのplanメソッドにテストの個数を指定します。そしてokメソッドの第一引数に結果がtrueになるようにテストを書き、第二引数にテストの名前(メッセージ)を書きます。

上記のテストの場合、テスト結果はブラウザに下記のように出ました。

1..1
ok 1 - open alert dialog

おお、これは簡単だし便利そう。Widget.Dialogのテストをopen.htmlとして書いてみました。

var test = new Test.Builder();
test.plan({tests: 4});
 
Widget.Dialog.alert('Alert dialog');
test.ok(document.getElementById('dmsg').innerHTML == 'Alert dialog', 'open alert dialog');
Widget.Dialog.close();
 
Widget.Dialog.confirm('Confirm dialog');
test.ok(document.getElementById('dmsg').innerHTML == 'Confirm dialog', 'open confirm dialog');
Widget.Dialog.close();
 
Widget.Dialog.prompt('Prompt dialog');
test.ok(document.getElementById('dmsg').innerHTML == 'Prompt dialog', 'open prompt dialog');
Widget.Dialog.close();
 
Widget.Dialog.prompt('Prompt dialog');
document.getElementById('dinput').value = 'foo bar baz';
test.ok(document.getElementById('dinput').value == 'foo bar baz', 'input value');
Widget.Dialog.close();

結果。

1..4
ok 1 - open alert dialog
ok 2 - open confirm dialog
ok 3 - open prompt dialog
ok 4 - input value

良さそうです。
さらに、このように作ったテストのHTMLを続けて実行できるのがTest.Harness.Browserです。index.htmlとして下記のように書いてみます。

var jsan = new JSAN('lib');
jsan.use('Test.Harness.Browser');
new Test.Harness.Browser().runTests(
  'open.html'
);

これだとopen.html一個しか無いのであんまり良さがわからないですが、runTestsメソッドにテストのhtmlをいくつも書けるのでテストが増えた場合は便利そうです。

結果。

open.html... ok
All tests successful. Files=1, Tests=4, 0.235 seconds

それぞれのテストページへのリンクも張られていて良さ気です。こんなに手軽なもんが存在するならJSANにアップするとか関係無く使いたかった。今頃知ったことを後悔しました・・・。

あとは、パッケージに含めるファイルを羅列するMANIFEST、authorなどのパッケージに関する情報を記述するMETA.ymlなどのファイルを作成して、tar.gzに固める作業がありますが、面倒臭そうなのでパッケージングを簡単にしてくれるperlのModule::Build::JSANを使ってみました。

Module::Build::JSANのインストール。

$ perl -MCPAN -e shell
cpan> install Module::Build::JSAN

Module::Build, Module::Build::JSANのドキュメントに従ってBuild.PLファイルを作成します。

#!/usr/bin/env perl
use strict;
use Module::Build::JSAN;
 
my $build = Module::Build::JSAN->new(
    module_name => 'Widget.Dialog',
    license     => 'gpl',
    dist_author => 'Masaki Komagata <komagata@gmail.com>',
    keywords    => [qw(Widget Dialog)],
    requires    => {},
);
 
$build->create_build_script;

これで大体準備完了です。ディレクトリ構成はこんな感じです。

$ tree
.
|-- Build.PL
|-- MANIFEST
|-- README
|-- doc
|-- lib
|   `-- Widget
|       `-- Dialog.js
`-- tests
    |-- index.html
    |-- lib
    |   |-- JSAN.js
    |   `-- Test
    |       |-- Base.js
    |       |-- Builder.js
    |       |-- Harness
    |       |   `-- Browser.js
    |       |-- Harness.js
    |       `-- Simple.js
    `-- open.html
 
7 directories, 12 files

そしてパッケージを作成します。

$ perl Build.PL
$ ./Build dist

できたパッケージをJAUSE(JavaScript Authors Upload Server)を使ってアップします。(PerlのPAUSEみたいなもの)
単にココでユーザ登録をし、ログインしてフォームから出来たtar.gzファイルをアップします。

この後どういうプロセスが存在するのかよく分かりませんでしたが、半日程待つとトップページに表示され、アップしたライブラリがダウンロードできるようになりました

jsan
jsan posted from フォト蔵

少し手間どりましたが、CPANに慣れている人ならすんなりいけるんじゃないかと思います。(慣れていない人 > 俺)

まだアップされているライブラリが少ないのでこれを機会に自作のライブラリをJSANにアップしてみてはどうでしょうか。

2006年12月15日

ThinkITのPHP開発手法の第二回目の連載が掲載されました!
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

naoya です。
ThinkIT にてウノウエンジニア陣による PHP 開発手法の連載が始まっていますが、第二回目の記事が掲載されました。
第二回目の記事は、Subversion 入門の記事となります。

=== 本文 ===

PHP開発におけるSubversionを用いたバージョン管理
今回は、Subversionによるバージョン管理方法とウノウでの導入事例について前編と後編にわけて紹介していきます。

Subversionとは
Subversionとは、無償で利用できるバージョン管理システムです。現在もオープンソースで活発に開発が進んでおり、執筆時点の最新バージョンは1.4.2となります。バージョン管理システムとは、ソースコードや仕様書などを含むドキュメントなど、時間とともに内容が変化するファイルを管理するシステムの総称です。
...

残りは、ThinkIT のページで読んでください。





※未承諾広告 ウノウで働きませんか
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

Keitaです。

ウノウでは、アルバイト(もちろん正社員も)を募集しています。
今はPHPプログラマが足りないので、そこらへんがある程度できる人が望ましいですが、もちろん他の部門も絶賛募集中です。
PHPだけか?といわれると、今のところPHPばっかりですが、別に他の言語でもかまわないのです。
Webサービスを作る工程のどこかで作業をすることにモチベーションを感じる人は、
こちらから
もっと詳しいことが知りたい方は、ここらへんみてもらうか、メールや問い合わせフォームからご質問ください。

2006年12月13日

PEAR::DBをオーバーロードして手軽にロギングとプロファイリングする
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

ウノウに入社してからすっかりエンゲル係数と体重が増加して困っているjokagiです. このまま年を越すのは微妙なので効果的なダイエット方法を教えてください. ということでエントリをはじめたいと思います.

さて今回はよくある「データベースのアクセスログ取りたいね」とか「プロファイルを楽に取りたいね」という要求をふとひらめいたアイデアでお手軽に実現してみました.

まず.いきなりすみませんが案件的にテスト実装した環境がPHP 4を使用していたため,この実装はまだPHP 5以上での動作は確認していません. また,今更メンテナンスモードで消える運命のPEAR::DBを扱うのかよ!!という方もいらっしゃると思いますが,とりあえず気づかなかったことにしてください.

基本的で最低限のPEAR::DBの使い方

PEAR::DBを丁寧に説明してもきりがないのでざっくりだけ. 下記はMySQLにつないであるテーブルからある条件の行を取ってくる例です.

$dsn = 'pgsql://user:pass@localhost/database';
$db = &DB::connect($dsn);
if (!DB::isError($db)) {
    $sql = 'SELECT * FROM a_table WHERE name = ?';
    $res = &$db->query($sql, array('username'));
    if (!DB::isError($res)) {
        while ($row =& $res->fetchRow()) {
            processRow($row);
        }
    }
}

このレベルから何をやっているか分からない方は公式マニュアルPEAR::DBの項目でいろいろなサンプルが用意されているので参考にしてください.

PEAR::DBをどう料理するか

ありがちなPEAR::DBの拡張パターンとしてextendsで継承し,DSNを何らかの方法で勝手に取得してオブジェクトのインスタンスを行うという感じがあると思います. また,さらにクエリログを取りたい!!などになると,ぱっと思いつくものは下記の方法しかありませんでした.

  1. 新規ドライバーを作成する.上記例だとDB_pgsqlを派生し,DB_mypgsqlみたいなクラスのファイルを作成し,DSNでそれを指定する(つまり「mypgsql://user:pass@localhost/database」)みたいなDSNにする).ってすごいダサいクラス名ですね(凹)このクラスでログを取ったり時間を計測したりする.
  2. DB::connect()が返すオブジェクトをプロパティに持つクラスを作成し,query()など問い合わせに必要なメソッド群をDB_pgsqlにバケツリレーし,ログを取ったり時間を計測する処理を随時挟んでいく.

「新規ドライバーを作成する」の方は実際にはPEAR::DBの実装が駄目すぎるので(個人的主観ですが)綺麗に実装できません(ドライバークラスのファイルは必ずディレクトリ名「DB」の下にないといけないとか). 後者も必要分メソッドを作るとヘタしたらquery(),getOne(),getAll(),...など結構沢山のメソッドを(ただバケツリレーするだけの単調なコードを)記述しなければいけません. 前者は個人的にやる気が起こらなかったので後者をどうにか楽にできないかなーと考えていたのですが,簡単にできるんですよ.オーバーロードで.

オーバーロードって何?

一般的な話でもPHP的な話でもちゃんと書くと今晩寝られなくなるのでやりません. ここでいうオーバーロードは一言で言うと「動的にクラスメソッドやプロパティを追加する」みたいなことができる仕組みです. ざっとした概念はPHPの公式マニュアルでも読んでください. だけではアレなのでとりあえず簡単なサンプルを用意してみました.

class ShowMessage
{
    function ShowMessage()
    {
    }

    /**
     *  オーバーロードクラスの動的メソッドの処理を行う
     *  特殊メソッド.$methodが「say」で始まる場合,
     *  1個目の引数を表示します.
     *
     *  このコードはPHP 4でしか動かないことに注意
     *
     *  @param string $method 実行されたメソッド名
     *  @param string $argument メソッドに付加された引数
     *  @param mixed $return メソッドの返り値への参照
     */
    function __call($method, $argument, &$return)
    {
        $result = null;
        if (preg_match('/^say([a-z]+)$/i',$method,$matches) && isset($argument[0])) {
            printf("%s is say '%s'\n", $matches[1], $argument[ 0]);
            $result = true;
        } else {
            $result = false;
        }
        return $result;
    }
}
overload('ShowMessage');

これを実行した結果はこんな感じです. ここでは上記クラスをShowMessage.phpというファイル名で保存した前提になっています.

$ php -r '
  require_once "ShowMessage.php";
  $obj = &new ShowMessage;
  $obj->sayTom("Hello!");
  $obj->sayGeoge("Guha!");'
  $obj->foo("Guha!");'
tom is say 'Hello!'
geoge is say 'Guha!'
PHP Warning:  Call to undefined method showmessage::foo() in Command line code on line 6

クラスShowMessageのメソッドはShowMessage()と__call()だけです.前者は単なるコンストラクタで,今回のように動的にメソッドが増えて見えるのは__call()の処理によるところが大きいです. この辺り分からないけど興味のある人はマニュアルを参考にしつつサンプルクラスを弄ってみてください.

PEAR::DBをオーバーロードで料理してみよう

さてここまでで大体想像はついたでしょうか? このエントリのはじめの方で「DB_common::connect()が返すオブジェクトをプロパティに持つクラスを作成し,query()など問い合わせに必要なメソッド群をDB_pgsqlにバケツリレーし,ログを取ったり時間を計測する処理を随時挟んでいく」という方法を紹介しましたが,今から新しくクラスをオーバーロード前提で実装します.

段々長くなってきたので細かい説明は省いて調理後のコードをさっさと出します. 下記例はとりあえずconnect()でデータベースに接続後,__call()を使用してquery(),getOne(),getAll()だけ対応させます.

class MyDB
{
    var $_db;

    function MyDB()
    {
        $this->_db = null;
    }

    function getDsn()
    {
        $result = null;

        /*
         *  ちゃんとした作りにするなら設定ファイルなりから
         *  DSNを生成して返します
         */
        $result = 'pgsql://user:pass@localhost/database';

        return $result;
    }

    function connect()
    {
        $result = null;

        $result = &DB::connect($this->_getDsn());
        if (!DB::isError($db)) {
            //  接続に成功したときだけ維持
            $this->_db = &$db;
        } else {
            $this->_db = null;
        }

        return $result;
    }

    /**
     *  オーバーロードクラスの動的メソッドの処理を行う
     *  特殊メソッド.$methodが「say」で始まる場合,
     *  1個目の引数を表示します.
     *
     *  このコードはPHP 4でしか動かないことに注意
     *
     *  @param string $method 実行されたメソッド名
     *  @param string $argument メソッドに付加された引数
     *  @param mixed $return メソッドの返り値への参照
     */
    function __call($method, $argument, &$return)
    {
        $result = null;

        $funcs = array('query', 'getone', 'getall');
        if ($this->_db !== null && in_array(strtolower($method), $funcs)) {
            $return = call_user_func(array($this->_db, $method), $argument);
            $result = true;
        } else {
            $result = false;
        }

        return $result;
    }
}
overload('MyDB');

このコードのキモになるのはcall_user_func()ですね. $funcsに許可するメソッド名があったら全部call_user_func()経由で$this->_dbに丸投げします. もっと対応したいメソッドがでてきたら$funcsに追加すればいいのです. 楽ですね…いや手動で追加するのは本当は面倒じゃないか!!

ってことで手抜きをするためにもう少し労力を割きます. やることは簡単で,PHPのクラスオブジェクト関数群get_class_methods()という「クラスメソッドの名前を連想配列として返す(マニュアルより引用)」という関数があります. ようはこの関数経由でメソッド一覧を取得し,それを__call()内で使用すればいいですね. ってことで改変してみました.

class MyDB
{
    var $_db;
    var $_overloadFunctions;

    function MyDB()
    {
        $this->_db = null;
        $this->_overloadFunctions = array();
    }

    function getDsn()
    {
        $result = null;

        /*
         *  ちゃんとした作りにするなら設定ファイルなりから
         *  DSNを生成して返します
         */
        $result = 'pgsql://user:pass@localhost/database';

        return $result;
    }

    function connect()
    {
        $result = null;

        $result = &DB::connect($this->_getDsn());
        if (!DB::isError($db)) {
            //  接続に成功したときだけ維持
            $this->_db = &$db;
            $this->_overloadFunctions = get_class_methods(get_class($db));
        } else {
            $this->_db = null;
            $this->_overloadFunctions = array();
        }

        return $result;
    }

    /**
     *  オーバーロードクラスの動的メソッドの処理を行う
     *  特殊メソッド.$methodが「say」で始まる場合,
     *  1個目の引数を表示します.
     *
     *  このコードはPHP 4でしか動かないことに注意
     *
     *  @param string $method 実行されたメソッド名
     *  @param string $argument メソッドに付加された引数
     *  @param mixed $return メソッドの返り値への参照
     */
    function __call($method, $argument, &$return)
    {
        $result = null;

        $funcs = array('query', 'getone', 'getall');
        if ($this->_db !== null && in_array(strtolower($method), $funcs)) {
            $return = call_user_func(array($this->_db, $method), $argument);
            $result = true;
        } else {
            $result = false;
        }

        return $result;
    }
}
overload('MyDB');

これでPEAR::DBのDB_commonのメソッドはすべて使えるようになりました(といってもすべてのメソッドが正しく動作するかテストしたわけではないですが). ここまでできたらMyDBのオブジェクトは通常のDB_commonのオブジェクトとほぼ等価に使用できると思います.

プロファイルやログの処理はどうしたらいいか

DB_coomonとほぼ等価に動作するMyDBのオブジェクトがあるので,__call()内でcall_user_func()をする前後で時間を計測したり,$methodを見てログを吐いたりすることであたかもPEAR::DBをそのまま使っているようでいて実は勝手にロギングされているといった使い方ができるようになります. 下記は__call()内で時間を計測する例です.

    function __call($method, $argument, &$return)
    {
        $result = null;

        $funcs = array('query', 'getone', 'getall');
        if ($this->_db !== null && in_array(strtolower($method), $funcs)) {
            //  call_user_func()の実行前時間を保存
            list($start_usec, $start_sec) = explode(" ", microtime());
            $start_time = (float)$start_usec + (float)$start_sec;

            $return = call_user_func(array($this->_db, $method), $argument);

            //  call_user_func()の実行後時間を保存
            list($end_usec, $end_sec) = explode(" ", microtime());
            $end_time = (float)$end_usec + (float)$end_sec;

            //  call_user_func()の前後の時間から差分を出す
            //  出した後は各自適切に処理をしましょう
            $diff_time = $end_time - $start_time

            //  call_user_func()の実行条件を定数LOG_FILEが示す
            //  ファイルに記録する例
            $line = strftime("%Y-%m-%d %H:%M:%S");
            $line ,= " Method:$method Argument:".serialize($argument);
            $line .= " Result:".serialize($return);
            $line .= " Time:".diff_time;
            error_log($line, 3, LOG_FILE);
            $result = true;
        } else {
            $result = false;
        }

        return $result;
    }

おしまい

今回のエントリで紹介しているオーバーロードとcall_user_func()の併用を実装に取り込むと下記のようなメリットがあります.

  • PEAR::DB専用の考え方ではないので,一般的なクラスでもアイデアは使用できる
  • 基本的に使いたいメソッドが増えるたびに何らかの修正をする必要がない
  • クラスの仕様(特にメソッド数など)に特にとらわれずに簡単に実装ができる
  • 場合によっては多重継承的な効果を持ったクラスを作ることができる

いいことばかりを書いていますが,問題点もあります.

  • オーバーロードを用いるとPhpDocumentorなどでドキュメントの自動生成を行いづらい
  • オーバーロード自体のノウハウがまだ一般的に広く存在しない
  • __call()の仕様がPHP 4とPHP 5で異なる(PHP 5の場合,引数は2つになる)

こういうオーバーロードは私も初めて使用したのでどういう問題があるかはまだ未知数です. とりあえず今回の手段はこれからも注意深く使ってみようと思います.

2006年12月11日

携帯サイト作成時のXHTMLでの相違点
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんばんは。harukです。

DoCoMo編…となるはずですが、特に書くようなことがないので、今回はXHTMLについて少し書いてみます。

現在ではすべてのキャリアが3G端末がメインとなってきています。

※2006年11月末現在

DoCoMo: 約60%

au: 約90%

SoftBank: 約35%


ほとんどの3Gの端末ではHTMLに加え、XHTMLを使うことができます。

XHTMLを使うことによって、文字の背景色を設定できたりするなど、デザイン表現が多彩になっています。

今回はXHTMLを使用する上での、各キャリアの仕様の違いなどをまとめてみたいと思います。

  • 対応機種
    • DoCoMo
      FOMA(初期の2001,2002,2101以外)
    • au
      WAP2.0ブラウザ搭載端末
    • SoftBank
      W型、3GC型
  • DOCTYPE宣言(推奨)
    • DoCoMo
      <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/1.0) 1.0//EN" "i-xhtml_4ja_10.dtd">
      <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/1.1) 1.0//EN" "i-xhtml_4ja_10.dtd">
      <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/2.0) 1.0//EN" "i-xhtml_4ja_10.dtd">
      <!DOCTYPE html PUBLIC "-//i-mode group (ja)//DTD XHTML i-XHTML(Locale/Ver.=ja/2.1) 1.0//EN" "i-xhtml_4ja_10.dtd">
    • au
      <!DOCTYPE html PUBLIC "-//OPENWAVE//DTD XHTML 1.0//EN" "http://www.openwave.com/DTD/xhtml-basic.dtd">
    • SoftBank
      <!DOCTYPE html PUBLIC "-//JPHONE//DTD XHTML Basic 1.0 Plus//EN" "xhtml-basic10-plus.dtd">
  • Content-Type
    • DoCoMo
      application/xhtml+xml
    • au
      text/html
      application/xhtml+xml
    • SoftBank
      text/html
      application/xhtml+xml
  • CSS
    • DoCoMoがインラインのみの対応のためstyle=""のように指定しないといけません。
  • その他
    • Content-Lengthが必須
    • 文字コードはShift_JIS
  • (XHTML関連)
    • 要素/属性は小文字
    • 空要素以外のタグは省略不可
    • 属性の省略不可
      (例) <input type="checkbox" name="hoge" value="abc" checked="checked" />


基本的なことばかりでしたが、

その他、細かい違いがあればぜひ教えて下さい。



2006年12月 8日

ウノウラボをリニューアルしました!
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加


こんばんは! やまもと@テスト番長です。

ウノウラボをリニューアルしました!
デザインの変更と共に、記事の著者が判るようにしてみました。

今後ともウノウラボを宜しくお願い致します。

#ご協力頂きましたSashaさん、naoyaさん、ありがとうございました!

2006年12月 6日

Web2.0時代のJavaScriptで注意することを5つほげほげ
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

Keitaです。

Ajaxが流行していますが、まだ、僕個人では実装レベルまでライブラリの蓄積が追いついていません。
各種ライブラリがWebフレームワークレベルでそろったら(そろえたら)使いたいなと思っていますが、なかなかそこまで手が出てないのが現状です。

とはいえ、社内でもDojoや、MochiKitなどのフレームワークがはやりつつあるので、そろそろつかいたいかなーと思いセキュリティを含めたリスクを調査しています。
とはいえ、まだまだ勉強中の身であるので、突っ込みいただけると助かります。

(1) クロスサイトスクリプティングに注意する

基本的な対策は、サーバサイドのときと同じく、描画を行うタイミングでエスケープ処理を行うことになります。 だだし、HTTPヘッダではなくBodyにエスケープしてない文字列をおいた場合にはAjaxではなく直接アクセスすると、XSSになる場合があるので注意が必要です。

エスケープ処理を行うのは、通常HTMLのレンダリングする場所ですが、上記のようなJavaScript経由でないアクセスも考慮に入れる必要があります。
HTTP上にエスケープしていない文字で通信する場合には、Ajax経由でないアクセスのこともHTTPのBODY部分ではなく「HTTPヘッダに入力するタイプのJSON」などを使うべきです。
Ajaxだけしかアクセスしねぇやーとか思ってると、罠のURLを踏んだユーザがアクセスしてしまう場合があります。

また、JavaScriptによるWYSIWYGで生のHTMLを操作できるライブラリなどを作成したり利用したりする場合には、それ自体にXSSが存在しないかどうか注意深く調査する必要があります。

もちろんサーバサイド側で全部エスケープ処理を付すのが一番楽だと思います。

(2) SEO対策に問題が生じていないかを注意する

本来クロールされたい項目がJavaScriptでしか抜き出せない状況になっている場合には、クローラーはクロールしてくれません。 SEOが必要なサイトでは、静的なページを用意するなどの対策が必要です。

(3) 不要な情報を公開していないか

たとえば、登録フォームにバリデータとして登録されているメールアドレスやIDかをチェックして「このIDは登録できます。」などと表示するといった処理を行うときには注意が必要です。 なぜならば、そのチェック処理を行うサーバサイドのインターフェースに、スクリプトなどで直接大量のIDを流し込むことにより容易にそのIDが使われているかチェックすることができます。

とはいえ、既存の登録フォームでも、スクリプトを流せばチェックできるものもありますので(CAPTCHAである程度は防衛できそうです。)リスクとしてはクリティカルではないと思いますが、技術者としてはベストプラクティクスを用意しておきたいものです。

(4) 通信量とアクセス頻度に注意する

わりと当たり前なのですが、onKeyPress系統をトリガーにするJavascirptにおいては、HTTP通信が発生するような処理は避けるべきです。 なぜなら、キー入力があった数だけ、HTTPリクエストが発生するからです。 すでにイベントが発生していたら処理しないなどの処理をはさむことで回避は可能ですが、何も考えずにやると痛い目を見ます。

(5) そもそも、お前、Ajaxいいたいだけじゃないかと

独りよがりのUIにはなりたくないものです。 上の4つに対してもそうですが、如何にかっこいいUIにするかを考えるよりは如何に使いやすいUIにするか、使ってて気持ちいUIにするかが重要です。

社内には、AjaxもFlashも使う人がいるので今度教えてもらいながら勉強します。
前回、見事に、逆SBOをしてしまった私ですが、今回もタイトルで逆SBOになりそうです。ほげほげ

ThinkITでウノウエンジニア陣によるPHP開発手法の連載が始まりました。
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

尾藤正人です。

ThinkITでウノウエンジニア陣によるPHP開発手法の連載が始まりました!!
暇なときにでも読んでいただければと思います。

第1回:複数人による開発の要所を押さえる

2006年12月 5日

Web2.0エンジニアのためのJavaScriptリファレンス集
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんにちは、hideです。
近年のAjax技術の台頭により、Web2.0時代のエンジニアにとってJavaScriptは欠かすことのできない技術となってきました。しかし、2000年頃のWeb1.0時代には低機能な言語として認知されていました。このことは、"Rediscover the JavaScript"と題された次の文章に良く表れていると思います。

10 年。世界が JavaScript の真の実力を発見するのに要した時間である。
1995 年、Netscape 社の Brendan Eich により開発・設計された JavaScript は、「世界で最も誤解されたプログラミング言語」などと呼ばれもした、ともすれば不遇とすらいい得る歳月を経て、あたりのそこここに満ち充ちていた「Web の旧来的なインタラクションの窮屈さを革命したい」という思いによって、ふたたび表舞台に招来された。(Shibuya.jsより)

最近は少なくなりましたが、僕の覚えている限りでも、右クリック禁止とか無駄に現在時刻を表示したりとか、ステータスバーに変なメッセージを表示させたりとかひどい使われ方をしていました。

そんな長い間誤解されていたJavaScriptなので、これから勉強するにしても正しいリファレンス・サイトを見る必要があります。というわけで、僕が利用させてもらっているサイトの中からいくつか紹介します。



JavaScriptist

JavaScriptリファレンスから逆引きサンプル集、prototype.jsやscriptaculousのサンプルなどとても内容が充実しています。Ajax/JavaScript関連の最新ニュースも集められていて、毎日見るサイトとしてもGood.

一撃必殺JavaScript日本語リファレンス

prototype.js, script.aculo.us, moo.fx, Rico, YahooUIなどライブラリ系のサンプルコードが充実しています。

JavaScript - Mozilla Developer Center

MozillaによるJavaScriptリファレンス。Core JavaScript 1.5 Guideは一度読んでおくことをお勧めします。

CSS Properties To JavaScript Reference Conversion

CSSプロパティとJavaScriptからアクセスする際の対応表。JavaScriptでは属性名に - が使えないので、若干表記法法が異なります。この違いを確認する際に利用します。

Prototype Dissected - Snook.ca

prototype.jsのチートシート。PNG形式の画像ファイルなので、ローカルにダウンロードして利用しています。

ECMA-262 3rd edition

ECMAScriptの仕様書。さらに深い部分を学びたい人向け。

2006年12月 4日

ユーザビリティって何だろう?(基本のまとめ)
このエントリーをブックマークに追加 このエントリーをlivedoorクリップに追加

こんばんわ、Sashaです。フォト蔵のUI改善への要望が高まっているのをうけて、最近、ユーザビリティについてみんなで考えています。

基本の基本が気になる私は、「ユーザビリティって何だろう」というところから考えるべく、『ユーザビリティのguru』と呼ばれるJakob Nielsenの「ユーザビリティ」の定義を復習しました。以下はそのまとめです。


ユーザビリティって何だろう?

ユーザビリティは、UIがどのくらい使いやすいものであるのかを示す質的属性です。「ユーザビリティ」という言葉は、モノをデザインする過程で「使いやすさ」を改善するための方法でもあります。

ユーザビリティは、次の5つの品質によって表すことができます。
学習しやすさ
初めてそのデザインに触れるユーザーが、どれだけ容易に基本的なタスクを発見し、遂行できるだろう?
効率のよさ
ひとたびそのデザインを学習したユーザーが、どれだけ素早くタスクを実行できるだろう?
記憶への残りやすさ
ユーザーがそのデザインにしばらくぶりに戻ってきた時、どれだけ容易に感覚を取り戻すことができるだろう?
誤りの起こりにくさ
ユーザーはどのくらいエラーを犯すだろう?そのエラーはどの程度深刻だろうか?どのくらい容易にエラーから復帰することができるだろう?
満足度
そのデザインを使うことが、どれだけ快適だろうか?

Nielsenがあげている他の「質的属性」で興味深いのが、デザインの機能性を示す、「ユーティリティ」。「このデザインは、ユーザーが必要としていることを反映しているか」、という質問です。つまり、どんなに「簡単な○○」であっても、その「○○」をあなたが必要としていなかったら、意味はない、と言うことです。同様に、プログラムがあなたが必要な「○○」を実現できるように書かれているのに、UIが難しいゆえにユーザーが「○○」を遂行できなかったら、やっぱり意味はないですね。

では、そのユーザビリティって、どうして大事なんでしょう。


ユーザビリティはどうして大事なの?

ずばり、ユーザビリティはサイトから「去る」人々を食いためるために必要です。デザインは、使う人のやる気をくじいてはならないのです。やる気をくじくと、人々はどんどん逃げてしまいます。ウェブサイトには、人々のやる気をくじく要素がいっぱい詰まっています。

Jakob Nielsenは、「デザインにかける費用のおよそ10%の予算をユーザビリティに使うべきだ」と言っています。


ユーザビリティはどうやったら向上するだろう?

答えは、ユーザビリティテストです。Jakob Nielsenは、「デザインの重要なユーザビリティ上の課題を洗い出すには5人のユーザーに対するテストでおよそ大丈夫」、と言います。ユーザーを、個別にテストして、起こる問題を自力で解決してもらうことも重要です。

重要なのは、

  • 『代表的なユーザー』に
  • 『代表的なタスク』を遂行してもらい、
  • ユーザーが何をして、どこでうまく言ったのか、どこで躓いたのかを『黙って観察』すること。

デザインを改善する過程の要所要所で小さなテストを繰り返して、テストの間に洗い出された問題点を修整する、というのが、効率のいいやり方のようですよ。


#ちゃんとした翻訳は、こちらにあります。