kなんとかの日記 このページをアンテナに追加

2010-04-26

DI コンテナの起動が遅いなら、起動が速いのを作ればいいじゃない

| 08:39 |  DI コンテナの起動が遅いなら、起動が速いのを作ればいいじゃない - kなんとかの日記 を含むブックマーク

自分で書いたコメントなんだけど、今見るといいこと書いてあるように思うので、エントリにしてみる。3行でまとめると:

  • Spring の起動が遅いことと、DI コンテナの起動が遅い/速いというのは、別の話。
  • DI コンテナの起動が遅いなら、起動の速い DI コンテナを作ればいいだけであり、あれだけ推していたものを起動の遅さを理由に使わないのはおかしい。
  • DI の有用性は、App Engine に関係しない。App Engine で必要ないなら一般のアプリでも必要ないはず (でもそうじゃないよね)。

> DIを使うとspin-upが遅くなってしまうから使わない方が良いみたいです。Springとかはそれでかなり苦労してるらしいです。

うーん、どうでしょう?

「Spring の起動が遅い」ことと「DI コンテナの起動が遅い」ことは別の話ですよね?spin up time が問題なら起動の速い DI コンテナを作ればいいのであって、DI コンテナを捨てるのは間違った選択じゃないでしょうか。従来の DI コンテナが起動時にすべてのクラスをロードするようなアーキテクチャだから起動が遅いのだと推測しますが、だったらロードを遅延させるような DI コンテナを作ればいいだけの話です (ひがさんの実力なら難しいことでもないでしょう)。

少なくともあれだけ「DI はスバラシイ」と主張していた陣営が、こんなことを理由にあっさりと DI コンテナを捨てるというのは、なんというか不自然さを感じます。

> おそらくひがさんは、DIを使うメリットがなくて、それよりもデメリットの方が大きくなる(spin upの時間はとても大切)から「複雑になるだけ」という言い回しになったんじゃないかーと思います。

DI コンテナ導入の具体的なデメリットが spin up time のことしか言及されてないのですが、仮にデメリットがその点だとしても、それを「複雑になる」という表現はしないと思います。だから spin up time の問題とは別に、DI コンテナの導入が「複雑」だと表現したのだと思います。

> 実際使ってみるとappengine上でDIが必要になったケースは(自分で使ってる限りでは)ないですね。

なぜ App Engine だと DI コンテナを必要としないのか、その理由はぜひ知りたいですね。ひがさんが述べているように、テストのしやすさとトランザクションまわりが他の手段で代替できるからというのが理由なら、別に App Engine に限った話じゃないと思います。

まつもとさんも「DI コンテナは必要ない」と主張しているんですけど、それは Ruby のような動的な言語に限定した話であって、Java のような融通の利かない言語では DI なり AOP なりで柔軟性を持たせる必要があると思います。App Engine に関係なく。

2010-04-20 - kなんとかの日記

#しかしそこまでして Java にこだわるかね。spin up time でさんざん苦労するなら、Python 覚えた方がはやくね?

2010-04-20

App Engine で DI を使うメリットはない?

| 06:59 |  App Engine で DI を使うメリットはない? - kなんとかの日記 を含むブックマーク

DIの主なメリットは、テストのしやすさと宣言的トランザクションだと思いますが、AppEngineではモックなしで簡単にテストができ、Bigtableの仕様的に宣言的トランザクションはほとんど使えないので、AppEngineでDIを使うメリットは余りないんじゃないかと思います。単に複雑になるだけ。

これが、Slim3でDIをはずした理由です。

2009-11-15 - yvsu pron. yas

うーん、どうだろ。DI のメリットって、システムを疎結合にできることだと思うんだけど。疎結合にできるから、たとえばテストがしやすくなったりするわけで。疎結合にできるメリットは App Engine でもうれしいと思うけど、違うのかな。なんか他の意図があるような気もする。

それより、『単に複雑になるだけ』という言葉が気になる。やはり Java 屋さんにとっても、DI コンテナを使うのは複雑さが増すという認識なんですかね。『DI は簡単だ』という人もいれば『複雑だ』という人もいて、どちらも都合のいいときに都合のいい主張をしているだけのように見える。

あと『AppEngine』が正しいのか、それとも『App Engine』が正しいのか、非常に気になるんですけど、実際どっちが正しいんでしょうか。2ch のスレが『AppEngine』と『App Engine』とで分かれてて混乱するわ。

