2014年4月30日水曜日

Rack::Session::PoolとRack::Session::Cookieの違い

RubyでRackアプリケーションを作成している時に、セッションの保存方法を調べていて、幾つかの方法があることがわかったんですがね。とりあえず、Rackには代表的なところで言うと、
  • Rack::Session::Cookie
  • Rack::Session::Memcache
  • Rack::Session::Pool
あたりがあるようです。Rack::Session::Cookie は Cookieを利用した単純なデータストア、Rack::Session::Memcache はクッキーの代わりにmemcachedを使う、Rack::Session::Pool は @pool にハッシュとしてデータを保存する、という説明が公式のドキュメントにも書いてあります。が、Rack::Session::Pool がよく分かりません。そもそもRack::Session::Cookieとの違いは何でしょう?

と思っていたら、どうやら同じ悩みを抱える方が海外にもいたようです。

http://stackoverflow.com/questions/13573968/using-racksessionpool-over-racksessioncookie

上記サイトと、僕が幾つかのサイトで調べた結果をまとめると、つまりこういうことですかね。
  • Rack::Session::Cookie
    → セッションID、及び全てのキー・バリューのペアをCookieに保存する。
  • Rack::Session::Pool
    → セッションIDのみクッキーに保存する。データはRack::Session::Poolのインスタンス変数@poolに、メモリ上で永続化の処理をせず(つまりそのまま)保存される。そのため高速で動作し、かつ保存できるオブジェクトに(永続化しないため)制約がない。ただし、アプリケーションを再起動した場合にはデータは全て失われる。
  • Rack::Session::Memcache
    → セッションIDのみクッキーに保存する。データはmemcachedにより保存するため、当然memcachedは導入済みである必要がある。おそらく、永続化の処理は入るため保存できるデータの制約はRack::Session::Cookieと一緒と思われる。高速で動作する。速度的にはRack::Session::Poolとほぼ同等(永続化の操作の分わずかに劣ると思うが)。アプリケーションを再起動してもデータは保持される。
速度性能を追求するかどうか、そしてアプリケーションの再起動時にデータを保存する必要があるかどうか、が使い分けのポイントですかね。

※2014/05/02 Rack::Session::Poolについて、データの保存先の記述を修正しました。(アプリケーションオブジェクトのインスタンス変数 → Rack::Session::Poolのインスタンス変数)

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月29日火曜日

PHPで、一時的に出力を抑制する

とあるオープンソースのコードを眺めていたら、下記のような記述がいくつもの箇所に使われているのを見ました。

ob_start();
〜何らかの処理〜
if (ob_get_level()) ob_end_clean();

調べてみると、ob_start()は出力のバッファリングをオンにして、すぐさま出力がされなくなります。例えば、ob_start()以降の処理で何らかのエラーが起きて出力がなされたとしても、それが画面に表示されないということです。

ob_get_level()は、出力のバッファリングのネストレベルを取得します。ob_start()はネストすることが出来て、そのネストレベル分解除しないといけません。

で、ob_end_clean()は、バッファ内の出力を破棄して(実際に出力を行わず)バッファリングを解除する関数です。

これらをまとめると、つまり、ob_start() から ob_end_clean() のまでの間の処理による出力は行われないということです。こういうやり方もあるんだなぁ。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

一億分の一の間違いすら、許されない〜ITエンジニアの生きる世界〜

Facebookに投稿したものですが、せっかくなので、こちらにも載せときます。

================

一億分の一の間違いすら、許されない―

プログラムは、書いたとおりに動く。そこには寸分の誤解もなく、その一言一句・一文字に至るまで、書かれたプログラムはそのままコンピュータに解釈される。一文字間違ったら、人間なら「ああ、ここミスしたのね」と判断してくれるが、コンピュータは一文字間違ったらそのまま実行しようとしてエラーになる。

例えば銀行で動くような巨大なシステムともなれば、想像もつかないが、少なくとも全体では数千万行、文字にして数億文字ものプログラムになるだろう。もしかするともっと巨大かもしれない。

しかし、その1文字でも間違いがあれば、システムは正常に動かない。そう、一億分の一の間違いすら、許されない―。プログラミングとは、実際そういうものなのだ。普段何も気にすること無くATMでお金を引き出せるのは、一億分の一の間違いもなく、システムが動いているおかげである。

