学生時代教育系バイトを渡り歩いてきた私がプログラミングを教えるときに意識していること

# はじめに


**プログラミングを人に教えるのは意外と難しい:thinking:**



　私は今年新卒でエンジニアになりました。最近は必死でバグの修正に取り組みながら毎日たくさんのことを学んでいます。
　さて、現在は実務に入っていますが、2か月ほど前までは新卒向けの開発研修に参加していました。私はプログラミングスクールでメンターのアルバイトをした経験があったので、同じく研修に参加している同期にプログラミングを教える場面が多々ありました。教える際に、私の学生時代のバイト経験が大分活きたので、そのあたりを踏まえて私がプログラミングを教える際に意識していたことを書いていこうと思います。本当は記憶が新しいうちに書きたかったのですが、実コードに圧倒される日々を過ごしてしていたらいつの間にか9月に..。ちなみに私の学生時代のバイト経験はこんな感じです↓
- 進学塾の講師(集団) 2年
- 子供向けプログラミング教室のメンター 1.5年
- 社会人(エンジニア転職志望者)向けプログラミングスクール 1年 ... など

# この記事の対象者
- 業務等で新人にプログラミングを教える機会がある人
- 開発組織で新人のメンターを担当している人
- 自分はコードをかけるけどそれを人に教えることに苦手意識がある人

# この記事を読んで得られること
- プログラミング初学者にプログラミングを教えるときに意識すべきこと 

# プログラミング初学者にプログラミングを教えるときに意識すべきこと 

では、本題に入っていきます。

まず、大前提として重要なのは、**教え方に必勝法は無い** ということです。
こう教えれば、だれでも一発で理解できる！みたいなものはありません。あったら全員がそれを見ればいいわけで、教え方が難しい、、、、なんて悩む必要はありませんよね。

では、どうすればいいか。教える際に重要なのは、**相手と前提を合わせる**ということです。

一人ひとり、前提の知識や理解度が違います。例えば、
- 情報の授業を受けたことがあるから言葉は多少わかるけど、プログラミングはやったことない。
- プログラミングはやったことないけど、数学は得意でロジックを組む作業は苦手ではない。
- 数学もプログラミングも情報の知識も全然ない。

といった具合です。この3人に同じことを教える場合、おそらく適切な教え方は3人とも変わってくるでしょう。


こういった前提の違いを把握できていないと、分かりやすく教えることは難しいです。

　自分はこれを当たり前に知っていると思ってたけれど、実は相手はこれを知らなかった、ということが起こると、おそらくその質問の時間は無駄になります。

　ここではこの自分と相手の認識の差異のことを**前提のずれ**と呼ぶことにします。

　この**前提のずれ**をなくすことが重要なわけですが、前提のずれを瞬時に見つけるのはかなり難しいです。少なくとも、こちらが一方的に話し続ける中で前提のずれを把握して修正していくなんてことは無理です。ではどうするか。

## 1. とにかく逆質問をする

　教えるとき、相手に質問していますか？一方的に話し続けていませんか？
私は、前提のずれは基本的に逆質問でしか発見できないと考えています。

　基本的に、1分以上話し続けるということはすべきでないと考えています。1分以上話すとなると、そのなかに知らない知識がいくつも出てくる可能性があるでしょう。もしその中に理解できていない概念などが存在すれば、その1分以上の説明の努力は無駄になります。

最低限、
「ここの意味は分かる？」
くらいは絶対に聞きましょう。そして、**1分に一回くらいは逆質問しましょう**。多いと感じるかもしれませんが、それくらいしないと相手にとって適切な回答をすることは(多分)難しいです。

　逆質問を投げられるようになったら、今度は、**オープンクエスチョン**を増やしていきましょう。
オープンクエスチョンとは「はい / いいえ」で答えられない質問のことです。「はい / いいえ」で答えられる質問のことはクローズドクエスチョンと言います。

「このfor文は何をしているかわかる？」
と聞いてしまうと、相手が多少理解できている場合には
「はい...なんとなく...」
みたいな返事をもらって、先に進んでしまうかもしれません。ここを、
「ここのfor文はどういう役割をしていると思う？」
のように質問すれば、理解していなければ答えられないですし、部分的に理解できていない場合もどこが理解できていないか把握できるようになります。

　このような逆質問を積み重ねることで、相手が何を理解していて、何がわからないのかを知っていくことができます。多少理解できていそうな箇所に関しては、
「ここのコードが何をしているか、上から順に私に説明してみてもらえる？」みたいにお願いすると、より理解度を把握しやすいかもしれません(全然わからない、みたいな場合には使えないですね)。

## 2. 結論を言わない (相手に言わせる)

　例えば、ここエラー出てるんですけどどうすればいいですか？みたいな質問が来たとします。このとき、「(エラー文をじーっと呼んで....) あーそれはね、ここにxxxxxって書けばいいんだよー」みたいに教えてしまうのが、結論を言ってしまうということです。結論を言ってしまうと、その場は丸く収まると思いますが、教えてもらう人は答えを教えてもらっただけであって直し方や足りない知識を学んだわけではありません。

　大切なことは、質問のやり取りを通して相手に**成長してもらう**ことです。

　例えば、エラーを解消できないという質問が来たとします。
ここで、上述の前提をすり合わせる話にもつながってくるのですが、そもそも何をすべきかわかっていない人もいるかもしれません。初学者であれば普通にいます。

　相手が初学者であれば、私ならば、今何が起きているかを説明してもらったうえで、
「まずは何をすべきだと思う？(何をしてみましたか？)」と聞いてみます。

