Python 開発者になるための採用面接準備 [翻訳記事]

nabbisen - Apr 12 '19 - - Dev Community

本記事は、以下の記事の翻訳です:
Preparing for a Python Developer Interview by Adam McQuistan on Stack Abuse
* 執筆者に許諾を頂いた上で掲載しています。


cover image

はじめに

私はこの記事で、自分の意見と提案について、述べて行くつもりです。それによって、あなたに Python のプログラミングに関する面接で、ライバルとなる他の候補者たちよりも目立てる最適なポジションに立ってもらいたい、と考えています。それがかなえば、あなたは Python 開発者としての仕事に就くことができるでしょう。

あなたはこんなことを考えているかもしれません。いま市場ではプログラマーが不足している。だから自分がしなければならないことは、ただ面接の場に出て、基本的な Python の文法に関するいくつかの質問に答えて、自分の学歴や資格の説明で残りの時間を埋めることだけだ、と。まずこの点からお伝えします。実際にはまったくそんなことはありません。仮にそれがうまく行ったとしても、あなたがチームで求められている資質を有していないと他のチームメンバに悟られてしまえば、雇用が長期間にわたることは無いでしょう。

さて、もしあなたが Python のプログラミング領域に進出し、さらには熟練の Python 開発者としての役割を担おうと目指しているのでしたら、このまま読み進められることをおすすめします。面接という名の競技場で、あたう限り勝利に近づくための、面接の秘訣をご紹介します。

Python の理解を深めましょう

