プログラマが知るべき97のこと/誰にとっての「利便性」か
優れたAPI の設計の重要性、そして難しさについては、これまで多くのことが語られてきました。最初から適切なAPIを作ることは難しく、しかし後からAPIに変更を加えることはもっと難しい。まるで子育てのような難しさ、と言っていいでしょう。経験を積んだプログラマならほぼ皆知っていることでしょうが、優れたAPIとは、まず抽象度がどこをとっても一様であり、その上で、整合性、対称性を備えているものです。優れたAPIはプログラミング言語のボキャブラリーを充実させ、言語に豊かな表現力を与えるものでもあります。しかし、そうした原則を十分に意識していたとしても、適切なAPIができるとは限りません。甘い物は身体に必要だが食べ過ぎると成長によくない、というのと同様に、原則にとらわれすぎるとかえって悪い結果を招くことがあるのです。
こう書いただけだと暖昧でよくわからないと思いますので、具体例をあげることにしましょう。以下の3つは、どれもAPIを設計する人が実際の作業時に言いそうなことです。そして、どの意見も「その方が利便性が高い」という理由で正当化されやすいのです。
- ほとんど同じ目的の呼び出しコードがクラスAにすでに存在するのに、クラスBに新たに呼び出しコードを持たせる必要はないのではないか。 - 目的がほぼ同じメソッドがすでに存在するのであれば、わざわざ新たなメソッドを作る必要はないのではないか。switch文を追加するくらいでいいのではないか。 - 2番目の文字列パラメータが".txt"となっていれば、自動的に、第1パラメータはファイル名であるとみなして構わなし。したがって、メソッドを2つ作る必要はない。簡単な話だ。
どれも善意から出た意見なのは確かです。しかし、こういう意見に従ってAPIを作ると困ったことが起こります。それは、「APIを使用したコードが非常に読みにくくなってしまう」ということです。たとえば、メソッド呼び出しのコードがこんなふうになります。
parser.processNodes(text, false);
このコードが何を意味するのか、APIの内部の実装を知らない人にはおそらくわからないはずです。ドキュメントを調べて何とか判ればまだ良い方でしょう。このメソッドは、たしかに利便性を考えて設計されているのですが、それはメソッドを「実装する側にとっての利便性」であり、決して「呼び出す側にとっての利便性」ではないのです。「することはほとんど同じなのに、2種類の呼び出しを使うのは不便ではないか」というのは、要するに呼び出す側にとって不便というのではなく、コードを書く自分が、内容のほとんど同じメソッドを2つ書くのが「面倒」という意味なのです。冗長で、不整合で、美しくないものを作りたくない、という意図は、基本的に間違っていません。しかし落ち着いてより深く考えるならば、それらの対偶にあるのは効率的、整合性、美しさです。必ずしも「利便性」ではありません。APIを作るというのは、複雑な処理を隠蔽するということです。これは正確には、APIを作る側が、複雑な処理を隠すために面倒な作業を引き受けなくてはならないということです。そうしなくては優れたAPIなどできません。作る側にとってみれば、考え抜かれたメソッドをいくつも書くよりも、大きなメソッドを1つ書く方が「便利」です。しかしそれは使う側にとって「便利」でしょうか?
より良いAPIを作るには、APIを1つの言語だと考えるといいと思います。APIを表現力豊かな言語にするにはどうすればいいかを考えるのです。基本的な言語なら「意味のある問いを立て、それに答える」ということができれば十分ですが、APIはさらに上のレイヤーの言語にするのです。つまりAPIでは、1つの問いに対応する動詞、つまりメソッドが必ず1つとは限らない、ということです。ボキャブラリーに多様性を持たせれば、微妙な意味の違いが容易に表現できます。たとえば、
というようなコードを書されるよりは、単にrunと書ける方が間違いなく使いやすいでしょう。walk(true)
とwalk(歩く)
は本質的には同じ動作で、ただスピードが違うだけとみなすこともできるのですが、言葉が2つある方が使う側にとっては便利なのです。このように、一つ一つ考え抜かれ、整合性と豊富なボキャブラリーを兼ね備えたAPIを上のレイヤーとして追加すれば、言語の表現力が高まり、コードも読みやすく、理解しやすくなります。APIを利用して、プログラマが自ら新たなボキャブラリーを作れるようになっているとさらにいいでしょう。APIを作った人間がまったく予期していなかったような使い方を、プログラマが自由に考えられるということです。それができればAPIを使う側にとっては非常に便利です。APIの開発をしていて複数の要素を1つのメソッドに詰め込みたい衝動にかられたら、是非思い出してください。英語には、たとえば「部屋を片づけて、静かに宿題をやりなさい(Make up your room, be quiet and do your homework)」ということを一語で伝えるような単語はないのです。たとえ同じことを何度も繰り返し言っていて、一語にまとめられれば便利だと思っても、それはしないほうが賢明なのです。
run(走る)