札幌Javaコミュニティ第24回勉強会に参加しました

あんまり他の人と話はできなかったけど、純粋にテーマと発表が為になりました。
@shuji_w6eさんと@quicyさんありがとうございました!

GAE/Jについて(@shuji_w6eさん)

spin-up、spin-downについて
spin-up
アプリケーションの起動にかかる処理のこと。インスタンスの起動時間。何も考えずに作ると結構時間がかかる。
spin-down
Google App Engineでは1分以上リクエストがないと強制的にインスタンスが終了する。Googleのサーバのリソースの円滑な割り当てを行うため。

ある程度大きいサービスを提供する場合、随時人がアクセスしリクエスト発生するためspin-upにかかる時間をそれほど考えなくてよいが、
あまりアクセスされないサービスの場合や、人の少ない深夜であったりすると結構spin-upにより待たされてしまい印象が悪くなってしまう。

それを解決するため、1分に一回自分のcloneを叩くという手もあるが、それはGoogleにより非推奨とされている。
そこで、いかにspin-upに負けないアプリケーションを作るかが鍵となってくる。

spin-up時間が短ければ、いくらspin-downされても大丈夫
  • 遅いアプリケーションを後から速くするのは難しい。最初から遅くしない設計にする。
  • 早い段階からローカルではなく、Googleのサーバ上で実測するとよい
  • slim3を使いましょう。spin-upが2秒切る
  • Google「お金を払えば速くするよ(^q^)」
Google App Engineの性質
  • 業務ではあまり使えない
  • 純粋に面白い
  • ノウハウは業務で活きる
  • 開拓し甲斐のある場所
  • CPUは一昔前のパソコン(Celeron)くらいか。ローカルでは速くてもサーバではどうか。
  • シンプルさが最重要
spin-up対策
  • ロードされるクラスの数を減らす。少なければ少ないほどよい。
  • ロードされるタイミングを分散する
  • クラスのロード時間→速くできない!どうにもできない!
  • 外部ライブラリ→なるべく使わない
  • Datastoreにキャッシュする
  • 初期化処理は最小限に!
  • 生のサーブレットを使う or slim3を使う。規模が大きくなってくると生のサーブレットではキツいのでslim3にしよう
  • 初期化処理時間よりクラスロード時間に注意
  • jarがあるだけでは影響なし
フレームワークの選択

→ slim3の方が本番に近いテストを行いやすい。クラスロードのイニシャルコストもかかる。

→ java.util.loggerで十分

→ spin-downしない前提で・・・

→ spin-upが500ms-800msくらい。実用できるかも?



初期化対策

(1)遅延初期化
  • 必要な時に初期化。クラスロードさせない
  • 特にMail,TaskQueue、Memcache API等は初期化コスト高いのでなるべく使わないようにする
  • 初期化処理では全部Datastore APIのみを使うとよい
(2)手動で初期化
  • 管理画面から手動実行
  • デプロイ後に1回やれば良い場合はそうする(初期データ投入など)
  • TaskQueueを活用→サイト構成の再構築処理
(3)そもそも初期化しない
  • 初期化コストとのトレードオフ
  • キャッシュは毎回Datastoreから取得(適切な自然キーを入れておく)
  • Memcacheも結局内部でDatastoreを使ってるし、初期化コスト結構高いので注意
slim3について
  • 1Action=1Controller class
  • URLからコントローラをリフレクションで生成
  • 初期化時にクラスがロードされない
  • クラス数が多くなる
  • リクエストパスの変更などがやや面倒
設計について
  • 静的なページ

→ html自体ををキャッシュして返す

  • 動的なコンテンツ

→ テンプレートエンジン→パース→オブジェクト返却

SWT/JFaceについて(@quicyさん)

Swingとの違い
  • Swingでいうペインはないが、コンポジットを使う
  • Swingとは逆で、ウィジェットを作る際にはコンストラクタに親を渡す設計(親は必ず必要)
  • Image、Font、Colorについては明示的なリソースの破棄が必要なので注意
作ったサンプルの一例

f:id:voidy21:20100522194458p:image

package org.hoge;

import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.layout.*;
import org.eclipse.swt.widgets.*;
import org.eclipse.swt.*;

public class SWTTest {
	public static void main(String[] args) {
		Display display = new Display();
		
		Shell shell = new Shell(display);
		shell.setText("たいとる");
		shell.setLayout(new FillLayout());
		
		Text text = new Text(shell,SWT.BORDER|SWT.MULTI);
		text.setText("てきすと");
		
		Button button = new Button(shell,SWT.NONE);
		button.setText("ぼたん");
		button.addSelectionListener(new SelectionListener() {

			@Override
			public void widgetDefaultSelected(SelectionEvent arg0) {
				
			}

			@Override
			public void widgetSelected(SelectionEvent arg0) {
				System.out.println("おされた");
			}
			
		});
		
		shell.open();
		
		//ウインドウが閉じられてなかったら
		while(!shell.isDisposed()){
			if(!display.readAndDispatch()){
				display.sleep();
			}
		}
	}
}

f:id:voidy21:20100522194459p:image

package org.jface;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.window.ApplicationWindow;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;

public class MyWindow extends ApplicationWindow {

	public static void main(String[] args){
	        MyWindow mw = new MyWindow(null);
		mw.open();
	}
	
	public MyWindow(Shell parentShell) {
		super(parentShell);
		this.setBlockOnOpen(true);//開いたら閉じないでブロック
		
		addMenuBar();
	}

	@Override
	protected void configureShell(Shell shell) {
		// TODO Auto-generated method stub
		super.configureShell(shell);
		shell.setText("たいとる");
	}

	@Override
	protected Point getInitialSize() {
		// TODO Auto-generated method stub
		return new Point(100,100);
	}

	@Override
	protected Control createContents(Composite parent) {
		Composite client = new Composite(parent,SWT.None);
		client.setLayout(new FillLayout());
		Text text = new Text(client,SWT.BORDER|SWT.MULTI);
		text.setText("てきすと");

		return text;
	}

	@Override
	protected MenuManager createMenuManager() {
		MenuManager root = new MenuManager("root");
		MenuManager mm = new MenuManager("ふぁいる");
		
		root.add(mm);
		mm.add(new Action("開く"){
			@Override
			public void run(){
				MessageDialog.openQuestion(getShell(), "test", "message");
			}
			
		});
		return root;
	}

}