ページ

2010年10月28日

MBA11環境構築編

ちびえあたん(MacBook Air)は、ちっこいのでCPUは非力です。Mac Portsのようなエネルギーを無駄使いするシステムにはちょっときついです。「エコな若者はHomebrewです。」といろいろな人が言うので、Homebrewを使うことになりました。

インストールは、
$ curl -O http://gist.github.com/raw/323731/install_homebrew.rb
$ ruby install_homebrew.rb
です。途中パスワードを聞かれるんで、おそるおそる入力します。しばらくすると終わっています。/usr/localが下々のものでも書き込めるようになっています。

さて、とりあえず、
$ brew install git
でgitがインストールできることを試してみます。brew install mercurialとしたらpipとかpythonをまずインストールしろと怒られます。人はシステムに従います。
$ brew install python
気がつくとpythonがインストールされています。2.7です。2.6がよかったな・・・。次に
$ brew install pip
ちゃんとインストールできるようです。virtualenvを入れようと思って
$ brew install virtaulenv
とすると、pipをインストールした後にpip install virtualenvしろと怒られます。怒るくらいなら、勝手にインストールすればいいのに・・・。でも、やっぱり人はシステムに従います。
$ pip install virtualenv
$ pip install virtualenvwrapper
ここまでやって、Mercurialをインストールしようと思っていたのを思いまして、brew install mercurialってやってもいうことを聞いてくれません。
$ pip install mercurial
がお作法のようです。ここまでがいつもPythonの本体にインストールするモジュールです。あとは、virtualenvの環境下にインストールします。

mercurialをインストールしても/usr/local/binにはインストールされません。なので、
$ ln -s /usr/local/Cellar/python/2.7/bin/hg /usr/local/bin
しておきます。ついでなので、virtualenvの環境を一個追加します。.bashrcに
export VIRTUALENVWRAPPER_PYTHON=/usr/local/bin/python
export WORKON_HOME=$HOME/.virtualenvs
source /usr/local/Cellar/python/2.7/bin/virtualenvwrapper.sh

を追加して、mkvirtualenv mainでメインの環境が一個できあがり。いろいろ抜けていそうな気がしなくもないですが・・・。

27インチiMacにいらいら

今年の夏に我が家にやってきた27インチiMacは画面はとてつもなく広いし、CPUは高速だしとても快適なマシンでした。満足度も極めて高いマシンでした。このまま3年かそれ以上、何もせずにその満足を享受できるはずでした。そう、MacBook Airを店頭で触るまでは・・・。

店頭で触ってみて、MacBook Airと言うよりSSDのすごさに驚かされました。まったくの引っかかりがありません。常に高速で動きます。そして、短い時間店頭で触って分かったことは、ほとんどの作業のボトルネックはハードディスクとのIOにあるんだと分かりました。SSDだとswap in/outを感じさせないぐらい速いというのを見て、メモリサイズもボトルネックじゃなくなりつつあるのかと、驚きました。最もSSDにそんなに頻繁に書き込んで寿命は大丈夫かいなと思わなくもないです。

で、それがそもそもの不幸の始まりでした。でかいデスクトップにはノート以上の性能を求めてしまいます。そして、ハードディスクとのIOの引っかかりがどんどん気になり始めます。SSDにすれば、爆速になるんじゃないかという妄想にとりつかれ始めます。人間の欲望にはキリがありません。いや、そんな大それた話じゃないですね。

Airの起動速度とか、スリープというか、多分ハイバネートからの復帰のスピードとか騒いでいますが、Windowsと違って少なくとも一度立ち上げたらOSのアップデートがかかるまでシャットダウンしないので そこはあんまり重要じゃないかな。普段の操作で全く引っかからないのがうらやましい限りです。

まだ、SSDの容量はそれほどでっかくないですが、Airと同じスピードで512GのSSDが3万円ぐらいになったら欲しいです。



2010年10月26日

gevent的websocket生活

IE9での実装は見送られて悲しいwebsocketで遊んでいたのはもう、一年近く前のことになります。そのときに書いたチャットのサンプルコードですが、サーバサイドはgolangで書いていました。golangはとっても好きな言語なのですが、Python、特にgeventはどうなのかな?と思って調べてみました。単にネタがなくってwebsocketに走ったと言えなくもないです。ごめんなさい。

geventでwebsocketってどうするの?と。twistedであれば、かなり独自のコードを書いて独自の処理を追加しないと行けません。Python界隈ではwsgi全盛の今となってはそれはないよね!と。今時のPythonの人はwsgiのミドルウェアを使ってwebsocketをやるもんだぜ!えっ?geventはどうなって?Flaskでも動かしてやって、イベントループをgeventを使うようにして、monkey patchをあてれば、同期処理で動いてたwebsocketが非同期になって、C10K問題も解決だぜ、ベイビー。おしまい。

