Wednesday, March 07, 2012

程式設計師的自我修練

寫程式很簡單。

但寫好程式就沒那麼簡單了。

我覺得要學會寫好程式是一條漫長、需要耐心的路。
還記得我大二的時候去的那家遊戲公司,
裡頭有位寫3D引擎寫了好多年的前輩,我們都叫他葉老大。
他沒有顯赫的學歷,但就是一個很愛寫程式、玩遊戲、跟cosplay的傢伙。

他寫程式不算快,但是非常細心,而且絕大多數的程式碼都十分整齊,
歐對了,整齊不是說等號有對齊、變數有對齊就叫整齊,
而是整個程式的架構非常的乾淨、對稱、一致,
如果用我現在的角度來看,我會說這真的是充滿了美感,
但是小大二那裡懂得什麼叫美什麼叫不美,只知道這是一套完全沒有說明文件的3D引擎,只好硬看硬學。
但沒過多久,很快的,我就上手了。他的介面真的很簡單而且好用,
我覺得拿現在OGRE3D來比都不會遜色到那裡去。
當然很可惜的這年頭做3D引擎已經不是一般遊戲公司會嘗試的事情了,現成的東西太多了...

在那段時間,與其說我學會用這套3D引擎,我覺得我學的更多的是設計。
我了解到一個引擎在設計上的哲學,程式介面定義上怎樣叫做乾淨,要注意對稱性跟一致性等等。
這對我後來的工作,不管是寫程式技巧的提升,還是架構設計,都有很大的影響。

我前面提到寫程式是門哲學,或者我會稱他是門藝術;
當然有人說他是工程,是要用工程手法去規範、去設計;
但我認為其實任何一門工程,學到最後,其實不是什麼東西都有答案的,更多的是經驗法則、慣例。
而這些經驗法則或慣例,也都是前輩們嘔心瀝血、在錯誤中學習後才得來的。

所以其實很多時候老工程師有很多有的沒的堅持。不要小看這些堅持,大部份一定是有道理的。
(當然有些不學新東西的老工程師除外)

所以回到標題,程式設計師要怎麼自我修練?

第一,我覺得最重要的是心態。
盡量多從別人的程式碼去學習,原則上沒有所謂"最好"的寫法,但是會有一些common practice。
不要第一時間就抗拒這些東西,而自己閉門造車,很難進步。
另外,每個引擎、每個框架、每套語言,都有他的邏輯跟哲理(就像中文跟英文跟西班牙文)。
寫什麼語言就要用那個語言的邏輯來思考,用他的哲理來解決問題。

第二,多寫多讀。
每一項工藝都是需要花時間練習的。這種東西沒什麼捷徑,只有多寫多錯多學習。
寫多了、看多了自然就會知道什麼叫好、什麼叫不好。

第三,寫程式速度的提升
寫程式的速度沒什麼好說的,就是打字要夠快、編輯器要好用。
什麼是好用的編輯器,這當然依語言而有差別啦,
當然有人會推用vim or emacs一招打天下,
我其實也不反對,畢竟真的蠻多優點的又是到處都可以跑(我最近也在學emacs...XD)
但我現在寫C++還是用Eclipse為主啦,畢竟Eclipse CDT真的做的很好,
比vim or emacs上的semantic completion好太多了,
加上refactor的功能也很好用,你也可以在eclipse掛vim or emacs的套件。
(雖然很吃記憶體,但反正記憶體很便宜...)

所以不管你是用什麼,如果你用了好一段時間,
但還是比不上跟你打字速度差不多的人用其它編輯器的速度,
那麼問題要嘛是你不夠認真學這個編輯器,要嘛就是這個編輯器沒辦法滿足你的需求。

第四,思考的速度
思考的速度我覺得是最難提升的。但跳躍性思考對於寫程式的人卻是最重要的技能之一。
這個需要日積月累、在平日就要練習的;
我覺得最快的方式是跟一群聰明的人在一起工作、一起討論。
當大家思考速度都很快的時候,你自然也會變快一些。

除了思考的速度之外,思考的密度也很重要;也就是說,除了求快之外,也要求面面俱到。
我覺得這個就跟右腦的跳躍性的思考模式有很大的關係。

這個練習的方式就是當大家在一起brainstorming的時候,某人提出你沒想到的點,
你不只能是說:「啊對」,你應該要想的是:「我怎麼沒想到」
要告訴自己的大腦說:「我應該要先想到這一點」才對。
久了他自然就會變聰明了。
相信我,這不是唬爛的,右腦是平行的,你要提升他的平行度,讓右腦主動"告訴"你問題在那裡。

