2013/04/19

素早くメソッドを逆引き

コンピュータにやらせたい処理はいろいろだと思いますが,
既に関数等の形で提供されているものを使わない手はありません.

その際に障害となるのが,目的の処理を記述したモジュールを探すことです.


最も素早く目的のモジュールを見つける方法は,記憶から引き出すことだと思います. しかし,この方法は目的のモジュールとその名前等の情報をほぼ完全な状態で記憶しておく必要があります. 名前など文脈のない事柄をきちんと記憶することは人間にとって難しい作業であると思います.

ただし,よく使うモジュールであれば,何回も使うため意識しなくとも記憶できるでしょう. たまに使うモジュールであれば,以前使った時の記憶がかすかに残っているでしょう. ちょっと施行錯誤すればすぐ思い出すかもしれませんし, 以前使った時のコードを見て思い出すこともできます.

一方で,全く行ったことのない処理は,探したり・作ったりする必要があります.
この「思い出す」という作業と「探す・作る」という作業の間には, 大きな差があることがわかるでしょうか?

そう,思い出すことはほぼ一瞬であるのに対して,探したり,作ったりすることは時間がかかります.
結局,手元のライブラリをある程度 記憶しておくことが必要であると言えます.


近年多くのIDEで実装されている入力補完機能. この機能が果たす役割は「入力補完」という側面よりも,「記憶の補完」という側面の方が大きいと感じています.

特に日本人は英単語のスペルを覚えることが英語圏の人よりも不得手でしょう. ですが,入力補完機能さえあれば,うろ覚えのスペルでも入力できてしまいます. 2つ目の単語を入力したり,単語の頭文字を順番に入力したりしても,目的の入力候補が見つかるIDEさえあります.
これは,まさに英単語のスペルという記憶を補完していると言えるのではないでしょうか. また,入力候補と一緒にドキュメントを表示する機能も,記憶補完の役に立ちます. そして,最終的には素早いコーディングにつながると思います.


ただし,入力候補から探すにしても,何もない状態から探すにしても, まずはライブラリが無ければ始まりません.
そのライブラリの性質として重要なのは抽象度の高いモジュール群とそれらモジュール同士の直交性です.

抽象度の高いモジュールは楽にコーディングする ために必要な要素であると言えます.
ただし,抽象度のより高いモジュールは,より「ドメイン固有の処理(特定の分野に特化した処理)」になっていくと考えられるため, ライブラリとして用意する場合は,きめ細かな制御ができない・目的に沿わないといった問題や, 多様な問題に対応するためにモジュールのが多くなりがちといった問題が存在します. 特に,モジュール数が多くなってしまっては, その分,記憶しなければならない量が増え,検索の質が低下するため,素早いコーディングにはつながりません.
モジュールは最小限の必要な分だけであるのが望ましいですが.必要最小限かどうかは判断が難しいため, 絶対数等よりも,モジュール同士の直交性に着目した方が賢明でしょう.
経営学で言うところのMECE(Mutually Exclusive and Collectively Exhaustive)のような概念です.


想像してみてください.

足し算のモジュールを 「1を足す」,「2を足す」,…と実装するととんでもない数になります.

こんなのはどうでしょう,
「2つの値を足す」,「3つの値を足す」,…これもキリがなさそうです.
通常は「2つの値を足す」モジュールだけで上記の全ての場合を網羅させると思います.

引き算はどうでしょうか?
「左の値から右の値を引く」モジュールがあればよさそうです.

しかし,足し算において負の数を考慮するなら,「左の値から右の値を引く」モジュールはいらないでしょう.

このように,他のモジュールで簡単にカバーできるモジュール同士は直交性が低いと言います. 逆に全く重複していれば,直交性が高いと言います.



多くのライブラリでは,抽象度と直交性についてよく検討されていることだと思います.
ただし,全ての分野に対応したライブラリ(言語の基本ライブラリ等)は一般化されているため, 抽象度が高いモジュールは少ないことでしょう.また,公開されているものは,インターフェイスの変更が難しいため, 必ずしも最適化されたといえるものでもないかもしれません.
また,解決したい問題があり,そのためのライブラリがあれば利用したいですが, そのライブラリの学習コストも考えなければなりません.
解決したい問題についてよく知らない場合でも,知らない部分だけを隠蔽してくれるライブラリがあれば理想的ですが, 隠蔽しすぎて,できることが制限されている場合もあります.
複雑な処理が必要な場合も,そこだけを隠蔽したモジュールがほしいところです.

結論として,利用するモジュールの抽象度は目的によって選択できるような環境が一番であると言えます.
基本的なモジュールの抽象度は,やはり,言語の基本ライブラリに依存してしまっています.
他のライブラリも抽象度を変えることは難しいでしょう.


