2011年9月26日月曜日

JavaScriptライブラリjQueryその1

こんにちは、Nakajinです。

今回は、jQueryについて書いていこうと思います。

jQueryとは、少ない記述で高度な処理ができる軽量なjavaScriptライブラリです。
CSSに近い形で記述することが可能です。

通常のJavaScript
var element = document.getElementById("test");
element.style.color= "red";

jQuery
$("#test").css("color", "red");

上記のように、jQueryではシンプルな記述で書くことができます。

jQueryを使えば、アニメーション効果を簡単に表現することもできます。

$("#test2").click(function() {
$(this).animate({width: "200px", height: '200px'}, "slow");
});

サンプル
クリックで拡大


jQueryは世界中で多く使われており、様々なプラグインも作成されています。
使っていない人は、是非使ってみるといいと思います。

2011年9月13日火曜日

第3回HTML5のススメ

もうすぐ、ゲームショウの季節になりました。たのしみですね。KOYAです。

さて、今回は、「ネイティブにも負けない!HTML5のタッチイベント」について
話していこうと思います。

で、どうすればタッチイベントが拾えるの?って感じですが、以下の数ステップで
簡単に実現することが可能です。

以下、このような指定。
 
canvas.addEventListener("touchstart", ?????, false);
canvas.addEventListener("touchmove", ?????, false);
canvas.addEventListener("touchend", ?????, false);
canvas.addEventListener("touchcancel", ?????, false);

とまぁタッチに関するイベントが4つあるので、canvasで使用するなら、Eventに登録するだけで使えちゃいます。

※addEventLisstenerの仕様に関しては割愛させて頂きます。

で具体的にどんなイベントの際に発生するのか?ってことですが・・・

touchstart・・・タッチ入力開始時に発生。
touchmove・・・タッチスライド時発生。
touchend・・・タッチイベント終了時発生。
touchcancel・・・今のところ不明。わかる方がいらっしゃいましたら、たゆたうへご連絡ください。


とこんな感じです。

さぁこれでとりあえずタッチイベントは拾えました。
今回もサンプルで何か作りましょう。

ってことで、第1回から引き続き使用している、たゆたうロゴをタッチしてドロップ&ドラッグで
動かしちゃうスクリプトを作ることにします。

さっそく以下ソース。

 
// キャンバス
var canvas;
// コンテキスト
var ctx;
// キャンバス幅
var canvasWidth;
// キャンバス高さ
var canvasHeight;

// 指定オブジェクト
var obj;
// 画像オブジェクト
var img;
// タッチオブジェクト
var touch;

window.onload = function() {
 init();
};

/**
* 初期化処理
*/
function init(){

 // キャンバスの取得を行う。
 canvas = document.getElementById('testCanvas');
 // コンテキストの設定。
 ctx = canvas.getContext('2d');

 // キャンバスの塗りつぶし。
 canvasWidth = 400;
 canvasHeight = 600;

 // イベントの挿入
 canvas.addEventListener("touchstart", startListner, false);
 canvas.addEventListener("touchmove", moveListner, false);
 canvas.addEventListener("touchend", endListner, false);
 canvas.addEventListener("touchcancel", endListner, false);

 // オブジェクトクラスを生成する。
 obj = new Object();
 obj.x = 100;
 obj.y = 100;

 // ドラッグ時のオブジェクト
 touch = new Object();
 touch.x = 0;
 touch.y = 0;
 touch.dropFlag = false;
 touch.startX = 0;
 touch.startY = 0;

 // たゆたうロゴ
 img = new Image();
 img.src = "http://?????????????????/tayutau.png";

 // ロード終了時に描画等開始。
 img.onload  = function() {
  obj.w = img.width;
  obj.h = img.height;
  // 描画処理を行う。

  setInterval("loop()", 50);
 }
}

/**
* ループ処理処理
*/
function loop() {

 // ドロップされていない場合、初期化。
 if (false == touch.dropFlag) {
  obj.x += touch.x;
  obj.y += touch.y;
  touch.x = 0;
  touch.y = 0;

 }

 // 背面を黒塗り
 ctx.fillRect(0, 0, canvasWidth, canvasHeight);
 // 描画
 ctx.drawImage(img, obj.x + touch.x, obj.y + touch.y);
}

/**
* タッチイベント開始
*/
function startListner(event) {

 // キャンバスの絶対座標を取得する。
 var rect = event.target.getBoundingClientRect();

 // キャンバスでのタッチ座標を取得する。
 touch.startX = event.touches[0].pageX - rect.left;
 touch.startY = event.touches[0].pageY - rect.top;
 event.preventDefault() ;

 // 画像に当たっていた場合
 if (touch.startX > obj.x && touch.startX < obj.x + obj.w) {
  if (touch.startY > obj.y && touch.startY < obj.y + obj.h) {
   touch.dropFlag = true;
  }
 }
}

