web-dev-qa-db-ja.com

アルゴリズムの格付け:読みやすさとコンパクトさ

次の試験/面接の質問を検討してください。


Cでstrcpy()関数を実装します:void strcpy(char *destination, char *source);

strcpy関数は、sourceが指すC文字列を、終了ヌル文字を含むdestinationが指す配列にコピーします。配列のサイズが指すと仮定します。 by destinationは、sourceと同じC文字列を含むのに十分な長さであり、メモリ内でsourceと重複しません。


あなたが面接官\審査官だったとしたら、この質問に対する次の回答をどのように評価しますか?

1)

void strcpy(char *destination, char *source)
{
  while (*source != '\0')
    {
      *destination = *source;
       source++;
       destination++;
    }
    *destination = *source;
}

2)

void strcpy(char *destination, char *source)
    {
       while (*(destination++) = *(source++)) ;
    }

最初の実装は単純です-読みやすく、プログラマーフレンドリーです。

2番目の実装は短い(1行のコード)が、プログラマーにとって使いやすいものではありません。このコードがどのように機能しているかを理解するのはそれほど簡単ではありません。このコードの優先順位に精通していない場合は、問題があります。

最初の答えは、両方のアルゴリズムが同じように動作し、コードのコンパクトさよりもコードの可読性が重要であると考えられているにもかかわらず、インタビュアーの\審査官の目には、より複雑でより高度な思考を示すのではないかと思います。アルゴリズムをこのようにコンパクトにすることは実装するのがより難しいので、試験の答えとしてより高いレベルの思考を示すように思えます。ただし、インタビュアー\審査官は、2番目の回答が読めないため、適切でないと見なす可能性もあります。

また、これはこの例に固有のものではありませんが、特に試験やインタビューで、アルゴリズムを実装する際のコードの可読性とコンパクトさの一般的な点についても触れておきたいと思います。

4
amiregelz

2番目の回答は、開発者がCEdgeのケースをよりよく理解していることを示しています。ただし、最初のバージョンは、これらのEdgeケースを理解する必要がないため、読みやすく、理解しやすくなっています。

質問された場合は、インタビュアーまたは審査官に何を求めているか尋ねてください。疑わしい場合は、毎回コンパクトさよりも読みやすいコードを探してください。面接官と審査官はすぐに決断疲労に達することができ、彼らを楽にすることはあなたを助けます。

面接官または審査官がもっと欲しい場合は、最初に読み取り可能なバージョンを作成し、次に2番目のバージョンを提供して、それが機能する理由を説明します。概念的な飛躍を短くできるため、これも役立ちます。

8
akton

それはすべて、そのコードの要件によって異なります。

  • それは速いことを意味しますか?
  • 最小限のメモリを使用するためのものですか?
  • 信頼できるという意味ですか?
  • それは維持可能であることを意味しましたか?

あなたが考慮する必要がある他の事柄はガイドラインです:

正しくする、それから速くする

最初の例は、3を満たす関数の理想的な最初の実装です。rd と4番目 上記の私のリストの要件。タイムクリティカルでもメモリ制限もないアプリケーションでも十分です。2番目の例は、1を満たす必要がある場合にコーディングするものです。st および2nd 要件または後で最初のコードに問題が見つかった(この特定のケースではありそうもない)。

テスターに​​関する限り、実際の補完すべきではないは、コードがテストに合格するかどうかを決定する要素です。重要なのはそれだけです:

  1. 正しい結果を生成します
  2. 「合理的な」時間内にこれを行います(アプリケーションごとに異なります)
  3. 「合理的な」量のコンピュータリソースを使用する(同上)

しかし、あなたの質問を読み直すと、インタビューを行っている人に「テスター」という言葉を使用していることがわかります。この場合、プログラマーのスキルレベルまたは能力を判断するためのコードを見ていると、2番目の例は、プログラマーがポインターとポインターのインクリメントがどのように機能するかを理解していることを示しているため、「より良い」でしょう。

ただし、コードが本当に「一度だけ記述」されていない限り(つまり、二度と見られることはない)、最初の例のコードが必要になることに注意してください。

7
ChrisF

Cでは、式x ++ = y ++は非常に一般的で簡単に理解でき、IMOは長いx = yよりも優先されます。 x ++; y ++; INTENTをより適切に表現するため、可能な限りいつでも。ループを終了するためのチェックが残ります。

while(*source != '\0')

vs

while(*source)

vs

while(*destination++ = *source++){}

2番目と3番目を理解するには、Cがゼロを偽と見なし、ゼロ以外のすべてを真と見なし、割り当て演算子が結果を返すという2つのことを理解する必要があります。

これらは両方とも、ジュニアCプログラマーにも根付いており、他の言語のプログラマーにも簡単に理解できるはずです。

要するに、私は2番目の方が読みにくいとは考えていません。実際、最初の方が++のない言語では、最初の方が読みにくいと思いますCプログラムのコンテキストで-もちろん必要ですが、言語bであるかのように言語aでプログラミングすることは混乱を招きます。 「なぜこのコードがそれをしているのか」という質問は「このコードが何をしているのか」よりもはるかに難しく、非標準的な使用法は私に理由を尋ねさせます...

ここで、何らかの理由でこれらをマークダウンしたい場合は、コメントがないことを確認してください。ポインタを扱うとき、そのような述べられていない制限はただ間違いを懇願しています。

6
jmoreno

一般的に、インタビューでコードを書くように人々に依頼する場合、私は彼らが私がデバッグして維持したいコードを書いているかどうかを調べています。それは私が最初の例のような答えを好むように導くでしょう。

