2013/04/19

素早くメソッドを逆引き

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

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


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

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

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

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


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

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


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

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


想像してみてください.

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

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

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

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

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



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

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


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



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

2013/04/18

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


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

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

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


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

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


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

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

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



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



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

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

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

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


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

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

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

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


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

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

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



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


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

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

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


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

2012/09/28

線形代数学とオブジェクト指向は似てる!?


プログラミングを始めると「オブジェクト指向って何?」って壁にぶつかるのではないでしょうか?オブジェクト指向について調べると本当にいろんな情報が手に入って,結局よくわからなかったりします.とりあえずオブジェクト指向って難しいということだけ判るかもしれません.

結論から言うと,オブジェクト指向という言葉や概念に明確な定義はなく,
「プログラムなどをもの(オブジェクト)として考えること」
に近い意味を持っています.そして,定義が曖昧なために説明も抽象的になり難しく感じてしまうのでしょう.


しかし,現在ほとんどのプログラミング言語がオブジェクト指向をサポートしており,プログラミングを行う上でオブジェクト指向はなくてはならないと言っていいほど重要な概念であることも事実です.さらに最近ではオブジェクト指向を直接プログラミングとは関係のないシステム開発の上流工程に応用するといった動きすら存在します.ですが,オブジェクト指向についての理解が深まれば,オブジェクト指向言語の理解はもちろん,その概念は様々な場面で(時には無意識に)役立つことも多いかと思います.



では,どうやってオブジェクト指向を理解すればよいか?


そもそも,オブジェクト指向が1つの概念である(実際はそうなのですが)と思っていることを一度やめてはどうでしょうか?

1つの分野,プログラミングという科目のオブジェクト指向という分野.数学の線形代数学のような.

こう考えてみると,一言ではオブジェクト指向という分野について語れないとわかるでしょう.一朝一夕には学べないことがわかるでしょう.


ここで,結局時間をかけて学ぶしかないのかと残念に思わないでほしいのです.もはやオブジェクト指向という概念の把握にかける無駄な時間は必要ありません.いや,時間はかけなければならないのですが,オブジェクト指向という分野を構成している要素を1つずつ理解する有意義な時間の使い方を推奨します.学問の1分野を学ぶときも,1つ1つの概念を理解して,演習問題を解いて,応用問題に取り組んで…といった形で学んでいた人が多いのではないでしょうか.そして,その知識を使う段階(という経験があればですが)でより一層理解が深まっていったと思います.オブジェクト指向も同じで,構成する1つ1つの概念に対して,特に必要なものから順に理解し,応用し…を繰り返して学んでゆけばよいでしょう.結局は経験がなければただの知識しか残らないのですから.


とは述べたものの,オブジェクト指向プログラミング(OOP)について知りたい方と話したい筆者のために,少しOOPとは何かに対する抽象的な意見を述べておきます.OOPの本質はポリモーフィズムに代表される(同じ点を抽出して同じ像とみなす)抽象化にあると筆者は考えています.そもそも,コンピュータ上の(コードを含む)データをものとみなす行為が抽象化です.プログラミング言語の進化自体抽象化の歴史みたいな一面があり,オブジェクト指向を説明する人は抽象化が大好きで何でも抽象化して考える癖があるように思います.一般的な議論をすることも,異なるものに対して同じ要素を抽出してきて同じものとみなすことも,ある意味抽象化です.だから,オブジェクト指向の説明は抽象的なものが多く,実際の具体的なコードがなんとなく少なく,プログラム以外の他のものが例えとして用いられていることが多いのではないでしょうか.この文章のタイトルからしてすでに抽象化を用いたものになっています.
OOPでは,言語でサポートされているものとそうでないもの,基礎的なものから応用したもの(デザインパターンなど)まで様々なものとみなす抽象化のためのテクニックが数多く存在します.以下に基礎的な概念の一部を列挙してこの説明を終えようと思います.

概念 説明
ポリモーフィズム(多態性) 同じように振舞わせる操作の抽象化
継承,ダックタイピング 同じように振舞う動作の抽象化
型,クラス(構造体),インスタンス 同じ属性のデータや処理をまとめる概念の抽象化
カプセル化 詳細を隠蔽し単純にする抽象化


最後になぜ,似ている分野の例に線形代数学を挙げたのかを説明しておきましょう.
それは,筆者が始めにどんなものか知ったときは大して必要なさそうに感じたものの,学ぶうちに必要不可欠なものに変わった点が似ていたためです.また,どちらも抽象化し,簡単にし,人間の理解を助けるという点でも似ているのではないでしょうか.