/**
* 移動
*/
function moveListner(event) {

 // つかんでいない場合
 if (false == touch.dropFlag) {
  return;

 }

 // キャンバスの絶対座標を取得する。
 var rect = event.target.getBoundingClientRect();
 // 現在のキャンバス位置から-開始位置の座標の算出

 touch.x = (event.touches[0].pageX - rect.left) - touch.startX;
 touch.y = (event.touches[0].pageY - rect.top) - touch.startY;
}

/**
* 終了イベント
*/
function endListner(event) {
 touch.dropFlag = false;

}

って事で、完成しました。少々長かった。
もっと簡単に実装できそうですが、サンプルソースって事で勘弁して下さい。

一部気になるコードだけ説明します。

1つ目は、

event.touches[0].pageX

なぜか配列になってる。。。
そう、マルチタッチだって対応してるんです。
なので、うまいことやれば結構なリッチでハッピーなゲームが作れるかもしれません。


そして2つ目は、

 event.preventDefault() ;

資料などを読むと、

イベントがキャンセル可能な場合、preventDefault メソッドを使用するとイベントのキャンセルを通知できるため、そのイベントの結果として通常は実装により実行されるデフォルトのアクションが実行されません~


と書いてあります。
何のために必要なのか?

最初はこれを記述せずに実装していたのですが、
タッチして移動するたびにブラウザがスクロールしてしまい、
うまく動作しなかったわけです。

こいつを入れてあげると、タッチイベント以降のイベントがキャンセルされるため、
スクロールせずにうまくタッチイベントが動くのです。

タッチイベントなんか簡単だろう。と思い実装してみたは良いものの
まさかこのような所でハマるとは思いませんでした。

以上、完。


2011年9月11日日曜日

PHPでオブジェクトから別のオブジェクトへプロパティをコピーする

こんにちは、matsuiです。

今回は弊社でソーシャルアプリを開発していく中で作成された共通処理の一部を紹介していきたいと思います。

ご紹介する内容は、指定されたオブジェクト間で同じ名前で定義されているプロパティの中身をコピーするというものです。

弊社内で使われているフレームワークでは、処理のレイヤーごとにデータを受け渡すためのオブジェクトを使ってやり取りしています。
そのような構造をとっているため処理のレイヤーを越える際に、オブジェクト間のデータの詰め替え作業が発生し、開発効率の低下を招く可能性がありました。
開発効率をできる限り下げないようにするために、下記のような「自動的に詰め替え作業を行う共通処理」を作成し、詰め替え作業のコストの削減を図っています。

----------------------------------------------------------------------
 /**
 * 指定されたオブジェクトに定義されているプロパティを詰め替える.
 *
 * 引数に指定された両方オブジェクトを比較し、同一のプロパティが存在した場合に第一引数のオブジェクトから第二引数のオブジェクトに値をコピーする。
 *
 * @param unknown_type $sourceDto
 * @param unknown_type $targetDto
 */
public static function copyProperties($sourceDto, $targetDto)
{
    if ($sourceDto === null || $targetDto === null) {
        return null;
    }
  
    $targetPropertyList = get_class_vars(get_class($targetDto));
  
    foreach ($targetPropertyList as $key =&gt; $value) {
        if (property_exists($sourceDto, $key)) {
            $targetDto-&gt;$key = $sourceDto-&gt;$key;
        }
    }
  
    return $targetDto;
  
}
----------------------------------------------------------------------

なお、お気づきの方もいらっしゃるかもしれませんが、
ご紹介した処理では、正確には「値のコピー」になっていない場合があります。

それはプロパティの中身が参照型と呼ばれる形式になっている場合です。
詳しい説明は割愛しますが、オブジェクト型などに代表される参照型の場合、参照先のオブジェクト自体が複製されるわけではなく、参照先オブジェクトへの参照がコピーされることになります。

さらにオブジェクトがネストされていた場合などは、「シャロー(shallow)コピー」と「ディープ(deep)コピー」の話も絡んできます。

記述された処理が思うような動きをしなかった場合は、参照型・シャローコピー・ディープコピーといった概念について確認していただいた方が良いかもしれません。

追記
PHP(Zend Engine)ではzvalという概念を持ち変数を管理しています。
そのため、変数の代入すら本来の値のコピーではないようです…それは今現在のZend Engineの実装の話なのでここでは取り上げませんが、興味のある方は調べてみるのも面白いと思います。

2011年9月8日木曜日

PHPテンプレートエンジンTwig 番外編:基礎構文サンプル