coolstylecoolstyle 2010/04/20 17:45 DIを使うとspin-upが遅くなってしまうから使わない方が良いみたいです。Springとかはそれでかなり苦労してるらしいです。

>DIが複雑なのか簡単なのか

おそらくひがさんは、DIを使うメリットがなくて、それよりもデメリットの方が大きくなる(spin upの時間はとても大切)から「複雑になるだけ」という言い回しになったんじゃないかーと思います。
実際使ってみるとappengine上でDIが必要になったケースは(自分で使ってる限りでは)ないですね。

kwatchkwatch 2010/04/20 20:31 > DIを使うとspin-upが遅くなってしまうから使わない方が良いみたいです。Springとかはそれでかなり苦労してるらしいです。

うーん、どうでしょう?
「Spring の起動が遅い」ことと「DI コンテナの起動が遅い」ことは別の話ですよね?spin up time が問題なら起動の速い DI コンテナを作ればいいのであって、DI コンテナを捨てるのは間違った選択じゃないでしょうか。従来の DI コンテナが起動時にすべてのクラスをロードするようなアーキテクチャだから起動が遅いのだと推測しますが、だったらロードを遅延させるような DI コンテナを作ればいいだけの話です (ひがさんの実力なら難しいことでもないでしょう)。
少なくともあれだけ「DI はスバラシイ」と主張していた陣営が、こんなことを理由にあっさりと DI コンテナを捨てるというのは、なんというか不自然さを感じます。

> おそらくひがさんは、DIを使うメリットがなくて、それよりもデメリットの方が大きくなる(spin upの時間はとても大切)から「複雑になるだけ」という言い回しになったんじゃないかーと思います。

DI コンテナ導入の具体的なデメリットが spin up time のことしか言及されてないのですが、仮にデメリットがその点だとしても、それを「複雑になる」という表現はしないと思います。だから spin up time の問題とは別に、DI コンテナの導入が「複雑」だと表現したのだと思います。

> 実際使ってみるとappengine上でDIが必要になったケースは(自分で使ってる限りでは)ないですね。

なぜ App Engine だと DI コンテナを必要としないのか、その理由はぜひ知りたいですね。ひがさんが述べているように、テストのしやすさとトランザクションまわりが他の手段で代替できるからというのが理由なら、別に App Engine に限った話じゃないと思います。

まつもとさんも「DI コンテナは必要ない」と主張しているんですけど、それは Ruby のような動的な言語に限定した話であって、Java のような融通の利かない言語では DI なり AOP なりで柔軟性を持たせる必要があると思います。App Engine に関係なく。

2010-04-18

Google App Engine で Java を使うと起動時間が数秒もかかるらしい

| 07:11 |  Google App Engine で Java を使うと起動時間が数秒もかかるらしい - kなんとかの日記 を含むブックマーク

 上記3つの対策を施し、詳細は省略しますが約50回の起動で、最小3693ms、最大14303ms、平均6884msとなりました。対策前(平均8895ms)と比較すると2000ms程度の改善です

GAE/J、起動時間(spin up時間)短縮の試行錯誤 : CB NANASHI管理人ブログ

これ、まじなのか。『平均6884ms』って、つまり起動に6.8秒もかかるってことだよね。

Google App EngineJava を使うと、起動するのに平均で約7秒、最大で14秒もかかるのか。これはひどい

この上でさらに JRuby + Rails を動かしてる人たちはすごいな。尊敬はするけど、真似しようという気にはならない。


ところで実際にサイトにアクセスしてみたが、数秒も待たされることは全然なくて、さくさく表示された。比較的アクセスがあるサイトなら、起動時間はあまり考えなくてもいいということかな。

kwatchkwatch 2010/04/19 13:59 > この時間は、デプロイ後にアプリケーションにアクセスできるようになるまで(spin up)の時間じゃないですかねー。

別にデプロイはさほど関係ないと思いますよ。「appengine spin up」でぐぐればわかると思いますが、たとえばこちらの説明をどうぞ。
http://d.hatena.ne.jp/higayasuo/20091115

> 例えば、最近、App Engineで問題になっているのは、spin upの時間です。
> spin upというのは、アプリケーションを起動することです。これまでの
> 常識だと、アプリケーションの起動時に多少時間をかけてもリクエストの
> 処理が早くなるなら、そっちのほうが優先されてきました。
>
> しかし、App Engineでは、負荷の状況にもよりますが、2,3分アクセスが
> ないと直ぐにアプリケーションがspin downされ、次のアクセスでspin up
> されてしまいます。spin up(アプリケーションの起動)に時間がかかる
> フレームワークは、App Engineには向いていません。
>
> また、起動に時間がかかるとかなりCPU時間を消費するので、貴重な
> リソースを消費(課金にもつながる)してしまい踏んだりけったりです。

