web-dev-qa-db-ja.com

私はJavaScriptをよく知っていますが、コーディングインタビューを爆撃します

そのため、私は現在、フロントエンド開発者としての新しいポジションを探しています。私はJavaScriptをよく知っており、クロージャ、カリー化、プロトタイプの継承、デザインパターン、アプリのパフォーマンス、フロントエンドアーキテクチャ全体について詩的に理解できます。しかし、それでも私はまだ就職の面接を爆撃することになります。 (私がインタビューしているFYIの仕事のほとんどは、ある種のMVCフレームワークでSPAを構築するためのものです)

通常、コーディングテストは、私が専門的に遭遇したことのない小さなコードスニペットです。ある種の数学の問題を解く関数を書くように。片手で携帯電話を持ちながら見知らぬ人にコーディングを試みて画面を見たり、入力したすべての文字を見たりするという継承の厄介さは別として、私は通常、このようなものを実際に目にすることはありません。

これは私が欠けている深刻なスキルセットですか、それとも面接官が私に無関係な質問をしていますか?私は関数型プログラミングとアルゴリズムチョップに取り組むべきだと思いますが、Web(または印刷物)に多くの良いリソースを見つけていませんか?

33
Mike Fisher

コードの記述は、面接プロセスの一部にすぎません。

実際に論理的な問題を解決することは、コード作成タスクの一部にすぎません。

インタビュアーは次のことを確認したいと考えています。

  • コードを書くことができます。言語で10年のプロの経験を持つ多くの候補者は、コードをまったく書くことができません。このテストは、それらの候補者を拒否することを目的としています。

  • コードを書く前に問題について考えます。多くの人はキーボードにジャンプし、数十行のコードを記述してから、元の問題について誤解していることに気付きました。

  • コードを書くときに自分を適応させることができます。あなたが解決策を見つけたが、それを実装し始めたとき、あなたの最初のアイデアは最良のものではなかったように見えた。あなたはすぐにより良いものに切り替え、最終的にあなたが書いたコードをリファクタリングできますか?

これはまた、そのようなインタビューはよりinteractiveであることを意味します。片手で入力する代わりに、ハンズフリーキットを購入するか、Skype経由で電話してヘッドセットを使用します。仕事でタイプしているときに、コメントや説明をしながらタイプします。突然、扱いにくくなります。

ペアプログラミングをしましたか?はいの場合、インタビューの状況は非常に似ていますが、インタビュアーがあなたに意見を与えない場合があり、終了時にキーボードを一緒に切り替えるように要求することはありません。

純粋な数学問題のいくつかの例と、それが開発者の非数学的なスキルをどのように示すかを示します。

例1:単純なcoding演習

JavaScriptでフィボナッチ数計算機を実装する必要があります。インデックスを変更できるはずです。フィボナッチ数列は次の規則に従います。

  1. シーケンスの最初の2つの番号は0と1です
  2. 後続の各番号は、前の2つの合計です。