こんにちは、Yuzuruです。
NakajinさんがTwigについて書かれていたので今回はおまけとして簡単な例を幾つか上げてみようと思います。
変数についてはPHPテンプレートエンジンTwig その2を参照

if
class User {
    public 'age' => string '10'
    public 'name' => string 'Ronaldinho'
    public 'sex' => string 'male'
}
$object = new User();
echo $template->render(array('user' => $object));
[twig]
{% if user.age < 20 and not user.sex == 'female' %}
     こんにちは、{{user.name}}くん
{% else %}
    こんにちは、{{user.name}}さん
{% endif %}

[表示]
こんにちは、Ronaldinhoくん

論理演算子はand, or, not です(&&とかと違うので注意)


for

i=0からi=10まで繰り返す処理

[twig]

{% for i in 0..10 %}
    * {{ i }}
{% endfor %}

[表示]
* 0 * 1 * 2 * 3 * 4 * 5 * 6 * 7 * 8 * 9 * 10

foreach的な繰り返し処理もfor

class User {
    public $id;
    public $name;
}
$object1 = new User();
$object2 = new User();

$object1->id = 1;
$object1->name = 'Carlos';
$object2->id = 2;
$object2->name = 'Sofia';
$objects = array();
$objects[0] = $object1;
$objects[1] = $object2;echo $template->render(array('users' => $objects));

[twig]
{% for user in users %}
    {{user.id}}:{{user.name}}
{% else %}
     ユーザはいません
{% endfor %}

[表示]
1:Carlos 2:Sofia
nullやemptyの時はelseに入ります。

文字列連結
~を使います。
[twig]
{% set name = 'Santiago' %}
{{ "Hello " ~ name ~ "!" }}

[表示]
Hello Santiago!

format
書式フォーマットの指定
[twig]
{% set hoge = 0.21311 %}
    1:{{ hoge }}
    2:{{ "%2.2f"|format(hoge) }}

[表示]
1:0.21311
2:0.21

[twig]
{% set name = 'Santiago' %}
{{ "Hello %s!"|format(name) }}

[表示]
Hello Santiago!

printfの書式指定と同様です。

date
日付の表示形式
[twig]
{% set created = '2011-09-07 11:22:33' %}
①{{ created }}
②{{ created|date("H:i") }}
③{{ created|date("m/d") }}

[表示]
①2011-09-0711:22:33
②11:22
③09/07

2011年8月28日日曜日

grep + 正規表現 + Apache %D

こんにちは、hodori です。

Webサービス開発に置いてそれなりに使われるちょっとした合わせ技です。

まず基本になるのはApacheの設定で%Dを入れることで
アクセスログにリクエストを処理するのにかかった時間をマイクロ秒単位で出してくれます。

そのアクセスファイルをgrepで正規表現を使って指定時間以上かかったリクエストだけ表示できます。

grep '.* [2-9][0-9][0-9][0-9][0-9][0-9][0-9]' access.log < 2秒以上の場合

同じようにtailと一緒にgrep + 正規表現を使うことで時間がかかった処理だけ監視できます。

tail -f access.log | grep '.* [1-9][0-9][0-9][0-9][0-9][0-9][0-9]' < 1秒以上のリクエストを監視

知っている人には今更なものですが結構使いどころが多い物でもあるので紹介させていただきました。

2011年8月12日金曜日

PHPテンプレートエンジンTwig その2

こんにちは、Nakajinです。

今回は、Twigの変数の扱い方について簡単に書いていこうと思います。

まず、PHP側でテンプレートに表示する変数のセットは以下のようになります。

[php]
<?php

require_once 'Twig/Autoloader.php';
Twig_Autoloader::register();

// Twigの基本設定
$loader = new Twig_Loader_Filesystem('./');
$twig = new Twig_Environment($loader, array(
'cache' => './cache',
));

// テンプレートの呼び出し
$template = $twig->loadTemplate('test.html');
// 変数をセットして出力
echo $template->render(array('test' => 'テスト'));

[twig]
<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>テスト</title>
</head>
<body>
{{ test }}
</body>
</html>

[表示]
テスト

test変数に「テスト」という文字列をセットしてTwig側で呼び出すことができました。

配列やオブジェクトを渡すこともできます。

[php]
$array = array(

'hello' => 'こんにちは'
);
echo $template->render(array('test' => $array));

[twig]
{{ test.hello }}

のように、「.」を使って配列の要素を指定することができます。

[php]
class Test {

public $hello = 'こんにちは';
}
$object = new Test();
echo $template->render(array('test' => $object));

[twig]
{{ test.hello }}

オブジェクトの場合も、「.」を使ってプロパティにアクセスすることができます。

[php]
class Test {

public function hello() {
return 'こんにちは';
}
}
$object = new Test();
echo $template->render(array('test' => $object));

