「できない」と「できる」

「そろそろブログを書こう」と思い続けて、3ヶ月経ってしまった。

私は、いま「中年の危機」とも言えるアイデンティティ・クライシスにある。もう少し、気持ちが整理されたら書こうと思いつつけてきたが、たぶんこの分だと永遠に気持ちは整理されまいと思い、日記を書くことにする。

私は、いま東京のとある粋なソフトウェア企業と契約して、あるソフトウェア開発のプロジェクトに従事している。こうやって働いている身分で、自分の人生の迷いを吐露すれば、顧客に不安を与えるに違いない。普通にまともなビジネスマンだったらやらないことだろう。

だが、いずれにしろ、迷いを抱えているのは否定しがたいし、それを表に表さず仕事をするのも、誠実な態度とは言えないのかもしれない。いろいろしがらみやらなんやらあることはあるが、一つ一つを計算に入れて戦略的に行動するなんていう器用なことが私はできないので、まあ、こういうのも悪くないのかもしれない。

まずは、私が抱える職業上の悩みから吐露しよう。私は、短期間の例外を除いて、大学卒業以来、ITの仕事に従事してきた。そのほとんどの期間、私は上司または顧客から要求仕様を聞き取り、それを満たすソフトウェアを作る、という仕事をしてきた。私は、さまざまな理由で一つの組織にコミットすることができなかった。その結果、私はいつまでも現場の最前線、つまりPCに向かって直接コードを書くプログラマの立場にとどまった。

はてなユーザーならよくご存じの通り、日本ではプログラマの地位は著しく低い。社会的な意義は高いはずなのに、地位がそれに追いつかないのはどういうわけだ…と私は憤った。もっとも、この点に関しては、この数年のウェブ企業の台頭によって、日本でも風向きが相当変わりつつあるようには思う。LINEが上場して1兆円の資金調達が噂されるような時代だからね。

ただ、最近、顧客とプログラマに中間に立つ人たち〜SIer は彼らを SE とよび、ウェブ系企業はディレクターと呼ぶ〜は、実は多くの場合やはりプログラマ以上に重要なんじゃないかと思うようになった。プログラマはもちろん優秀でなくてはいけない。だがそれ以上に、彼らに何をいつまでにどのように作るべきか的確に伝えられなければ、顧客が望むものが作れるはずがない。

以前から私の文章をお読みの方々はよくご存じの通り、私は数年前、日本企業の仕事の仕方を厳しく糾弾した。その多くは私がプログラマとして大企業のオフィスで見聞した経験に基づいている。だがいまはこう思うのだ。末端のプログラマとして、誰かの指示に基づいて作業をする身では、プロジェクト管理をする人たちの失敗の影響をモロに受けるしかないではないか。プロジェクト管理に問題があると考えるなら、なぜ自分がSEなりディレクターなりプロジェクトマネジャなりになって、問題を解決しようとはしなかったのか?私は単に現実から逃げていただけではないのか?と。

もう一人の私がこう自分を弁護する。「そんなこと言ったって無理に決まっているじゃないか。これは構造的な問題なんだ。誰がやったとしても、そういう場に放り込まれたら同じことをやるに決まっている。私がプロジェクト管理をやったって何も変わらないさ」と。

確かにそうなのかもしれない。構造的問題だと指摘するのは、何かをしないためには、ほぼ完璧ないい訳である。「私が異性にもてないのは構造的な問題だからどうしようもない」。確かにそうなのかもしれない。

でも、本当にそうなのだろうか?本当に問題解決への道は一本も残さずに閉ざされていたのだろうか?「何かがひとつでもあること」は簡単に証明できる。しかし「何かが絶対存在しない」ということは、多くの場合、証明不可能だ。

実務上優秀な人たちの共通点は「できない」とは言わないことだという。彼らはかならず「できる」という。以前の私は、そういう話を眉唾で聞いていた。「できないことはできないだろうよ」と。よくよく観察してみれば、彼らはべつに超自然的な力を信じて、根性で頑張ればなんでもできると信じているわけではなさそうだ。彼らは正確には「できるようにする」のだ。物事が自然に成就するように、頭をギュウギュウに絞って、成功確率を高めるべく環境を整備するのだ。

「できない」ということのメリットは、それが間違っていることはほとんどない点だ。この予言は自己実現的に成就する。「できない」といえば、ほぼ間違いなくそれは「できないようになる」。それに、「できない」といえば、何もする必要がないから、誠に便利ではある。

ただ「できない」ということのデメリットは、それが人生を少しも豊かにしてくれないという点だ。できないといえば、実際にできないようになり、何も起こらない。何も生じず、何も得ず、退屈な人生だけが残る。

