Вызывать пользовательские исключения, возвращать константы или возвращать символы? Зачем? - PullRequest
1 голос
/ 05 марта 2012

Предполагая, что у меня есть 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

что лучше? или это зависит (от чего?)

Ответы [ 5 ]

2 голосов
/ 05 марта 2012

Почему не вы бросаете исключения? Они могут инкапсулировать дополнительную информацию, кроме только их типа, тривиально спасены, и если вы используете IDE, они являются первоклассными гражданами.

2 голосов
/ 05 марта 2012

Что-то, что указывает на ошибку программиста, например, неправильный тип аргумента, переданного методу, определенно вызывает исключение.Исключение приведет к падению программы, обратив внимание программиста на тот факт, что они используют ваш класс неправильно, чтобы они могли решить проблему.В этом случае возвращать код ошибки не имеет смысла, так как программе придется включать код для проверки возвращаемого значения, но после отладки программы таких ошибок быть не должно.

ВВаш 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 голосов
/ 05 марта 2012

Я против использования исключений при обнаружении 403-х, 404-х, некорректных URL-адресов и подобных распространенных явлений в сети.Исключения предназначены для «внутренних» ошибок.В World Wild Web плохие URL-адреса совершенно исключительны.Должен быть метод (ы) для обработки каждого отдельного заболевания URL.Я бы лично возвращал специальные значения в виде символов или некоторые объекты «SpecialCase», записывающие то, что произошло.Существует также недостаточно используемый оператор catch ... throw.

0 голосов
/ 05 марта 2012

Вы должны поднять ошибки. Если вы столкнулись с неверно сформированным URL-адресом, или если страница не найдена, или если вы не были авторизованы для доступа к странице, это означает , вы не можете продолжить сканирование . Возврат ошибки или исключения возвращается из метода и позволяет вызывающей стороне справиться с необычной ситуацией.

Он также должен включать информацию об ошибке, такую ​​как коды ошибок, URL-адрес, который привел к ошибке, и любую другую соответствующую информацию. Это может помочь в определении того, как лучше всего обработать ошибку, и впоследствии может быть отформатировано в полезное сообщение для пользователя.

То, что вы не должны делать, , это возвращать числовые коды ошибок. Ruby - это не C. Просто используйте вместо этого символы.

0 голосов
/ 05 марта 2012

Если это исключение, то непременно вызывает исключение!Все три из этих случаев, на мой взгляд, являются исключениями.Хотя некоторые могут утверждать, что коды состояния 4xx не заслуживают исключений, так как вы можете ожидать их возникновения, они все еще являются клиентом ошибки .

Вы также можете прочитать о Ruby's throw /catch, который предлагает поведение, подобное исключению, для случаев, когда применяется "не использовать исключения для потока управления" (хотя я не думаю, что это так).

...