[twig]
{{ test.hello }}

オブジェクトの場合も、「.」を使ってプロパティにアクセスすることができます。

[php]
class Test {

public function getHello() {
return 'こんにちは';
}
}
$object = new Test();
echo $template->render(array('test' => $object));

[twig]
{{ test.hello }}

また、オブジェクトのgetterメソッドにアクセスすることもできます。

次回は、Twigの構文について書いてみようと思います。

2011年8月2日火曜日

第2回HTML5のススメ

最近、通勤には自転車を使っています。痩せるといいな。KOYAです。

第2回はHTML5で追加された機能、「Web Storage」について話していこうと思います。

WebStorageってなに?っていうと、memcachedだったり、TokyoTyrantだったりと同様のKey-Value型のストレージ機能です。
ただし、WebStorageはクライアント側に保存することができるというところがかなり魅力的です。
WebStorageは大別すると2種類存在します。


sessionStorage…ブラウザを終了するとデータが失われる。
localStorage…ブラウザを閉じてもデータが残る。


今回は永続的に保存することが可能なlocalStorageの話をしていきます。
実はすごく簡単で以下の様に記述すればすぐに実装が可能です。


// "test"というKeyに"abcdefg"とい文字列を保存
localStorage.setItem("test", "abcdefg");
// "test"をアラートで表示。
alert(localStorage.getItem("test"));


通常WebStorageに保存する場合、setItemでデータを保存し、getItemで出力するという形になっています。
ですが、一々webStorageなのか違うのかなんて意識しないでも保存する方法があります。それが以下の記述の仕方です。


// "test"というKeyに"abcdefg"とい文字列を保存
localStorage.test = "abcdefg";
// "test"をアラートで表示。
alert(localStorage.test );


オブジェクトのプロパティに値を格納するかの如く保存できています。すごいですね、WebStorageは。

さぁ、そしてここからが本題です。
第1回でお話しした、画像表示ですが、画像自体をクライアント側に保持できないか?と思い挑戦しました。

実はこのWebStorage、1つ弱点があり、実は文字列しか格納することができません。
ですので、画像自体はバイナリデータなので保存することができません。
なので、一旦base64に変更してから保存するしかありませんでした。
※アプリケーションキャッシュを使うという手もありますが、それはまたの機会に。

以下ソースとなります。


window.onload = function () {
main();
}

function main() {

// ローカルストレージに画象がない場合
if (localStorage.imageData == null) {
// キャンバスの作成
var saveCanvas = document.createElement('canvas');
// コンテキストの取得
saveCtx = saveCanvas.getContext("2d");
// Imageオブジェクトの作成
var objectCaba = new Image();
objectCaba.src = "http://~~~~tayutau.png";
// 読み込み完了時
objectCaba.onload = function() {
saveCtx.drawImage(objectCaba, 0, 0);
// ローカルストレージに保存
localStorage.imageData = saveCanvas.toDataURL("image/png");
// ローカルストレージから描画する。
draw();
}
} else {
// ローカルストレージから描画する。
draw();
}

}

function draw() {

// キャンバスの取得
canvas = document.getElementById("test");
// コンテキストの取得
ctx = canvas.getContext("2d");

// Imageオブジェクトの作成
var objectCaba = new Image();
// ローカルストレージから画象の読み込み
objectCaba.src = localStorage.imageData;

// 読み込み完了時
objectCaba.onload = function() {
ctx.drawImage(objectCaba, 0, 0);
}
}


とこのような感じで書けば、画象を保存し表示することが可能です。
どのようにそれを実現しているかを説明します。

var saveCanvas = document.createElement('canvas');
という記述で、canvasを作成し、

localStorage.imageData = saveCanvas.toDataURL("image/png");
toDataURLで現在キャンバスに描かれているデータをbase64に変換し、ストレージに保存しています。

他の記述は前回と同様に単純に表示しているだけですので、割愛させて頂きます。
以外に簡単にできたように見えますが、当初作成していたときに実はjavascriptの構造上の落とし穴に引っかかりましたが
その話は次回に持ち越すことにします。

ということで、次回は、canvasを表示する際の"落とし穴"の話と、標準搭載ではなくなってしまったWebDataBaseの話をしていこうと思います。

2011年7月30日土曜日

MySQL5.5のベンチマークテスト その2

こんにちは、matsuiです。

前回に引き続き、MySQL5.5のベンチマークについて、mysqlslapを使って得られた結果から5.5の特徴を見ていきたいと思います。
進め方は前回と同様、MySQL5.1とMySQL5.5のベンチマークのスコアを対比させる形です。