そこで,私は自分たち専用のよく使う処理をまとめたライブラリを作るということを提案します.
自分たちで作ったものなら,目的に応じた適度な抽象度を備えることができます.
そして何より覚えやすいと思います.
同じような処理を何度もしているなら,ある程度,直交性を無視してでも,検討してみるとよいでしょう. なぜなら,それはもう抽象度が異なる次元のモジュールかもしれないのですから. 抽象度が異なるモジュールは,上位のモジュールで明確に分離すれば,同じ処理内容でも新たに作る価値は十分あると思います. そうした,小さな改善も積み重なれば,かなりコーディングが速くなるはずです.



さて,では全く行ったことのない処理は,どうやって探したり,作ったりしましょうか? この件についてはまた次の機会に取り上げたいと思います.

2013/04/18

素早くコーディングするには


動的に型を判断する言語が大きな注目を集めています.
この人気はどこから来ているのでしょうか?

動的型付という側面はそれ自体では長所にも短所にもなりますが,
本質はそこにはないように思います.

注目されている言語に共通しているもの,それは
「簡潔にコードを記述できること」これに尽きると言っても過言ではないでしょう.


コーディングっていうのは結構大変な作業ですよね.
1単語も間違えられない.場合によってはインデントすらも.

こんな作業を少しでも楽にこなしたい 」と誰もが思っていると思います.
そもそも,楽するためにコンピュータに仕事をさせようとしているのですから,
そう考える方は相当いらっしゃることと思います.


そんな中で使ってみる最新の言語.
もちろん最初は今使っている言語の方が使い慣れている分,使いやすいでしょうが,
次第にちゃんと使えるようになると気持ちいいぐらいに楽にコーディングできる場合もあるのです.

特に,
静的 → 動的
手続き → OOP → 関数・アスペクト
など,シフトしてきたパラダイムに沿った言語の変更や

型推論,補完,インライン(無名)関数
といった記述量を少しでも少なくする機構を備えた言語への変更はとても刺激的なものです.



私自身もいろいろな言語を使ってきましたが,
やはり,楽にコーディングできる言語は使っていて気分がいいです.



さて,この「楽」って感じる要素について,もう少し考えてみたいと思います.

この楽さは,「簡潔にコードを記述できること」が大部分なのでしょうが,
そんなに簡潔なコードが大事なのでしょうか?

よく,引き合いに出されるのが記述は短いが,一見まったく意味不明なコードです.~参照~

このようなコードは,思い通りに記述するのも難しいはずです.簡潔に記述できていません.


私は「コーディングの楽さ」を体現した指標として
「コードの簡潔さ」よりも「 コーディングの素早さ 」を考えたいと思います.

とある研究によると,プログラマが一定時間内に記述できるコードの量は
どんな言語を使ってもほぼ一定という結果が得られているらしいです.

もし,正しいならコーディングに「素早さ」なんて存在しないかもしれません.
しかし,コンピュータにやらせたいことを実装するためのコード量は,場合によって大きく異なります.

「言語によって」ではなく「場合によって」と記述した理由がこの記事を書いた理由です.


もちろん,言語による記述量の差も大きいです.
最も言語間で差がつくと考えられるのは,型の記述の有無やモジュールの書き方です.
特に動的型付・静的型付と呼ばれる言語間での記述量は明らかに動的型付言語の方が少ないでしょう.
動的型付の言語が趣味などの範囲で特に人気なのは上述の側面によるところが大きいと考えられます.

というのも,静的型付言語における沢山の「おまじない」のような記述は,
その多くがそのコードを利用する「他人」のためのものであり,
プログラミング初心者や気軽にプログラミングしたい人にとっては,よくわからない,面倒な記述なのです.

一方で,処理内容の記述に関しては
十分検討された言語においては,必要十分なシンボル数で目的の記述ができるため,
言語間の差はほとんどないと言えます.



そして,記述量の差が最も大きく影響を受けるのが「ライブラリ」です.


極端な言い方をすると,コンピュータにやらせたいことが既に関数等で存在すれば,
その関数を呼び出して,はいおしまい.となるわけです.
ただし,既に存在している関数は複雑な処理を一言で表せるように対応したものは少なく,
コンピュータにやらせたいと思っていることも十分に複雑な処理である場合がほとんどでしょう.

しかし,複雑な処理であっても既存の処理をうまく組み合わせることによって実現できることもあります.
いろいろな場面に対応した関数などがより多く存在すれば,その中に今,コンピュータにやらせたいことが存在する確率は高まります.
コンピュータにやらせたいことが丸々存在しなくとも,その一部が見つかる確率は確実に高くなるはずです.
すなわち,既存の関数が多ければ多いほど記述量は短くなり(短くなる確率が高まり),素早くコーディングできる計算です.

ただし,記述するために辞書を引く労力・時間は考慮されていません.
この場合の辞書を引くという作業は,作業に必要な関数を調べる作業のことであり,
逆引きのマニュアルで調べる,ネットで調べる,人に聞く等の方法が考えられます.
つまり,とある処理を素早くコーディングするには,
いろいろな場面に対応した関数などの存在だけではなく,
処理を記述するための語彙(関数など)を
素早く探してくる能力や仕組みが必要であることがわかります.


次回はライブラリの中に存在する処理を
素早く見つける方法について考えてみようと思います.