「駄目な面接の質問」にあるコピー関数の要件定義を回答してみる。

元ネタ

http://www.aoky.net/articles/david_pickett/stupid_interview_questions.htm

* 著者の知人がプログラマの面接で、ファイルコピー関数を書くように言われた
* 著者なら「タイムスタンプは？」「スプーフィングは？」と細かく聞き返して相手を困らせただろう

というお話。

　自分がこの面接官だったらどう答えるか、知恵を絞って書いてみることにしました。知らないことばかりでGoogle先生だよりですが、とりあえず最後まで答えることを目標に。

以下「Q」はそのまま、「A」の行を自分なりに変更しています。

----

Q. 「コピー」というのはどういう意味ですか？

A. ファイルの中身を新しいファイルにコピーするということです。

Q. タイムスタンプはどうすればいいでしょう？

A. 作成時刻はコピー完了日時、更新日付は元のファイルのままにしてください。

Q. 新しいファイルは名前も同じにする必要がありますか？

A. デフォルトは同じファイル名です。上書きしそうなときは実行されないようにしたいですね。

Q. 同じ名前でもかまいませんか？

A. 上書きしなければ、同じ名前でOKです。

Q. スプーフィングを気にかける必要はありますか？ それにトルコ語のIは？

A. ファイル名はASCIIと日本語以外許可しないでください。記号については相談させてください。OSによってNG文字が違うこともあるので。ここで日本語というのはUnicodeのここからここまでの範囲です。

Q. 同じ場所に作る必要がありますか？ 同じ場所なら(たぶん)同じ名前にはできないでしょう。自分自身にコピーするというのでもないかぎり(それはそれで別な疑問が出てきますが…)。

A. 自分自身へのコピーはしません。

Q. 属性はどうしますか？

A. 難しいですね。同じだと問題ですか？(わからない)

Q. 元のファイルの属性を変更すべきですか？ そのファイルコピーがバックアップやアーカイブ操作で使われるなら、「アーカイブ」属性をオンのままにしておくのは間違いだと思いますが。

A. そうなんですか。バックアップがちゃんと動作するように属性変更お願いします。

Q. 元のファイルのアーカイブ属性がオフならどうしますか？ 新しいファイルもオフにするんですか？ それだとユーザのバックアップソフトの動作が変になりそうですが。

A. バックアップは必要ですね。Windowsシステムの普通のコピーを使った時の動作を確認して、それと同じように属性変更しましょう。

Q. ユーザのためのソフトウェアのデザインを考えるアプローチとしてそれがいいかどうか疑問ではありますが、そう言われるのであれば。

A. はい、ユーザのためにちゃんとコピー関数作りましょう！ 

Q. 圧縮はどうしますか？ これもファイルの属性ですが、コピー先の場所で圧縮がサポートされていない可能性もあります。

A. ググったんですけど、圧縮属性はNTFSのみで動作するそうですね。Windowsの通常コピーでは、FAT32にコピーしたときは圧縮を解除するのだとか。SDカードにコピーすることは使用条件で想定されるので、コピー先が圧縮不可かどうかチェックして、必要に応じて圧縮を解除してください。

Q. 元のファイルが圧縮されていて、コピー先で圧縮がサポートされていてもですか？

A. そうです。(変更なし)

Q. 暗号化はどうでしょう？ 元のファイルが暗号化されていて、コピー先の場所で暗号化がサポートされていない場合は？

A. えーっと、これちょっとよくわからないですね…ただ、元の解答にある「暗号化を解除」というのはセキュリティ上の問題があります。コピーされても読まれないように暗号化されているものと思いますから、暗号化されたままコピーするのが良いのではないでしょうか。

Q. うーん。話がそれるようで申し訳ないんですが……それは深刻なセキュリティホールになり得ますよね？ 特にそのファイルコピー関数が(直接間接に)任意のパラメタをサポートすることになるとしたら。

A. (回答スキップ)

Q. 作成者はどうしますか？

A. 今回は元ファイルの作者でお願いします。

Q. ファイルの所有者はどうしますか？

A. Windowsのデフォルト動作と一緒にしたいので、あとで調べて回答します。

Q. ファイルのパーミッションは？ 継承したパーミッションと割り当てられたパーミッションを別に扱うべきでしょうか？

A. パーミッションは考えなくていいです。

Q. どのオペレーティングシステムで動く必要がありますか？

A. 元ネタはWindows XPを指定していましたが、今回は現時点で最新のWindows11で想定しています。

Q. Home、Pro、Media Centerとありますけど？

A. 全部で動いて欲しいですが、とりあえずHomeで動作確認できれば良いです。

Q. 対象とするサービスパックは何ですか？

A. 最新のSPのみサポートすればよいです。

Q. それ以前のサービスパックはサポートしなくともよいということですか？

A. そうです(きっぱり)。

Q. コピー元のファイル名はどのように渡されるんですか？

A. 引数で渡す想定で回答していました。

Q. それはNULL終端文字列か、長さ付文字列か、それともオブジェクトですか？

