優秀なソフトウェア開発者を採用する方法

今日本屋に行ったらこの本を衝動買いしてしまいました.

ソフトウェア開発者採用ガイド

ソフトウェア開発者採用ガイド

Joel on Softwareで有名なJoel Spolsky氏の新刊です.どうやったら優秀なソフトウェア開発者を採用出来るかという,ソフトウェア企業の人事担当者向けの本なのですが,学生が読んでも〈採用する側がどういうことを考えているのか分かるので)割と面白い本だと思います.ちなみにJoel on Softwareはまだ読んでません.読んでおくべき本としてよく挙げられている気がするのですが,実務としてソフトウェアを開発してない人にも楽しめる内容なんでしょうかね..
この本,今読んでいる途中なのですが,今まで読んだ内容から察するに,企業の人事担当者がどういう採用戦略をとっているかを見ることで色々分かることがありそうです.具体的には,面接官の方がこちらにどういう質問をしてくるか,またこちらの質問にどう応えるか反応を見ることで,どういう人を採用しようとしているか,つまり近い将来同期になるであろう人たちがどういうタイプの人になるか,大体予想出来そうです.そんな感じで一方的に面接するんじゃなくて,お互いに面接し合うぐらいで望めば良いし,ミスマッチ防止にも役立つんじゃないかと思います.ちなみに,本文では通常の採用面接以前に,インターンシップを通じて学生を囲い込むことのメリットや重要性も語っていたりします.
もちろんアメリカ西海岸での採用活動が背景なので,日本でどのぐらい当てはまるかは未知な部分が多いですが,少なくとも私はこういう採用方法をとっている企業があったら応募してみたいと思いました.
しかし最近買った本(一つ前のエントリ)と今日買った本の内容を比べると,自分の進路について揺れてるのが行動に現れてておもしろいと思いました.

はてなグループ内 はてブホットエントリ機能は,はてなグループのキラーファンクションになるんじゃないか?

追記

はてなグループのリニューアルが待ちきれなかったので自分でなんかそれっぽいものを作りました.
はてなグループで日記を書いてるメンバーの新着ブックマークフィードを取得するYahoo! Pipesを書いた - yanbe.diff - subtech
ホットエントリでは無いものの,それなりに面白いかもしれません

さらに追記

下記内容は はてなリングで同様のことが出来ると分かりました.たしかにそんな機能がありましたね.
http://python.ring.hatena.ne.jp/
今後は積極的に使っていこうと思います.


最近はてなグループを使い始めて思ったのだが.なぜグループ内はてブ ホットエントリ機能が無いんだろう.
あまりまとまってないですが,とりあえず以下,自分のTwitterの投稿から転載.Twitterは一人ブレストに向いてると思った.

昨今ソーシャルブックマークやデジタルデータのスクラップなど、自分のアンテナに引っかかる情報の蓄積方法は飛躍的に進歩してきました。 しかしそれらを自分の引き出しと..- 人力検索はてな http://q.hatena.ne.jp/12123... それはてなグループで出来るよ!

yanbe on Twitter: "昨今ソーシャルブックマークやデジタルデータのスクラップなど、自分のアンテナに引っかかる情報の蓄積方法は飛躍的に進歩してきました。 しかしそれらを自分の引き出しと..- 人力検索はてな http://q.hatena.ne.jp/1212356959 それはてなグループで出来るよ!"

はてなグループがストックとフローを両方上手く扱える事に気づいて,これはいいものだと思った.はてなグループはてなブックマークに次いでリニューアルの優先順位が高くすべきと思う.俺が使ってるからそう思うのかもしれないけど.

yanbe on Twitter: "はてなグループがストックとフローを両方上手く扱える事に気づいて,これはいいものだと思った.はてなグループははてなブックマークに次いでリニューアルの優先順位が高くすべきと思う.俺が使ってるからそう思うのかもしれないけど.."