kwatchkwatch 2010/04/19 14:44 あれ、元コメントが消えてる?間違って消してしまった?もしそうならごめんなさい>元コメント主

2010-04-15

Google App Engine ではプログラムから static ファイルを読みこめない

| 07:52 |  Google App Engine ではプログラムから static ファイルを読みこめない - kなんとかの日記 を含むブックマーク

Google App Engine で、スクリプトから画像ファイルの一覧を取り出そうとしたけど、できなくてはまった。

helloworld.py

# -*- coding: utf-8 -*-
import os, glob
print "Content-Type: text/plain"
print ""
print "hello"
imgdir = os.path.join(os.path.dirname(__file__), 'img')
for x in glob.glob(imgdir + '/*'):
    print x     #=> 何も表示されない

print open(imgdir + '/favicon.ico')
   #=> IOError: [Errno 13] file not accessible

ドキュメントによれば、ファイルへの書き込みはできなくても読み込みはできるはずなんだけど。

アプリケーションは、ファイル システムへの書き込みはできません。ファイルの読み取りはできますが、アプリケーション コードとともにアップロードされたファイルのみに限られます。

Error 404 (Not Found)!!1

と思ってたら、こんな投稿が。

You can read files that weren't marked as static resources, in the regular fashion.

Google グループ

どうも、static ファイルとして設定したファイルは、スクリプトから読み出せないようだ。

application: helloworld
version: 1
runtime: python
api_version: 1

handlers:
  - url: /css
    static_dir: css
  - url: /js
    static_dir: js
  - url: /img
    static_dir: img     # 'img' 以下は static ファイルとして指定
  - url: /.*
    script: helloworld.py

つまり、static ファイルとそうでないファイルとでは、そもそもファイルの配置場所が違うんだろうな。だからスクリプトからは static ファイルが簡単には読み出せないんだろう。


ところでこの制限は公式のドキュメントに書かれてあるんだろうか。ご存知の方がいましたら教えてください。

2010-04-11

はじめての Kay Framework 体験記

| 07:44 |  はじめての Kay Framework 体験記 - kなんとかの日記 を含むブックマーク

Google App Engine 専用フレームワークというふれこみの『Kay』を試してみる。

なお環境は Mac OS X 10.6、Python 2.6.2 (自前コンパイル)、GAE SDK 1.3.2。


ダウンロードと解凍

プロジェクトの Web サイトからダウンロードして解凍。

$ cd /tmp
$ wget http://kay-framework.googlecode.com/files/kay-0.8.0.tar.gz
$ tar xzf kay-0.8.0.tar.gz
$ ls -F Kay-0.8.0
.hg_archival.txt        RELEASE_NOTES           kay/
.hgignore               TODO                    manage.py
.hgtags                 app.yaml                settings.py
AUTHORS                 cron.yaml.sample        urls.py
LICENSE                 docs/
README                  favicon.ico

とりあえず行数を数えてみる。

$ find Kay-0.8.0 -type f | xargs wc | tail -1
   89294  382125 7583671 total

8万9千行!! 何かの冗談か?

どのファイルが大きいのか調べてみる。

$ find Kay-0.8.0 -type f | xargs wc | sort -nr | head -11
   89294  382125 7583671 total
    3845   11783  125396 Kay-0.8.0/kay/management/gae_bulkloader.py
    2329    8571   76128 Kay-0.8.0/kay/lib/simplejson/_speedups.c
    2320    8134   75771 Kay-0.8.0/kay/lib/werkzeug/datastructures.py
    2220    6979   65886 Kay-0.8.0/kay/utils/forms/__init__.py
    1549    5135   57546 Kay-0.8.0/kay/lib/jinja2/compiler.py
    1484    6814   63444 Kay-0.8.0/kay/lib/werkzeug/wrappers.py
    1477    2461   33172 Kay-0.8.0/kay/lib/pytz/__init__.py
    1390    5512   53304 Kay-0.8.0/kay/lib/werkzeug/routing.py
    1387   11531  494228 Kay-0.8.0/kay/lib/pytz/zoneinfo.zip
    1201    3660   49756 Kay-0.8.0/kay/lib/babel/messages/frontend.py

