程式導師實驗計畫第三期開始快一個月了。有了前兩期的累積,第三期到目前為止執行得滿順利的,我也嘗試了很多想嘗試的新東西,這部分之後可以再寫一篇文章跟大家分享。

有滿多文章都在談「如何問一個好問題」,例如說最經典的:提問的智慧。但好像比較少文章在談:「如何給出一個好答案」。

或是更精確地說,如果你是要站在一個導師的角度去回答學生問題,我覺得「給出一個好答案」並不是最好的方法,「引導學生自己找到答案」才是正確解答。不過依據學生提問的種類不同,其實也會有不同的回答方法。

接下來我會談談我自己在回答學生的問題時會盡量遵守的一些準則,並且說說我認為哪些是好的,哪些又是不好的。如果你有哪些部份想討論的,都歡迎在底下留言。

壞方法:直接告訴學生答案

在《學生為什麼不喜歡上學?》這本書中,有一段是這麼說的:

回到教學上,我是這麼想的:我要學生學習的內容,說白了就是一個問題的答案。答案本身一點都不有趣,但如果你知道問題的話,答案可能會很有意思。所以把問題說清楚才那麼重要。

但我有時候覺得,身為教師,我們都太強調求出答案,而沒有花足夠的時間讓學生理解問題,並了解問題的重要性。

答案一點都不有趣,有趣的是去尋找答案的那個過程。我覺得有時候若是直接給了答案,反而就像看電影爆雷那樣,一切就都不再有趣了。

但在有些情形之下,直接給答案還是可以的。我開頭有說了,依照問題的不同也會有不同的應對方式,我先提出一個原則好了:

在回答學生問題的時候,讓他「知道答案」不是最重要的。讓他「知道怎麼找到答案」才是。因為唯有這樣,下一次他才能自己解決問題。

這邊我直接舉一個常見的例子。

在要學生寫出判斷質數的程式碼時,有個很常見的錯誤會長這樣:

發生錯誤之後,學生可能會帶著這段 code 來找你,問你說:「老師,為什麼這題輸出的結果跟我想的不一樣?」或是「老師,為什麼這樣解不行?」

這時候我認為比較不好的答案是:「因為你的程式碼跟你的邏輯不一樣,你那個 return true 應該要放 for 外面才對」

若是回答這個,學生看了之後可能會有兩種反應:

  1. 先改程式碼,改了之後發現正確就不管它
  2. 想了一下發現老師說得對,把程式碼改掉之後變正確了

好方法:不要輕易告訴學生解答,而是引導

那我認為比較好的回答是什麼?比較好的回答是引導他,讓他自己發現問題在哪裡。

具體上該怎麼做呢?

我會跟他說:「你丟 9 這個數字進去,然後一行一行跟我說程式碼是怎麼跑的」。

老手跟新手有一個很大的差別。

我看到程式碼以後,我就可以假裝我是電腦一行一行執行,但新手不行。新手看程式碼是憑感覺的;憑感覺應該會這樣跑,但現實往往事與願違。所以要幫助新手,就要幫他培養這種程式思維。

學生一行一行把執行順序寫下來後,會變成這樣:

  1. 執行 isPrime(9)
  2. 判斷 n 是否等於 1,不是,往下執行
  3. 執行 for 迴圈,設定 i = 2,符合 2 < 9,繼續執行
  4. 跑到迴圈裡面,判斷9 % 2,不等於 0,回傳 true

這時候就能發現程式的邏輯錯在哪裡了。正確的邏輯應該是:「2 ~ n-1 的正整數都無法整除,才是質數」,但現在變成:「只要沒辦法被 2 整除,就是質數」。

意識到這點之後,學生就自然能夠修正錯誤了。

我的原則是:「你沒有自己理解過這段程式碼,別叫我幫你 debug」,因為幫你 debug 也沒有用。你需要的不是我幫你 debug,而是學會自己怎麼 debug。

所以好方法跟壞方法的差別在哪裡?差別在於解法是誰想出來的。你自己想出來的解法跟別人想出來然後告訴你,你覺得哪一個印象會更深刻?

壞方法:剝奪學生學習 Google 的機會

以下是真實案例,一個學生曾經問過我的問題:

請問一下 Google 表單點選輸入框後,那個底線的特效怎麼弄的 ? 搞了一下午弄不出來,但又覺得這特效很不錯

此時你可能會做出幾個選擇:

  1. 直接跟他說可能是 transition 搭配 padding 或是 width 之類的
  2. 把 demo 寫好直接丟給他
  3. 丟 material UI 的 source code 給他
  4. 自己也不知道,於是丟 Google 之後貼第一個搜尋結果的網址給他

但無論是哪一種,一樣都是直接讓他知道結果。下次再碰到問題時,他一樣會跑來問你,因為他不知道該怎麼找答案。

好方法:讓他學習你的 Google 關鍵字

