与える情報を減らす
API で与える必要のある情報が少ないほど、プログラマが考えなければならないことは減る。 情報を提供するためにはプログラマがそれを与える方法を考えなければならない。
また、最終的に与えなければならない情報でも、提供するタイミングを遅らせることができる。 そのような遅延ができれば、プログラマはそのタイミングまでは考えなくてよい。 また、タイミングが遅れれば、判断に使える情報が増加するため、考えるのは容易になる。
なお、逆にいうと、値を要求することは、プログラマに考えることを強制する。 この点は、プログラマに考えさせるために利用できる。
手間の節約
- 完全に不要にできれば、値を求めるコードを記述する必要がなくなる
- 遅らせて、判断しなくて済んでいるあいだは、判断した結果をプログラムに記述しなくて済む
- 判断に失敗したとき、判断が遅かった方が、やりなおす作業は少なくて済む
思考の節約
- 情報を提供する必要がなければ、なにが正しいか考える必要がなくなる
- 提供のタイミングが遅くてよければ、判断するための思考を後回しにできる
- タイミングが遅ければ遅いほど判断するために利用可能な情報が増え、判断が容易になる
例
GC (garbage collection)
開放のタイミングをプログラマが考える必要がなくなる
Generics
リスト構造をプログラムで扱うことを考える。
- Pascal では、任意の型のリストを扱うことはできず、手続きを記述する段階で対象の型を決定しなければならない
- C では、任意の型のリストを扱う手続きは記述が難しく、対象の型を決定したほうがやさしい
- C++ では template により、任意の型のリストを容易に実現できる
- Java でも generics により、任意の型のリストを容易に実現できる
- Haskell では、任意の型のリストを容易に扱える
- Lisp では、任意の型のリストを容易に扱える
ここであげた Pascal, C では、任意の型のリストを実現するのは難しいため、 プログラマは、リスト構造を実現する時点で対象の型を決定することになる。
それに対し、C++, Java, Haskell, Lisp では、リスト構造を実現する時点では 対象の型を決定する必要がなく、その判断を省ける。
そして、対象の型に関する判断に間違いがあったときに、Pascal, C ではリスト構造のコードに修正が必要になるが、 C++, Java, Haskell, Lisp ではそのような判断の失敗自体がありえない。
また、判断することが少なければ、コードがいろいろな状況に対応できるようになり、再利用性が上がる。 リストの場合には、プログラミング言語の標準に含まれることもある。
動的配列
Ruby などでは、配列は自動的に伸長する。 つまり、存在しない要素に代入すると、代入した要素まで配列が伸びる。
これに対し、C などの言語の配列は自動的には伸長しない。
自動的に伸長する配列は、配列の生成時に長さを判断しなくてよい、 つまり、プログラマが長さを決定することを遅延することを許す。
動的言語
Lisp などの動的言語では、プログラムが完成していなくても動作させられる。 とくに、静的型がないことにより、完成していない部分に nil など単純な式を記述してもよく、 その部分に制御が到達しなければ問題なく動作する。
これは、作りたい部分から作っていけるということであり、作らない部分に関する判断を遅延できるということを意味する。
Dependency Injection (DI)
Dependency Injection は、 コンポーネント間の関係をコンポーネントに直接記述するのでなく、 外部から指定するやりかたである。
これは、直接記述するのが静的に関係を決定するのに比べ、 コンポーネント間の関係の決定を実行時に遅延しているとみなせる。