<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/rss2full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><rss xmlns:atom="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" version="2.0"><channel><atom:id>tag:blogger.com,1999:blog-5592148</atom:id><lastBuildDate>Thu, 01 Mar 2012 14:24:38 +0000</lastBuildDate><category>App Engine</category><category>Python</category><category>Development</category><category>Tests</category><category>書籍</category><category>Eclipse</category><category>Mac</category><category>Career</category><category>Presentation</category><category>LabVIEW</category><category>ActionPad</category><category>Mercurial</category><category>Lifehack</category><category>Triathlon</category><title>Even More Addicted to Indentation</title><description /><link>http://torufurukawa.blogspot.com/</link><managingEditor>noreply@blogger.com (Toru Furukawa)</managingEditor><generator>Blogger</generator><openSearch:totalResults>513</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/rss+xml" href="http://feeds.feedburner.com/EvenMoreAddictedToIndentation" /><feedburner:info uri="evenmoreaddictedtoindentation" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><feedburner:browserFriendly></feedburner:browserFriendly><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-5437073118782707569</guid><pubDate>Sun, 15 Jan 2012 10:44:00 +0000</pubDate><atom:updated>2012-01-15T22:27:34.336+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Tests</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>mock で外部依存なくしてユニットテストする例</title><description>&lt;p&gt;mock を使ったニットテストの、シンプルなシーンをまとめました。例として「Twitter アカウントのスクリーンネームを指定し、そのアカウントの最新のツイートの内容を取得する」という機能を実装する場合を考えます。&lt;/p&gt;

&lt;div style="font-size: large;"&gt;外部に依存しない機能のテスト&lt;/div&gt;

&lt;p&gt;まず、簡単にユニットテストを書けるような場合から考えます。create_user_timeline_url() 関数を定義し、Twitter アカウントの screen_name を渡すと、そのアカウントのつぶやきを取得するために URL が返される、としましょう。たとえば Twitter アカウントのスクリーンネーム wozozo を渡すと、 http://twitter.com/statuses/user_timeline/wozozo.json が返ってくることを確認します。&lt;/p&gt;

&lt;p&gt;実装とテストは以下のようになります。URL のテンプレートを定数にしたほうがいいとかありますが、そこは、やっつけです。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# tw.py
def create_user_timeline_url(screen_name):
    """return URL to get screen_name user's timeline"""
    base = "http://twitter.com/statuses/user_timeline/%s.json"
    return base % screen_name
&lt;/pre&gt;

&lt;pre class="prettyprint"&gt;
# tests.py
import unittest
import tw

class CreateUserTimelineUrlTest(unittest.TestCase):
    def test(self):
        result = tw.create_user_timeline_url('wozozo')
        expected = 'http://twitter.com/statuses/user_timeline/wozozo.json'
        self.assertEqual(result, expected)
&lt;/pre&gt;

&lt;p&gt;ユニットテストは「外部に依存させずに、既知の入力に対して、期待する出力が得られることを確認する」ことを確認する、ということなので、上記でユニットテストができています。&lt;/p&gt;

&lt;div style="font-size: large;"&gt;外部に依存する機能のテスト&lt;/div&gt;

&lt;p&gt;続いて get_latest_tweet_text(screen_name) という関数を作ります。これは screen_name を与えると、そのアカウントの最新のツイートのテキストを返してくれる関数です。たとえばユーザ wozozo が、最後に「show!」とツイッターで発言していれば、この関数は文字列「show!」を返します。機能の実装と、テストはこんな感じでしょうか。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# tw.py
import urllib
import json

def get_latest_tweet_text(screen_name):
    """return latest tweet message by screen_name user"""
    url = create_user_timeline_url(screen_name)
    fin = urllib.urlopen(url)
    content = fin.read()
    content_obj= json.loads(content)
    return content_obj[0]['text']

...
&lt;/pre&gt;

&lt;pre class="prettyprint"&gt;
# tests.py
import unittests

class GetLatestTweetTextTest(unittest.TestCase):
    def test(self):
        text = tw.get_latest_tweet_text('wozozo')
        self.assertEqual(text, 'show!')
&lt;/pre&gt;

&lt;p&gt;いろいろと問題があります。そもそも wozozo ユーザが最後に show! とつぶやいていないと、確実に破綻します。なので、テストが想定している状況を作り出す必要があります。&lt;/p&gt;

&lt;p&gt;だからと言って setUp でいちいち「show!」とつぶやいてからテストするのは、あまりに外部に依存しすぎです。Twitter が落ちていたらテストできないからです。また、テスト項目が大量にあったら、ものすごい勢いで API をコールするわけで、IP アドレスからのアクセスの制限に引っかかります。OAuth が必要な機能を使っていたらアプリやアカウント停止されられるかもです。ですので外部に依存しないようにしたい。&lt;/p&gt;

&lt;p&gt;（1件もつぶやいていない場合はエラーがでますが、別の問題なので、今は依存にだけ集中します）&lt;/p&gt;

&lt;p&gt;get_latest_tweet_text の依存先は、&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tw.create_user_timeline_url() 関数&lt;/li&gt;
&lt;li&gt;urllib.urlopen() および、そこで発生する通信&lt;/li&gt;
&lt;li&gt;json.loads() 関数&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;の、3つです。&lt;/p&gt;
&lt;p&gt;2つ目の urlopen() は、すでに述べた理由から、ユニットテストでの依存を断ち切りたい箇所です。&lt;/p&gt;
&lt;p&gt;3つ目の json.loads() は標準ライブラリの関数です。バグがないという保証ありませんが、Python のパッケージのテストを通っていることを考えると確率としては非常に低いでしょう。この部分は、正常に動作する Python の機能だと考えます。&lt;/p&gt;

&lt;p&gt;問題は1 つめです。正直なところ、こういう関数への依存を切り離すかどうか迷っています。比較的シンプルな関数なので、いちいちモックとか作るのかよ、という気分になります。なりますが、ここはユニットテストでは依存させない箇所として扱います。よりどころにしているのは、 Daniel Arbuckle の「Python Testing Beginner's Guide」です。&lt;/p&gt;

&lt;blockquote&gt;
&lt;pre&gt;
class testable:
    […]
    def method3(self, number):
        return self.method1(number) * self.method2(number)
    def method4(self):
        return 1.713 * self.method3(id(self))

[…]
&lt;/pre&gt;

Consider method4.  Its result depends on all of the other methods working correctly.  On top of that, it depends on something that changes from one test run to another, the unique ID of the self object.  Is it even possible to treat method4 as a unit in a self-contained test? If we could change anything except method4, what would we have to change to enable method4 to run in a self-contained test and produce a predictable result?
&lt;/blockquote&gt;

（超訳: method4 の結果の正しさは、他のメソッドがすべて正しく動作することに依存している。それに加えて、self のユニークな ID を取得するなどという、テストごとに値が変わるようなものにも依存している。そんな状況で method4 を自己完結しているものとしてテストできるだろうか？ method4 以外に変更を加えたときに、method4 のテストがとおり、かつ、予想できる結果を得られるようにするには、どうしたらいい？）

&lt;p&gt;create_user_timeline_url() の処理はシンプルですが、標準ライブラリよりはバグ率が高いでしょう。また Twitter の都合で URL が変わるかも知れません。そう考えると、create_user_timeline_url を本当に呼び出さずに、この関数の戻り値が既知の入力であるかのようにテストをしたくなってきます。&lt;/p&gt;

&lt;p&gt;というわけで create_user_timeline_url と urllib.urlopen をモックにします。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# tests.py
import unittest
import mock
import tw

class GetLatestTweetTextTest(unittest.TestCase):
    @mock.patch('urllib.urlopen')
    @mock.patch('tw.create_user_timeline_url')
    def test(self, create, urlopen):
        # mock create_user_timeline_url
        url = 'http://example.com/wozozo'
        create.return_value = url
        # mock URL reader
        fin = mock.Mock()
        fin.read.return_value = '[{"text":"show!"}, {"text":"tenga"}]'
        # and set it to urlopen's return value
        urlopen.return_value = fin
        # call UUT function
        text = tw.get_latest_tweet_text('wozozo')
        # assert returned text
        self.assertEqual(text, 'show!')
        # assert 'bucho' is passed to create func once
        self.assertEqual(create.call_count, 1)
        self.assertEqual(create.call_args, (('wozozo',), {}))
        # assert URL from create func is passed to urlopen once
        self.assertEqual(urlopen.call_count, 1)
        self.assertEqual(urlopen.call_args, ((url,), {}))
        # assert urlopen().read() is called once w/o args
        self.assertEqual(fin.read.call_count, 1)
        self.assertEqual(fin.read.call_args, ((), {}))

...
&lt;/pre&gt;

&lt;p&gt;順番に見ていきま show。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
class GetLatestTweetTextTest(unittest.TestCase):
    @mock.patch('urllib.urlopen')
    @mock.patch('tw.create_user_timeline_url')
    def test(self, create, urlopen):
&lt;/pre&gt;

&lt;p&gt;tw.create_user_timeline_url, urllib.urlopen を mock.Mock オブジェクトと入れ替えます。そして、このtest メソッドの中では、それぞれ create、 url_open という名前でモックにアクセスできます。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # mock create_user_timeline_url
        url = 'http://example.com/wozozo'
        create.return_value = url
&lt;/pre&gt;

&lt;p&gt;create_user_timeline_url 関数の戻り値を定数で指定しておきます。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # mock URL reader
        fin = mock.Mock()
        fin.read.return_value = '[{"text":"show!"}, {"text":"tenga"}]'
&lt;/pre&gt;

&lt;p&gt;urlopen() は本来 file-like オブジェクトを返し、これが裏側で通信します。通信させたくないので、Mock を作ります。そして、read() メソッドの戻り値を指定しておきます。本当は、もうちょっと本物のレスポンスに似せたほうがいいかも知れません。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # and set it to urlopen's return value
        urlopen.return_value = fin
&lt;/pre&gt;

&lt;p&gt;それを urlopen() の戻り値で返されるようにします。これで、urllib.urlopen() は、上で定義した fin が返るようになります。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # call UUT function
        text = tw.get_latest_tweet_text('wozozo')
&lt;/pre&gt;

&lt;p&gt;で、テスト対象の関数を呼び出します。以下、入出力の確認です。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # assert returned text
        self.assertEqual(text, 'show!')
&lt;/pre&gt;

&lt;p&gt;まず、戻り値の確認。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # assert 'bucho' is passed to create func once
        self.assertEqual(create.call_count, 1)
        self.assertEqual(create.call_args, (('wozozo',), {}))
&lt;/pre&gt;

&lt;p&gt;create_user_timeline_url('wozozo') が1度だけ実行されていることを確認します。そして、このときの戻り値が...&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # assert URL from create func is passed to urlopen once
        self.assertEqual(urlopen.call_count, 1)
        self.assertEqual(urlopen.call_args, ((url,), {}))
&lt;/pre&gt;

&lt;p&gt;urlopen() の引数に使われていることを確認。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
        # assert urlopen().read() is called once w/o args
        self.assertEqual(fin.read.call_count, 1)
        self.assertEqual(fin.read.call_args, ((), {}))
&lt;/pre&gt;

&lt;p&gt;最後に read() メソッドが引数なしで呼ばれていることを確認して、おわり。&lt;/p&gt;


&lt;p&gt;urlopen() など依存先の関数/メソッド呼び出しというのはテスト対象関数からの「出力」なので assert でテストしています。そして、それらの戻り値というのは、テスト対象関数への「入力」なのでモックで既知の値を渡しています。こうすれば「外部に依存させずに、既知の入力に対して、期待する出力が得られることを確認する」というユニットテストができることになります。&lt;/p&gt;

&lt;div style="font-size: large;"&gt;まとめ&lt;/div&gt;

&lt;p&gt;以上、外部依存する部分を mock で入れ替えるシーンを、書いてみました。シーンとしてはシンプルなんですが、煩雑に思えるかも知れません。どこまでを外部とするのか、というのは未だに課題です。通信するとか、開発中の比較的大きな別モジュールとかは、外部扱いにしています。&lt;/p&gt;


&lt;iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;bc1=000000&amp;IS2=1&amp;bg1=FFFFFF&amp;fc1=000000&amp;lc1=0000FF&amp;t=addicted2inde-22&amp;o=9&amp;p=8&amp;l=as4&amp;m=amazon&amp;f=ifr&amp;ref=ss_til&amp;asins=1847198848" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"&gt;&lt;/iframe&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-5437073118782707569?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2012/01/mock.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-8122019646703188059</guid><pubDate>Sat, 07 Jan 2012 03:23:00 +0000</pubDate><atom:updated>2012-01-07T12:23:37.348+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Google App Engine の開発サーバで pdb.set_trace() を使う</title><description>&lt;p&gt;Google App Engine で開発していて、標準デバッガの pdb を使おうとして困ったのでその顛末のメモです。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
import pdb; pdb.set_trace() 
&lt;/pre&gt;

&lt;p&gt;と書いても、期待通りに動作しません。stdin と stdout の向き先が変わっているので、画面への表示とキーボードからの入力ができないのだと思います。&lt;/p&gt;

&lt;p&gt;有用な&lt;a href="http://jjinux.blogspot.com/2008/05/python-debugging-google-app-engine-apps.html?showComment=1215024240000#c3791312023634236304"&gt;ブログのコメント&lt;/a&gt;を見つけましたので、そのままパクり。&lt;/p&gt;

&lt;p&gt;gaedb.py というファイルを作っておきます。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
# gaedb.py
def set_trace():
    import pdb, sys
    debugger = pdb.Pdb(stdin=sys.__stdin__,
        stdout=sys.__stdout__)
    debugger.set_trace(sys._getframe().f_back)
&lt;/pre&gt;

&lt;p&gt;で、アプリケーションコード内で、&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
import gaedb; gaedb.set_trace()
&lt;/pre&gt;

