轉錄-追求神乎其技的程式設計之道

※ [本文轉錄自 geodesic 看板]

寫這東西的人好像比我還年輕= =看得懂這篇文章不知道是悲是喜…
-
本文

作者:vgod

追求神乎其技的程式設計之道(一)

最近有讀者問到我學寫程式的方法和經驗,
讓我一下掉入時光隧道回想起當初用VB寫出自己第一個遊戲時的成就感,
但當初沒料到的是我真的就此迷上了電腦和寫程式的快感,
不知不覺也過了10年的光陰…。

在這篇文章中,我想寫出我對程式設計的看法和我一路學習上來的歷程和經驗。

寫程式是一條無止境的道路,不只是科學和工程,更是一種藝術。

而我還在追求「神乎其技」的半路上,雖然還有很多要學的,
但我也希望能讓初學者更容易看清楚這條路是什麼樣子,
避免陷入盲目追求新技術的死巷中。

一切的開始

如果是從 DOS 時代開始玩電腦的玩家,
應該都知道當初 DOS 有兩個內建的 QBASIC 小遊戲:貪食蛇和猩猩丟香蕉。

這兩個小遊戲是許多人兒時共同的回憶,我還記得我國小時曾有幾堂電腦課,
當時老師在台上嘰哩瓜啦的不知道在教什麼,
而台下每台電腦都是貪食蛇或丟香蕉的畫面
(老師對不起,其實我就是帶頭做亂的罪魁禍首…)。

微軟把這兩個 QBASIC 遊戲附在 DOS 內對我產生了莫大的影響,
那是我第一次發現到原來 QBASIC 和不只是像 PE2 能打打字而已,
QBASIC 竟然能把一堆看起來像咒語的文字變成遊戲!

幸運的是我家剛好有本第三波的 QBASIC 入門書,沒事我就自己拿起來翻著看,
雖然當時太小,即使把整本都看完了還是搞不懂貪食蛇是怎麼寫出來的,
但也誤打誤撞知道了原來這就是程式設計,
原來我能直接把貪食蛇檔案內的一個數字改掉就能有幾百條命可以死,
原來學寫程式就能做出電腦遊戲…。

對小孩子而言,知道這些事就像告訴他魔術師袖子裡的秘密一樣,
我一天到晚興奮地要老爸帶我去書局看電腦書,
彷彿真的可以搞懂電腦螢幕背後的一切魔法一樣,我也夢想著有一天能寫出自己的遊戲。

但當時我沒想到的是,我還真的花了十幾年的時間在探索電腦的魔法…。

MUD 與黑白棋

升上國中後,家裡裝了一台 28.8kbps 的 modem,當時的 internet 還沒完全成形,
在沒有 Google 的時代 internet 是沒什麼價值的。

當時的 modem 最常被我拿來上一些撥接式的 BBS,那時候的撥接 BBS 站台還不少,
最棒的是還能從站上抓到很多軟體和各式各樣的教學文章,
像是如何用組合語言寫電腦病毒,如何破解大富翁 2 之類的文章。

這些文章對當時的我就像武林密籍一樣,雖然沒辦法完全看懂,
但我也是從中得到很多零碎的概念,
像是 16 進位的換算、組合語言、中斷向量、常駐程式….。

在國二時,我還不小心迷上當時一個超熱門的 MUD – 萬王之王(KK),
每天放學回家都急著連上線,讓家裡電話整晚都忙線中,玩到每個月電話費都是上千元,
搞得我媽數次警告要把 modem 收起來再也不讓我上網了。
(還好她沒真的這麼做,不然我現在就沒辦法寫這篇文章了。)

MUD 是現在 MMORPG 的純文字版,整個虛擬世界都用文字描述,
並且只要用 telnet 就可以連上去玩了。

但內行的玩家都知道,玩 MUD 應該要用 zMud 或是 UNIX 下的 tintin++,
因為這兩個軟體可以設定所謂的 trigger,偵測到某些事件的發生,
就能自動採取事先指定好的動作。

因為一切的訊息都是由文字呈現,所以偵測事件非常簡單,
只要看看有沒有特定字串出現就可以了;
而要做特定的動作也很簡單,就是送出文字指令而已。
(眼尖的人一定會發現,這其實就是現在 MMORPG 外掛的最原始形式。)

嚴格說起來,zMud 是我首次寫「實用程式」的平台,
我學會透過 trigger 在MUD的世界中寫自動化的機器人,自動在迷宮中遊走,
自動換裝備打怪練功..。

