Atenção! Programador C ++ chegando aqui com idéias possivelmente diferentes de como o tratamento de exceções deve ser feito, tentando responder a uma pergunta que certamente é sobre outra linguagem!
Dada esta ideia:
Por exemplo, imagine que temos o recurso de busca, que executa a solicitação HTTP e retorna os dados recuperados. E, em vez de erros como ServiceTemporaryUnavailable ou RateLimitExceeded, geraríamos apenas um RetryableError, sugerindo ao consumidor que ele deveria apenas tentar novamente a solicitação e não se importar com falhas específicas.
... uma coisa que eu sugiro é que você possa estar misturando preocupações de relatar um erro com cursos de ação para responder a ele de uma maneira que possa degradar a generalidade do seu código ou exigir muitos "pontos de conversão" para exceções .
Por exemplo, se eu modelar uma transação envolvendo o carregamento de um arquivo, ela poderá falhar por vários motivos. Talvez o carregamento do arquivo envolva o carregamento de um plug-in que não existe na máquina do usuário. Talvez o arquivo esteja simplesmente corrompido e encontramos um erro ao analisá-lo.
Não importa o que aconteça, digamos que o curso de ação seja relatar o que aconteceu com o usuário e avisá-lo sobre o que ele deseja fazer ("tente novamente, carregue outro arquivo, cancele").
Lançador vs. Apanhador
Esse curso de ação se aplica independentemente do tipo de erro que encontramos neste caso. Ele não está incorporado na idéia geral de um erro de análise, não está incorporado na idéia geral de não carregar um plug-in. Ele está incorporado na idéia de encontrar esses erros durante o contexto preciso de carregar um arquivo (a combinação de carregar e falhar). Então, tipicamente, eu vejo isso de maneira grosseira como a catcher's
responsabilidade de determinar o curso da ação em resposta a uma exceção lançada (por exemplo: solicitando opções ao usuário), não a thrower's
.
Dito de outra forma, os sites em que as throw
exceções geralmente não têm esse tipo de informação contextual, especialmente se as funções lançadas forem geralmente aplicáveis. Mesmo em um contexto totalmente degeneralizado quando eles têm essas informações, você acaba se esquivando em termos de comportamento de recuperação, incorporando-o ao throw
site. Os sites que catch
geralmente têm a maior quantidade de informações disponíveis para determinar um curso de ação e oferecem a você um local central para modificar se esse curso de ação mudar alguma vez para a transação em questão.
Quando você começa a tentar lançar exceções, não relatando mais o que está errado, mas tentando determinar o que fazer, isso pode degradar a generalidade e a flexibilidade do seu código. Um erro de análise nem sempre deve levar a esse tipo de prompt, varia de acordo com o contexto em que uma exceção é lançada (a transação sob a qual foi lançada).
O Lançador Cego
Em geral, muito do design do tratamento de exceções geralmente gira em torno da ideia de um lançador cego. Não sabe como a exceção será capturada ou onde. O mesmo se aplica a formas ainda mais antigas de recuperação de erros usando propagação manual de erros. Os sites que encontram erros não incluem um curso de ação do usuário, eles incorporam apenas as informações mínimas para relatar que tipo de erro foi encontrado.
Responsabilidades invertidas e generalização do apanhador
Ao pensar sobre isso com mais cuidado, eu estava tentando imaginar o tipo de base de código em que isso pode se tornar uma tentação. Minha imaginação (possivelmente errada) é que sua equipe ainda está desempenhando o papel de "consumidor" aqui e implementando a maior parte do código de chamada. Talvez você tenha muitas transações díspares (muitos try
blocos) que podem ser executadas nos mesmos conjuntos de erros e todas, da perspectiva do design, levam a um curso uniforme de ação de recuperação.
Levando em conta os conselhos sábios da Lightness Races in Orbit's
resposta correta (que eu acho que realmente vem de uma mentalidade avançada orientada a bibliotecas), você ainda pode ser tentado a lançar exceções "o que fazer", apenas mais perto do site de recuperação de transações.
Pode ser possível encontrar um site intermediário comum de manipulação de transações a partir daqui, que realmente centralize as preocupações "o que fazer", mas ainda dentro do contexto da captura.
Isso se aplicaria apenas se você pudesse projetar algum tipo de função geral usada por todas essas transações externas (por exemplo: uma função que insere outra função para chamar ou uma classe base de transação abstrata com comportamento substituível que modela esse site intermediário de transações que realiza a captura sofisticada )
No entanto, esse poderia ser responsável por centralizar o curso de ação do usuário em resposta a uma variedade de possíveis erros, e ainda dentro do contexto de pegar e não jogar. Exemplo simples (pseudocódigo Python-ish, e eu não sou nem um desenvolvedor experiente em Python, por isso pode haver uma maneira mais idiomática de fazer isso):
def general_catcher(task):
try:
task()
except SomeError1:
# do some uniformly-designed recovery stuff here
except SomeError2:
# do some other uniformly-designed recovery stuff here
...
[Espero que com um nome melhor que general_catcher
]. Neste exemplo, você pode transmitir uma função que contém qual tarefa executar, mas ainda se beneficiar do comportamento de captura generalizada / unificada para todos os tipos de exceções em que você está interessado, e continuar a estender ou modificar a parte "o que fazer" você gosta deste local central e ainda dentro de um catch
contexto em que isso normalmente é incentivado. O melhor de tudo é que podemos impedir que os locais de lançamento se preocupem com "o que fazer" (preservando a noção de "atirador cego").
Se você não encontrar nenhuma dessas sugestões aqui e houver uma forte tentação de lançar exceções "o que fazer" de qualquer maneira, lembre-se principalmente de que isso é muito anti-idiomático, pelo menos, além de potencialmente desencorajar uma mentalidade generalizada.