うーん、1000行以上のファイルがごろごろしているなあ。どうも lib/ 以下に重量級ライブラリが存在しているようだ。

$ ls  Kay-0.8.0/kay/lib | cat
babel/             # 国際化(i18n)用ライブラリ
debug/             # ?
jinja2/            # テンプレートエンジン
pytz/              # タイムゾーン用ライブラリ
simplejson/        # JSON ライブラリ
werkzeug/          # WSGI 用便利ライブラリ集(?)

simplejson って Python 標準添付じゃなかったっけ。。。と思ったら、標準添付なのは 2.6 からで、GAE が使っている 2.5 では標準添付じゃなかった。

ライブラリ個別に行数を数えてみる。

$  (cd Kay-0.8.0/kay/lib/; for x in *; do printf '%12s' $x; find $x -type f | xargs wc | tail -1; done)
       babel   24627  158907 4127073 total
       debug     166     550    5668 total
      jinja2    9617   32678  731434 total
        pytz    3551   16596  550724 total
  simplejson    4211   15183  141240 total
    werkzeug   16809   63170  667749 total

大きいなあ。どれも有名どころのライブラリなんだろうけど、コンパクトさにはまるで欠ける。

軽快さを求めて Python を使っているのに、これじゃまるで Java だ。

プロジェクトの作成

気を取り直して、チュートリアルをやってみる。

まずはプロジェクトの作成。

## SDK が /usr/local/google_appengine にないとエラーになる
$ python kay-0.8.0/manage.py startproject myproject
The Google App Engine SDK could not be found!
Please visit http://kay-docs.shehas.net/ for installation instructions.
## 仕方ないのでシンボリックリンクを張る
$ sudo ln -s $HOME/tmp/google_appengine /usr/local 

SDK が /usr/local/google_appengine にないとエラーになるようだ。でもこの決めうちは柔軟性に欠ける。$JAVA_HOME にならって、$GAE_HOME を設定してもらうようにしたほうがいいんじゃないだろうか。

## コマンドを再度実行
$ python kay-0.8.0/manage.py startproject myproject
/private/tmp/google_appengine/google/appengine/ext/remote_api/remote_api_stub.py:64: DeprecationWarning: the sha module is deprecated; use the hashlib module instead
  import sha
/private/tmp/google_appengine/google/appengine/tools/dev_appserver_login.py:33: DeprecationWarning: the md5 module is deprecated; use hashlib instead
  import md5
/private/tmp/kay-0.8.0/kay/lib/jinja2/__init__.py:31: UserWarning: Module yaml was already imported from /private/tmp/google_appengine/lib/yaml/lib/yaml/__init__.pyc, but /usr/local/python/2.6.2/lib/python2.6/site-packages/PyYAML-3.09-py2.6-macosx-10.6-i386.egg is being added to sys.path
  __version__ = __import__('pkg_resources') \
/private/tmp/kay-0.8.0/kay/lib/jinja2/__init__.py:31: UserWarning: Module jinja2 was already imported from /private/tmp/kay-0.8.0/kay/lib/jinja2/__init__.py, but /usr/local/python/2.6.2/lib/python2.6/site-packages/Jinja2-2.2.1-py2.6.egg is being added to sys.path
  __version__ = __import__('pkg_resources') \
/private/tmp/kay-0.8.0/kay/lib/jinja2/__init__.py:31: UserWarning: Module werkzeug was already imported from /private/tmp/kay-0.8.0/kay/lib/werkzeug/__init__.py, but /usr/local/python/2.6.2/lib/python2.6/site-packages/Werkzeug-0.6-py2.6.egg is being added to sys.path
  __version__ = __import__('pkg_resources') \
Finished creating new project: myproject.
$ ls -F myproject
app.yaml        kay@            settings.py
favicon.ico     manage.py@      urls.py

なんか警告がでた。最初の 2 つは、Python 2.6 で deprecated になったモジュール (sha と md5) を GAE SDK が使っていることによる警告。あとの 3 つは Kay のライブラリによるもので、システムの中にすでに PyYAML や Jinja2 がインストール済みだと警告がでるようだ (えー?!)。

アプリケーションの作成

気を取り直して、続き。myproject/ の下に、新しくアプリケーション (myapp) を作成する。