@T_Hash なるほど..考えておきます.はてなグループは存在は知ってるけど何が嬉しいのかよく分からんというのが多くの人の印象だと思うので.

yanbe on Twitter: "@T_Hash なるほど..考えておきます.はてなグループは存在は知ってるけど何が嬉しいのかよく分からんというのが多くの人の印象だと思うので."

現在存在しないけどはてなグループのリニューアルで考えれる拡張として,グループ全体の日記の全文フィードと,登録メンバーだけが対象のはてなブックマークホットエントリ,新着ブックマークなどが挙げられると思う

yanbe on Twitter: "現在存在しないけどはてなグループのリニューアルで考えれる拡張として,グループ全体の日記の全文フィードと,登録メンバーだけが対象のはてなブックマークホットエントリ,新着ブックマークなどが挙げられると思う"

はてなグループ登録メンバーだけが対象のはてなブックマークホットエントリはキラーファンクションになると思うんだけどなぁ

yanbe on Twitter: "はてなグループ登録メンバーだけが対象のはてなブックマークホットエントリはキラーファンクションになると思うんだけどなぁ"

例えば編み物グループというのが存在するとして,そういうグループに登録しているユーザが興味を持ちそうなページがホットエントリに上がってくるイメージ.2chやプログラミング,ライフハックの話題などでは無くてね

yanbe on Twitter: "例えば編み物グループというのが存在するとして,そういうグループに登録しているユーザが興味を持ちそうなページがホットエントリに上がってくるイメージ.2chやプログラミング,ライフハックの話題などでは無くてね"

ちなみにはてなグループ登録メンバー全員の日記の全文フィードも本当ははてなグループ自身が持っているべき機能だと思う.

Hatena::Group::Subtechに入りました

http://subtech.g.hatena.ne.jp/y_yanbe/

今後は技術ネタのうち公共性の低いもの?はsubtechの方で気張らずにだらだらと書いていくことになると思います.

アウトプットの場所を分散させることになんの意味があるのか分かりませんが,なにか意味があるんじゃないかと思って何となくやってみてます.現状で多分10箇所ぐらいあるんじゃないかな.

一つ確かだと思っているのは,今使っているサービスに自分が書いた内容の蓄積があるからといって新しいサービスを試すのを躊躇するのはある意味機会損失だということです.どんどん新しいサービスを試していって,自分に最適なバランスを見つけつつ,それまでのアウトプットはうまい感じにアグリゲート出来ればいいんだよなー.

データと手続きを分離することは構造化プログラミングの基本ですが,Webサービスみたいなレイヤーにもそういう概念が今後求められていくんだと思う.現状で該当するのはRSSみたいな規格でそれ自体はよく出来てると思うのですが,他にもいろんなアプローチがあっていいと思うんですよね

Hatena::Group::Vimに参加しました

Twitter@kana1氏経由でHatena::Group::Vimというグループ]が存在する事を知り,参加しました.私のページはyanbe.vim - vimグループです.

vimのマニアックなネタを気軽に書ける雰囲気だし,そういうネタに対しても早速反応があったりするので気に入りました.今後Vim関連の小ネタなどはHatena::Group::Vimであまり気張らずにさくさく書いていく事が多くなると思います.ちなみにこれが初のはてなグループ利用だったりします.

参加した背景や今後の方向性など

私は基本的に,ブログはその人がどういう人なのか知るのに有用なツールでもあると思っています.なのでネット上でこの人面白いなーと思う人に出会ったときは,とりあえずブログをチェックします.

なので最初にはてなグループが発表されたときは,(どんなトピックも全部1つのダイアリに書いた方が,他の人からみてどんな事に興味を持っている(いた)人間なのか把握しやすいのに,なぜそんな事をするんだろう)と内心思っていました.しかし実際は,どうやら話題によっては適切な場を選んだ方が何らかの反応をもらえる可能性が上がるようで,自分にとってはそちらの方がメリットがあると判断しました.ちなみにyanbe (@yanbe) | Twitterもいつのまにかそういう存在になっていて,そろそろ6000updatesを超えようとしています.

