APIが何もしないとき、正しく何もしない
- APIが何もしてはいけないとき、それが正しい方法で何もしないようにすることが重要である。
- たとえば、Windowsには大規模な印刷インフラがあるが、Xboxにはそのようなインフラがない。
- Xboxでアプリが印刷を試みたときに
NotSupportedException を投げるのは、やり方として誤っている。
- アプリはPCで主にテストされていたため、Xboxで実行された際に例外処理されず、アプリがクラッシュする可能性がある。
- Xboxで印刷機能を「サポート」するより良い設計は、印刷関数自体は成功させつつ、インストールされたプリンターが存在しないと報告することだ。
- ユーザーが印刷を試みるとプリンターの選択を求められるが、一覧は空なので、ユーザーは「プリンターがないのか」と気づいて印刷要求を取り消す。
- プリンターのインストールを試みるアプリ向けには、プリンターのインストール関数が「ユーザーが操作を取り消した」という結果コードとともに即座に返るようにできる。
- 目標は、印刷機能が完全にサポートされているかのように振る舞いながら、実際にはプリンターが存在しないかのように振る舞うことだ。
- 印刷がまったく動作しないシステムでは、印刷ボタンをUIから隠すために、印刷可能かどうかを確認する関数を追加できる。
- このような振る舞いは「不活性(inert)」と呼ばれる。
- API表面は依然として存在し、仕様どおりに機能するが、実際には何もしない。
- 重要なのは、文書化された方法と一貫した形で何もしないことで、既存コードとの問題を最小限に抑えることである。
API無効化の例
- ウィジェットハンドルを生成するさまざまな関数、ウィジェットハンドルを受け取る関数、ウィジェットハンドルを閉じる関数を含むAPIを無効化する例がある。
- チームは当初、
CreateWidget が成功するものの null ポインターを返すことでAPIを無効化する案を提案した。
- しかし、この方式ではアプリが混乱する可能性がある。「呼び出しは成功したのに、有効なハンドルを受け取れなかったのか?」
EnableWidget が「無効なハンドル」を返すのも混乱を招きうる。
- 既存の文書から、ウィジェットの作成がユーザーによって取り消されたことを意味する
ERROR_CANCELLED という戻り値が見つかった。
- したがって、アプリがウィジェットを作成しようとするたびに「いいえ、ユーザーが取り消しました」と返すことが可能になる。
GN⁺の意見
- この記事で最も重要なのは、APIが何もしないとき、それがユーザー体験を損なわず、既存コードとの互換性を維持する方法で何もしなければならないという点である。
- このようなアプローチは、開発者にAPI設計の重要性を強調し、ユーザーフレンドリーなソフトウェア体験の提供に貢献する。
- この記事はソフトウェアエンジニアリングの細やかな側面を示しており、予期しない環境でもアプリが優雅に失敗する方法を探る興味深い事例を提供している。
2件のコメント
Hacker Newsの意見
「エラーを握りつぶすこと」についての意見:
panicは、テスト時にプログラマーのミスを大きく知らせるよい方法である。後方互換性についての意見:
UIデザインへの不満:
Microsoft の学習不足についての指摘:
Xbox の印刷非対応についての意見:
API利用についての助言:
NotSupportedExceptionを投げること自体は誤りではない。「悪意ある順応」についての感情:
セキュリティについての肯定的な意見:
ブラウザー戦略についての回顧:
例外処理に対する批判者たちの誤解:
Lobste.rs の意見
冗談はさておき、このような過度に防御的なプログラミングやユーザー体験には同意できない。これではソフトウェアが理由も分からないまま役目を果たさず、なぜそうなっているのか知る方法もなくなる。アプリはエラーを捕捉して、できる限りユーザーフレンドリーなメッセージを作るべきで、そうでなければ元のエラーメッセージでもユーザーに見せるべきだ。バックグラウンド作業ならエラーログがあるべきだ
この記事がアプリ開発者ではなく API 開発者の視点で書かれている点は認める。だから API のエラーを文書化し、呼び出し側で対処できるエラーメッセージを提供すべきだ
また、アクセス権がないという理由で UI からボタンを隠すのも嫌いだ。スペースが許すならボタンは表示したまま無効化し、ユーザーがマウスオーバーしたときにどうすれば有効化できるかを知らせるメッセージを出すほうがよいと思う
全体としては正確さを要求するほうがよい。ただし既存ユーザーが 10 億人いるなら、できるだけ壊さないのは非常に賢明で、ユーザーの立場からは単に動くので、システム全体としての実際の価値も生まれる。結局のところ態度としては早く失敗せよ、ただし大規模には失敗させるなであるべきだ
これは API というよりABI 安定性に近い。Windows では 15 年前にビルドされたソフトウェアでも、できる限り新しい OS 上で動き続けなければならない。関数シグネチャを変えられないので、もはや意味をなさない API でも動き続けるようにするには、善意の嘘をつく必要がある
たとえば API は今でも Active Desktop が存在するふりをしている。代替案は古い既存ソフトウェアを大量に壊すことだからだ
その機能が消えたのか、その間に別の画面に埋もれてしまったのか分からなくなる
だがアプリがそうしないと、そのアプリを使う人たちは Windows を責める。アプリではなく Windows を責め、アプリがクラッシュした場合でさえ同じだ
だから Microsoft は回避策を作る。印刷ジョブがただ消えるようにしておくほうがはるかに簡単で、そうすればユーザーは少し考えてから「ああ、そうだ、プリンターがないんだ」と受け入れる
ifチェックを頻繁に入れるのを見かける。そういうのを見るたびにこの記事を思い出すそこでエージェントには null チェックを繰り返さず、無害な関数を使い、宣言時点でその値が決して null ではないことを一度だけ確認するよう指示した