- 10:34 うん。まさにその通りだよ。「現場から入ってしまった人は、まず目的に必要なものをでっち上げ、後でそれの裏にある背景や理論を勉強すると、「なるほど〜 だからアレはあーなってたのかー!」と楽しく学習することができます。」→ http://docs.komagata.org/4654
2010-11-05
twitter より (2010-11-04)
2010-11-02
一意性の確保 - ハッシュ関数
以下は実験中の Blogger Glass のコード、そのセッション管理を担当するモジュールの一部でセッション ID を生成す関数になっている。
(src/session.py より)
def generate_session_id(seed):
m = hashlib.sha1()
m.update(datetime.datetime.now().isoformat())
m.update(str(seed))
return m.hexdigest()
以前、ウェブアプリにおけるセッションを病院に治療に来る患者の関係にたとえた(→「Cookie の使い方 - GAE におけるセッションの保持」)。病気(やケガ)の治療では病院側が患者についてさまざまな情報を記録しておき(カルテ)、その記録と患者個人をひもづけるために番号を使うと書いた。この番号に相当するのがセッション ID なのだ、とも書いた。
カルテと患者のひもづけで大事なことはそれが一通りに定まることだ。これが混乱すると(あるカルテが別の患者のものだと扱われる等)大変なことになる。これを確実にするための 1 つの方法は、空白のカルテ用紙にあらかじめ重複しない通し番号を振っておくというものだ。番号の一意性 (uniqueness) が確保できていることが、患者という個人の識別に利用できる理由だ。
ウェブアプリにおけるセッション ID についても、同じことがそのままあてはまる。すなわち、ウェブアプリとクライアント(ブラウザ)のひもづけには、一意性の保証された何かを利用しなければならない。↑で示した関数は、この一意性の保証された何かを、ハッシュ関数(一方向ハッシュ関数とも言う)によって生成している(標準ライブラリの hashlib)。
ところで、このハッシュ関数が生成する「何か」は本当に一意 (unique) なのだろうか? あるいは完全に一意なものではないとしてどれぐらい一意なのだろう?
一方向ハッシュ関数
先のコードで使っている hashlib.sha1 という関数はハッシュ関数の中でも一方向ハッシュ関数(Wikipedia:ja では暗号学的ハッシュ関数)と呼ばれるものだ。
(「入門SSH」p.44 より)
一方向ハッシュ関数は、任意の長さの入力から固定長の出力を返す関数です。一方向ハッシュ関数の出力は一方向性(出力から入力を得るのが困難)と衝突困難性(同じ出力を得る 2 つの入力を得るのが困難、衝突耐性)を持ちます。この特徴から、ファイルなどが改ざんされていないことのチェック(もしファイルが改ざんされていれば、出力が異なるはず)や電子署名のために入力を短く固定長にするためなどに利用されます。[...snip...]代表的な一方向ハッシュ関数には、MD5、SHA-1、SHA-256、SHA-512 があります。
もともと、一方向ハッシュ関数はデータの改ざんの有無を検査するような(セキュリティに関係する)目的に使われるが、上記の 2 つの特性のうち「衝突困難性」があるため「一意性の保証された何か」を生成するためにも利用できるわけだ。
さて、hashlib.sha1 で使われている SHA-1 という一方向ハッシュ関数では常に 160 ビットの値を生成する。言い換えると、生成できるのは高々 2^160 個の「何か(符号なしの整数値)」でしかない。もし、毎回異なる値を生成できるとしても、2^160 回以上 ID を生成させれば同じ ID が出てくることになる。そう、これで生成できる「何か」は完全に一意なものではないのだ。
ほどほどの一意性
確かに一方向ハッシュ関数では「完全な一意性」を得ることはできない。でも、良く考えてみれば 2^160 (2 の 160 乗) というのは、結構大きな数だ(→ 「2^64 (2 の 64 乗) って、どれぐらい?」)。うん、いや、結構っていうか、日常生活のスケールでは決して出会うことのないぐらいの大きさだ。ちょっと、Python で計算させてみた。
[imac] mnbi% python Python 2.6.1 (r261:67515, Feb 11 2010, 00:51:29) [GCC 4.2.1 (Apple Inc. build 5646)] on darwin Type "help", "copyright", "credits" or "license" for more information. >>> n = 2 ** 160 >>> len(str(n)) 49 >>> print n 1461501637330902918203684832716283019655932542976
10 進数で 49 ケタ。つまり、10^48 より大きく、10^49 より小さい。読み方は、10^48 が「極(ごく)」なので……
(2^160 の 10進数表現の読み方) 1 (極) 4615 (載) 0163 (正) 7330 (澗) 9029 (溝) 1820 (穣) 3684 (じょ) 8327 (垓) 1628 (京) 3019 (兆) 6559 (億) 3254 (万) 2976
……となる。つまり「一極四千六百十五載(飛んで)百六十三正七千三百三十澗九千(飛んで)二十九溝千八百二十穣三千六百八十四じょ八千三百二十七垓千六百二十八京三千(飛んで)十九兆六千五百五十九億三千二百五十四万二千九百七十六」だ。
意図的に(たいていは悪意を持って)同じハッシュ値を作ろうとしない限り、同じ値が生成されることはないと言って良い。「完全な」ではないにしろ、「ほどほどの一意性」(実際には「実用的な」と言うべきだろうな)は保証されているようだ。
ちなみに「新版暗号技術入門 秘密の国のアリス」によれば、SHA-1 の「強衝突耐性」は 2005 年に破られたとのこと(同 p.176)。ここで「強衝突耐性」とは
(「新版暗号技術入門 秘密の国のアリス」p.170 より)
強衝突耐性とは、ハッシュ値が一致するような、異なる 2 つのメッセージを見つけ出すことが非常に困難である、という性質です。
のことだ。
もっとも、ウェブアプリとクライアント(ブラウザ)のひもづけるセッション ID としてハッシュ値を使う場合、セッション ID を知られただけでアウトだけどね。病院のたとえで言えば、診察券に書かれた患者番号を誰かに知られてしまい、診察券を偽造されてしまうかもってところか。ま、病院と患者の場合は、そんなことをしても意味がないがね(診察券に病院で治療を受ける以外の使い道があれば別)。
ウェブアプリのセッションを管理する「何か」としてハッシュ値を使う場合、大事なことは異なるクライアントに同じ「何か」をわたさないようにすることだ。「何か」を(通信の)途中で盗まれないようにすることは別問題。
そもそも、Blogger Glass のような「公開情報を読み取り専用で扱う」アプリでセッションを盗まれたとしても大した問題にはならないよ。
参考文献
「6.4 ハッシュ法」の一部としてハッシュ関数を扱っている(p.487 〜 492)。ただし、扱っているのは一般的なハッシュ関数であり一方向ハッシュ関数ではない。
関連リンク
- ハッシュ関数 (Wikipedia:ja)
- 暗号学的ハッシュ関数 (同上)
- 命数法 (同上)
- Blogger Glass (GAE アプリ)
関連記事
2010-10-18
twitter より (2010-10-17)
- 14:29 「0を1に」「1を10に」「10を100に」っていう分類が(分類そのものではなく、その表現が)おもしろい。もう少し下世話に表現するなら「発明家」「起業家」「経営者」って感じかな。→ http://docs.komagata.org/4633
- 14:34 なくなるというならケータイに乗り換えても良いんだけど(もうあきらめた)、電話番号だけはそのまま使いたい。あちこちに連絡先として登録してあるから変更するのがメンドウだよ。 → http://bit.ly/99vJnd
2010-10-03
ウェブアプリのデバッグ
バグとは……
不具合、欠陥、障害。いくつかの呼び名があるが、プログラマにとっては「バグ」という名前が一番馴染み深い。そして「バグ」とは、プログラムに関わる誰かにとって何かがうまくいかない状態のことを言う。「誰か」(利害関係者)はユーザであることが多いが、他にもプログラマ自身のこともあるし、さらにはユーザでもプログラマでもない他の関係者(例えば発注者)の場合もある。「うまくいかない」というのは、言葉を変えれば「期待した通りにならない」ということだ。この「期待した通り」のことを一般に仕様と呼ぶ。
正しいとされる「期待」(仕様)が誰にとってのものであれ、実際のプログラムの振る舞いとの差異が指摘されてしまえば、それはバグになる。バグに対してプログラマが許される振舞いは次の 4 つ。
- バグを修正する。
- 「これは仕様(あなたの期待通り)のものです」と関係者を説得する。
- 他のプログラマに回す。
- 対処を先送りにする。
プログラマがどの対応を選ぶかは、彼または彼女の置かれた状況によって異なる。けれどたいていのプログラマは、それがどんなバグであれ、基本的には修正したいと考える。修正以外の道を選ぶとすれば、プログラマ自身の心情よりも周辺事情(迫る期日、労力の不足、...)がそれを許さないからであることが多い。
だから諸事情がそれを許せば、プログラマは 1. を選ぶ。そして、1. を選んだ瞬間から、デバッグが始まる。
デバッグの基本
デバッグには 2 つの側面がある。それは (a) バグを見つけること、(b) それを修正すること、の 2 つだ(→ 「Code Craft」p.206)。そしてデバッグの真髄は (a) にある。バグを見つけることさえできれば、修正は単純であることが多いからだ(そうでない場合、完全に修正するには設計変更をともなうことになり、それはもはや修正と呼ぶの域を超える)。
また、デバッグ作業を段階に分解すると以下のようになる(→ 「Code Craft」p.209-212 を参照)。
- 障害を認識する
- 障害を再現する
- 欠陥の所在を突き止める
- 問題を理解する
- テストを作成する
- 欠陥を修正する
- 修正できたことを立証する。
前半の 3 つが先の (a) に、残りが (b) に相当する。
同じことが「Code Complete」(下巻 p.96) では次のように書かれている。
- エラーを安定させる(確実に再現させる)。
- エラーの原因を特定する。
- 欠陥を修正する。
- 修正をテストする。
- 同様のエラーを探す。
多少の表現の違いはあるが、どちらも同じことを主張している。つまり、デバッグの段階は、(1) 再現可能な環境を構築すること、(2) その中でバグの原因となるコードを特定すること、(3) 修正を行うこと、最後に (4) 検証を行うこと、となる。
今回は、この中でも (2) の原因を特定するための方法について考えてみる。
ウェブアプリのデバッグ
バグの原因となっているコードの場所を突き止める場合、一番確実な方法は print 文などによって、おかしなことが起きる場所をしぼりこむことだ。
(「プログラミング作法」p.175)
プログラムが何をしているのかわからないときには、もっと多くの情報を表示させる文を追加するのが一番手軽で効率の良い手段となり得る。
ウェブアプリのようにコンソールを持たないプログラムの場合、プログラムに print 文を埋め込む方法は使えない(あるいは使うべきではない)。その代わりの手段がログだ。
ログを取る
GAE アプリでは、Python の標準ライブラリにあるロギングモジュールを使い、ログを記録することができる。
記録されたログは、ローカルの開発環境で実行している場合は GAE Launcher からアプリごとのログを表示させれば見ることができる。GAE の本番環境では管理コンソールからアクセスできるとのこと。
ログはプログラムの動作を知る上で何よりも重宝する。一方で、大量のログはアプリのパフォーマンスに影響を及ぼす可能性があるし、ストレージ等のリソースも消費する(GAE の場合はどうなんだろう?)。また、多すぎれば見る方にも負担になる。デバッグ用に一時的に埋め込んだログ出力は、デバッグ(と修正の検証)が終わったら、本番環境に配備する前に取り除く方が良い。
いちばん大事なこと
実は、デバッグにおいて何よりも忘れてはならない手法がある。それは記録を取ること。
これは「プログラミング作法」の p.178 でも「手がかりのない困難なバグ」に対処する方法の 1 つとして紹介されている。「Code Complete」下巻 p.102 でも、バグを見つけるためのヒントとして「メモ帳を用意して、試してみることをリストアップする」ことが挙げられている。
デバッグの作業中に、仮説を立てているのであれ、分割統治法でバグの範囲をしぼりこんでいるのであれ、あるいは同じ間違いを探しているときであれ、自分の記憶を信頼しすぎてはいけない。記憶は平気で嘘をつく。そもそもバグの大半は、ちょっとした見落しや、記憶違いから入り込むのだ。バグを潰す作業で同じことをやっていては、同じ間違いを見逃したり、別の間違いを潜り込ませることになりかねない。
あらかじめ作業リストを作って消していく方式でも良いし、思いついたことやったことを簡単にメモするだけでも良い。不確実な記憶に頼らず、確実な記録を残すこと。
参考文献
第5章がデバッグについての章になっている。取り上げられているバグの例は、(他の 2 冊とくらべて)具体的で読んでいておもしろい。ただし、載せられているコードの断片はいずれも C のものばかりなので、Ruby や Python でのデバッグにそのまま活かせるものではない。
この「コード・コンプリート」は「プログラミング作法」でデバッグに関する参考文献として挙げられている。第23章(下巻に収められている)がデバッグについての章になっている。ここに挙げた 3 冊のうちで「バグを見つける」ことに関する具体的な手順については、これがもっとも詳しい。
第9章「謝りの検出」がデバッグについての章だ。3 冊のうちでは、バグおよびその原因の分類について詳しい。
関連リンク
- アプリケーションのイベントのログ (GAE 公式ドキュメントより)
- 14.5 logging -- Python 用ロギング機能 (Python ライブラリリファレンス; PyJUG)
- library logger (Ruby リファレンスマニュアル Ruby 1.9.2 版 より)
関連記事
2010-09-30
既存のプロジェクトを github に公開する
ローカルで(つまり、手元の Mac や PC で)すでに git 管理しているディレクトリを github に公開する方法をメモしておく。単純な手順だし、ヘルプにも詳しく書かれているからそれを見れば良いだけなんだが、いずれ自分視点での記録も重宝するはず。
以前に書いた記事の続きになる。よって、ここでは Github へのユーザ登録はもちろん、SSH 公開鍵の登録も完了しているものとする。
手順
公開までの手順を段階に分けると以下のようになる。
- github に新プロジェクトを登録する。
- ローカルのリポジトリで、Github のプロジェクトリポジトリをリモートリポジトリとして追加する。
- ローカルからリモート(github)に既存のコミットを push する。
1. プロジェクトの登録
github にログインし Dashboard を開くと、右のサイドバーに「New Repository」というボタンが見つかる。これをクリックすると登録の開始となる。
登録画面で指定する情報は 3 つ。「Project Name」、「Description」そして「Homepage URL」だ。大事なのは「Project Name」。ここに入力したものがそのままリポジトリ名(の一部)になる。ここで日本語を指定するとどうなるかはわからない。また、プロジェクト名が早い者勝ちなのかどうかは不明(たぶんそうだろう)。
「Description」と「Homepage URL」は登録後にプロジェクトの個別ページから変更できる。登録には空でも良いようだ(少なくとも Homepage URL を空にしても問題なかった)。
2. リモートリポジトリの追加
手元の git リポジトリに対して、コミットをやったり(push)取ったり(pull)するためのリモートリポジトリを追加する。
git のヘルプ(Creating a repo) にあるように以下のコマンドを実行すれば良い。実際には、foo を github のユーザ名、bar を手順 1. で作ったプロジェクト名で、それぞれ置き換える。
git remote add origin git@github.com:foo/bar.git
このコマンドの意味は、手元の git リポジトリに対して、origin という名前で git@github.com... のリポジトリを参照する、と宣言するものだ。つまり、リポジトリに(短い)別名を付けているのだ(↓参照)。
(「入門git」p.105 〜 106 より)
自分のデフォルトのリモートリポジトリには origin という名前が付いている。これは、何であれクローンしてきたリポジトリのフルネームに対する別名だ。[...snip...]
自分のリポジトリに origin がなければ、git remote add で、origin を追加することができる。ローカルリポジトリを git init で開始した後、それをリモートリポジトリに送る必要があるときには、この方法が便利だ。
3. 既存のコミットを push
push コマンドは、その名の示す通り、手元のリポジトリに対するコミットをリモートリポジトリに送るものだ。git push A Bで、B のリポジトリに対してなされたコミットを A のリポジトリに送る、という意味になる。引数の順序が少し混乱を招くが(「push A to B」だと思うと逆の意味なる)、これは引数を省略できるという仕様によるものだろう。
(「入門git」p.103 より)
Git はこのコマンドがパラメータなしで呼び出されると、いくつか推測をする。まず、プッシュ先は origin リポジトリだろうと推測する。次に、リポジトリ上にある現在のブランチを、リモートリポジトリ上の対応するブランチ(もしあれば)に送信するのだろうと推測する。
push で指定するのは、まず「どこに送るのか」という情報であり、次に「何を送るのか」を指定する、と覚えれば良い。少し考えれば当たり前のことだとわかる。なぜなら「何を送るのか」は大抵の場合わかりきったことだからだ。だから「どこに送るのか」を指定するのだ。で、リモートリポジトリが 1 つしかなければ、それすらも明白なので省略可能なのだ。
実行結果
以下に、手順 2. 〜 3. を実際に実行している様子を示す。ここでは bloggerglass という GAE 上のアプリのソース一式を登録している。
[imac] mnbi% git remote add origin git@github.com:mnbi/bloggerglass.git
[imac] mnbi% git config --list
[...snip...]
remote.origin.url=git@github.com:mnbi/bloggerglass.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
[imac] mnbi% git push origin master
Identity added: /Users/mnbi/.ssh/github_id_rsa (/Users/mnbi/.ssh/github_id_rsa)
Counting objects: 42, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (42/42), 8.72 KiB, done.
Total 42 (delta 8), reused 0 (delta 0)
To git@github.com:mnbi/bloggerglass.git
* [new branch] master -> master
日々のコミット作業
リモートリポジトリを作ったからといって、ローカルで行う日常の作業はほとんど変化しない。唯一違うのはローカルリポジトリにコミットした後、リモートリポジトリへ push することが増えたこと。
先に例として挙げた bloggerglass では、今のところリモートリポジトリは 1 つで、ブランチも作っていないから、引数なしで push コマンドを実行するだけで良い。
以下に、push コマンドの実行例を示す。
[imac] mnbi% git push Counting objects: 9, done. Delta compression using up to 4 threads. Compressing objects: 100% (5/5), done. Writing objects: 100% (5/5), 425 bytes, done. Total 5 (delta 4), reused 0 (delta 0) To git@github.com:mnbi/bloggerglass.git 6057da1..7f9add6 master -> master
bloggerglassでは、すでに typo の修正やデバッグ用のコードの除去などで(...orz)、数回コミットを push している。↑の実行例もその 1 つ。
参考文献
関連リンク
- Creating a repo (help.github)
関連記事
2010-09-27
twitter より (2010-09-26)
- 12:07 RT @deltam: 「コードがドキュメントです(キリッ」ではなくて「コードがドキュメントかつドキュメントがコードです(キリリッ」。英語が母国語の人がJavaなどのソースコードを読むときの感覚と日本人が読むときの感覚はだいぶ違ってると思う。
- 13:15 フリスク、買うのも久しぶり。ピンクグレープフルーツって言ってもあんまり変わらん。ひたすらミントだわ。
- 13:23 RT @masui: gitの入門記事で 'git ls-files' コマンドが解説されてるのを見ないのは何故だろう。 現在どのファイルがバージョン管理されてるか知りたいときはどうするのが普通なのか?
- 17:04 コン猿スゲェ、というのはおいといて。これも立派な計算機だ。これがオモチャ(もともと玩具だってことだけど)に見えてしまうのは、われわれが「コンピュータ==プログラマブルな機械」だと思っているから。RT @masui: コン猿天才だな http://bit.ly/d7Er0A
- 17:08 「プログラマブルな機械」というのは、比較的簡単にプログラムを変更できる機械、という意味。何が言いたいかっていうと、「プログラムできる機械ってスゲェよ」ってこと。だから、みんなプログラマになろうぜ。
2010-09-22
twitter より (2010-09-21)
- 08:32 英語を忘れそうなのでメモ。proof of concept 。プロトタイプの前段階として位置付けられているようだ。→ http://ja.wikipedia.org/wiki/概念実証
- 08:34 ふむふむ。proof of concept は proof of technology や pilot project とは別のプロセスなのね。この辺りの言葉はきちんと定義して使わないと誤解のもとだね。→ http://ja.wikipedia.org/wiki/概念実証
- 22:22 ドルだての買い物をするときには円高がうれしいね。RTM の pro アカウントを更新したんだが、$25 ≒ ¥2,200.- だった。
2010-09-04
2010-08-17
Github に SSH 公開鍵を登録する
Github のリポジトリにアクセスするためには、あらかじめこちらの SSH 公開鍵を登録しておかなければならない。公開鍵は ssh-keygen コマンドで作れば良い。ウチの環境では、LAN 内の他の Mac へのリモート接続等に公開鍵を使っているため、今回 Github へ登録するものは、それとは別に作ることにした。そのための手順は以下のようになる。
- 公開鍵生成時に鍵ファイルの名前を指定する。
- Github への SSH 接続では標準とは異なる鍵ファイルを使うように設定する。
SSH 公開鍵の生成
以下が実際の公開鍵生成の実行結果。参考にしたのは help.github にある「Generating SSH keys (OSX)」。また、鍵のファイル名を変更する方法については「Macにgitをインストールしてそのままgithubにも登録」にならった。
[imac] mnbi% ssh-keygen -C "mnbi@foo.bar.baz"
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/mnbi/.ssh/id_rsa): github_id_rsa
[...snip...]
SSH の設定
「Troubleshooting SSH issues」の "SSH config" にしたがい、~/.ssh/config に以下の記述を追加する。
Host github.com
User git
Hostname github.com
PreferredAuthentications publickey
IdentityFile ~/.ssh/github_id_rsa
Github への接続テスト
生成した公開鍵(↑の実行例では github_id_rsa.pub)の内容を Github に登録した後、「Generating SSH keys (OSX)」にしたがい、接続テストを行う。以下はその実行結果。
[imac] mnbi% ssh git@github.com
The authenticity of host 'github.com (207.97.227.239)' can't be established.
RSA key fingerprint is 16:27:ac:a5:76:28:2d:36:63:1b:56:4d:eb:df:a6:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'github.com,207.97.227.239' (RSA) to the list of known hosts.
Identity added: /Users/mnbi/.ssh/github_id_rsa (/Users/mnbi/.ssh/github_id_rsa)
PTY allocation request failed on channel 0
ERROR: Hi mnbi! You've successfully authenticated, but GitHub does not provide shell access
Connection to github.com closed.
Github はシェルアクセスを認めていないため接続は切られる。肝心なのは「You've successfully authenticated」の部分。これにより、認証は成功したことがわかる。
追記@2010-11-17
実際のプロジェクトの登録については、「既存のプロジェクトを github に公開する」を参照。
関連リンク
- Macにgitをインストールしてそのままgithubにも登録 (kishi-r.com)
- Generating SSH keys (OSX) (help.github)
- Troubleshooting SSH issues (help.github; 認証情報のファイルを標準とは別の名前にする場合の SSH config の設定方法が載っている)
関連記事
2010-05-25
twitter より (2010-05-24)
- 16:13 [MM読了]特別料理 (異色作家短篇集) http://bit.ly/cQdbHr ★★★☆☆ 素直におもしろいと思える作品集。どの一編にもきちんと「オチ」がついていて、しかもわかりやすい。「どこがおもしろいんだろう」と首をひねることがない。
- 16:17 理屈から言って、プログラマがプログラミングをするのに必要なのはノートパソコンひとつ。つまりどこでだって仕事はできる。むしろ、そうあるべきなんだろうな。 → http://www.100shiki.com/archives/2010/05/swapyourshop.html
- 16:18 ネットすら、あるにこしたことはないけど必須でもない。資料ならHDDに放り込んでおける。ある程度の準備さえしておけば、断線状態だってプログラミングできる。
- 16:21 だから、大きな画面の方がイイとか、キーボードがどうとか、マウスがどうとか、あるいは机が椅子が、なんてことを気にするのはプログラマとして自慢できることじゃないのかも。
- 18:58 パックマン → http://www.google.com/pacman/
2010-02-13
プログラミングが難しいのは…
購読しているとあるブログで知って、The Evolution of End User Programming という動画を見た。その中で、エンドユーザにとってプログラミングが難しいのは、それが、"Indirect & Abstract" なものであるからだ、と言っていた。うまい表現だと思った。まったくその通りだ、と。
さらに言えば、エンドユーザにとってのプログラミングだけでなく、プログラマにとっても「間接的で抽象的」なものはわかりにくい。プログラミングだけでなく、コンピューティング(コンピュータを使ってあれこれすること)自体についても同じことが言える。
バッチから対話型へ、大型汎用機からパソコンへ、CUI から GUI へ、構造化プログラミングからオブジェクト指向プログラミングへ。コンピューティングの進化は、いずれも「間接的で抽象的」なものを「直接的あるいは具体的」な何かへと置き換える方向に進んでいる。
アプリやデバイスを考えるときに心に留めておくべきことだ。
関連リンク
参考文献
動画の中で紹介されていた文献だけど(↑)、まだ出版されていない。2010/4/29 に出版予定となっている。
2009-11-11
捨てることで見つける
【連載】Google世代の整理術「デジタル情報整理ハックス」 (21) 「どうしてもとっておきたいエントリ」はどうするか?
情報収集と一口に言っても、新聞のスクラップが主だった時代に比べて、インターネット時代の今は、収集のたやすさと情報量の豊富さにおいて、圧倒的です。こういう環境では、厳選のレベルをいくら高く設定しても、高すぎることなどないように思えます。
「気になったものはなんでも取っておくといい」というのは、むしろ紙の時代の箴言です。今ではむしろ、ちょっとでもいらないかなと思えた情報は、とにかく捨てた方がいいと言っても、過言ではないでしょう。
「はてブ」や diigo のような SBS の登場で URL を記録しておくことがとても簡単になった。その結果、ブックマークがあふれてしまう。で、せっかく取っておいた URL も埋もれてしまって見つけられない。しかたがないから、ブックマークを検索するようになる。で、ふと気付く、「あ、Google で検索すればいいじゃん。ブクマ、いらないな」と。
RSSリーダーの登場でウェブに流れる情報の監視がとても簡単になった。その結果、未読フィードがあふれてしまう。結局、読まないまま「既読にする」をクリックしてしまう。ちらっとタイトルだけを見た記憶から、あんな記事やこんな記事があったはず、とRSSリーダーに保存されたフィードを検索するようになる。で、ふと思う、「あ、これって Google で検索するのと同じ。RSSリーダー不要。ってか、最初から読まなくて良いんじゃないか?」
情報が大量に蓄積してしまうと、見つけるためには検索を用いるしかない。情報の山を始めから終わりまで(少なくとも見つかるまで)、順にたどるような方法は探索時にコストがかかりすぎる。蓄積時に整理、分類すれば探索の手間は省けるが、今度は蓄積するときにコストが発生する。加えて、たいていの人は体系立った分類法など身につけてはいない。一貫した分類を行おうとするだけで苦痛になる。整理が不要な量に収まっているときだけ効率良く整理できる。人はスケーラブルにはできていない。「大量」を相手にするには機械に頼るしかない。
一方で、検索には「見つからないかもしれない」問題がつきまとう。たとえ自分が蓄えた情報であっても目的の対象を見つけられるとは限らない。「ブックマークしたはず」という記憶が間違っていることもあるし、適切な検索語を思いつけないこともある。整理と探索にかかるコストを劇的に軽減してくれる「検索技術」は「発見する」という事象を確率化してしまうのだ。
「確率化されてしまった発見」に対して、「見つかる確率」を上げるためにさまざまな工夫が発明されてきた。SBS のように、ブックマークを共有し、タグづけを「みんな」で行うことで、集合知を味方につけようとする技術はその代表。けれど、ちょっと考えてみよう。これは Google が検索精度の向上の名のもとに日々取り組んでいることとかぶっているんじゃないか? PageRank はそもそも集合知を検索に生かそうという試みだ。ウェブ履歴は個人の嗜好を検索に反映させるものだ。
だったら、情報はどんどん捨ててしまおう。大丈夫、それがネット上のものであるなら、Google が拾ってくれる。きちんとしまっておいてくれる。必要になったら見つけてくれる(かもしれない)。見つからなければそれまでのもの。縁がなかったってことだ。心配ない、情報は、興味を引くものは他にもいっぱいある。
捨てて、捨てて、捨てまくって、それでもなお捨てられずに残るものがあるなら、それは自身にとって肝心な何か。「必要だから」じゃない、「役に立つから」でもない。それは自分にとって「忘れたくないモノ」。こだわらずにはいられない何か。捨てることで大事なものを見つける。それだけを手に持って、あとは全部、丸ごと Google に任せよう。
情報はしぼらなきゃならないという発想。これは、限られたリソースをどこに投資するかという問題(選択と集中)のバリエーションだ。そして、この問題はライフハック界隈で繰返し聞く「制御(コントロール)を取り戻す」という主張とつながくる。
「しぼる」は「捨てる」、「あきらめる」と同義。「あきらめる」こと、それが肝心。その代わり、あきらめなかったことはとことん追求する。こだわる。それが職人ってものだろう?
2009-11-08
平等分散リポジトリの見せる夢
はじめての Git
LOG+REPOのテンプレートや素材、そして記事を保全するために Git で管理することにした。まずは「入門git」の第三章、「最初のプロジェクトを作る」に書かれた手順を追ってみた。
git init がすべての始まり。CVS や Subversion とは違い、中央リポジトリは存在しない。昨日までの作業場所がそのままリポジトリの置き場所にもなる(↓)。
(入門git; p.25)
Git で自分のリポジトリがあるのは、自分の作業ツリーとまったく同じ場所にある.gitディレクトリの中だ。
ファイルを作ったら git add、そして git commit。変更しても git add、そして git commit。さっき何を変更したかを忘れたら git status。これまでにどんな変更をしたかを思い出したければ git log。詳細な差分が知りたくなったら git diff。
日常のサイクルを思い出すには Git早見表の "Commands Sequence" が最適。
Git は RCS っぽい
CVS や Subversion を一から導入するのはかなりハードルが高い。ソフトウェアのインストールのことではない。今時の有名なソフトウェアのインストールはとても簡単 (Git もそうだった)。よほどマイナーなプラットフォームにこだわっていない限り、迷うことはほとんどない。大変なのは、実際にプロジェクトをバージョン管理ソフト(以下、VCS)の管理下に置く作業の方だ。こっちには途方に暮れる点が少なくない。
何よりリポジトリをどこに置くかで迷う。ローカルなマシンに置くのか、ネットワーク上の共有フォルダに置くのか。ネット上に置くなら、むしろ VCS をサーバとして動かすべきじゃないのか。いっそのこと、Google に頼むか。・・・などなど。
慣れているなら迷わない。けれど、最初にこれをやるのはかなりハードだ。失敗してしまえば(後からもっと良い方法を思いついたら)、やり直しはメンドウ。そう思うと、ますます指が動かなくなる。
その点、作業場所がそのままリポジトリだという Git の方法は迷いがない。思い立ったら、ただ git init と叩くだけでいい。「やっぱ、や〜めた」となれば、rm -rf .git で、キレイさっぱり忘れてしまえる。
ふと思った。「あ、これって、RCS と同じ感覚だ。」
RCS は、もうずっと以前に unix 界隈でメジャーだった VCS (→ Wikipedia:Revision_Control_System)。そんなの聞いたことないや、っていう人はターミナルを開いて /usr/bin あたりを見てみるといい。ci とか co というコマンドが見つかるはずだ。少なくとも Snow Leopard には入ってる (Xcode と一緒に来たのかもしれない)。
RCS は、基本的に個人の作業成果を管理するためのシステムだ。独立したリポジトリの概念はなく、作業場所がリポジトリも兼ねる (ディレクトリごとに RCS ディレクトリを作れば、そこがリポジトリになる)。だから、チームで作業するようなプロジェクトには向かない。
個人からチームへ
ソフトウェアの規模が増大するにつれて、ソフトウェア開発の主役は個人からチームに移っていった。VCS にもチームでの作業を前提とした機能が求められた。CVS の誕生だ(→ Wikipedia:Concurrent_Versions_System)。CVS の始まりは RCS への不満だったという。RCS をベースにして、そこに不足している機能を付け加える方法で開発が進められた。いつしか RCS への依存もなくなり独立した VCS として、オープンソースソフトウェアプロジェクトを中心に広く使われるようになった。
一方で、ソフトウェア開発は複雑化の一途をたどった。チームメンバーの増加、地理的分散、増大するリリース作業の負担。プロジェクトインフラとしての VCS には、大規模かつ複雑なプロジェクトをサポートする機能が求めらるようになった。つまり、CVS にも機能不足と呼ばれるときが来たのだ。
(Subversion実践入門 第2版;p.6 - 7)
Subversion のプロジェクトは、CVS に精通した開発者のチームによって開始された。(・・・中略・・・) 彼らは CVS が既に古くなりつつあることを感じて、それに代わるツールを開発すべき時が訪ずれたと判断したのだ。Subversion の開発者たちには CVS の短所が痛いほど分かっていたので、彼らは高性能で現代的なバージョン管理システムを設計することに特に重点を置いた。
集中から分散へ
リポジトリを集中させるか、または分散させるか。分散させ、かつどこかにマスターを置くハイブリッド型か。これらはスタイルの違いであり、どれが優れていて何が劣っているというものではない。プロジェクトとチームの特性に応じて適切なものを選択するのが賢いやり方だ。
だから、Git が現状(2009年末時点)で最高の VCS であり、他の VCS を使うことなど考えられない、などと言うつもりはない。しかし、個人が自分自身の活動を管理するために使うとしたら、Git のような分散タイプ、それもリポジトリ間に優劣の差(マスター/スレーブ)がない平等分散リポジトリタイプをサポートするものが良い。他の分散 VCS も「平等分散リポジトリ」をサポートするなら、あとは好みの問題だ。
個人の復権
GitHubの登場はコミッタを特権階級から追い落とす革命だった - Hello, world! - s21g
かつてはメンテナやコミッタが専権的にソフトウェア開発の決定権を握っていた構造が、Git/GitHubの登場によって、気がつかないうちに崩れ去っている。これはソフトウェア開発史上、非常に大きな出来事なんだろう
不思議なものでオープンなはずの、オープンソースソフトウェアでは↑のような状況が存在するのだという。一方で、クローズドな環境である企業の開発現場では、リポジトリの管理(昔はライブラリアンと呼ばれた)はメンドウなだけの労働であることが多い。誰も進んでやりたがる業務じゃない。そこでは管理者(マネージャじゃないよ、英語でいうならアドミニストレータ)は特権階級なんかじゃない。むしろ下働きだ。誰かがやらないといけない作業、大事なんだけど報われることの少ないロール。
オープンソースソフトウェアのプロジェクトにおいて、リポジトリに対する権限が開発者間に階級を生んでいるのだとしたら、そしてそれが開発者の間に感情の軋轢を生じさせるのならば、それはプロジェクトの特性に適していない管理方式なのだ。その場合、Git のような分散かつ平等なリポジトリを持つシステムは救いになる。
皆が自分のリポジトリを持ち、誰もマスターではなく、またスレーブでもない。ソースコードはブランチすることが前提で、世界中にさまざまな変種が存在する。誰もが自由にプッシュでき、誰もが自由にマージできる。ソフトウェアを中央のコミッタがデザインするのではく、個々のプログラマが自らの用途に合わせ、思うままにアレンジできる。何が正しくて何が間違っているのか、プログラマ自身が決めることができる。個人としてのプログラマの復権だ。
あとひとつ。Git のもたらすこのビジョンこそ、ソフトウェアの再利用というプログラマの(古くからの)夢を実現するものじゃないだろうか。再利用すべきはバイナリじゃない。ソースコードだ。皆がリポジトリを持つことで初めてそれが可能になる。