…いろいろグタグタ言ってきたが、ポイントはこういうことだ。慎重に何事に対しても「できない」と言い続けてきた私は、たぶん間違っていた。43歳にもなってそんなことを言わなければならないのはつらい。ただ、60歳や70歳になっていうよりはいくらかはマシだろう。

これからは、困難な状況にぶちあたっても、すぐ「できない」とは言わないことにしよう。日本も世界もいろいろ状況は絶望的だが、改善の余地は全くないとは言わないことにしよう。その状況に対して自分が全く何もできないとは思わないことにしよう。

どんな難しい問題も解決「できる」のだ。解決までの道筋なら、必ずいくつか思いつくことができるからだ。すぐはできなくても、いずれ「できるようにする」ことはできるからだ。

…とまたまた脱線して自分の本筋の悩みを吐露するには至らなかったが今日はこの程度にしておこう。続きはまた今度。

jQuery.Deferred 風の非同期処理ライブラリを CoffeeScript で書いてみた

jQueryソースコードを読むのが日課の今日このごろ、みなさんはいかがお過ごしですか?

Deferred は、連鎖した非同期処理を楽にしてくれるライブラリだ。以下のエントリを読むと概要がわかる。

爆速でわかるjQuery.Deferred超入門 - Yahoo! JAPAN Tech Blog
結局jQuery.Deferredの何が嬉しいのか分からない、という人向けの小話 - Qiita

jQuery の ready イベントはどういうふうに処理されているのか、ソースコードを追っているうちにぶち当たったのが、この Deferred ライブラリ。ソースコードをいくら読んでもよく理解できない。理解できない理由は、

  • 無名関数が何重にもネストされている
  • そのため変数名がどの値に束縛されているのかよくわからない
  • さらに jQuery.extend を使って混乱に輪をかけている

など。たぶん非常に頭がいい人なら理解できるのだろうが、私には無理だった。

ソースに対する断片的理解と Deferred の仕様から、自分なりに Deferred 風のライブラリを書いてみた。CoffeeScript で書くと期待以上にコードが美しかったので、Github で公開してみた

こんな感じで使う。

delay = (ms, task) ->
  setTimeout task, ms

x = []

task1 = ->
  df = new Deferred()
  delay 100, ->
    x.push(1)
    df.reject()
  df.promise()

oktask = ->
  d = new Deferred()
  delay 100, ->
    x.push(2)
    d.resolve()
  d.promise()

ngtask = ->
  d = new Deferred()
  delay 100, ->
    x.push(-2)
    d.reject()
  d.promise()

task2 = -> x.push(3)
task3 = -> x.push(4)

task1().then(oktask, ngtask).done(task2).fail(task3)

delay 300, ->
  expect(x).toEqual([1, -2, 4]) 

Git のコミットを見やすくする

最近は、SourceTree を通じて git レポジトリを操作する人たちも多いようだ。私はふだん Ubuntu 上にいるので、残念ながら SourceTree は使用できない。コマンドベースで git を使わざるを得ない。

コマンドベースでもぜんぜん構わないのだが、どうも git show-branch や git log の出力が気に入らない。

たとえば、git show-branch -a とすると、次のような表示になる。

! [b2] ci2
 * [master] Revert "c5" YES!!
--
 * [master] Revert "c5" YES!!
 * [master^] c5
 * [master~2] c4
 * [master~3] ci2
+  [b2] ci2
+  [b2^] ci3
+* [master~4] ci1

git show-branch の使い方については、

git show-branch の見方 - 言語ゲーム

が詳しい。

要するに、git show-branch は1つ以上のブランチについて、共通の先祖コミットが現れるまでの各ブランチのすべてのコミットを表示してくれる。これでブランチの分岐具合がよくわかるというわけだ。

まず第一に私は上の [master^] みたいなコミットの相対表示が好きじゃないので、SHA1 ハッシュ表示してみよう。git における本当のオブジェクトは SHA1 だ。HEAD / ブランチ / タグ等はすべてこれら SHA1 をファイル名として持つオブジェクトに対する軽量のポインタにすぎないのだ。だから、最初から SHA1 で見たほうがいい。どうせ SHA1 は大抵の場合最初の4文字で識別できる。

(ちなみに git rev-parse コマンドの引数として、ブランチ名や最初の n 文字だけの SHA1 を与えると、完全な SHA1 ハッシュを得ることができる)

git show-branch --sha1-name -a とすると表示が次のように変わる。

! [b2] ci2
 * [master] Revert "c5" YES!!