這時的我突然體會到,會寫程式真是太棒了,我在 MUD 中簡直跟神一樣。

其實當時我也不過只會用最基本的變數、if、迴圈而已,
但透過在虛擬世界中寫機器人的練習,讓我的邏輯思考概念有飛快的進步,
也給我了非常強烈的動力想好好學一個正統的程式語言。

升上國三後,很幸運的透過推薦甄試提早上了台中一中,升學壓力解除後,
老師和父母就完全不管我要幹麻了。

這時我終於有了一段完整的時間可以好好的再把 BASIC 重新學過,
無奈的是在我國三時 QBASIC 已經快滅絕了,
取而代之的是 Windows 上的 Visual Basic,我只好硬著頭皮買本新書來從頭學起 VB。

當時我看的是王國榮的 VB 5 入門書,整本書有六七百頁吧,
比我國三所有課本疊起來都還厚,
現在想想小時候真的有點不知天高地厚竟然相信自己能看完這麼厚的磚頭書。

那時候我每天上課就帶著這本磚頭去學校,這樣看了幾個禮拜下來,
沒想到我這時突然都看得懂了,
很多原本不知道有什麼用途的概念突然都相互連結起來了。(多虧了在MUD裡的訓練!)

就這樣,某天突然有種打通任督二脈的感覺,我發現我全搞懂了,
迴圈、陣列、Windows GUI 控制項、去背貼圖…,
我突然想通要怎麼用程式語言寫出遊戲了。

從那之後,每天回家就是打開 VB 寫程式,我想寫個黑白棋來檢驗自己的想法,
我把自己知道的所有概念都放進去,有 GUI 元件、有貼圖、有動畫、有音效..,
這是我第一個完整的程式,從頭到尾每一行都是自己寫出來的。
(以現在的眼光來說只能說是一個期末 project 規模的小程式,
但對當時的我可是意義非凡)

這個黑白棋讓我印象最深的其實是 debug 的痛苦經驗。

我花了一個禮拜把程式的核心部分完成,
但在吃子的時候卻跑出一個不明的 bug 會打亂整個盤面。

為了找這個 bug,我又花了一個禮拜,每天從早到晚都在想哪裡寫錯了,
後來慢慢 trace 了好久,才發現竟然只是一個變數忘了歸零!!!

這種 bug 很常見,不過只是 programmer 最容易犯的無心之過之一,
但這件事對我的影響非常大,它讓我花了很長時間在想以後要怎麼避免犯同樣的錯。

我後來才知道一個普通的 programmer 和厲害的 programmer 從這裡就會分出高下:
普通 programmer 犯了這種錯會覺得很平常,並提醒自己下次別再這麼笨了,
但實際上不久後一定又會再犯同樣的錯;
厲害的 programmer 會反省自己寫程式的方法,
並改變原有的方法或習慣來避免以後再度產生同樣的 bug。

古老的程式設計教材(尤其是 C 語言),都說要把變數宣告在函式的一開頭,
並且因為變數宣告完還得經過初始化,
所以很多人習慣是在函式開頭宣告並初始化所有變數。

這不是錯的,可是,這其實就是會導致 bug 的元兇。

因為變數在開頭就被初始化,這樣在真正要用到它的時候就能直接拿來用,
但是如果這個變數需要被歸零(也就是重新初始化)並在迴圈中重複利用,
就很容易會忘記要再多做這一步。(在多層迴圈中更容易發生)

我為這個 bug 苦惱了幾天,後來才意識到這是 coding style 的問題,
只要改變宣告變數的習慣,就能避免犯這種錯誤。

如果一開始就在迴圈內宣告並給定變數的初始值,而不是在函式開頭宣告,
就不會有這種 bug 跑出來了。

有了這個經驗後,我歸納出一個原則:
「永遠在變數需要被用到的最內層區塊才宣告並初始化該變數。」

這種原則很重要,我日後一直放在心裡,它也幫助我避免掉未來再犯同樣錯誤的可能。
(事實上,我後來再寫了十年的程式,再也沒有比這更痛苦更長久的 debug 經驗了…)

(待續)##

追求神乎其技的程式設計之道(二)

(本來沒有想寫這麼長的,哪知道一下手後欲罷不能…。
看來這系列文章會變成長連載了。)

資訊奧林匹亞與程式競賽