Python 開発者を対象とした仕事に採用される人であれば、Python について理解している、というのは、当然のことのように思わるかもしれません。しかしながら、そうでは無いこともあります。あなたはもしかすると、Python の必須知識が無いままに、はったりを言って面接を切り抜けようと画策しているかもしれません。それはそれで、真剣に努力しなければ難しいものです。それよりは、貴重な時間を Python の最低限の基礎を身に付けるために費やすことを、今すぐにでも考えた方が良いでしょう。そうすれば、仕事を得るための面接において十分な対応をすることは非常に難しいということが、わかるでしょう。ただしもしも、他のオブジェクト志向の高級プログラミング言語(いわゆる Java、JavaScript、C#、......などです)を、何年にもにわたって使用した経験をお持ちでしたら、そこまでの話では無いでしょう。このようなことを言って、気を悪くはしないで頂きたいのですが......採用時に嘘はつかないようにしましょう。

最低限のこととして、次のことは説明できるようになっておきましょう。Python によく出て来る構文、すなわちループ / 制御フロー構造 / リスト内包表記について、です。それから基本的なクラスの定義もできるようになっておきましょう。もしもこの中に耳慣れないものが含まれているのでしたら、本記事(英語)と同じ StackAbuse 上にある Scott Robinson の 完全な初学者のための Python チュートリアル(英語) という記事を通読することをおすすめします。

プロジェクト事例を紹介しましょう

あなたは学校、コーディング・ブートキャンプ、あるいは現在もしくは過去の職場で、忙しくされていたことでしょう。それがわかった上でですが、私にとっては、このことの重要性をどれだけ強調しても十分ではありません。あなたは Python 開発職に採用されようとしています。その際、効果的なやり方で、雇用主であるマネージャーに確信を抱かせなければなりません。まず彼らが必要としているスキルを、あなたが持っているということを。次に、それがために、ある製品に対して、もしくは、いつの日にか製品になってその会社に価値をもたらすことになるであろうあるプロジェクトに対して、あなたが非常に大きい貢献ができるであろうことを、です。

私の経験上、コーディングができることを証明する最も良い方法は、適当な分量のコードを提示して、ソフトウェアに適用できる部品をつくる能力があることを説明する方法です。簡単な Web アプリケーションで結構です。あるいはデータ処理用のスクリプトでも、ミニマルなデスクトップ・アプリケーションでもかまいません。ここで重要なことは、構成が良いものを、きちんとした書き方で、且つ、読みやすいコードで書く力が、あなたにある、と相手に思わせることです。

このことを実現する最良の方法は、パブリックな Github や BitBucket、あるいは GitLab のリポジトリを持つことです。そこでサンプルのプロジェクト(群)を公開しましょう。そうすることで、あなたにとっての利点が生まれます:

  • オープン・ソース・コミュニティに参加することができます。それ自体すばらしいことですし、その中においても、すばらしいことに恵まれるでしょう。
  • あなたが Git のバージョン管理の基礎も知っていることを証明できます。
  • あなたの名前がそこに現れることで、同じような仕事のコンタクトを受けるチャンスが広がります。

二番目の点について触れておきます。サンプルのプロジェクトを構築する際には、それを実際のプロジェクトのように扱いましょう。すなわち、一回ごとに機能の一部分を完成させて、その内容を説明するコミット文とともにバージョン管理でコミットするのです。このことがもたらす効果にいずれ驚く時が来るでしょう。求人中のマネージャーは、あなたが Git のバージョン管理方法を理解していて、それを実施できることに、大きい価値を置くものです。

データ構造とアルゴリズムに関する技術を磨きましょう

まず第一に Python の一般的なデータ構造について理解しましょう。リスト、ディクショナリ、タプルなどについて、それからクラスのつくり方についてです。

次に、より汎用化されたデータ構造について理解すると良いでしょう。連結リスト、スタック、キューなどについてです。それらは Python の標準ライブラリでは必ずしも使われてはいないものです。しかし、この言語を使う中では、どこかで使う可能性があるものたちです。

Python の基本的なデータ構造と前述の汎用化されたデータ構造を比較対照できるようにも、なっておいた方が良いでしょう。リストのような既存の Python のデータ構造を用いてスタックのような機能を実装するのか、あるいは 連結リスト のようなクラスを手組みで実装するのかを選べるようにしておくのです。

以下は、連結リストを対象とした、手組みの実装のサンプルです。 Element (Node としての役割も果たしていますが)という内部クラスを利用して、データ要素を制御しています。

class Element:  
    def __init__(self, value):
        self.value = value
        self.next = None

class LinkedList:  
    def __init__(self, head=None):
        self.head = head

    def append(self, value):
        if self.head is None:
            self.head = Element(value)
        else:
            current = self.head
            while current.next is not None:
                current = current.next
            current.next = Element(value)

    def pop(self):
        if self.head is None:
            return None

        if self.head.next is None:
            value = self.head.value
            self.head = None
            return value

        current = self.head
        while current.next.next:
            current = current.next
        value = current.next.value
        current.next = None
        return value

    def peek(self):
        if self.head is None:
            return None
        current = self.head
        while current.next:
            current = current.next
        return current.value

    def remove(self, value):
        if self.head is None:
            return None

        if self.head.next is None:
            if self.head.value == value:
                self.head = None
                return True
            return None

        if self.head.next.next is None:
            if self.head.next.value == value:
                self.head.next = None
                return True

        current = self.head
        while current.next.next:
            if current.next.value == value:
                current.next = current.next.next
                return True
            current = current.next
        return None

    def insert_first(self, value):
        next_element = self.head
        self.head = Element(value)
        self.head.next = next_element

    def delete_first(self):
        if self.head:
            new_first = self.head.next
            self.head = new_first
Enter fullscreen mode Exit fullscreen mode

連結リストのような特定のデータ型を使うのが役に立つケースを、見極められるようにしておくと良いでしょう。

例えば、リストの先頭に対して頻繁に要素を追加したり削除したり、という操作を行うような場合、Python 標準のリストを使用するよりも、連結リストのようなものを使用する方が、はるかに効率的です。しかしながら、ここで特筆すべきことがあります。そのような操作が最も一般的に行われるのは、キューやスタックにおいてであり、連結リストは実際のところそれらに適用できます。しかし Python のコレクション・モジュールは既に、dequeという組込みのデータ構造を持っています。これは重要なことなので、面接で議論する時にも持ち出されるかもしれません。

Python の面接において、連結リストの手組み実装の話題が出て来た時には、独自クラスのコーディングのスキルがあることを、主として説明するようにしましょう。その中で Python 標準のリストと連結リストの仕組みの違いを話すのです。

それから、いくつかの基本的なアルゴリズムについても念頭に置いておきましょう。すなわち、ソートや検索のような一般的な処理を行う時に使われるものについてです。

例えば、リストにおいて、線形探索よりも二分探索の方が、はるかに優れたパフォーマンスを見せます。それがどのようなもので、なぜそうなのか、ということを説明できると良いでしょう。具体的に言いますと、線形探索では時間計算量が常に O(n) になりますが、かたや二分探索では O(log n) です。線形探索では無く二分探索を使うのに適したケースについても、説明したい、と思われるかもしれませんね。それなりに大きいリストを何度も検索することが見込まれる場合は、リストをソートして二分探索が行えるようにするための労苦を払う価値があるかもしれません。しかしリストの検索がほんの数回しか行われないような場合においては、ソートを行っても、その労苦に見合うものは得られないかもしれません。さらに、言及する価値のあることがあります。次のような場合は、ディクショナリのような他のデータ構造を使うだけで済むかどうかについて考慮するべきでしょう。すなわち検索キーがハッシュ化できる場合です。その場合、要素の検索や追加を本質的に O(1) で実行できるようになるでしょう。

問題を理解して解決するチカラ

特定の言語の、文法や、一般的に使われているデータ構造およびアルゴリズムを記憶することと比べて考えてみましょう。よしやそれらにどれほどの価値があろうとも、華のある開発者になろうとするならば、ずっと大切なことがあります。あなたをその他大勢から際立たせて見せることができる要素があります。問題、ユースケース、あるいはソフトウェアとして実装する好機、さらにはソースコードに落としてもらいたいと請われる事柄に関わる他の何か、以上のようなものに関する、それを理解するチカラです。

ここで要求されるのは、ハード面とソフト面、両方のスキルの組合せです。あなたは、積極的に特性上の要求やバグの詳細に耳を傾け、関連する事実をおさえ、さらには追加でキーとなるものを洗い出すための質問を投げ掛ける必要があります。それから、それらすべての情報を噛み砕いて、実施可能な個々のタスクやコンポーネントに落とし込む必要があります。それらが有機的に組み合わされて、やがて希望されている機能性を発揮するようになるでしょう。

私を信じてください。雇用者があなたの資質として見極めたいと考えているのは、究極的には、このことなのです。いかにして、あなたはプログラミングのタスクや課題と向き合うのか、ということと、あなたはキーとなる情報を集めて解決策を考案するためにそれらを使うことができるのか、ということです。

言うは易く行うは難し、です。しかしながら、成功の見込みを引き上げるために、できることがあります。何かと言うと、実践を たくさん 積んで、いろいろな種類の課題に挑戦すること、です。より多くの課題に取り組むことで、課題の汎用的なパターンをより多く認識し、解決策を続けざまに考案できるようになります。それらの解決策は往々にしてほんの少しの差分だけで調整可能なのです。プログラミングにまつわる課題を解決する経験を積むための良い方法は、Daily Coding Problem のようなサービスを使うことです。

Daily Coding Problem は、サインアップすると、毎日 Python で表現されたプログラミングの問題をメールで受け取れるようになるサービスです。一例を挙げますと、 Daily Coding Problem のホームページには、受信することになるであろう問題のサンプルが掲載されています。このようなものです。「N 段の階段があります。一度に 1 段もしくは 2 段だけ上ることができます。階段が N 段ある場合に、それを上るのに何通りの上り方があるかを返す関数を記述してください。上る段数の順番は区別するものとします。」

おもしろいことに、段数の組合せの順列は、階段が (N - 1) 段の場合と (N - 2) 段の場合の和に単純化できます。これはフィボナッチ数列において N 番目の数を得るためのアルゴリズムを実装するための主となるロジックであることに、お気付きになるかもしれません。

このことについて、もう少し踏み込ませてください。

階段が 1 段(N = 1)である場合、一度に 1 段もしくは 2 段だけ上る上り方で、何通りの上り方があるでしょうか?正真正銘の 1 通り、すなわち [1] の選び方だけですね。

N = 1 => [1]  
Enter fullscreen mode Exit fullscreen mode

では 2 段(N = 2)の階段ではどうでしょうか?

N = 2 => [1, 1], [2]  
Enter fullscreen mode Exit fullscreen mode

それでは、N > 0 である条件で f(N) = f(N - 1) + f(N - 2) の数式を考えてみましょう。

[1] + ([1,1], [2]) = [1,1,1], [1,2], [2,1] 
Enter fullscreen mode Exit fullscreen mode

先ほど言いましたように、これはフィボナッチ数例の再帰的な実装です。Python では次のようになります。

def step_combinations(stairs):  
    if stairs <= 1:
        return 1
    return step_combinations(stairs - 1) + step_combinations(stairs - 2)
Enter fullscreen mode Exit fullscreen mode

Daily Coding Problem では、毎日問題が送られて来るだけではありません。少しのお金を掛けることで、それらの問題に関する詳しい解説を得て、追加の応用問題を解くのに役立てたり、サービスから送られて来た解答と自分のものとを比べることができるでしょう。

より良い成果を出すために

本記事は Python 開発者としての仕事に就くための面接に関するものです。そのため私はここまで Python に固有の技術スキルに焦点を当てて来ました。しかしながら私の経験では、Python の開発者が実際に Python のコードしか書かない、ということはめったにありません。実際のところ、何か一つの技術やプログラミング言語しか用いずに仕事に取り組んで行こうという考えは、長期的な雇用を得ようと考える立場からは、まったくばかげています。

私からの助言は次の通りです。補助的な技術にも注意を払いましょう。質問の中で、しばしば「知っていることが好ましい」ものとして聞かれる技術があります。JavaScript、CSS、Java などなど......です。それらのことについても調べておきましょう。そうすれば、あなたには他の事柄を学ぶ能力も意志もある、ということを示せます。そしてその会社にあなたの価値を感じさせることができるのです。

もう一つ、実践しておくと良いことがあります。それはその会社に関する知識を持っておくことです。自分が働こうとする会社について、基本的な調査を行いましょう。その会社の何かしらに注目しましょう。その会社が持っているか、あるいは持とうとしている、主要な収益源や特徴的な文化が何であるのか、などについてです。

最後になりますが、決して小さくは無いことを、お伝えします。面接時の服装について、触れておきたいと思います。印象を与えるのに服装がものを言うことは、言うまでも無いことでしょう。しかし、実際に私が耳にしたり目撃したり、ということがあったのですが、開発者の中にはジーンズやパーカーを着た姿で面接に現れる人がいます......。アルバイトでは無いのですよ!もしもその会社の文化が十分にやわらかいものだとしても、最低限、ビジネス・カジュアルでは臨むべきです。ただし私はスーツをおすすめします。あなたはせっかく Python のすばらしいスキルを披露して、且つ、その会社への理解に相手を感心させられるように、努力をして来たのです。だからこそ、それを台無しにしないようにしましょう。「ううむ、この人はプログラミングのことを知っているのかもしれない。しかしそれは他の N 人の候補者も同じだった。そして、そちらの人たちは、アーケードからフラッと入って来ました、という感じでは無かったなぁ。」という印象を、初めに抱かせてはいけません。

簡潔に言いますと、身だしなみも輝かせましょう。Python のスキルだけでは不十分です。

おわりに

この記事で私は、自分の気付きに基づいた次のことを表現しようとして来ました。すなわち、Python の開発者としての採用面接において、ライバルたちよりもあなたを目立たせるための違いを生み出すものが何であるのかについてです。私は次の事々の重要性について述べました。Python を実際に理解していること、一般的なデータ構造とアルゴリズムを使えること、さらには Daily Coding Proble のようなサービスを通して多くの課題に取り組むことで、より優秀な課題解決者になること、についてです。それだけで無く、企業研究や適切な服装をすることのような基本的なことさえ述べて来ました。この記事の中に何かしらの価値を見出してくれることを願っています。しかし最も強く願っているのは、あなたが将来の Python の面接を突破するために、この記事が役に立つことです。

お読み頂いたことに改めて感謝申し上げます。コメントや批判がありましたらお寄せください。

参考情報


お読み頂きどうもありがとうございました。

本記事は、以下の記事の翻訳です:
Preparing for a Python Developer Interview by Adam McQuistan on Stack Abuse

To Adam: Thank you so much for your kind permission for me to translate your article.

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .