2つのことを同時に学ばない

こんにちは、ある人のところてんです。プロシンという情報処理学会の<s>新年会</s>学会にかれこれ15年くらい参加しているわけですが、本稿はそこで水島さんと話をした「2つのことを同時に学ばない」という考え方についてのまとめになります。

初手レイトレーシング

「2つのことを同時に学ばない」というのは私が発した言葉ですが、この言葉には私の友人の影響があります。

私の友人に「新しいプログラミング言語を覚える際には、とりあえずレイトレーシングを書いてみる」と言うやつがいます。
彼にとってはレイトレーシングのコードは、資料を何も調べずとも書けるそこそこに複雑なコードという位置づけのようです。

そのため、彼にとってはレイトレーシングを新しい言語で書くことで、言語仕様にのみ問題を絞って勉強することができるわけです。仮に実行結果がマズかったとしても、それは言語仕様の理解の問題であり、アルゴリズム自体に問題ないことが彼にとっては明白なのです。

逆を言うと、言語とアルゴリズムの二つのことを同時に学ぼうとした場合、実行結果がマズかったとすると、どちらが問題でうまくいかないかが明確ではないため、その解決に多大な時間を奪われてしまうわけです。

初学者とN個の問題

多くのプログラミングの初学者にとって、二つや三つのことを同時に学習しなくてはいけないことが、効率的な勉強の妨げになっているのではないかと私は考えています。

何も知らない人にいきなりエディタを渡して、「さぁプログラミングを始めましょう」と言っても彼の目の前には、言語仕様、アルゴリズム、IDE、ファイルシステム、型システム、標準入出力、デバッグノウハウ等々の壁が立ちふさがります。

そして、どれが問題で実行結果がマズいのかが分からず、結果として適切な言葉で検索することもできず、質問することもできず、なかなか成長できないということが起こってしまっていると考えています。

そのため、私は「二つのことを同時に学ばない」というのが効率的な勉強のためには必要なのではないかと考えています。

フロー体験、問題の難易度

心理学の一分野にフロー体験という概念があります。

簡単に説明すると問題の難易度と当人のスキルが噛み合っている状態だと、脳が学習状態に入り、高い集中力を発揮できるというものです。
そして簡単すぎると学習ができず退屈と感じ、難しすぎると成功する目が見えないため学習が行えなくなってしまい、不安になってしまいます。

最近出たニュースに「正答率85%が最も効率的に学習できる」という話がありましたが、これもフロー状態を維持できる難易度が一番学習効率がいい、という話なんだろうなぁと思います。

人はフロー状態を維持できるかどうかで生産性は大きく変わります。

「2つのこと同時に学ばない」というのは、フロー状態を維持するための難易度調整でもあります。これがセルフマネジメントできるかどうかで、当人の生産性は大きく変わると思っています。

ちなみにこれは、新人指導で毎回、頭を悩ませる問題です。
技術力が足りないのにいきなり本格的な本を読み始めて難しすぎて挫折して伸び悩む新人に、いかに初学者向けの本を推薦するか、けれども当人は難しい本を読みたがり…
という問題、どうしたらいいですかねー。

2つ以上のことを同時に学ぼうとした場合の実例

この記事を書いている際に、まさに実例が出てきたので紹介しよう。

学習中はとにかく疑問が無限に湧いた。写真を中央に配置するにはどうするか、指示の順序はどう書けばいいのか――。言われたとおりにコードを書いても、思うように動かない。もちろんスクールで基本的な方法は教わるが、週1度の授業ではとてもすべての疑問を解消できない。平日の仕事後、毎晩終電までカフェにこもり、課題提出のためにコードを叩いた。しかしエラーは解消せず、原因がわからない。冒頭に記したような真っ暗なトンネルの中でもがく日々が続いた。

(中略)

ただ初心者にとってはその「ググり方」が難しい。確かにインターネット上には、多くのコードの書き方が紹介されている。しかし、そのほとんどは「理解している人」が書いており、初心者にはなじみのない用語が多く交じる。各々の用語や概念には膨大な周辺情報があり、どこまでググっても「全体像」を理解できないのだ。部分部分の「正解」をいくらインプットしても、自分が望む作品のコードの書き方、つまり「個別解」がわからない――。私が最初に直面したプログラミングの難しさは、この一言に尽きる。