在升上高中前,我因緣際會透過一個國中的同班同學認識了他的哥哥 YJL。
YJL 比我大三年,我要進中一中時他剛好畢業,很巧的是他很會寫程式,
一直都是中一中的資訊能力競賽代表隊成員。

剛認識他時,他就 demo 給我看他用 QBASIC 自己寫的橫向捲軸射擊遊戲,
當時看得我目瞪口呆,我完全沒法想像 QBASIC竟然能寫出這麼順暢且華麗的遊戲。

這個 demo 如果不說,我一定會以為這是市面上在賣的商業遊戲
(我那時還以為一定要學 C 才能寫出這種遊戲)。

透過 YJL 我也得知原來高中還有資訊能力競賽和奧林匹亞這種比賽,
聽他述說跟全國的高手一起比賽寫程式時,讓我不知不覺也熱血沸騰起來。

我把他高中時留下的各種參考資料全帶回家,
並透過他認識了更多還在中一中的強者學長們,
就這樣在踏進高中校門的同時也決定了我這三年的方向。

這裡我先介紹一下對於高中生最重要的資訊比賽。

高中的學科能力競賽是教育部主辦的比賽,
包括數學、物理、化學、生物、地球科學、資訊,
每間高中通常會先辦個校內初賽來選出代表選手,再由這些選手參加各區域的能力競賽,
最後各區的前N名(每科的人數不同)才能參加全國競賽。

以資訊科來說,我記得是校內取 6 名,中區再取 6 名進全國決賽。

到了全國決賽能拿到前 10 名,還能直接保送進資訊奧林匹亞的培訓營,
不用再另外參加培訓營的入營考。
至於資訊奧林匹亞 (International Olympiad in Informatics, IOI)
則是國際性的資訊比賽,參加的人是從每個國家挑選出來的頂尖高中生,
每年輪流由一個參賽國舉辦,選手要進行兩天每次連續五個小時的頭腦比賽,
其中只有一半的人可以得到獎牌。

這些比賽和一般的程式比賽其實很不一樣。

這種比賽比的是解決問題的能力,不是比賽軟體實做的能力。

題目比較像數學問題,只是除了紙筆外,
還得用某種程式語言實做出能解出正確答案的程式,
也就是說參賽者必須想出問題的解法(演算法),再透過自己擅長的程式語言寫進電腦,
讓電腦執行後輸出問題的答案。

這種解題比賽主要考驗的是運用資料結構和演算法以有效率的方法解決問題,
並寫出正確程式的能力。

大學有個類似的比賽是 ACM ICPC,問題類型和 IOI 很類似,
但比賽的模式和方法則有很大差異,有興趣的人可以自行尋找相關資料。

雖然 IOI 是給高中生參加的比賽,但 IOI 題目的水準其實非常高,
如果你能輕易解出 IOI 的問題,
那… 我跟你打賭去 Google 面試也有 99% 的機率會通過。

順便一提,Google Code Jam 就是一個開放給所有人參加的解題比賽,
題目類型就跟 IOI 和 ACM ICPC 差不多,前一百名就有獎金,
還能免費去 Google Mountain View 總部玩一玩喔。

參加比賽是一個評估自己實力的好方法,沒在比賽會場上較勁過,
真的很難體會解題與寫程式能力的差距可以有多麼巨大。

一個頂尖的程式設計師和一個普通的程式設計師,
其生產力是很輕易的能有十倍甚至百倍以上的差距,
而寫出來的程式碼品質及效率也是同樣會有如此巨大的落差。

透過良性的競爭,高中這段時間也成了我進步最快的一個時期…..

(待續)##

追求神乎其技的程式設計之道(三)

勁敵

熱血的少年漫畫都有一種標準公式,熱血但什麼都不懂的主角,
加上一個天才勁敵的刺激,讓主角能在不斷遭遇的困難和挫折中不斷爬起來進步。

就像火影忍者中的鳴人和左助,或是棋靈王中的進藤光與塔矢亮,
要進步最快的方法就是找到一個遠遠超過自己的勁敵作為目標並且努力打敗他。

我在高一時參加校內的資訊能力競賽初賽,
在都還搞不太清楚要比賽什麼東西時就去參加了。

當時只會用 BASIC,知道要用筆寫程式時還嚇了一跳,
還懷疑閱卷老師難道能在頭腦裡執行程式嗎?
我記得那題目不難,我每題都有寫,但最後只拿了個佳作,離學校的代表隊還遠得很
(話雖如此,我也是唯一有得獎的高一生了)。

