fc2ブログ

[Closure Compiler]型定義チェックでコードの品質を向上する

前のエントリで紹介した、Google製JavaScriptコード圧縮・最適化ツールClosure Compilerだが、コメントで型定義を行うことで強力な警告機能を利用できる。

コメントの構文はJsDocの記法に従う。基本的な書き方は JsDoc Toolkitを使う! - ドックコメントの書き方 を参照。
型定義の記法は、Closure Compilerを使う! - アノテーションによる型定義 を参照。
タグについては、とりあえず以下を押さえておけばいいと思う。
・クラスには @constructor をつける。
・プロパティの型は @type で記述。
・引数の型は @param、戻り値の型は @return で記述。
・複雑な型の別名は @typedef で宣言。
大事なのは型表現なので、ここはひと通り目を通すことをお勧めする。
指定できる型は、Google JavaScript Style Guide - JavaScript Types の Types in JavaScript に一覧がある。

それでは、Closure Compilerの利用方法を説明する。
<テスト対称コード sample.js>
/**
 * @namespace
 */
var ccsample = {};

/** @typedef {{x: number, y: number, z: number}} */
ccsample.Vector;

/**
 * 図形クラス。四角形または三角形を管理。
 * @param {ccsample.Vector} i0 頂点
 * @param {ccsample.Vector} i1 頂点
 * @param {ccsample.Vector} i2 頂点
 * @param {?ccsample.Vector} i3 頂点
 * @constructor
 */
ccsample.Quad = function(i0, i1, i2, i3) {
  /** @type {ccsample.Vector} */
  this.i0 = ccsample.copyVec(i0);
  /** @type {ccsample.Vector} */
  this.i1 = ccsample.copyVec(i1);
  /** @type {ccsample.Vector} */
  this.i2 = ccsample.copyVec(i2);
  /** @type {?ccsample.Vector} */
  this.i3 = ccsample.copyVec(i3);
};

/**
 * Vectorをコピー
 * @param {ccsample.Vector} vec コピー元Vector
 * @return {ccsample.Vector} コピー結果
 */
ccsample.copyVec = function(vec) {
  return {x: vec.x, y: vec.y, z: vec.z};
};

型定義チェックを行うには、--warning_level VERBOSE をつける。
windowsのコマンドプロンプトで実行する場合、実行コマンドは以下のようになる。
java -jar compiler.jar --warning_level VERBOSE --js sample.js --js_output_file sampleout.js > gccout.txt 2>&1
標準出力をgccout.txtにリダイレクトしている。エラーや警告は標準エラー出力に出力されるため、2>&1で標準エラー出力もリダイレクトしている。
コマンド実行結果は以下のとおり。
sample.js:25: WARNING - actual parameter 1 of ccsample.copyVec does not match formal parameter
found : (null|{x: number, y: number, z: number})
required: {x: number, y: number, z: number}
  this.i3 = ccsample.copyVec(i3);
ccsample.copyVecはnullを許容しないのに、上記の箇所でnullが入力される可能性があると警告してくれる。

Closure Compilerのすごいところは、単に型チェックをするだけではなく、コードの解析も行っていること。
この警告を受けて次のようにコードを修正すると、警告が出なくなる。
  /** @type {?ccsample.Vector} */
  this.i3 = null;
  if (i3 !== null) {
    this.i3 = ccsample.copyVec(i3);
  }
条件演算子もちゃんと解析してくれるので、以下のように書いてもいい。
  this.i3 = (i3 === null) ? null : ccsample.copyVec(i3);

このように、型表現を駆使した型定義を書いてClosure Compilerでチェックすることで、想定外のデータが入力される可能性を減らすことができる。
厳密に入力チェックをしていないprivateメソッドなどではかなり有効。

なお、Closure Compiler用の型定義でjsdoc_toolkit-2.4.0を実行したところ、JsDoc Toolkitが認識できないものがあった。
・@typedef を認識しない
・@type の型を{ }で囲った場合、{ }内を出力しない
・配列の型を Array.<...> と書いた場合、< >内を出力しない
JsDocを出力する場合は要注意。