条件5
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=3 --number-char-cols=5 --concurrency=1000 --auto-generate-sql-write-number=300 --auto-generate-sql-execute-number=300 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 646.631 seconds
Minimum number of seconds to run all queries: 646.631 seconds
Maximum number of seconds to run all queries: 646.631 seconds
Number of clients running queries: 1000
Average number of queries per client: 300

MySQL5.5
Average number of seconds to run all queries: 601.654 seconds
Minimum number of seconds to run all queries: 601.654 seconds
Maximum number of seconds to run all queries: 601.654 seconds
Number of clients running queries: 1000
Average number of queries per client: 300

前回の条件4の結果からクライアントの数よりもクエリ数の方が実行時間に大きな影響を与えると推測し、クライアント数はそのままにクエリ数を条件4の30から10倍し、300で実行してみました。
5.1は8倍、5.5は100倍かかったということで、どちらも急激に実行時間が長くなっています。
性能劣化の比率だけで言うのであれば、5.5の方が性能劣化が激しいですが、そもそも条件4の結果自体が5.1と5.5で13倍近く違いますので、この結果だけでは5.5になって性能が劣化したとは言えません。


条件6
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=10 --number-char-cols=10 --concurrency=1000 --auto-generate-sql-write-number=10 --auto-generate-sql-execute-number=30 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 20.053 seconds
Minimum number of seconds to run all queries: 20.053 seconds
Maximum number of seconds to run all queries: 20.053 seconds
Number of clients running queries: 1000
Average number of queries per client: 30

MySQL5.5
Average number of seconds to run all queries: 12.499 seconds
Minimum number of seconds to run all queries: 12.499 seconds
Maximum number of seconds to run all queries: 12.499 seconds
Number of clients running queries: 1000
Average number of queries per client: 30

条件6では少々検証方向性を変更し、クライアント数とクエリ数は条件4と同じのまま、カラム数と事前に存在するデータの量を変更しています。
カラム数はintとcharを合わせて5倍近くになっていますが、事前に用意されるデータは1/10です(もともと大した量ではないので、実行前の予測としては結果にを与えるほどの減少量ではないと予測しました)。
結果を見ると、条件4よりも処理時間が短くなりました。
カラム自体は増えているはずですので、事前に存在するデータの量が、実行時間に大きな影響を与えたのでしょうか。
ちなみに--auto-generate-sql-load-typeをmixedに指定していますので(mixedはpkによるselectとinsert)、実行時間の変化はSELECT文の発行によるものなのかもしれません。


条件7
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=10 --number-char-cols=10 --concurrency=500 --auto-generate-sql-write-number=10 --auto-generate-sql-execute-number=30 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 5.148 seconds
Minimum number of seconds to run all queries: 5.148 seconds
Maximum number of seconds to run all queries: 5.148 seconds
Number of clients running queries: 500
Average number of queries per client: 30

MySQL5.5
Average number of seconds to run all queries: 3.661 seconds
Minimum number of seconds to run all queries: 3.661 seconds
Maximum number of seconds to run all queries: 3.661 seconds
Number of clients running queries: 500
Average number of queries per client: 30

条件6からクライアントを半減させました。
条件3からみた場合クライアント数は同じで、クエリ数は条件3の1/3です。
条件4からみた場合は、クライアント数が半分で、クエリ数は同一です。
カラム数と事前のデータについてもは条件6と同様です。
5.5についてはクライアント数が1000程度の場合、処理時間はクライアント数に比例しています。
やはり5.1と5.5では、大幅な処理時間の劣化が始まるポイントが改善され、より安定して高いパフォーマンスが出るように調整されているように思えます。


最終結果
2回に分けてMySQLの5.1と5.5を比較してきましたが、なんとなく特徴が見えてきたのではないでしょうか(検証しきれなかった問題もありますが…)。
今回の検証で特におもしろい結果となったのは、条件4のようなケース(多数のクライアントで少量のSQL実行)において、5.1よりも並列処理性能が大幅に増したという点です。
ソーシャルゲームのように多数のクライアントが比較的少数のSQLを実行するというケースにおいて、特に重要な改善と言えます。
また、サーバの管理コストの面からみると、サーバプログラムの性能向上はそのままサーバの管理コスト減につながります。

全てのケースにおいて、5.5のパフォーマンス向上は素晴らしいものがあり、特に(処理限界は実行環境のスペックに左右されますが)「並列処理性能向上」と「パフォーマンス劣化開始地点の引き上げ」はMySQLに関わる方全てに非常にうれしい点といえるのではないでしょうか。
MySQK5.1から設定周りで変更点も少なくないですが、弊社で運用している限りMySQL5.5を使ったために発生したトラブルはありません。
5.1から5.5へ移行できる環境であるならば、ぜひ5.5への切り替えを検討されてはいかがでしょうか。

2011年7月25日月曜日

新卒エンジニアも勉強会に行ってみると良いですよ、という話