過了幾個月,我非常驚訝的發現台北市的資訊能力競賽,
竟然有一個建中的高一生 SBB 拿了一等獎,
更可怕的是他接下來又在全國能力競賽拿到二等獎,
才高一就已經有能選上奧林匹亞國手的氣勢,前途無可限量。

受了他的刺激,我非常拚命學習,先花一個月自己把 C 語言學起來,
接下來就到圖書館借回所有有關資料結構和演算法的書,每天都拚命看。

這是我進步最快的時期,
當時我在家自己跟著已經進入 IOI 培訓營的選手們
一起練習 ACM Online Judge 上的題目。

每天到學校都在看 Introduction to Algorithms,因為沒有電腦,
只好用紙筆練習解 ACM Online Judge 上的問題。

白天在學校想解法,回家就在電腦上把程式寫出來,並 submit 上去看看結果對不對。

透過這種方式練習,可以看到自己解出問題的數量不斷增加,
強烈的成就感能刺激自己不斷練習不斷思考,如此循環之下真的進步得非常快。

很快地,在我升上高二後,我發現我已經寫了三百多題,
進入ACM Online Judge 世界排行榜的前幾名了。

同時我也發現有另一個跟我一樣每天都增加好幾題的人,
沒想到竟然就是跟我同年的建中 SBB。

雖然我每天都能寫兩三題,但 SBB 的解題數仍遠遠在我前面,
逼得我只好印出所有題目,帶去學校不管上課下課都在紙上解題。

就這樣我們的差距慢慢拉進,不知不覺我們也站上排行榜的前兩名。

如果我今天多寫一題,我就能暫時站上第一,但隔天馬上又會被他超越過去,
彷彿他早就已經囤積了數十題起來等著慢慢折磨我一樣。

就在這樣的刺激下,我就像漫畫中的熱血主角一樣快速成長,進入了勁敵所在的境界。

我順利從校內初賽、中區預賽,一路拿第一進到全國決賽。

非常戲劇性的是,在這年全國能力競賽,SBB 拿了滿分得到第一,我錯了半題排名第二,
而全國能力競賽一向是前兩名都為一等獎,也就是說我和 SBB 原本應該都是一等獎,
沒想到評審說我和第一名的滿分有個落差,所以一等獎就改成一名,
而我就變成了二等獎第一…(實在很嘔,但也不能怎樣Q_Q)。

比賽雖然輸了,但我沒有很難過,因為我知道自己還能再進步,還能變得更強,
繼續努力下去我很可能可以選上奧林匹亞的國手。

國手之路

高中各學科的奧林匹亞是每年一度的國際盛事,奧林匹克運動會比的是人類體能的極限,
而各學科的奧林匹亞比的則是運用腦力的極限。

我第一次是從 YJL 那聽到這比賽名字的,但那時覺得非常遙遠,
因為我看到連他這麼厲害的人都選不上國手,可見這不是一般人能輕易踏進去的領域。

改變我想法的是中一中穿堂的一張照片。

中一中有個不錯的傳統,只要代表學校參加比賽或科展獲獎,
學校就會把獲獎學生的照片掛在穿堂的榮譽榜上。

還記得高一時在穿堂閒晃,一個個欣賞歷屆學長們偉大的功績,
突然間發現有個叫 CLK 的學長厲害得不得了,不但在中區能力競賽拿第一,
到了全國也還是第一,而且他還選上了 97 年 IOI 的國手。

後來我才知道他以前也是中一中電研社的社長,而那屆的副社長也非常厲害,
自己寫了一個 microkernel 作業系統代表台灣去美國參加國際科展。

有這些如傳奇一般的學長,給了我很大的激勵作用,
我這時突然覺得自己或許也能像他們一樣有照片被掛在上面的一天。

現在想起來,還真不知道當時自己怎麼能這麼有信心,其實有種不知天高地厚的感覺。

但或許也因為如此,
才沒有被這種「看起來很困難」的目標嚇到而連嘗試的勇氣都不敢拿出來。

很有趣的是,在我剛上高一時,CLK 是中一中第一個也是唯一一個資訊國手。

但就在我高一下的時候,有三個高三的學長竟然同時選上 99 年 IOI 的國手。

因為一年資訊國手名額只有四個,一直以來都是建中學生呼聲最高,
這年我們一口氣拿下三個名額簡直是不可思議的奇蹟。

我也因此而信心大增,
彷彿我每天在他們旁邊練習也能受到逸出的強者氣息感染而變強一樣。

就在我在全國能力競賽拿到第二名後,我就開始為 IOI 培訓營做準備。
IOI 培訓營大約收 30 人,要關在師大內集訓四週,每天都請教授來上課,
每週進行一次模擬考。

第二個禮拜結束會先淘汰一次,留下來 10 個人再繼續廝殺,直到四個禮拜結束。

培訓營過後不是馬上就能知道成績,還要過一段時間才會知道四個國手是誰,
但因為留到第二階段基本上就等於有了保送任何大學資訊系的資格,
所以第二階段的氣氛其實還比較歡樂一些。

在師大集訓的四週讓我認識很多在這個領域頂尖的強者們,
我覺得這更勝於實際上在課堂上學到的東西。

這些強者們如今都還持續在資訊界的各個領域活躍,
常常覺得不管到哪參加活動或研討會都還是可以碰到這些有相同背景的人,
可見這個培訓營真的也訓練出許多資訊界的中堅份子。

在集訓時,大家也不是每天各自悶著頭寫程式。

其實很不好意思說,當時在培訓營進步最多的可能是魔法氣泡對戰的戰術…。

雖然有電腦就會被拿來玩電動,但培訓營的學生還是比較特別。

每年培訓營都會流行一些能用程式寫 AI 來決鬥的遊戲,
像是坦克大戰、俄羅斯方塊等等,我們那年流行五子棋,
大家利用空閒時間寫五子棋的AI,碰在一起時就讓各自的程式互相決鬥分個高下,
玩起來比自己親自下去玩還刺激很多。

經過四個禮拜的集訓,每天討論演算法,每天寫程式,到最後連睡覺都會夢到程式碼。

當時因為才高二,也不會覺得壓力很大一定要留到第二階段甚至要選上國手,
一直抱持平常心反而意外表現得不錯。

結訓過後,我每天沒事就盯著培訓營的網頁看,希望能趕快看到國手名單公佈。

就在名單公佈的那天,我盯著螢幕驚訝的說不出話,我竟然真的選上國手了!

這真的是平常完全不敢想像的事情,
真的沒想到我竟然也有一天能讓自己的照片被掛在中一中的穿堂上….。

(待續)##

追求神乎其技的程式設計之道(四)

程式設計到底是什麼?

2000 年 IOI 在北京舉辦,這年台灣的代表隊成績還算不錯,拿到三銀一銅,
比較可惜的是我第一天表現不理想而落到了銅牌,
雖然不至於兩手空空無顏面對江東父老,
但也知道自己的實力大概就在銀牌和銅牌的邊緣處吧。

IOI 結束後,我又回到了學校,但因為已經取得大學保送資格,
在學校其實也是輕鬆寫意,成天就看自己的書或研究自己有興趣的東西。

在這段時間中,我開始有所警覺,我發現我雖然很會寫程式解題,
但那都是一兩百行以內的小程式,真實世界的程式根本不是這個樣子的!

雖然我能很快看出一個問題該用什麼演算法效率最高,
並且在很短的時間內把自己的想法正確地轉換成程式碼,
但我還是不知道市面上的軟體或遊戲是怎麼做出來的。

我這時才開始接觸 C++和物件導向的概念,
我突然發現要寫個大程式還真不是簡單的事,除了程式語言外,
還有好多瑣碎的函式庫得學。

像是要畫圖就要學 2D 的 SDL 或是 3D 的 OpenGL,
要做 Windows GUI 程式就要學 Windows SDK 或是 MFC,要寫網路連線就得學 socket,
要讓遊戲執行順暢甚至得用組合語言寫某些部分…。

好多好多東西不斷湧出來,學這些東西很有趣,
因為我一邊學就會一邊聯想到學會這個功能後可以用在遊戲裡的什麼地方,
於是整個學習過程就像把我夢想中的拼圖一塊一塊拼上去一樣,非常有成就感。

邊寫這種實用性的程式時,我也發現以往在比賽中累積了很多不好的習慣,
像是濫用全域變數、變數隨便命名、把整個程式塞在 main 裡…。

這些壞習慣在寫小程式看不出來有什麼差別,但隨著程式規模變大,
這就變成了很致命的習慣。

