Pergunta

Eu estava tendo uma discussão com um dos meus colegas sobre como defensiva seu código deve ser. Eu sou tudo pro programação defensiva, mas você tem que saber onde parar. Estamos trabalhando em um projeto que será mantida por outros, mas isso não significa que temos de verificar a existência de todas as coisas loucas um desenvolvedor poderia fazer. Claro, você poderia fazer isso, mas isto irá adicionar uma grande sobrecarga para o seu código.

Como você sabe onde traçar a linha?

Foi útil?

Solução

Eu não sei que não há realmente nenhuma maneira de responder a isso. É apenas algo que você aprende com a experiência. Você só precisa perguntar a si mesmo o quão comum um problema potencial é susceptível de ser e fazer um julgamento. Considere também que você não necessariamente Have para sempre código defensivamente. Às vezes é aceitável apenas para observar eventuais problemas na documentação do seu código.

Em última análise, porém, eu acho que isso é apenas algo que uma pessoa tem de seguir sua intuição diante. Não há nenhuma maneira certa ou errada de fazê-lo.

Outras dicas

Qualquer coisa que um user entra direta ou indiretamente, você deve sempre sanidade-check. Além disso, algumas asserts aqui e ali não vai doer, mas você realmente não pode fazer muito sobre programadores loucos edição e quebrando seu código, de qualquer maneira -!)

I tendem a alterar a quantidade de defesa Eu coloquei no meu código com base no idioma. Hoje eu estou trabalhando principalmente em C ++ para que meus pensamentos estão à deriva nessa direção.

Ao trabalhar em C ++ não pode haver programação defensiva suficiente. Eu trato o meu código como se eu estou guardando segredos nucleares e todos os outros programador está fora para pegá-los. Afirma, mantas, compilador tempo hacks modelo de erro, a validação de argumento, eliminando ponteiros, em profundidade revisões de código e paranóia gerais são todos jogo justo. C ++ é uma linguagem maravilhosa mal que tanto amor e severamente desconfiança.

Eu não sou um fã do termo "programação defensiva". Para mim, isso sugere um código como este:

void MakePayment( Account * a, const Payment * p ) {
    if ( a == 0 || p == 0 ) {
       return;
    }
    // payment logic here
}

Isso é errado, errado, errado, mas devo ter visto isso centenas de vezes. A função nunca deveria ter sido chamado com ponteiros nulos, em primeiro lugar, e é totalmente errado para aceitá-los calmamente.

A abordagem correta aqui é discutível, mas uma solução mínima é falhar ruidosamente, usando uma declaração ou lançando uma exceção.

Editar: Não concordo com algumas outras respostas e comentários aqui - Eu não acho que todas as funções devem verificar seus parâmetros (para muitas funções isso é simplesmente impossível). Em vez disso, eu acredito que todas as funções devem documentar os valores que são aceitáveis ??e afirmam que outros valores irá resultar em um comportamento indefinido. Esta é a abordagem adoptada pelas bibliotecas mais bem sucedidos e amplamente utilizado já escritos -. Bibliotecas padrão C e C ++

E agora vamos as downvotes começar ...

Se você está trabalhando em APIs públicas de um componente, em seguida, vale a pena fazer uma boa quantidade de validação de parâmetros. Isso me levou a ter o hábito de fazer a validação em todos os lugares. Isso é um erro. Tudo o que o código de validação nunca é testado e potencialmente torna o sistema mais complicado do que precisa ser.

Agora eu prefiro Validar por testes de unidade. Validação definitivamente acontece por dados provenientes de fontes externas, mas não chamadas de desenvolvedores não externos.

Eu sempre Debug.Assert minhas suposições.

A minha ideologia pessoal:. A atitude defensiva de um programa devem ser proporcionais ao máximo ingenuidade / ignorância do potencial base de usuários

Ser defensivo contra os desenvolvedores que consomem o seu código de API não é tão diferente de ser defensiva contra usuários regulares.

  • Verifique os parâmetros para se certificar que estão dentro dos limites apropriados e de tipos esperados
  • Verifique se o número de chamadas de API que podem ser feitas estão dentro de seus Termos de Serviço. Geralmente chamado de estrangulamento que normalmente só se aplica a serviços web e funções de verificação de senha.

Além de que não há muito mais o que fazer, exceto Verifique se o seu recupera de aplicativos bem no caso de um problema e que você sempre dar ampla informação para o desenvolvedor para que eles compreendam o que está acontecendo.

A programação defensiva é apenas uma maneira de hounouring um contrato em um projeto-a-contrato maneira de codificação.

Os outros dois são

  • total de programação e
  • programação nominal.

É claro que você não deve se defender contra cada coisa louca um desenvolvedor poderia fazer, mas então você deve indicar no contexto wich ele vai fazer o que é esperado para usar pré-condições.

//precondition : par is so and so and so 
function doSth(par) 
{
debug.assert(par is so and so and so )
//dostuf with par 
return result
}