2012/09/12

プログラミングを勉強しなくちゃと思ったら


なんとなく,プログラミングを勉強しなくちゃと思った時,まず,プログラミング言語を選んでいる(決めてしまっている)人が多いと思います.もちろん選択の余地がない人もいるかもしれませんが,もし,自分で選べるならこんなに幸運なことはないでしょう.もし,使ったことがある言語があったとしても,再考してみるのもよいかもしれません.

今回はすこし,プログラミング言語をどう選ぶかについて考えてみます.


ちなみに,誰でも,自分を無意識に正当化する傾向があるために,自分が使っている言語の短所が見えなくなりがちです.自分が使っている言語の長所を過大評価しがちです.プログラミング言語についての評価には必ずと言っていいほど,評価者が使っている言語が影響を与えていると理解した上で,情報収集することを推奨します.


まず最も重要なことは,プログラムを書いて実現したいこと(目的)をはっきりさせておくことです.

データ処理なのか? ライブラリ・アプリケーション・システム開発なのか? 等


特に各領域に特化した言語(DSLやそれに準ずるもの)であるほど,できないことが多いです.
(しかし,これは欠点ではなくむしろシンプルさを追求した長所でしょう.)


そんなこと,初心者にはわからないよーってときは有識者に聞くか,自分が達成したいことに近いことをしている言語を探すといいでしょう.ついでに,プログラミング以外の方法も検討するとよいかもしれません.既存のアプリケーションを使えばできることも多いと考えられます.小規模なデータ処理が目的ならExcelで十分な場合が多いです.Excel(VBAじゃなくて)はデータがフロントエンドのプログラムだという人もいます.


そして,次に拡張性と使いやすさ,簡単さを天秤にかけます.



どんな項目で判断していけばいいか列挙してみます.


フレームワーク

  • 簡単にプログラムを動かせるのか?
  • 環境は簡単にインストールできるか?
  • そもそもどうやって動かすか?
  • ツールのサポートは?

言語の入力しやすさは 文法の簡単さ単純さ・ツールによる補完 によって決まると考えられますが,両方を追求することは難しく,トレードオフの関係にあるといってもよいでしょう.文法の簡単さ有利なのが,動的と呼ばれる言語で,使う関数の数などがあまり大きくならない分野での,素早い開発に適しているといえます.一方,ツールによる補完には静的と呼ばれる言語が有利です.入力補完は開発者の記憶までも補完してくれると考えられます.


ライブラリ

  • 言語デフォルトのライブラリは充実しているか?
  • 目的を簡単に達成させられる既存のライブラリは存在するか?手に入るか?

とある言語を学ぶ上で,ライブラリの存在は大きく,そのライブラリを調べる作業が必要になってきます.そのためにはライブラリの調べ方と,調べたい内容についての知識が必要です.

コンピュータは人が考えたものなので,法律みたいに決まりごとが沢山あります.うまく使うにはコンピュータ自体の理解も必要になります.処理速度を上げたいならCPUの仕組み,ファイルを扱いたいならファイルシステムについてよく知っているほど,ライブラリを調べるのが容易になるでしょう.更にライブラリ自体にもプログラミングのノウハウが詰まっています.よってプログラミングパラダイムなどの知識も調べる役に立ちます.


リファレンス

  • どのくらい情報が出回っているか?どうやって情報を取得するか?
  • その言語が有名かどうか?
  • 使える人が周りにいるか?

勉強するなら情報は多いに越したことはありません.本屋での書籍数・Web検索結果でおおよそのその言語の普及具合がわかります.Web上の情報量を示したTOIBE Indexっていうのもあります.どうせ学ぶなら注目されているものを学びたいものです.


文法

  • 学びやすいか?
  • 記述しやすいか?

文法は上の3つに比べたら些細な問題です.最近はほとんどの言語が他の言語の長所を取り入れる形で文法とライブラリの拡張が行われています.



ほとんどの言語は拡張すれば(簡単かどうかは別にして)いろんなことができるようになっていきますが,面倒なことに変わりはないので,言語デフォルトのライブラリやフレームワークがその言語を特徴づけていると言えるでしょう.


最終的には上にあげたことを踏まえたうえで何を使うか自分で決めるしかありません.
おおまかな指針としては,
小規模な問題には動的な言語でライブラリが充実しているものを,
大規模な問題には静的な言語でリファレンスが充実しているものを利用するのがよいと考えられます.

2012/09/11

パラダイムシフトを受け入れよう

