Feeling Transfer Protocol

何か心が動いた時とかに衝動的に気持ちを発信するツール

メモ化についておさらい

フィボナッチ数列を求めるプログラムを例に、
メモ化についてサクッとメモをしておく。

#!/usr/bin/python


def fib(n):
    u"""
    フィボナッチ数列でn番目に来る要素を返す
    """
    nums = []
    f, s = 0, 1
    while len(nums) <= n:
        nums.append(f)
        f, s = s, f+s
    return nums[n]


def memoFib():
    u"""
    フィボナッチ数列生成のための関数を返す
    """
    memo = [0, 1]
    def fib2(n):
        u"""
        フィボナッチ数列でn番目に来る要素を返す
        """
        if len(memo) > n:
            return memo[n]
        else:
            memo.append(fib2(n-2) + fib2(n-1))
        return memo[n]
    return fib2

if __name__ == '__main__':
    count = 4000

    print "non memo start !!"
    for x in xrange(count):
        fib(x)
    print "non memo end"

    print "memo start !!"
    f = memoFib()
    for x in xrange(count):
        f(x)
    print "memo end"

作成したのはフィボナッチ数列のn番目の要素を返却する関数。

まずfib関数。
こいつは素直にフィボナッチ数列を求める関数。
初期条件(f, s = 0, 1)揃えて、while文の中でfとsをそれぞれ更新していく。
そうしてnums配列にフィボナッチ数列が溜まっていくようにして、
溜まったnums配列のn番目を返してやれば条件を満たす関数の出来上がり。

次に少し複雑なのがmemoFib関数。
こいつはmemoという初期配列を用意して、
fib2という内部で宣言した関数を実行せずに返す。

返ってきたfib2を使ってフィボナッチ数列のn番目の要素を求めるように作った。

fib2も作りは単純な再帰処理で、
再帰の最終点(この場合はlen(memo) > nの状態)での処理を書いて、
それ以外のときは自分を呼び出した結果を用いてmemo配列に要素を追加する。

上記の内容を実行すれば明白な実行速度差が確認できる。
本来ならベンチを取ってどのくらいタイムが縮まっているかを測って書いておこうかと思っていたが、あまりにも一目瞭然で、memoFibを使った方ははっきり言って爆速。

しかし逆に、内部的に再帰処理を持っているため、
何も設定値を変更していなければ、
pythonのデフォルト再帰呼び出しの上限に引っかかりポシャる。
例えばfor文で回さずに、いきなりf(4000)を呼び出すとエラーでコケる。

先ほどメモ化の方は爆速だとのたまったが、
それはこのケースに関しては至極当然の話で、
memoFibの返す関数は過去の実行結果が存在すればその時点で計算が終わる。
つまり「関数が複数回呼ばれる」というケースに対して非常に特化しているといえる。
っつかメモ化って複数回呼ばれるケースに対して特化した最適化手法だと思う。

そもそも上記の例は、詐欺的なやり口でメモ化を押し売るときに使うようなものだ。

なぜならこの例だと、fib関数は最終的なfib(n)を求めるためにfib(n-1)もfib(n-2)も、
一から計算し、しかもせっかく計算した結果は放棄している。
つまりn番目の値を求める前に無駄な計算を山ほど行なっていることになる。
fib関数を作った人間は普通このような使い方はしない。

本来フェアに速度を戦わせるのであれば、下記のようにすべきである。

if __name__ == '__main__':
    count = 200000

    print "non memo start !!"
    fib(count)
    print "non memo end"

    print "memo start !!"
    f = memoFib()
    for x in xrange(count):
        f(x)
    print "memo end"

こうすれば両方共、最終的な結果を得るための計算を一度しか行わない。
上記を実行した結果、両者は同じくらいの速度で結果を返してきた。
そのため今度はベンチマークを取って実行速度を比べてみる。

if __name__ == '__main__':
    import time

    count = 200000

    start = time.time()
    fib(count)
    end = time.time()
    print end - start

    start = time.time()
    f = memoFib()
    for x in xrange(count):
        f(x)
    end = time.time()
    print end - start

