クリスマスの直後は、オハイオの会社からオファーを rescind したいとの連絡があり、雇用の件を白紙に戻されるという事態になっていました。どうも経営が芳しくなかったらしく、私がインタビューに行った後、会社に何かしらの変化があったのでしょう。いずれにせよ、少なからずショックだったのを覚えています。なので、年末も正月も自宅にこもり、ひたすらインタビュー対策の勉強をし続けてました。出口の見えないトンネルの中を迷走しているようで精神的にもかなりきつかったです。
ですが今日、ウィスコンシン州のマディソンにあるソフトウェア会社から software developer のポジションでオファーをいただきました。今度の会社は規模が大きく、インタビューのプロセスも何ステップにも渡る綿密なものだったので、いきなりオファーが白紙に戻るというようなことはないと思います。まだ最終決定は下していませんが、とりあえず首の皮がつながった感じです。
では、ここからインタビュー反省記に移ります。
Salesforce.com はクラウドコンピューティングの分野で非常に強く、日本国内でも日本郵政公社をはじめ Salesforce.com のシステムを導入している企業も少なくないようです。MSE の友人達で Salesforce.com から最初のコンタクトがあった人達は、みな行きたがっていたのを覚えています。私もそのひとりでした。
私が Salesforce.com と行ったインタビューは CMU キャンパスでのインタビューが一回と onsite のインタビューが一回で、アプライしていたポジションは software quality engineer でした。Salesforce.com では Apex と呼ばれる独自言語が開発に用いられているようですが、そのシンタクッスやメカニズムが Java に似ているのでしょうか、キャンパスでの質問は Java に関する質問が多かったです。とくに返答に困ったものはありませんでした。それに加え、あるプログラムの入力に対するテストケースを書く質問もありました。そのプログラムは単語の並びを逆転させるプログラムで、逆転の際、単語間のスペースの数は維持されます。たとえば、文字列 "My name is Yuki." が入力として与えられた場合、プログラムの出力は文字列 "Yuki. is name My" になります。私がテストケースとして考えたのは、プログラムが仕様通りにふるまうノーマルケース、入力が null や空文字のケース、入力がスペースを含まないケース(入力が "Hello" のときは "Hello" がそのまま返ってきてほしい、というのもスペース以外の文字が区切り文字と考えられている可能性があるかもしれないので)、あるいは入力が大文字のみ、小文字のみ、あるいはその両方が混ざった mixed case の文字列(プログラムが大文字から小文字またはその逆に勝手に変換するようなことがないことを保証するため)などをザッと挙げました(ほかにもテストケースを考えましたが、いまはちょっと思い出せません)。インタビューの終わりには、会社やポジションに関する質問をして、キャンパスでのインタビューはとくに大きな失敗もなく無事に終わりました。この時点ではまだ特に反省と呼べるようなものはありません。
数日後にリクルーターから連絡があり、そのまま onsite インタビューに行くことが決まりました。Salesforce.com の本社があるサンフランシスコはとてもきれいな街で、時間があれば観光もしたかったのですが、学期の真っ直中だったため、それはかないませんでした。
Onsite インタビューは 4, 5時間にわたる長いインタビューでした。全部で3つのパートからなり、プログラミングエクササイズ、テストケースを考える質問、アルゴリズムとデータ構造の質問でした。最初のプログラミングエクササイズでは、60分以内に文字列を操作するプログラムを2つ実装し、それぞれに対し JUnit のテストケースを書けるだけ書くというものでした。ただし、String クラスのメソッドは使ってはいけないという制約つきでした。さて、最初に「しまった!」と思ったのが、キーボートの配列が米国のキー配列だったことです。なにいってんの?と言われてしまいそうですが、日本から持ってきたラップトップをそのまま使ってた私はずっと日本のキー配列に慣れてしまっていて、米国のキー配列で (, ), ;, +, = などのポジションになかなか慣れず、コーディングに少なからず影響が出てしまいました。極度に緊張した状況下でこれはあってはならないことでした。Studio で一緒のメンバーだった Jeff からも常々「Yuki、米国のラップトップ使えよ」と言われてましたが、こんなところでネックになるとは思ってもみませんでした。ホワイトボードの上でのエクササイズであれば問題なかったんですけど。最初の反省、1) 米国のキー配列にとっととスイッチすべしです。
そして、実装するプログラムのひとつは、2つの文字列を比較する compare メソッドでした。シグネチャは
int compare(char[] a, char[] b)で、もしも辞書順(lexicographical order)で a が b の前に来るようであれば -1、a と b が同一の文字列であれば 0、a が b の後に来るようであれば 1 を返すメソッドです。具体的には、a が "apple" で b が "orange" だった場合(簡単のため String 型の表記をしています)、compare は -1 を返します。そのまま文字コードを頭から比べていけばよいものを、いま思い出しても信じられないのですが、なぜか私は a と b に含まれる文字をそのメソッドの中でソートしたんですよ。なので、"apple" は "aelpp" になり、"orange" は "aegnor" になってしまうわけです。これでは辞書順もなにもあったものではありません。おそらくこれはもうひとつのメソッドを実装する際に少し効率のよいアルゴリズムを使ってやれと思い、そのアルゴリズムを頭の中で思い出そうと必死だったため、今フォーカスすべきメソッドに集中していなかったせいかもしれません。まあ、それにしてもこれから辞書順を比較しようっていうのに、その文字列の中の文字をソートするってのはナイですよねぇ(笑)
で、そのもうひとつのメソッドというのが String クラスの split メソッドと同等の機能を持つもので、シグネチャが
char[][] split(char[] text, char[] pattern)です。text の中から pattern を探し出し、pattern をもとに text の文字列を分割します。たとえば、split("My***name***is***Yuki.", "***") の出力は{"My", "name", "is", "Yuki."} になります(また String 型の表記をしています)。私が非常に愚かだったのは、text の中から pattern を探し出すのに、for ループを二重にネストさせた簡単なものにすればよかったものを、Rabin Karp という文字列探索アルゴリズムを実装したことです。for ループを使ったアプローチより、Rabin Karp の実装には時間がかかりましたし、なによりRabin Karp で終わりではないのですから。そのあと text をスプリットし、例外的な入力がきても正しく振舞うように実装するには、むしろ文字列探索の後のほうの作業の量が多いです(インタビューのあと改めて実装してみてそう感じました)。なので、このアプローチは完全に失敗でした。Software quality engineer にとって重要な JUnit のテストプログラムの列挙も満足に網羅できませんでしたし、Rabin Karp をずっと考えていたせいで、compare メソッドの実装でも意味の分からないことをするし。うーん、なぜこんなアプローチをとったのか。Rabin Karp を実装しきれば、interviewer を impress できると思ったからか。まったくもって interviewer が何を期待しているかがわかっていない者の解答ですよね。教訓としては、2) インタビューなど限られた時間内での実装は、まず簡単なアプローチで攻め、期待されている答えに真っ先にたどり着くこと。改善はそれからです。MSE の Mel 先生もよく「First find a solution. Then make it better.」と言っておられました。まずとにかく動くものを考えろと。よりよいアプローチはそれからだ、ということですね。身をもって学びました。
テストケースを考える問題は、銀行の ATM をどうテストしますかというもの。ここで求められたのは、とにかく頭の中の assumption をできるだけ排除すること。たとえば、どんな人を対象にした ATM なのか?子供?成人?お年寄りの方?目の見えない方?それによって考えるべきテストケースが変わってきます。何をテストするかということを明確にしなければなりません。そして、普段自分はこんなことはしないだろうというテストケースを考えること。たとえば、偽札を入れてそれを正しく ATM が拒否するか、日本の一万円札とアメリカの100ドル札を混ぜて入れてもオーケーか、小銭の代わりに砂利を入れるとどうなるか、バンクカードのかわりに大学の学生IDカードを入れたらどうなるかなどなど。interviewer から指摘されるまで、ずっと ATM の入金や引き出しといった機能テストにばかり気を取られていたので、あまりよろしくありませんでした。このセッションでの反省は、3) テスターはまず何をテストするかを明確にするべき。そして"常識"という概念を排除してテストケースを考えるべしですね。
最後のアルゴリズムとデータ構造のセッションでは、辞書を実装しましょうという問題。辞書に対して考えられる操作としては、検索、編集、ソート、追加、削除などがあります。これを配列、リスト、2分探索木、ハッシュテーブルで実装するとそれぞれの操作の実行速度がビッグ・オー記法で考えてどう違いますかというものでした。それに加え、ある単語のアナグラムを全て辞書から拾ってきたい場合、どういうアプローチをとりますかという問題。アナグラムとは、文字の順序を入れ替えるとまた別の単語になるというものです(rat、art や dog、god など)。アルゴリズムのクラスや日ごろ自分で勉強したものが頭の中にしみついていたので、このセッションは一番よかったと思います。特に反省すべき点はないですね。
大ポカをあちらこちらでやらかしたせいで、onsite インタビューは通りませんでしたが、プレッシャーがかかった状態でアウトプットを出すにはどうすべきかということを学ばせていただき、貴重な経験をさせていただきました。インタビューの連絡も大変スムーズでしたし、Salesforce.com には感謝をしたいと思います。なお、米国のソフトウェア会社のインタビュー問題が知りたい方は、このサイトをご覧ください。有名どころの会社のインタビューの問題は、かなりの数網羅されています。特に Microsoft と Amazon のインタビュー問題が充実しており、私もインタビューの準備をする際は、このサイトを参考にしています。
反省点のまとめ with Salesforce.com
- 米国のキー配列にとっととスイッチすべし
- インタビューなど限られた時間内での実装は、まず簡単なアプローチで攻め、期待されている答えに真っ先にたどり着くこと。改善はそれから
- テスターはまず何をテストするかを明確にするべき。そして"常識"という概念を排除してテストケースを考えるべし
とても参考になりました!是非その他の会社についても書いていただけるととても助かります。
返信削除自分のTwitterアカウントは@starsky5なので是非followしてください :)
@Takeshiさん
返信削除そうおっしゃってくださって非常に嬉しいです。Salesforce.com 以外の会社はかなり早い段階で(onsite に行く前に) decline されているので、自分の失敗談や友人の成功談を交え、何をすればオファーをもらえるチャンスが上がるかについて書きたいと思います。
こんにちは。小山です。
返信削除すごい頑張ってますね。尊敬しますよ。
ただ、日本のラップトップを使っていて、アメリカのキーボード配列で戸惑ったところは、失礼ながら笑ってしまいました :)
それではまた。
@小山さん
返信削除ブログやメールで励ましのお言葉をいただき、誠にありがとうございました。あのときは精神的に一番きつい時期だったので、本当に助かりました。
私も小山さんの姿勢を見習い、自らの道を切り開いていこうと思います。これからもどうぞよろしくお願いいたします。
いや~、キーボートは(笑)普段楽している部分があると、こういうところでしっぺ返しが飛んできます。