2010年4月20日火曜日

QConTokyo2010にいってきた

去年は旦那が参加したので、今年は私が参加してきました。

ですが、開始前から残念なお知らせ。
アイスランド火山噴火の影響による欧州航空便の欠航に伴い、
以下2名によるセッションを変更いたしました。

4/19(月) 16:00-16:50 Erich Gamma 氏
4/20(火) 14:30-15:20 Jim Webber 氏
残念すぎます><

でも、参加者は200名弱はいた模様。女性は...平日のセッションの割には少なめだったかなぁー。
特に2日目は少なかった。1日目はFlex/Flashのセッションあったからか?!

会場の雰囲気としては、イマイチ盛り上がりに欠けてる感触。
盛り上げたいなら日本の有識者やコミュニティをもっと招待してみるとかしたらどうなんだろうか。
そうじゃないのであれば、twitterとかfacebookとかQConでしかきけないようなセッションをもっと時間をかけてやってみる方が私は嬉しいなぁー...とアンケートに書いてきた。

ま、聞きたかったセッションは面白かったですよ。
ピックアップしたセッションのみですが、内容報告。


Data Architecture at Twitter Scale
Nick Kallen

Twitterでのscaleのお話。最初からメインディッシュな感じです。

Twitterの初期は、MySQLのRDBで組んでた。項目は、[ID] [USER_ID] [TEXT] [CREATED_AT] ぐらい。
最初に発生した問題はディスクスペースだった。
それまで縦方向のスケールしていたのを、横方向へのスケールへ転換することになったが、どのようなパーティショニングするかの検討を行った。
(1) IDを、奇数と偶数の2つに分ける → ユーザについての全ての情報を取りたいときに不便
(2) USER_ID 毎にわける → (1)と逆の問題
(3) 時間軸でわける
Twitterの特性として、検索される大半のデータは新しいデータが多いため、(3)を採用。

cassandraに移行する予定があるが、cassandraが「魔法の杖」なんかじゃない。
Twitterだったら時間軸に特性があったように、アプリ毎の特性を判断して考える必要がある。
事前にフェッチしておくなども一つの手。

人のつながり情報関連(フォローしている、フォローされている)について、膨大な処理件数になってしまう。
そんなSocialGraphの処理の方が処理件数が多い (4:1)
フォローしている人/されている人 は重複してレコードを持っている(非正規な状態)
速度のために、データの近くで演算するようにする


有機的なユーザーインターフェイス実装における課題とアプローチ
隈元 章次 SiTE4D

アスクルのAdobeAIRガジェットを作られた会社の方です。
デザイナ、プログラマ、テスター 、IAが同じポジションで協力しながら開発していっている姿に感動。
特に、デザイナさんと企画段階からいろいろ相談して何かをつくってみたい..と思っている日々だったものでw

2ndオペレーション
右から出てきたウィンドウ、右にドラッグしたら実は消えるのでは? と想像して、できるとインパクトがあったりする。
でも、それを1ndオペレーションにすると、分かりにくい/使いにくい となるので、2ndでやる。

仕様/コンセプトは開発前にプレビズ(動画)を作成して固める。
最終的なゴールは、このプレビズのものとブレない。 (確かにブレてなくてビックリ!)
ブレさせないためにいろんな規格化(進むボタン系は黄色とか)をしている。
---> そのため、途中で客の担当者が変わって違うことを言い始めても修正できる。
---> そのため、作業の人展開もできるようになる。
α版アプリを毎日客に使ってもらう。
テストは全て動画で記録する。納品はその動画を入れたハードディスク毎行っている。


Scaling Memcache at Facebook
Marc Kwiatkowski

メインディッシュ2つ目です。
えと、内容のボリュームがでかいうえ、難しかったため、あまりついていけず。
なので間違っていたらごめんなさいベースでw

Facebookは友人の情報が密接につながっているため、膨大な処理量になる
PHPでシリアライズしているが、thriftを使うようになって、3倍の早さ/30%小さくなった
2つのデータセンターwest,east には memcache proxyを使って一貫性を保っている

データを更新すると、
(1) Databaseのupdate
(2) memcacheのdelete
(3) (複数の)クライアントからmemcacheへget
(3') 存在しないため(複数の)クライアントにfailが返る
(4) failを受け取ったら、databaseへadd (勝ったクライアント1つのみ反映される)

タイミングにより、違うバーションの2つのKEYが存在する状態が発生する可能性がある。
その解決として、Keyに、スキーマバージョンとオペレーションバージョンを含んでいる。

memcacheのdelete処理をより早くするために、
複数のKeyをまとめて送っている。
LocalでのDeleteなのか、GlobalでのDeleteなのか?を認識。
データが存在しなかった時には、PlaceHolderのオブジェクトを作り、情報を格納して処理を進める。
テストは、 python 、ctypesで書いていて、コマンドラインから実行できるようなものを作成している。


Programming the Cloud
Gregor Hohpe

急遽開催となったセッション。講演者はBest Software Writingにあった、"Starbucks Does Not Use Two-phase Commit"を書いたGoogleの方です。
Googleで提供している、GFS, BigTable, MapReduce, Sawzall(そーぞる)。SawzallはDSL。

(1) Uncertainty(不確実性) これはしょうがない。つきあっていくしかない。
(2) Asynchrony(非同期) 結果の順番が一緒になるとは限らない
(3) Interaction(相互作用) 不確実性をカバーするもの。でもfreeではない。
(4) Conversation(会話) 会話のパターンができるはず。講演者がまとめている最中らしい。本でるのかも?
(5) Back to Basics(基本に戻る) Bigtableはその例。必要なもののみシンプルに作成している。よく陥りがちなのが、不確実性をカバーし一貫性を保とうとするためいろんなレイヤーで処理を挟んで、システムを複雑にしてしまう事。トラブルが発生した時逆に原因追及しにくくなる。シンプルな方がいい。
(6) Empower the Run-time(ランタイムに合わせて) 決めすぎると分散しにくい。人間が頭で考える事と、その言語/環境に合ったものは違うこともある。
例として、int[4] の配列の値を全て足す処理を作成する場合。Loopを使ってしまいがちだが、int[0], int[1], int[2], int[3] の順番で足す必要はない。結構、ループ指向に陥りやすものだが、頭の切替が必要。

今まで(Before)と、これから(After) との比較
BeforeAfter
Object-OrientedProcess-Oriented
Rich Domain ModelEvent based
Method CallsChannel based
PrescriptiveDescriptive
SingleThreadParallelizable
Easy to debugDifficult to debug


不確実性のため、会話が必要 という観点は実世界と同じ。
逆に、今までのオブジェクト指向は、思い描いていた理想の世界だったのかも?

• • •

Flex4のコードネームGumboって。。

Flex4が先月(?)にリリースされたので、ちゃんと見てみなければと思っているaqubiです。ども。

Flex4のコードネームがGumboらしいのですが、goo辞書でみてみると
gumbo
[名](複 〜s)1 《植物》オクラ(okra);そのさや.2 [U][C]((米))ガンボシチュー:オクラと鶏肉, 青野菜などでつくる.3 [U](米国西部の)ねば土:湿るとねばねばする.━━...

オクラ ですよ、オクラ! !

今までのAdobe製品のコードネームをちょっとググってみたら、
AdobeAIR → Apollo(アポロ)
Flash9.0 → BLAZE(炎)
Flex3 → Moxie(元気)
Flex4 → Gumbo(オクラ)
Mobile用Flex → Slider(滑るもの)

うーん、由来をおききしたくなる感じ。

せっかくなのでその他のコードネームもまとめてみた。

MacOS
Mac OS X v10.0 → Cheetah(チータ)
Mac OS X v10.1  → Puma(ピューマ)
Mac OS X v10.2 → Jaguar(ジャガー)
Mac OS X v10.3 → Panther(ヒョウ)
Mac OS X v10.4 → Tiger(トラ)
Mac OS X v10.5 → Leopard(ヒョウ)
Mac OS X v10.6 → Snow Leopard(雪ヒョウ)

ビュンビュン走りそう!

java
J2SE 1.3  → Kestrel (タカ)
J2SE 1.3.1  → Ladybird(テントウムシ)
J2SE 1.4.0  → Merlin(ハヤブサ)
J2SE 1.4.1  → Hopper(バッタ)
J2SE 1.4.2  → Mantis(カマキリ)
J2SE 5.0  → Tiger(トラ)
Java SE 6  → Mustang(馬)
Java SE 7  → Dolphin(イルカ)

いろんな動物。

Eclipse
Eclipse 3.2 → Callisto
Eclipse 3.3 → Europa
Eclipse 3.4 → Ganymede
Eclipse 3.5 → Galileo

木星の衛星の名前。
イオ(io)がないのは、 I/Oと混乱するかららしい。
そのかわり発見者の名前ガリレオが採用されたらしい。
次のEclipseは e4と呼ばれている?
なんかちょっと寂しい。
• • •

2010年4月18日日曜日

GeekToolでGit情報をデスクトップに表示



GeekToolでGitの情報を表示してみた。

Shellのcommandの設定で、
/opt/local/bin/git --git-dir={/pass/to/project/}.git --work-tree={/pass/to/project/} {gitのコマンド}
とすればOK.

私の主な目的は更新漏れ防止なので、更新間隔は30secで設定。
ディスプレイがもっと横長で大きくなってほしくなります。
• • •

2010年4月17日土曜日

良い目を養う

「良い目を養うには本物を見ること」
私の父親は、骨董品収集が趣味だったので、良く言っていたのを思い出します。
実家はドがつく田舎でしたので、大きな美術館もなく本物の絵画や彫刻を見るタイミングはほとんどありませんでした。
小さい頃、都会の美術館に連れて行ってもらった事があり、その時は本で見た絵画との差に愕然とした記憶があります。
私は覚えていないのですが、”美術館でaqubiがいなくなった” と両親が探しまわった事件があり、「普通の子供はすぐに飽きて美術館の外にでてしまっているだろう」と先入観を持っている両親は外をいろいろ探していたらしいのですが、その時には私はまだ館内にいたオチ。
私はあまりにも熱心に見ていたので進むペースが遅かったというのが原因だったようです。

では、私には美術的才能があったのか?というと全然ない。(周りの人はもぅご存知だと思いますが)
いま思うと原因は、自宅に飾られていた水墨画やら、彫刻やらを普段から目にしていたからなのだと思います。
(それらが果たして本物だったのかどうかはいささか疑問ですがw)

これと同じ事を先日感じたのが、Webデザイン。
私はプログラマなので、主に見ているのはEclipseとプロジェクト管理ツールとメーラ...です。
プロジェクト管理ツールについてなのですが、ヌーラボに転職する前はTracを使っていたのですが、転職後はBacklogを使うようになりました。
Backlogのデザインは、デザイナさんが行っているのでデザインがいい!と評判(!?)のものです。
それをよく見るようになって、より自分が作るページのなんちゃってデザインが許せなくなる度が高くなった気がします。

もちろん以前より、「いいデザイン」というのには興味があって情報収集とかしてはいたのですが、普段常に見る のと 見ていない のとでは無意識的に差がでてくるような気がします。

そう思うと、仕事を行う職場風景についても大きく差がでてくるのではないかと思います。
洗練されたデザインの職場、遊び心がたっぷりの職場.... おじさんがいそうな職場、若者がいそうな職場... モノトーンな職場、ポップな職場...よくありそうな職場、独創的な職場...。
それらの雰囲気については、外部からのお客さんが感じるだけでなく、普段からいる社員についても洗脳のように刷り込まれていくのかもしれない。

起業する場合、まず「こんな企業にしたい」という思いを事務所のデザインとして表す というのもよいのかもしれないですね。

まぁ私が起業を考えている訳では全然ないのですが(笑)
• • •

2010年4月15日木曜日

GoogleBuzzボタン

Googleのブログを見てみると、GoogleBuzzのボタンをサイトに配置する方法が紹介されています。

http://www.google.com/buzz/stuffにアクセスすると、「バズに投稿」「バズでフォロー」のJavaScriptがコピーできます!



ここで作成されたリンクからBuzzの投稿を表示してみると、こんなダイアログが出てきてポストができた。


このTechCrunchとかと同じようにBuzzボタンが...私のページにも作れる!

このボタンのリンクの詳細は GoogleBuzzAPI-Buttons and Gadgetsにあるよーです。

単純に
http://www.google.com/buzz/post
というリンクで、バズが投稿できるリンクになります。

パラメータに、message, url, imageUrl, hl が指定できるようになっていて、
http://www.google.com/buzz/post?message=Here's%20Buzz!&url=http://www.google.com/buzz
こんな感じになる。
ちなみに、hlはロケールっぽい。

<a href="http://www.google.com/buzz/post"
class="google-buzz-button" title="Google Buzz"
data-message="Here’s Buzz!"
data-url="http://www.google.com/buzz"
data-locale="en"
data-button-style="normal-count"></a>
<script type="text/javascript" src="http://www.google.com/buzz/api/button.js"></script>

と書いてるのが↓ 見えてる?


• • •

2010年4月12日月曜日

ImageIOを使って画像操作

Javaのjavax.imageio.ImageIOを使うと、画像操作が簡単に出来ます。

たとえば、gifファイルをjpegファイルに変換するには以下のコードで行えます。
BufferedImage image = ImageIO.read(new File("input.gif"));
ImageIO.write(image, "jpeg", new File("output.jpg"));


簡単ですね。素晴らしい。

カラーのJPEG画像を、グレースケールに変換するには以下で。
BufferedImage image = ImageIO.read(new File("input.jpg"));
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
newImage.getGraphics().drawImage(image, 0, 0, null);
ImageIO.write(newImage, "png", new File("output.jpg"));


BufferedImageのタイプには、
public static final int TYPE_INT_RGB = 1;
public static final int TYPE_INT_ARGB = 2;
public static final int TYPE_INT_BGR = 4;
public static final int TYPE_BYTE_GRAY = 10;
public static final int TYPE_BYTE_BINARY = 12;

などなどあり、前記の例では、TYPE_BYTE_GRAYのBufferedImageに書き込んだのでグレースケールにしています。

そんな便利なBufferdImageですが、透過GIFの場合は注意が必要です。
透過GIFを、ImageIO.readで読込みして作成したBufferedImageのタイプは、TYPE_BYTE_BINARY = 12 になります。
TYPE_INT_ARGBではないのですねー。

透過GIFを新しいBufferedImageに書き込みして編集し、再び透過GIFとして出力したい場合にて癖があるみたい。
例えば、単純に以下の操作をしてみる
BufferedImage image = ImageIO.read(new File("alpha.gif"));
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), image.getType());
newImage.getGraphics().drawImage(image, 0, 0, null);
ImageIO.write(newImage, "gif", new File("output.gif"));