まあ、ことはそれほど単純じゃないですし、それだけだとつまらないので、geventでwebsocketを扱うgevet-websocketで書いてみます。昨日、Komodo Editを使うって宣言しておきながら、Emacsで書いています。はい。軟弱ものです。gevent-websockeはpip install gevent-websocketでインストールできます。

基本的にクライアントのコードは一年前とほぼ同じものです。ここにコードのすべてがあります。

from geventwebsocket.handler import WebSocketHandler
from gevent import pywsgi
import gevent

chat_clients = set()

def handle_chat(ws):
    chat_clients.add(ws)
    while True:
        message = ws.wait()
        if message is None:
            break
        for client in chat_clients:
            client.send(message)

    chat_clients.remove(ws)

def app(environ, start_response):
    path = environ["PATH_INFO"]
    if path == "/":
        start_response("200 OK", [("Content-Type", "text/html")])
        return open("chat.html").readlines()
    elif path == "/chat":
        handle_chat(environ["wsgi.websocket"])
    else:
        start_response("404 Not Found", [])
        return []

if __name__ == "__main__":
    server = pywsgi.WSGIServer(("", 5000), app, handler_class=WebSocketHandler)
    server.serve_forever()



geventには、wsgiとpywsgiという似たようなものが二ついます。一時pywsgiはobsoleteの警告が出ていたのに、最新版ではでなくなっています。二つの関係がよく分かりません。pywsgiのWSGIServerにWebSocket用のHandlerを渡します。このHanlderはクライアントがWebSocketとしての接続を要求してきたらWebSocketとして処理できるようになります。それ以外は通常のWSGIとして処理します。
WSGIのミドルウェアと違ってhandlerがenvironにwsgi.websocketにwebsocketのオブジェクトをセットします。
WebSocketで実際のロジックはhandle_chatのところです。めちゃくちゃ簡単ですね。golangのコードと大差ありません。

wsgiのインターフェースでこんな風に長時間の接続を処理するのは向いていないと思っていました。でも、計量スレッドのようなものたちの上で動かせば、そこそこ行けるんじゃないかと思い始めました。でもApacheのような人(同期IOで処理する人)がフロントにいるような環境だとやっぱり無理っぽいな〜、と。

もし、gevent-websocketのコードの説明を始めたら、それはネタがない証拠です。

でわでわ。

工場見学に行ってみた

最近は工場見学が流行っているらしいので、アサヒビール神奈川工場に工場見学に行ってみました。見学後にビールが3杯タダで飲めます。お得です。でも、僕はドライバーなので、見ているだけです。代わりにお子様用ソフトドリンクか、大人用ノンアルコールビールが飲めます。僕はサイダーを飲みました。サイダー好きなんです。工場はかなり田舎にあるので、車で行かなかった場合は電車とバスを乗り継ぎます。バスの値段を見ると、最寄りの駅まで片道1000円ちょっとでした。ビールがタダ、と言うことに釣られていくと、かえって損ですね。

さて、工場見学で中に入って、とあるモニターを見ると、こんな画面が・・・。

なかなか素適です。某会社のOSのブルースクリーンっぽい画面を表示していました。

さて、工場見学は、まあ、子供は楽しかったようです。まりあ先生はかわいかったです。でも、工場の中には人はいませんでした。すべてロボットが猛烈な勢いでビールを造っているそうです。 パッケージングした後の倉庫への搬入までロボットがやっている映像がありました。フォークリフトが無人で動いているらしいです。凄いです。人の手で作られていないのは寂しいとか良くないとか言う思想を僕は持ち合わせていないので、機械でほとんどできるということに単純な驚きを持つだけです。

 見学が終わった後はお土産は、・・・・買いません。キリッ。でも見学の前に軽く食事をしました。となりでは焼き肉のおいしそうなにおいがしていました。足柄牛とかいう高そうな肉も食べられるらしいです。 



2010年10月25日

Komodo Edit 6をインストール

Emacsは使わないと宣言しておきながら、今だにEmacsを使い続けています。意志が弱いです。Emacsを使わないふりをするために、その代替としてKomodo Editを使っていました。Komodo IDEと言う人は売り物で、理不尽に高いです。Komodo Editはそのエディタ部分を抜き出してフリーになっています。OpenKomodoでオープンソースで開発しているとかしていないとかで、宗教的な理由でオープンソースじゃないといけない人でも大丈夫かもです。

さて、そのKomodo Editですが、油断をしていてたらしばらく使っていませんでした。気がつくとバージョン6がでていたので、インストールして、またKomodo EditのユーザになってEmacsを卒業する決意をしました。

なかなか信じて貰えないので、証拠画像です。信じて貰えたでしょうか?

