
開発スタイルの変化がもたらすチーム連携の重要性
今回、グリーがHTML5で開発しているスマホアプリでは、その開発スタイルが、既存のものとは大きく変化している。既存プロダクトの開発スタイルでは、バックエンドエンジニアが機能と画面の作成を兼務することが多く、開発は多くても2~3名で行っていた。
一方、今回のプロダクトでは、これまでより開発が大規模化し、さらにリッチなUIの実現が求められた。バックエンドエンジニアが兼務するのは難しくなり、フロントエンド専門のチームとの分業体制となった。演出やアプリ、サウンドなど、多数のチームが関わるため、各チーム間の連携が重要となった。このスタイルのメリットは負荷が分散して専門化することだが、仕様のぶれや手戻り発生というデメリットがある。
では反田氏たちは、課題解決のためにどう動いたのか。まずフロントエンドとバックエンドのエンジニアの連携を難しくした背景には、「テンプレート化を考慮しない実装」というものがあった。フロントエンドエンジニアが先行して画面を実装していくのだが、それを実際にプロダクトに組み込むことになったときに問題が出てきた。
ソーシャルゲームでは、レイアウトがほぼ同一で、背景画像が異なっている画面がよくある。そうした場合、サーバ側で背景画像を置き換えているのだが、パラメーターがCSS/JavaScriptにハードコーディングされているものに関しては、置き換えられない。そのため、組み込み時点で実装を変えなければならなくなる。
また通常の手法では、HTMLが完成しないと、テンプレート化できない。さらにデザインが変更されるとHTMLの変更が必要になり、変更の差分を見て、再度テンプレート化をするといった作業が繰り返し発生する。また、マークアップの意図を理解できなかったケースで、テンプレートタグの組み込み漏れがあった。
以上の問題に対し、早い段階で実行したのは以下の3つ。
- テンプレートによる置き換えを想定して実装する。
- パラメーターで置き換わる画像はCSSで指定しない。
- JavaScriptで参照するパラメーターは、HTML側にdata属性で埋め込む。
連携でポイントになるのが、テンプレートの共有化だ。デザイン変更時などの手戻り発生を防ぐためには、「マークアップの段階で、テンプレートを組み込めばいい」というわけで、今回はSmarty互換のJavaScriptテンプレートエンジン『jSmart』を導入した。
HTMLではなくテンプレートを直接マークアップすることで、クライアント/サーバ間でテンプレートを共有化できるようになり、手戻りが発生しなくなった。
フロントエンドエンジニアが、サーバ側のSmartyテンプレートを直接編集するという方法もあるが、採用しなかった。なぜなら、開発中にサーバ側のプログラムがたびたび動作しなくなることが予想され、そのたびにフロントエンド開発作業がストップしてしまうからだ。
フロントエンド開発時は、モックデータを用意し、動作確認する。そのモックデータに合うようにサーバ側はデータをセットする。jSmartで作ったテンプレートをスクリプトで変換し、サーバ側にインポートすることで、手間なくテンプレートの組み込み作業ができるようになった。
サウンド組み込みと演出の作業効率改善も課題となった。まず、HTML5で音を鳴らそうとすると、1つの問題がある。それは、<audio>タグにより同時再生可能な音源数に制限があり、複数の音を組み合わせて再生することが不可能だということだ。つまり、BGMとSEを同時に再生することができない。これはゲームの演出を作るにあたって、致命的な問題だ。
そこで新プロダクトでは、GREE SDKが提供するアプリ側のサウンド再生APIを利用することで回避している。具体的には音声ファイルをアプリに組み込み、アプリ側のサウンド再生APIをWebViewから呼び出し、音を鳴らす。
しかし、まだ課題が残る。アプリがないとサウンドの検証ができないのである。そのため演出やサウンド担当者は、ボリュームの調整や音源の差し替えを、アプリの開発者にいちいち依頼しなければならない。
そこで、GREE SDKとHTML5それぞれのサウンド再生APIを切り替えて使える、ラッパーAPIを用意して対応した。<audio>タグにアプリ側API固有のパラメーターをdata属性として設定し、アプリとPCブラウザ、それぞれで適切なAPIを呼び出して再生する。この結果、アプリでもPCブラウザでも音声再生をサポートできるようになった。
ゲームの演出作成に必要な機能満載のアニメーションエンジンLWFを活用
続けて反田氏は、LWF(Lightweight SWF)を使った開発事例を紹介した。
LWFはGREE内製アニメーションエンジンで、SWFをHTML5のCSS/Canvasアニメーションに変換し、再生するものだ。OSSで公開されているので、誰でも利用できる。
ゲームの演出作成に必要な機能がそろっていることが大きな特徴で、まず、演出に必要なパラメーターを渡すインターフェースが充実している。カード画像など、ユーザーの状態に合わせた画像の置き換えが可能で、端末解像度に応じた画像の切り替えもサポートしている。
中でも反田氏が注目を促すのが、CSSやCanvasなど描画方法を選択できる点だ。というのも、端末によって最適な描画方法というのは異なるためだ。CSSとCanvas、それぞれ速い端末がある。選択できるのがLWFの強みとなっている。
LWFは、画像を外部リソースとして読み込む。そのため、キャッシュを有効に使うことができ、転送量/待ち時間を減らすことができる。これは、高解像度の画像を大量に使用する場合に、特に重要だ。また、LWFはテクスチャシートというものに対応している。これはCSSスプライトのように、演出内で使う画像を1つにパックし、まとめて読み込めるようにするものだ。1つにまとめることで、より効率的に読み込むことができる。
新プロダクトでの組み込み例
演出ごとに、LWFの初期化やエラー処理を書いていくのは、バックエンドエンジニアにとって負担が大きい。そこで、そういった処理を共通化した。HTML内のdata属性に、LWFのパラメーターを全部展開してしまうことで、自動的に再生できるようにした。
LWFの制作は一見、敷居が高いように感じるのだが、LWFSというLWFへの変換/再生を行うアプリを使うと、複雑なセットアップをせずに、LWFが制作できるようになる。エンジニアが開発環境をセットアップする必要はなく、LWFSをインストールするだけですぐに使える。LWFSにより演出の確認、改善というイテレーションを回しやすくなる。
反田氏たちがLWF利用において注意した点だが、まず画像の読み込みに1つでも失敗すると、LWFは再生されない。そこで適切にエラー処理をして、エラーページなどに遷移させる必要がある。また、演出パラメーターは、オブジェクトとして渡されるので、サーバ側で演出パラメーターを出力する際に、余分なパラメーターを含めないようにする。そうすることで、ゲーム内部でのみ使用するパラメータの流出を防ぐ。
見落としがちなポイントとして、LWFSで再生確認に使用するLWFと、サーバ側に組み込まれているLWFとでバージョンが一致していることを確認することだ。LWFのバージョンアップにより、動作が異なることがある。加えて制作時には、ページ遷移などの処理をLWF内に直接埋め込まず、単独で動くようにすることが重要だ。このようにすることで、制作時のブラッシュアップを効率的に行えるようにする。
開発効率化とエラー検知、キャッシュ有効利用への取り組み
LWF利用以外の取り組みだが、まずバックエンドに関しては、ユニットテストをきちんと書くようにした。バックエンドの処理を、User、Point、Item…などの単位でパッケージ化した。Jenkinsでユニットテストを定期的に実行することで、機能追加などによるデグレードを防止している。
JavaScript/CSSのビルド環境としては、GruntJSを導入し、開発用、リリース用などのビルド作業を定型化している。
また、Androidのデバッグを簡単にするため、console.logの出力内容をログサーバに送信する BirdWatcherというものを組み込んだ。
JavaScriptのエラーは、サーバ側では検知できない。そこで適切なエラーハンドリングをすると共に、原因個所の情報をサーバに通知するようにした。
アプリ内キャッシュに関しては、キャッシュ容量の上限を設け、使わないものからLRUで削除する。事前にロードすることで、読み込み時間を短縮させるなど最適化が可能だ。
最後に反田氏はまとめとして、「各チームがイテレーションを回せるように、依存をなくす」「早い段階で調整し、仕様の不整合を防ぐ」「LWFとLWFS活用の有効性」「エラー検知、キャッシュの重要性」「JenkinsやGruntJSなどで開発を効率化」を強調し、セッションを閉じた。