Category Archives: Web技術

今学ぶべきプログラミング言語:Hack (Hacklang)

Web開発ではどの言語を使ったらよいか

大規模Webサイトとか、業務システムを作るならつべこべ言わずJavaにしとけと個人的には思っているのですが(.NETは詳しくないので)、次のようなシチュエーションを良く聞きます。

  • さくっとWebアプリを開発したい(or PHPの資産を活用したい)
  • 型安全が欲しい
  • パフォーマンスも良い方がいい
  • Javaはめんどくさい
  • .NETはお金がかかるから避けたい

こんな時に、HHVM + Hacklangは良い検討対象だと思っています。理由としては、

  • PHPの資産が使える
  • 型安全である
  • HHVMは速い

僕のブログでも下記の記事で触れてきました。

しかし、Web上の記事をみてもあまり普及している感じがしないです。理由として考えられることは

  • PHPでいいじゃん(できることは変わらない)
  • 現時点でサポートする開発環境/エディタが充実していない
  • 情報が少ない
  • HHVMをホスティングできるレンタルサーバーがない

ということがあると思います。

もともとPHPの危ないポイントを回避しながら使いこなすことができる生粋のPHP職人の方々は素直にPHP書けば良いでしょう。しかし、PHPは罠だらけの言語です。できれば触れたくないと思っている人も多いです。一方で、技術の完成度というのは、いかにそれが使われるかにかかってきます。例えばJavaScriptはパフォーマンスという点では不利な言語でしたが、複数のWebブラウザによるのスピード競争の結果、最も速く、最も開発環境が充実したプログラミング言語になりました。そして、サーバーサイドのそれはPHPやJavaです。

ざっくり言って、PHP+型は夢の組み合わせです。Hackは無理なことをせず、それをうまく実現しています。静的型付け言語としてはScalaやGoもありますが、HackはPHPと同じくWebを前提としている言語として価値があると思います。

どのように学べばよいか

日本語の情報なら、下記の電子書籍があります。

現時点では英語が読めないとHackを学ぶのは厳しいですし、英語が読めるならこの本の内容は公式ドキュメントでカバーできるのですが、はじめの取っ掛かりには良いと思います。

技術評論社よりePub版も販売されていますが、僕はAndroidとWindowsではソースコードを綺麗に表示できるアプリを見つけることができなかったため、読み切りだと割りきってKindle版を買うことをおすすめします。

そこから先は、公式サイトのチュートリアル、公式ドキュメントこれに尽きると思います。

http://hacklang.org/tutorial

FBIDEがリリースされたら熱そう!

上記チュートリアル、使ってみるとあれって思いませんか?リアルタイムの文法チェックやコード補完がサポートされています。どこにそんな高級エディタがあるのでしょう。現状vimとemacsしか選択肢がない言語です。ではこの高機能なエディタは、チュートリアル用に作られた専用プログラムなのでしょうか?

これは、FBIDEのサブセットではないかと思います。下記ビデオで紹介されています。

Introduction to FBIDE - Hack Dev Day

シンプルでクールなWebベースのIDEのようです。リリースされたらものすごいワクワクします。

Hackは新しい言語なので、型推論など便利な仕組みを持っています。そして優れたIDEがリリースされれば鬼に金棒ではないでしょうか?

そういえば、Hackの文法チェックコマンドは hh_client とタイプします。これも、IDEのバックエンドで使われるための布石のような雰囲気がします。FBIDEにかぎらずHackの開発環境をこれで作ることは可能のような気がします。例えばHackのEclipseプラグインなどを作ることもできるのではないでしょうか。

FBIDEがリリースされたら本気出す?

いつ来るかわからないFBIDEを待っていてHackの勉強を怠るというのは、技術者の姿勢としてはよろしくないです。現にいま使うことができる言語です。このブログでもWordPressのプラグインが作れることを紹介しました。なんといっても、PHPのエコシステムに乗れば、すでにほとんどのことができます。2014年も残り3ヶ月あまりですが、今年中に勉強する言語としては、最有力であると思います。

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を使わないしくみがもし汎用化できて、公開することができれば最高ですね。それは私の業務的にはプライオリティが高いことなので、案外実現してしまう可能性もあります。が、まだ約束できることではないことので、現時点ではまだ考慮にいれられないことが残念です。