例:[〜#〜] f [〜#〜] = 0、[〜#〜] f [〜#〜]1 = 1、[〜#〜] f [〜#〜]2 = 1、[〜#〜] f [〜#〜] = 2、[〜#〜] f [〜#〜]10 = 55。

3分です。

ここで、面接担当者は、できるだけ早く考え、解決策を見つけて、迅速に実装することを望んでいます。このような演習は、実際の開発者が行うこととは無関係であり、CSの学位を取得するときに見つけることができるものに非常に近いですが、インタビュアーはこのようなことを好むので、実行しましょう。また、時間の制約により自動テストを行うことができないため、インタビュアーはおそらくこれを期待していません。

「アルゴリズムの説明で、再帰について考えさせられます。 2番目のルールは、次の再帰関数につながります。」

_var fibonacci = function (n) {
    return fibonacci(n - 2) + fibonacci(n - 1);
};

console.log(fibonacci(10));
_

「再帰を終了するために、fibonacci関数の本体を置き換えることにより、特殊なケースを追加します。」

_switch (n) {
    case 0: return 0;
    case 1: return 1;
    default: return fibonacci(n - 2) + fibonacci(n - 1);
}
_

「できました。」

結論

先ほど申し上げたように、このような演習は、実際の開発者の仕事とはまったく無関係です。意味がなくなりますか?少なくともそうではありません。

  • 問題について考えることができる。一部の候補者は完全に失われ、ストレス下では、問題に取り組むための可能な方法を考えるために割り当てられた時間よりも多くの時間がかかります。

  • 再帰を知っているか、通常のループを介して再帰を回避できます。後で、インタビュアーは、再帰を使用する方法/使用しない方法があるかどうか、および再帰の利点/欠点は何かを尋ねるかもしれません。

  • プログラミング言語の基本を理解している。人物がswitch、ガード節、条件付き、または 辞書 を使用しているかどうかは関係ありません。背景に応じて、候補者は同じことを達成するために異なるツールを選択します。

  • 単体テスト、スケーラビリティ、パフォーマンスなどをもたらすことなく、問題に集中し続けます。次に、面接担当者は、パフォーマンスに関して、上記の関数がひどい理由を尋ね、候補者がパフォーマンスを合理的なレベルにするために何をすべきか説明することを期待します。

例2:トリッキーな質問

JavaScriptでフィボナッチ数計算機を実装する必要があります。 できるだけ速くする必要があります。インデックスを0から100の範囲で変更できる必要があります。フィボナッチシーケンスは次の規則に従います。

  1. シーケンスの最初の2つの番号は0と1です
  2. 後続の各番号は、前の2つの合計です。

例:[〜#〜] f [〜#〜] = 0、[〜#〜] f [〜#〜]1 = 1、[〜#〜] f [〜#〜]2 = 1、[〜#〜] f [〜#〜] = 2、[〜#〜] f [〜#〜]10 = 55。

3分です。

ここで、面接担当者は候補者が問題を解決できるかどうかではなく、どの方法が他の方法よりも速いかを推測する能力に関心がないことを示す興味深い制約があります。

これらのトリッキーな質問は通常、トリッキーな答えを招きます。ここでは、時間の制約があるため、複数の実装を作成し、それらをベンチマークし、最速のプロファイルを作成し、最適なソリューションを提供する方法はありません。

代わりに:

「Googleに「最初のフィボナッチ数列」を許可してください... This は有望に見えます。とともに 簡単な (これはoxymoronになります)正規表現です。値のコンマ区切りリストを作成できます。」

_sed -e "s;\([0-9]*\) \([0-9]*\);'\2',;g" fbncc10.txt | tr '\n' ' '
_

「最後に、プログラム自体。」

_var map = ['0', '1', '1', '2', '3', '5', '8', '13', '21', '34', '55', '89', '144', '233', '377', '610', '987', '1597', '2584', '4181', '6765', '10946', '17711', '28657', '46368', '75025', '121393', '196418', '317811', '514229', '832040', '1346269', '2178309', '3524578', '5702887', '9227465', '14930352', '24157817', '39088169', '63245986', '102334155', '165580141', '267914296', '433494437', '701408733', '1134903170', '1836311903', '2971215073', '4807526976', '7778742049', '12586269025', '20365011074', '32951280099', '53316291173', '86267571272', '139583862445', '225851433717', '365435296162', '591286729879', '956722026041', '1548008755920', '2504730781961', '4052739537881', '6557470319842', '10610209857723', '17167680177565', '27777890035288', '44945570212853', '72723460248141', '117669030460994', '190392490709135', '308061521170129', '498454011879264', '806515533049393', '1304969544928657', '2111485077978050', '3416454622906707', '5527939700884757', '8944394323791464', '14472334024676221', '23416728348467685', '37889062373143906', '61305790721611591', '99194853094755497', '160500643816367088', '259695496911122585', '420196140727489673', '679891637638612258', '1100087778366101931', '1779979416004714189', '2880067194370816120', '4660046610375530309', '7540113804746346429', '12200160415121876738', '19740274219868223167', '31940434634990099905', '51680708854858323072', '83621143489848422977', '135301852344706746049', '218922995834555169026', '354224848179261915075'];

var fibonacci = function (n) {
    return map[n];
};

console.log(fibonacci(10));
_

結論

トリッキーな質問はトリッキーな答えを誘います。勇気を出さないでください。3分しかないときにベンチマークやプロファイリングを開始しないでください。経験を活用しながら、問題を解決するための賢い方法を考えてください。私の経験から、マップを使用する方が数値を計算するよりも速いかもしれないというヒントが得られます。それは間違っているかもしれませんが、時間の制約を考えると、この試みは予期されるはずです。

ツールを知ることも役立ちます。これは開発者のスキルの重要な部分です。正規表現を知らなければ、割り当てられた3分間グーグルでカンマ区切りのリストを作成するか、必要な配列を構築するパーサーの作成を開始します。

優れた開発者とは、すぐにコーディングを始める人ではなく、より良い機会が得られたときにコーディングを回避する方法を知っている人を覚えておいてください。一部の面接担当者は、コーディングのように見えますが、コードをほとんど必要としない割り当てをためらうことはありません。

例3:完全なアプリケーション開発

JavaScriptでフィボナッチ数列を実装する必要があります。シーケンスの長さは、プログラムの実行中に決定されます。シーケンスは次のルールに従います。

  1. シーケンスの最初の2つの番号は0と1です
  2. 後続の各番号は、前の2つの合計です。

例:0、1、1、2、3、5、8、13、21、34、55、89。

アプリケーションは、ユーザーが入力フィールドを介してシーケンスの長さを指定できるように、Webページとして提示する必要があります。

1時間あります。

はじめましょう。

「サンプルシーケンスは非常に役立ちます。これにより、一連の単体テストを実行して、実装が完全に間違っているように見えないようにすることができます。一般に、私はnode.jsにMochaを使用するか、クライアントサイドJavaScriptにQUnitを使用しますが、ここでは簡単にするために、たくさんのテスト関数を投げます。」

「_index.htm_および_fib.js_ファイルを作成することから始めます。次に、_index.htm_に、W3Cに準拠していない非常に最小限のコードを入力します(私のHTMLスキルにも興味がある場合は、後でこれに戻すことができます)。 "

_<label>Length</label> <input id="length" value="15" />
<input id="compute" type="button" value="Compute" />
<div id="result" style="font-weight:bold;"></div>
<div id="tests"></div>
<script src="fib.js"></script>
_

「フィボナッチジェネレーター関数を呼び出して結果を表示するコードを書いてみましょう。」

_fibonacci = (function () {
    var compute,
        init;

    compute = function (length) {
        // TODO: Implement Fibonacci sequence.
        return [1, 2, 3];
    };

    init = function () {
        var button = document.getElementById('compute');
        button.addEventListener('onclick', function () {
            var length = parseInt(document.getElementById('length').value, 10),
                result;

            console.log(
                'Computing Fibonacci sequence of length ' + length + '.'
            );

            result = compute(length);
            document.getElementById('result').innerText = result.join(', ');
        });
    };

    return {
        compute: compute,
        init: init
    };
}());
_

「コードを初めて実行するときがきました...機能しません。何も起こりません。なぜ?"

「OK、最後にfibonacci.init();を忘れてしまいました。追加しましたが、何も起こりませんが、少なくともコンソールにはメッセージが表示されます。ちょっと待って、それはonclickではなくclickです。私はJQueryを頻繁に使用するため、プレーンなJavaScriptでイベントの名前を忘れ始めます。」

「いくつかのテストを追加しましょう。」

_ensureAreEqual = function (expected, actual) {
    var testResultsContainer = document.getElementById('tests');
    testResultsContainer.innerText += (expected.equals(actual) ?
            '.' :
            ('Actual [' + actual.join(', ') + '] is different from ' +
             'expected [' + expected.join(', ') + '].'));
};

test = function () {
    ensureAreEqual([0], compute(1));
};
_

「配列の比較は注意が必要な場合があるので、 this answer から_Array.prototype.equals_コードをコピーして貼り付けます。」

「アプリケーションを実行すると、次のように表示されます。」

実際の[1、2、3]は期待される[0]とは異なります。

「フィボナッチ数列の実際の実装(_return [1, 2, 3];_)を考えると、テストは失敗しました。これを変更する時がきたのです。」

「元のステートメントから、フィボナッチ数列は_[0, 1]_で始まるため、computeは次のようになります。」

_compute = function (length) {
    var fib = [0];
    return fib;
};
_

「これにより、最初のテストに合格することが可能になり、2番目のテストを作成できるようになりました。」

_ensureAreEqual([0, 1], compute(2));
_

「失敗したので、computeに戻って変更します。」

_compute = function (length) {
    var fib = [0, 1];
    return length === 1 ? [0] : fib;
};
_

「これで両方のテストに合格しました。今度はEdge以外のケースに移行するときです。」

_compute = function (length) {
    var fib = [0, 1],
        i,
        next,
        current = 1,
        previous = 0;

    for (i = 2; i < length; i += 1) {
        next = current + previous;
        previous = current;
        current = next;
        fib.Push(next);
    }

    return length === 1 ? [0] : fib;
};
_

「100などの長い長さでは結果が正しく見えないことを除いて、3つのテストはすべて合格です。これらの結果を正しく得るには、 任意の精度のライブラリを使用する必要がありました 。改善すべき点もあります。たとえば、命名規則が悪すぎる場合があります(fibとは)。 HTML関連のJavaScriptコードは、テストコードだけでなく、別のオブジェクトにも移動する必要があります。また、compute(0)のテストも、入力のチェックも行っていません。」

結論

例を歩くと、インタビュー中に予想される相互作用を確認できます。すべてがスムーズであったわけではありません(最初にいくつかのミスをしたため、アプリケーションを実行しても何も起こらないという恥ずかしい状況になりました)。長いシーケンス長をサポートする必要がある場合、元のアプローチは不十分でしたが、達成しましたそれを示すために:

  • さまざまな問題を処理できます
  • 私はテスト駆動開発を使用しています。フィボナッチ数列はこのための絶好の機会です。
  • ソースが信頼できるときにコードをコピーして貼り付け、それを最初から作成すると、非常に複雑でエラーが発生しやすくなります。
  • 私はJQueryなどのライブラリに過度に依存していません。
  • 私は適切なスコープを選択しました。インタビュアーは私のJavaScriptスキルをチェックしたいので、完璧でクリーンなHTMLを書くのに時間を無駄にしません。ここで時間を費やさないことで、ユニットテストの作成により多くの時間を費やすことができます。
  • 多くのことが完璧ではないことを心に留めながら、いつ終了して完了したかを知っています(compute(0)のように失敗しますが、デモには関係ありません)。

これはまさに面接担当者があなたに期待するべきことです。

52