なっく日報

技術やら生活やらのメモ

「APIデザインの極意 - Java/NetBeansアーキテクト探求ノート」を読んで

APIデザインの極意 Java/NetBeansアーキテクト探究ノート

APIデザインの極意 Java/NetBeansアーキテクト探究ノート

こちらを読んで。

全体的な感想

まだまだ理解が浅いですが、ざっと。
とにかく、API設計は利用する開発者目線になるのが大事という感想です。
API設計というのは、利用者を意識するという点で、デザイナーがUIを設計する作業に近いなと自分の中で解釈しました。
(パッと見かっこいいけど、なんだこのクソUIは!的なのありますよね・・・?)

印象に残った箇所

  • 選択的無知
  • 利用者の信頼を得ること > 美しさ・正しさ
  • 失敗例(JavaMail API

選択的無知

私たちは、車や携帯電話の中身の仕組みを完璧には理解してないけど、日々の生活で問題なく使いこなしています。
それと同様に、何を深く知り、何を深く知る必要がないかを積極的に選択することを選択的無知というそうです。
あとがきを読むと、筆者は、ブラックボックス化されたライブラリやフレームワークを組み合わせて巨大なアプリケーションを作ることを良しとしている印象を受けました。(もちろん、必要に応じて中身をみる必要もあるということも言ってますが)
それを受けて思ったのは、敢えてブラックボックスを受け入れて、便利なライブラリやフレームワークを組み合わせてより早く・よりいいモノを作っていくのがビジネスやってく上でも重要だなと。
例:Unity、AWS

利用者の信頼を得ること > 美しさ・正しさ

コードの美しさ・正しさは大事だが、それよりも利用者の信頼を得ることが大事だと。

美しさ

例えば、非推奨のAPIが増えまくるとカッコ悪いけど、
APIの利用者が、これまでに費やしてきた時間を無にしないように、APIを長持ちさせる。
そのために、バイナリ互換性、機能互換性を重視。

余談:この辺読んでいて、Dan Kogai404 Blog Not Found:美しいプログラムの美しくないソース というエントリを思い出しました。

正しさ

正しさのために使いやすさを犠牲にすることで多くの問題を作り出す可能性があると。
↓「それだ!」と思った本文を引用します。

私が、ファイルの内容を読み込んで、ファイル内のすべての行を表す String もしくは String 配列へ変換するユーティリティメソッドを作成することなく、 その時間を使って、この本を書くことができたら、この本は何年も前に出版されていたことでしょう。 Java でディスクからファイルを読み込む方法が異常に「面倒」だと思っているのが、私だけではないと確信してます。

Java書いたことある人なら分かると思いますが、

BufferedReader br = null;
try {
    File file = new File("/tmp/input.txt");
    br = new BufferedReader(new FileReader(file));
    String line;
    while ((line = br.readLine()) != null) {
        System.out.println(line);
    }
} catch (IOException e) {
    e.printStackTrace();
} finally {
    try {
        br.close();
    } catch (IOException e) {
    }
}

的なやつ。一度に数GBのファイルを読み込むと死ぬけど、String asText()とか、欲しかったと書いてました。

失敗例(JavaMail API

基本的に、プロトコルの変更に強いAPIにはなっているが、利用者には使いづらいAPIになっていると。
メールの送受信に使われるプロトコルでそんな種類ないのに、そこに拡張性を持たせたのは確かに誤りかもしれないですね。 筆者はJavaでメールのアプリケーションが少ないのはそのせいだとまで言っています。 私はJavaの素のAPIでメール送信処理を書いたことはないのですが、 JavaMail APIJava Docをみると↓のようなイメージだそうです。

Properties props = new Properties();
props.put("mail.smtp.host", "my-mail-server");
Session session = Session.getInstance(props, null);

try {
    MimeMessage msg = new MimeMessage(session);
    msg.setFrom("me@example.com");
    msg.setRecipients(Message.RecipientType.TO,
                      "you@example.com");
    msg.setSubject("JavaMail hello world example");
    msg.setSentDate(new Date());
    msg.setText("Hello, world!\n");
    Transport.send(msg, "me@example.com", "my-password");
} catch (MessagingException mex) {
    System.out.println("send failed, exception: " + mex);
}

確かにちょっとやり過ぎ感ありますね。

総括

濃い本でしたが、学びも多かったです。何度か読みなおしたい。