Eu acho que você tem que trazer a questão de saber se você está criando testes também. Você deve ficar na defensiva em sua codificação, mas como fora apontado por JaredPar - Eu também acredito que depende do idioma que você está usando. Se é código não gerenciado, então você deve ser extremamente defensiva. Se ele conseguiu, eu acredito que você tem um pouco de wiggleroom.

Se você tem testes, e algumas outras tentativas de desenvolvedores para dizimar o seu código, os testes falhará . Mas, novamente, depende de cobertura de teste em seu código (se houver).

Eu tento escrever código que é mais do que defensiva, mas para baixo hostil direita. Se algo der errado e posso corrigi-lo, eu vou. se não, jogar ou passar sobre a exceção e torná-lo alguma outra pessoa problema. Qualquer coisa que interage com um dispositivo físico - sistema de arquivos, conexão de dados, conexão de rede deve ser considerada unereliable e propensos a falhas. antecipando essas falhas e captura-los é fundamental

Uma vez que você tem essa mentalidade, a chave é ser consistente na sua abordagem. você espera devolver códigos de status para os problemas comminicate na cadeia de chamada ou você gosta exceções. modelos mistos vai matá-lo ou pelo menos levá-lo a beber. pesadamente. se você estiver usando alguma outra pessoa api, em seguida, isolar essas coisas em mecanismos que armadilha / relatório em termos que você usa. usar essas interfaces de embrulho.

Se a discussão aqui é como código defensivamente contra o futuro (possivelmente malévolo ou incompetente) mantenedores, há um limite para o que você pode fazer. Cumprimento de contratos através de cobertura de teste e uso liberal de afirmar seus pressupostos é provavelmente o melhor que você pode fazer, e isso deve ser feito de uma forma que, idealmente, não atravancar o código e tornar o trabalho mais difícil para os futuros mantenedores não-malignas do código. Afirma são fáceis de ler e compreender e torná-lo claro o que os pressupostos de um determinado pedaço de código é, por isso eles são geralmente uma ótima idéia.

Codificação defensivamente contra as ações do usuário é outra questão inteiramente, e a abordagem que eu uso é pensar que o usuário está fora para me pegar. Cada entrada é examinado cuidadosamente como eu posso controlar, e eu fazer todos os esforços para ter o meu código de prova de falhas - tente não persistem qualquer estado que não é rigorosamente controlado, a correta onde você pode, saída graciosamente se você não puder, etc. Se você só pensar em todas as coisas bozo que poderiam ser perpetrados em seu código por agentes externos, você fica na mentalidade certa.

Codificação defensivamente contra outro código, como a sua plataforma ou outros módulos, é exatamente o mesmo que os usuários: eles estão fora para te pegar. O sistema operacional é sempre vai trocar seu segmento em um momento inoportuno, as redes estão sempre indo para ir embora na hora errada, e em geral, abunda maus em cada esquina. Você não precisa de código contra cada problema potencial lá fora - o custo em manutenção pode não valer a pena o aumento da segurança - mas com certeza não faz mal para pensar nisso. E, geralmente, não faz mal para explicitamente comentário no código, se há um cenário que você pensou, mas consideram sem importância por algum motivo.

Os sistemas devem ter bem fronteiras, onde a verificação defensiva acontece projetado. Deve haver uma decisão sobre onde a entrada do usuário é validado (em que limite) e onde outras questões defensivas potenciais requerem verificação (por exemplo, pontos de integração de terceiros, APIs disponíveis publicamente, regras de interação do motor, ou diferentes unidades codificadas por diferentes equipes de programadores ). verificação mais defensiva do que viola SECO, em muitos casos, e apenas aumenta o custo de manutenção por muito pouco benifit.

Dito isto, existem alguns pontos onde você não pode ser muito paranóico. Potencial para estouros de buffer, corrupção de dados e questões semelhantes devem ser muito rigorosamente defendida contra.

Recentemente, tive cenário, em que os dados de entrada do usuário foi propagado através da interface fachada remoto, interface de fachada, em seguida, local, em seguida, uma outra classe, para finalmente chegar ao método onde ele foi realmente usado. Eu estava pedindo a minha auto uma pergunta:? Quando deve ser o valor validado eu adicionei validação de código apenas para a classe final, onde o valor foi realmente utilizado. Adicionando outros trechos de código de validação em aulas que coloca no caminho de propagação seria de programação muito defensiva para mim. Uma exceção pode ser a fachada remoto, mas eu saltei-lo também.

Boa pergunta, eu lanço já fracassou entre fazer checagens e não fazê-las. É um 50/50

situação, eu provavelmente ter um meio termo onde eu seria apenas "Bullet Proof" quaisquer rotinas que são:

(a) Chamado de mais de um lugar no projeto

(b) tem uma lógica que é susceptível de alterar

(c) Você não pode usar valores padrão

(d) a rotina não pode ser 'falhou' graciosamente

Darknight

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top