『プログラマー脳』認知科学でプログラミングはもっと楽しくなる!

すべてのプログラマーに読んでもらいたい本だ。

経験の浅いプログラマー、ベテランプログラマー、そしてもっと言うとプログラマーでなくても得られるものが多い本であると思う。

認知科学に基づく」と聞くと難しい内容が書かれていると思ってしまうが、そんなことはない。認知科学とはどんなものなのかを紐解きながら読み進められるのでわかりやすく楽しい本になっている。

この本にはコードを「書く」ときのテクニックが書いてあるだけでなく「読む」ことにもフォーカスを当てている。

プログラマーはどうしてもコードを書くことに重きを置きがち(どうしたら良いコードが書けるか、効率の良いコードが書けるか)だが、もっとコードを読む訓練が必要であると著者はいう。

それは、プログラマーの仕事はコードを書いている時間よりも読んでいる時間の方が多いからだ。

自分に当てはめて考えてみると確かにそうだ。まあ僕はプログラマーを名乗れるほどコーディングをしていないからというだけなのだけれど・・・。

この本を読めば読むほどコードを読む、書くテクニックを知って、コードと対峙したくなってくるだろう。

 

  • 複雑なコードを読む時の認知的負荷を軽減するテクニック
    • すべての変数を丸で囲む
    • 類似した変数を線でつなぐ
    • すべてのメソッドや関数を丸で囲む
    • メソッド/関数呼び出しをその定義場所と線でつなぐ
    • クラスのインスタンスをすべて丸で囲む
    • クラス定義とそのインスタンスの間に線を引く
  • 普通の文章でもコードを読むときにも適用できる文書理解の戦略
    • 活性化:関連する事柄を積極的に考え、過去の知識を活性化させる
    • 監視:文章の理解度を把握し続ける
    • 重要性の判断:文章のどの部分んが最も関連性が高いかを判断する
    • 推論:文章にはっきりと書かれていない事実を補完する
    • 可視化:読んだ文章の内容を図解して理解を深める
    • 自問自答:その文章について、質問を作り、それに答える
    • 要約:文章の短い要約を作成する

 

名前 説明 悪い名前の例
ルールを逸した大文字の利用

識別子の名前では、大文字は適切に
利用しなければならない

pagecounter
アンダースコアの連続 識別子の名前にアンダースコアを
連続して使うべきではない
page__counter
辞書に載っている単語の利用 識別子は意味のわかる単語のみを利用して、
省略形はそのほうが完全表記よりも
一般的な場合にのみ使用する
pag_counter
単語数 識別子は2単語から4単語以内で構成すべきである
page_counter_
converted_and_
normalized_value
多すぎる単語 識別子には5単語以上を使うべきではない
page_counter_converted_and_normalized_value
短すぎる識別子 識別子は8文字未満であってはならない。
ただし、c、d、e、g、i、in、inOut、
j、k、m、n、o、out、t、x、y、zは利用してよい
P、page
列挙型識別子の宣言の順番 何か特別な理由がない限り、列挙型の名前は
アルファベット順に宣言されるべきである
CardValue = {ACE, EIGHT, FIVE, FOUR, JACK, KING...}
前後のアンダースコア 識別子名の先頭や末尾に
アンダースコアをつけてはならない
__page_counter_
識別子への型情報の追加 識別子の名前にハンガリアン記法などを用いて
型情報を追加してはならない
int_page_counter
長すぎる識別子 可能なら長い識別子名は避ける
paga_counter_converted_and_normalized_value
ルールを逸した命名 識別子は、一般的ではない方法で
大文字と小文字を組み合わせてはならない
Page_counter
数字を表す識別子名 識別子は、数字を表す単語だけで構成してはならない FIFTY

 

 

名前