おそらくこの記者はWebサイトを構築するような課題を与えられていたのだと思う。しかし記者にとっては、Webサイト構築にはHTMLそのものの概念、CSS、JavaScript等々の複数の問題を同時に学ぼうとしてしまっており、どれが原因でエラーが出ているのか分からない状態に陥ってしまっているように見える。

マンツーマンの授業ほど理解が進むものはない

最終的に記者は別のサービスを通じてマンツーマンのプログラミングの授業を受けることで、疑問を解消することができた。OJT等の対話を通じて何が分からないのかを探っていくプロセスは、複数のことに同時にぶち当たっているときには極めてうまく働く。

しかしまぁ、これはコストが高い。そして毎回やっていては自走できない。人がいないと学習ができない人と、自分ひとりで学習できる人の成長速度は大きな差となる。
なので、いつかは人がいないと学習できないという状況から脱却しなくてはいけない。

ところてんの場合

初手レイトレとはいかないですが、自分にとってある程度簡単な問題を新しい言語や環境で書くことで、その環境に対する理解を獲得していきます。インターネット上に作業記録が残っていたものを引っ張り出してくるとこんな感じ。

  • Rubyを覚えるのに粒子法のコードを書く
  • C++のリハビリをするのにSiv3DでBox2Dで遊んでみる
  • Goを覚えるのにPID制御を書いてみる
  • JavaScriptのリハビリをするのにドラムマシンを作ってみる

自分にとって既知のアルゴリズムを新しい言語で書くことで、うまく実行できなかったとしても、自分の言語仕様に対する理解の問題であるとすぐに切り分けることができるわけです。

同じブロックが4個つながったら爆発して消える、みたいなロジックが入っていたはず

仕事ではじめる機械学習の場合

実はこの考え方は「仕事ではじめる機械学習」を書いた際にも実践しています。

「未知のデータに未知のアルゴリズムを試さない」という方針のもと、Uplift Modelingの紹介の章では、絶対に成功するであろうテストデータを作るプログラムを作り、それをもとにアルゴリズムを開発することで、データの問題なのか、アルゴリズムの問題なのかを切り分けられるようにしています。

Uplift Modelingには標準的な公開データセットが存在しないため、今回はデータセットの生成からはじめます。加えて、今回のように新しいアルゴリズムを実装する際、性質が未知のデータセットを用いてアルゴリズム開発を行うと、出力された結果がおかしかった場合、データセットの性質によるものなのか、アルゴリズムにバグがあるせいなのかが分からないためです。(仕事ではじめる機械学習、192pより引用)

私が技術顧問で手伝っている会社でもこのことはよく言っています。アルゴリズムの問題なのか、データの問題なのかを切り分けられるようにすることで、バグや悩む時間を大幅に減らすことができるわけです。

まとめ

2つのことを同時に学ぶと、次のような問題が起こる

  • どちらが原因で問題が発生したのかの切り分けができないので、原因の特定が困難であり、検索することも難しく、学習を阻害する
  • 難しすぎる課題は、フロー状態に入ることができない

1つのことに絞って学ぶことは次のようなメリットがある。

  • 何が原因で問題が発生したのかが明白であり、原因を特定しやすい
  • 適度な難易度を維持できるため、フロー状態に入りやすくなり、生産性が大きく向上する

初学者にとってプログラミングは複数のことを同時に学ぶことに相当するため、何が原因でうまくいっていないのかを把握することができず、それが結果として学習の阻害として働いているのではないか。(仮説)

とはいえ、プログラミングの初学者に一つずつ物事を教える適切な方法は確立されていないので、これが発明できたら面白そう。

余談

初手レイトレースの友人とは関係ないけど、ライブコーディングでC++でレイトレースを書いているVtuberを勝手に紹介する。つよい。そして、実は件の友人が中の人なんじゃないかと疑っている。

追記:2つ以上のことを同時にやるしかない場合

女騎士、経理になる。 (8) より引用 https://amzn.to/2RwypHt

にゅーるにゅーる

にゅーるにゅーる