「転職しました」

2011年12月22日木曜日

あるいは、@muo_jpの頭の中。

技術の話だと思った?残念、さやかちゃんでした!
本エントリは「Android Advent Calendar 2011」への参加エントリです。12/22担当の@muo_jpと申します(ぺこり

「転職しました」というのは、ひょっとすると今年一番多く見たblog記事タイトルですね。転職アドベントカレンダーとか裏の裏の裏の裏の裏ぐらいまで開催出来るんじゃないかという勢いです。

イントロ
AndroidやiOSはエコシステム(生態系)を構成する要素です。OS本体だけで完結するものではなく、それを載せる端末、そして上位で動作するアプリケーション、その他サーバサイドなど数多の要素が複雑に絡み合ったものです。今回は、Androidエコシステムの中でも実際にアプリやハードウェア、サービスを開発している技術者にフォーカスした話を書いてみます。つまり、技術者の転職という話です。OSバージョンアップの話もADKの話も全部すっ飛ばして、転職の話です。
とにかく今年はAndroid界隈を中心に、自身の周囲で転職する人が多い年でした。そんな年の終わりに、技術者の転職というものと、これからの技術者における個人と会社のありかたみたいなのを考えてみた次第です。書いてるのは至って普通なことで、新しいとしたらAndroid好きなエンジニア(私)がAndroid方面の人々の転職を一年間眺めてきた結果を書いてるというあたりでしょうか。
技術者としての人生の考え方、転職の考え方などについて最近だと転職エージェント系の視点で書かれたのは多いけど、エンジニア視点ってのはあんまりないかなと思い、これは今年のうちにAndroidな話のひとつとして書いておいたほうがいいと信じ技術ネタをぶん投げて書くことにしました。
用意していたエントリを当日になってごっそりキャンセルしてこの記事書き始めましたさーせん。そして、内輪向けの書き方にならないよう注意を払ったつもりですが、通りすがりに読んでイミフ、という感じだったら私の力不足です。先に謝っておきます。

注意書き
  • 技術者転職how-toでも、技術者採用how-toでもないのでご了承ください
  • ごめんね、AndroidエントリなんだけどAndroid技術エントリじゃなくてごめんね

2011年、ソーシャル、スマートフォン転職の一年間
明らかに、転職の年だったという話。年の後半、秋口あたりから転職者がかなり多かった。最近だと@tomo_watanabeさんとか@adamrockerさんとか@zaki50さんとか。
少し引いて考えてみると、ソーシャル系とスマートフォン系、共に人の動きが激しい一年だった。
ソーシャル系は昨年の頭あたりからずっと。ソーシャル系では、サービス開発志向の人が多くSAPへ、より大規模なデータやインフラ/ミドルウェアへの興味が強い人が大手プラットフォームへ集中という構図。
スマートフォン系(iOS/Android)は今年に入ってから激しくなった。とはいえ、まだマネタイズが難しい。iTunes Store / Android Marketで展開するアプリにおいて、課金での売上を読むのは依然として難しい状況。スマートフォンの中でもB2Cでお金になっているのはソーシャル(特にゲーム)が多いという状況。
このへんは一定は産業化されてるという話を少々。ある程度新規参入しやすい領域というよりは産業化/大規模化が進行している。つまり規模の経済が成り立つようになりつつある。ゲーム系だと従来の大手コンソール向けゲームベンダーが強くなってる。
B2B(2C)の観点だと、ユーザのスマートフォン移行が急激に進行しているために従来提供してきたサービスをスマートフォンへ「対応させざるを得ない」状況が生じたことでの仕事が多いように見える。端末の販売に直結するAndroid本体周辺のプリインアプリケーションなども一定ボリューム投資されている状況ではあるが、支配的な発注額は占めていない(はず)。となると新規投資フェイズの会社へ行くか、ソーシャル系で筋の良さそうな会社へ行くか、B2B(2C)の発注者または受注者側へ行くか、はたまた全く別の軸を選ぶか、という流れ。

なんで転職の舞台がスマートフォン(特にAndroid)って話。単純に考えると、そのエリアに強い人の転職市場における市場価値上昇という話。これはAndroid端末の種類・出荷台数を見れば明らか。 だけどそれって本当にお金になってるの?って話は先程書いたとおり。ただ、アプリ/サービス開発需要が高まった結果、技術者の転職しやすい状況にはなった。
では、人の流動性って上がったのかな?というのは当然気になる疑問だけど、調べてない。同じく人材市場として観た際の流動性についても、上昇したのか否かという数字を持っていないので確実なことは言えない。
ここで成長してる市場における人材の流動性が高まるというのは、平均勤続年数が低下しつつ、平均給与が比較的変動しないないしは上昇する状況と考えられる。少なくとも自身の周囲では起きているように思うけれど、サンプルが少なすぎるのでなんとも言えない。

転職者の簡単なプロファイル的なもの。直感的にはこんな感じ、というのをまずぶん投げておく。
エンジニアに限って(というのが、他の方面の人をあんまり知らないから)言えばわりと独身者が多い。年齢的に20代半ばから30代前半辺りの人が多い。ちょうど企業の中での自身の成長というのを強く意識する頃かなという感じ。
リスクに対する許容度を考えてみる。リスクの許容度は、当然結婚や子供によって左右される。リスクを取ってでも新たな行動を取ろうとするモチベーションについて考える際に参考にしたいのはマズローの欲求階層仮説。彼は人の欲求を以下の5段階に分け、このより高いレベルに向かって希求するものだとした。
  1. 生理的欲求 / 生命維持のための食欲・性欲・睡眠欲等の本能的・根源的な欲求
  2. 安全の欲求 / 衣類・住居など、安定・安全な状態を得ようとする欲求
  3. 所属と愛の欲求 / 集団に属したい、誰かに愛されたいといった欲求
  4. 承認の欲求 / 自分が集団から価値ある存在と認められ、尊敬されることを求める欲求
  5. 自己実現の欲求 / 自分の能力・可能性を発揮し、創作的活動や自己の成長を図りたいと思う欲求
5段階の中でフェイズの壁を感じた時に、自身の状況を強く考えるんじゃなかろうかというのが、直感的なところ。けどそれだけだとなんだかうそくさいので、いろんな人のケースを考えつつもう少し検討してみる。

転職していったひとびと
私の周りには、前向きな転職をしてる人が多い。いやまあ、後ろ向きな理由を好んで話すようなもんじゃないだろうからそう見えてるだけかもしれんけど。
これには時期的な事情が多分にあると考えられる(このへんは2節目で書いた)。もちろんクリエイターに認められない部分はあるけど、Androidは常用端末として一定以上の地位を占めるようになってるのは事実。
前向きな転職する人が多い一方で「Androidなんていう、まだ誰も知らないけどきっとこの先大きなうねりを生みそうな技術に賭けるために完全に畑違いだけど行くぜ」って感じのは、もうないんだろうな。ちょっと寂しい。まあいいや。
それはさておき。
エンジニアな人(特に、Android界隈に居る人々)の頭の構造ってどういう感じだろうと考える。
実際にどんな転職した人が居るっけ。1年前ぐらいから転職してる人多い。具体名を挙げるのは控えたい。数例を挙げるとこのような感じ。
  • メーカー勤務でわりと好き勝手にやれて給料も良かったけれどスタートアップへ転職した人
  • メーカー勤務で技術的な挑戦エリアの狭さを感じ、またその組織を変えていくことが非常に困難だと感じてスタートアップへ転職した人
  • メーカーの研究所勤務で、実際に新しい技術を使った開発を行いたくてスタートアップへ転職した人
  • 新卒からSIer勤務で自身の技術的な興味範囲と周囲のギャップに悩みスタートアップへ転職した人

かくいう私も転職組でね。あんまり長々と自分語りをしたいわけではないのでサラッと書いておくと私のバックグラウンドは経営学、生き方は主にテンションベース。身の回りに凄い人が多くて、そういう人と話すと、めっちゃテンション上がりながらめっちゃ憂鬱感じるという驚異の重ね合わせ状態を体感出来て楽しい、という感じ。
さて、そう言うほどAndroid方面の方々の転職話をしっかりと知っているわけでもないので、以下の分析では他に私が話を聞く機会があった方の中でマインド近そう、と感じた人の分も含めてみる。
皆がどういうポイントを重視して転職していったのかという話
  • 十分なお金を稼ぐことが出来るか
    そして、それが本源的に持つ金銭的価値と比較して適切と考えられるか(バブルならバブルで、期間の読みは妥当か)
  • 人間関係
    自分の求める距離感とマッチしているか(ある意味、会社の空気)
  • 会社から受けるストレス
  • マネージャとの関係
    エンジニアはエンジニア出身のマネージャなど、技術面で何かしらの尊敬を出来たりする人の言うことしか聞かない(ってことが多い)ので、マネージャが技術に対して一定以上の認識を持っているかどうか
  • 新しいことが出来る環境か
    AndroidやiOSなどに特化したスタートアップへ転職した人にはここが大きい感
  • 自身の人生の中でのステップ
    技術に深く関わり、自ら実装するフェイズからマネジメントフェイズへの移行なども
  • 会社の未来
    時代の変化にあわせて仕事の中身を変えていくことが出来るか
  • 自身でどこまでをコントロールすることが出来るか
    まずいところがあったとしても、自分の力で変えていくことが出来るか
    これをコントロールしたい度が強いほど、初期スタートアップへ行ってる感
  • 自身が会社のメインストリームに居らるかどうか
    メインストリームに居るべきと考えられるのか(むしろ新規投資系の事業に居たほうがいい場合もある。このへんは会社のスタイルによる)
  • 尊敬できる人が居るか
逆に、このへんの全てではないけれど一定の領域で満足を得られている人は転職していないし、当分転職しなさそうな人も多い。

転職していったAndroiderってこんな人かなー

  • 会社以外の人と触れる機会が多い人
  • 社外の勉強会や定例会での発表を行なう人
  • 積極的に情報を取り込み、自分の中で処理して発信する人
  • 飲み会好きな人
  • なんか新しいことやってみるのが好きな人
  • ヘンな人
    • 尖った分野を持ってる人
    • いくつかの分野を合わせてヘンなことを出来る人
  • 技術に対して取り組む姿勢(ここはあんまり一致する像が浮かばない。むしろいろいろ)
    • 技術がとことん好きな人も居る
    • 技術を使ってなにかを作ることが好きな人も居る
    • 人を巻き込んでサービスを作るのが好きな人も居る
  • Android好き?
    • 必ずしもAndroid大好きじゃない人も
これからのAndroid界隈の転職の形
業界全体としてマネタイズ策がもっとうまく出来て行かないと、早晩限界が来そう。当然単価は下がるしオフショア化もある程度は出来るようになっていくから(特に、新しいことをやるよりも既存の仕組みをルーチン回して新サービス/アプリ化する仕事から順次)。
大手志向って出てくるの?これ、微妙なところ。
個人(フリーランス)でやるか、会社でやるか。個人のほうが自由を確保出来るか?という話。会社で一定安定した収益基盤を保持しているほうが、積極的な投資を行える場合もある(これは会社の文化にもよる)。
個人対会社という構図。
技術者を集める構造とか分かる?技術者にとって、よりよい会社のありかたってどんなものだろう。技術者が会社に対して持つ要望(先ほど挙げたのが一例)を、全てではないにしても可能な範囲で満たすこと。難しい?難しいですたぶん。けど、他の会社が技術者に対する魅力を一定以上訴求するようになれば、ここを頑張らなきゃどうしようもなくなるので、この先はもう少し頑張る会社が増えると読んでる。
どういう会社に転職するとこの先幸せになれるんだろう。人によって全然違う。しかし、やっぱ凄い人が居るところに人は集まる。会社は自社の魅力をこれまでよりももっとオープンにすれば、割と伝わりやすい時代にはなってる。

会社と個人がうまく付き合っていくには
個人対会社というのは敵対関係じゃないし、片側が搾取する関係でもないべき。どっちかというと補完的なもの。会社だと厄介だけど個人だとやりやすいってエリアは、ここ数年かなり増えてる。例えばOSSの利用ひとつとっても、会社でGPL'edなソフトウェアのソースを利用して何かを作ってリリースというのは、現実問題結構大変。個人なら、当然自分自身の判断でなんとかなる。稟議の行列がしんどいと思うものはどんどん個人化してしまうのが良いはず。
その結果「会社で出来ないから個人でやる」というものがどんどん増え、開発者の会社に対するコミット度合いがどんどん低下するようなら会社のあり方を考えないとまずい。この意味でも「時間を100%コミットして、仕事終わったらヘロヘロになって自分の時間で何も出来ないような状態が恒常的である会社」などでは、その業務自体から得られる成長や満足が一定以上なければ人の流出は止まらない。
どういう形であれば個人の成長と会社でのアウトプットを両立出来るんだろう。ここには割と考えられることがあって
この1年間とか3年間とかを振り返って自分は成長することが出来た?出来たならそれは会社のおかげ?自分のおかげ?出来なかったならそれは会社のせい?自分のせい?それって多分一歩引いて考えると自分のせいなんだけど会社を変えることで改善しそう?
という問いを自分に対して投げかけてみて、会社での成長(または金銭面を含めた満足)と個人での成長(または金銭面を含めた満足)がバランスしているかを見ると、そこそこ分かる気がする。それと、関連してこれからの技術者像ってのを考えてみる
  • 社内・社外及び社内+社外でのコラボを多めに
    自身の視点を広げ、現時点で自身の持つ価値を比較的正確に把握するため
  • 技術だけでない、せめてもう一つの視点を持つべき
    経営視点?サービス視点?デザイン視点?自身が既に持っているバックグラウンドなどをほどよく活かしつつ、従来とは異なるエリアへ取り組むことで継続的な成長を習慣付けることが出来そう
こういう感じだと、会社と個人というのをうまくバランスさせて成長していくことが出来そうな感じ(自分の周囲とか見ていて感じるものなのであんまり客観性無いけど)。
一方、会社としては、人を囲い込むのが良いかというとそんなことはない。人間関係でも会社対個人でも、ヘタな囲い込みをするほど相手をなめちゃいけない。例えば、人材流出を防止する目的で勉強会参加禁止措置を取るなどすると、どんどん人は辞めていく(出来る人からやめていく)。

この1年半のうちに転職した人間として
作りたいと思った瞬間がアプリ/サービスの作りどき、端末は買いたいと思った時が買いどき、転職しようと思った瞬間が転職どき。
となると、自分がどういう状況になったら転職したいと思うのか、ということを想像しておくと兆候を掴んだ時に動きやすくなる。自分の場合は、だいぶ前にITをやるということだけ決めて仕事を始めたので、前職がITやめると決まった瞬間に転職活動始めた。確か、電話で話し終わった瞬間にDoDA開いてた。
twitterや各種Android関連の集まりで会える人って、面白いバックグラウンド持ってる方が多い。なんせ、Android界隈って起源が全然違うめっちゃ多様な人々が集まってる。そしてエンジニアがいかに大切な存在かということを分かってる人がいっぱいいる。だからこそたまに異様に心強いんじゃないかなー。生き方とかも参考になる。
つい先日も「これからの年収の話をしよう」という話があったりと、先輩に学ぶことも多いしね。割と損得抜きに思いをぶつけられる相手が多いような気がする。もやもやしたら(問題無い範囲で)ぶつけてみたらいいんじゃないかな!
人生は考えたほうが断然楽しい!

ということで
私、中澤 慧は12/31付でKLab株式会社を退職しません
私、来年はたぶんPS Vitaで遊びます。SDK欲しいです。
実は、@vvakameに「みゅおの頭の中みてみたい」と言われたので書いてみたというのも少しあります。小ネタの仕込みから、アニメネタへ偏ってるかが分かると思います(攻殻/まどマギ/ピンドラ)。
あ、そうそう。最近読んだ中では「先延ばし屋の予定帳」が秀逸でした。締め切りすぎないとパフォーマンスが上がらん的な話。締め切りを2倍過ぎてから作業を始めると、どんなに悪くても締め切りを4倍遅れることはないという素晴らしい理論です(白目)。

ではではこんなところで。長文お付き合いありがとうございました。来年も楽しい一年になりますように、そして(省略されました…続きを読むにはご自身で書いて下さい)

TopCoder SRM練習 - SRM 525 DIV 2 Easy/Medium

2011年12月4日日曜日

次回のSRMで復帰予定なのでそろそろ感覚取り戻していくべく練習。
以前とは違ってSRM同様75分の中で解くのを重視。

今回やったのはSRM 525 Div 2

まずはEasy問題。
(0, 0) - (N-1, 1) の 2 x N な通路中を(0, 0)からスタートして(N-1, 0)まで到達出来るかどうかを判定して返せ
という問題。で、条件としては「1点以上を共有しているマスには移動できる」の中で制約に「Wとマークされているマスは水浸しで通れない」ってのがある。
少し図に書いて考えてみると
□□
□□
ok
□■
■□
ok
■□
□■
ok
□■
□■
ng
■□
■□
ng
ということで、縦にFが2つ並んでいるものを除けば良いということになる。で、これはうっかり忘れてたのだけれどゴール地点がW(水浸し)ならそもそも到達不可能として弾かなきゃいけない。後から問題の制約条件読むと「道の最初と最後は水浸しじゃない」と明記されてたので救われた形。
public class RainyRoad {
 public String isReachable(String[] road) {
  int width = road[0].length();
  for (int i = 0; i < (width - 1); i++) {
   if (
     (road[0].charAt(i) == 'W' && road[1].charAt(i) == 'W') ||
     (road[0].charAt(i + 1) == 'W' && road[1].charAt(i + 1) == 'W')
     ) {
    return "NO";
   }
  }
  return "YES";
 }
}
コードはこのとおり。無駄に2列ずつやってるのは、最初のうち問題を読み間違って「上下左右にしか動けない」と勘違いしてた状態で書いたコードの残骸(非効率だけど間違いではない)が含まれるから。システムテスト通ってスコアは212.31 / 250。

続いてMedium問題。
読んだ瞬間には「うわ、GDD DevQuiz系?」と探索アルゴリズムに弱いのを思い出したけど、まずはしばしごにょごにょ考えた。
問題をざっくり訳すと
指定サイズ(1辺は1-30マス)の盤面のいくつかのマスにコインが置かれてる。このとき、コイン群を盤面全体に対して上下左右いずれかに動かし、盤面の端から適当な数のコインを落として指定された(K枚)のコインのみを盤面に残すための最短手数を返せ
というもの。
単純に考えると1回のオペレーションで4通り、探索すると最大30x2=60手なので2^120ぐらい読む必要がある。これは2秒の制限中では明らかに無理。
ということでしばらく図を眺めてごにょごにょと考え「移動順はともかく、元盤面の中でサブの盤面を定義してその中にK枚のコインが残るようなケースのうち最も手数の少ないものを探しだす」んだと思いついた(ちょい遅かった)。
こうすると始点と終点の選び方で30^4、選んだエリアの中に含まれるコインの枚数を数えるのに最大30^2(実際はサブセットに限定される分、もうちょい小さい)の計30^6、ループは7億回ちょいとなって2秒制限の中ではやばい感じがするけどひとまず実装してみた。
ちなみに実装中に考えていたループ回数の低減策は「指定エリアに含まれるコイン枚数を辞書として持つ」で、計算量的には30^4+30^2と相当効くはず30^4+30^4となって半分程度に出来る(辞書の辿り方によってはむしろ悪化する)。ただ、その分81万要素を保持する必要が出てくるので変なパックするとメモリ足りなくなる(64MBしか使えないらしい)。まあこのあたりは一旦HashMapあたりで作って不足するならcharの配列あたりに落としていけばいいかなと。
で、そんなことをほんのり考えつつひとまず書いたナイーブな実装がこれ。
public class DropCoins {
 public int getMinimum(String[] board, int K) {
  int min = 9999;
  int width = board[0].length();
  int height = board.length;
  for (int i = 0; i < width; i++) {
   for (int j = 0; j < height; j++) {
    for (int k = i; k < width; k++) {
     for (int l = j; l < height; l++) {
      // (i, j) -> (k, l)
      int tmpCnt = 0;
      for (int m = j; m <= l; m++) {
       for (int n = i; n <= k; n++) {
        if (board[m].charAt(n) == 'o') {
         tmpCnt++;
        }
       }
      }
      if (tmpCnt == K) {
       int left = i;
       int top = j;
       int right = width - k - 1;
       int bottom = height - l - 1;
       int steps = 0;
       if (left < right) {
        steps += left * 2 + right;
       }
       else {
        steps += left + right * 2;
       }
       if (top < bottom) {
        steps += top * 2 + bottom;
       }
       else {
        steps += top + bottom * 2;
       }
       if (steps < min) {
        min = steps;
       }
      }
     }
    }
   }
  }
  return (min == 9999 ? -1 : min);
 }
}
時間切れになるかなーと思いつつシステムテスト(この適当さがあんまり良くないんだけど)走らせたところ、最も時間のかかるケースで411msかかりつつも時間内に処理出来てパス。スコアは265.44 / 600。
例によって道筋が立ってからはほとんど一本道でいけたけど危なくてしょうがない。
tmpCntのカウント中にカウントがKを超えた場合には途中で諦めるというのも手なんだけど、そのぶん分岐が増えるわけで微妙。

Hard問題は開いてないし当分開かないでいいと思う。