Rails遺留程式中最常犯的錯誤(上)

algo31031發表於2014-07-23

近來我一直在對幾個遺留專案作維護。

眾所周知,處理遺留專案多數時間都感覺糟透了,因為那些程式碼通常都醜陋不堪而且晦澀難懂。

我決定做一個列表,記錄下那些公認的不良實踐,或者是我認為不太好的實踐,以及如何改良程式碼來避免這些不良實踐。

問題一覽

  • 在模型層以外使用查詢方法
  • 在檢視層使用業務邏輯
  • 使用無意義的方法名和變數名
  • 條件判斷時使用unless或者否定的表示式
  • 沒有遵循“命令,不要去詢問”原則
  • 使用複雜的條件
  • 在模型的例項方法裡,本來不需要的時候使用了“self.”
  • 使用條件表示式並且返回了條件
  • 在檢視層使用行內樣式
  • 在檢視層使用JavaScript
  • 呼叫方法時把另一個方法的呼叫作為引數
  • 沒有使用類來隔離Rake Tasks
  • 沒有遵循Sandi Metz的規則

在模型層以外使用查詢方法

不好的

這段程式碼不可重用而且難於測試。如果你在別的地方也想查詢全部使用者並進行排序,就會出現冗餘程式碼。

好的

比起在控制器裡使用查詢方法,我們的做法是在模型層中使用scope把它們獨立出來,就如下例所示。這樣做既可以使程式碼能夠複用,又便於程式碼閱讀和測試。

每當你想用where、order、joins、includes、group、having或者其他查詢方法時,記得要把它們放在模型層裡。

在檢視層使用業務邏輯

不好的

初看之下這小段程式碼似乎沒什麼問題,但是它會讓HTML變得有點難以閱讀,而且可以肯定的說一旦你在檢視層新增了邏輯程式碼,那麼日後你定會新增更多的邏輯到檢視。這段程式碼還有一個問題,裡面的邏輯無法複用,而且不能單獨測試。

好的

使用Rails的helper方法把業務邏輯隔離出來

使用無意義的方法名和變數名

不好的

這類遺留程式碼最主要的問題在於:你需要花費大把時間來搞清楚這些程式碼的用途。r_topics這個方法是做什麼的,rt這個變數又是什麼意思。其他的一些變數,比如在程式碼塊裡用到的那個,變數名的含義很模糊,這樣也使得它們的用途初看起來很難理解。

好的

對方法和變數命名時選那些能表達出其含義的名字。這樣更便於其他開發者理解你的程式碼。

這樣改進的好處在於:

  • 第一次看到方法名時就會對方法返回值有個概念。一個與給定問題集合相關聯的主題的集合。
  • 現在你能夠了解related_topics表示一個陣列,它裡面存放了一個與給定問題集合相關聯的主題的集合。之前打程式碼裡rt表示什麼非常含糊。
  • 使用topic代替之前的t,並用question替換掉q,使得你的程式碼更便於閱讀,因為你不再需要腦補這些變數的用途。現在這些程式碼已然能夠自解釋一切。

條件判斷時使用unless或者否定的表示式

不好的

這段程式碼也許並不難理解,但是使用unless或者否定的條件表示式會稍微增加程式碼的發覆雜度,因為你必須對它要判斷的條件自行腦補。

好的

改用if或者肯定的條件表示式之後,上述程式碼就會好懂得多。

不覺得這樣寫程式碼更易讀了嗎?我更傾向於使用if而非unless,用肯定的表示式多過肯定的表示式。實在不行就新增個反意的方法,比如我們在User模型里加的那個。

沒有遵循“命令,不要去詢問”原則

不好的

這裡的問題是在不恰當的地方出現了控制邏輯。你先判斷了使用者是否是不可用,如果的確不可用,就啟用這個使用者。

好的

比較好的改辦法是把控制邏輯放到enable!方法裡。

現在控制器不用關心user需要滿足何種條件才會被啟用。相關的判斷由User模型和enable!方法來處理。

使用複雜的條件

不好的

條件表示式弄的太過複雜了,實際上這裡只想知道一件事:使用者可以刪掉post嗎?

好的

從上面的程式碼我們可以瞭解到,一個使用者需要是post的所有者或者這個使用者是管理員,並且post本身也是可用的,才可以刪除這個post。最好的做法就是,把這些條件抽取成一個日後可以複用的方法。

每當條件表示式裡出現了&&或者||,就應該把它們提取為方法,以備以後複用。

相關文章