24 October 2009

很久沒寫 blog 了,沒為什麼,就是懶而已... 另一方面則是沒什麼感想可以寫。過去一兩年來,寫的程式比較雜,也多學了 haskell, python, actionscript 和 scala 幾個語言。haskell, scala 和 python 我都是寫來玩的,actionscript 則是工作上需要寫遊戲,硬著頭皮去學。actionscript 到了 3.0 之後,越來越像 java,所以一開始寫起來沒什麼障礙,總之當做 java 用,大概都會對。

後來學了 scala 之後,想寫個 toy project 實際運用 FP (functional programming),看看能體會到什麼。不過實在沒什麼題目可以玩... 就開始打起 actionscript 的主意。actionscript 其實也算是部份的融合 OOP 和 FP 的概念,所以像是 filter/map/foreach/function as object... 這些基礎設施都有具備。而近期又有一個單人開發遊戲的機會,對我來說這是個很好的練功實證的機會 -- 能在真正的產品開發上使用 FP 的方式進行,沒有比這個方法更能學到真正的內容了。(作作 tutorial、寫個 toy project 永遠只是隔靴騷癢、半瓶水,不會學到什麼精神...)

Well, 目前該專案已經尾聲。寫了這一兩個月,我跟所有品嘗過 FP 的 imperative programmer 一樣,腦袋瓜硬生生的轉了180度。現在看到 collection 的想法完全不同了 -- Think transformation instead of iteration。第一個最大的差別是想的時間比較久,你必須思考 collection 在各個 step 的轉變,這有點像是寫 SQL 時的那種思考方式 (寫 SQL 也要花很多時間...)。第二個差別在於當然是 FP 寫出來的程式少了很多無謂的變數,關於這點其他 blog 和書有更好的著墨,所以這裡就不提了。第三個差別是 bug 很明顯的變少,使用 FP 方式處理 collection 的相關程式,如果出了錯,那多半是對需求理解有誤,而不是程式不按照心理所想的邏輯運作 (就是心理想的是一回事,寫出來的,因為少加了個 1,或是在錯的地方 break,造成不預期的錯誤)

受限於 actionscript 提供的 FP 功能有限,有一部份處理 collection 仍然用 iteration 的方式來寫。這剛好提供了一個絕佳比較的機會 -- 我發現 FP 的方式想的比較久,但完成的比較快。imperative 則是寫的很快,但是 debug 卻很久。這樣看來兩者在開發時間上都算平手啊!想加快開發時間,不是說選了其中一個方法就可以了。你選了 FP,你就得花時間熟練 FP 的思考方式,以縮短思考時間;選了 imperative,你就得熟悉 iteration 法常犯的錯誤,然後練到 "本能性的避開"、進而減少出錯的機會。而就維護性來說,FP 的方式對已經懂得人很好維護的,然而罩門是懂 FP 的人不多... 而 imperative 雖然大家都會寫,但是看到 i,j,k... foo.length-1, break, continue到處亂交錯,這樣的程式也要想老半天才知道要在哪裡下刀啊。所以維護性也算平手吧。

然後... 重要的一點是, FP 沒辦法讓你不用再寫 unit test 。該寫的 test 還是跑不掉的。FP 雖然減少了許多想法轉換到程式的錯誤,但是沒辦法避免想法錯誤。hmm... 講的太玄嗎?對於沒有 FP 經驗的人,大概不能體會我上面說的,但你可以用 SQL 去理解 -- 試想,有人可以 SQL 一次就寫對嗎?

那麼,有什麼結論呢?FP 比 imperative 好? imperative 比 FP 好?我的看法是看 context 吧。你們的團隊是否有多數的人願意學習 FP 呢 (不用會,只要有動機肯學)。如果答案是肯定的,那麼團隊可以開始 shift 到 FP 的寫作方式。一開始開發肯定會變慢,但是到後期因為 debug 時間減少,反而會後來居上,這是值得的。但如果你的團隊沒幾隻貓想學 FP,那麼你就打消念頭吧,FP 留給自己增加功力就好,因為你寫的 FP 再好也沒人會維護,到時反而變負擔。

技術是給人用的,好壞還是看使用的人吧。

ps. 對於 FP ,我目前只有嘗試基本的 collection 操作,FP 當然還包括更多其他東西 (如 tail recursion),所以這篇的心得不適合當做一個通盤的參考依據。(沒人會認真看待吧... 沒人..)


回響

可以用 Tag <I>、<B>,程式碼請用 <PRE>