スポンサーサイト



Closure Compilerを使ってJavaScriptコードを圧縮する

githubでソースを公開するようにしたので、GAEにアップするJavaScriptコードを圧縮することにした。
圧縮ツールはいろいろあるが、Googleが提供しているClosure Compilerを使うことにした。
日本語資料は Closure Compilerを使う! が詳しい。

Closure CompilerにはWeb版の Closure Compiler Service UI があるが、一定時間内で連続して利用できる回数などに制限がある。

ローカルPCで圧縮を行う場合、Closure Compiler Application を使用する。
JRE6以上がインストールされていれば、jarファイル1つをダウンロードするだけで特に設定作業は必要無い。

試しにPre3dのコードを圧縮してみた。
windowsの場合、コマンドプロンプトを起動し、compiler.jar のあるフォルダにcdしてコマンドを実行する。
>java -jar compiler.jar --js ..\pre3d\pre3d.js --js ..\pre3d\pre3d_shape_utils.js --js ..\pre3d\pre3d_path_utils.js --js_output_file ..\pre3d\pre3d.min.js
ファイルを圧縮するだけであれば、コマンドオプションは入出力ファイルを設定するだけでいい。
上記のコマンドを実行した結果、合計 66.9KB が 17.8KB になった。圧縮率 26.6% だ。
デフォルトのCompilation LevelsはSIMPLE_OPTIMIZATIONSなので、グローバル変数名は変わらない。
コマンドオプションの詳細は Closure Compiler Application:コマンドラインオプション を参照。
デフォルトの文字エンコーディングは UTF-8 なので注意。

圧縮する際、きちんと構文解析してエラーチェックをする。
  var a = {
    a0: 1,
    a1: 2,
  };
のような、IE7以前でエラーになるケースもチェックしている。
文末の ; が無いと圧縮後ファイルが壊れることも無い。
Closure Compilerは、ファイルサイズよりもgzip圧縮されたときのコードサイズを優先するので、圧縮後のファイルサイズが大きくなるケースがある。

JSDocの @license タグをサポートしており、
/**
 * @license Pre3d, a JavaScript software 3d renderer.
 * (c) Dean McNamee , Dec 2008.
 */
と記述すると、この部分は圧縮されずに
/*
 Pre3d, a JavaScript software 3d renderer.
 (c) Dean McNamee , Dec 2008.
*/
と出力される。圧縮後のファイルに著作権表示などを書く手間がはぶける。

ざっと使ってみて、JavaScriptコード圧縮ツールとしてかなり使えることがわかった。
更に Compilation Levels を ADVANCED_OPTIMIZATIONS にして使用したところ、コードの品質向上にも使えることがわかった。
次エントリでADVANCED_OPTIMIZATIONSについて解説する予定。
<追記>
コードの品質向上について書きました。
[Closure Compiler]型定義チェックでコードの品質を向上する
型定義チェックはデフォルトのSIMPLE_OPTIMIZATIONSでも可能でした。

githubでソースコードを公開してみた

ソースコードのバージョン管理をきちんとやろうと思い、ソースコードの公開も兼ねてgithubを使うことにした。

これだけのためにCygwinをインストールする気にならないので、msysGitを使うことにした。
Github を Windows で使ってみる 2011 年版
に従ってmsysGitのインストールとgithubのリポジトリ作成を行った。
~/.ssh が自分の環境には存在しないなど、上記リンク先と動きが違うところがあったので、そこは原文を参照した。

リポジトリは作ったものの、どうやってソースコードを登録すればいいのかさっぱりわからない。
そもそもGitがよくわからない。
そんなわけで
分散バージョン管理システムGitの使い方入門
Gitを使いこなすための20のコマンド
をザザっと斜め読み。
でも git add とかよくわからい。