而這種習慣一但養成,之後會變得更難改,所以強烈建議初學程式設計的朋友們,
一開始就不要偷懶,從認真幫變數想個好名字開始吧!

這段期間也讓我想了很多關於程式設計的有趣問題,像是寫程式到底算是科學 + 工程,
還是藝術?
寫程式必須要非常非常精確,任何一個字打錯都可能會讓整個程式跑出完全不同的結果,
這對於天生就容易犯錯的人類來說實在是艱鉅的挑戰。

為了避免錯誤太多,我們只能用一些固定的流程並強迫程式設計師遵守,
讓可能的錯誤減到最低,這就是所謂的軟體工程。

雖然有工程的影子,但寫程式卻是很難精確管理的工作,因為面對同樣的問題,
不同的人絕對會寫出不同的程式,甚至是提出不同的解決方法﹔
有的程式可能要跑三天三夜,有的程式卻能在瞬間得到正確解答﹔
有的程式碼雜亂不堪,也有的程式碼井然有序清晰易讀﹔
有的人要花三天寫 1000行,也有人能在一天寫100行就達到完全相同的效果﹔
這些程式的目的可能完全相同,但呈現方法卻有千萬種,
軟體工程難道可以限制每個程式設計師大腦運作的方式和速度嗎?

從程式碼的觀點來看,不同的人寫出的程式碼也一定不相同。

從程式碼的排版、命名、段落安排、抽象化程度、運作流程
可以看出作者的個性、態度、思考邏輯及深度。

從這個角度來看,寫程式更像是種藝術,
就像是畫筆或樂器一樣是一種表達自我並將思想具體化的工具。

另外我很感興趣的是,人一定要寫程式才能叫電腦做這麼多複雜的工作嗎?
能不能教電腦寫程式,讓人只要告訴電腦要寫什麼樣的程式就好?
或是有沒有更簡單更方便的方法能和電腦溝通,並且保有同樣的控制力?

就在被這個問題困擾著的同時,
我意外從一本書看到基因演算法(Genetic Algorithms)這個名詞。

稍微研究過後讓我大吃一驚,因為我發現基因演算法是一個超級有效率的搜尋演算法,
可以在幾近無限廣大的可能解裡面很快找到接近最佳解的答案。

所以,我很快想到了,如果想要讓電腦寫程式,
其實就是告訴他要寫的程式要達到什麼目的,
並讓他在幾近無限大的可能程式中找出能跑出我們需要答案的那個程式。

這是一種把寫程式視為搜尋的概念,我當時想到這件事非常興奮,
但我並不知道其實早就有人想出同樣的概念(這叫 Genetic Programming),
並已經做了許多研究。

其實有時候無知是件好事,
這樣才會有勇氣在不知道這個問題有多難的情況下去嘗試看看。

如果我當初就知道這問題其實是能拿好幾個博士學位
甚至是得到圖靈獎(Turing Award, 資訊界的諾貝爾獎)的難題,
我可能連繼續嘗試的勇氣都不會有了。

(待續)##

追求神乎其技的程式設計之道(五)

讓電腦自己寫程式的夢

在高三突然對於讓電腦自己寫程式產生興趣後,我每天就都想著這件事,
夢想著未來某一天的電腦能跟我一起寫程式,當我把程式目的說給它聽時,
它就一邊把細部的程式碼產生出來:
我不用想如何命名變數,或是要用什麼演算法,
還是我到底要不要把這個功能變成獨立的class…;
我只要動動嘴巴:
「我想寫一個橫向捲軸的射擊遊戲。
玩家操縱著會變形的飛機,還有四種武器。
第一關要長這樣這樣……」,然後電腦就幫我把遊戲寫出來了!
如果真的可以這樣,那該有多好啊!(如果真的成真,恐怕我也要失業了?)[註一]

這個想法實在太讓人興奮了,雖然說這是一個遙遠的夢想
(其實那時候我並沒有覺得這麼遙遠,只能說自己太不自量力XD),
但也開啟我對於人工智慧、程式語言結構、軟體工程等領域的高度興趣。

寫程式很難?

在高中時代頗不知天高地厚的我,
一邊嘗試著利用基因演算法(Genetic Algorithms)讓電腦自己產生程式碼,
一邊研究各種程式語言的結構和特性。

靠直覺摸索出利用 tree 作為中介來描述一個程式後
(那時沒唸過 compiler,不知道這個其實就是 Abstract Syntax Tree),
我突然就對這個想法的可行性信心大增,所以一時衝動就去報名了國際科展,
打算把這個想法實做出來。

