2013-06-04 33 views
3

我有很多這樣的(〜30)方法WCF服務:從簡單的方法中刪除重複的代碼 - 走得太遠?

public Foo GetFooById(string id) 
{ 
    try 
    { 
     return FooLogic.GetById(id); 
    } 
    catch (Exception ex) 
    { 
     throw LogAndThrowFaultException(ex); 
    } 
} 

的代碼,這些方法是完全不同的是將try塊一條線一樣。這很簡單,我甚至已經抽象日誌並拋出一個異常。

乾的精神,我可以再進一步,做到這一點:

public Foo GetFooById(string id) 
{ 
    return PerformServiceOperation<Foo>(() => FooLogic.GetById(id)); 
} 

對於這項工作,這個方法會處理重複的try/catch代碼,並調用每個FUNC:

private T PerformServiceOperation<T>(Func<T> func) 
{ 
    try 
    { 
     return func.Invoke(); 
    } 
    catch (Exception ex) 
    { 
     throw LogAndThrowFaultException(ex); 
    } 
} 

這太過分了嗎?代碼是否已經儘可能簡單,並且應該單獨保留?或者,將func傳遞給helper方法並讓該方法處理重複try/catch是個好主意?我也關心可讀性。我認爲對輔助方法的調用有點難看。

+5

DRY本身並不是終點;它的目的是*降低維護成本*。多少錢一小時才能做出這樣的改變,多少錢才能做出這樣的改變,從長遠來看可以節省您的時間?我會稱這是浪費你寶貴的時間;花你的寶貴時間編寫測試用例或者查看規範或實現新功能或編寫性能監控工具;所有這些東西都會有更大的投資回報。 –

+0

埃裏克說什麼。你的「乾的精神」的例子已經是乾的;你所做的只是增加一些額外的儀式。 –

+0

我同意@EricLippert。而且這種抽象級別只會讓你的代碼更難閱讀,因此難以維護。沒有任何模式,原則或方法論可行。只有在他們有意義時才使用它們,並在達到遞減(甚至負數)回報點時停止。 –

回答

4

我不得不說,一般來說,在生產代碼中,我傾向於認爲DRY應該被採用到極端。我有幾個幾十年來發展的原因。

1)「修復」在一個地方得到傳播。像這樣一個簡單的修復建議可以節省數小時的QA反彈代碼,因爲一個接一個的方法不能通過簡單的測試。這可能是一個極端的例子,但我看到它發生了。同樣,儘管你知道這個代碼被複制,你必須在多個地方進行修復,下一位工程師是否知道這一點?

順便說一句,一個可行的替代方法是將每個地點的代碼重複引用其他位置,以便維護人員知道去哪裏。

2)編程能力。通過堅持絕對0代碼重複,您將學習使您成爲更好工程師的技術。我有很多代碼可供選擇,工程師堅持說他們不能讓它變得更幹 - 但我自己做了十幾次(或許有一個你在這裏用過的技巧),因爲我' d在某個時刻必須解決它。

3)可能是最不明顯但最重要的 - 迭代重構。重構通常只能分層進行。你當然看到了一堆混亂,不可思議的代碼,只看到了最小的重構 - 但在重構之後,其他人變得清晰,並使其他人變得清晰。我採取了大量的方法,每個人都不敢碰,並以這種方式將它們縮小到原始尺寸的1/10。

4)數據提取。如果你堅持DRY,你最終會得到大量的數據,因爲最基本的重構之一就是從類似的代碼中提取不同的數據,然後合併代碼。這使得你的代碼更易於維護 - 在過去,我經常能夠在重構之前花費數小時或數天的時間解決一個字符串數組更改的問題。

我不得不讓人們相信我到過的每一個人(你可以通過查看對這個問題說「不」的人數來看到這一點)。在開始之前,極度乾燥通常是一種艱難的銷售 - 直到他們看到結果。我認爲你可以親自做的最重要的事情就是承諾自己能幹,因爲你的才能會讓你(當你練習時會變得更多)。

如果您列出的特定重構導致問題,那麼您已經學到了一些東西,並且可以在下次以不同的方式處理它。你學到了,時間沒有浪費。

順便說一下,您將學習到以非常可理解的方式編寫非常乾的代碼至關重要 - 這並非總是很容易,並且可能會導致一些人討厭「重構」,並且「過度工程」,直到他們發現他們正在編寫代碼的人在通信(通過代碼)方面不夠好。 PS:我應該提到另外一個 - 因爲DRY編碼很有趣。複製和粘貼代碼(以及修復代碼)是您作爲程序員可以做的最悲慘的工作,但創建仍然可用且可維護的簡短DRY代碼是一個精神挑戰,任何值得他的鹽的工程師都應該享受這個難題。

+0

太棒了。我要分享這個。謝謝。 –

+1

順便說一下,在XP中,這個原則被稱爲「無情重構」,並被認爲是必需的 - 沒有它,一個小型的敏捷團隊將難以維護不斷髮展的代碼庫。 –

+0

優秀的答案,不能同意更多。 – Jim

2

從概念上講,我不認爲這太過分了。改變一次處理異常的方式,你會很高興你決定不要一遍又一遍地輸入相同的try-catch塊。我會更傾向於通過某個方面處理異常,但您的解決方案也是可行的。

0

走得太遠?

請注意,您在每個方法,以推動異常處理的方法的補充到PerformServiceOperation()的調用。除非您從重複的異常處理中節省大量維護時間,否則您可能會走得很遠。但是,如果已經有方法將異常處理添加到您選擇的框架(WCF)來處理未處理的異常,那麼這樣做不會太遠。

使用aspect oriented programming(AOP),記錄異常的方法攔截非常簡單。但是由於這個原因,切換到AOP確實太過分了......