プログラミングは複雑な作業であるため,これまでに多くのノウハウが蓄積され,その多くがプログラミング言語の仕様として取り込まれています.そのためノウハウの取り入れ方の異なる数多くの言語が存在しています.

最も根本的なノウハウはプログラミングパラダイムと呼ばれ, プログラミングパラダイムの取り入れ方の違いでプログラミング言語の基本仕様が異なります.

プログラミング
パラダイム
説明
命令型 CPUへの命令を順番に記述していく.
命令の構造化 CPUへの命令をループ・条件分岐・式などのブロックに分けて記述していく.
データの構造化 複数のデータをまとめて1つのデータとして扱う.
オブジェクト指向 複数のデータと処理を関連付けて,それらを1つの「もの」として扱う.
関数型 複数の関数を組み合わせて関数を作っていく.関数と値を区別しない.
アスペクト指向 呼び出す関数の処理の詳細を,呼び出している側で把握,改変できるようにする.
論理型 論理を記述して,結果を得る.


各プログラミングパラダイムの詳細な説明はかなり長くなるのでここでは割愛します. 各プログラミング言語は複数のプログラミングパラダイムを持つことが多く,パラダイムの影響度も言語によって異なります. 更に1つの言語をとってみても何回かのバージョンアップで異なるプログラミングパラダイムを取り入れていることも珍しくありません.

1つのプログラミングパラダイム(言語)に慣れ親しむとそのやり方(=ノウハウ)だけでほとんどのプログラムは作成できてしまいます. それで十分なときもありますが,もっと簡単な方法がある場合が多いので複数のプログラミングパラダイムを体験することは (同じ言語を使うときでも!)今後の作業を大幅に短縮してくれることでしょう. もともとプログラミングパラダイムは言語仕様以前のノウハウなのです.

最近ではほとんどの言語でOO(Object Oriented=オブジェクト指向) が取り入れられているので知らないうちにオブジェクトを使っていることが多いです.

しかし,使い道がわからない道具は無いのも同然で, オブジェクト指向が何かがあいまいなままでは,どんな道具も同じ釘を打つ物体にしかなりません.

オブジェクト指向プログラミングにおいて,最も重要なのはオブジェクトの存在と, そのオブジェクトがどのようなものかです.

オブジェクトがどのようなものかをコンピュータ上で表す方法に型システムというものがあります. これは元来,コンピュータ上のデータを意味のあるものとして扱えるように導入されたノウハウですが, さらに拡張されてオブジェクトがどのようなものかを表すために用いられています.

プログラミング言語は型の扱い方とそれに伴う言語仕様で大きく以下の3つに分類されます. この分類は言語の実行環境との関係も深いです.

型システム 説明
1 型システム無し  初期・低レベルのプログラミング言語に多い.
 CPUの機能を最大限活用できるが,データの意味を間違いやすい(わかりにくい).
 C言語などプログラマ自身でメモリ管理を行える(しなければならない)言語は高速なコードが生成可能.
アセンブラ
C言語
COBOL
BASIC
強引に型を変換する

弱い静的型付け
2 型をコンパイル時に確認し,型変換エラーを検出する

強い静的型付け
 型の間違いをコンパイル時に見つけることができるが,記述が面倒.
 コードから型が判別でき,エディタでのサポートが充実しているものが多いが,コンパイルなどの実行のための作業が面倒.
C#
C++
F#
Java
Fortran
Haskell
Objective-C
ObjectiveCaml
ObjectPascal(Delphi)
Scala
VB.NET
3 型を実行時にインタプリタが確認し,強引に型変換する

弱い動的型付け
 型の宣言が不要で簡素な記述ができるが,実行するまで間違いに気付けない.
 エディタのサポートがない反面,多くの言語に記述と実行が同義のインタラクティブな環境があり,すぐコードがテストできる.
 コードから型が判別でき,エディタでのサポートが充実しているものが多いが,コンパイルなどの実行のための作業が面倒.
 弱い型付けは型の概念が希薄で初心者にとってわかりやすいが,強い型付けよりもエラーに気づきにくい.
Erlang
JavaScript
Parl
PHP
MATLAB
型を実行時にインタプリタが確認し,型変換エラーを検出する

強い動的型付け
Lisp
Mathematica
Prolog
Python
R
Ruby
Scheme
Smalltalk


OOとは何か,簡単にいえばただのノウハウですが,OO言語を使えば否応なしに型の存在と向き合うことになります. その時,型が「コンピュータ上のデータ+αを表すもの」ということを, OO言語(OOとしての機能)を使い始めた方は意識するとよいでしょう.

型システムはもはや無くてはならないプログラミングのノウハウなのです.