真的做了以後才發現,最難的部份不是產生出程式碼。

如果你把程式語言的基本元素,像是 if、for、變數、運算符號等東西做成一塊塊磁體,
然後拿給一隻猴子玩,那麼牠其實也能拼出一堆程式給你,
問題是:「你要怎麼知道這些程式碼真的達到了你想要的目的?」

悟出這個道理後,
我突然瞭解寫程式最難的部份是在驗證程式碼真的跟你所想表達的事情完全相同。
(所以說我對於各家軟體公司的 QA 地位都低於 RD 其實感到很不平)

基本上,我們只能設計大量的可能輸入值丟進程式裡,
並比對程式跑出來的結果和我們想要的輸出相不相同。

即使在這種情況下,
我們也只能說這個程式在測試過的這些輸入值上所產生的結果是正確的。

也就是說,除非我們測試過所有可能的輸入(這意味著無限多種可能),
不然永遠沒辦法知道某個程式是對還是錯。

除此之外,即使只測試一個輸入值,也還有個很嚴重的問題:
「我們怎麼知道這個程式要跑多久?」
換句話說,當你程式跑下去,你怎麼知道他是掉入一個無窮迴圈,
還是其實正在拚命計算當中?

我在參加國際科展時,認識了歐陽明教授,
他告訴我這個問題叫做 Halting problem,
Alan Turing 在 70 年前就證明了這是一個無解的問題。

知道這件事後,才發現自己所知實在太少,對於資訊科學的基本知識實在非常不足,
但這次經驗其實也給了我一個明確的方向,讓我把書中的理論和實際的目標連結在一起。

見樹又見林的學習之道

提到書本中的理論,有很多人問過我要怎麼學習寫程式或資訊相關的知識,
我順便在這邊分享些心得給大家參考。

常看到許多人抱怨大學裡學的東西都是理論,
畢業後找工作時才發現什麼都不會都得重學;
當然企業也會抱怨,大學應該多教一些實務課程,不然出社會後還得重新訓練。

說來說去,一致的口徑指向理論和實務是打死也扯不上關係的樣子,
尤其念資工的人更常這麼說:
「學校為什麼不教 C#?為什麼不教我做網頁?好歹也要教個 HTML 嘛!」

我覺得學習任何事物,一定要有充分的興趣才會有效率,
在不知道所學為何的情況下被逼著學習是非常痛苦且沒有效率的。

最近看了一本書:

沒有資優班,珍視每個孩子的芬蘭教育,
書中提到芬蘭教育成功的秘密在於「見樹又見林」,
這句話也是我對於如何學習最想分享的秘訣。

台灣的教育方法是「先見樹,再見林」,也就是先教你細部的方法和技術,
等你都學會之後(或是硬背起來之後),出社會後就會知道為什麼要學這些東西。

(很多人小時候都聽過「等你長大就知道唸書有多重要」吧。
可是現在比較多人畢業後反而說「我不知道之前念那麼多書有什麼用」)

在這種體制之下,許多人在還沒見到整片森林的美景前就被一棵棵大樹搞得暈頭轉向,
痛苦萬分,在不知道「學了這個可以做什麼」的情況下,
不管學什麼都會覺得沒有意義沒有動力。

而「見樹又見林」的學習方式,是先找到能引起自己興趣的目標,
讓自己有個理由去認真學習,之後再往細部的技術和理論去學習。

我從小就很想自己寫遊戲,為了達成這個目標,我就四處尋找相關的資料,
慢慢的我就知道自己應該要學好一個快速的低階語言(像是C++),
如果要寫繪圖引擎可能還得學一點圖學的理論和技術,
如果要做網路連線還得學網路相關的技術…。

這裡有個重點是,不要看過森林後就忘記它,而又迷失在幾棵樹幹上,
要讓自己一直重複見樹又見林的過程。

這跟如何有效開發軟體的秘訣是一樣的。

一個有效率的軟體開發方式是用 iterative process,
把包含設計、實做、測試的 iteration 時間縮短,
但要一直不斷重複這個 iteration 無數次來改進現有的成果。

同理,在已經有目標的狀況下學習時,每當學會一些新東西,
就要馬上試著把它實現出來,即使是只有幾行程式碼的 prototype 也沒關係。

只要一直不斷的學,這個 prototype 就會一直被改進,
一直加進最新學到的知識和技術而更接近最終的目標。