すると、出力結果は透過GIFではなくなってしまいます。

透過GIFとして出力するためには...
一つ目の方法としては、書き込み先のBufferedImageをインデックスカラーのタイプ(BufferedImage.TYPE_BYTE_INDEXED)にして、カラーパレットを作成し、透過の色を指定してあげると透過GIFとして出力できるようです。以下は、透過gif, 透過pngファイルを一つにして出力した例。

public static void main(String[] args) {
try {
BufferedImage image = ImageIO.read(new File("alpha.png"));
BufferedImage image2 = ImageIO.read(new File("alpha.gif"));
BufferedImage newImage = convertToIndexed(image);
newImage.getGraphics().drawImage(image2, 0, 0, null);
ImageIO.write(newImage, "gif", new File("output.gif"));
} catch (Exception ex) {
ex.printStackTrace();
}
}

public static BufferedImage convertToIndexed(BufferedImage src) {
BufferedImage dest = new BufferedImage(src.getWidth(), src.getHeight(), BufferedImage.TYPE_BYTE_INDEXED);
Graphics g = dest.getGraphics();
g.setColor(new Color(231, 20, 189));
g.fillRect(0, 0, dest.getWidth(), dest.getHeight());
dest = makeTransparent(dest, 0, 0);
dest.createGraphics().drawImage(src, 0, 0, null);
return dest;
}