很多新手不是不會用 Google,他們當然也知道問問題以前要先 Google。但問題是,關鍵字要怎麼下?對新手來說這個領域是完全陌生的,甚至連專有名詞都還沒瞭解過,你要他們怎麼下關鍵字?

所以我認為的好方法就是:把你針對這問題會下的關鍵字給他。

以這題來說,我會下的是:「underline transition css google form」,我自己試過之後發現前幾筆資料看起來是 ok 的,就會把這個關鍵字丟給學生。

壞方法跟好方法的差別在哪裡?

差別在一個是學習你的解答,一個是學習你解決問題的方法。

壞方法:容忍壞問題,盡情發揮通靈本領

雖然說大家都看過提問的智慧,但很多新手提出來的問題都還是很沒有智慧。沒有啦開個玩笑,這樣講有點太嚴重。我的意思是,他們提出來的問題依然沒有那麼好,沒有附上所有你需要的 debug 資訊。

例如說這個問題:

請問: curl: (60) SSL certificate problem: unable to get local issuer certificate 要怎麼解決?

你可以直接拿錯誤訊息去 Google 然後把解法丟給他,但這並沒有解決問題。因為他的問題還有一個,那就是:「不知道怎麼正確地提問」。

還有一個例子:

請問有人用 Eslint 遇到 2:29 error Parsing error: Unexpected token )嗎?我 google 後有人說這句指程式碼是正確的,但轉寫格式有錯就會出現類似問題,不太懂這句的意思

有 Google 過,很好。但光憑這個錯誤訊息,我是沒辦法 debug 的。我必須知道你第 2 行到底放了什麼程式碼,才知道問題出在哪,才能幫你忙。

當然,很多有經驗的工程師都已經培養了通靈的技能,而且級別還滿高的。有時候對於這種壞問題,還是可以發揮通靈王的本事,直接猜中他原本的程式碼可能長什麼樣子,然後就把問題給解決了。

但這是治標而不是治本。

好方法:壞問題請改成好問題,而不是靠通靈

除了學生問的那個問題以外,最大的問題其實是學生不知道怎麼問出好問題。培養問問題的能力也是很重要的,有時候你一旦學會提問,在把問題整理好的時候可能就已經知道如何找到解答了。

針對第一個提問,我會問他說:「你嘗試過哪些解法了?」、「你下了哪些指令?」、「可以給我看 terminal 的截圖嗎?」。一個好問題,能夠讓別人看到問題以後直接幫你 debug,因為你把該給的資訊都給了。

所以這個問題如果是我來問,會變成這樣:

我在下指令:curl https://google.com 的時候碰到錯誤:curl: (60) SSL certificate problem: unable to get local issuer certificate,這是 terminal 的截圖(附上圖片)。我拿錯誤訊息去 Google 之後找到了這篇文章(附上連結),照著上面寫的加上一個參數 xxx 之後還是一樣,想問一下有其他解法嗎?

針對第二個提問,我會問他說:「你是不是少附了什麼?」,對方就應該會把程式碼也給貼上來。除了這些,其實也應該要把 terminal 截圖給貼上來,看一下 ESLint 錯誤發生時的截圖,才有足夠的資訊可以來 debug。

這邊一樣給完整範例,是我的話會這樣問:

我剛剛在跑 ESLint 的時候出現了這個錯誤: 2:29 error Parsing error: Unexpected token ),這邊是我的程式碼(附上文字),這邊是編輯器的截圖(這樣比較好看行號),這是 terminal 的截圖(可以看 ESLint 的錯誤訊息),我拿這錯誤去 Google 之後好像都是不太相干的文章,不太知道錯在哪裡,想問一下有人有任何方向嗎?

問問題的時候請把握幾個原則:

  1. 錯誤發生在哪?(文字加截圖)
  2. 錯誤內容為何?(文字加截圖)
  3. 你怎麼下關鍵字?(搞不好只是關鍵字沒下好)
  4. 你試過哪些解法?(可以給連結)
  5. 你猜測可能是哪邊有問題?(雖然不一定準就是了)

要準備完整一定會比較麻煩,但這是必要的。而且如同我上面所說的,很多時候你把問題準備好之後,就會發現自己已經知道怎麼解開了。

總結

回答問題時,其實就是一個原則:

讓學生學習你解決問題的方法,而不是學習你的成果。

你怎麼 debug,你就教學生怎麼 debug,而不是幫學生把 bug 修好之後跟他說:「欸欸,是這個問題」。

引導式的教學方法會比較花時間,而且有時候你會覺得有點繞遠路(明明就知道錯在哪裡卻不能直接跟他說),但我覺得長期來看,這才是比較有效率的方法。

以上是目前我自己在教學時會盡量採用的方法,也順便幫自己記錄起來。搞不好過個一兩年我會發現其實有更好的方法,或甚至當初覺得的壞方法其實是好方法之類的。

有什麼跟教學相關的心得也歡迎留言跟我討論,感謝。