呃,好像還欠一篇文章,那就來補唄。
會寫這篇文章的原因主要是下面兩則朋友的噗文,因為噗浪還是不太適合長篇大論,所以我就把回應移到部落格來了。
-
好寫[指針對PG在開發而言]與介面的友善度[指針對user而言],該如何取捨?但是似乎這兩者不該一起評論,因為永遠是友善度優先才能考量好不好寫
-
到底應該邊coding邊refactor?還是整個開發完再做?
第一個問題我記得我回答的是說:『可以先亂抄,然後再來 Refactor……」
然後接下來就有人冒出來說什麼 JSP 通常不能 Refactor,能 Refactor 的只有 Java 的部份等等。
首先,先說說什麼叫 Refactor 吧,講 Refactor 的聖經裡是這麼定義 Refactoring 和 Refactor 這兩個詞的:
- Refactoring (noun)
- A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.
- Refactor(verb)
- To restructure software by applying a series of refactorings without changing its observable behavior.
也就是說,Refactor 的重點是在不改變程式外在行為的情況下改進程式內部的架構,和你用什麼程式語言或是不是 JSP 根本沒關係。更極端一點的說,將一個使用表格排版的網頁改成用 CSS 排版,也可以視為是 Refactor 的一種。
所以我回答第一個問題是認真的:先隨便抄,弄出一個能動的東西再來修改,再來 Refactor。
我還記得我們敬愛的李家同杯杯有句名言:『寫程式一點也不難的,每一個程式都有一個流程圖,我們要寫一個程式,最重要的是設計這個流程圖,一旦流程圖設計出來,程式也就很快可以寫出來了。』
這句話對剛寫程式的人來說或許為真,但等你開始做超出作業以外的 Project 的時候,就會發現這句話根本是個屁--你根本畫不出所謂的流程圖,而大學的軟工課堂上教你的什麼 Waterfall Model 根本行不通,你就是完全不知道要怎麼從無到有把程式生出來,就算你是個資深工程師!
到最後的結論就是:什麼程式架構,什麼流程圖都是個屁,管他是從哪個範例裡抄來的,只有會動能動的程式才是王道!
再來,第二個問題,到底該一邊 code 一邊做 refactor,還是等整個開發完再來 Refactor?
如果你維護過別人的程式,就知道『只有會動能動才是王道的程式』很快就會從王道變成一小坨屎,然後再變成一大坨屎,最後就會變成一大坨乾掉的屎,而你是絕對不會想要加水把他重新整型成一坨比較漂亮的屎的。
是的,就算是自己寫的程式,到最後還是會變成一坨乾掉的屎。
我一直相信 Extreme Programming、Agile software development、Test-driven development、Behavior Driven Development 不會是無緣無故被提出來的,而他們會在現在的軟體開發方法論中佔有一席之地,甚至被許多人所採用,一定是因為他們確實能夠解決一些問題。
而這些方法論中其實都有一個共同的概念--每一個循完先完成一個『只有會動能動才是王道』的小功能,並持續在開發的過程中進行某些 Refactor,讓程式碼從『只有會動能動就是王道』轉移成『可被維護』的程式碼。
而前一陣子發佈的 SPlurk 是我第一次從道到尾使用 BDD 完成一個專案的開發,其實我不懂 BDD,我只是依照就我所了解的 BDD 精神,遵守以下幾點來開發而已:
- 一個功能必定伴隨著一個測試
- 一個功能實作完後,必定跑一次測試,確認測試通過,才 commit 到版本控制系統中
- 等到覺得自己的程式碼太醜的時候,就做 Refactor
- 做完 Refactor 一樣再跑一次測試
在這裡,我並沒有很嚴格的遵守 TDD / BDD 裡要先寫測試案例的要求,我通常是一邊實作,一邊寫測試案例。覺得測試案例不夠直覺時,又回頭修正實作,等到實作與測試案例都沒問題也測試過了,這才 commit。
我一直遵守這樣的遊戲規則,然後等到某天要實作另一個新功能時,發現原來的程式碼裡重覆的部份太多,就先暫停加新功能的事,先 Refactor 將重覆的程式碼抽成獨立函數,並確認修改過後的程式碼可以通過測試。
之後繼續加新功能,等到某天發現怎麼一個檔案長大到快超過五百行了,又再做一次 Refactor,把這個檔案切成其他小檔案,然後再跑一次測試,確定我的修改沒問題。
老實說,我很訝異用這個方式寫出來的程式碼,其架構和漂亮程度是我寫程式到現在最滿意的幾次之一。
當然,很多時候有些測試是沒辦法自動化的(舉例來說,SPlurk 我最後加進去的 PlurkBot 你要怎麼測?!說實話,我想不出來……),但我覺得這並不是主要的問題,更根本的重點是--你要承認,會動能動的程式才是王道,但這個王道如果不去理他,他很快就會變成一坨屎,你得在他還沒成為屎之前讓他成為失去成為一坨屎的潛力。
而 TDD/BDD 的好處,其一是他可以幫你確認你程式的外部使用介面,其二是他可以給你一個簡易的驗證程式是不是有問題的方法(他不能保證你的程式沒有錯,但至少可以確定他在某些情況下是對的)。
就算你的程式沒辦法寫自動化的測試案例,但我還是覺得如果能夠用下面的方式來開發系統,日子還是會好過很多:
- 一次只新增一個功能
- 每次 commit 前都先經過測試
- 發現程式碼快變成屎之前就先停下來實作的部份,Refactor 先,這時你花費的時間通常不會太多。
- Refactor 完也一樣先測試先,至少確定他可以動吧。
反正現在都有版本控制系統,了不起就是倒回舊版本而已,實在沒理由不在程式碼還沒變成屎之前就先清理掉他。
回響