Komodo Editはコード補完やfoldingなど、コードを書く上で必要そうなことはほぼできます。ソースコードのツリービュー(クラスやメソッドなどの一覧)がプラグイン(NST - New Source Tree)でできるのですが、それは僕のところでは動きませんでした。何か別のプラグインとコンフリクトしてんじゃね?と言う人もいるらしいで、iMacにもインストールして確かめてみます。

とりあえず、インストールしただけでまだ、何も試していません。UIが大きく変わるとかで一時期騒がれていたらしいですが、以前のバージョンからUIが何が変わったか分かりません。まあ、ほとんどKomodo Edit使わずにEmacsを使っていた罰です。きっと。

と言うことで、僕は今からEmacsユーザではなくなりました。きっと。


さてさて、Komodoを家のiMacにもインストールしましたが、やっぱりNSTでソースツリーは見えません。やっぱり壊れているようです。でも、インストールした0.49というバージョンはとっても安定しているとか書いています。困ったものです。

2010年10月23日

本をiPhoneとかiPadで読む

iBooksというか、iBooksの本を購入できる環境が中々できないし、Kindleも日本語の本を売ってくれません。でも、電子書籍を読むってどうゆうことか、やってみないとわかりません。種類は多くないですが、iPhoneでもアプリとして本は読めるし、理想書店で種類は多くなくても本を買って読むことができます。Fujisanもあります。ばらばらなのはいやなのですが、KindleなりiBookに統一されのを待つよりも、今ある環境を試すのも一興です。

将来的にはKindleとかiBookになりそうな気がして、本棚が理想書店とかいろんなものに分散されるのがいやだったのですが、大体の本が一度読んだら2回目は読まないので、諦めたともいいます。

さて、今年の夏ぐらいから本を買って読んでいます。まず、iPadは本を読むために買ったのですが、本を読むデバイスとしては僕は気に入っています。理想書店とか、アプリとしての本も快適に読めます。ただ、オライリーからPDFを買ったのですが、PDFだけは不満がのこります。字が小さすぎるのです。ページの余白部分がないぐらい拡大されていれば読みやすいのですが、そうすると、ページをめくるときなどに不満がでます。

その次にiPhoneでも読んでみました。iPadの大きな画面で読みやすさになれた後なので、iPhoneの小さな画面で大量の文字を読むのは不可能とか、快適じゃないとか思い込んでいました。でも、iPadまでとは行かなくても、電車で立ちながら読めるし、悪くはありません。「これから正義の話をしよう」はiPhoneで読みました。

本を読むということで言えば、紙でもiPhoneでもiPadでも何でもいいです。以前にも書きましたが、強いて言えば、 横書きで読めるiPhoneとかiPadのデバイスは紙よりもいいです。

この記事では、 新しいデバイスを否定的にとらえていますが、それは自分のスタイルをデバイスに引きずられているだけのような気がします。まあ、メールなりTwitterなり頻繁にチェックするような人は、紙の本だろうと何だろうと、良くないのかも知れません。僕は、暇なときしかメールとか新着をチェックしないので、特殊なのかも知れません。逆に言えば、メールとか読んだり、Twitterを読んだりしているときは、暇つぶしをしているだけです。

と言うか、本を読んでいる最中にリンクがあったからって言ってそれをクリックしていたら、読みおわらないじゃん。

とりあえず、僕はメールもTwitterもなるべく通知させないようにしています。通知されてもすぐには読まないし。 



2010年10月22日

MacBookAirなんて、か、買わないんだからね

ちっちゃいMacBookAirがでました。至る所で話題になっています。知り合いもポチッと購入しちゃった人もいます。小さくて割と軽いMacBookAirは魅力的ですが、持っているMacBookが壊れそうになるまでは、今回発売されたMacBookAirは買いません。キリッ。

欲しいかどうか聞かれた、それはもちろん欲しいです。でも、スペック的にちょっと微妙です。欲しいのは11インチの方です。13インチは電車の中で使うにはちょっとでかいのです。時々、まわりの人からの攻撃にさらされます。なので、11インチのサイズはとっても魅力で期す。でも、画面の縦は800は欲しいですね。

メモリは4Gまでのせられるのはすばらしいです。でも、CPUがちょっと残念感が漂います。1.4Gとか、1.6GがFSB800MHzでどれくらいのスピードなんでしょう?クロック数だけでも2G欲しいですね。MacPortsをいれると思うのですが、コンパイルのスピードはCPUに依存するしね。母艦でコンパイルして、サブのMacにインストールってできるのかな?

それから、ストレージは、64Gはさすがにきつすぎます。128Gあれば、写真とか動画を入れなければなんとかなりそうな気がします。でも、バッテリがカタログ上、5時間しかもちません。

我慢するとして、11インチでSSD128Gでメモリ4GでCPUを1.6Gのものを選ぶと、13万円ぐらいです。 13インチでSSD128Gでメモリを4Gにしても13万円ぐらいです。しかもCPUはよりはやく、バッテリはより長く、解像度はより高く、でも300gぐらいおもいし、ちょっと大きいです。さてさて、いろいろ迷いどころです。