リファレンスはないのかと探したら
Git ユーザマニュアル
を見つけた。コマンドの詳細はhelpコマンドを使えばいいのか。
addコマンドの詳細を知りたかったので git help add と入力したら、ブラウザが起動してちょっとびっくり。
ファイル指定で * が使えるのは便利だ。

作成したソースコードをリポジトリに登録するには
  1. 登録対称ソースコードを、git init を実行したディレクトリに格納。
  2. Git Bashで以下のコマンドを実行。
  $ cd ソースコードを格納したディレクトリ
  $ git add .
  $ git commit -m 'コミットメッセージ'
  $ git push origin master
とするだけ。
git add . でカレントディレクトリのファイル/ディレクトリを全てaddできる。

この前作った 勝手にチンチロリン を機能追加する予定なので、JavaScriptソースコードをgithubで管理することにした。
READMEには、他を参考にしてファイルの概要やライセンスなどを書いた。
「使用や配布は自由ですが著作権は放棄しません」ってことでライセンスは BSD license にした。

リポジトリに登録してgithubに反映されたが、READMEの文字コードをUTF-8にしないと日本語が文字化けする。
コミットの取り消しってどうやるんだ?と調べて
githubにpushしたcommitの取り消し
に従ってコミット取り消して再pushした。

そんなこんなで作成したリポジトリはこちら。
mimami24i/jsdice

あとは使いながら覚えていこう。

チンチロリンのゲームを作ったのだが・・・

HTML5 Canvasでサイコロを描くプログラムを使って、チンチロリンのゲームを作った。

勝手にチンチロリン | 無職のHTML5 Canvas
ccrorin1.png

とりあえず賭金固定で作ったので、スタートボタンを押したら何もすることが無い。
ゲームじゃないなこれは。
そのうち賭金を指定できるように修正しよう。

<関連エントリ>
サイコロを改造してチンチロリンで敵と戦うゲームを公開した

ちょっとだけテスト駆動開発した

サイコロを描くプログラムの修正が終わったので、これを使って何か作ることにした。
「サイコロと言えばチンチロリン」ってことで、あまりゲーム性は無いと思うんだけどチンチロリンゲームを作ることにした。

サイコロを3つならべて振ることができたので、出目や役の判定処理をコーディングすることに。
ここで、TDD(テスト駆動開発)でやってみることにした。
大した処理ではないので、Fake It やリファクタリングなどはせず、
  テストプログラム作成 → 出目や役の判定処理実装 → テスト実行
をやっただけ。1サイクルで完了した。

テストプログラムを作ってるうちにインタフェースの漏れに気づいたり、実装イメージが湧いてきたりした。
テストプログラムの作成を手間だとは感じなかった。効率良く開発できたと思う。
今回は「出目や役の判定」ということで仕様がカッチリと固まっていたので、TDDに向いていた気がする。
動かしながら仕様を調整していくような機能では、いちいちテストプログラムを作るのが手間になりそう。

これからも部分的にTDDを取り入れてみようかな。

サイコロを描くプログラム修正中 2日目

昨日の続き。
3Dサイコロを描くプログラムで表示される目の向きが、実際のサイコロと違う。
1,4,5の目は対称なので関係無いが、2,3,6の向きがおかしい。
あまり重要ではないところだが、暇なので向きにこだわることにした。

立方体にテクスチャとしてサイコロの目を貼れば簡単なのだが、Pre3d.TextureInfo では context.drawImage() を使用するので負荷が大きくなる。
あくまでも線(Pre3d.Path)を使って目を描くことにする。

回転前の立方体各面に、テクスチャのように目のpathを作成した。
立方体の回転に合わせてpathも回転すればいい。
だが、pathは面とは独立しているので裏面のpathも表示されてしまう。

Pre3d.Renderer.bufferShape() で面の裏表判定処理を行っているが、今回のケースではこれよりも簡単に裏表判定できることに気づいた。
立方体の中心が(0, 0, 0)なので、「回転後の面重心Z座標 > 0」の面を表として表示すればいい。