&lt;p&gt;と書けば、期待通りの pdb.set_trace() 動作します。ちゃんちゃん。&lt;p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-8122019646703188059?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2012/01/google-app-engine-pdbsettrace.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-968104597852161196</guid><pubDate>Sun, 01 Jan 2012 08:16:00 +0000</pubDate><atom:updated>2012-01-01T17:16:18.710+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Mercurial</category><title>Mercurial の Case Folding Collision を修復する</title><description>&lt;p&gt;調子にのって Makefile を書いていたら、平行しているブランチで makefile と Makefile を作るという失態です。ほんとうに、あけましておめでとうございます。&lt;/p&gt;

&lt;p&gt;結論から言うと、&lt;a href="http://www.softwareprojects.com/resources/programming/t-how-to-fix-mercurial-case-folding-collision-1937.html"&gt;How to fix Mercurial Case Folding Collision&lt;/a&gt;で解決しました。以下、個人的なメモです。&lt;/p&gt;

&lt;h1&gt;問題の再現方法&lt;/h1&gt;

&lt;p&gt;ベースになるリポジトリを作る。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
$ hg init foo
$ cd foo
$ touch foo.c
$ hg add
adding foo.c
$ hg commit -m "foo.c"
&lt;/pre&gt;

&lt;p&gt;小文字の「makefile」を持つブランチを作る。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
$ hg branch low
marked working directory as branch low
$ touch makefile
$ hg add
adding makefile
$ hg commit -m "added makefile"
&lt;/pre&gt;

&lt;p&gt;default ブランチで「Makefile」を作る。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
$ hg up default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ touch Makefile
$ hg add
adding Makefile
$ hg commit -m "added Makefile"
&lt;/pre&gt;

&lt;p&gt;ブランチをマージする。&lt;/p&gt;
&lt;pre class="prettyprint"&gt;
$ hg up default
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge low
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg st
M makefile
$ hg commit -m "merged"
$ hg up low
0 files updated, 0 files merged, 1 files removed, 0 files unresolved
$ hg up default
abort: case-folding collision between makefile and Makefile
&lt;/pre&gt;

&lt;h1&gt;修正する&lt;/h1&gt;

&lt;p&gt;ブランチを眺めましょう。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ hg glog
o    changeset:   3:94ffa654c8c1
|\   tag:         tip
| |  parent:      2:65bd31a51e91
| |  parent:      1:67211aceefe3
| |  user:        furukawa
| |  date:        Sun Jan 01 16:39:17 2012 +0900
| |  summary:     merged
| |
| o  changeset:   2:65bd31a51e91
| |  parent:      0:21c6ffb22524
| |  user:        furukawa
| |  date:        Sun Jan 01 16:39:16 2012 +0900
| |  summary:     added Makefile
| |
@ |  changeset:   1:67211aceefe3
|/   branch:      low
|    user:        furukawa
|    date:        Sun Jan 01 16:39:15 2012 +0900
|    summary:     added makefile
|
o  changeset:   0:21c6ffb22524
   user:        furukawa
   date:        Sun Jan 01 16:39:14 2012 +0900
   summary:     foo.c
&lt;/pre&gt;

&lt;p&gt;そんなわけで、具体的な作業にはいります。changeset 1 で、makefile を追加したのがそもそもの元凶である、と仮定します。このリビジョンを修正します。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ hg debugsetparents 1
$ hg debugrebuildstate
&lt;/pre&gt;

&lt;p&gt;上の操作で changeset 1 を親とするリビジョンにしています（たぶん）。で、makefile をなかった事にします。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ hg rm -A -f makefile
$ hg forget makefile
$ hg commit -m "fixed case problem"
$ hg up -C tip
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg glog
@  changeset:   4:b636a1636454
|  branch:      low
|  tag:         tip
|  parent:      1:e8c081d89471
|  user:        furukawa
|  date:        Sun Jan 01 16:47:06 2012 +0900
|  summary:     fixed case problem
|
| o  changeset:   3:20205d0bcf9d
|/|  parent:      2:d1de5468f0be
| |  parent:      1:e8c081d89471
| |  user:        furukawa
| |  date:        Sun Jan 01 16:41:58 2012 +0900
| |  summary:     merged
| |
| o  changeset:   2:d1de5468f0be
| |  parent:      0:43bc62047652
| |  user:        furukawa
| |  date:        Sun Jan 01 16:41:56 2012 +0900
| |  summary:     added Makefile
| |
o |  changeset:   1:e8c081d89471
|/   branch:      low
|    user:        furukawa
|    date:        Sun Jan 01 16:41:56 2012 +0900
|    summary:     added makefile
|
o  changeset:   0:43bc62047652
   user:        furukawa
   date:        Sun Jan 01 16:41:55 2012 +0900
   summary:     foo
&lt;/pre&gt;

&lt;p&gt;default ブランチに、これを取り込んで終了&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ hg up 2
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ hg merge low
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don't forget to commit)
$ hg commit
created new head
&lt;/pre&gt;

&lt;h1&gt;まとめ&lt;/h1&gt;

&lt;p&gt;こういう操作で修復できました。が、実はよくわかっていません。とくに、debugsetparents と debugrebuildstate が危ういです。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-968104597852161196?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2012/01/mercurial-case-folding-collision.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-10778463242595899</guid><pubDate>Fri, 30 Dec 2011 22:57:00 +0000</pubDate><atom:updated>2011-12-31T08:12:09.189+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><title>翻訳: Google App Engine で、アプリケーションの応答をよくする 15 の方法</title><description>&lt;div class="p1"&gt;
&lt;/div&gt;
&lt;h2 class="title" style="background-color: white; margin-bottom: 6px; margin-left: 0px; margin-right: 0px; margin-top: 3px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;



&lt;span style="font-family: Arial, Helvetica, sans-serif; font-size: small; font-weight: normal;"&gt;&lt;span style="color: #333333;"&gt;&lt;span style="line-height: 24px; text-transform: capitalize;"&gt;大規模ウェブサービスのプラクティスを紹介している、High Scalability の記事「&lt;/span&gt;&lt;/span&gt;&lt;a href="http://highscalability.com/blog/2011/10/31/15-ways-to-make-your-application-feel-more-responsive-under.html" style="line-height: 1em; text-transform: capitalize;"&gt;15 Ways To Make Your Application Feel More Responsive Under Google App&amp;nbsp;Engine&lt;/a&gt;」を訳しました。&lt;/span&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif; font-size: small; font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif; font-size: small; font-weight: normal;"&gt;記事は Java 前提で、私は Python で Google App Engine を使っているのですが、それでも面白いなと思ったので、有効な方法は使っていこうとしています。ついでなので翻訳したものを残しておくことにしました。&lt;/span&gt;&lt;/div&gt;
&lt;h2 class="title" style="background-color: white; margin-bottom: 6px; margin-left: 0px; margin-right: 0px; margin-top: 3px; padding-bottom: 0px; padding-left: 0px; padding-right: 0px; padding-top: 0px;"&gt;

&lt;span style="font-family: Arial, Helvetica, sans-serif; font-size: small;"&gt;&lt;span style="font-weight: normal;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/span&gt;&lt;/h2&gt;
&lt;hr /&gt;
&lt;div&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;軽量な査定用フィードバックサービスを提供している&amp;nbsp;&lt;a href="http://www.small-improvements.com/"&gt;&lt;span class="s1"&gt;Small Improvements&lt;/span&gt;&lt;/a&gt;&amp;nbsp;が、&lt;a href="http://www.small-improvements.com/app-engine-performance-tuning#"&gt;&lt;span class="s1"&gt;Performance issues on GAE, and how we resolved them&lt;/span&gt;&lt;/a&gt;&amp;nbsp;という素晴らしい記事を書いている。どのようにして、ほとんどのリクエストを 300ms から 800ms でさばき、memcache が効いていなくても2秒、速いページなら150ms 程度でさばけるようになったかの事例になっている。全体として、ものすごく速くしているわけではないけれど、PaaS として GAE が気に入っているなら、検討すべき内容だろう。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;パフォーマンスが悪いときに、できることが限られているというのが、PaaS のやっかいなところだ。でも、Small Improvements の人たちは賢くかつ辛抱強く改良をして、詳細な方法とその結果を提供してくれている。アドバイスはGAE に特化したいるけれど、別の状況にも当てはまるだろう。以下に、彼らが実施した、パフォーマンスの小さな向上（small improvemens) の15の方法をあげる。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;ol class="ol1"&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;App Engine が遅い日もある、と知る。&lt;/b&gt; App Engine はパフォーマンスが悪い日がある。設計段階で、潜在的にレイテンシが変化することを考慮しておく必要がある。常にベストな状況であることを想定しないこと。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;クエリよりも GET する。&lt;/b&gt;&amp;nbsp;Datastore から、ID で直接取得するのは 250ms 。クエリするのには 800ms かかる。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;GET のバッチと、スレッドローカルキャッシュを組み合わせる。&lt;/b&gt;キーごとに個別にGETせず、ひとつのバッチにまとめて GETする。結果を HashMap に保存しておいてレンダリングに使う。モジュール化したアプリケーションでは、内部状態の小さな断片を、引き回すのは避けたいだろうから、&lt;a href="http://java.dzone.com/articles/java-thread-local-%E2%80%93-how-use"&gt;&lt;span class="s1"&gt;ThreadLocal&lt;/span&gt;&lt;/a&gt;&amp;nbsp;に置いておき、いつでも各モジュールからアクセスできるようにする。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;クエリの結果は Memcache に保存する。&lt;/b&gt; appstats ツールを使ってどのクエリが、キャッシュするに値するほど使われているからを見つけ出す。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;ログイン前にmemcache を温める。&lt;/b&gt;&amp;nbsp;ユーザが完全にログインするより前に Ajax を発行して、データをキャッシュしておく。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;ログイン後に memcache を温める。&lt;/b&gt; ユーザがログインしたら、次に読み出しそうな5ページをキャッシュしておく。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;救いようがないほど遅いときには、つなぎのページを表示する。 &lt;/b&gt;最初のクエリの時間を測り、もしも遅ければより速いページへ遷移させる。そのページが閲覧されている間に、元のページをキャッシュする。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;memcache を使えないといは、非同期に読み出すことで、行儀よくしょぼくする。&lt;/b&gt;クエリが遅いなら、その場では全情報をレンダリングしない。クエリが終わったところから順番に描画する。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;アクティブでないときにも再キャッシュ。&lt;/b&gt;ユーザがしばらくアクティブでない状態が続いたら、キャッシュが失効しそうなデータを再キャッシュするようなリクエストを、ブラウザから飛ばす。こうすればユーザが戻ってきたときにキャッシュに残っている。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;データを非正規化する。&lt;/b&gt;「このマネージャの部下は誰か」のような 300ms かかるようなクエリは、結果を予め保存しておき、人同士の関係が変わったときに再計算する。こうすれば GET で結果を取得できるので、速い。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;JAR を使う。&lt;/b&gt; これ最強。何千ものクラスがあったら、ロードするのに 400ms はかかる、これはディスクアクセスがあるからだ。すべてのクラスを JAR に入れておけば、ロード時間が飛躍的に向上する。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;ウォームアップリクエスト&lt;/b&gt;。 できるかぎり GAE の&amp;nbsp;&lt;a href="http://code.google.com/intl/ja/appengine/docs/java/config/appconfig.html#Warmup_Requests"&gt;&lt;span class="s1"&gt;warmup 機能&lt;/span&gt;&lt;/a&gt;を使う。コードパスを吟味して memcache にデータを書き、主な UI を描画し、鍵（キー）となるクエリを発行し、ログインをシミュレートし、時刻の計算をする。こういう処理は VM とデータをウォームアップする。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;書込は後回しにする。&lt;/b&gt; 時間がかかったり、たくさんのクエリを発行した後は、書込処理をタスクキューにいれる。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;非同期でメールする。&lt;/b&gt; メール送信はタスクキューから行う。&lt;/span&gt;&lt;/li&gt;
&lt;li class="li1"&gt;&lt;span style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;非同期でクエリする。&lt;/b&gt;複数のクエリを並列に実行する。&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-10778463242595899?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/12/google-app-engine-15.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-1861039487440967066</guid><pubDate>Mon, 12 Dec 2011 14:47:00 +0000</pubDate><atom:updated>2011-12-13T10:57:19.305+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Python</category><title>six</title><description>&lt;p&gt;&lt;a href="https://connpass.com/event/142/"&gt;2011 Python アドベントカレンダー&lt;/a&gt; のエントリです。Python 2 と Python 3 の差異を吸収するラッパ集として &lt;a href="http://packages.python.org/six/"&gt;six&lt;/a&gt; というライブラリを触ってみました。&lt;/p&gt;


&lt;p&gt;Python 3 に同梱されている 2to3 というツールは、ひとつの Python 2 のソースから、 Python 3 用のソースを自動生成します。したがって、もとの Python 2 用コードと Python 3 用コードのふたつのバージョンを持つことになります。&lt;/p&gt;



&lt;p&gt;一方、six がやろうとしているのは、ひとつのソースコードを Python 2 と Python 3 からも呼び出せるようにすることです。提供されるのは、基本的な定数や、ラッパ関数です。&lt;/p&gt;



&lt;h1&gt;文字列リテラルのフェイク&lt;/h1&gt;



&lt;p&gt;Python 3 と言えば文字列です。&lt;/p&gt;


&lt;pre class="prettyprint"&gt;
# coding: utf-8

print(u'うほ')
&lt;/pre&gt;&lt;p&gt;Python 3 ではこれはエラーになります。six.u() 関数は、文字列リテラルのフェイクになってくれるそうです。&lt;/p&gt;


&lt;pre class="prettyprint"&gt;
# coding: utf-8

