Monthly Archives: 8月 2014

Windows8タブレットを買って再会した二次元の「幼なじみ」たち

僕はモバイル機器を買うと必ず「幼なじみに再会」できるかどうかを試すという儀式的なことを行います。ツッコミはご自由にしてください。何を言われても屈しません。

先日、Windowsタブレットを買いました。
数ある中から僕はLenovo IdeaPad Miix2 8を選びました、

今回はWindowsということで、取り立てて苦労することなくゲームが動くだろうと思ったら結構動きませんでした。せっかくなので結果を報告します。

ところで、このブログはGoogleアドセンス広告を掲載させて頂いているため、いわゆる18禁はNGと思われます。なので、メイドロボットが出てくる昔の葉っ(ryとかいうことを書くことは許されないと思いますので、諦めて全年齢向けの作品のみの情報を扱わせていただきます。

(キャプチャ載せようともしましたが、めんどくさいし、著作権的な問題もあるので省略します。タイトル覚えてる人は脳内補完をよろしくお願いします)

Kanon全年齢版

言わずもがな。定番ギャルゲブランドKeyの代表作、ヒロインの名雪さんが最初のシーンで「再会のお祝い」っていうんですね。状況的にバッチリですね!ちなみに、いきなり文字化けしましたが、フォントを変更することで、文字化けはあっさり直りました。

Air全年齢版

状況はKanonと同じ感じでした。エンジンのバージョン的にも近いのでしょう。

CLANNAD

ストレスなく動きました。いわゆる「クラナドは人生」とか。僕はごめんなさい。最後までやっていないので、せっかくなのでそのうち、攻略しようと思います。

センチメンタルグラフティ

全国に散らばるえっと13人でしたっけ、女の子に会うためにバイトでお金を稼いでヒッチハイクの旅をするという、どうしてこうなったのかよくわからない迷作ですね。僕はえみりゅんが好きりゅん。

これはXPのころから、オープニングは見れないから、初期データをでっち上げるという技で起動はしたのですが、なんだかフォントサイズがずれてしまって見るに耐えない状況でした。

エーベルージュ2

このシリーズがなければ僕はこの世界を知らないまま学生時代を過ごしたに違いない。その二作目、前作よりもストーリーがキビキビしてて良かったです。メルさんが好きでした。起動することは確認しましたが、キーボードがないと、ゲームを終わらせる手段がなさそうです。これでは困ってしまうので二度と起動することはないでしょう。

ファンタスティックフォーチュン

僕がやった唯一の乙女ゲー、乙女ゲーといえど主人公の姫さんが可愛いくて、声優の茶山莉子さんの名前まで覚えてしまった程に、大変満足できた作品でした。が、動きませんねー (T_T)

Zweii

ギャルゲじゃないけど、Falcomが作ったキャラがかわいいアクションRPGゲーム。
主人公兄妹に会えたら嬉しかったんですが、いきなり起動しませんでした><

他にも、いくつかのゲームを動かそうとしてみましたが、どうも動かないことが多かったです。寂しいというかなんというか。まあ、そんなものでしょう。どうせ、外に持ちだしていって、公衆の前でにやにやしながらプレイするわけにはいかないので、容量ももったいないし消しちゃいました。

結論

幼なじみにいつまでも逢えるってものじゃないのです。きっと、みんなそれぞれの人生を歩んでいったのでしょう。

HHVM Hack (hacklang) を使った型安全なWordPressプラグイン開発で必要なこと

このブログで使っている WordPress プラグインの開発を Hack 言語を使ってやってみたのでその結果わかったことを書きます。

前置きその1 なぜWP-Pluginを開発したのか?

WordPressのユーザーの多くは自分でプラグインを開発しないでしょう。既に多くの実用的なプラグインがあるからです。

僕がこのブログのためにプラグインを開発した理由は、次の二つです。

  • テーマに対して透過的にブログを開発したかった。
  • 成功しているプラグインアーキテクチャの一例としてWordPressを勉強したかった

前者は、僕はデザインができないので、デザインはテーマを頼らざるを得ませんから、テーマの中にちょっとしたカスタマイズを入れたい場合でも極力テーマのファイルをいじりたくないためです。

簡単なロジックでもテーマに書いてしまうと、いざテーマを変更したいと思ったときに自分でいじった部分を新しいテーマに移植しなければなりません。

それは避けたいので、ブログパーツを入れる程度のことでも、wp_headやwp_footer、the_contentにadd_actionやadd_filterしました。

Hackとは

Facebookが開発した新しいプログラミング言語です。今年の3月に公開されたばかりの非常に新しい言語ですが、僕の見解では今すぐ使える実用的な言語だと思っています。理由は次の通りです。

  • PHPコードをrequireできる
  • PHPコードからrequireできる
  • PHPの機能がほぼ全部使える

つまり次のような事例で活用できると思います

  • 楽にWeb開発したいけど、型チェック付きの安全な開発がしたい
  • PHPの資産を活用したい

おまけに、Hackの実行環境であるHHVMはPHPも併せて高速がウリです。

ただし、現在HHVMを動かすレンタルサーバーは存在しないので自分でVPSやIaaSを契約してWebサーバを構築する必要があり、作ったプラグインを他人に配布してもHHVM実行環境がなければ動かせないという問題があります。

WordPressプラグインを公開して公式サイトから配布することもできませんね。

型チェックの仕方

プラグインのディレクトリ直下で

$ touch .hhconfig

とタイプして.hhconfigファイルを作成します。そうすると、このディレクトリはhh_clientで監視することができるようになります。

そのまま

$ hh_client

と打つと例えば以下のように

$ hh_client
/hello.php:4:13,21: Typing error
/hello.php:4:13,21: This is a num (int/float) because this is used in an arithmetic operation
/hello.php:4:13,21: It is incompatible with a string

のように、エラーがあったら表示してくれます。ちなみにエラーになってしまった行には次のように記述していました。

print (1 + "hello, \n");

このコード、Webから実行すると、実行することは出来てしまいます。つまり、PHP文法的にOKならばWebプログラムとして動かせるが、Hack言語的にNGかどうかを事前にチェックできるようにして、バグを防ぎ、必要なユニットテストのケース数を減らすことに寄与してくれます。

Hackでプラグインを作る方法

単純に、プラグイン用のPHPファイルの先頭を

<?php

の代わりに

<?hh

で書き始めるだけです。
あとは通常のプラグインとして開発すれば良いです。

Hackでプラグインを開発するときの注意点

globalが使えない

WordPressでは、#postや$wp_queryのようなグローバス変数に便利な情報が格納されています。

しかし、これを使おうとすると、実際はうごくのですが、hh_clientを実行するとエラーになってしまいます。例えば次のような感じです。

<?hh
require("hello2.php"); // この中でグローバル変数 $hello が定義されていることとする。
function init() {
        global $hello;
        print (1 + "hello, " . $hello . "\n");
}
init(); 
$ hh_client
/hello.php:4:16,21: Expected ;
/hello.php:5:25,30: Undefined variable: $hello
/hello.php:5:13,21: Typing error
/hello.php:5:13,21: This is a num (int/float) because this is used in an arithmetic operation
/hello.php:5:13,21: It is incompatible with a string

実はPHPのすべての機能をHackが提供しているわけではありません。下記のページにサポートしない機能が記載されています。

http://docs.hhvm.com/manual/en/hack.unsupported.php

globalのほかに、if: endif構文やeval $$ なんかもサポートしていないのですね。

回避方法

HackはPHPをrequireできる特徴を活用してこの問題は次のように解決できました。
hello2.php

<?php
        function get_php_global($name) {
                global $$name;
                return $$name;
        }

global $hello;
$hello = "world";

こうして、hello2.phpをhello.phpからrequireしておけば、

print (1 + "hello, " . get_php_global('hello') . "\n");

のようにしてグローバルな値を取得することができます。

わー!こんぐらちゅえーしょん!

フック関数の登録時にはfun関数を使おう(2014-08-19追記)

WordPressプラグイン開発ではadd_actionやadd_filter関数を使用してフック関数を登録していきます。

こんな感じで書きます。

function init() {
    add_action('wp_head', 'seo_metadatas');    
}
function seo_metadatas() {
    // 省略
}
init();

この時、うっかりタイプミスをして関数名seo_metadatasを書き間違えるとどうなるでしょうか?特に何もエラーを這い出さず、単にカスタマイズが反映されないだけになります。いくらhh_clientで型チェックをしていても無視されます。add_actionの第2パラメータはただの「文字列」だからです。

結論から言うと、次のようにすればこの問題は解決できます。

add_action('wp_head', fun('seo_metadatas'));

Hack and HHVM: fun - Manual

fun関数は文字列引数を受け取って呼び出し可能な「関数型」として値を返します。逆に言えば、<?hhタグ内ではPHPみたいに$文字列変数を使って動的な関数呼び出しを本来はサポートしていないようです。

fun関数の結果をvar_dumpしてみるとただの文字列だと出力されるので、PHPとしては「文字列」として扱われます。

まとめ

  • HHVMで配信しているWordPressだったら、特に苦も無くHackでプラグインが開発できそう
  • globalなど、Hack非サポートの機能を使う場合はPHPで記述してrequireすればよい!
  • add_action, add_filterの引数はfun関数で囲って渡す

ちなみに、型安全なのは実行時じゃなくて、チェック時なので、くれぐれも、本番環境で直接vimでコードをいじったりしないように。それじゃバグが見つかった瞬間に本番でバグってますから!w

僕は、開発用のフォルダを掘ってチェックOKだったらrsyncでwp-content/pluginsに同期するようにスクリプトを組んでます。恥ずかしいけどさらしときます。

#!/bin/bash
rsync -av --delete --exclude=.git ${1} ~/wordpress/wp-content/plugins/${1}

これ書くまでrsyncってリモートじゃなくても使えるなんて知らなかった程度のコマンド弱者ですががんばってます。w

では、
Have a good Hack life!

5年間Mayaaを使って思ったこと

関連記事はこちら:そろそろ2年間Mayaa使ってわかったことを書く

上記記事を書いたのが2011年ですので、あれから3年。まだMayaa使ってます(笑)

一つのプロダクトをずっとメンテし続けられるって、ビジネス的に成功した証拠ですから素晴らしいです!というわけで、10年の半分Mayaaを使い続けて思ったことを書いてみようと思います。

Mayaaは長期メンテに耐えるライブラリか

もちろんYesです。もう作られてから10年近い老舗プロダクトで、Javaは1.4準拠だったりしますが、それを加味しても十分現役で使えます。それは、私の勤務先でもずっと使い続けられていることが証拠です。

教育コスト・生産性は

当初とっつきにくい、教育コストがかかると思いましたが、大して問題になりませんでした。既に10人以上の開発者がMayaaを使った開発をしていますが教育コストが高いと思ったことはありません。

この辺りは、「2年間~」のときに書いたように開発ルールを定めたことが効いたのだと思います。はじめにビビってこれらのドキュメントを整えたことがかえって組織には良かったのかもしれません。

コードとデザインが分離するのでフロントのコードがスパゲッティにならないことも良かったです。最初のめんどくささは確実に後から利益となって返済されています。

デザイナーとの相性

あれから、想像した以上にデザイナーと開発者のすれ違いというものを多く目撃してきました。しかしそれはそもそも話せば分かる問題だったり、Javaプログラマーは業務システムを多く経験してきていてフロントに疎いことが問題だったりするためであり、むしろ、Mayaaを使うことで、一緒のプロダクトを同時開発することで発言した必然的なことであるような気がします。

多くの組織では、デザイナーと開発者の線を明確に切るようです。うちのように両者が入り乱れて開発できる現場というのはそんなに多くないでしょう。それができることは、お互いに、そしてプロダクトにとっても、ユーザーにとっても良いことだと思います。

パフォーマンス

今私が全力で取り組んでいる課題です。インフラがクラウド化してパフォーマンスとコストが直結したこと、Webの利用が広がりユーザトラフィックに対してサーバの余裕はもはやないこと、そしてWebブラウザの性能が向上したこともあり、低コストで、高パフォーマンスを実現することがWebアプリケーションに求められています。

そんな中で、Mayaaははっきり言ってパフォーマンスが良くありません。

Mayaaはかなり頑張っています。まず重要なのがキャッシュです。SpecificationCacheというオブジェクトに、ページのツリーデータがキャッシュされていきます。このため、普段のレンダリングは十分に高速です。ただし、キャッシュを行った結果は次の2つの問題点が発生します。

  • キャッシュ自体のメモリのオーバーヘッド
  • 更新直後などのキャッシュがない状態のパフォーマンス

キャッシュ自体のメモリオーバーヘッドは大きいです、たった数10KB程度のテンプレートファイルが1MBを超えたりします。特にJava6の古いマイナーバージョンや、Java5以前を使っているなら、即Java7以降に移行するべきです。Java6u14以降には圧縮ポインタという機能が搭載されています。詳しくはこちらに書きました。→64bit環境でなんかheapを多く消費するなあと思ったら

それでも、メモリを食うことは変わらないので、なるべく大きめにヒープを割り当てるようにしてください。トラフィックやサイトの種類にも依存しますが目安としては全テンプレートファイルの10から50倍程度用意するべきだと思います。

キャッシュがないときの問題も大きいです。そこで、Mayaaは可能な限り、キャッシュがない状態を防ごうとしています。ヒープがいっぱいになってキャッシュがGCによって消えてしまった場合や再起動した時も、ハードディスク上にserializeしておき、そこから復元することでXML解析の時間を短縮しようとする機能があります。この機能はデフォルトでOFFになっていますが、ONにしても問題が発生することはないので、プロジェクトの初期段階からONにすることをおすすめします。

キャッシュがない状態でのレンダリングで最も時間を食っている原因は、Rhinoスクリプトのコンパイル・最適化です。Rhinoスクリプトをそのまま実行すると遅いので、一旦Javaクラスとしてコンパイルするとう最適化を行っています。そして、Javaクラスは繰り返し実行するにつれてJITコンパイルされ次第にネイティブコードに近くなっていきます。なので、数回同じページを表示すると、JSPやServletで画面を構築した場合に劣らないくらい高速になります。VMを再起動したり、テンプレートを更新するとこれらキャッシュは消えてしまいます。コンパイルされたRhinoスクリプトはtransientなので、シリアライズ・デシリアライズされると最適化がはじめからやり直しです。この件については、今後Mayaa自体が効率化することを望みます。

究極のパフォーマンス改善は、そもそもRhinoScriptを使用しないことです。RhinoScriptを使用しないためには、独自のProcessorを作成する必要があります。Mayaaのソースを読んでいくことで、TextCompiledScriptが使用されている箇所を軒並み潰して、Reflectionなどを使用して直接Javaコードを呼び出すようにすることで、ページの処理速度が最大5倍程度速く出来ました。

拡張性

かなり良いです。5年間で本体をforkし独自のコードを挿入する必要があったことはありません。

Processor, InjectionResolver, Builderなどを独自化することで全く別のテンプレートエンジンに仕上げてしまうこともできます。

ただし、一方で、拡張するには非常に多くのコードを書かなければいけなかったり、キャッシュやMayaaツリーの解析など、あらゆる機構が独自で実装されているため、ソースコードのかなりの部分を精読しなければなりません。なんでもできるけど、その難易度は高いといったところです。

XPathMatchesInjectionResolverは無効にするべき

Mayaa User Mailing listに私が報告したとおり、こいつがあるとパフォーマンスが低下します。またメンテ性が悪いのではじめから使うべきではありません。

org.seasar.mayaa.provider.ServiceProvider
を編集し、下記のようにコメントアウトしてしまいましょう。

<!-- <resolver class="org.seasar.mayaa.impl.builder.injection.XPathMatchesInjectionResolver"/> -->

動的なページの構築、MayaaはSPAよりPJAXと相性が良い

最近はSPAといって静的なHTMLページ一枚でWebアプリを構成し、JavaScriptによる非同期リクエストにサーバはJSONを返すことで画面を構築していくというアプローチが普及しつつあります。AnqularJSなどがそのページの作り方をサポートするライブラリとして有力です。

この構成でサイトを作る場合は、そもそもMayaaの出る番がありません。しかし、もし作っているものが、Webサイトの延長で、全ての画面の状態にはURLがあるという状況においてはSPAにせず、Mayaaを使ってPJAXを実装するとスムーズです。

つまり、Ajaxに対してレスポンスするのはJSONではなく、普通のHTMLページであり、jQueryを使うなどしてここから必要な断片を画面に上書きするというアプローチです。Push Stateを使用してURLも書き換えてしまえばSEOもバッチリです!このURLが静的コンテンツとしてMayaaにリクエストした時のページのURLでもあり、静的ページと動的ページの両方をMayaaによって実装することができます。

2014年以降もMayaaは最強か?

これについては、なんとも言えないでしょう。
拡張しやすさを求めるならMixer2、生産性を求めるならThymeleafもあります。パフォーマンスを求めるならJSPで割り切るのも手です。

デフォルト状態でのデザイナーとの相性が非常に良いので、CMSのような物を作りたい場合は、Mayaaは未だにかなり良い選択肢です。この領域にはWordPressというそもそものデファクトスタンダードがあるので、わざわざJavaで作るという機会はあまりないかもしれません。でも、もしそのタイミングが訪れたなら、WordPressのテーマやプラグインよりもずっと良い基盤です。

パフォーマンスの問題がシビアな状況ではあまり適切とはいえません。あらゆる汎用エンジンは何かしらパフォーマンスとトレードオフの関係にあります。いっそ、独自でテンプレートエンジンを作るのも手だと思います。

Mayaaの柔軟性を取り入れつつ、パフォーマンスも良くしたい場合、私が業務で取り組んでいるRhinoを使わないしくみがもし汎用化できて、公開することができれば最高ですね。それは私の業務的にはプライオリティが高いことなので、案外実現してしまう可能性もあります。が、まだ約束できることではないことので、現時点ではまだ考慮にいれられないことが残念です。