APIデザインにおける七つの大厄介

(編注:2016/7/29、頂いたフィードバックを元に記事を修正いたしました。)

APIをデザインするということは、科学であり技術でもあります。多くの頭の良い人たちが失敗を重ねてきました。成功している人たちは、APIの主な目的を念頭においてデザインしているのです。その目的とは、「開発者たちをウンザリさせる」ということです。

親愛なる仲間たち、その崇高っぽい追求を称えるべく、「APIデザインにおける七つの大厄介」を共に数え上げようではありませんか(私がしたことを見てください)。リスティクル(箇条書き形式の記事)を書くつもりはないのですが、少なくともタイトルは教養ある宗教的文献が参照元です。

まず、ルールを決めましょう。ここでは、成功し、きちんと機能しているAPIを取り上げます。ですから、「動かない」とか、「大量のセキュリティホールがある」といったことは厄介ごとに数えません。「致命的」を文字通りに考えないでください(訳注参照1)。そして誰も使っていないAPIも対象ではありません。失敗したAPIは厄介ではなく、ただダメなだけです。ここで議論するのは、小さなことです。小さな、イライラさせられる、理解不能な、オンラインスラング辞書Urban Dictionaryが羅列する言葉で表されるような、誰もが知り、嫌っている厄介ごとについてです。

例の多くは直近でイライラさせられたAndroidのものですが、それだけをとりたてて非難する意図はありません。これらの罪はAndroidの専売ではないのですから。

厄介ごと その1 – trsnss(素っ気なさ過ぎる)

もちろん、ネーミングの規則化は困難です。それでも、常識で考えてもう少し長いほうがよいと思います。どうしても短くしたいなら、キー入力を最小限に絞ることに命をかけているUnix使いの人たち(曰く、「貴重なEを惜しんでdupで済ませられるところを、dupeと言う必要があるだろうか」)に任せたらどうでしょうか。

その2もこれに関わっています。

厄介ごと その2 – makingNamesMuchTooLongToBePractical(長過ぎて実用性に欠ける名前)

逆にAppleが与えてくれるのは、このような珠玉の傑作です。

outputImageProviderFromBufferWithPixelFormat:pixelsWide:pixelsHigh:baseAddress:bytesPerRow:releaseCallback:releaseContext:colorSpace:shouldColorMatch:

厄介ごと その3 – 同義語を使っている

Androidよ、あなたのことです。

“BlankActivity”と”EmptyActivity”は明確に別のものです。違いは何でしょうか。以前は分かっていましたが、今は空っぽ(empty)です、つまり、思い出せません(blank)。

Androidにはツールバーがあります。ある時点から名前を変えてアプリケーションバーまたはアクションバーと呼ばれるようになりました。次のような素敵なコードで指示されます。

// Set the toolbar as my app bar
   setSupportActionBar(myToolbar);

短縮化するか、しないか。これは明らかにGoogle本社にとってどうでもいいことです。両方とればいいではないですかgetExternalDirectoryとgetExternalFilesDirを相互参照するのです。これらは2つの位置を返します。いずれにしても、ディレクトリにファイルを格納したい時もあれば、私は知りませんが、どこか別の場所に入れたい時もあるからです。

タップとタッチの違いは何でしょうか。私には分かりません(少なくとも、スマートフォンに関しては)。そして、時々クリックという言葉も使っているAndroidデザインチームにも分からないのでしょう。

ねえ、どのバージョンを使ってる? ああ、KitKatか。でなければ、4.1かな。いや、SDKバージョン19かも。待て待て、それは全部同じものだよ。この調子でこれからもうまくいくといいけど。

そして、Androidの最後の例です。プロジェクトのアセットをURLで管理したい? それなら、ソースツリーに/assets/を足し、”file:///android_asset/”で始まるURLを構築するだけです。その通り、片方は単数形、もう片方は複数形です。1つには頭にandroid_が付いており、もう1つには付いていません。なぜでしょうか。それは彼らがGoogle様であり、何でもやりたい放題だから、です。どうしますか、FirefoxOSでも使ってみますか。

厄介ごと その4 – ドキュメントが乏しい(または皆無)