説明 悪い名前の例
ルールを逸した大文字の利用 識別子の名前では、大文字は適切に利用しなければならない pagecounter
アンダースコアの連続 識別子の名前にアンダースコアを連続して使うべきではない page__counter
辞書に載っている単語の利用 識別子は意味のわかる単語のみを利用して、省略形はそのほうが完全表記よりも一般的な場合にのみ使用する pag_counter
単語数 識別子は2単語から4単語以内で構成すべきである page_counter_converted_and_normalized_value
多すぎる単語 識別子には5単語以上を使うべきではない page_counter_converted_and_normalized_value
短すぎる識別子 識別子は8文字未満であってはならない。ただし、c、d、e、g、i、in、inOut、j、k、m、n、o、out、t、x、y、zは利用してよい P、page
列挙型識別子の宣言の順番 何か特別な理由がない限り、列挙型の名前はアルファベット順に宣言されるべきである CardValue = {ACE, EIGHT, FIVE, FOUR, JACK, KING...}
前後のアンダースコア 識別子名の先頭や末尾にアンダースコアをつけてはならない __page_counter_
識別子への型情報の追加 識別子の名前にハンガリアン記法などを用いて型情報を追加してはならない int_page_counter
長すぎる識別子 可能なら長い識別子名は避ける paga_counter_converted_and_normalized_value
ルールを逸した命名 識別子は、一般的ではない方法で大文字と小文字を組み合わせてはならない Page_counter
数字を表す識別子名 識別子は、数字を表す単語だけで構成してはならない FIFTY

 

イギリスのオープン大学の准上級講師であるサイモン・バトラー(Simon Butler)が作成した変数名で発生する問題の一覧

名前 説明 悪い名前の例
ルールを逸した大文字の利用 識別子の名前では、大文字は適切に利用しなければならない pagecounter
アンダースコアの連続 識別子の名前にアンダースコアを連続して使うべきではない page__counter
辞書に載っている単語の利用 識別子は意味のわかる単語のみを利用して、
省略形はそのほうが完全表記よりも一般的な場合にのみ使用する
pag_counter
単語数 識別子は2単語から4単語以内で構成すべきである page_counter_converted_
and_normalized_value
多すぎる単語 識別子には5単語以上を使うべきではない page_counter_converted_
and_normalized_value
短すぎる識別子 識別子は8文字未満であってはならない。
ただし、c、d、e、g、i、in、inOut、
j、k、m、n、o、out、t、x、y、zは利用してよい
P、page
列挙型識別子の宣言の順番 何か特別な理由がない限り、
列挙型の名前はアルファベット順に宣言されるべきである
CardValue = {ACE,
EIGHT, FIVE, FOUR,
JACK, KING...}
前後のアンダースコア 識別子名の先頭や末尾にアンダースコアをつけてはならない __page_counter_
識別子への型情報の追加 識別子の名前にハンガリアン記法などを用いて
型情報を追加してはならない
int_page_counter
長すぎる識別子 可能なら長い識別子名は避ける paga_counter_converted_
and_normalized_value
ルールを逸した命名 識別子は、一般的ではない方法で
大文字と小文字を組み合わせてはならない
Page_counter
数字を表す識別子名 識別子は、数字を表す単語だけで構成してはならない FIFTY

 

 

文法的に一貫した命名を大切にする考え方と、コードベースを通して一貫した命名であることを大切にする考え方がある。

前者はチャンク化を助け、後者は名前を処理する際に認知的負荷を下げる。

 

スネークケースかキャメルケースか

プログラマーと非プログラマー合わせて135人が参加した研究で、被験者はまず「リストをテーブルに拡張する(Extends a list to a table)」といった変数の役割を説明する文章を見せられ、4つの選択肢から、その文章を表す変数名として適したものを選ぶように指示された。

選択肢としては、extendListAsTable, expandAliasTable, expandAliasTitle, expandAliasTableなど。

結果、プログラマーと非プログラマーの両方において、キャメルケースを使う方が、より適切なものを選択する確率が高いことが示されている。