でも、夏に27インチiMacをかっちゃっているので、 今回は見送ります。MacBookもまだ元気そうだし。



2010年10月21日

プロジェクトのバッファ

プロジェクトで安全のためにある程度のバッファをもってスケジューリングすることはよくあることです。それ自体は悪いことではありません。精神安定上、いいことかもしれません。

アリエルはできてからもう10年ぐらい経つので、その間に数々のプロジェクトがありました。プロジェクトの数とほぼ同じぐらいの数だけ、プロジェクトマネージャがいました。正確に覚えていないのですが、プロジェクトマネージャがいなかったプロジェクトもあったような気がするので、ほぼ同じぐらいという表現です。

プロジェクトが沢山あってそれらがすべて成功した訳じゃないです。もっとも、最初の5年ぐらいは悲惨なものだったかもしれません。まあ、若かったから仕方ないです。アリエルができたときは僕は29だったし。

で、いろいろなプロジェクトを見ていて、明らかにプロジェクトが遅れていて、周りが遅れていると指摘しても平然としているプロジェクトマネージャもいました。僕は小心者なので、平然としていられません。そして、そのプロジェクトマネージャのいい分は、「バッファーがあるから大丈夫です。」「今はバッファを使っているので、何の問題もないです」。言い分はわかるのですが、プロジェクトの運営の最初の方から、もしくは危険そうだとわかり始めても、バッファに過度の期待というか逃げを作ってしまって、結局バッファを食いつぶしてプロジェクトが遅れるというものでした。

プロジェクトが遅れるのはある意味、仕方ないこともあるので、そのことはどうでもいいのですが、バッファがあるからと思考が停止してしまうのは最悪です。その状態でプロジェクトが遅れても誰もかばってくれません。いや、嘘です。かばうこともありますが、それは別の利害関係からかも。

まとめると、プロジェクトマネージャは大変なんです。きっと。いやいや、プロジェクトマネージャじゃなくても、小さなチームのリーダーでも大変なんです。それらを手を出したくても、口だけ出してじっと見るのです。でも、わかってもらえないのです。



2010年10月20日

iMacにメモリを増設したでござる

VMWareを1000円で買ったのですが、iMac 2010midでVMをいくつか走らせるにはメモリが4Gでは若干不安です。いくつVMを走らせるつもりだ?というのもありますが、メモリを増設しました。最近、IO-Dataの2Gx2のモジュールを買おうと思ったのですが、これが実売2万円ぐらいです。ほぞ、買うつもりでいたのですが、いろいろ調べると、CORSAIR DDR3 1333MHz 8GB(4GBx2枚) 2x204pin SODIMM Unbuffered CMSO8GX3M2A1333C9
が1万8千円ぐらいです。4Gで2万円と8Gで18000円じゃ、8Gを買うでしょう。ネット上での評判も悪くありません。というか、気持ち悪いぐらいいいです。

20101019.png ということで、買って増設しました。もともと、4Gのモジュールが乗っていたので、合計12Gです。今のところ、普通に使えています。久しぶりに自分でメモリを増設したので、ドキドキしました。特にマシンが重いし、でかい(27inch)ので落っことさないように慎重です。手順自体はとっても簡単です。ねじの穴をつぶさないように注意するぐらいです。

きっとこれで、iMovieとか触っても不満はなくなるはずです。メモリを16Gにした人もいるみたいですが、そんなには必要ないでしょう。僕も8Gで十分だと思うし。

で、増設してからそれほど時間が経っていませんあが、前よりハードディスクがガリガリいうのが少なくなったような気がします。 

 



VMWareのUbuntuにVMWare Toolsをインストール

ネタがないので、とってもつまらないエントリが続きます。UbuntuをVMWareにインストールしたので、VMWare   Toolsをインストールしました。VMのイメージを作っているときには、VMWare Toolsのダウンロードが遅かったのでスキップしたやつです。

UbuntuにログインしてからVMWareのメニューの[仮想マシン] - [VMware Toolsのインストール]を選択します。すると、UbuntuにToolsのイメージが/media/VMWare Toolsにマウントされるので、その中のtarボールを展開します。

$ tar xf /media/VMware¥ Tools/VMware_Tools_xxx.tgz
$ cd vmware-tools-distrib
$ sudo ./vmware-install.pl

あとでインストラクションに従ってひたすらエンターキーを押すだけです。最初はちゃんと読んでいたのですが、途中で疲れてすっ飛ばしました。
インストールが終わって、とりあえず、再起動しようかと思ったのですが、めんどいのでXだけ再起動。ウインドウのサイズを変更すると、ちゃんとUbuntuのサイズも変わってくれます。

