重構,讓人快樂讓人苦

來源: Veda原型  發布時間: 2012-03-22 21:38  閱讀: 2839 次  推薦: 2   原文鏈接   [收藏]  

  重構,是編寫代碼必須要面對的一項操作,同時也應該是程序員樂于實踐的一項內容。不論是邏輯實現還是設計過程,乃至整個分層結構,我們都可能面臨并且實施重構。這篇文章不會告訴您什么是重構,如何去優美的重構等等的理論,只想和大家分享一些感受,并且探討一些問題。最近的兩周,我一直對我們團隊的一個子業務框架做重構的工作,很多地方讓我感到很痛苦,于是便有了這篇文章。

  牽一發而動全身的根源在哪里

  當我打開解決方案,查看代碼的時候,我們會發現很多問題,比如冗余的代碼,性能低下的邏輯實現等等,但是當我著手去改造的時候,潛意識告訴我整個似乎不能動,牽扯的面太廣了。更改一個小地方,上下一串都要做相應的調整,這當然不是我想要看到的。大范圍的調整會直接影響系統的穩定性,帶來潛在的危險,同時會增加測試團隊的負擔;在版本控制方面會造成線上和線下版本在同一內容的巨大差異,版本更新的時候拿什么來保證一套幾乎全新的代碼替換線上系統是正確的選擇呢?因為很多問題只有在最真實的環境才能被暴露出來。

  這樣的修改,修改成本無疑是巨大的,因為我們期望修改的只是那一小塊代碼而已。大范圍的代碼調整,同時也伴隨著單元測試代碼的調整。測試團隊如果因此來重新走測試用例,那么付出的辛苦可想而知。

  我要做的是重構而不是重寫,造成這種現象的原因在哪里呢?

  整個解決方案具有相對完整的分層結構,DAO層、實體層、業務邏輯層。實體層也對數據實體和業務實體做了分別定義。但是進行業務實現的時候我們并沒有進行有效的隔離和代碼的職責劃分。

  很多代碼在處理業務邏輯的時候直接調用DAO,然后使用返回的數據組織業務實體。當我們的業務實體需要按照領域劃分為兩個或者更多的層次的時候,結果會變得更為糟糕,因為我們需要以底層的業務實體為輸入從而輸出上層的實體。當你以一個順序工作流的方式完成一整套操作的時候,也許感覺很有成就感,整個過程天衣無縫,完美無缺。但是當我們嘗試改變其中的某些內容的話,噩夢就開始了,實體的改變勢必會引起邏輯的改變,但是這種改變是有連鎖反應的。

  業務實現的過程很多時候就是不同層次間的實體的轉化過程,那么實現過程中單單考慮解除依賴不能收到很好的效果,從業務邏輯的職責出發,劃分出清晰的業務層次,再以實體轉變的結合點來考慮分解才能達到良好的效果。

  獨立的領域層尤為重要

  各種經典的MVC架構的實現,常常讓人產生誤解,認為那樣做就已經完美了。事實上,一個業務的框架的重點不是增、刪、改、查,我更傾向于將DAO從業務框架中分離出去(最后我也是這樣做的),整個系統應該提供統一的DAO服務,子業務框架要專注于業務的實現。

  當我們嘗試將一整套業務實體獨立出來的時候,我們認為已經做了很好的業務理解,但是這是只見樹木不見森林的想法。在某些系統中,領域的實現只占代碼總量的很少一個比例,但是其重要性往往卻是相反的一個比例。當我們選擇將領域代碼和其他代碼混合在一起的時候,意味著我們的分層結構也隨之混亂。

  "用標準的架構模式來完成與上層的松散關聯。將所有與領域相關的代碼都集中在一層,并且將它與用戶界面層、應用層和基礎結構層的代碼分離。領域對象可以將重點放在表達領域模型上,不需要關系它們自己的顯示、存儲和管理應用任務等。這樣使模型發展得足夠豐富和清晰"。在清楚了整個領域模型之后,再考慮選擇合適的模式來解決分層問題,我覺得是合理的做法。

  在對業務和領域沒有充分理解的時候不要下手

  在重構過程中,發現很多業務實體的定義不著邊際,很多概念只是對數據實體的拓展,結果出來的東西和數據實體的邏輯關系截然不同。對數據調取的邏輯沒有充分理解,那么組織業務實體的時候很容易出現不恰當的數據訪問方式,比如循環訪問數據庫。

  如果整個領域模型的建立和劃分都是錯誤的話,我們仍然能實現所需要的功能,但是如果對這樣的代碼進行重構無疑等于推倒重來。

  現在看來,當我們為了實現功能而急匆匆的不擇手段的時候,為將來的維護和升級埋下了隱患。當我們想要將公用的數據調取和業務邏輯實現從各個子項目中抽象出來變成基類、接口、Helper或者Service的時候,我發現不同子項目的開發者對業務和領域的理解有著很大的差異,因而在實現方式和實體定義上都有很大的不同。這個時候我們又注意到組織實體的邏輯并沒有單獨的分離出來,抽取的工作遇到了難題。也許我們可以分離出代理,然后使用Adapter來適應原有的實體組織邏輯,又或許我們應該廢除不合理的實體定義,也意味著廢除了相應的實現邏輯。

  如果我選擇將不合理的實體替換為正確的實體定義將面臨巨大的挑戰,也許從數據調取到最終的邏輯都要調整。當然全面調整的原因是我們沒有實現很好的隔離。

  迷茫,面對一個幾千行的Method

  這是我無法容忍的情況,整個子業務的實現幾個大方法全搞定了,每個方法里無數個"Region"和"End Region"。這樣的情況就別談什么分離和設計了。最起碼的,當你在用"Region"和"End Region"的時候,就應該意識到這里可以分離出一個方法來。

  大方法帶來很多弊端。它的可維護性差,可閱讀性差,和系統的分層結構不融合,不能進行有效的單元測試。當然對大方法的重構并不像代碼本身那么發雜,如果它的邏輯足夠清晰的話。但是如果一個思維足夠清晰的程序員又怎么會寫出這樣的代碼,所以對這樣的代碼進行重構,面臨一個很大的問題就是那些在不同邏輯里重用的局部變量。當然更重要的問題是理不清頭緒。

  光去抱怨是沒什么意義的,這樣的方法出現的原因是什么呢?一個是開發者沒有很好的理解業務框架的結構和目的,二是對程序設計的基本思想理解的不夠好,三是對業務邏輯本身理解的不夠清晰。對于這樣的實現去重構,除了從業務角度出發,抽絲剝繭,慢慢的剝離,還有什么好辦法呢?推倒重來嗎?

  重構,要隨時進行

  當有一份代碼覺得不合適,而沒有及時重構的話,那么整個解決方案就可能變成垃圾場。后續的開發人員會以存在即合理的想法來看待這些垃圾代碼。尤其是新加入的成員,只能模仿別人在怎么做。從測試驅動的開發理念看,程序開發是一個不斷重構的迭代過程。很多人將重構看成是一件大事,一聽到重構就害怕起來,尤其是測試團隊。當然這里不能否認,不恰當的重構會給測試團隊造成很大的麻煩。

  集中重構是極其錯誤的思想。不要想著等某些開發任務結束了,有時間了再集中精力來重構代碼。當系統相對穩定之后,重構要付出的代價可能是整個團隊無法接受的。對分層架構的重構應該是建立架構的最初一段時間,不斷的調整達到最優。當項目進行一段之后,再來調整整體結構無疑是讓人無法接受的。

  重構要避免過度設計

  最后要說的是,重構要圍繞一個適度的目標來進行,要考慮代價,同時不代表模式應用的越多越好。相反的,在重構過程中,要時時考慮是否把簡答的事情想復雜了。

  目前我重構的代碼中,還沒有這樣的問題,這里也就不啰嗦了。

  說了這么多,我還是想聽聽各位的看法和感受,如何進行有效的重構,如何在編程的最開始的階段就避免很多重構障礙的產生?

2
0
 
標簽:重構
 
 

文章列表

arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()