こうして、自分の手元にあるサイコロと同じ目の向きに表示することができた。
サイコロの表示位置を指定できるようにする修正も行った。
プログラムをだいぶ修正したので、明日はQUnit用テストプログラムを書き直してテストするつもり。

サイコロを描くプログラム修正中

2D/3Dサイコロを振る | 無職のHTML5 Canvas
でサイコロを描くプログラムを作ったので、サイコロを使ったゲームを作ろうと思った。
だが、このプログラムでは中央に1個のサイコロしか表示できない。

そんなわけで、サイコロの個数や位置を指定できるようにプログラムを修正することにした。
2Dサイコロはすぐできたのだが、3Dサイコロ方が時間がかかっている。

サイコロの個数を増やすと3D処理の負荷が大きくなる。
描画の際の負荷を減らすように3Dレンダリング用バッファを作成していたのだが、描画時の負荷をいっそう減らすようにプログラムを修正している。
具体的には、Pre3d.Renderer.drawBuffer()用に作成したバッファを、canvasのcontextに直接描画用のバッファに変更している。
Pre3d.Renderer.drawBuffer()を介さずに直接描画するため、描画の度に行っていたレンダリング処理が無くなって負荷が減る。

直接描画するため、Pre3d.Renderer.drawBuffer()内に記述されていた処理をいくつか自分のプログラムに移したので、Pre3dバージョンアップ時のメンテナンスが問題になる。
そこまでして負荷削減する必要あるのかなぁとも思う。

[Google App Engine for Python] deployできないディレクトリ名

久しぶりにPythonプログラムをGAE/Pにアップしたのだが、ローカル開発環境ではちゃんと動くのに、appspot.com上では「.pyファイルが見つからない」とエラーが出た。
しばらくハマったのだが、app.yamlに
  script: html5/pre3dHowTo/pre3dHowToTop.py
と書いたのが原因だった。
途中に数字のあるディレクトリのファイルはdeployできないようだ。
  script: html5/predHowTo3/pre3dHowToTop.py
だとちゃんとdeployできる。

静的ファイルは、途中に数字のあるディレクトリのファイルでもdeployできる。
  static_dir: html5/pre3d

GAE/Pの問題と言うよりは、Google App Engine Launcher の問題だな。
Windows以外の環境ではどうなんだろう。

Pre3dでHTML5 Canvas上に立体サイコロを描く手順をまとめた

3Dを描くJavaScriptライブラリPre3dを使って、HTML5 Canvas上に立体サイコロを描く手順をまとめた。

Pre3dで立体サイコロを描く
draw3dTitle1.png

自分が書いたのを読んでみると、同じような内容を何度も書くなど冗長な感じがする。
もっとシンプルに書けないのだろうか。

3D描画JavaScriptライブラリにはいろいろ種類があるが、Pre3dしか知らないので良さを主張できない。
自分がPre3dを選んだ理由は「ファイル数が少なくてソースコード読むのが楽そうだから」だし。

JavaScriptの3Dは、いずれはWebGLに収まりそうだから、他のライブラリを調べる気にはならいなぁ。

Pre3dのチュートリアル作成中

HTML5 Canvasで3Dを描くJavaScriptライブラリPre3dのリファレンスを作成した。
公開しようと思ったが、これだけだと寂しいので、チュートリアルのようなものを作ることにした。

Pre3dを使って以下のような立体サイコロを描く手順をまとめている。
dice1
思ったよりもボリュームが大きく、現在6ページ目まで書いた。全部で7か8ページぐらいになりそう。
全部読んでくれる人がいるのだろうか?という気にもなるが、きちんとまとめて公開するつもり。
(公開しました → Pre3dで立体サイコロを描く)
プロフィール

himax64

Author: 南西
30代後半の無職です。
就活もせずダラダラ生きてます。
作ったもの

最新記事
人気記事
検索フォーム
カテゴリ
月別アーカイブ
最新コメント
最新トラックバック
RSSリンクの表示
QRコード
QRコード
カウンター