import six
print(six.u('うほ'))&lt;/pre&gt;


&lt;p&gt;実行してみましょう。&lt;/p&gt;




&lt;pre class="prettyprint"&gt;
$ python2.7 foo.py

ãã»
$ python3.2 foo.py
うほ
&lt;/pre&gt;&lt;p&gt;えー！six.u() の引数は、 unicode-escape でエンコードされた文字列じゃないとだめだそうです。「うほ」の場合は "\\u3046\\u307b" です。これはあんまりじゃないかと。しかも、&lt;/p&gt;


&lt;pre class="prettyprint"&gt;
$ python2.7 foo.py
うほ
$ python3.2 foo.py
\u3046\u307b

&lt;/pre&gt;

&lt;p&gt;ええぇぇ。そりゃまあ、リテラル表記を関数で代用するんですから、大変だと思いますよ。&lt;/p&gt;



&lt;p&gt;見なかったことにして、six.b() に行きましょう。これは b'…' のフェイクです。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
x = six.b('AB')
print(x[0]+x[1])
&lt;/pre&gt;

&lt;pre class="prettyprint"&gt;
$ python2.7 foo.py
AB
$ python3.2 foo.py
131
&lt;/pre&gt;


&lt;p&gt;oh… このあたりの挙動は &lt;a href="http://d.hatena.ne.jp/atsuoishimoto/20110425/1303696948"&gt;石本さんのブログ&lt;/a&gt; で書かれていますが、リテラルのフェイクは難しいようです。&lt;/p&gt;


&lt;p&gt;気をとりなおして別の関数を見ましょう。それは文字列なのか、それともバイト列なのかを知りたいとき、isinstance とかを使うわけです。が、Python 3 では、このあたりの型や継承関係が変わっています。&lt;/p&gt;


&lt;pre class="prettyprint"&gt;
x = u'foo'
if isinstance(x, basestring):
    print(x.encode('ascii'))

y = b'ABC'
if isinstance(y, str):
    print(y.decode('ascii'))
&lt;/pre&gt;

&lt;p&gt;Python 2 では、上のように書いたりしたんですが、Python 3 では basestring は存在しませんし、str はバイナリを表しません。そこで、six の text_type と binary_type を使います。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
x = six.u('foo')
if isinstance(x, six.text_type):
    print(x.encode('ascii'))

y = six.b('ABC')
if isinstance(y, six.binary_type):
    print(y.decode('ascii'))
&lt;/pre&gt;
&lt;p&gt;実行してみると…&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ python2.7 foo.py
foo ABC $ python2.7 foo.py b'foo' ABC&lt;/pre&gt;

&lt;p&gt;お、これはわりとちゃんと動きますね。text_type は unicode (py2) か、str (py3) のエイリアスになっています。binary_type は同じく str と bytes です。&lt;/p&gt;

&lt;h1&gt;辞書のイテレータ&lt;/h1&gt;

&lt;p&gt;Python 2 の iteritems, iterkeys, itervalues は、Python 3 では items, keys, values に名前が変わっています。そして、Python 2 の items, keys, values はなくなっています。&lt;/p&gt;

&lt;p&gt;この差異を吸収するのが、 six.iteritems などの関数です。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
for k,v in six.iteritems({'spam':99, 'ham':0}):
    print(k,v)&lt;/pre&gt;&lt;pre class="prettyprint"&gt;$ python2.7 foo.py ('ham', 0) ('spam', 99) $ python3.2 foo.py ham 0 spam 99&lt;/pre&gt;&lt;p&gt;辞書のメソッドを使わずに、six.iter* を使うことで、必ずイテレータを返すようになります。&lt;/p&gt;

&lt;p&gt;表示が違うのは、print(k,v) の解釈の違いです。 Python 2 では、タプル (k,v) をプリントしています。一方、Python 3 では、k と v ふたつの引数をとって、それぞれをスペース区切りで表示します。&lt;/p&gt;

&lt;p&gt;six には、これを吸収する関数もあります。&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
six.print_(1,2,3)
&lt;/pre&gt;

&lt;p&gt;実行すると…&lt;/p&gt;

&lt;pre class="prettyprint"&gt;
$ python2.7 foo.py
1 2 3
$ python3.2 foo.py
1 2 3
&lt;/pre&gt;

&lt;h1&gt;まとめ&lt;/h1&gt;

&lt;p&gt;言語仕様が変わって、オフィシャルに 2to3 が用意されるくらいですから、ラッパくらいでは吸収し切れない、というのがよく分かりました。個人的な感想は、2to3のほうが筋がいいんではないか、と思いました。&lt;/p&gt;

&lt;p&gt;あしたは &lt;a href="http://twitter.com/#!/nonNoise"&gt;@nonNoise&lt;/a&gt; さんにバトンタッチです。よろしくお願いします。&lt;/p&gt;

&lt;p&gt;2011-12-13 追記: pre タグがおかしかったのなど、諸々修正。blogspot って wysiwig エディタでコード書くのがいまいち。&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-1861039487440967066?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/12/six.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-5736354387707575894</guid><pubDate>Sun, 04 Dec 2011 12:55:00 +0000</pubDate><atom:updated>2011-12-04T22:00:06.006+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>mock.patch をデコレータ、コンテクストマネージャとして使う</title><description>&lt;div&gt;
patch はコンテクストマネージャでもあるので、with を使った書き方ができます。with でつくられたブロックの中でだけ、モックが機能するようになります。&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; from mock import patch
&amp;gt;&amp;gt;&amp;gt; with patch('random.random') as m:
...     import random
...     random.random()  # もうモックになっている。戻り値は Mock オブジェクト
...     m.return_value = 0.5
...     random.random()  # 戻り値は 0.5
... 
&amp;lt;mock.Mock object at 0x423ed0&amp;gt;
0.5
&amp;gt;&amp;gt;&amp;gt; random.random()  # モノホンの random 関数
0.84432022018162511
&lt;/pre&gt;
&lt;div&gt;
with ブロックの中に入った時点で、random.random はモックになってしまいます。必須ではありませんが、 &lt;code&gt;as m&lt;/code&gt; のように書いて、変数 m でモックへアクセスできます。patch().start() の戻り値と同じです。&lt;/div&gt;
&lt;div&gt;
with ブロックを抜けるときに、パッチャー の stop() メソッドが実行されたのと同じ状態になり、モックではなくなります。&lt;/div&gt;
&lt;div&gt;
複数のモックを使いたいときには、with ブロックをネストするわけですが、それはちょっと鬱陶しいですよね。インデントが深くなりすぎるかも、なので。そんな時は 標準ライブラリの contextlib.nested を使います。&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; from contextlib import nested
&amp;gt;&amp;gt;&amp;gt; from mock import patch
&amp;gt;&amp;gt;&amp;gt; from __future__ import with_statement
&amp;gt;&amp;gt;&amp;gt; with nested(patch('random.random'), patch('random.randint')) as (m, n):
...     m.return_value = 0.5
...     n.return_value = 3  # random.randint のモック
&lt;/pre&gt;

&lt;div&gt;
patch は、デコレータとしても使えます。&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; from mock import patch
&amp;gt;&amp;gt;&amp;gt; @patch('random.random') 
... def func(m):
...     import random
...     print random.random()
...     m.return_value = 0.5
...     print random.random()
... 
&amp;gt;&amp;gt;&amp;gt; func()
&amp;lt;mock.Mock object at 0x429730&amp;gt;
0.5
&amp;gt;&amp;gt;&amp;gt; random.random()
0.94254256426687633
&lt;/pre&gt;
&lt;div&gt;
関数を patch でデコレートすると、元の関数にMock オブジェクトが渡されるようになります。上の例では、第1引数 m が random.random に対応するモックです。このモックが使われているスコープ内、つまりこの関数内でモックが有効になっています。関数を抜けると（正確には、関数を抜けて、デコレートしている外側のスコープを抜けると）、モックではなくなります。したがって、 func() を呼び出した後で、random.random() を呼び出すと本来の戻り値になります。&lt;/div&gt;
&lt;div&gt;
unittest モジュールを使ったテストを書く時には、テスト関数に、デコレータからモックを受け取るように書きます。&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class MyTest(TestCase):
 @patch('random.random')
 def test1(self, m):
  import random
  m.return_value = 10.0
  self.assertEqual(random.random(), 10.0)
&lt;/pre&gt;
&lt;div&gt;
というわけで mock オブジェクトの機能でした。機能を知ることと、使えることはまた別なので、実際にテストでどうするのがいいか、は、別の機会に。私自身、試行錯誤しております。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-5736354387707575894?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/12/mockpatch.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-8127747181018646805</guid><pubDate>Sun, 27 Nov 2011 15:17:00 +0000</pubDate><atom:updated>2011-11-28T00:31:13.751+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>mock.patch</title><description>&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;mock ライブラリの patch 関数の挙動を書きます。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;パッチャーの start()/stop() メソッドを使う&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;標準ライブラリの random.random 関数を例にとります。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; import random
&amp;gt;&amp;gt;&amp;gt; random.random()
0.90675850364670885
&amp;gt;&amp;gt;&amp;gt; random.random()
0.9838226858480108
&lt;/pre&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;patch 関数を実行してみましょう。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; from mock import patch
&amp;gt;&amp;gt;&amp;gt; p = patch('random.random')
&amp;gt;&amp;gt;&amp;gt; random.random()
0.27552766919082217
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;とくに、何も変わったことは起こりません。patch 関数の戻り値は _patch オブジェクトです。ドキュメントにはパッチャーと書いてあります。パッチャーの start() メソッドを呼ぶと変化が起こります。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; m = p.start()
&amp;gt;&amp;gt;&amp;gt; m
&amp;lt;mock.Mock object at 0x366f30&amp;gt;
&amp;gt;&amp;gt;&amp;gt; random.random
&amp;lt;mock.Mock object at 0x366f30&amp;gt;
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;random.random という名前の参照先が、元の乱数生成関数ではなく、Mock オブジェクトに置き換わっています。random.random と p.start() の戻り値は同一の Mock オブジェクトです。&lt;/span&gt;&lt;br /&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;random.random は Mock オブジェクトなので戻り値を書き換えることもできます。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&amp;gt;&amp;gt;&amp;gt; random.random()
&lt;mock.mock 0x366f10="" at="" object=""&gt;
&amp;gt;&amp;gt;&amp;gt; m.return_value = 100
&amp;gt;&amp;gt;&amp;gt; random.random()
100
&amp;gt;&amp;gt;&amp;gt; random.random.return_value = 0
&amp;gt;&amp;gt;&amp;gt; m()
0
&amp;gt;&amp;gt;&amp;gt; random.random()
0
&lt;/mock.mock&gt;&lt;br /&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;パッチャーには stop() メソッドがあり、これを実行すると元に戻ります。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; p.stop()
&amp;gt;&amp;gt;&amp;gt; random.random
&amp;lt;built-in method random of Random object at 0x6b3b6210&amp;gt;
&amp;gt;&amp;gt;&amp;gt; random.random()
0.029689653478273681
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;テストで使う&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;def foo(x):
    return random.random() * x
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;関数 foo をテストする場合を考えます。テストすべきは、&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;br /&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;random.random を引数なしで 1 度呼び出したこと。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;random.random() の戻り値に、x をかけたものが返ること。&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;です。random 関数の戻り値がわかっていれば、テストできますね。モックしましょう。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;import random
import unittest
import mock

def foo(x):
    return random.random() * x

class MyTestCase(unittest.TestCase):
    def test(self):
        # random.random が常に1を返すようモックる
        p = mock.patch('random.random')
        p.start()
        random.random.return_value = 1
        # テスト対象関数を呼び出す
        result = foo(2)
        # random.random() を1度呼んでいることを確認
        self.assertEqual(random.random.call_count, 1)
        self.assertEqual(random.random.call_args, ((), {}))
        # 戻り値をテスト
        self.assertEqual(result, 2)
        # モックを戻す
        p.stop()  

if __name__ == '__main__':
    unittest.main()
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;これでテストできるようになりました。ですが、問題がありまして、テスト中に例外が出ると p.stop() が呼ばれません。random.random はモックのままなので、他のテストが実行されたきに、意図しない結果になることもあります。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;というわけで、必ず実行されるように、setUp と tearDown で、パッチャーの start() と stop() 使います。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class MyTestCase(unittest.TestCase):
    def setUp(self):
        # random.random が常に1を返すようモックる
        self.p = mock.patch('random.random')
        self.p.start()
        random.random.return_value = 1

    def tearDown(self):
        # モックを戻す
        self.p.stop()

    def test(self):
        # テスト対象関数を呼び出す
        result = foo(2)
        # random.random() を1度呼んでいることを確認
        self.assertEqual(random.random.call_count, 1)
        self.assertEqual(random.random.call_args, ((), {}))
        # 戻り値をテスト
        self.assertEqual(result, 2)