キャメルケースで書かれた識別子の方が、正しい選択肢を選ぶ確率が51.5%高いことがわかった。ただし、キャメルケースを使うと精度は高くなるが答えを出す速度が遅くなっていた。

→キャメルケースの変数は、スネークケースで書かれた変数よりも覚えやすい一方、スネークケースの方が変数を認識するまでにかかる時間は短くなる。

 

フェイテルソン氏による、よりよい変数名のための3ステップのモデル

  • 名前に含めるべき概念を選択する
  • それらの核概念を表す単語を選ぶ
  • それらの単語を使って命名を行う

 

ワシントン州立大学の教授であるアルナウドヴァが定義した言語的アンチパターン

  • メソッド名に書かれた以上の働きをするメソッド
  • 実際の働き以上のことをするかのごときメソッド名
  • メソッド名に書かれたのと真逆のことをするメソッド
  • 実際に格納されているよりも多くのものが含まれているかのごとき識別子名
  • 実際に格納されているよりも含まれているものが少ないかのごとき識別子名
  • 実際に格納されているものと真逆な識別子名

専門知識の呪い(curse of expertise)

何かのスキルを習得するとそれを習得するまでにどれだけ時間を要したのか、どれだけ大変だったのかを忘れてしまう呪い。

経験豊富なプログラマーが新人プログラマーのトレーニングを効果的に行えなくなる理由のひとつ。

学ぶ側は教える側が思っているほど(これも勘違いなことが多いけど)簡単ではないと感じていることを教える側が認識してあげるべきである。

 

心理学的フレームワーク「新ピアジェ主義」

幼児の発達の4つの段階に注目した発達心理学ピアジェの研究を基にしたもの。

 

段階      振る舞い
感覚運動期 計画や戦略は立てることができず、ただ感覚に基づいて動くことしかできない 0〜2歳
前操作期 仮説や計画を立て始めるが、それを確実に思考に生かすことはできない 2〜7歳
具体的操作期 眼に見える具体的なものについては仮説を立てられるようになるが、一般的な結論を出すのはまだ難しい 7〜11歳
形式的操作期 形式的な推論をすることができるようになる 11歳以上

この新ピアジェ主義のモデルをプログラミングに適用するとこうなる

段階      特徴 プログラマーの行動
感覚運動期 計画や戦略は立てることができず、ただ感覚に基づいて動くことしかできない プログラムの実行について、まったく正しくない理解しか持たない。この段階では、プログラマーはプログラムを正しく読み、追いかけることはできない
前操作期 仮説や計画を立て始めるが、それを確実に思考に生かすことはできない トレース表を作成するななどして、複数行のコードの結果を手作業で確実に予測することができるようになる。前操作期のプログラマーは、コード全体ではなく、一部のコードについてどんな処理をしているかを推測することが多い
具体的操作期 眼に見える具体的なものについては仮説を立てられるようになるが、一般的な結論を出すのはまだ難しい 前操作期的な帰納的アプローチではなく、コードそのものを読んで、演繹的にコードについて理由づけを行うことができる
形式的操作期 形式的な推論をすることができるようになる 論理的で一貫性のある、体型的な推論ができる。形式的操作的な推論には自分の行動を振り返ることも含まれ、これはデバッグには不可欠である

 

新人研修時はプログラミングに関する活動を1つに限定する

活動 新人教育時の活用方法
探索 コードベースを見渡して、その全体像を把握する
検索 特定のインターフェースを実装しているクラスを探す
転写 新人に作業の具体的な手順について明確な計画を与える
理解 特定のメソッドを自然言語で要約するなど、コードの内容を理解する
増強 既存クラスへの機能追加(計画の作成も含む)

 

コードの中のどこが最も重要であるかを新人に伝える

新人研修で最も重要なのは、新人自身が現在どの程度の理解度にいるのかを把握し続けること。
→定期的に振り返りの作業をすることを伝える