これは全く大げさな話ではない。確か数年前に世間を騒がした銀行のシステム不具合も、結局直接的な原因となったのは、僅か数文字のプログラムの不備によるものであった。

とはいっても、やはりプログラムは人間の書いた通りに動いただけである。コンピュータが「プログラムはこう書いてあるが、実は別の意図に違いない」などと勝手に解釈することは原理的にありえない。

そして、プログラムの記述に使うプログラミング言語の決まり事もまた、全部人間が決めたものだ。やはりそこにも、解釈にずれが生じる余地はない。つまり、完全に余すところなく、全ての支配権は「こちら」にあるのだ。

ところが、すんなりとプログラムが動くことは、めったにない。何故ならば、完全であるコンピュータは、完全に人間の命令を反映するのだから、人間の不完全さもまた、忠実に完全に再現するからだ。

ITエンジニアは、確かに、物言わず忠実に応答を返すコンピュータ相手の仕事だ。それは、外部の人間から見れば、無味乾燥とした味気のない、まるで砂漠のような世界に見えるかもしれない。

しかし、先に述べたように、コンピュータとは、人間を映す鏡でもある。組み上げられたシステムをよく見れば、意外なほどに、人間の意志や感情が映っているのを見ることができる。

無機質なようでいて、実は人間臭い―。ITエンジニアの生きる世界とは、そういう世界なのだ。

2014年4月26日土曜日

一人プロジェクトでもGitは役に立つ

ちょいと先日ある人が、「一人でやってるとGitもあまりありがたみがない」なんてことを言ってましたけれども、そんなことは無いと思いますよ。

そういう僕も昔はSubversionしか知らなくて、Gitを知った時もメリットが理解できず、移行したのは単に「将来性がありそうだから」くらいの理由だったんですがね。使ううちに、「これは明らかにGitに優位性がある」と実感できるようになりました。さらに、「たとえ一人のプロジェクトだとしてもやはりGitは有効活用できる」と思ってます。

ポイントは、リモートリポジトリとローカルリポジトリの使い分けにあります。開発中は色々と試行錯誤をしながら進めていくものですが、それらをコミットしていくと、結構変更が入り乱れてきます。一段落したところで変更をまとめてスッキリさせたいと思うわけですよ。

そういう時に、ローカルリポジトリに試行錯誤のためのブランチを作ってそこでにコミットしていき、一段落したところで、それらの変更をまとめて改めて別のブランチにコミットします。具体的には、以前この記事に書いたような merge --squash を使う方法が有用です。リモートリポジトリにプッシュするのは変更をまとめたブランチのみとしておけば、リモートリポジトリのコミットログもスッキリし、分かりやすくなります。

そういえば、ブランチの概念もSubversionとGitでは全然違いますよね。Subversionだとブランチはあくまで派生であって、trunkを更新するのが基本。Gitの方はmasterとは別のブランチにコミットして、masterにマージして取り込む、というのがよくあるパターンです。ですので一人プロジェクトでも気軽にブランチを切っていきます。

というわけで、一人プロジェクトでもGitは相当役に立ちますよ、という話でした。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月25日金曜日

仕様書・自動化テスト・実装の三位一体開発

タイトルは最近考えてることでしてね。ちなみに最初に申し上げておくべきことは、以下に書くことは、仕様を決める権利・スケジュールを決める権利・開発方法を決める権利を自らが持っている開発チーム及び開発者を対象としている、ということです。ということは受託開発よりも、自社サービスや自社製品の開発あるいは社内システム開発という立場向け、ってことです。

言いたいことを一言で言うと、仕様書・自動化テスト・実装を行き来しながら少しずつ作っていく、ということです。例えば、仕様書に少し書き加え、該当する自動化テストを少し書き、さらに該当する実装を少し書く。それを小さいサイクルで繰り返していく。というふうに。

もちろん、例えば実装方法に依存して考えなければならない部分があったりして、先に仕様書が書けない場合なんかもありますけど、その時は実装を先に書いてもいいわけです。その代わり可能な限り早く仕様書に反映し、該当する自動化テストも書くようにします。つまり、どれか1つだけが大きく突出しないようにします。

これの一部だけを取り出すと、自動化テストと実装の部分だけ見れば「テスト駆動開発」になるでしょう。さらに自動化テストの範囲が広がって振る舞いや挙動の記述も含むようになれば「ビヘイビア駆動開発」となりますね。