&lt;/pre&gt;
&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;つづき&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;patch をデコレータや、コンテクストマネージャとして使えるのですが、それは、また今度。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-8127747181018646805?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/11/mockpatch.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>1</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-7776917993019420350</guid><pubDate>Thu, 24 Nov 2011 15:56:00 +0000</pubDate><atom:updated>2011-11-25T01:43:04.656+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>mock ライブラリの Mock クラス</title><description>&lt;span class="Apple-style-span" style="font-family: inherit;"&gt;mock ライブラリを使ったテストのことを書こうと思ったのだけれど、テストの仕方なんて教えてもらう立場なんだから、いい例を思いつくわけもなく、挫折。&lt;/span&gt;&lt;br /&gt;
&lt;br /&gt;
というわけで、mock ライブラリで提供されている機能を、簡単に書きだしていくことにします。mock を使ってテストする具体的な方法は、また今度。&lt;br /&gt;
&lt;br /&gt;
今回は Mock クラスの基本機能です。ちなみにこれだけでは、テストを書くにあたってのメリットは限定的です。&lt;br /&gt;
&lt;br /&gt;
Mock クラスは引数なしで、インスタンス化できます。以後、Mock オブジェクトと呼びます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; from mock import Mock
&amp;gt;&amp;gt;&amp;gt; wozozo = Mock()
&amp;gt;&amp;gt;&amp;gt; wozozo
&amp;lt;mock.Mock object at 0x106fc4390&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
Mock オブジェクトにドットでつなげると、別の Mock オブジェクトが取り出せます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo.foo
&amp;lt;Mock name='mock.foo' id='4412162832'&amp;gt;
&amp;gt;&amp;gt;&amp;gt; wozozo.bar
&amp;lt;Mock name='mock.bar' id='4412163024'&amp;gt;
&amp;gt;&amp;gt;&amp;gt; wozozo.bar
&amp;lt;Mock name='mock.bar' id='4412163024'&amp;gt;
&lt;/pre&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
同じプロパティ名を指定すると、同じ Mock オブジェクトが返ってきます。上の例では、wozozo.bar は必ず同じ Mock オブジェクトを参照しています。&lt;br /&gt;
&lt;br /&gt;
もちろん、任意の属性に、任意のオブジェクトを代入できます。&lt;br /&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo.baz = 3
&amp;gt;&amp;gt;&amp;gt; wozozo.baz
3
&lt;/pre&gt;
&lt;br /&gt;
Mock オブジェクトを、関数のように呼び出すこともできます。また、 call_count プロパティは呼び出した回数を返します。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo()
&amp;lt;mock.Mock object at 0x106fc44d0&amp;gt;
&amp;gt;&amp;gt;&amp;gt; wozozo.call_count
1
&amp;gt;&amp;gt;&amp;gt; wozozo()
&amp;lt;mock.Mock object at 0x106fc44d0&amp;gt;
&amp;gt;&amp;gt;&amp;gt; wozozo.call_count
2
&lt;/pre&gt;
&lt;br /&gt;
Mock オブジェクトなら呼び出せるので、ドットでつないで得られるプロパティも呼び出せます。引数を渡すこともできます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo.unko(1)
&amp;lt;mock.Mock object at 0x106fc4590&amp;gt;
&lt;/pre&gt;
&lt;br /&gt;
call_count の他にも呼び出し系のプロパティがあります。call_args は、最後に呼び出されたときの引数を返します。また、call_args_list は呼び出されたときの引数の履歴を返します。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo.unko.call_count
1
&amp;gt;&amp;gt;&amp;gt; wozozo.unko.call_args
((1,), {})
&amp;gt;&amp;gt;&amp;gt; wozozo.unko(1, 'a', foo='hoge')
&amp;lt;mock.Mock object at 0x106fc4590&amp;gt;
&amp;gt;&amp;gt;&amp;gt; wozozo.unko.call_count
2
&amp;gt;&amp;gt;&amp;gt; wozozo.unko.call_args
((1, 'a'), {'foo': 'hoge'})
&amp;gt;&amp;gt;&amp;gt; wozozo.unko.call_args_list
[((1,), {}), ((1, 'a'), {'foo': 'hoge'})]
&lt;/pre&gt;
&lt;br /&gt;
戻り値を指定することもできます。下の例では、wozozo.unko() で 999 を返すようにしています。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; wozozo.unko.return_value = 999
&amp;gt;&amp;gt;&amp;gt; wozozo.unko()
999
&lt;/pre&gt;
&lt;br /&gt;
任意の関数を割り当てることもできます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; def f(x, y):
...     return x + y
... 
&amp;gt;&amp;gt;&amp;gt; wozozo.unko = f
&amp;gt;&amp;gt;&amp;gt; wozozo.unko(2, 3)
5
&lt;/pre&gt;
&lt;br /&gt;
てな具合です。&lt;br /&gt;
&lt;br /&gt;
何が嬉しいかと言うと、簡単に何かのフリをさせることができる、ということです。すぐに思いつくのは (1) 生成するのがだるいインスタンスのフリをさせる、 (2) 関数やメソッドのフリをさせる、の2つです。&lt;br /&gt;
&lt;br /&gt;
1つめの例として datetime オブジェクトを受け取って、年の情報だけを使うような関数を考えます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; def next_year(today):
...     return today.year + 1
... 
&amp;gt;&amp;gt;&amp;gt; next_year(datetime.now())
2012
&amp;gt;&amp;gt;&amp;gt; today = Mock()
&amp;gt;&amp;gt;&amp;gt; today.year = 2000
&amp;gt;&amp;gt;&amp;gt; next_year(today)
2001&lt;/pre&gt;
datetime なら、年月日を直接指定できるので大したことないですが、複雑なプロセスを経て、他のオブジェクトへの参照をしているようなオブジェクトで、かつ、一部のプロパティしか使わないのであれば、 Mock オブジェクトで代替すると便利です。&lt;br /&gt;
&lt;br /&gt;
2つめの例としては random 関数を考えます。戻り値が決定論的に定まらないので、テストするのが大変です。そこで random の名前のくせに、常に0.5を返すようにしてみます。&lt;br /&gt;
&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; random = Mock()
&amp;gt;&amp;gt;&amp;gt; random.random.return_value = 0.5
&lt;mock id="4412163920" name="mock.random"&gt;&amp;gt;&amp;gt;&amp;gt; random.random()
0.5
&amp;gt;&amp;gt;&amp;gt; random.random()
0.5
&amp;gt;&amp;gt;&amp;gt; random.random()
0.5&lt;/mock&gt;&lt;/pre&gt;
&lt;br /&gt;
こうすると、テストがやりやすくなりますね。&lt;br /&gt;
&lt;br /&gt;
問題は、何かの関数の「中で」random 関数が呼び出される、ということです。もちろん、random 関数を引数に与えるような設計にするといいのでしょうが、人からもらったコードはそうなってないこともあるでしょう。&lt;br /&gt;
&lt;br /&gt;
それを、うまくやってくれるのが mock.patch() 関数です。&lt;br /&gt;
&lt;br /&gt;
眠い。寝よ寝よ。つづきは、またこんど。&lt;br /&gt;
&lt;br /&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-7776917993019420350?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/11/mock-mock.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-4242183988072244852</guid><pubDate>Wed, 23 Nov 2011 15:25:00 +0000</pubDate><atom:updated>2011-11-24T00:25:01.659+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Python 温泉で開発プロセスの教えを乞う</title><description>&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;初めて参加した Python 温泉で、 @voluntas と @aohta に開発プロセスの教えを乞いました。いろいろ教えてもらった中で、実際に手を動かし始めたことを書きます。&lt;a href="http://d.hatena.ne.jp/Voluntas/20111123/1322022817"&gt;@voluntas のブログ記事&lt;/a&gt;をベースに書いていますが、ふたりに教えてもらったことを混ぜています。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;前提は、&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;- 自社サービス開発&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;- エンジニアの人数は不足気味&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;- 使用する言語は Python のみ&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;- ウェブ API 開発がメイン&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;環境の構築&lt;/span&gt;&lt;/div&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;開発環境を簡単に作れるというのは実はとても重要なファクターです。&lt;br /&gt;これを目指すのがオススメです。git clone | hg clone して make だけたたけばあとは全部用意してくれるが理想ですね。&lt;/span&gt;&lt;/blockquote&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;これは私が苦手なこと（そういうものが私には多い）のひとつです。というわけで、本当に基本的なことだけやりました。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;人生初の buildout を使いました。いままで、便利そうなんだけど、よく分かんないってことで敬遠していました。が、今回は 「Python ライブラリを入れる」ことだけを書きました。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;Makefile&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;.PHONY: env

env:
     python2.7 bootstrap.py --distribute
     bin/buildout
&lt;/pre&gt;
&lt;br /&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;buildout.cfg&lt;/span&gt;&lt;/b&gt;&lt;br /&gt;
&lt;pre =""="" class=" prettyprint"&gt;[buildout]
parts = env

[env]
recipe = zc.recipe.egg
eggs =
    nose==1.1.2
    mechanize==0.2.5
    simplejson==2.2.1
interpreter = python
&lt;/pre&gt;
&lt;div class="p3"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;これだけ。これで hg clone して make したら環境をつくれます。なんで今までやらなかったんだろう。無用な&lt;span class="s4"&gt;混乱を避けるためにバージョン番号を指定してしてあります。&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;単純だけど動く buildout.cfg を書けるようになったことが、今回のツール知識の中で最大の成果です。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;機能テスト&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;上の環境は、開発しているアプリケーション本体ではなくて、その機能をテストするためのものです。@voluntas のブログでいうところの外部テストです。&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;なので、nose が入ってるんですね。アプリケーションは HTTP で JSON を返すので、戻り値のチェックのために simplejson を入れています。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;import urllib
import simplejson as json

def setup():
    # いろいろ初期化
    __SERVER = …
    ...

def test_my_api():
    res = app.call_api('/my/api', x=1, y=2)
    assert res['status'] == 0

def call_api(path, **kw):
    """API を呼び出して、レスポンスを辞書で返す"""
    params = urllib.urlencode(kw)
    fin = urllib.urlopen('%s%s' % (__SERVER, path), params)
    body = fin.read()
    return = json.loads(body)
&lt;/pre&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;上のようなファイルを作っておいて、 bin/nosetest を実行すると、setup して test_my_api を実行してくれます。 nose を使うのも初めてですが簡単でした。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;自社ライブラリ&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;前述の call_api 関数は別のモジュールに切り出してあります。ゆくゆくは自社ライブラリとして格上げの予定。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;大したコードではないので自社ライブラリにしなくていいんじゃ、と思ったのです。が、「call_api のテストだけ書いておけば、[simplejson などの] 依存先の使わない機能の不具合を無視できるのだから、自社ライブラリの動作確認だけすればよいでしょ。だから自社ライブラリにしちゃえ」という教えでした。これが一番私にとって重要な考え方でした。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;次の課題&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;buildout でインストールした mechanize は OAuth 機能のテストに使います。リダイレクトやブラウザ上で操作などがあるので、自動テストにはブラウザを抽象化してくれるライブラリが必要でした。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;def signup_with_twitter(screen_name, password):
    """Twitter アカウントでログイン"""
    def userop(browser):
        # Twitter にログインして承認
        browser.select_form(nr=0)
        browser["session[username_or_email]"] = screen_name
        browser["session[password]"] = password
        browser.submit()
    return _oauth('twitter', userop)

def _oauth(authority, userop):
    browser = mechanize.Browser()
    browser.set_handle_robots(False)
    # OAuth 開始の URL を開く
    browser.open("%s/oauth?authority=%s" % (__SERVER, authority))
    # ユーザ操作
    userop(browser)
    # レスポンスパラメータを取得
    # example.com/path?foo=1&amp;amp;bar=x =&amp;gt; {"foo":["1"], "bar":["x"]}
    url = browser.geturl()
    data = cgi.parse_qs(urlparse.urlparse(url).query)
    return data
&lt;/pre&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;これはこれで Twitter を使った OAuth のテストができるので問題ありません。問題は、Twitter に問題があると、テストが FAILすることです。それは Twitter の問題であって、私が開発しているアプリケーションの問題ではありません。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;なので、OAuth が成功した or 失敗したふりをしてくれるモックが必要です。それが次の課題だろうな、と考えています。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;おわりに&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;何をしようとしているかというと、継続的インテグレーションをしたいのです。サーバサイドのエンジニアが少ないので、できるだけ自動化したいわけです。人間は創造的なことに時間を使うべきだ、と個人的に信じています（それでまあ、例の対談とかの流れになるわけです）。そのためには自動的に環境構築して、テストできるようにする必要があるのですが、ずーっと止まっていました。今回の温泉で、一歩目を踏み出せたのは大きな収穫でした。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;おまけ&lt;/span&gt;&lt;/div&gt;
&lt;div class="p7"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;
&lt;/span&gt;&lt;/div&gt;
&lt;div class="p6"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;35歳ごろ（定年だというのに）ソフトウェア開発業界に入りたい、と思うようになりました。このとき、Python Code Reading で発表 → BPStudy に行く → Python 温泉に行く → 顔を知ってもらう → どっかの会社に潜り込む、という戦術を妄想していました。そして、37歳にしてやっと Python 温泉に行けました。順番がずれていますが、自分の人生で計画通りにいったことなどないので、自分にしては上出来です。&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-4242183988072244852?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/11/python.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-3277229363203236916</guid><pubDate>Sun, 13 Nov 2011 12:07:00 +0000</pubDate><atom:updated>2011-11-13T21:14:06.064+09:00</atom:updated><title>python の mock ライブラリを使ってみる</title><description>&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;最近 mock ライブラリを使うようになりました。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;能書き&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;（ここは単体テストとモックの意義が分かってる人には、価値ゼロです。）&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;単体テストというのは、本来、あるコンポーネントの依存先に影響されないように、対象をテストします。が、これまでは比較的てきとーで、依存先のテストが通っていれば、依存先を完全に分離せずにやってきました。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;これには2つ問題があって、(1) そもそもそれは単体テストではない、(2) 依存先が外部だったらどうするんだ、と。例えば、Twitter からタイムラインをとってくる、とかですね。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;想定するテスト対象&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;def get_user_timeline(user)
    """タイムラインをとってきて、辞書で返す"""
    twitter = Twitter()
    response = twitter.get_timeline(user.id, user.access_token)
    timeline = [{'text': tweet.text} for tweet in response['tweets']]
    return timeline