さて、Parallelsのコーヒレンス(であっていたかな?)に対応するユニティを試してみます。ParallelsはWindowsしかできなったと思うのですが、ちゃんとLinux君でも動きました。よかったよかった。

2010年10月19日

VMWareをインストールして、Ubuntu

VMWare Fusionを1000円ほどで買ったのでインストールしました。本当は、Ubuntuサーバを5、6個インストールするつもりだったのですが、それはまた、今度です。VMWare自体のインストールは簡単です。そういえば、英語でVMWareが動いていると思ったら、そうじゃなくって、日本語でした。英語でも日本語でもどっちでもいいけど。

インストール後、Ubuntu 10.10 Desktop日本語Remixをインストールしました。[ファイル] - [新規]でウィザードが立ち上がるので、[ディスクを使用せずにインストール]ボタンを押して、ディスクイメージからインストールします。すると、次の画面がでてきます。
簡易インストールって何かよくわかりませんが、初めてなので、それを選択します。ついでにパスワードも入れておきます。

仮想マシンからホームフォルダにアクセスするは、まあ、そういうものなんでしょうが、アクセスできて困ることはないので、読み書きできる形式にしました。

で、続けるを押すと、続きます。VMWare Toolsをダウンロードするか聞かれるので、ここは、ダウンロードでしょう。



でも、ダウンロードが始まってみると、遅いのです。ダウンロードがおわらないのであります。あきらめます。

あきらめると、次の画面になります。

さて、終了を押すとインストールが始まります。何も設定しなくても勝手にどんどんインストールされていきます。すごいです。待てば良いだけです。

しばらく待ってインストールがおわりました。Ubuntuを立ち上げてログインすると、あれ?英語です。自動インストールしたせいで、デフォルトの言語が英語になっていました。そのぐらい気にしては行けません。
ログイン画面に戻って日本語ロケール、キーボードにしてログインします。今度は日本語です。最初に英語でログインしたおかげで、勝手にできるフォルダ名が英語です。すばらしいです。フォルダ名を変更するかきかれますが、せっかく英語になってくれたのに、切り替えるのはもったいないです。はい。

で、気になって、ターミナルを立ち上げてdateコマンドをうつとPDTというタイムゾーンになっています。カリフォルニアみたいです。さすがはメリケンのソフトです。タイムゾーンを日本語にしました。これで、きっとすべて大丈夫なはず。


VMWare Toolsはそのうちそのうち。

2010年10月15日

VMWare Fusionのアップグレード版、安い


僕はMacBookとiMacをもっています。MacBookにはちょっと前のバージョンのParallelsが入っています。Parallelsは悪くない製品なんですが、一年ごとにバージョンアップをしています。新しいモノ好きなのでバージョンアップ自体はいいことなんですが、バージョンアップに伴ってお金が発生します。それが大体50ドルぐらいです。で、これはかなり大きな出費です。それと、ParallelsのLinuxの対応がちょっといまいちのような気もします。

さて、Macで動くメジャーなVMは、ParallelsとVMWare FusionとVirtual Boxぐらいです。iMacにもVMを入れようと思っていたのですが、まず、VirtualBox。これは、オープンソースで無料でありながら、ちゃんとしたものです。最初は、VirtualBoxをいれて使おうと思っていました。多分、上の3つの中で一番Linuxをちゃんと扱える製品だと思います。でも、悲しいことに、VirtualBoxは名前の前に「Oracle VM」がつきます。一気に使う気が失せました。

Parallelsは高い。特に、バージョンアップ費用。

VMWare Fusionですが、他のプラットフォームは無料なのに、Macだけお金が発生します。Macユーザは金払いがいいからかもしれません。さて、日本語のVMWareのサイトをみても何も書いていないのですが、英語のサイトをみると、今年いっぱいまで9.99ドルでVMWare Fusionの古いバージョン、もしくはParallelsのすべてのバージョンからアップグレードできるって、書いてあります。9.99ドルなので、1ドル85円としても850円ぐらいです。まあ、もともと9.99ドルなので、為替レートとにらめっこしなくてもいいですね。

と言うことで、安かったのでVMWare Fusionを買ってしまいました。未だインストールしてません。

まあ、Parallelsも面白そうな機能はあるんですが、でも面白いだけで多分使わない機能だし・・・。 





2010年10月14日

トラブルシューティングの方法

ソフトウェアの開発にはバグは憑き物です。バグはそこにあるので、末永くうまくつきあっていかなくてはいけません。すごいプログラマであれば、その憑いていたものは別の人に憑くかかも知れません。

さて、最近、他の人がバグと戦っているのを横でみている機会がありました。いや、先週末ぐらいからそんなことしかしていないような気がします。できれば、プロジェクトの終わりの段階だけじゃなくって、もっと速い段階からみてみたいと思うんですが、なかなかそんな時間はありません。