$ cd myproject/
$ python manage.py startapp myapp
Running on Kay-0.8.0
...(先ほどと同じように警告がでるので省略)...
$ ls -R
app.yaml        kay@            myapp/          settings.pyc
favicon.ico     manage.py@      settings.py     urls.py

./myapp:
__init__.py     models.py       templates/      urls.py         views.py

./myapp/templates:
index.html

settings.py を編集し、INSTALLED_APPS と APP_MOUNT_POINTS を変更する。

$ vi settings.py
$ cat settings.py
...(snip)...
INSTALLED_APPS = (
    'kay.auth',
    'myapp',
)

APP_MOUNT_POINTS = {
    'myapp': '/',
}
...(snip)...

開発用サーバの起動

開発サーバを起動する。ポート番号の指定方法がわからなかったので、ヘルプで調べている。

$ python manage.py -h | less
$ python manage.py runserver --help | less
$ python manage.py runserver -p 8082
...(snip)...
INFO     2010-04-10 12:22:22,466 dev_appserver_main.py:399] Running application myproject on port 8082: http://localhost:8082

さあ準備はできた。ここまで出来たら、ブラウザで http://localhost:8082/ にアクセスしてみる。

以下がその実行結果だ!


Traceback (most recent call last):
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 3185, in _HandleRequest
    self._Dispatch(dispatcher, self.rfile, outfile, env_dict)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 3128, in _Dispatch
    base_env_dict=env_dict)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 515, in Dispatch
    base_env_dict=base_env_dict)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 2387, in Dispatch
    self._module_dict)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 2297, in ExecuteCGI
    reset_modules = exec_script(handler_path, cgi_path, hook)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 2188, in ExecuteOrImportScript
    handler_path, cgi_path, import_hook)
  File "/private/tmp/google_appengine/google/appengine/tools/dev_appserver.py", line 2102, in LoadTargetModule
    module_fullname, import_error_message)
  File "/usr/local/python/2.6.2/lib/python2.6/logging/__init__.py", line 1433, in exception
    error(*((msg,)+args), **{'exc_info': 1})
  File "/usr/local/python/2.6.2/lib/python2.6/logging/__init__.py", line 1426, in error
    root.error(*((msg,)+args), **kwargs)
  File "/usr/local/python/2.6.2/lib/python2.6/logging/__init__.py", line 1056, in error
    self._log(ERROR, msg, args, **kwargs)
....(snip)....
  File "/usr/local/python/2.6.2/lib/python2.6/posixpath.py", line 95, in splitext
    return genericpath._splitext(p, sep, altsep, extsep)
  File "/usr/local/python/2.6.2/lib/python2.6/genericpath.py", line 101, in _splitext
    if p[filenameIndex] != extsep:
RuntimeError: maximum recursion depth exceeded in cmp

・・・再帰がネストしすぎてエラーになってるorz。

原因を自分で追求するほどの気力はないので、はじめての Kay 体験記はここで終了。

まとめ

Google App Engine 専用というふれこみの『Kay』フレームワーク。しかし実際に試してみると、エラーが出て先に進めないという残念な結果になった。作者さんの環境ではうまく動くと思われるので、環境依存の部分が多分にあるのだろう。

気になった点:

  • SDK を /usr/local/google_appengine に置くというのが決めうちなら、ちょっと格好悪い。$GAE_HOME のような環境変数を設定するほうがよさそう。
  • すでに Jinja2 や PyYAML がシステムにインストールされてあると警告がでるのはなんとかしてほしい。
  • Rails では Rake という便利コマンドがあるけど、それに相当するものはなさそう。manage.py は違うっぽいし。
  • ファイル数やファイルサイズが大きすぎる。なるべく import を遅延させるよう工夫したとしても、これだけ大きいと焼け石に水のように思う。
  • 結局、Kay 自体は GAE 専用に作られているんだろうけど、GAE 用には作られてないライブラリを多数抱え込んでいるので、どうしようもない気がする。

今日の結論: やっぱ webapp でいいや。

SurgoSurgo 2010/04/11 10:21 なぜ Python 2.6 で動かしているのでしょうか・・・?

kwatchkwatch 2010/04/12 08:38 深い理由は特にないです。強いて言えば、2.5.x が Snow Leopard でコンパイルできなかったことぐらいです。
#それとも質問の意図は別にあります?

aodagaodag 2010/04/12 09:23 virtualenvを使ってみてください。

kwatchkwatch 2010/04/13 07:53 ん?virtualenvを使うと、SnowLeopardでも2.5がコンパイルできるようになるんでしょうか。