--
 * [674042d] Revert "c5" YES!!
 * [41df102] c5
 * [efba81d] c4
 * [13aa75b] ci2
+  [af37738] ci2
+  [04cd130] ci3
+* [466ca30] ci1

このほうがずっと見やすいと思う。SHA1 ハッシュは最初の7文字に統一されているので、コミットメッセージが揃って見える。だが私はまだ不満がある。これだと「いつ」「誰が」コミットしたものかわからないのだ。

そこでまたシェルスクリプト(というか Ruby ワンライナー)で解決。

h2n (hash to name)

#!/bin/sh
ruby -pe '$_.gsub!(/([\da-f]{7})/) { "#{$1}:" + `git log -n 1 --pretty=format:%an #{$1}`[0,3] + ":" + `git log -n 1 --pretty=format:%ai #{$1}`[5,11] }'

このシェルスクリプトを使ってみる。

git show-branch --sha1-name -a | h2n

この表示結果はこんな感じ。

! [b2] ci2
 * [master] Revert "c5" YES!!
--
 * [674042d:Eij:02-20 13:18] Revert "c5" YES!!
 * [41df102:Eij:02-20 13:01] c5
 * [efba81d:Eij:02-20 12:53] c4
 * [13aa75b:Eij:02-20 12:49] ci2
+  [af37738:Eij:02-20 12:49] ci2
+  [04cd130:Eij:02-20 12:50] ci3
+* [466ca30:Eij:02-20 12:48] ci1

SHA1 ハッシュだけが表示されていた場所が [(SHA1):(Author の最初の3文字):(日時(月日時刻だけ))] と変化しているのがわかる。

h2n は単に 7桁の16進数が標準入力から来たら、それを commit の SHA1 だと想定して作者と日時を付加するのである。お好みにあわせて h2n を改造して、表示したいものを変えてほしい。

ブランチの分岐具合を別の形で表す git log --graph --oneline --decorate=short をパイプで h2n につなぐと結果はこんな感じ。

 git log --graph --oneline --decorate=short | h2n

表示結果。

*   b0b0f23:Eij:02-22 06:39 (HEAD, master) Merge branch 'b1'
|\  
| * bc91937:Eij:02-22 06:37 (b1) b1-3
* | 6c341ab:Eij:02-22 06:39 m4
|/  
* 521f612:Eij:02-22 06:35 b1-2
*   bdc88f3:Eij:02-22 06:33 m3
|\  
| * 5706047:Eij:02-22 06:32 b1-1
* | 46ba933:Eij:02-22 06:33 m2
|/  
* be4d840:Eij:02-22 06:31 1

…といちいち断りを入れるのが面倒だったので、偉そうに書いてしまったけど、私は git を本格的に使い始めて3週間の初心者なので、間違いがあったら(優しく)教えてくださいね。

Enjoy Git!

git オブジェクトの表示

最近、ふたたび Ruby on Rails を使って仕事をしている。Rails 4 を使っているのだが、この数年での Rails 界隈の長足の進歩には驚かされることばかり。昔、不満だった点がことごとく改善されて、本当に良くなっている。IT は、この停滞した世界にあって、唯一、真に猛スピードで進歩を遂げている分野なのかもしれない(これが社会を大きく変えていくだろうことを妄想すると頭がクラクラしてくるわけだが)。

いまの仕事仲間は、git と GitHub を当たり前に使いこなしている。正直、個人的にちまちま git を使っていただけの私は大いにめんくらった。ブランチだのプルリクエストだのいろいろ言われても、わけわからん、というレベルであった(本当に仕事仲間には申し訳ない…)。

で、仕方ないので猛勉強した。

最初は、

サルでもわかるGit入門 〜バージョン管理を使いこなそう〜【プロジェクト管理ツールBacklog】

で学習。よいサイトだと思うが、どこかしっくりこない。Gitはコマンド体系が煩雑すぎるように感じる。

やはり、最強は本家のドキュメント。

Git - Book

これを読んではじめて git の仕組みが腑に落ちた。というか、感動で心が打ち震えた。git は(ほぼ)すべての情報を git オブジェクトで管理しており、中身の SHA1 ハッシュをそのままファイル名にしていること。git は基本的にファイルシステムのスナップショットの集合を管理するツールであること。ファイルシステムのスナップショットは、(ルート)ツリーオブジェクトで表され、コミットオブジェクトはスナップショットに対する注釈にすぎないこと。

上のサイトのうち特に

Git - Gitの内側

の章をおすすめしたい。つか、プログラマーなら全員読め!!と言いたい。これを読まずして git が理解できるか!という勢いである(すみません・・・自分を棚に置いて)。

