2012-03-04 74 views
1

假設我有一個WebCrawler類。它可能遇到幾個錯誤。我應該如何向上傳播錯誤?引發自定義異常,返回常量或返回符號?爲什麼?

使用異常:

class WebCrawler 
    class UrlBadFormatError < StandardError; end 
    class PageNotFoundError < StandardError; end 
    class UnauthorizedError < StandardError; end 
    def crawl(url) 
    if(! url =~ /some_format/) 
     raise UrlBadFormatError 
    response = get(url) 
    if(response.code == 404) 
     raise PageNotFoundError 
    if(response.code == 403) 
     raise UnauthorizedError 
    ... 
    end 
end 

或常量:

class WebCrawler 
    URL_BAD_FORMAT = 1 
    PAGE_NOT_FOUND = 2 
    UNAUTHORZIED = 3 
    def crawl(url) 
    if(! url =~ /some_format/) 
     return URL_BAD_FORMAT 
    response = get(url) 
    if(response.code == 404) 
     return PAGE_NOT_FOUND 
    if(response.code == 403) 
     return UNAUTHORZIED 
    ... 
    end 
end 

或符號:

class WebCrawler 
    def crawl(url) 
    if(! url =~ /some_format/) 
     return :url_bad_format 
    response = get(url) 
    if(response.code == 404) 
     return :page_not_found 
    if(response.code == 403) 
     return :unauthorized 
    ... 
    end 
end 

這是最好的?或者它取決於什麼?

回答

2

對於指示程序員錯誤的東西,例如傳遞給方法的參數類型錯誤,肯定會拋出異常。這個異常會導致程序崩潰,引起程序員的注意,他們錯誤地使用了你的類,這樣他們就可以解決這個問題。在這種情況下,返回錯誤代碼是沒有意義的,因爲程序將不得不包含代碼來檢查返回值,但在程序調試完成後,這種錯誤不應該發生。

在您的WebCrawler類中,是否爲預計crawl有時會收到一個錯誤的URL作爲參數?我想答案可能不是。因此,當傳遞錯誤的URL時,引發異常將是適當的。

當引發異常時,執行流突然「跳」到最內層的處理程序。由於您可以將方法的「主要流程」寫爲簡單的直線代碼,而不需要包含大量關於該方法的詳細信息,因此這可能是構建代碼時非常有用的一種方法,用於在異常不是而不是時發生大部分時間當發生一些罕見的錯誤情況時會發生什麼。這些細節可以從「主流程」代碼中分離出來,並放入一個異常處理程序。但是,如果在正常情況下預期會出現錯誤情況,最好將錯誤處理代碼與「主要流程」內聯,以更清楚地說明發生的情況。如果程序的控制流程「跳過」(正常流量控制使用例外情況),這意味着讀者還必須在程序文本中「跳過」,因爲他們正在弄清楚它是如何工作的。

對於另外兩個,我認爲至少有時候,HTTP請求會返回一個錯誤代碼。要確定一個例外情況或特殊返回值是否是指示這種情況的最佳方式,我會考慮在正常使用情況下這些情況的發生頻率。也想想客戶端代碼將如何讀取。如果您使用的例外,他們將不得不寫類似:

urls.map do |url| 
    begin 
    crawl(url) 
    rescue PageNotFoundError 
    "" 
    rescue UnauthorizedError 
    "" 
    end 
end 

(順便說一句,我認爲這個代碼示例顯示了一句:這可能是一個好主意,如果兩個自定義異常的從一個共同的超類繼承,所以你可以用一個rescue條款追上他們兩個如果需要的話),或者如果您使用的錯誤代碼,它看起來是這樣的:。

urls.map do |url| 
    response = crawl(url) 
    if [:page_not_found, :unauthorized].include? response 
    "" 
    else 
    response 
    end 
end 

你認爲哪讀更好?這真的取決於你。你做的一件事不是想要做的就是用整數常量來表示錯誤。爲什麼使用整數?當您在調試跟蹤中打印它們時,您必須查看常量列表以查看每個常量的含義。使用符號在計算上同樣有效。

0

如果這是一個例外,那麼通過一切手段引發異常!在我看來,所有這三種情況都是例外情況。雖然有些人可能會爭辯說4xx狀態碼並不值得您考慮,但它們仍然是客戶端錯誤

您也可以閱讀關於Ruby的throw/catch,它們適用於「不使用控制流的異常」的情況下的類似於異常的行爲(儘管我認爲這不是這種情況)。

2

爲什麼不會你拋出異常?除了類型之外,它們可以封裝額外的信息,可以輕鬆獲得救援,如果您使用的是IDE,則是一等公民。

+5

我不認爲你是否使用IDE或者不應該考慮* how *或*你編程的內容。 – 2012-03-04 20:47:16

+2

@AndrewMarshall這是一個觀點,但它確實很重要。 – 2012-03-04 20:52:27

+3

除了可能的風格/文檔約定(實際上並不影響文字代碼),否則不應該。作爲頭等公民的例外情況(我認爲你的意思是課程)是真實的,不管你是否使用IDE--使用IDE都不會改變這種情況。 – 2012-03-04 20:59:50

0

您應該提出錯誤。如果您遇到格式不正確的網址,或者找不到網頁,或者您無權訪問該網頁,則表示您無法繼續抓取。從方法中返回錯誤或異常,並讓調用者處理異常情況。

它還應該包含有關錯誤的信息,例如錯誤代碼,導致錯誤的URL以及任何其他相關信息。它可以幫助決定如何最好地處理錯誤,並且可以稍後將其格式化爲對用戶有用的消息。

不應該做什麼,永遠,是返回數字錯誤代碼。 Ruby不是C.只需使用符號。

-1

我反對在網絡上遇到403s,404s,畸形的網址和類似的常見事件時使用例外。例外是指「內部」錯誤。在World Wild Web中,糟糕的網址完全沒有意義。應該有一個方法來處理每個不同的URL疾病。我會親自將特殊值作爲符號返回,或者記錄發生了什麼的一些「SpecialCase」對象。還有未被使用的catch ... throw語句。

+1

僅僅因爲錯誤發生了很多,並不意味着它不是一個例外。如果汽車由於電池電量不足而無法啓動,那麼這是否是正常行爲,但是這是一個錯誤情況,需要特殊情況才能解決。不要讓你的壞習慣與最佳實踐混淆。無論通信發生的頻率如何,通信失敗都是例外情況。失敗!=成功。 – ocodo 2013-06-06 03:07:24

+0

我的答案並不明顯,我的理由並不明顯,所以也許它並不是那麼好:更糟糕的是,我自己也忘了他們:-)但是我的習慣不是怪,因爲我喜歡例外 - 不僅僅是當電池是平的,而且路燈是紅色的時候。有[關於這個的一個討論](http:// stackoverflow。com/questions/2018137),明確提到Sinatra使用catch/throw來處理HTTP異常,[我開始另一個](http://stackoverflow.com/questions/16972757)。 catch/throw是否真的很糟糕,或者只是沒有被使用? – 2013-06-06 21:50:52