&lt;/pre&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;辞書にレンダリングを分離すべきとかありますが、いまは Twitter から取ってくる箇所だけ考えます。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;テストの度に本当に Twitter にアクセスしていては単体テストになりません。ってなわけで、 mock ライブラリを使います。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;インストール&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;easy_install mock&amp;nbsp;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;で、おｋ。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;Mock クラス&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mock のインスタンスのプロパティは適当にやってくれます。事前に定義する必要はありません（定義することはできます）。しかも foo.bar にアクセスするとき、いつも同じオブジェクトが返されます。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; import mock
&amp;gt;&amp;gt;&amp;gt; x = mock.Mock()
&amp;gt;&amp;gt;&amp;gt; x.foo&lt;mock id="1838576" name="mock.foo"&gt;
&amp;gt;&amp;gt;&amp;gt; x.foo&lt;mock id="1838576" name="mock.foo"&gt;
&amp;gt;&amp;gt;&amp;gt; x.foo == x.foo
True
&lt;/mock&gt;&lt;/mock&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mock インスタンスは常に呼び出し可能です。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;pre class="prettyprint"&gt;&amp;gt;&amp;gt;&amp;gt; y = mock.Mock()
&amp;gt;&amp;gt;&amp;gt; y()
&lt;mock.mock 0x33da30="" at="" object=""&gt;
&amp;gt;&amp;gt;&amp;gt; y.hoge()
&lt;/mock.mock&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;テストを書いてみる&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;get_user_timeline 関数の仕事は、(1) 引数 user を twitter.get_timeline() に渡すこと、(2) その戻り値から辞書を作成すること、です。user オブジェクトの作成や get_timeline() で何が起こっているかは、別の単体テストでやることです。なので、 user と get_timeline はモックにしちゃいましょう。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;任意のモジュール内の、任意のクラスのメソッドを入れ替えるときは、patch 関数を使います。&lt;/span&gt;&lt;/div&gt;
&lt;div class="p2"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class GetUserTimelineTest(unittest.TestCase):
    def test(self):
        # モックのコンテクストで実行
        # 動作を変えたいメソッドを文字列で指定する。
        with mock.patch('mymodule.Twitter.get_timeline') as m:
            # レスポンスで使うダミーの tweet を作る
            tweet0 = mock.Mock()
            tweet1 = mock.Mock()
            # get_timelineメソッドを呼び出したときの戻り値をモック
            m.return_value = {"tweets":[tweet0, tweet1]}
           
            # 引数で渡すオブジェクトもモックにする
            user = mock.Mock()

            # 単体テスト対象関数呼び出し
            result = get_user_timeline(user)

            # モックが1度呼ばれていることを確認
            self.assertEqual(m.call_count, 1)
            # モックが呼ばれたときの引数を確認
            self.assertEqual(m.call_args,
                             ((user.id, user.access_token),{}))
            # 戻り値の確認
            self.assertEqual(len(result), 2)
            self.assertEqual(result[0]['text'], tweet0.text)&lt;/pre&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;
&lt;br /&gt;
&lt;div class="p1"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;わかりにくいなぁ。もっと時間かけて丁寧に書かないと、知らない人には伝えられない気がしてきた。&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-3277229363203236916?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/11/python-mock.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-6086622238173180926</guid><pubDate>Fri, 28 Oct 2011 20:00:00 +0000</pubDate><atom:updated>2011-10-29T22:55:12.282+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><title>ドキュメント書きを効率化した5つの方法</title><description>&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;API の仕様書なるものを書いている過程で、繰り返し作業が多く、いくつかの作業を工夫したのでまとめておきます。前提として、私はコードを一切書かず、依頼先にドキュメントを渡し、成果物としてコードを受け取ります。reST で書いて、Sphinx で HTML をビルドし、Wed-DAV 上のディレクトリに置くことで共有します。&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;1. 継続ビルド&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span"&gt;Sphinx によるドキュメントを継続ビルドしています。&lt;/span&gt;&lt;/span&gt;&lt;span class="Apple-style-span" style="color: #222222; font-family: Arial, Helvetica, sans-serif; line-height: 16px;"&gt;&lt;a href="http://torufurukawa.blogspot.com/2011/10/omake-sphinx.html"&gt;omake を使わずに、Sphinx ドキュメントの継続的ビルド&lt;/a&gt;&amp;nbsp;&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;に具体的な方法を書きました。明示的なビルドをしなくなったので、書くときにはひたすら文書自体に集中して書いて、ブラウザでHTMLを確認する、というのを続けていけます。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;make html をいちいち手でやっていると、どうしても文書ではなくて、ビルドするっていう行為に集中してしまうのです。継続ビルドなら書く方に集中できます。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;欠点として、sphinx でビルドするとき、リンクエラーなんかは2回目以降のビルドではでなくなるので、エラーはどんどん流れていってしまいます。大きなコミットする前には make clean; make html &amp;nbsp;します。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;2. ひな形&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Komodo Edit の snippet に、ひな形を登録しておき、ワンクリックで挿入します。各 API は、だいたい同じフォーマットで記述するので、便利です。キーボードショートカットも割り当てられますが、そこまで使わないので、クリックで十分でした。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;3. 進捗の測定&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Komodo Edit のコマンド機能を使って、時刻、文書中に現れる "..todo::" の個数と、ソースファイルの文字数を出力するコマンドを登録しています。作業が一段落したところで、実行して、スプレッドシートにコピペします。スプレッドシートではそれをグラフにしています。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;この工程は、作業と関係ないのですが、だらけるのを防止するために、自分の活動が成果物の量としてどのくらい反映されているのかを可視化していました。TODO は書いている途中で増えたりしますし、共通した部分をまとめると、ざくっとソースが小さくなるのですが、それは別に構いません。短期的なやる気の問題です。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;echo -e `date "+%Y-%m-%%d %H:%M"`\\t`grep todo:: api/*.rst *.rst | wc -l`\\t`cat \`ls *.rst api/*rst\` | wc -c`&lt;/span&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;4. Mercurial のログを取り出す&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;現在の Mercurial ブランチの各リビジョンのメッセージを取り出すというコマンドも作りました。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;いきなり完成版のドキュメントを渡すことができなかったので、追記や変更した版を出していくことにしました。そのとき変更履歴を changelog.rst に書くわけですが、コミットの度に編集していると面倒ですし、だいたい内容は mercurial のログと重複します。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;そこごで、リリースごとにブランチをきっているので、ひととおり作業が終わったら、このコマンドを実行し、まとめて整形するようにしました。作業後半はこのコマンドがいちばん作業時間の軽減になりました。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;hg log -b `hg branch` -v | awk '$1 !~ /(changeset|branch|user|date|files|description|tag):/ {print}'&lt;/span&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;b&gt;5. Makefile に upload ターゲット&lt;/b&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Makefile に upload ターゲットを追加して、make upload で反映します。これはすぐですね。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;以上は、作業の効率化であって、仕事全体の効率化とは別の問題です。こうしたらいいとか、あったらぜひ教えてください。まだまだ書くのが、というか、要件を頭で整理するのが遅いです。困ったものです。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-6086622238173180926?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/10/5.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-6650811525226025998</guid><pubDate>Fri, 14 Oct 2011 00:03:00 +0000</pubDate><atom:updated>2011-10-14T09:06:06.050+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Development</category><title>omake を使わずに、Sphinx ドキュメントの継続的ビルド</title><description>&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Sphinx つかってドキュメント書いているのですが、自動的にビルドできないかなぁと思ったのが、1ヶ月くらい前です。そのときは、&lt;a href="http://d.hatena.ne.jp/ymotongpoo/20101024/1287902137"&gt;EUnitとOMakeでテスト駆動開発&lt;/a&gt;とかを読んで&amp;nbsp;omake の P オプションがよさそうだったのですが、実現に至らず。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mac OS X Lion で Komodo Edit 使って編集しています。omake -P すると、最初に1回ビルドが走ったあと、polling for filesystem changes ってなったまま表示が変わらず、ソースを編集すれどもすれでも、ビルドされません。ターミナルで vim とかで編集/保存すると omake -P はちゃんと変更を検出してくれて、期待通りに継続ビルドになります。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;もうファイルシステムとか分かんないので、Makefile を適当に追記して生きていくことにしました。以下追記部分。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;auto:
     @while :; do make html_silent; sleep 1; done

html_silent: .built
     @echo &amp;gt; /dev/null