Git の内部構造を説明した文章としては、

実践 Git - 低レベルに知る Git
見えないチカラ: 【翻訳】Gitをボトムアップから理解する
ファイルシステムとしての Git - 言語ゲーム

あたりもよい。

上で紹介した文章を読めば一番わかり易いので、私がとやかくいう必要もないのだが、とりあえず git 関係のシェルスクリプト(半分 Ruby だが)をさらしておく。

ただ使ったアルゴリズムについては、100%の自信があるわけではないので、ご使用は自己責任で。間違いがあったらぜひ教えて下さい。
(あと .git/index ファイルの内部構造がわからなくて困っています。インターネットをいくら探しても資料が見つからないのでだれか教えて下さい)

これらのコマンドが git レポジトリ(.git ディレクトリ)がある場所で使う。

gitobj

SHA1 ハッシュ(最初の7文字) + git オブジェクトタイプ(commit, tree, blob, tag) の表示

#!/bin/sh

gitobjhash() {
  # .git/objects 以下の git オブジェクトの閲覧
  (cd .git/objects ; find . -type f | grep -v info | grep -v pack | sed 's#[\./]##g')
  # pack された git オブジェクトの閲覧
  (cd .git/objects/pack; git verify-pack -v pack-*.idx 2> /dev/null | ruby -ne 'puts $1 if /^([\da-f]{40})/')
}

# git オブジェクトタイプの表示
gitobjhash | ruby -ne '$_.chomp!; puts "#{$_[0,7]} #{`git cat-file -t #{$_}`}"'

gitcm

すべてのコミットメッセージの表示

#!/bin/sh

grep commit | awk '{print $1}' | ruby -ne '$_.chomp!; puts "#{$_[0,7]}\t#{`git log -n 1 --pretty=format:%an #{$_}`[0,3]}\t#{`git log -n 1 --pretty=format:%at #{$_}`}\t#{`git log -n 1 --pretty=format:%ai #{$_}`[5,11]}\t#{`git log -n 1 --pretty=format:%s #{$_}`}"' | sort -k 3

gitobj コマンドの出力結果は下のような感じ。

$ gitobj
=>
198f3c9 blob
d1990c1 blob
5c5a274 blob
bdc88f3 commit
6bf9b0e blob
4c1cd76 tree
...

パイプで gitcm コマンドにつなぐことができる。

$ gitobj | gitcm
=>
...
521f612 Eij 1393018559 02-22 06:35 b1-2
bc91937 Eij 1393018674 02-22 06:37 b1-3
6c341ab Eij 1393018758 02-22 06:39 m4
b0b0f23 Eij 1393018795 02-22 06:39 Merge branch 'b1'
...

1列目:コミットの SHA1 ハッシュ
2列目:Author の最初3文字
3列目:Author date の UNIX タイムスタンプ
4列目:Author date (月・日・時間・分のみ)
5列目:コミットメッセージ

Have fun with Git!

Ruby の仕事を探しています

来年2014年1月から2〜3ヶ月の期間、参加できる IT プロジェクトを探しています。

私にとって最も得意で好きな言語は Ruby なので、Ruby 関係(Ruby on Rails 等)の技術を使うプロジェクトだと助かります。
Ruby の経験は15年、Ruby on Rails は7年以上の経験があります。

以前はこのブログで、RubyRuby on Rails の記事を書いていました。
Ruby の記事
Ruby on Rails の記事

Ruby の次に得意なのは JavaScript です。その他、PHP, Java, C/C++, Perl などを使った実務経験があります。
Python の実務経験はありませんが、対応できると思います。
LinuxUNIX 系OSの基本的操作もできます。

プロジェクトの内容は問いません。新規開発でもよいですし、既存システムの改修でも対応可能です。
ただ研究開発的なプロジェクトがおそらくは私の資質をもっともよく生かせるように思います。
英語は得意なので、英語が必要なプロジェクトも対応可能です。

勤務地は、横浜近辺だと助かりますが、東京都内等、通える距離であればOKです。
もちろん持ち帰りの形態の仕事も歓迎です。遠距離でのオフショア的な仕事も大丈夫です。

私の人となりについては
私の半生1
私の半生(スライド)

契約形態は、受託契約・契約社員等、ご相談に応じます。
私は、株式会社ソフトカルチャーの代表取締役なので、会社間契約も可能です。
報酬金額についても相談させてください。

メールを eijisakai@gmail.com までいただければ詳細な職務経歴書をお送りします。
よろしくお願いします!

怖がり屋

私は昨日、本気で今すぐベトナムに渡って仕事をするつもりだった。だが、そう決意をした数時間後、なんともいえない恐怖が襲ってきて、その決断を覆さざるをえなかった。

    • -

私は、子供のころから怖がりである。高所恐怖症だったし、他にもいろいろ怖いものがあった。優しい言い方をすれば「繊細」だった。自分のやりたいことの方向にどんどん突き進むタイプではなかった。

私はこの恐怖の源泉がどこにあるかは知らない。生まれつきの脳の仕組みに基づく器質的なものなのかもしれない。あるいは幼少期のいくつかの経験がトラウマとなって引き起こされたものなのかもしれない。

私が内省的な子供になったのは、言語の力によって、この恐怖に対抗し、言語で作り上げた幻想の世界に住むことで、かりそめの安定感・安心感を得るためであった。

だが、この精神安定の仕組みには大きな副作用が伴っていた。それは世界から溌剌とした躍動感を失わせ、生きる喜びを失わせたのだ。つまり世界は「退屈」なものになった。

    • -

私が常に人生にどこか退屈さを感じながら生きていること、ときどき突拍子もないことをしてこの退屈さを打ち壊してその一瞬だけ生きている感覚を取り戻すもののすぐに恐怖心からもとの退屈な日常に戻ろうとすること、何をしても長続きしないこと、人や組織と継続的な関係(コミットメント)を持つことができないこと、それゆえにいつも人生に対して表層的な満足に止まざるを得ないこと、常に前に向かって突進しつづけているように見える起業家の人たちに深い憧憬の念を抱いていること…。こうした私の人生の繰り返されるパタンは、私のこの根源的な恐怖を言語の力によって封じ込めようというこの戦略と関係している。

これは、私にとって精神的な牢獄である。私は、この恐怖から逃れて、もっと自由に感じ自由に生きたい。しかし、いくらそう願ったところで、恐怖は私を解放してくれない。私は、ときどき、この「自己や環境に対する制御をすべて失う感じ」を抱いてパニックに陥り、そういう状況を与える事物から全力で逃走することがある。これは私の人生においてきわめて有害なパタンであり、こうした事態を避けるためには、大幅に安全マージンをとって行動せざるをえない。つまりパニックが起こりえない安全領域を慎重に歩む、きわめて保守的な生き方を強いられる。つまり「退屈」な生き方だ。

結局のところ、進歩は漸進的にしかやってこないのだろう。恐怖の核心に対して正面突破を試みるのではなく、漸近しつつ少しずつ日常圏から離れて負荷を上げていくこと…。つまらない話だがこれしか私の活動領域を広げていく方法はないのかもしれない。

    • -

私は、この数年間、いわゆる「普通の働き方」をしてこなかった。何が普通かは議論が分かれるところだろうが、サラリーマンの家庭に育った私にとって「普通の働き方」とは、週5日は、家から離れた場所にある職場で働くことだ。私は、細々とした自営業をやってきたので、家で仕事をすることが多かった。ITをメインにして自営業をしている頃はよかったのだが、それ以外の仕事では残念ながら生活を支えるだけの収入を得ることができなかった。だから、これから数ヶ月間、そういう「普通の働き方」を日本で試してみようと考えている。

私もかつてはそうやって普通に働いていたのだが、当時からこの働き方は私にとって快適ではなかった。いまからやってやれるものなのかどうか。やれるとしたらどれほど苦痛なものなのか。私は性格からしてこれからもずっと自営業を続けていくだろうが、経済状況によっては「普通に働く」ことを強いられるかもしれない。リスクに満ちた人生で「普通に働くことも苦手だが不可能ではない」という保険がほしい。たぶん人生に根源的な恐怖を持たないひとたちは、そんな保険をかけることなく人生を突き進んでいくのだろうが、私は残念ながらカッコいいアニメのヒーローじゃない。私は怖い。でもこの恐怖を乗り越えたい。だから保険を掛けるのだ。

    • -

私がこの数年間、人生の荒野をさまよう経験の後に得た教訓は、「収入は少なくてもいいから絶対にゼロにするな」だ。必ずしも常に貯金できるほど稼ぐ必要はないが、人間は常に何らかの形で働きつづけ、収入を絶やさないことが重要だと思った。仕事は、灯火に似ている。たとえ煌々と燃え上がらなくても、種火があれば、可能性は残る。一つの仕事はたいてい次の仕事につながるものだ。そうやって仕事をしつづける限り、生き残ることができる。ヒーローではないその他大勢である私たちにとっては、どんなにかっこ悪くても生き残ることがまずは肝要なのだ。そして生きていればよいこともいずれ必ず起こるはずなのだ。