上記実行結果がこちらである。

2.32484006882
2.04464197159

何度やっても0.3秒ほどメモ化の方が速い結果となった。 

個人的にはメモ化の方が遅いだろうと思っていた。
それは中で毎回if文を実行しているのと、
for文でxの値をインクリメントする処理が入っているから。

しかし、結果はそれでもメモ化の方が速いと出ている。
が、上述した自分の感覚が間違っているとはどうしても思えない。

ので一旦ここでの結論は下記としておく。
・メモ化が使える場所で使うと、実行速度は上がる
・自分の想定と食い違ったのは下記のような要因があるものと思われる。
・・time.timeを用いたベンチマークの精度が悪い
・・fib関数に無駄が存在する
・・コンパイラがifやインクリメント等の処理を最適化したためほぼノーコストだった

また元気があるときに、
気が向いたら上記の結論を再検証してみる。

Chrome Developer tools font size

Google Chrome の Developer toolsでハマったのでメモ。

ある日、
ページの文字を大きくして見ようと思い、
確かショートカットで「Command」+「+」とかあったなーとか思い出して、
実際キーボードでは「Command」+「Shift」+「;」と押してみた。

すると、
おお!閲覧ページが拡大表示されるではないか!
えいっ、えいっ・・・
っと調子にのって大きくしすぎたので、
今度は逆の「Command」+「-」で小さくっと。

えいっ、えいっ・・・

ん??

一向に小さくならないってあれ?
Developer toolsの文字がやたら小さくなっとる・・(´・ω・`)ショボーン

ここで自分が「Command」+「-」のつもりで、「Command」+「Shift」+「-」としていたことに気づく

今度こそ、
「Command」+「-」で。
えいっ、えいっ・・・

うん小さくなった。


けど、
Developer toolsの文字サイズはどうやって治すんだろう??
さっきまではどうも「Command」+「=」で文字を小さくしてしまったようなんだけど・・・

とハマリにハマった挙句、
いろんなショートカットを闇雲に試した結果、
Developer toolsの文字サイズを大きくするには「Command」+「^」であることを知った。

文字サイズが小さすぎて、
configのボタンも識別できず、
その他オプションなどでもサイズ変更に至らなくて、
絶妙に嫌な汗をかいていたのだが、
解決してよかった。

引越し業界の闇

この度、目黒から埼玉へと引越しをすることに相成りました。

というのも、ここ1年半ほど同棲をしていたのですが、
築50年越の1Kで管理費込で家賃8万円という、
なんともまぁ微妙な物件に住んでおりまして、、、。

そもそも26にして同棲をしていて、
何が辛いかってプライベートが全くないことなんですね。

家に帰ったら彼女が常に自分が何しているのかを見ていて、
通勤中の電車では同じ車両に乗った人の目が見ていて、
会社では同僚達に見られているわけじゃないですか。

別に悪いことしたいわけでも無ければ、
人に見られてやましいことがあるわけでもないですし、
彼女はともかく、通勤電車の人や同僚がそこまで自分に注目しているわけではないのですが。
やはり人間、一人で好きなことに時間を割きたいことも多々あるわけで。

そこで自分の部屋を得るべく引越すことにしたのです。
ただ、まだまだ薄給の手前、家賃額を増やすのには抵抗がありまして、
同じ8万円という価格帯でかつ、部屋が多い、
通勤でそこまで苦労しない場所というので、埼玉に住むことになりました。

住む場所は不動産ポータルサイトのHOME'Sにお世話になって、
見つけた家に問い合わせを行い、
連日不動産会社を巡っては希望・条件などを突きつけて探して見つけました。

不動産会社の人間は、個人的にはとても好きな人種で、
竹を割ったような爽快さと、根性。
話も盛り上がりますし、自分はエンジニアなので「良い営業」とかの持論は持ちあわせておりませんが、
とてもああいう人たちは好きですね。


その半面、引越し業界はとても闇だと感じてしまいました。


まぁ家が決まると、
いつから鍵を渡されるか(もちろんそれは家賃の発生を意味する)って話になるわけですが、
鍵を渡されたまま家を放置すると、家賃が発生していますので、住み始めないと損するわけで。

けど、家具がないことには生活もままならないなら、
引越しで家具を持ってこなくてはならないんですね。

これまで親まかせに生きてきた手前、
その辺の事情に精通していなかった僕は、
またHOME'Sにお世話になって引越し業社を探しました。

一括問い合わせというサービスで、
住所を書いて電話番号を書いて、運んで貰いたい荷物のチェックを入れて、
いざ送信!これで各業社から、「うちなら幾らでやるよ!」てきなメールが殺到して、
うまく相見積もりすればちょっとお得に引っ越せる!なんて考えていたのですが。。。

ちなみにこの一括引越しサービスで送信したのが、
諸事情により朝4:00頃だったのですが、
一番はじめにレスポンスがあったのが、朝4:05。
レスポンス方法電話。

さて、引越しの見積もり依頼も出したし、
そろそろ寝るかって時に震え出す電話。

え?なに??
と思い、フリーダイヤルからの着信を受ける朝4:05

「もしもし?お問い合わせいただいた○○社です!」
「はい。。」
「引越しに関しまして今から2,3分お時間いただけないでしょうか?」
「すみません、そろそろ寝るので明日にしてもらえないでしょうか?」

個人的な意見ですが、
ちょっと非常識すぎませんか?

こっちが電話したならいざ知らず、
Webサービスで問い合わせているのに、
時間帯も考えずに電話ですよ??

人によったらもしかしたら、
cron登録でサービス問い合わせしてることだってありえるじゃないですか?
まぁその例はあまりに稀有ですけど、
にしたって、朝4:00のレスポンスは非常識だと感じました。

それからというもの、
サイトからは15社程度に見積もりを行ったのですが、
毎日電話三昧。

うめつくされる着信履歴。
フリーダイヤルは出ないって決めてても、
ケータイと思しき番号からも着信が。あれ?誰か番号変えてたの登録してなかったかな?
とか思ってでるとやっぱり「すみません、引越しの○○社です!」

挙げ句の果てには僕がソフトバンクであることを見越してか、
インスタントメッセージを飛ばしてくる強者まで現れました。

不動産会社が、問い合わせに対して、
しつこく噛み付いてくるというのは聞いていたのですが、
不動産会社ではなく、引越し業者の方がかなり手口が悪い印象を強く受けました。

明らかにコールセンターから、
電話に出た時も第一声が「もしもし?」とか普通。
まぁ別に自分の常識を押し付ける気はありませんが、
気分よく建設的な会話をする上でのマナーとか態度ってあるじゃないですか?

特にひどかったやり取り

「もしもし?○○社ですけど」
「はい?」
「引越しの○○社ですけど。」
「ああ、はい。」
「この度は電話見積もりという事でよろしかったでしょうか?」
「いえ、メールで見積もりというサービスで問い合わせたのですが。」
「あぁ、うちメール見積もりやってないんですわ」
「?けどこちらはメール見積もりで・・・」
「電話見積もりでよろしかったですね?」

ツー、ツー、ツー

とまぁ、そんな引越し業界の闇を一身にうけ、
精神的な摩耗をしたため、同じ苦しみを味わう人がなるべく少なくなるよう、
この場で少し実態を共有させて頂きました。

一括問い合せ自体はそれ以上に楽で効率のよい方法はあまりパッとは思いつきませんが、
それをした結果、着信の嵐になることは、予め覚悟した上で、
申し込みをしたほうが、精神的には健全でいられるのではないでしょうか?

なんせまぁ引越し業界はまだまだ発展途上と言わざるを得ないですね。

とあるnosetestsコマンドのあれこれ1

pythonのnoseモジュールのお話

※ インストール

pip install nose


例えば下記のようなsample_test.pyを書いておいて、

#!/usr/local/bin/python
# -*- coding: utf-8 -*-

class TestSample(object):
    """This is sample test."""

    @classmethod
    def setup_class(cls):
        """set up for class"""
        print "this is setup_class."

    @classmethod
    def teardown_class(cls):
        """tear down for class"""
        print "this is teardown_class."

    def setup(self):
        """set up for test case"""
        print "this is setup."

    def teardown(self):
        """tear down for test case"""
        print "this is teardown"

    def test_A(self):
        """sample test case A"""
        print "this is test case A."

    def test_B(self):
        """sample test case B"""
        print "this is test case B."

    def test_C(self):
        """sample test case C"""
        print "this is test case C."
        assert False
nosetests sample_test.py

みたいな感じでサクッと実行すると、

/home/user% nosetests sample_test.py
..F
======================================================================
FAIL: sample test case C
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/user/sample_test.py", line 37, in test_C
    assert False
AssertionError:
-------------------- >> begin captured stdout << ---------------------
this is setup
this is test case C.

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 3 tests in 0.002s

FAILED (failures=1)

ってな出力がなされて、無事テストが通ったことがわかります。
も少し分かりやすく表示したい場合は、nosetestsコマンドのオプション -vをつけて、
verboseモードで実行してやると良いでしょう。

/home/user% nosetests sample_test.py -v
sample test case A ... ok
sample test case B ... ok
sample test case C ... FAIL

======================================================================
FAIL: sample test case C
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/user/sample_test.py", line 37, in test_C
    assert False
AssertionError:
-------------------- >> begin captured stdout << ---------------------
this is setup
this is test case C.

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 3 tests in 0.004s

FAILED (failures=1)

無愛想な「..F」という記号の代わりに、
今度はdocstringが出力され、その結果okだったのかFAILだったのかが出力されています。

さらに、これまでの例ではprint文が全く出力されていないことに気が付きます。
そこでつけるオプションが -sです。
これはnoseのキャプチャリングをキャンセルするオプションです。

/home/user% nosetests sample_test.py -s
this is setup_class.
this is setup
this is test case A.
this is teardown
.this is setup
this is test case B.
this is teardown
.this is setup
this is test case C.
Fthis is teardown
this is teardown_class.

======================================================================
FAIL: sample test case C
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/local/lib/python2.7/site-packages/nose/case.py", line 197, in runTest
    self.test(*self.arg)
  File "/home/user/sample_test.py", line 37, in test_C
    assert False
AssertionError:
-------------------- >> begin captured stdout << ---------------------
this is setup
this is test case C.

--------------------- >> end captured stdout << ----------------------

----------------------------------------------------------------------
Ran 3 tests in 0.003s

FAILED (failures=1)

これで、各setupやteardownがどの順で呼ばれているのかが明確になりました。

では本日記の最終内容。

それは、あるテストケースのみをテスト実行したい時の方法

【方法1】

from nose.plugins.attrib import attr

# ... (間は省略します)

@attr(now=True)
def test_A(self):

# ... (以下省略)

実行したいテストケースの上にデコレータを書いておいて、

nosetests sample_test.py -a "now"

で実行。

/home/user% nosetests sample_test.py -a "now" -v
sample test case B ... ok

----------------------------------------------------------------------
Ran 1 test in 0.002s

OK

【方法2】

/home/user% nosetests sample_test.py:TestSample.test_B -v
sample test case B ... ok

----------------------------------------------------------------------
Ran 1 test in 0.001s

OK

もう一つの方法がこれ。
コロンつなぎでクラス名、テストケース名として指定するパターン。

中々色々あって、勉強し甲斐がありますなー。

タグ付けする奴作ってみた

タグ付けする奴を作ってみた。

そもそも詳細をお話する前に、自身について少し話す。
自分は会社ではQAエンジニアを名乗らせていただいている。
小生がQAエンジニアを名乗るなど本当に生意気で、
会社ではいつも申し訳ないという気持ちと、
大きな衣装が早く体に合うように大きく成長したいという2つの間で仕事に励んでいる。


ところで自分の会社ではQAグループは出来てまだ日が浅く、
豊富な人材が割り当てられているというわけでもないため、
なかなか本来やりたい業務というものに力を割けずにいる。

そんな中、自分勝手ではあるが、自分にはどうしてもやりたいことがあり、
それは過去の障害の分析を元に、将来の障害を予防するといったものである。

過去の障害を分析することで、自社で起きやすい障害や傾向などをつかむことが出来れば、
そのデータを元に周囲を納得させ改善につなげることが出来るのではないかという想いからである。


さて前置きが長くなったが、そこで件のタグ付けする奴である。
コードは下記

http://www.u--u--u.com/open/mkTag/jqueryUiSample.html

タブが複数あり、そのタブの中には一段粒度の細かいタグが入っている。
タブ自体はjQueryUIのtabsで簡単に表現可能である。
タブの切り替えにより、コンテンツが切り替わる仕組みがこんなに簡単に表現できるとは、
もうDOMを触る上でjQuery無しというのは中々難しい時代になっているなといった具合である。

そして各タブ内のタグはこちらもまたjQueryUIによりdraggableとなっており、
上部にある黄色の枠内にdroppableとなっている。

本来は、ある一つの障害に対してこのUIを提供し、
その障害に当てはまるタグを追加してもらう。
例えば「セキュリティ」というタブには「XSS」や「CSRF」などのタグがあるだろう。
「人的ミス」のタブには「タイポ」や「ファイル上げ漏れ」などのタグがあっても良い。

一つの障害に対し、そういった複数のタグ付けを行うことで、
あとから障害をまとめて整理しやすく、また分析しやすい状態を目指す。


よって、上記のUIはあくまでまだ一端であり、
本来はこれにたいして、ID指定で障害の情報を取ってくる部分を実装したり、
保存でDBに書き込んだりと、サーバサイドもしっかり書かないといけないだろう。


ただ、まぁ不完全ではあるが、
一応当たり前といえば当たり前だが、
障害に対しタグ付けを行う際、あとからタグをとることも考えて、
dropした時に、テンプレートを挿入するように実装している。
draggableはhelper属性を"clone"とすることでかのようなUIを実現し、
テンプレートにはspan要素で「x」という閉じるボタンを実装している。

また同じタグが複数並ぶのを良しとしたくないので、
そこは一度すでに並んでいるタグをパースし、
同じタグがあれば、点滅してすでに存在することを示してやることにした。

足りていない部分としては、
タブとタグの追加機能である。
ブラウザのタブのようなUIでタブの追加を許し、
同様にタグの追加も許したいなと思っている。

抱負 兼 自己紹介

社会人生活早二年。

気づけばもう三年目に突入している。

入社当時からの想いが未だ強く、三年を節目に自己成長のための転職を視野に入れようと思う今日。 それを一つのきっかけに時代錯誤ではあるがブログを始めようと思う。

このブログには自分にとっていくつかの意味がある。

第一に文章力の向上。 誰かに何かを文章として伝えることをこれまで嫌厭してきたため、 すっかり素直な情報発信力が皆無と化してしまった自覚がある。 お陰で日本語もとてもへんてこな具合になっている事は容赦いただきたい。。

第二に情報発信力の向上。 思ったことや検証したこと学んだことを体験記として書き込み、 それを「価値」として受け入れてもらえるなら僥倖。 批判され「持って無かった視点」を得られるならそれもまた良く、 何よりもこのブログを通して、社外の人と知り合えると最高だと思う。

このブログは、 頑張って少なくとも1年間は続けたいと思う。 これまで数多のブログを開設しては三日坊主で亡き者にしてきたが、 今回は頑張ってみようと思っている。

あと、このブログでは、 Webに関して書くつもりでいる。 それはJavaScriptももちろんそうだし、Pythonや、 あるいはRHELなどのサーバサイドのお話もしていきたい。

自分としては自信をアプリケーションエンジニアであると思いたいし、 そうあるようにする努力は苦痛ではない。 ただ、だからといって実装ばかりにとらわれるのではなく、 「常識」としてサーバのこともある程度わかるし、 プログラマだけどHTMLやCSSについてもあまりちゃちなコードは書きたくないなと思っている。

別にこんなオナニー記事を書くために一念発起して立ち上げたブログではないので、 このへんで歯切れ悪く終わっておく。 これから幾らかの記事を書いていく中で、 自分の伝えたいことを完結に伝えられる文章力が身につくと良いなと切に思う。