.built: *.rst img/*
     $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
     @touch .built
     @echo
     @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
&lt;/pre&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;「make auto」して使います。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;auto と html_silent は、.PHONY に入れてあります。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;毎秒、.built ファイルと、ソースファイルの日付を比較して、ソースファイルのほうが新しければビルドして、touch .built するだけです。ださくてすみません。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-6650811525226025998?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/10/omake-sphinx.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-6633020827719005420</guid><pubDate>Wed, 12 Oct 2011 23:17:00 +0000</pubDate><atom:updated>2011-10-13T08:20:13.460+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>@tokibito さんの TestBedTestCase をいじる</title><description>&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;&lt;a href="http://d.hatena.ne.jp/nullpobug/20111010/1318192425"&gt;@tokibito さんが、Google App Engine のスタブを使う TestCase クラスを紹介しています。&lt;/a&gt;私の仕事でも使っています。&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
サブクラスを作ったときに、TestBedTestCase の setUp と tearDown を明示的に呼び出さないといけないのがちょっと面倒です。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class MyTestCase(TestBedTestCase):
    def setUp(self):
        super(MyTestCase, class).setUp()
        # … 準備 ...

    def tearDown(self):
        # … 片付け …
        super(MyTestCase, class).tearDown()
&lt;/pre&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
Pythonic なので、これはこれで別に問題ないんだろうけど、これ結構めんどくさい。あと、nose 使えば、モジュールごとに setUp を定義しておくと、こういうのもやってくれるはずだけど、老害じじいは nose とか分かんないので、とりあえずスルー。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
という訳で、ベースクラスの setUp と tearDown を自動的に呼び出すようにして使っています。setUp の呼び出し順は、基底クラスの setUp の後で、派生クラスの setUp。tearDown は逆です。それぞれ、C++ なんかのコンストラクタとデストラクタと同じにしました。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class CascadingTestCaseMeta(type):
    """Metaclass for TestCase class

    This metaclass make setUp method calls all setUp methods 
    in base classes and then calls defined setUp method.  
    Likewise tearDown but in opposite order.
    """

    def __init__(cls, name, bases, ns):
        for method_name, reverse in [('setUp',False), ('tearDown', True)]:
            setattr(cls, method_name,
                    cls._create_method(method_name, bases, ns, reverse=False))

    @classmethod
    def _create_method(self, method_name, bases, ns, reverse=True):
        """return a method that calls all methods with given 
        name in class hierarchy
        """
        # create method sequence in parent and current classes
        methods = [getattr(base, method_name, lambda self: None)
                   for base in bases]
        methods.append(ns.get(method_name, lambda self: None))
        # reverse order if necessary
        if reverse:
            methods.reverse()
        # define method to call all methods
        def call_methods(self):
            for method in methods:
                method(self)
        # return the caller method
        return call_methods

class CascadingTestCase(unittest.TestCase):
    __metaclass__ = CascadingTestCaseMeta

class TestBedTestCase(CascadingTestCase):
    # 以下、@tokibito さんのコード
&lt;/pre&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
TestBedTestCase のメタクラスを直接指定していないのは、testbed の setUp よりも「前に」何かしたいときと、「後に」何かしたいときがあると思ったからです（でも今のところない…）。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;pre class="prettyprint"&gt;class MyTestCase(TestBedTestCase, MyBaseTestCase):
    def setUp(self):
        ...
&lt;/pre&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
と定義すると、TestBedTestCase.setUp, MyBase.setUp, MyTestCase.setUp の順に呼び出されます。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
TestBedTestCase のsetUp と tearDown が呼び出されるのが明示的じゃない気がしますが、そこの明示性は諦めました。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
やっぱ nose かなぁ…。&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-6633020827719005420?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/10/tokibito-google-app-engine-testcase.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-3727656357166637107</guid><pubDate>Sat, 24 Sep 2011 10:49:00 +0000</pubDate><atom:updated>2011-09-24T19:49:59.427+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Google App Engine の backends インスタンスをデータベース的に使おうとしてみた</title><description>&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ウィルスとかフィッシングとかにやられる奴ってなんなの？ ひっかかる努力をしないと、ひっかからないだろあんなもん、と思っていた時期が私にもありました。まんまと&lt;a href="http://twitterspam.info/35"&gt;フィッシング&lt;/a&gt;に引っかかった情弱です。&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;現実を見たくなかったので、Google App Engine の backends インスタンスを、DB サーバ的に使えないかなぁと、試してみました。単純なケースでは、パフォーマンス的にも、コスト的にもあまりメリットがないです。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ソースコードは&amp;nbsp;&lt;a href="https://github.com/torufurukawa/backendtest"&gt;https://github.com/torufurukawa/backendtest&lt;/a&gt;&amp;nbsp;に置いてあります。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;&lt;b&gt;コード&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;backends.yaml&lt;/span&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;backends:&lt;br /&gt;- name: memdb&lt;br /&gt;&amp;nbsp; start:&amp;nbsp;memdb.py&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;「memdb」という名前で識別するインスタンスで、起動時には&amp;nbsp;memdb.py&amp;nbsp;を見るように設定します。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;memdb.py&lt;/span&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;from google.appengine.ext import webapp&lt;br /&gt;from google.appengine.ext.webapp import util&lt;br /&gt;DATA = {}&lt;br /&gt;class InitializeHandler(webapp.RequestHandler):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def get(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; global DATA&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; DATA['foo'] = 'foo'&lt;br /&gt;application = webapp.WSGIApplication([('/_ah/start', InitializeHandler)], debug=True)&lt;br /&gt;util.run_wsgi_app(application)&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;memdb インスタンスが起動するときに呼ばれる /_ah/start に対してハンドラを設定します。ここでは動作確認用に、DATA 辞書をちょっといじっています。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;memdb モジュールの DATA 辞書を、 Key-Value ストアとして使うことにします。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;まずデータを書き込むとき用のハンドラ群。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;main.py （抜粋）&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;MEMDB_BACKEND_ID='memdb'&lt;br /&gt;MEMDB_HOSTNAME=backends.get_hostname(MEMDB_BACKEND_ID)&lt;br /&gt;DATA='spam'*10&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;def stop_watch(op_name):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; """ロギングと共通レスポンス用のデコレータ。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; 関数を実行して、実行時間をログとレスポンスに書き出す。&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; """&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def outer(func):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; def wrapper(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; start_at=time.time()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; func(self)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; end_at=time.time()&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; log='[%s] %s'%(op_name,end_at-start_at)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; logging.info(log)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.response.out.write(log)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; return wrapper&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return outer&lt;br /&gt;&lt;br /&gt;class BackendWriteHandler(webapp.RequestHandler):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @stop_watch('backend:write')&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def get(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hostname=MEMDB_HOSTNAME&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; response=fetch('http://%s/memdb/set/%s/%s'%(hostname,get_key_name(),DATA))&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;class MemdbSetHandler(webapp.RequestHandler):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; """/memdb/set/(.+)?/(.+) で呼ばれるハンドラ"""&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; d ef get(self,key,value):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; importmemdb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; memdb.DATA[key]=value&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.response.out.write(value)&lt;br /&gt;def get_key_name():&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; return''.join([random.choice('abcdefghijklmnopqrstuvwzyz')for i inrange(10)])&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;外部から、通常のインスタンス上 の BackendWriteHandler の get が呼ばれます。ランダムに作ったキーと定数値を指定して、memdb インスタンスの /memdb/set/&amp;lt;key&amp;gt;/&amp;lt;value&amp;gt; を GET します。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;memdb インスタンスのハンドラが、MemdbSethandler です。モジュールグローバルの DATA 辞書を、key と value で更新します。これで memdb 上の値の更新ができます。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;続いて、呼び出しです。main.py から抜粋。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;/div&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; line-height: 20px;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; line-height: 20px;"&gt;&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;class BackendReadHandler(webapp.RequestHandler):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; @stop_watch('backend:read')&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def get(self):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; hostname = MEMDB_HOSTNAME&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; response = fetch('http://%s/memdb/get/%s' % (hostname, get_key_name()))&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; data = response.content&lt;/span&gt;&lt;/span&gt;&lt;/blockquote&gt;
&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; line-height: 20px;"&gt;
&lt;/span&gt;&lt;span class="Apple-style-span" style="-webkit-border-horizontal-spacing: 2px; -webkit-border-vertical-spacing: 2px; border-collapse: collapse; line-height: 20px;"&gt;&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;class MemdbGetHandler(webapp.RequestHandler):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; """/memdb/set/(.+)?/(.+) で呼ばれるハンドラ"""&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: 'Courier New', Courier, monospace;"&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; def get(self, key):&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; import memdb&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; value = memdb.DATA.get(key)&lt;br /&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; self.response.out.write(value)&lt;/span&gt;&lt;/blockquote&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;外部からアプリの通常のインスタンスへは、BackendReadHandler が呼ばれます。memdb インスタンスに対して /memdb/get/&amp;lt;key&amp;gt; を呼び出します。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;memdb のハンドラは MemdbGetHandler で、DATA 辞書から値を取り出して返す、というものです。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;&lt;b&gt;実行してみた&lt;/b&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Datastore、Memcache、backends で読み書きをしてみました。きちんとやってなくてさーせん。なんどかブラウザからちょこちょこ URL にアクセスして、安定していたあたりの10件の平均時間 [ミリ秒] と標準偏差です。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Storage&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Write&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Read&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Datastore&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 14±1&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 4±0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mecache&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2±0&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 2±0&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Backend&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 49±83&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; 87±88&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;かなり遅いのと、所要時間がえらく不確定です。アクセスの感覚もゆっくりとったので、Datastore よりも早いんじゃないのかくらいの期待をしていたのですが、ぜんぜんです。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;コストのほうを計算してみました。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;100ミリ秒（0.1秒）ごとに読み書きのいずれかが発生するとしましょう。楽観的に考えて、スパイクはなし、と。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;そうすると、1ヶ月での読み書き回数は、&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;0.1 [秒] x 3600 [秒/時間] x 24 [時間/日] x 30 [日/月] = 25,920,000 [回/月]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;デフォルトの B2 クラスのインスタンスの1ヶ月の使用料は、&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;0.16 [ドル/時間] x 24 [時間/日] x 30 [日/月] = 115 [ドル/月]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;です。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;同じ回数のアクセスを、Datastore に対して行うと、&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;書き込みのみ費用 = 0.01 [ドル/10k回] x 25,920,000 [回/月] = 26 [ドル/月]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;読み込みのみ費用 = 0.07 [ドル/10k回] x 25,920,000 [回/月] = 181 [ドル/月]&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;読み込みだけ発生すれば、backends のほうが安いです。が、実際にはそんなわけないですしねぇ。うーむ。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;b&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;とは言え…&lt;/span&gt;&lt;/b&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Datastore から複数のエンティティを取得すると、その分読み込み回数のカウントが増えます。アプリによっては、それを backendsではうまくハンドルできるかも知れません。memcache のデータは揮発する可能性がありますが、backends はメモリに気をつけていれば datastore ほどではないにしてもなんちゃって永続化できます（そのあたりの監視や処理にCPU時間が必要でしょうけど）。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;なので、この使い方がすなわちダメではないんでしょうが、個人的にもっとあからさまな速度差や、コスト差が出るのかなぁと妄想していたので、少しざんねんです。今日は残念な日なのでしょう。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-3727656357166637107?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/09/google-app-engine-backends.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-1764685314308305728</guid><pubDate>Mon, 19 Sep 2011 13:54:00 +0000</pubDate><atom:updated>2011-09-19T22:54:38.470+09:00</atom:updated><title>半島を出よ探訪</title><description>&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;村上龍の「半島を出よ」の舞台あたりに行く機会がありました。えーっと博多のほうですよ。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; margin-left: 1em; margin-right: 1em;"&gt;&lt;a href="http://1.bp.blogspot.com/-EJnLNB3JG4M/TndHTqvVI4I/AAAAAAAAAbo/TktFhIjPdUE/s1600/camp.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="210" src="http://1.bp.blogspot.com/-EJnLNB3JG4M/TndHTqvVI4I/AAAAAAAAAbo/TktFhIjPdUE/s320/camp.jpg" width="320" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ホテルから野営地までは、団体出入り口から外に出て四車線の広い道路を渡るのが最短の道筋だ。しかし高麗遠征軍制圧区域に出入りする車はほとんどないので、道路はまるで夜の平壌のように換算としている。狙撃の危険があるわけではないのだが、車の行き来も遮蔽物もまったくない幅三十メートルの道路を横断するのは気持ちが悪かった。チェ・ヒョイルは、ホテルから野営地に戻るときはいつも福岡ドームの正面ゲートのほうから迂回することにしていた。&lt;/span&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ホテルから野営地のモデルとなる広場を見た様子。前の道路が、チェ・ヒョイルが横断するのをためらっている道路。右側は、まっすぐ伸びていってて、遮蔽物はまったくない。正面に見える大きな建物が、九州医療センター。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;作品では、開発がとまってこの広場は放置されていた、と書かれています。若干手入れされていますが、それほど積極的に使われていないようです。ヒルトンと病院の間のこの空間「どーすんだよ、ここw」みたいな感じになっているのかも知れません。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-dF5Q76sKJh4/TndHU7ZnUgI/AAAAAAAAAbs/iH02CZcuxps/s1600/camp2.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="182" src="http://2.bp.blogspot.com/-dF5Q76sKJh4/TndHU7ZnUgI/AAAAAAAAAbs/iH02CZcuxps/s320/camp2.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;左のほうは道が右にゆっくり曲っていってきます。チェ・ヒョイルはこちらのほうから、迂回して渡っている。カラフルな建物群がホークスタウンで、物語の中では、高麗遠征軍による広場の制圧後は、営業していない、という設定。&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; margin-left: 1em; margin-right: 1em;"&gt;&lt;a href="http://1.bp.blogspot.com/-7J3XcovNcc0/TndHZYEYDHI/AAAAAAAAAbw/g8xUT6mtfCA/s1600/hananoki.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" height="215" src="http://1.bp.blogspot.com/-7J3XcovNcc0/TndHZYEYDHI/AAAAAAAAAbw/g8xUT6mtfCA/s320/hananoki.jpg" width="320" /&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;/div&gt;
&lt;div class="separator" style="clear: both; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; margin-top: 0px; text-align: left;"&gt;
&lt;/div&gt;
&lt;blockquote style="text-align: left;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;なるほど、というようにチェ・ヒョイルは真剣な顔を崩さずにうなずき、橋を指差して、ずいぶん長い橋ですね、と言った。 [...]&amp;nbsp;こんなに眩しいのにどうしてブラインドを下ろさないのだろうか。チェ・ヒョイルがそのことを不審に思ったとき、突然窓ガラスが割れ、外の空気が流れこんできた。チェ・ヒョイルが思わず身をかがめたとき、缶入りコーヒーに似た黒い金属の筒が前方の床に転がった。&lt;/span&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;観月橋から、岸の方を見た様子。右側の2階建ての建物に、戦闘劇の現場になったレストランが入っています。窓は南向きです。左側の岸の向こうのほうに、駐車場の車が見えます。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;岸にいると、バルコニーに誰かが隠れているかどうかは、「誰かがいるんじゃないのか？」っていうつもりで覗きこまないと見えません。池にかかっている橋まできて、やっと見えます。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://2.bp.blogspot.com/-HvrHWFH8tfg/TndHawolNDI/AAAAAAAAAb0/VyoULl5fwj4/s1600/domeandhilton.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;img border="0" height="153" src="http://2.bp.blogspot.com/-HvrHWFH8tfg/TndHawolNDI/AAAAAAAAAb0/VyoULl5fwj4/s320/domeandhilton.jpg" width="320" /&gt;&lt;/span&gt;&lt;/a&gt;&lt;/div&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;海からの風で煙がこちら側に漂ってきて、ホテルの根元の黒い穴が露になり、キム・ヒャンモクは奇妙な感覚にとらわれた。自分のからだが左に傾いていくような感じがしたのだ。視界が右に傾いていくようだった。カタツムリのような形をしたガラス張りの建築物が粉々になり、ガラスの細かな破片が飛び散るのを見て、ホテルが右に倒れているのだと気づいた。ナイフのよう形を保ったままホテルはゆっくりと傾いていき、地鳴りのような音と猛烈な風が起こった。&amp;nbsp;&lt;/span&gt;&lt;/blockquote&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://2.bp.blogspot.com/-HvrHWFH8tfg/TndHawolNDI/AAAAAAAAAb0/VyoULl5fwj4/s1600/domeandhilton.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;作中でキム・ヒャンモクがいた病院から道をはさんだ右側、ホークスタウンからの様子です。左から、ヒルトン福岡シーホーク、同じく4Fのアトリウム（作中/当時ラグナグ）、ヤフードーム（作中/当時福岡ドーム）です。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;こんなものが倒壊したら、ひどいもんです。この写真をとっていた場所や、すぐ近くの野営地にいたら、爆風と飛んでくる瓦礫でアウトでしょう。作中では実際アウトだったわけですが。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;そのうち他の写真もまとめるかも。&lt;/span&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-1764685314308305728?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/09/w.html</link><author>noreply@blogger.com (Toru Furukawa)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-EJnLNB3JG4M/TndHTqvVI4I/AAAAAAAAAbo/TktFhIjPdUE/s72-c/camp.jpg" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-7005783647508267371</guid><pubDate>Sun, 11 Sep 2011 13:22:00 +0000</pubDate><atom:updated>2011-09-11T22:44:32.963+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Google App Engine memcache cas (compare and set)</title><description>&lt;div style="font-family: Arial;"&gt;
Google App Engine SDK 1.5.3 で memcache cas (Compare and Set) 操作ができるようにななりました。今更ですが。&amp;nbsp;&lt;a href="http://neopythonic.blogspot.com/2011/08/compare-and-set-in-memcache.html"&gt;GvR のブログ&lt;/a&gt;でも丁寧に解説されています。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div style="font-family: Arial;"&gt;
で、どんなときに使おうっかなぁと思うわけです。データが揮発してよい、クライアント間のデータ共有の遅延を遅らせたい、整合性は保つ、みたいなときに意味があるのでしょうか。クライアントが自身のID を渡してサービスを呼び出し、最後に呼び出して一定時間以内のクライアント数を数える、みたいな機能とか。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;script src="https://gist.github.com/1209524.js?file=cas_test.py"&gt;
&lt;/script&gt;

&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Verdana, sans-serif;"&gt;と、思っ&lt;/span&gt;&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;たんですが、cas のリトライに失敗したときにどうしましょうっかねぇ。どっか、別のエラーの回数を incr() しといて、エラー率とアクセス数を関連付けるとかでしょうか。むずい。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;2011-09-11 22:43 追記: シャーディングで、ひとつのキーに集中しないようにする、というのは大前提で。&lt;/span&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-7005783647508267371?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/09/google-app-engine-memcache-cas-compare.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-6994675243339372162</guid><pubDate>Sat, 03 Sep 2011 15:53:00 +0000</pubDate><atom:updated>2011-09-04T11:42:18.161+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">App Engine</category><category domain="http://www.blogger.com/atom/ns#">Eclipse</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>Eclipse と virtualenv で App Engine アプリを開発する設定</title><description>&lt;br /&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Emacs で Google App Engine 触っているのですが、もういい加減に IDE 使おうと思いました。Wing IDE、Komodo IDE、PyCharm あたりを考えたのですが、（ここでビール3杯をはさんだのでロジックは忘れたが） Eclipse だろうとなりました。で、ちょっとはまったので、メモです。&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;前提&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Mac OS X (Lion)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Google App Engine Launcher を使う。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;プロジェクトごとに virtualenv 環境を用意する。&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;インストール手順&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp;（したければ）Python をインストールする。(homebrew の 2.7)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;App Engine Launcher をインストールする。(1.5.3)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Eclipse をインストールする。(3.7.0)&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;a href="http://pydev.org/manual_101_install.html#installing-with-the-update-site"&gt;PyDev をインストール&lt;/a&gt;する。(2.2.2.2011082312)&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;プロジェクト作成手順&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;[File]-[New]-[Other…]- [PyDev の下の PyDev Google App engine Project] を選択して [Next]&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;[User default] のチェックをはずす&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Directory にソースコードがあるディレクトリを指定 e.g. /Users/bucho/show&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;Interpreter が空欄なので「Click here to configure an interpreter not listed」 をクリック&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;[New] をクリックして適当な名前にする。e.g. python2.5@show&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;PYTHONPATH に追加すべきディレクトリが出てきます。デフォルトでチェックがはいっている項目に加えて、virtualenv の Python がもともと参照している /lib ディレクトリにもチェックします。例えば homebrew でインストールした Python 2.7 なら、/user/local/Celler/python/2.7/lib/python2.7 とか。（2011-09-04 追記）&lt;br /&gt;&lt;strike&gt;いろいろと PYTHONPATH に追加すべきディレクトリが出てくるけどデフォルトでOK。&lt;/strike&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ターミナルで、echo $PATH した値をコピー&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;[Environment] タブをクリック、New ボタンをクリックして、Name に「PATH」、Value 欄にさっきのをペースト。（私の環境で必要だったのは /usr/local/bin です。めんどいので全部ペーストしました）。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;[Finish]ボタンをクリック&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;App engine の場所を聞いてくるので「/Applications/GoogleAppEngineLauncher.app/Contents/Resources/GoogleAppEngine-default.bundle/Contents/Resources/google_appengine」 を指定する。&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp;[Django0.97] にチェック。&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif; font-size: large;"&gt;&lt;strike&gt;補完が...&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;これでいちおう動くんだけど、標準ライブラリの import 文なんかを、resolve できない。たとえば import unittest だと、下みたいになります。&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div class="separator" style="clear: both; text-align: left;"&gt;
&lt;a href="http://4.bp.blogspot.com/-sfPZtsyypsU/TmJMvd8hehI/AAAAAAAAAak/G2Ls7eyzs0Y/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2011-09-03+23.29.30.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;strike&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-sfPZtsyypsU/TmJMvd8hehI/AAAAAAAAAak/G2Ls7eyzs0Y/s1600/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2011-09-03+23.29.30.png" /&gt;&lt;/strike&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;img src="file:///Users/torufurukawa/Library/Application%20Support/Evernote/data/101370/content/p25532/b4d4b763606cb1a2597c10b767a11feb.png" /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;コードは動くけど、補完してくれなくて、それじゃあ何のために IDE 使ってんだよって話です（Emacs でも補完とかできるんでしょうけど、.emacs とか無理っす）。&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;[Eclipse]-[環境設定]-[PyDev]-[Interpreter]-[Python] を選択&lt;/strike&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;インタプリタ設定を選択してから、「Forced builtin」を選択。&lt;/strike&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;[New] ボタン → 「unittest」と入力する。&lt;/strike&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;&lt;br /&gt;&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;strike&gt;これが正しいやりかたなのか、まったく分からないわけですが、とりあえずこれで様子見です。&lt;/strike&gt;&lt;/span&gt;&lt;/div&gt;
&lt;div&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-6994675243339372162?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/09/eclipse-virtualenv-app-engine.html</link><author>noreply@blogger.com (Toru Furukawa)</author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-sfPZtsyypsU/TmJMvd8hehI/AAAAAAAAAak/G2Ls7eyzs0Y/s72-c/%25E3%2582%25B9%25E3%2582%25AF%25E3%2583%25AA%25E3%2583%25BC%25E3%2583%25B3%25E3%2582%25B7%25E3%2583%25A7%25E3%2583%2583%25E3%2583%2588+2011-09-03+23.29.30.png" height="72" width="72" /><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-3423981396381717887</guid><pubDate>Wed, 31 Aug 2011 23:08:00 +0000</pubDate><atom:updated>2011-09-01T08:08:23.942+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">Career</category><category domain="http://www.blogger.com/atom/ns#">Python</category><title>バスキュール号に入社しました</title><description>&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;@shin_no_suke&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;どういうことなの？ (hg)changeset:&amp;nbsp;&amp;nbsp; 164:aedce6151bf9 user:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Shinya Okano&amp;lt;...&amp;gt; date:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Wed Aug 31 17:23:39 2011 summary:&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; buchoはオワコン&lt;/span&gt;&lt;/blockquote&gt;
&lt;blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;( &lt;a href="http://twitter.com/#!/shin_no_suke/status/108831096287920128"&gt;http://twitter.com/#!/shin_no_suke/status/108831096287920128&lt;/a&gt;&amp;nbsp;より)&lt;/span&gt;&lt;/blockquote&gt;
&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;&lt;br /&gt;&lt;/span&gt;&lt;br /&gt;
&lt;!--?xml version="1.0" encoding="UTF-8"?--&gt;

&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;昨日で&lt;a href="http://www.beproud.jp/"&gt;株式会社ビープラウド&lt;/a&gt;を退職し、本日より&lt;a href="http://www.bascule-go.com/"&gt;株式会社バスキュール号&lt;/a&gt;で働きます。&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
なんで辞めるの？と聞かれるのですが、因果関係としては、ビープラウドを辞めるからバスキュール号に行くのではなくて、バスキュール号に行くのでビープラウドを離れます。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
以前、マーケティングをかじっていたことがあります。プロモーションのためのシステムを開発するという、バスキュール号のビジネスに関わりたいと思うようになりました。サーバサイドのエンジニアとしての採用ですが、企画にも口を出してよいということなので、そういう現場で働いてみたいという思いです。別に尻文字を間近で見たいからではありませんよ。見たいですけど。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
業務としてのソフトウェア開発未経験の私を拾ってくれて、ここまで育ててくれたビープラウドには感謝しています。技術的なスキルも、その他のスキルもまだまだビープラウドで学ぶ余地はいっぱいあるので、そこはもったいないなぁと思います。また、ちゃんとバリューを出せていたのだろうか、と憂うことなど多々あります。が、気に病んでいても私の価値は変わりませんし、私にとってのベストをつくしたので、評価はビープラウドのメンバーとそのお客様に任せるということで。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
仕事では当分 Python を使い続けますし、仕事におけるタスク自体は似ていますし、公私共にソーシャルグラフは大きく変わることはないので、これまでどおり、自分が出せるバリューを出していく所存でございます。&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="font-family: Arial;"&gt;
そうそう、&lt;a href="http://jobs.beproud.jp/"&gt;ビープラウド&lt;/a&gt;も&lt;a href="http://www.bascule-go.com/recruit/#job5"&gt;バスキュール号&lt;/a&gt;も、Pythonista を探しています。&lt;/div&gt;
&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-3423981396381717887?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/09/blog-post.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-7281732063102995368</guid><pubDate>Sun, 31 Jul 2011 09:08:00 +0000</pubDate><atom:updated>2011-07-31T18:33:51.642+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">書籍</category><category domain="http://www.blogger.com/atom/ns#">Development</category><title>バグの影響を伝播させないアプローチ - Michael T. Nygard / Release It!</title><description>&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;なんとか It! シリーズのひとつ「Release It! 」を読みました。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;航空券予約システムをダウンさせたバグの経験から始まります。&lt;/span&gt;&lt;br /&gt;
&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;極論を言うと、この種のバグがひとつ残らず消滅するなんて夢物語にすぎない。 バグは発生する。消えてくれないなら共存するしかない。 [...] この例で最悪だったのは、ひとつのシステムのバグが全システムに伝播して影響したことだ。答えるべき問いは、「ひとつのシステムのバグが他に影響するのをどうやって防ぐか?」である。 (p.21)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;バグの影響を伝播させないシステムの作り方、というのが、この本の「本番用システム」のあるべき姿です。その中からいくつかピックアップ。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;本番と同じサイズのデータセットでないと、クエリで数百万行が返っ てきて、それをオブジェクトに変換するときに何か起きるか確かめることかできない。本番と同じサイズのテストデータを使えば、パフォーマンステストでより良い情報が得られるという副次的な効果もある。 (p.93)&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;ダミーでいいから量をある程度用意するのはよいことだと思う。いまやっているプロジェクトでは、想定ユーザ数と平均的なユーザの典型的な行動パターン（つまり各URLのアクセス頻度）のシナリオを用意してもらえた。まだ調整中なのだけれど、どこがボトルネックになっているのか分かるし、優先順位も明らかになっている。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;待たせた結果がエラーメッセージであってはならないし、相手のタイムアウトまで待たせてもいけない。それでは、こちらの問題を呼び出し側に転嫁するだけだ。 (p.116)&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;フェイルファストっていうのは、なんか努力せずに諦めたみたいな感じがするんだけど、応答が遅い状態が長く続くくらいなら、さっさとフェイルして、アラートメールを出したほうがいい。どうせアラートメール出すハメになるのだから。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;開発プロジェクトか大忙しのときに、こうした設計についてのトピックを意識するのは難しいかもしれない。[...] そんなあなたにいいニュースかある。これらの問題を開発中に取り上げるのは断念してもいい。ただし、これは悪いニュースでもある。開発中に収り上げないなら、 本番で取り組むことになるだろう。&amp;nbsp;(p.235)&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;開発開始段階ですべての機能/非機能要件が決定されていない（つまりほとんどの）場合、最適な設計も最初に決定できないということになる。少し設計して、作って、また設計して、の繰り返しになるので、設計コストは増加する。そのかわり不適切な設計のままつっぱしって、システムがダウンするリスクを避けられる。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;今やっている案件でできていることは続けたいし、できていないことは今後やっていきたいものです。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: x-small;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-size: small;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;/span&gt;&lt;br /&gt;
&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=4274067491&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-7281732063102995368?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/07/michael-t-nygard-release-it.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-7348513109159810991</guid><pubDate>Mon, 11 Jul 2011 13:36:00 +0000</pubDate><atom:updated>2011-07-11T22:50:03.929+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">書籍</category><title>データではなくメソッドを学ぶ - 森博嗣「科学的とはどういう意味か」</title><description>&lt;div style="font-family: Arial;"&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;「信仰は科学です( ｰ`дｰ´)ｷﾘｯ」みたいなことを普段言っている割には、かなりな勢いで直感でものを考えているふるかわです、こんばんは。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;駅の本屋さんでふと目に止まって、森博嗣の「科学的とはどういう意味か」を買いました。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;人間にとって「気持ち」の影響力は大きい。けれど、いくら感動しても、いくら泣いても、飢えている人を救うことはできない。いくら一時の笑顔があっても、それは「解決」ではない。 (p.12)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;当たり前のことですが、つい忘れてしまいますね。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;こんなに大げさな話ではなくても、問題の解決にまったく寄与しないことが、自明であるにも関わらずやってしまうことってあります。目下の課題とまったく関係のない質問、誰にも聞かれていないし、役にもたたない発言など。そういうことに自覚的でありたいと思います。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;学科で教わることには、以上のように2種類ある。きっちりと分かれてるものではないけれど、大別すると、「データ（情報）」と「メソッド（方法）」だ。[...] これに対して、後者は、それらの材料を用いて加工する「方法」を憶えることになる。算数や数学というのは、一言でいえば「方法」なのである。 (p.35)&lt;/span&gt;&lt;/blockquote&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&amp;nbsp;「大学の研究室でやった研究で仕事してる奴なんか、ほとんどおらんで。ここは方法論を教えるところやから」と言ったのは、私が所属した研究室の先生の言葉でした。私は物覚えが悪いので、テストは常にひどかったですし、いまでもひどいです。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;仕方なく方法論を身につけようと思いました。なので、何か新しいことを知ったら、とくにそれが方法論であったり、解釈の仕方であったりすると、「この方法を違う問題に当てはめられないか」と考えます。いつも、ではないですが、そういうふうに考える傾向があります。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;それがどのくらい有効なのかよく分かりませんが、少なくとも私には役に立つ考え方であり、アプローチです。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;と、まあ、当たり前なことを、ドヤ顔で書いてみました。「こんなこと役に立つのかよ」って思い悩む、高校時代のときから余裕でプログラミングとかできている学生の役に立てば、と思いました。&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=4344982207&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/span&gt; &lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-7348513109159810991?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/07/blog-post.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-7046569871470830484</guid><pubDate>Sun, 10 Jul 2011 13:39:00 +0000</pubDate><atom:updated>2011-07-10T22:39:04.043+09:00</atom:updated><title>大阪国際トライアスロン 2011</title><description>&lt;span class="Apple-style-span" style="font-family: Arial;"&gt;大阪市此花区の埋立地であるところの舞洲（まいしま）で開催された、大阪国際トライアスロン舞洲大会に出ました。別にワールドカップとかではないです。&lt;/span&gt;&lt;br /&gt;
&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;てめー、この仕事の立て込んでるときに、と、言われそうではあるのですが、トライアスロンしなければ、きっと飲んだくれてるだけでしたので、まだ、マシであったと思っていただければ。スイム750m、バイク23km、ラン5km の短い距離でもありますし。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;スイムは大阪湾を泳ぎます。東京湾を泳いだこともあるし、汚いといっても知れているだろう、そう思っていた時期が私にもありました。ビニール袋が打ち上げられていると思ったら、鯛の屍骸でした。往復750mのコースを、岸と並行に泳ぐコースです。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;バイクは4周回で、23km。大井埠頭みたいなもんだろうから、大したことないだろう、そう思っていた頃が（以下略）。夢舞大橋という橋を往復するのですが、これがまあ坂です。しかも可動橋なので道路のつなぎ目が大きい段差になっていて、バランスをくずしやすいのです。バイクが下手な私は、下りのスビードをあげられませんでした。橋以外はコーナーが続き、こちらもスピード出しにくいです。アウターギアつかってない。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;埋立地のランなんてフラットだから楽勝だろう、そう思っていた頃(ry 。岸に沿った歩道を走るのですが、津波対策なのか、そういう景観狙いなのか、埋めたての土砂が余っていたのか、結構アップダウンがあります。ただ、変則片道2.5km のコースには、給水ポイントがわりとあります。500m ごとは言い過ぎかもですが、1kmよりは短い間隔で給水があります。ただし、水だけ。全体的を通して、日を遮る箇所がほとんどなく、かなり暑いです。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;JTU 公認のエリート部門もあるので、スタッフはたくさんいます。大阪の都市部でのレースの手軽さを求めるならよいかも。ちなみに電車は通っていません。オリンピック誘致できてたら、通ってたかもですね。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;そんなレースでした。&lt;/div&gt;&lt;div&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-7046569871470830484?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/07/2011.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-2571038445918725438</guid><pubDate>Sun, 12 Jun 2011 08:25:00 +0000</pubDate><atom:updated>2011-06-12T17:26:45.579+09:00</atom:updated><category domain="http://www.blogger.com/atom/ns#">書籍</category><category domain="http://www.blogger.com/atom/ns#">Development</category><title>節度をもって変化を抱擁する - アラン・デービス「成功する要求仕様 失敗する要求仕様」</title><description>&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;今の職場に入ったとき、初めてアサインされた仕事が要件仕様の定義でした。そのときに何冊か買った本のうちの、ひとつが、アラン・デービスの「成功する要求仕様 失敗する要求仕様」です。原題が「Just Enough Requirements Management - Where Software Development Meets Marketing」であるということに、今、気づきました。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;ケビン・フォースバーグとハロルド・ムーズによるNASAプロジェクト の研究によれば、NASA(米航空宇宙局)が要求活動を含む計画活動に開発予算の5パーセント以下しか充てなかったプロジェクトでは、総コストは40~170パーセント超過した(図1-11)。一方、NASAが全開発予算の10~20パーセントを計画活動に充てたプロジェクトでは、コスト超過は30パーセント未満だった。 (p.21)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;計画活動に時間をかけると、コスト超過が起こりにくい。デービスは他のところでも、この例を挙げて、計画に時間をかけるように勧めています。その最初の段階での成果物が、要件仕様、というわけです。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;私は、スケジュールが要求を決めるべきだと強く感じている。 (p.23)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;最大の不足するリソースは時間だということを考えれば、必然的にこういう方針になりますね。時間は貯めたり、借りたり、増やしたりといったことができない、とドラッカーが指摘していたと思います。もちろん、時間を節約するために、ヒト、モノ、カネを調達することはできるでしょうけれど、時間自体を増やすことはできません。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;どれだけ徹底的に導き出しを行っても、要求は変わっていくものだ。問題は変化していく。そして、問題に対する ステークホルダーの認識も変わっていく。要求を洗練させ、議論するうち、ステークホルダーは新しい要求をさらに思いつくはずだ。それでいいのである。ただ、変化に対する備えはしておこう。決してステークホルダーに「それで、これが最終的な要求なんですね?」などと言ってはならない。 &amp;nbsp;(p.55)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;耳が痛いです。最後の要求なのか、とつい聞いてしまいます。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;一方で、要求を決めないと、設計や実装ができません。だから、多くのアジャイルなプロセスでは、タイムボックスを区切って、その間は仕様変更をしないというプラクティスがあるわけです。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;しかし、約束してもいい。スピードと品質は両立できないものなのだ。 &amp;nbsp;(p.67)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;これは心しておかないと。そして、それを痛感するような経験もあります。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;ul&gt;&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;要求への変更は、善であり、悪ではない。&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;要求変更の流れを阻止しようとしてはならない。&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;要求変更の流れを管理できるようにならなくてはいけない。&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;どの要求を次のリリースに含め、どの要求を含めないかを決定するために、定期的にミーティングを開く。&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;10パーセント以上の要求変更を受け入れれば、プロジェクトは失敗するだろう。&amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;&lt;/div&gt;&lt;blockquote&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;(p.209)&lt;/span&gt;&lt;/blockquote&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;「変化を抱擁せよ。ただし、抱擁できる範囲で。」ということです。その手段として、さまざまなやり方があり、アジャイルな手法はこの前提をもっているように見えます。ですが、デービスはアジャイルがいい悪い、という見方ではなくて、要求のトリアージができるプロセスに、という立場をとっているようです。&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;br /&gt;
&lt;/span&gt;&lt;/div&gt;&lt;div&gt;&lt;span class="Apple-style-span" style="font-family: 'Helvetica Neue', Arial, Helvetica, sans-serif;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=4822282910&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/span&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-2571038445918725438?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/06/blog-post_12.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-243661093589624112</guid><pubDate>Sun, 05 Jun 2011 04:38:00 +0000</pubDate><atom:updated>2011-06-05T13:42:10.048+09:00</atom:updated><title>構成管理をちまちま始めるヒント集 - 「パターンによるソフトウェア構成管理」バーチャック、アップルトン</title><description>&lt;div style="font-family: Arial;"&gt;構成管理というは、開発プロセス全域に影響があるので、変化を起こすときに大変な思いをすることがあるんじゃなかな、と思います。プロジェクトの途中で、しかも、自分が下っ端だったり、いろんな事情で発言力が弱いときだってあると思います。どっかのこわい話とか、&lt;a href="http://togetter.com/li/74353"&gt;バージョン管理システムについて&lt;/a&gt; &amp;nbsp;の話題とか。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;そんなときに、この本のプラクティスをちょっとずつ実践することで、ちょっとずつプロセスに変化ができて、その変化に慣性がついてくれば、大きな変化になるのかも知れません。幸か不幸か、私の職場は mercurial + trac 、最近は　redmine ですし、多少ラディカルな変化も受け入れやすい体質なので、よく分かりませんが。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;すべての変更（とその依存関係）が、集約化された統合ビルドプロセス によってビルドされるかどうかを確認して下さい。 p.114&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;Python のウェブアプリの場合は、本番環境へのデプロイも含まないといけませんね。実行時まで分からないことが多いというのは、こういうとき割と不便です。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;新しいメジャーリリース用にコードラインを分岐する時が来たら、前回のリリースラインから新しいリリースラインを分岐する代わりに、まず前回のリ リースラインを本流にマージして下さい。そこから新しいリリースラインを分岐してドさい。 p.62&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;まず、現行最新版の変更を、メインの開発作業に取り込め、ということですね。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;バージョン管理システムを使って、ベンダから受け取ったソフトウェアのバージョンと、顧客に配布したソフトウェアの両方を管理して下さい。 p.123&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;どっかから拾ってきたライブラリを使用するときには、(1) 本家から引っ張ってきたコードを保持するブランチ/リポジトリ、と (2) そのコードを自分で変更したコードを保持するブランチ/リポジトリで管理せよ、ということです。本家でバージョンアップがあったら(1) に取り込み、つづいて、(1) を (2) に取り込む、ということです。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;フレームワークが大きくバージョンアップするような場合には、そうはいきませんが、それはまあアプリケーションからみたら、プラットフォームが変更されるということなので、ここでの議論の対象外です。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;それぞれのビルドをすべてスモークテストの対象とし、アプリケーショ ンがあまりにも明らかな形で動かなくなることがないように検証しましょう。 p.145&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;スモークテストというのは、機械の箱を開けて修理したあとに、電源を入れたときに煙が出ないか確認する、というのが語源です。つまり、よっぽどひどいコード変更をしていないのか、というののテスト。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;API を提供するサーバ開発と、JavaScript や Flash で書かれたクライアント開発が、別組織になっているときのデバッグ中に使いました。各 API 個別のテストはもちろん書いてあるのですが、それとは別に、ちょっとした変更を依頼されたときに、スモークテストを走らせていました。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;回帰テストのテストケースは、以下の項日から構成するとよいでしょう。&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;- リリース前の品質保証プロセスで見つかった問題。&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;- 顧客およびユーザから報告された問題。&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;- 要求什様に雌づくシステムレベルテスト。&amp;nbsp;&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;p.158&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;（テストがないという意味での）レガシーコードを触るときに、これやりますね。まず fail するテスト書いて、修正して、pass させる。それを回帰テスト（ユニットテストに含めるにしろ、より上位レベルのテストになるにせよ）として残す、と。レガシーコードをいじるときには、いきなり全部のテストを書くわけにもいかないので、変更/修正する箇所から段階的に追加していくことになるかと。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;リリース済みバージョンと次回リリースの開発を同じコードラインで対応しようとするのではなく、保守用と継続開発用でコードラインを分割しましょう。 p.171&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;よい子のみんなは、きっとやっているよね ♡&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=4798112593&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-243661093589624112?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/06/blog-post.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-6285823581271308500</guid><pubDate>Sat, 28 May 2011 03:35:00 +0000</pubDate><atom:updated>2011-05-28T12:36:27.744+09:00</atom:updated><title>メタ認知のヒント: Andy Hunt 「リファクタリング・ウェットウェア - 達人プログラマーの思考法と学習法」</title><description>&lt;div style="font-family: Arial;"&gt;転職するときに、以前の職場の上司からもらった本です。当時はピンとこなかったけれど、今読み直すと理解できるようになりました。同時に、この1年何をしてたんだという後悔も。まあ、後悔は毎日のようにしているので、慣れっこです。なんで、もう一度念入りにおしりを拭かなかったのだろう、とか。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;格言とは、その状況に応じて臨機応変に解釈が可能な基本的な 原理・原則です。 (p.11)&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;レシピと格言とは異なるのもなのですが、混同されていることがあると思います。この本でも、疑わしければユニットテストしろ、というのをレシピと取るか、格言と取るかで、具体的な行動や判断基準が変わってくるとあります。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;プロジェクトの終わる瞬間が知力のビークであり、開始時点ではもっとも低いということです。これでも、早い段階で決断を下すのが賢明な判断だと思えますか? (p.113)&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;アジャイルなソフトウェア開発は不確実な状態での作業を許容する方法論です。 最初のうちはプロジェクトの最終日が本当はいつになるのかわかりません。次の反復でどの機能が採用されているかは100%確実にはわかりません。反復が何回あるのかわかりません。でもそれでまったく問題ないのです。その不確実性に浸る心地よさを味わえるようになればよいのです。進んでゆく過程で徐々に答えが見つかり、最後にはすべての答えが出ています。 (p.114)&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;時間がたつほうが判断が正しくなり、時間が早いほうが残り時間が多くなります。そのトレードオフであると考えるといいのかも知れません。ういうモデルでプロジェクトを考えてみると、「アジャイルと規律」なんかで言われていることと一致するのかも。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;最低限の時間を定期的に投資すると決めてしまうのです。[...] その時問すべてが等しく生産的になるとは限りませんが、定間的に予定に組み込むことで、長い目で見るとうまくいくでしょう。 (p.151)&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;長い目でみるとうまくいく、っていうのは、安心と自信を与えてくれる。おそれずにやっていこう。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;blockquote&gt;しかし「最初からうまくいく」ことが大切なのでは なく、「最終的にうまくいった」ということが重要なのです。 (p.184)&lt;/blockquote&gt;&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;これは斬新。いままで失敗は悪だと思い込んでいた。最終的にうまくいく過程で、失敗できるようリスクを最小化すればよいのだ。一発成功を狙うほうがはるかにリスクが高い。&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;&lt;br /&gt;
&lt;/div&gt;&lt;div style="font-family: Arial;"&gt;と、まあ、Andy Hunt が書いているということもあって、最終的にはアジャイルな話になってきました。それでも、長期的な学習や、そのメタ認知の視点のヒントがありました。実践してうまくいったらものがあれば、また、どこかで書きます。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=4873114039&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-6285823581271308500?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/05/andy-hunt.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item><item><guid isPermaLink="false">tag:blogger.com,1999:blog-5592148.post-5677016931471701818</guid><pubDate>Sat, 28 May 2011 02:12:00 +0000</pubDate><atom:updated>2011-05-28T11:12:05.515+09:00</atom:updated><title>村上龍 / ラッフルズホテル</title><description>本棚を整理していたら、村上龍の「ラッフルズホテル」なる小説が出てきました。あーこれ読んでなかったわーと思って、読んでみたら、読んだことある本だった。後半まで気づきませんでした。&lt;br /&gt;
&lt;br /&gt;
&lt;span class="Apple-style-span" style="font-family: arial, helvetica, osaka, 'MS PGothic', sans-serif; font-size: x-small;"&gt;&lt;iframe class="ap_never_hide" frameborder="0" id="served_preview" marginheight="0" marginwidth="0" scrolling="no" src="https://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&amp;amp;bc1=000000&amp;amp;IS2=1&amp;amp;bg1=FFFFFF&amp;amp;fc1=000000&amp;amp;lc1=0000FF&amp;amp;t=addicted2inde-22&amp;amp;o=9&amp;amp;p=8&amp;amp;l=as4&amp;amp;m=amazon&amp;amp;f=ifr&amp;amp;ref=ss_til&amp;amp;asins=408749828X&amp;amp;internal=1" style="height: 240px; width: 120px;"&gt;&lt;/iframe&gt;&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/5592148-5677016931471701818?l=torufurukawa.blogspot.com' alt='' /&gt;&lt;/div&gt;</description><link>http://torufurukawa.blogspot.com/2011/05/blog-post_28.html</link><author>noreply@blogger.com (Toru Furukawa)</author><thr:total>0</thr:total></item></channel></rss>