同時動腦也動手(註二),
用這種角度來學習就能充分瞭解自己學會的東西可以用在什麼地方,
馬上得到回饋的成就感還會刺激自己繼續向前進,形成一個非常有效率的學習循環。

用這種角度看學校教的東西,就能知道書本上的理論可以用在哪,
並且又欠缺哪些實務知識讓自己無法做出想要的東西。

這方法理論上可以擴展到任何事物的學習,
重點在找到有興趣的目標和書本裡知識的連結,我覺得這是老師應該要出力的地方,
無奈的是台灣的教育體制把中小學老師們變成出考題和改考卷的機器人….。

註一:
其實,現在真的有這樣的研究,
而且驚人的是目前已經有了非常接近我想像中未來的雛型。

最讓我興奮的是 MIT Media Lab 的 Hugo Liu 和 Henry Lieberman 做的 Metafor:
只要對電腦用英文描述你要的程式,電腦就自動把 Python code 生出來給你….。

註二:

話說, MIT 的校徽上就是一個拿著鎚子的工匠和一個拿著書的學者,
所代表的意義就是 「Mind and Hand」,也就是期望每個學生都能手腦並用,
除了做夢外也要實做出來才算數啊。

##

追求神乎其技的程式設計之道(六)

最近新玩具太多,差點讓我的 blog 被 N82 系列文章淹沒了。

幸虧即時看到 qing 兄兩篇不錯的文章 程式設計的兩個觀點 (1/2)和
程式設計的兩個觀點 (2/2),讓我決定還是來早點把這個系列寫完,不然就快變富奸了。

qing 兄的兩篇文章指出程式員的兩種型態,
一是重視演算法、資料結構、執行效率的「效率魔人」,
二是重視程式架構、擴充性、彈性、可理解性的「架構狂」。

這兩種人其實都很好,要完成一個偉大的軟體,團隊中兩種人一定都要有。

比較糟糕的是,有很多「第三型態人」,他們的信念只有一條:「程式只要會動就好」。

第三型態人不在乎效率,也不管架構漂不漂亮,上面要求他做什麼,
他就想辦法東湊西湊,從 Google 找程式剪貼,從 MSDN 抓範例來用,
反正只要能隨便測過一個 case 就能交差了。

其實第三型態人也不一定是不懂演算法、不懂 design patterns,
他們常常只是因為火燒屁股了,就不管三七二十一先弄出可以動的程式再說,
效率或架構等到下一階段再來改就好…。

問題是,下一階段又有新的功能要做,
這些人再度面臨抉擇時還是會決定先讓程式「會動再說」。

我看過很多各式各樣的程式員,只要碰到這種人,同樣的過程是履試不爽不斷出現。

所以要成為一個優秀的程式設計師的關鍵是什麼?
關鍵不在於 coding 速度有多快、懂多少演算法,或是背了多少 patterns,
最重要的是「熱情」!

偉大的程式設計師都非常喜歡寫程式,寫程式的過程是一種絕妙的享受,
他們執著的地方或許不同,可能是程式的效率,也可能是開發的效率,
甚至是架構的彈性或是程式碼的精簡美觀程度,
但他們都非常想要並堅持自己應該寫出「好程式」。

熱情能驅動他們把軟體的某一個面向雕琢到極致,這需要超乎常人的毅力和堅持,
以及絕不向壓力妥協的精神。

只要具備這種熱情,不管你在乎的是什麼,都可以成為一名偉大的程式設計大師。

P.S. 雖然這篇文章講的東西很八股,但我發現這真的非常重要,
看一個人的熱情就能知道他做出來的成品是什麼樣子。

如果是我來面試,我一定會在面試時觀察這人有沒有喜歡寫程式的熱情,
沒有熱情的人容易向現實壓力低頭,也不會要有不斷精益求精的信念,
在如此競爭的時代是很難生存的。

P.S.2 要追求神乎其技前,當然要先知道自己的目標是什麼樣子,
所以我本來想在這篇寫一個優秀的程式設計師應該要有的特質和能力,
但才寫了第一項就落落長。

所以還是等待下一篇再繼續這個主題好了。(路人:「這不就是擺明要當富奸嗎!」)

(待續)##

相關文章

  1. 壞擋。來不及
  2. 角板山。極壽司
  3. 畢業。照片。2008
  4. 系上。碳封存。Nature
  5. 工作