這種能力也是除錯時常用到。像我大部份的時候還沒看GDB就知道問題在那,
其實很多時候都是被主動"告知"的。

第五,架構的哲學
其實你看很多design pattern,我覺得那只是一種程式設計師溝通的語言。
我自己覺得很多架構的設計,都是跟大自然或者這個社會同構的。
責任歸屬、權力分配,這些都是架構設計第一個要思考的問題,其次就是命名(古人說的嘛,名正才言順),
最後才是實作細節;但這不代表實作細節不重要,實作細節在架構設計的初期其實也是非常重要,
你可以思考的愈深入,這個架構愈不容易因為實作的變化而需修正。
所以你不能只看到表面的問題,只考慮表面的合諧。

第六,深入底層
程式設計師是個解決問題的人。
你愈了解底層的實作,就愈能用有效率的方法解決上層的問題。
所以作業系統、程式語言、組語、計算機架構這些科目我覺得太重要了。
當然這些課其實通常在學校有很大一部份是過時的,但他的基礎概念不能沒有;
其實最近真的去實作一個程式語言之才發現自己以前對程式語言或編譯器設計的無知,
才真的了解很多語言的設計的道理所在。

另外學習系統管理我覺得也是一個好的程式設計師可以挑戰的技能。
大多數人不喜歡學系統管理,不喜歡打指令,不喜歡處理這麼煩雜又不一致一東西,
但是我認為這就是一種訓練,訓練你如何在一片混亂中,找到規則。
很多的開放原始碼專案裡,連個文件都沒有,
如果你能快速的在一堆程式碼中找到他的邏輯、了解他的哲理,
那麼我想你的能力應該可以超越85%的程式設計師了。

所以我也很推薦大家去讀沒有文件的程式碼,練習trace code的能力。
像是如果是寫C++的話,我推薦大家去trace一些boost的原始碼;
像是mpl、fusion、tuple、function/bind、graph等等,其實只要花點耐心,我覺得都可以看懂的。
而且在你trace code的過程中,會學到很多別人的技巧。簡而言之,框架的底層都是很精彩的。
對了,除了學會技巧之外,最好同時也要學會他們的哲學;
千萬不要只會看sample code,學會怎麼用就了事了。

第七,相信自己、相信直覺
很多時候你要相信自己現在寫這段code是對的,
就像要相信自己現在下的這個command會有你預期的結果,
這樣你才能在解決現在的問題時,先去思考接下來的問題。

舉例來說,所以如果一個系統管理員打一個bash指令,
要去看他的結果你才能決定你的下一步要做什麼,那就太慢了;
應該要跟CPU一樣,要有speculative execution,
在打這個指令的同時你已經想好接下來要做那些事情了。

寫程式也一樣,你在寫這一行的時候,你打字速度如果跟不上你的思考速度,
你就要練習用50%的腦去完成現在要做的事,剩下50%去思考接下來要做的事。
(就像你邊開車也是可以同時跟旁邊的正妹聊天啊XD)

第八,程式碼的掌握度
很多人寫程式的習慣是每次寫一點,然後慢慢的測試再測試,最後達到原本的目標;
這也就是很多人說的小步開發。

我的習慣比較不一樣,我不喜歡每次寫一點寫一點,
我喜歡一次把所有東西寫完,然後跑幾次GDB除錯。
這可以稱的上是大步開發。

這點爭議性比較大,有人認為這樣寫有可能漏東漏西,少考慮一些條件等等的,

但我認為這個跟你一次寫多少無關,而是跟你對這份程式碼的掌握度有關;
簡單說,如果你對你的程式碼掌握度夠高,就跟成年人走路一樣,
那這小步開發裡的每一步難道還要學小baby似的又走又爬嗎?

而當你有能力勇敢的跨大步的時候,你邊寫也要邊在腦袋裡跑這段程式碼,
考慮各種可能的情況(同樣的,要讓右腦告訴你),
最後跑GDB測試就好了。

大步開發這只適用在對程式碼的掌握度夠高的時候。
如果你第一次用某個複雜的library像是boost graph,
或是寫了一些複雜的template metaprogramming的程式碼,
或是做嵌入式系統,或是寫些比較小但很複雜的程式,那還是小步小步的開發比較適合。

以上是我這麼多年來寫程式的心得。
希望大家還能多自我修練,互相學習,寫出好的程式。
這樣才不會白白浪費你程式設計師的人生啊~

2 Comments:

東之月 said...

請讓在下稱呼閣下為設計師‧‧‧( _ _ )

好文,轉貼去。

I-Cheng said...

好棒的文章~~ 借轉fb