private static BufferedImage makeTransparent(BufferedImage image, int x, int y) {
ColorModel cm = image.getColorModel();
if (!(cm instanceof IndexColorModel))
return image;
IndexColorModel icm = (IndexColorModel) cm;
WritableRaster raster = image.getRaster();
int pixel = raster.getSample(x, y, 0);
int size = icm.getMapSize();
byte[] reds = new byte[size];
byte[] greens = new byte[size];
byte[] blues = new byte[size];
icm.getReds(reds);
icm.getGreens(greens);
icm.getBlues(blues);
IndexColorModel icm2 = new IndexColorModel(8, size, reds, greens, blues, pixel);
return new BufferedImage(icm2, raster, image.isAlphaPremultiplied(), null);
}

透過色をベタっと塗りつぶしてあげる感じ。
だけど、画質が落ちてしまうんですよねー。

もう一つの方法としては、BufferedImage.TYPE_INT_ARGBのBufferedImageに透過の変換をしたイメージ書き込んで透過画像を出力する方法。以下で出来る様子。

public static void main(String[] args) throws IOException {
BufferedImage image1 = ImageIO.read(new File("alpha.png"));
BufferedImage image2 = ImageIO.read(new File("alpha.gif"));

Image transpImg1 = makeColorTransparent(image1, new Color(image1.getRGB(0, 0)));
Image transpImg2 = makeColorTransparent(image2, new Color(image2.getRGB(0, 0)));
BufferedImage dest = new BufferedImage(300,300, BufferedImage.TYPE_INT_ARGB);
Graphics2D g2 = dest.createGraphics();
g2.drawImage(transpImg1, 0, 0, null);
g2.drawImage(transpImg2, 0, 0, null);
g2.dispose();

File outFile2 = new File("sample2.png");
ImageIO.write(dest, "PNG", outFile2);
}

public static Image makeColorTransparent(BufferedImage im, final Color color) {
ImageFilter filter = new RGBImageFilter() {
public int markerRGB = color.getRGB() | 0xFF000000;
public final int filterRGB(int x, int y, int rgb) {
if ((rgb | 0xFF000000) == markerRGB) {
return 0x00FFFFFF & rgb;
} else {
return rgb;
}
}
};
ImageProducer ip = new FilteredImageSource(im.getSource(), filter);
return Toolkit.getDefaultToolkit().createImage(ip);
}

どっちも、x=0, y=0の位置のものを透過色としているって感じ?あってる?

後者の方が画質が落ちないのですが、Toolkit.getDefaultToolkit().createImageを使うと環境依存がある的な記事もみたので、ちょっと気になったりもする。
• • •