もし仕様書だけを集中して先に完成させてしまうと、いわゆるウォーターフォール型になります。あるいは仕様書も一緒に作っていくという概念を抜かせばアジャイルになります(大雑把に言えば)。

なお、「◯◯駆動開発」と呼んでしまうと、その「◯◯」を原則として先に作らなければならないということになりますが、仕様書・自動化テスト・実装は常に順番を固定して作れるようなものではなく、むしろお互いを行き来しながらバランスを取りつつ進めていく、という表現がしっくりきます。その上で、理想としては「仕様書→自動化テスト→実装」の順番のサイクルを維持する、と思っておけばいいと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月24日木曜日

たまには「手を動かさないこと」も必要

よく手を動かすことが重要だって言われますよね。特にエンジニアの世界ですと、コマンドを覚えるとか、プログラミング言語を習得するとか、新しいツールを使うとか、ドキュメントを書くとか、そういう文脈で使われる言葉が「手を動かせ」です。確かにその通りであって、手を動かすこと重要である、という意見を否定しようだとは全く思いません。

でもしかし、いついかなる時も手を止めないことが良いことだ、とは僕は思わないわけですよ。たまには、手を止めて静かに深く黙考することも、これまた非常に大事なことだろうと思うのですね。別に長くそうしろとも言いません。1分とか2分とか、場合によっては30秒でいいから、集中的に思考する時間が必要なときもあります。

例えばプログラミングの前の設計を行うことを考えてみます。全体の構想を考えているとして、最初は図に書き出していくわけですよ。思いつくことを色々と。僕は紙に書き出すのが好きなのでマインドマップ形式で描いたりします。

で、しばらくすると全部書き尽くすわけですね。「手が止まる」わけですよ。そこで次の段階に移行して再び手を動かす作業を再開する、のではちょっと甘いのですね。そこはむしろ、描いたものを眺め直して、頭の中でイメージを作り、足りないものが無いか、もっと掘り下げて細かく書いておくべき点はないか、などを検討することで、完成度が上がるのです。その時こそ、手を動かさずに静かに深く考えるべきタイミングですよね。時間にしたらわずかに1・2分かも知れませんが、この時間を取るか取らないかの差は大きいはずです。

ちなみに手を止めて黙考していると「ほら、手が止まってるよ」とか何とか言って文句をつけてくる人が居たりするかもしれません。手を動かしていないと仕事してないと思ってたみたいです。そういう人は分かってないので、無視しておきましょう。僕も過去の職場にいましたね。その人は自分を忙しくするのが得意でいつも悲劇の主人公気取りの人でした。相手にするだけ無意味です。

もちろん、あまり長い黙考は疲れるし意味が無いので、僕が言っているのはせいぜい数十秒から数分間程度のことです。でも、それが重要な時もある、ってことは理解しておかなければいけないと思います。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。

2014年4月23日水曜日

auでテザリングする時のIPアドレスとポート

自分のホームページは自前で仮想サーバをまるごと借りて運営してるんですけど、しばらく前から、テザリング使用時に、80番ポートのHTTPアクセスはできるものの、SSHなどその他のアクセスが出来ない、という状況が続いていました。その前まではできてたんですがね。

サーバ側のファイアウォールの設定を見なおしてみたり、HTTPでリクエストを投げた時にログに記録されるIPアドレスを確認したりしてみましたが、リクエスト元のIPアドレスには、確かにSSHの22番ポートなど、HTTPの80番ポート以外のアクセスも許可されていました。それでもアクセスが出来ない状況でした。

で、調べるうちに下記ページを発見。
http://www.au.kddi.com/developer/android/kaihatsu/network/

上記リンク先のページの最後の方に、下記の記述があります。

「Port80番通信とPort80番以外の通信では送信元IPアドレスが異なる場合があります」

うおーい、多分これだよ。てことで、早速一時的にファイアウォールを無効にして、テザリング中にHTTPで80番ポートへのアクセス元IPと、SSHで22番ポートへのアクセス元IPを確認してみると・・・異なってた!で、80番ポート以外からのアクセス元IPアドレスのファイアウォール通過許可が無かったのが原因なのでした。

なお、auのテザリング時のIPアドレス一覧は、上で挙げたリンク先に載ってます。とりあえず、リンク先に書いてあるIPの範囲でファイアウォールの設定を行い、無事つながるようになりました。

※この記事について指摘・意見・提案・感想などありましたら下のコメント欄にどうぞ。