　ここで、「誤字脱字を確認する」とか、「テキストをコピペしなおす」といった返事が返ってくるかもしれません。ここで明らかになるのは、「エラーが出たらとりあえずエラー文を読む」という前提が異なっているということです。これは、いきなり結論を言ってしまっていたら見逃す可能性があります。

　これで、エラー文を読むことを知らない、という前提を得て、エラー文を読む必要があるということを伝えることができます。次は何をすべきでしょうか。
例えば、一般的なエラー文の見方を知らない可能性もあります。それも逆質問で聞いてみましょう。
「今起きているエラーの内容を簡単に説明できる？それはどこに書いてある？」といった感じに聞いてみると理解度を把握できるでしょう。

このように、**再現性があり今後にも生かせる知識や手法**を教えてあげられると、成長を促すことができるでしょう。

## 3. 細かい単位で振り返る
　質問の規模によっては、質問のやり取りが10分20分、それ以上になってしまうことも意外とあるのではないでしょうか(プログラミングスクールだと30分以上かかる対応もたくさんありました)。そのような場合、終わった後で、とりあえず疑問は解決できたけど、結局何を教わったんだっけ、みたいなことになりかねません。それを防ぐには、10分に一回、や区切りがよいところなど、適切なタイミングで振り返りをしましょう。「一旦ここまで何をやってきたか確認しよう」といった感じで、こちらが説明するものありですが、これも相手に答えてもらい、ここまでの学びを言語化してもらうのも有効です。

　意外と、この振り返りのタイミングで相手にそこまでの内容を言語化してもらうと、「やっぱりここがあまりよくわかっていない」という返事が返ってくることもよくあります。追加で説明してあげましょう。このように、振り返りを挟むと、途中までうまく言語化できていなかった不明点が明らかになることもあるので、適宜振り返りを挟むのは重要です。

## 4. 時には、厳密さを多少妥協することも必要
　プログラミングや開発で登場する概念は、中々一発で理解することが難しいものも多いです。例えば、オブジェクト指向、再帰、MVCモデル、クラスの継承、などなど。

　これらを誰に対してもわかりやすく教えるのは正直私も結構難しいですが、その原因は、これらは抽象度が高いからだと思っています。例えば、classについて聞かれたときに
「クラスとはオブジェクト指向プログラミングにおいて、オブジェクトの設計図に相当するもので、クラスに基づいて作製されたオブジェクトの実体のことをインスタンスといいます。」
と説明しても初学者にはなかなか伝わらないでしょう。

　例えば、よくあるclassの説明するときの例えとして、タイ焼き機の例があります。
タイ焼き機の型がclassで、タイ焼き機で生成されるタイ焼きそのものがインスタンスに相当するよ、のような例えです。

　この例えがあるだけでも、多少は理解が進むと思います(実際にこれだけ説明して完全に納得する人はあまり見ませんが、助けにはなっているでしょう)。プログラミングは理解しにくい概念が多いので、多少厳密性を失ってでも身の回りの物や既知のものに例えたりすることで理解を促すことが可能です。

　数学を教えるときなども、例えば微分を知らない人に微分の定義を教えるところから始めると、とっつきにくいでしょう。とりあえず微分とは傾きを求めるものだよ、のように雑な概念を教えて、簡単な例題をこなして微分することに慣れてから厳密な定義を教えた方が結果的に早く理解できたりします。

　これと同じように、抽象度の高い概念を教えるときは、多少雑にしてでも**具体例に落とし込む**ことが近道だったりします。**厳密な理解は後から獲得できればそれでよい**という考え方です(賛否両論あるとは思います)。

## 5. 合ってたらわかりやすく褒める＋同情する
　これは単純に質問ハードルを下げるということと、成長実感を与えるという意味で非常に重要です。大人も褒められたいですし、褒められると当然うれしいです。冒頭で逆質問をたくさんするようにと書きましたが、それが正しかったら声に出して肯定しましょう。加えて、相手が間違ってしまったときも、「ここってなかなか理解するのむずかしいですよね、自分も最初つまずきました。全然大丈夫ですよ」のようなフォローを入れてあげると、質問に対する心理的なハードルが下がるでしょう。

## 6. 小ネタ
### 変数の中身や出力を細かく確認する
　コードが理解できない場合、その原因の一つに、途中で値がどうなっているかよくわからない、というのがあります。例えば、for文の中に複雑な処理が入っていて、毎回の実行で変数がどう変わっているのかイメージできない、などです。そういうときは、デバックツールやprintなどを使って変数の中身を見せてあげましょう。

### 1回の質問で全部解決しようとしない＋宿題を出す
　質問を解決する道のりが長い場合は、「一旦ここまで自分でやってみよう。ここまで終わったらまた続きを質問してください。」のように宿題を出して質問の時間を分割すると、相手は一旦自分の中で整理する時間を作れるので結果的に少ない質問時間で理解を促せたりします。

### 伝えたいことを絞る
　例えば、逆質問で前提の状態を見極める中で、知らないことが結構多い、みたいなこともあると思います。オブジェクト指向がわかっていない+データ型の厳密な差異がわかっていない、などです。そのような場合は、例えばオブジェクト指向にターゲットを絞り、データ型については「一旦この場ではxxxxxxのようなものだと理解してください」のように詳細な説明をあきらめることで、最重要項目をしっかり理解させることが可能です。人間なので、一回のインプット量には限界があります。

## おわりに

　かなり量が多くなってしまいましたが、私が他人にプログラミングを教えるときはこのあたりを意識しながら対応しています。少しでも、プログラミングの教え方に困っている方のお役に立てればうれしいです。