アセットURLについて言えば、ドキュメントを読んでも分からないでしょう。この方法でファイルにアクセスできるか否かに全く影響しないメソッド、WebSettings.setAllowFileAccessメソッドにおけるぞんざいな言及は別です。確かに、古い、暗黙の了解のような機能なのです。

それからContext classがあります。誰も結局何なのかはっきり知らない、でもどこでも見かけるというKardashian家のようなclassです。そして誰も理由は分かりませんが、ほとんど全てのAPIの呼び出しに必要なのです。おかしな話です。

Activityにツールバー、アクションバー、アプリケーションバーを追加したい時はどうすればよいのでしょうか。ここに後方互換ライブラリを用いた方法が記載されています。では、後方互換が必要ない場合は、当然、内蔵classで対応できるのでしょうね? しかし、これも公式ドキュメント内で見つけることはできないでしょう。

そして、後方互換と言えば…

厄介ごと その5.1beta3 - バージョンの非互換性

Android開発をしたことがあるなら知っているはずです。私?私はそれについて書くことさえできません。メモリが粗悪過ぎて…。ご存知の通り。

KitKatで動くものが、MarshmallowやJelly Beanで動かないのはなぜだ!?!?!?

厄介ごと その6 – 超複雑風味的複雑化(簡単なことが難しい)

ああ、Fragmentを嫌うのが半ば趣味のようになってきました。これはAndroidドキュメントの実際の図説です。

Android Fragment Lifecycle
注釈:fragmentを追加
Fragmentが有効
ユーザが後方に誘導、あるいはfragmentの削除、置き換え
fragmentをバックスタックに追加、その後削除、置き換え
fragmentがバックスタックからレイアウトに戻る
fragmentは壊れる

しかし、FragmentよりもひどいのはNotificationです。Androidドキュメントの「簡単なNotificationの作成」の項を見てください。どれだけ簡単なのかが分かりづらかった場合に備え、最初の文章でその言葉をわざわざ繰り返しています。「次のスニペットはシンプルなNotificationを表しています」。この「何とシンプルな」コードスニペットを見てみましょう。

NotificationCompat.Builder mBuilder =
        new NotificationCompat.Builder(this)
        .setSmallIcon(R.drawable.notification_icon)
        .setContentTitle("My notification")
        .setContentText("Hello World!");
// Creates an explicit intent for an Activity in your app
Intent resultIntent = new Intent(this, ResultActivity.class);

// The stack builder object will contain an artificial back stack for the
// started Activity.
// This ensures that navigating backward from the Activity leads out of
// your application to the Home screen.
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
// Adds the back stack for the Intent (but not the Intent itself)
stackBuilder.addParentStack(ResultActivity.class);
// Adds the Intent that starts the Activity to the top of the stack
stackBuilder.addNextIntent(resultIntent);
PendingIntent resultPendingIntent =
        stackBuilder.getPendingIntent(
            0,
            PendingIntent.FLAG_UPDATE_CURRENT
        );
mBuilder.setContentIntent(resultPendingIntent);
NotificationManager mNotificationManager =
    (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// mId allows you to update the notification later on.
mNotificationManager.notify(mId, mBuilder.build());

何とまあ、この流麗絢爛な素朴簡潔さには圧倒されます。

くどいことに、Androidのドキュメント作成者はさらに「これだけです。ユーザに通知されました」と追い打ちをかけてきます。なるほど、これだけか! 何らかのコードが必要だと思っていたけれど、このスッキリ明確な27行の美を示してくれたわけですね、非常に安心させられます。それから使用する3つのclassのインポートを忘れてはいけません。ああ、後方互換性的なものが欲しい場合は、全く別のclassのセットに加え、Gradleのファイルもアップグレードして、その他にも作業が、つまりもう、どうだっていいです、付き合い切れません、止めてバーテンダーになります。

何ですって?

まだありました、これらXMLの30行を忘れずに別のファイルにコピペしてください。

さて、最後のそして7つ目のAPIデザインにおける致命的な厄介ごとは…

7. XML

もう、たくさんですね。


  1. 訳注:原文タイトルは「Seven Deadly Annoyances of API Design」であり、「Deadly」が「致命的」にあたります。『七つの大罪』への参照を加味して訳したため分かりづらくなってしまっておりますが、ご了承ください。