A. コピー元はWindowsのパス名かURI形式で渡したいです。今ググったのですが、JavaのPathみたいなものがあれば、それを使用したいです。Paths.get(String…)のでPathオブジェクトが生成できるので、比較的安全にファイル名を渡せそうです。URIはPaths.get(URI)で変換して渡せばよいかなと思っていますが、不都合ある場合には相談させてください。

Q. NULLポインタが渡される可能性はありますか？

A. 引数のオブジェクトがNULLな可能性は常にあるので、関数内でチェックしてエラー処理して欲しいです。

Q. 空文字列が渡される可能性は？

A. 空のStringが渡されることはありませんが、Pathオブジェクトは空のPathでも生成可能なようです。

Q. 不正な形式の文字列が渡される可能性はありますか(NULL終端してないというような)？

A. Paths.getメソッドにはInvalidPathExceptionがあるので、不正なパス名は渡らないと思います。メソッドにバグがあるかもしれない不安はあるので、脆弱性情報が上がっていないか調べて回答してください。

Q. ファイル名のエンコーディングは何ですか？

A. 元ネタには「Unicodeです」と書いてあるのですが、それは無理ですよね…

Q. すいませんが、その……Unicodeというエンコーディングはありません。Unicodeのデータを使うには、UTF-8、UCS-2、UTF-16といった特定のエンコーディングを指定する必要があります。

A. Windows11では(ようやく)ファイル名がUTF-8になったそうですね。ただ、一般に「外部から受け取った文字列はすぐソースコードと同じ文字コード、もしくは内部形式に変換する」というマナーがあります。関数に渡す前に文字コードはデコードしておきますので、この関数内でデコード処理は考えなくてよいです。

Q. わかりました。Windows のAPIに渡すためにUTF-8からUTF-16に変換しなければならないのがちょっとばかり面倒になりますけど。

A. windows10+PerlだとSJIS経由なんですよ。だからちょっとマシになったとは思います。

Q. ビッグエンデイアンですか、リトルエンデイアンですか？

A. ああ、お好きな方に！

Q. 相対パスも受け入れるべきですか、それともフルパスだけにしますか？

A. Pathオブジェクトをフルパスに変換してください。ここで思い出したのですが、システムフォルダにウィルスファイルをコピーされたりしたら問題ですね。妥当なパスかチェックをしたい気持ちはありますが、コピー関数でそれを記述するのは再利用性に欠けますね。まず一旦「ダメなパス」をチェックする関数を別に作りましょう。あなたはコピー関数の冒頭でその関数を呼び出してください。

Q. パラメタをチェックするのに、どういうパスを受け入れるか条件はありますか？

A. 「ダメなパス」をチェックする関数を別に作るので、コピー関数はそれを冒頭で呼び出してください。

Q. コピー先のファイル名は生成するんですか、それとも渡されるんですか？

A. 引数で渡します。

Q. 非同期コピーをサポートする(あるいは認める)必要がありますか？

A. マルチスレッドの環境を想定するか、という質問でしょうか。ファイルが壊れる心配があるので、排他処理などはして欲しいです。

Q. エラーはどのように出せばいいですか？ 例外ですか？ エラーコード？

A. 難しいですね。

Q. 例外は関数内で処理を試みるべきでしょうか？ あるいは呼び元に投げればいいですか？

A. (たぶん)そのまま投げればいいです。発生する例外を仕様書に書いてください。

Q. コピー先にすでにファイルがある場合はどうしますか？

A. 上書きはしません。ファイルコピーに失敗したらfalseを返すのが良いかと思いますが、設計書のレビューまでに相談させてください。

Q. 呼び元で保証するということですか？

A. 呼び出し元でコピー先のファイル存在は保証しません。上書きしてファイルを失うのは嫌なので、今回は上書きコピーは一切しないようにお願いします。

Q. では、もし仮に存在したら、プログラムを単に終了させてかまいませんか？ これは明らかに前提条件に反しますし、何が起こったのかわからなくなりますが。

A. ファイルコピーに失敗したらfalseを返すのが良いかと思います。あとは呼び出し元で判断します。

Q. 代替データストリームはどうですか？

A. 「インターネットからDLしたファイルかどうか」などの情報のことですね？元ファイルの情報を保持して欲しいです。

Q. あの、もし付け込まれているように感じているのでしたら、どうか気を悪くなさらないでください。ただ必要な仕様を明確にしたいだけなんです。山ほどあるライブラリやフレームワークの中のコピー処理を使うのでなく、ファイルコピー関数を自分で書くとなると、特定の要求のセットを満たすことになり、お聞きしたような質問に対してしかるべき回答をいただく必要があります。お望みなら適当なものをさっと作ることもできますが、要求や目的という点であまりに多くの未解決の問題があると申し上げざるを得ませんでしたので……

A. はい、私も普段当たり前に使っているコピー機能を作るのに、これだけ必要な仕様があるという事を全く知りませんでした。たくさん質問をいただいてありがとうございます。

Q. よろしいでしょうか？

A. ヨシ！


おしまい😃