はてなグループがサービスインして大分経ちますが,使い方というか関わり方がやっと分かった気がします.

今後必要になってくるのはこういう風に各Webサービスに分散した個人のアウトプットを一カ所に集約するようなサービスだと思っていて,Facebook - ログインまたは登録の方向性には同意するのですが,もっと簡単にサードパーティやユーザが対応サービスを拡張出来たりする仕組みがあればいいのにと常々思っています.

GVIMで編集中のスタイルシートの色をプレビューするcss_color.vimを256色ターミナル環境(Vim)でも動かすパッチ

6/30: 本パッチがcss_color.vim 0.7で正式に採用されました

6/12 19:15: 公開したパッチに不具合があったので修正
css_color.vimという,編集中のスタイルシート(*.css)の色(#FF0000)などに,シンタックスハイライトの設定をリアルタイムかつ動的に適用する事で,色をプレビューしながら編集出来るcss.vimというプラグインがあります.

css_color.vim - CSS color preview : vim online

http://lanpartei.de/~niklas/vim/after/syntax/css-color-vim.png

これは大変すばらしいのですが,GVIM用に書かれているため,内部でシンタックスハイライトの設定を"#RRGGBB"のような16進数で行っています.256色表示に対応したターミナルの環境でVimを使うには,このような形式ではなくxtermの256の固定パレット番号でシンタックスハイライトの指定をする必要があります,こういった環境を用意するには,xtermのコンパイルオプション(--256-colors)を設定したり,MacだとiTermというターミナルエミュレータを使うなどいろいろあります.

vim 256 - Google 検索

その一方で,GVIM用に作られたvimのカラースキームを256ターミナルで使うための試みが行われています.

frexx.de

ここでは#FF0000のような文字列をxterm-256colorのパレット番号に変換するツールが公開されています.このツールは

0. 「xtermのパレット番号と対応する(R,G,B)の組み合わせのマッピング」をあらかじめ用意する

入力:"#FF0000" のような文字列

1.  入力文字列をR, G, Bそれぞれの値に分解する
2.  あらかじめ用意したマッピングのうち,色空間上でもっとも近い色を選び,それを返す

出力:入力に対応するxtermのパレット番号

といったことをやっています.しかしこのツールはC言語で実装されているため,そのままではVimプラグインとして組み込む事は出来ません.

しかしそれほど難しいことをやっているわけではないので,これをVim scriptに移植し,上記のcss_color.vimの該当する箇所に組み込みました.具体的には現在の環境がターミナル(has("gui_running")が偽)で,使用可能な色数を示すt_Co変数の値が256だったときに,上記処理を適用するようになっています,

すでに作者の方にはパッチをメールでお送りしたので,次のリリースで反映されるかもしれませんが,自分で試したい方は以下にパッチを張りますのでよろしければどうぞ.

以下2008-02-12にリリースされたバージョン0.6のcss_color.vimに対するパッチです.元のソースコードはこのページから入手する事が出来ます > css_color.vim - CSS color preview : vim online

--- css.vim	2008-06-11 00:54:08.000000000 -0700
+++ css.vim.new	2008-06-11 03:12:38.000000000 -0700
@@ -26,20 +26,94 @@
    if s:currentmatch !~ a:pat.'\/'
       exe 'syn match '.group.' /'.a:pat.'\>/ contained'
       exe 'syn cluster cssColors add='.group
-      exe 'hi '.group.' guifg='.s:FGforBG(a:clr)
-      exe 'hi '.group.' guibg='.a:clr
+      if has('gui_running')
+        exe 'hi '.group.' guifg='.s:FGforBG(a:clr)
+        exe 'hi '.group.' guibg='.a:clr
+      elseif &t_Co == 256
+        exe 'hi '.group.' ctermfg='.s:Rgb2xterm(s:FGforBG(a:clr))
+        exe 'hi '.group.' ctermbg='.s:Rgb2xterm(a:clr)
+      endif
       return 1
    else
       return 0
    endif
 endfunction
 
+"" the 6 value iterations in the xterm color cube
+let s:valuerange = [ 0x00, 0x5F, 0x87, 0xAF, 0xD7, 0xFF ]
+"
+"" 16 basic colors
+let s:basic16 = [ [ 0x00, 0x00, 0x00 ], [ 0xCD, 0x00, 0x00 ], [ 0x00, 0xCD, 0x00 ], [ 0xCD, 0xCD, 0x00 ], [ 0x00, 0x00, 0xEE ], [ 0xCD, 0x00, 0xCD ], [ 0x00, 0xCD, 0xCD ], [ 0xE5, 0xE5, 0xE5 ], [ 0x7F, 0x7F, 0x7F ], [ 0xFF, 0x00, 0x00 ], [ 0x00, 0xFF, 0x00 ], [ 0xFF, 0xFF, 0x00 ], [ 0x5C, 0x5C, 0xFF ], [ 0xFF, 0x00, 0xFF ], [ 0x00, 0xFF, 0xFF ], [ 0xFF, 0xFF, 0xFF ] ]
+:
+function! s:Xterm2rgb(color) 
+	" 16 basic colors
+   let r=0
+   let g=0
+   let b=0
+   if a:color<16
+      let r = s:basic16[a:color][0]
+      let g = s:basic16[a:color][1]
+      let b = s:basic16[a:color][2]
+   endif
+	
+	" color cube color
+   if a:color>=16 && a:color<=232
+      let color=a:color-16
+      let r = s:valuerange[(color/36)%6]
+      let g = s:valuerange[(color/6)%6]
+      let b = s:valuerange[color%6]
+   endif
+	
+	" gray tone
+	if a:color>=233 && a:color<=253
+      let r=8+(a:color-232)*0x0a
+      let g=r
+      let b=r
+   endif
+   let rgb=[r,g,b]
+   return rgb
+endfunction
+
+function! s:pow(x, n)
+   let x = a:x
+   for i in range(a:n-1)
+      let x = x*a:x
+   return x
+endfunction
+
+let s:colortable=[]
+for c in range(0, 254)
+   let color = s:Xterm2rgb(c)
+   call add(s:colortable, color)
+endfor
+
+" selects the nearest xterm color for a rgb value like #FF0000
+function! s:Rgb2xterm(color)
+   let best_match=0
+   let smallest_distance = 10000000000
+   let r = eval('0x'.a:color[1].a:color[2])
+   let g = eval('0x'.a:color[3].a:color[4])
+   let b = eval('0x'.a:color[5].a:color[6])
+   for c in range(0,254)
+      let d = s:pow(s:colortable[c][0]-r,2) + s:pow(s:colortable[c][1]-g,2) + s:pow(s:colortable[c][2]-b,2)
+      if d<smallest_distance
+      let smallest_distance = d
+      let best_match = c
+      endif
+   endfor
+   return best_match
+endfunction
+
 function! s:SetNamedColor(clr,name)
    let group = 'cssColor'.substitute(a:clr,'^#','','')
    exe 'syn keyword '.group.' '.a:name.' contained'
    exe 'syn cluster cssColors add='.group
-   exe 'hi '.group.' guifg='.s:FGforBG(a:clr)
-   exe 'hi '.group.' guibg='.a:clr
+   if has('gui_running')
+     exe 'hi '.group.' guifg='.s:FGforBG(a:clr)
+     exe 'hi '.group.' guibg='.a:clr
+   elseif &t_Co == 256
+     exe 'hi '.group.' ctermfg='.s:Rgb2xterm(s:FGforBG(a:clr))
+     exe 'hi '.group.' ctermbg='.s:Rgb2xterm(a:clr)
    return 23
 endfunction
 
@@ -65,7 +139,7 @@
    endif
 endfunction
 
-if has("gui_running")
+if has("gui_running") || &t_Co==256
    " HACK modify cssDefinition to add @cssColors to its contains
    redir => s:olddef
       silent!  syn list cssDefinition

Google App Engineのテンプレートエンジン(Django 0.9.6)のfirstofタグが多バイト文字列に対応してない件

Google App Engineの個人的な印象

Google App Engine

  1. 作ったアプリのデプロイが楽
  2. 普段使っていて慣れ親しんでいるPythonを採用
  3. 標準で採用されている各フレームワーク(WebOb, Djangoのテンプレートエンジン)のセンスがいい

ということで,今のところ割と好きです.ただ,Google App Engineが現時点(2008年6月8日)ではまだPreview Releaseなので,今回,人柱の役目を果たそうと思います.

ちなみにこの問題のために1時間ぐらいはまりました.

djangoのテンプレートエンジンにおけるfirstof タグとは?

{% firstof var1 var2 var3 %}

こうするとvar1, var2, var3の順に変数を評価していって

  • 最初に偽でないと評価された変数のみを(文字列化して)出力する
  • 最後の変数まですべて偽だったら何も出力しない

というもの.

症状

firstofタグの引数に多バイト文字列な変数を与えると以下のようにUnicodeEncodeErrorがthrowされる

line 96, in render
    return self.template.render(context)
  File "/usr/local/google_appengine/google/appengine/ext/webapp/template.py", line 95, in _template_render_replacement
    return _original_template_render(self, context)
  File "/usr/local/google_appengine/lib/django/django/template/__init__.py", line 168, in render
    return self.nodelist.render(context)
  File "/usr/local/google_appengine/lib/django/django/template/__init__.py", line 705, in render
    bits.append(self.render_node(node, context))
  File "/usr/local/google_appengine/lib/django/django/template/__init__.py", line 718, in render_node
    return(node.render(context))
  File "/usr/local/google_appengine/lib/django/django/template/defaulttags.py", line 57, in render
    return str(value)
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-2: ordinal not in range(128)

原因

以下に示す通り,
django 0.96のfirstofタグ
が多バイト文字列の環境に完全には対応していない.57行目にてsys.getdefaultencoding()の文字コードでデコードされると考えられるが,この値はPython2.5においてデフォルトのエンコーディングはasciiである.一方で,Google App Engineではsys.setdefaultencoding()にてデフォルトのエンコーディングを変更する方法も無いため,多バイト文字列が入力されるとUnicodeEncdeErrorがthrowされる.

46	class FirstOfNode(Node):
47	    def __init__(self, vars):
48	        self.vars = vars
49	
50	    def render(self, context):
51	        for var in self.vars:
52	            try:
53	                value = resolve_variable(var, context)
54	            except VariableDoesNotExist:
55	                continue
56	            if value:
57	                return str(value)
58	        return ''

対策

対策方法1

多バイト文字列を扱う場合は firstof タグを使わず通常の{% if var %}タグで処理する.ifタグだと文字列を与えなくてもdecodeしないため,UnicodeEncodeErrorはthrowされない.

対策方法2

Google App Engine付属のテンプレートエンジン(django 0.96相当)ではなく,後述のとおり本問題が解決されている最新開発版のdjangoを,自分のGoogle App Engineの領域にデプロイして,そちらのテンプレートエンジンを使う

補足

なお,2008年6月9日時点での最新開発版である
django trunk(revision 7557)のfirstofタグでは,このバグは修正されている模様である.83行目のsmart_unicodeという関数のネーミングに開発者の苦労が忍ばれる.

72	class FirstOfNode(Node):
73	    def __init__(self, vars):
74	        self.vars = map(Variable, vars)
75	
76	    def render(self, context):
77	        for var in self.vars:
78	            try:
79	                value = var.resolve(context)
80	            except VariableDoesNotExist:
81	                continue
82	            if value:
83	                return smart_unicode(value)
84	        return u''