こんにちは、Yuzuruです。
自分は今年の4月から新卒で働き始めたばかりなのでちょっとちがったテーマで書いてみようと思います。
さて、記念すべき(?)一回目のテーマは勉強会です。
弊社たゆたうでは勉強会への参加が推奨されているのですが、新人となると知り合いもいないし、自信もない… なかなか不安が多くて足踏みしてしまう世界なのではないかと思います。
自分もまだまだ新米なので恐縮ですが、とりあえず最初に当たって砕けろで参加したときに「行って良かったなぁ」と感じたことを挙げてみるので何かの参考になれば幸いです。
・自分がライン上にいるというのが分かる
完璧にはわからないまでもなにか知っていることがあるともうちょっとで理解できそう!と自分がその道にいることを認識できます。
 ・研修の成果が実感できる
もちろん全てが繋がっているわけではないのですが、不安と期待の入り交じった中で行った研修も同上の理由で納得度UPかもしれません。
・未来への視野が拡がる
技術寄りの関心を持った人が周りに増えると自然とイメージも沸いてくる…気がします。
・単語の読み方、発音がわかる
ネットや書籍だと意外とわからない!
・今までどういうスタンスでやってきたか、社会の先輩に聞ける機会
就職活動における説明会などはいわゆる建前も多いわけで…。勉強会にもよりますがフランクに会話してくれる方が多いと思います。
・次の為のバネになる
内容がわからなかったりすると次はわかるようになろう!という気持ちが芽生えます。
・色々楽しくなる
上に挙げたようなことを実感できるとスキルアップの意味が大きくなり仕事の楽しみが増え、勉強会自体や技術情報を集めたりする楽しさも増えます。
ちなみに自分が初めて参加したのはJAWSUGの勉強会でした。
ネットで簡単エントリできる勉強会も多いので、色々参加してみると新しい発見があるかもしれませんね。
※行って良かった楽しかった!で終わらないようにアウトプットするのも大事とよく聞きます。なかなかできてないので反省…。

2011年7月15日金曜日

Xdebugのプロファイル

こんにちは、hodori です。


PHPで開発を行うエンジニアがよくお世話になるのがXdebugのプロファイル機能です。

実行される順番や各関数ごとの実行時間・実行回数などの役に立つ情報をとれるので

デバッグやボトルネックを調査する際に大変便利なものです。


普通に使う分にはXdebugを投入して php.ini の中に

xdebug.profiler_enable = 1

を記述するだけなので簡単に使えます。


ただ、この状態だとすべてのアクセスでプロファイルが作られるので

クラウド上に開発環境を置いて共用で使う場合などは

調査したいファイルのプロファイル以外にも多数のプロファイルができてしまい

必要なプロファイルを探すのが少々面倒だったりします。


それを回避するための方法を二つほど紹介しようと思います。


一つ目はプロファイルを生成するホスト名を指定する方法があります。

共用の環境に複数のVirtualHostを作って運用している場合に

任意のHostへのアクセスだけプロファイルを残す設定です。

  xdebug.remote_host = "local.hoststar"

管理用のページとアプリを同じサーバーの別VirtualHostとして

運用している場合などにアプリのプロファイルだけを残す事が出来ます。


もう一つの方法は少々手間が増えることになりますが、

プロファイルを生成したい場合のみ、その旨をパラメータで指定する方法です。

設定は php.ini に下記の2行を記述して

xdebug.profiler_enable = 0
xdebug.profiler_enable_trigger = 1

プロファイルを生成したい場合にGETかPOSTで「XDEBUG_PROFILE」を送ると

その場合のみプロファイルが生成されます。

携帯端末などでテストしている場合などは入力が少し面倒だったりしますが……。


Firefoxのアドオンの「Xdebug Helper」のプロファイル生成のON/OFF機能なども

この設定を使っていたりします。Firefoxを使えない状況でも少しの面倒で

使い分けができるので覚えておくと便利かなと思い紹介させていただきました。

2011年7月12日火曜日

PHPテンプレートエンジンTwig その1

こんにちは、Nakajinです。

弊社では、主にPHPを使って開発をしていますが、テンプレートエンジンとしてTwigを導入してみました。

今回はTwigの記述方法について簡単に説明したいと思います。

まず初めに、簡単なサンプルを以下に記述します。

[ソース]
{% set test = 'あいうえお' %}
{{ test }}

[表示]
あいうえお

Twigでは基本的に「{{ }}」「{% %}」の2つの区切り文字を使って記述していきます。

{% set test = 'あいうえお' %}
1行目では、test という変数に「あいうえお」という文字列を格納しています。
条件式やループ、変数の代入などに「{% %}」を使用します。