ただし、この特定の質問をする人は、おそらく、インタビュー対象者が2番目の例の非常に一般的なstrcpyイディオムを知っているかどうかをテストしています。これは、ポインターとCに関する知識のテストであり、コードの可読性やコンパクトさのテストではありません。

3
Bill the Lizard

頭に浮かぶことがいくつかあります。

それが機能する場合、それは十分に良いはずです。コードのフォーマットに執着することは、時期尚早の最適化に執着することほど生産的ではありません。ほとんどの場合、それは価値を追加しません。

このコードの動作を理解するのはそれほど簡単ではありません。このコードの優先順位に慣れていない場合は問題です。 "。それは問題ですプログラマーはそのような構造に十分な能力がないため。このようなコンパクトな構造は、実際にはそのような単純なコードでは非常に一般的であり、経験豊富なプログラマーなら誰でもすぐに理解し、単純であるため実際にそれらを好みます。

これは非常にスタイルの問題であり、人によって異なります。このような質問に対する正解はないと思います。

1
zxcdw

テスターコンテキスト

まず、テスターを定義しましょう。ソフトウェア開発とソフトウェアテストの役割の違いは、たまたまソースコードへのアクセスに関係しています。開発者は、単体テストに重点を置いて、コードの詳細に常に連絡を取り合っています。テスターと呼ばれるチームメンバーは、ほとんどの場合、統合テスト、ストレステスト、負荷テスト、互換性テストに重点を置いて、実装の最低レベルを意図的に忘れています。したがって、テスト担当者は、タイプミスがビルドを中断したとき、またはスタックトレースがログを作成したときに、ソースコードの構造に気付く可能性が最も高くなります。

チームの他のメンバーが維持しやすいと思うスタイルを使用することは、通常、テスターが長期的にはビルドの中断や動作の欠陥を少なくすることを意味します。疑問がある場合は、チームに尋ねるか、単純さを追求してください。

コードレビューコンテキスト

もちろん、コミットする前に他の開発者がコードをレビューしている場合、コードスタイルの違いは重要です。組織/製品/プロジェクト内で標準的であるか、他のチームメンバーに馴染みのあるものが適切です。他は正しくありません-マイナスポイントとやり直し。

特定のプラクティスが現在の標準よりも優れている理由、および標準を更新する必要がある理由をこの開発者が説明できる場合(この質問はすでにいずれかの方法で利用可能な多くの引数をすでに提供しています)、それはプラスポイントですが、理由はありません最初に意図的に逸脱し、2番目のみを説明したため。

インタビューコンテキスト

インタビュー中、タイプミス、インデントの違いなどは実際には問題ではありません。 2つの実装は、まったく同じバイナリコードにコンパイルされます。同じタスクの標準(しゃれを意図した)実装と比較して、同等のサンプルのいずれかは、標準Cに精通していない人にとって、はるかに読みやすく、はるかに遅く、さらに より安全に使用できます 図書館。これは、タスクの「重複しない」部分がrestrictキーワードに変換された可能性があるが、変換されなかったことが一因です。

コーディングスタイルの違いは、開発者の魂についてのことを言っています。示されている両方のコーディングスタイルは完全に業界標準のものであるため、コーディングスタイルのみに基づいて候補者の経験やスキルを判断するのは愚かです。ただし、2人のプログラマーが最終的に異なる方向に向けられた役割を提供されるか、特定の組織がこれら2つの性格スタイルのうちの1つだけに適している可能性があります。

1
Jirka Hanika

最初の実装はストレートフォワード-読み取り可能でプログラマーフレンドリーです。

2番目の実装はより短い(コードの1行)が、プログラマにやさしくない;それは理解するのはそれほど簡単ではありませんこのコードの動作方法です。このコードの優先順位に慣れていない場合は問題です

そこにあなたの答えがあります。

インタビュアーがあなたのコードを見るとき、彼らはあなたのコーディングスタイルも見るでしょう。読みやすさは量産コードにとって重要であるため、そのようなコードを記述できることを示すようにしてください。
試験については、理解可能性も目指す必要があります。そのため、コードに欠陥があると誤って判断されることはありません。

1
Matsemann

なぜあなたは両方の答えを与えることができないのですか?

面接で間違った答えがあったと誰かに言われ、そのせいで仕事を拒否されたことがありますが、私の手順はうまくいきました。彼は読みやすい方法ではなく、迅速な方法を望んでいました(ゲーム会社でした)。彼は彼の巧妙な近道を説明したが、それでも私にとっては大きな失望だった。私は彼の解決策を調べて試す前に、数週間だまされたと感じてうんざりしました。それはそれが機能するのを妨げるであろう深刻なバグを持っていることが判明しました!

後から考えると、面接を終えた直後(または少なくとも翌日、冷静になったとき)に問題に取り組み続けるべきでした。そうすれば、私は彼に連絡して問題についての議論を続け、彼の好ましい解決策がどこで失敗したかを示すためにテストケースを電子メールで送信し、バグなしで問題をより近く解決する修正を提案することができました。

私が面接で質問した候補者のほとんどは、彼らを間違えました。私はついに諦め、候補者に彼らが興奮していると感じた最近のプロジェクトについて説明するように頼みました。それはおそらく、とにかくより良い面接の質問です。オープンエンドなので、誰かのスタイルや視点、知識や能力を感じることができます。誰かが質問に対して2つの正しい答えを与えて、相対的な長所と短所について話し合ったことがあれば、私は気が付かなかっただろう。そのような人は、有罪判決を受けた連続殺人犯であり、仕事を得ないために性犯罪者でなければなりません!多分私は最高の人材プールから雇っていなかったかもしれませんが、あなたはそれを持っています。

1
GlenPeterson