横でバグと戦っているのをみると、とても面白いです。バグを報告する人から、バグの内容を聞くのですが、現象を正しく理解する前に何か作業を始めようとしてしまいます。現象を確認すると、なかなかちゃんと答えられません。まずは、原因とか対処方法とかはいいので、現象を正しく理解することをやんないといけません。

現象が理解できたら、再現性をみないといけません。再現しないものは直ったという確証が得られないのです。でも、現実は悲しいことに特定の環境でしか再現しないものとか、すごく低い確率でしか起きないので、デバッグできなかったり、デバッグしようとすると再現しない嫌らしいものもいます。まあ、そういうものはソースコードを頭の中に入れて、頭の中で再現させるルート見つけたりしましたが、僕はもうそんな芸当ができるほど若くはないです。

コードをみながら再現するルートを見つけようとすることもあります。でも、最近みていた若者はコードをみると、なぜか直そうとか、バグの原因箇所を第六感によって見つけようとします。何もわかっていないのに、どう直すのか、不思議です。六感の信用度もよく分かりません。なので、ちゃんと考えてもバグは生まれるのに、そんな風に直す(?)とさらなるバグの原因になったりします。

で、再現できれば直すのはほとんどのケースが簡単です。ほとんどなので、直せないもの、直すのがめちゃくちゃ大変なものもあります。  

で、以前、僕がバグを解析しているところを若い人に見せて教えようとしたことがあります。結果は見事に失敗でした。思考をすべて言葉にしている訳じゃないので、いくつかをすっ飛ばしていたり、説明するのがもどかしくなったり、理解してもらえなかったり・・・。今回は、指示を出しただけですが、うーん、成功とは言えないような・・・。

結局、トラブルシューティングで言える確実な方法とは、「まずは落ち着け!」。 



2010年10月8日

プログラマの二つの世界なんてあるんだろうか?

プログラマが直面する二つの世界」は とっても面白いんだけど、それ以上にとっても違和感を覚えました。あんまり状況がわかっていないし、僕の働いている環境が特殊なのか、そういう対立するような世界には直面したことがありません。どんなにがんばっても現実的な予算と時間でその要求を実装することがそもそも無理というのはありますが・・・。

さて、二つの世界の住人がいるとしたら、僕はプログラムの設計・実装を重視する方です。そして、必然的に会社としても設計・実装を重視する文化です。でも、それらを重視するとして、顧客の要求も追求しないで一体何を作ろうとしているのか、目的がわかりません。まあ、Chandlerのように何を作ろうしているのかわからないまま、コードをこねくり回していたオープンソースのプログラムもありましたが、そんなのは例外でしょう。 

コードをきれいにすることは、顧客の要求とは違うと言う立場のようです。社内にもそういう風に誤解している人もいます。僕は受託開発の経験がなく、パッケージソフトの開発しか知らないです。パッケージソフトなので、一度限りのコードはほとんどなく、常にメンテナンスのことを考えなければなりません。一度書いたコードは製品がある限りメンテナンスし続けなければなりません。顧客の要求を満たすことは、ある一定のコスト内です。そのコスト内でメンテナンスし続けなければならないです。 メンテナンスが大変なコードはその後のメンテナンスコストの増大につながり、それがその後の価格などに響いてきます。品質とか、機能拡張とかの話にもなりますが、結局、顧客にとってメリットをもたらします。

なので、二つの世界は二律背反なのではなく、リリース期間までを考えたバランスの世界だと思います。 

でも、お客さんがエンジニアを理解してくれないって? そんなことはないんじゃないかな。僕の働いている会社のエンジニアたちは割とお客に理解してもらえているつもりです。



2010年10月6日

iPhoneって本当に直感的?

iPhoneって発売直後とか直感的で使いやすいって言われたりしていました。僕にとっては違和感なく使えて、悪くない製品です。でも、一歩下がったところから冷静にみると、本当に直感的かと言えば、ある程度は直感的だけど、それ以上は独特の慣れが必要です。慣れて言うのは、ちょっとした驚きなどから学習するものです。

さて、iPhoneのアプリとか、iPhone用のWebサイトって結局、どれも似たようなUIやユーザビリティになってきています。厳密には違うのかもしれませんが、すくなくとも僕はそう感じます。なので、新たに作るものは、すでにあるものにあうように作る、UIやユーザビリティを同じように作るのが、ユーザにとっての学習コストや使い勝手からするとよい訳です。

そこで、ほとんど、というか全くiPhoneを使ったことがない人がいきなりiPhoneを使うと、それらのUIやユーザビリティに慣れていません。なので、そこで戸惑いが生じます。戸惑いをなくすために、iPhoneの他のアプリと操作性の一貫性がなくなった方がいいのかもしれません。それはごく短期的な話です。それって、使えば使うほど、いらだつものです。

もう一つ困ったことは、iPhoneの小さな画面にPCのサイトのような画面を持ち込もうとすることです。 iPadなら違和感がないのですが、iPhoneにPCのサイトのを持ち込むと大きな景色を小さな窓から覗いているようで、とてもストレスフルです。僕の会社のCTOも少なくともちょっと前まではこのことがわかっていませんでした。今もわかっていないかもしれませんが・・・。で、実際に自分で使い込んでいないので、言ってもわかってもらえません。すごい割り切りが必要なんですが、割り切れないようです。まあ、すごいUIがあるならそうしますが、そんなに簡単にUIができあるものもないです。

そんな中、「このサイトはこのUIを実現しています」って見せられるものは、うーん、それって、どう考えても使いにくそうだし、かっこ悪いし・・・。僕は大きな景色を小さな窓で覗きたくはないんです。モックを作ればわかってもられるのかもしれません。でも、使いにくいとわかりきっているものを、モックといえども作るのはいやです。まあ、それは技術的に無理だよ、というのもあるんですが・・・。



2010年10月5日

MongoDBで作る20分ブログ

20分かどうかはよく分かりませんが、とりあえず、MongoDBを使ってエントリの登録、表示、編集するだけのブログのサンプルです。WebのフレームワークはFlaskを使っています。それ以外は特別なものはないはずです。コメントの追加は、気が向いたらやります。

まず、MongoDBをPythonから利用するにはpymongoを使いますが、これはMongoDBに対する薄いラッパーです。ORマッパーっぽいというか、MongoDBは全く構造化されていないのでもう少し構造化する者というか、堅いRDBから抜け出して生ぬるいMongoDBに来たのにまた、もうちょっと堅くなろうとするのか、まあそのようなライブラリがいくつかあります。

今回はFlaskを使っていますが、Django好きには、Django-MongoKitというのがいるらしいです。でも、僕はあんまりDjangoを使わないので、おしまい。で、Django-MongoKitというのは、MongoKitをDjangoから使う者です。MongoKitとは、
MongoKit framework try to keep its simplicity when you manage mongodb in python. MongoKit was developed to be fast and light with KISS and DRY in mind. MongoKit brings structured schema and validation layer on top of the great pymongo driver
ということです。構造化したスキーマやバリデーションなどもう少し高レベルのAPIを提供しようというものです。

それ以外には、MongoEngineという人もいるらしいです。基本的にはMongoKitと同じ思想です。MongoEngineのサイトにはMongoEngineはDocument-Object Mapperと書いています。なかなか面白い表記です。

高レベルなAPIもありますが、やっぱり今回はpymongoを直接扱います。

import pymongo
from pymongo.objectid import ObjectId
from flask import Flask, request, flash, render_template, url_for
from flask import session, redirect
from flask import g

def req_start():
    g.mongo = pymongo.Connection()

def req_end(response):
g.mongo.disconnect()
    del g.mongo
    return response

app = Flask(__name__)
app.debug = True
app.before_request(req_start)
app.after_request(req_end)

とりあえず、リクエストが来たらグローバルな値にMongoDBへのコネクションをセットして、リクエストが終わるとMongoDBとの接続を切って変な状態が残らないようにしています。

@app.route("/")
@app.route("/")
def index(oid = None):
    db = g.mongo.blog
    if oid:
        entries = db.entry.find({"_id": ObjectId(oid)})
    else:
        entries = db.entry.find().sort([("created", -1)])

    return render_template("index.html", entries=entries)

一覧とエントリの詳細を表示しています。サボっていますが、許してください。oidが指定されていたらMongoDBの内部IDで検索して、それらを表示します。oidが指定されていなければ、全部取得して日付でソートしています。

@app.route("/save", methods=["POST"])
def save():
    db = g.mongo.blog
    form = request.form
    oid = form.get("oid", None)
    if not oid:
        entry = {}
    else:
        entry = db.entry.find_one({"_id": ObjectId(oid)})
       
    entry["title"] = form["title"]
    entry["body"] = form["body"]
    result = db.entry.save(entry)
    oid = str(result)

    return redirect(url_for("index", oid=oid))

保存も、特に変なところはないですね。バリデーションをサボっているのはご愛敬。データはtitleとbodyしかありません。

テンプレートの中身はgithubのコードをみてください。
で、ここまでがきっと20分です。

コメントは、Embedded Documentにすればあんまり考えずにできます。でも、その場合だとサイドバーをつけたときに、「最近のコメント」を表示できないです。db.commentというテーブルを作って、コメントを2段階で取得した方がいいです。でも、でも、でも。

でわでわ。

2010年10月4日

Pythonで3分MongoDB

PythonでMongoDBで遊びます。shardingとかGridFSとか、MongoDB自体のお話はまた、きっと後日。

まずは、mongodbのインストール。

$ sudo port mongodb

MongoDBを動かします。Cassandraと違って一般ユーザで。

$ mongod  --dbpath data

