例外クラッシュ

先週、私は同僚の何人かとともに、Goが例外や他の同様のメカニズムを使用する代わりにエラーコードを返すことにより、予想されるシナリオでエラーを処理するという事実について大声で話しました。 人々は例外によるエラーを回避することに慣れているため、これはかなり議論の余地のあるトピックであり、Goは Cを含むいくつかの言語で以前に採用されていた既知のモデルの改良版を返します。 これは、エラーがプログラマーの目の前に現れ、 常にエラーに対処するように強制することを意味します。 さらに、例外は、例外のある言語では、追加のアクションを伴わないすべての間違いが、何がどこで発生したかに関する完全な情報を伝えるという事実の方向に進みます。これは場合によっては役立ちます。



ただし、これらのすべての設備には、簡単に定式化できるコストがあります。

例外は、開発者にバグを心配しないように教えます。



悲しい結果は、あなたが素晴らしい開発者であっても、真実であるということです。あなたはあなたの周りの世界に影響され、間違いを許さないのです。 問題は、インポートしたライブラリ、コンピューターにインストールされているアプリケーション、およびデータを保存するサーバーに表示されます



レイモンドチェンは2004年にこの問題について説明しました



例外をスローしてモデルに正しいコードを書くことは、エラーコードを返すモデルを書くことよりもいくつかの点で困難です。何も失敗する可能性があり、これに備える必要があるからです。 エラーコードが返されるモデルでは、エラーをチェックする必要がある瞬間は明らかです。エラーコードを受け取った直後です。 例外のあるモデルでは、エラーはどこでも発生する可能性があることを知る必要があります。



つまり、エラーコードが返されるモデルでは、誰かがエラー処理をスキップすると、これが明示的に発生します。エラーコードはチェックされません。 同時に、誰かがエラーを処理するコードを検討するときに例外をスローするモデルでは、エラーが明示的に示されていないため、すべてがそれほど明確ではありません。

(...)

コードを書くとき、コードのすべての行で発生する可能性のある各例外の結果について考えますか? 正しいコードを作成する場合は、これを行う必要があります。




これは絶対に真実です。 例外をスローする可能性のある各行には、忘れがちなエラーのあるスクリプト用の隠された「else」ブランチがあります。 エラー処理のためにコードを埋め込むことは無意味な繰り返しのように見えますが、それを書くと開発者は別のシナリオを思い出すことになり、多くの場合、このコードは空ではありません。



これについて私が書いているのはこれが初めてではなく、この声明をめぐる論争を考えると、問題を確認するいくつかの例を見つけました。 今日私が見つけることができる最良の例は、Python 3.3標準ライブラリのptyモジュールです。



def spawn(argv, master_read=_read, stdin_read=_read): """Create a spawned process.""" if type(argv) == type(''): argv = (argv,) pid, master_fd = fork() if pid == CHILD: os.execlp(argv[0], *argv) (...)
      
      







誰かがargvの間違った実行可能ファイル名でこのコードを呼び出すたびに、execlpが失敗し、フォークされたプロセスが無視されるため、未使用でゴミのない未知のPythonアプリケーションが生成されます。 そして、このモジュールのクライアントが例外をキャッチするかどうかは関係ありません。 現地の義務は履行されていません。 もちろん、spawn関数自体の内部を除いてtry /を追加することで、エラーを簡単に修正できます。 ただし、問題は、 この機能がGuido van Rossumが最初にコミットした1994年以降にこの機能を見たことがあるすべての人にとって普通のように見えることです。



別の興味深い例を次に示します。



 $ make clean Sorry, command-not-found has crashed! Please file a bug report at: https://bugs.launchpad.net/command-not-found/+filebug Please include the following information with the report: command-not-found version: 0.3 Python version: 3.2.3 final 0 Distributor ID: Ubuntu Description: Ubuntu 13.04 Release: 13.04 Codename: raring Exception information: unsupported locale setting Traceback (most recent call last): File "/.../CommandNotFound/util.py", line 24, in crash_guard callback() File "/usr/lib/command-not-found", line 69, in main enable_i18n() File "/usr/lib/command-not-found", line 40, in enable_i18n locale.setlocale(locale.LC_ALL, '') File "/usr/lib/python3.2/locale.py", line 541, in setlocale return _setlocale(category, locale) locale.Error: unsupported locale setting
      
      







システムアプリケーションにロケールデータがないため、これは非常に深刻なクラッシュです。皮肉なことに、コマンドが欠落している場合は、インストールするパッケージをユーザーに伝える必要があります。 グリッドの上にcrash_guardへのリンクがあることに注意してください 。 この関数は、スタックの端ですべての例外をキャッチし、詳細なシステム情報とトレースバックを表示して問題の解決を支援するように設計されています。



このような「パラシュートインターセプト」は例外指向プログラミングでは非常に一般的であり、このアプローチは、原則として、開発者にアプリケーションでの適切なエラー処理の誤った感覚を与えます。 アプリケーションを真に保護する代わりに、クラッシュする便利な方法になります。 この場合、必要に応じて警告を表示し、プログラムを通常どおり動作させる方が適切です。 これは、単に次の行をラップすることで実行できます。



 try: locale.setlocale(locale.LC_ALL, '') except Exception as e: print("Cannot change locale:", e)
      
      







明らかに、これは簡単です。 しかし、ここでも問題は、これをすぐに行わないのが自然だったということです。 実際、これは当然のことです。間違ったパスを考慮しない方が良いと思われます。 この場合、コードは短くなり、より簡単になり、結果として、目的の結果につながるコードのみが残ります。



この結果、残念ながら、脆弱なソフトウェアとピンクの象の世界に突入します。 エラーを返すより表現力豊かなスタイルは正しい思考を構築しますが、関数またはメソッドは結果としてエラーを返しますか? どのように処理されますか? システムとやり取りする関数は実際にはエラーを返しませんか? 起こりそうな問題はどうですか?



驚くほどのクラッシュと単純に予測不可能な振る舞いは、そのような不本意な過失の結果です。



オリジナル



All Articles