2行目では、test変数の値を出力しています。
変数の出力に「{{ }}」を使用します。

Twigは、テンプレートの継承機能などもあり、独自のカスタムタグの追加など拡張性も高いので、ぜひ使って見てください。

2011年6月30日木曜日

第1回HTML5のススメ

暑い日々が続きますね。KOYAです。

まだまだソーシャルアプリの売上はフィーチャーフォンの方が大きいですが、
AndroidやiPhoneを所持している方も多くなってきました。

という事で、そろそろスマートフォン向けソーシャルアプリ。。。。
HTML5で作ることをおすすめします。

第1回の今回はHTML5の中でも特に注目されているキャンバスタグのよく使う方法について記載しようと思います。

そもそもキャンバスタグとは、
標準のHTMLとJavascriptで、線や円などの図形、画像などを複合的に描画することが出来ます。

今回は画像と画像を組み合わせようと思います。












上記2つの画像を用意します。


わずか数ステップを記述すれば
このように画像を重ねることが可能。



<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<meta charset="UTF-8">
<title>test</title>

<script type="text/javascript">

window.onload = function () {
main();
}

function main() {

// キャンバスタグを取得
canvas = document.getElementById("test");

// コンテキストを設定
ctx = canvas.getContext("2d");

// 背面を黒塗り
ctx.fillRect(0, 0, 126, 151);

// 明日のキャバクイーン画像
var objectCaba = new Image();
objectCaba.src = "images/caba.png";
ctx.drawImage(objectCaba, 0, 0, 201, 151,0, 0, 201, 151);

// たゆたうロゴ
var objectTayutau = new Image();
objectTayutau.src = "images/tayutau.png";
ctx.drawImage(objectTayutau, 0, 0, 126, 151,0, 80, 60, 70);

}
</script>
</head>
<body>
<canvas id="test" width="201" height="151"></canvas>
</body>
</html>

と記載すれば、下記のように画像を重ね合わせて描画することが可能です。










canvasタグは他のネイティブアプリ等と同様の書き方でほぼ書けるお手軽タグとなっています。
iPhone、Androidで両対応するようなことがあれば、是非活用してくださいね!!



2011年6月24日金曜日

MySQL5.5のベンチマークテスト その1

こんにちは、matsuiです。

弊社ではソーシャルアプリを開発・運用していますが、主な実行環境の一つとして Amazon EC2を利用しています。
EC2について知りたい方はAWS(Amazon Web Service)のサイトを見て頂くとして、
今回は弊社システムでよく利用している「MySQL」のベンチマークテストについてです。

長らく安定版は5.1系で止まっていましたが、ようやく5.5系安定版が公開されたことを受けて、どの程度の性能アップがなされているのかを確認してみました。

確認方法はMySQL 5.1.4から標準で付属しているmysqlslap(クライアント負荷エミュレーション)を使います。
mysqlslapを使う理由としては、標準で付属しており、事前準備がいらないというのがいいですね。
どれぐらい性能アップしたか知りたいという欲求を満たすには十分な気がします。

今回は比較対象として、実際にシステム内で使われているMySQLと同じバージョンを用意することにします。

環境としては、以下の通りです。

Amazon EC2(AWS)
EC2 Instance Type : t1.micro

MySQL 5.1.54(比較対象)
設定は、innoDB plugin有効、--innodb-buffer-pool-sizeに200MB程度割り当て(弊社内の貧弱マシン用の設定)、他細かいところを少しだけ修正。

MySQL 5.5.4
設定はデフォルトのまま。

次にmysqlslap実行時オプションについて、今回使うものだけを簡単に解説します。

--auto-generate-sql
ファイルやコマンドオプションを介して提供されていない場合、SQLステートメントを自動的に生成

--auto-generate-sql-guid-primary
GUIDベースのプライマリキーカラムを作成

-e innodb
テーブル作成の際使用するストレージエンジン

--number-int-cols=3
INT型カラムの作成数

--number-char-cols=5
CHAR型カラムの作成数

--concurrency=10
クライアント数

--auto-generate-sql-write-number=1000
テーブルに格納するデータ数

--auto-generate-sql-execute-number=1000
クライアントごとのクエリ数

--auto-generate-sql-load-type=mixed
アクセスパターン(mixedはpkによるselectとinsert)

--create-schema=test
スキーマ名

-h localhost
接続先ホスト

-u root
接続ユーザ

-p
パスワード

では実際のベンチマークのスコアです。
差がわかりやすいように同条件のmysqlslapを実行し、MySQL5.1をMySQL5.5でどのような違いが現れるかを一つ一つ見ていきます。

条件1
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=3 --number-char-cols=5 --concurrency=10 --auto-generate-sql-write-number=1000 --auto-generate-sql-execute-number=1000 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 2.934 seconds
Minimum number of seconds to run all queries: 2.934 seconds
Maximum number of seconds to run all queries: 2.934 seconds
Number of clients running queries: 10
Average number of queries per client: 1000

MySQL5.5
Average number of seconds to run all queries: 2.181 seconds
Minimum number of seconds to run all queries: 2.181 seconds
Maximum number of seconds to run all queries: 2.181 seconds
Number of clients running queries: 10
Average number of queries per client: 1000

10クライアントで1000クエリずつということで、特に弊社のようなサービスではあまり現実では発生しない条件ですね。
MySQL5.5の方が40%程度高いスコアが出ています。

条件2
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=3 --number-char-cols=5 --concurrency=100 --auto-generate-sql-write-number=1000 --auto-generate-sql-execute-number=1000 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 127.041 seconds
Minimum number of seconds to run all queries: 127.041 seconds
Maximum number of seconds to run all queries: 127.041 seconds
Number of clients running queries: 100
Average number of queries per client: 1000

MySQL5.5
Average number of seconds to run all queries: 72.507 seconds
Minimum number of seconds to run all queries: 72.507 seconds
Maximum number of seconds to run all queries: 72.507 seconds
Number of clients running queries: 100
Average number of queries per client: 1000

次は100クライアントで1000クエリにしてみました。
やはりこのようなケースは少ないですが、条件1と同じ方向性でさらに負荷をかけてみました。
やはりMySQL5.5の方が40%程度高いスコアが出ています。


条件3
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=3 --number-char-cols=5 --concurrency=500 --auto-generate-sql-write-number=100 --auto-generate-sql-execute-number=100 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 49.727 seconds
Minimum number of seconds to run all queries: 49.727 seconds
Maximum number of seconds to run all queries: 49.727 seconds
Number of clients running queries: 500
Average number of queries per client: 100

MySQL5.5
Average number of seconds to run all queries: 12.090 seconds
Minimum number of seconds to run all queries: 12.090 seconds
Maximum number of seconds to run all queries: 12.090 seconds
Number of clients running queries: 500
Average number of queries per client: 100

条件3では500クライアントで100クエリにしてみました。
条件1と2の少ないクライアントで多くのクエリという流れとは逆に多いクライアントで少ないクエリという方向性でテストしてみました。
クエリ総数は条件2の時の半分になっていますので、単純に条件2よりはいいスコアになるのではないかと推測していましたが、予想よりも早かったです。
特に条件2の時のMySQL5.5が72 sec -> 12 secということでスコアの伸びが、MySQL5.1側に比べて高くなっています。

条件4
$ mysqlslap --auto-generate-sql --auto-generate-sql-guid-primary -e innodb --number-int-cols=3 --number-char-cols=5 --concurrency=1000 --auto-generate-sql-write-number=30 --auto-generate-sql-execute-number=30 --auto-generate-sql-load-type=mixed --create-schema=test -h localhost -u root -p

MySQL5.1
Average number of seconds to run all queries: 82.359 seconds
Minimum number of seconds to run all queries: 82.359 seconds
Maximum number of seconds to run all queries: 82.359 seconds
Number of clients running queries: 1000
Average number of queries per client: 30

MySQL5.5
Average number of seconds to run all queries: 6.553 seconds
Minimum number of seconds to run all queries: 6.553 seconds
Maximum number of seconds to run all queries: 6.553 seconds
Number of clients running queries: 1000
Average number of queries per client: 30

条件3の結果を受けて、さらにクライアント数を増やし、クエリ数を減らす方向で実施してみました。
弊社のシステムではどちらかといえばクライアント数が多く、クエリ数は少なめになることが多いです。
そういう意味では実際の利用想定負荷パターンに少し近づいたといえます。
驚くことに、MySQL5.1と5.5でまったく逆の結果が得られました。
5.1は条件3に比べて総クエリ数は減っているのにも関わらず、処理時間は増えています。
5.5は条件3に比べて、処理時間が半分になっています(200%のスコア)。

中間報告
ここまでの結果からMySQL5.5は5.1に比べて全ての条件で高いスコアを出しています。
さらに特徴として5.5は多くのクライアントが存在するケースにおいて、5.1よりも高いスコアが出る傾向にあるようです。

さて、長くなってしまいましたので、今回は一旦ココまでとします。
次回「MySQL5.5のベンチマークテスト その2」では、さらに別の条件で5.1と5.5の性能の違いを見てみたいと思います。

2011年6月1日水曜日

blog開設

こんにちは、株式会社たゆたうのmatsuiです。

弊社は主にソーシャルゲームの開発・運用を行っています。
このブログでは、弊社のエンジニアが業務の中から得たノウハウなどを公開していきます。
よろしくお願いします。