では、PythonでMongoDBを遊ぶためにpymongoをインストール。

$ pip install pymongo
さて、準備ができたので早速遊びましょう。MongoDBをインストールしたらmongoというインターラクティブシェルも一緒にインストールされます。これを使って、インターラクティブにmongodbを操作できます。でも、残念ながら今回はPythonのインターラクティブシェルで遊びます。
pymongoをインポートしたらMongoDBとのコネクションを取得します。localhostでデフォルトのポート番号で動いているので、Connectionの引数は省略しています。

>>> import pymongo
>>> conn = pymongo.Connection()

はい。それじゃ、MongoDBのデータベースに接続します。今回は、testと言うデータベースです。conn["test"]と書いてもいいです。データベースがあれば既存のものが使われ、なければ作られます。

>>> db = conn.test
>>> db
Database(Connection('localhost', 27017), u'test')

データベースができたらusersと言うテーブル相当のものを作ります。と言ってもアクセスするだけです。

>>> db.users
Collection(Database(Connection('localhost', 27017), u'test'), u'users')

では、nameにlirisでデータを保存します。Pythonの辞書がデータを指定します。最終的にはJSON、本当はBSONにデータはシリアライズされます。BSONについてはそのうち。
スキーマとかテーブルの定義とか難しいことは考えなくても、辞書にぺけぺけデータをセットしておけば、よきに計らって貰えます。この辺がRDBと違っていい加減、いや柔軟なところです。

>>> db.users.save({"name": "liris"})
ObjectId('4ca97e9dd013fd6412000000')

データを保存したので本当に保存されているか確認したくなるのが人情です。早速確認します。いますね。

>>> db.users.find_one()
{u'_id': ObjectId('4ca97e9dd013fd6412000000'), u'name': u'liris'}

それじゃ、もう一人。

>>> db.users.save({"name": "liris", "blog": "http://blog.liris.org"})
ObjectId('4ca97ecfd013fd6412000001')

で、データを確認します。今度はすべてのデータをなめ回してみます。
                                                                               
>>> for user in db.users.find():
...     print user
...
{u'_id': ObjectId('4ca97e9dd013fd6412000000'), u'name': u'liris'}
{u'blog': u'http://blog.liris.org', u'_id': ObjectId('4ca97ecfd013fd6412000001'), u'name': u'liris'}

二匹に増えています。
それじゃ、tagsとして配列でデータを入れてあげます。

>>> db.users.save({"name": "ohtani", "tags": ["liris", "ariel"]})
ObjectId('4ca97fc5d013fd6412000002')
>>> for user in db.users.find():
...     print user
... 
{u'_id': ObjectId('4ca97e9dd013fd6412000000'), u'name': u'liris'}
{u'blog': u'http://blog.liris.org', u'_id': ObjectId('4ca97ecfd013fd6412000001'), u'name': u'liris'}
{u'_id': ObjectId('4ca97fc5d013fd6412000002'), u'name': u'ohtani', u'tags': [u'liris', u'ariel']}

タグの中身で検索です。

>>> db.users.find_one({"tags": "liris"})
{u'_id': ObjectId('4ca97fc5d013fd6412000002'),
 u'name': u'ohtani',
 u'tags': [u'liris', u'ariel']}

辞書の中にさらに辞書を入れてみます(Embedded Document)。

>>> db.users.save({"name": "master", "nature": {"always": u"遅刻", "often" : u"来ない"}})
ObjectId('4ca98098d013fd6412000003')

Embedded Documentの中身で検索するときは、「.」で連結します。ちなみに、Embedded Documentだけのコレクションを扱うことはできないです。

>>> db.users.find_one({"nature.always": u"遅刻"})
{u'_id': ObjectId('4ca98098d013fd6412000003'),
 u'name': u'master',
 u'nature': {u'always': u'遅刻', u'often': u'来ない'}}

lirisさんが2匹もいるとうざいので、こんなやつは一匹だけにします。まずは、いらなさそうなやつをみつけだして、

>>> user = db.users.find_one({"name": "liris", "blog": None})
>>> user
{u'_id': ObjectId('4ca97e9dd013fd6412000000'), u'name': u'liris'}

消えちまえ!の呪文を唱えます。消えています。

>>> db.users.remove(user)
>>> for user in db.users.find():
...     print user
...
{u'blog': u'http://blog.liris.org', u'_id': ObjectId('4ca97ecfd013fd6412000001'), u'name': u'liris'}
{u'_id': ObjectId('4ca97fc5d013fd6412000002'), u'name': u'ohtani', u'tags': [u'liris', u'ariel']}
{u'_id': ObjectId('4ca98098d013fd6412000003'), u'name': u'master', u'nature': {u'always': u'遅刻', u'often': u'来ない'}}

切断しておしまい。

>>> conn.disconnect()

これで、きっと3分です。

会社に白いイヌがいた

触るとしゃべる