Seja liberal no que você aceita… ou não?

43
[Disclaimer: esta questão é subjetiva, mas eu prefiro obter respostas apoiadas por fatos e / ou reflexões]

Acho que todo mundo conhece o Princípio da Robustez , geralmente resumido pela Lei de Postel:

Be conservative in what you send; be liberal in what you accept.

Eu concordaria que para o projeto de um protocolo de comunicação generalizado isso pode fazer sentido (com o objetivo de permitir fácil extensão), no entanto sempre achei que sua aplicação ao HTML / CSS foi uma falha total, cada navegador implementando sua detecção / comportamento de ajuste silencioso, tornando quase impossível obter uma renderização consistente em vários navegadores.

Eu noto que o RFC do protocolo TCP considera a "Silent Failure" aceitável a menos que especificado de outra forma ... o que é um comportamento interessante, para dizer o mínimo.

Existem outros exemplos da aplicação desse princípio em todo o comércio de software que surgem regularmente porque eles têm desenvolvedores mordidos, do topo da minha cabeça:

  • inserção de ponto-e-vírgula em Javascript
  • C (silencioso) conversões internas (o que não seria tão ruim se não fosse truncado ...)

e existem ferramentas para ajudar a implementar o comportamento "inteligente":

No entanto, acho que essa abordagem, embora possa ser útil ao lidar com usuários não técnicos ou ajudar usuários no processo de recuperação de erros, tem algumas desvantagens quando aplicada ao design da interface biblioteca / classes:

  • é um pouco subjetivo se o algoritmo adivinhar "certo" e, portanto, pode ir contra o Princípio de menor espanto
  • torna a implementação mais difícil, portanto, mais chances de apresentar erros (violação de YAGNI ?)
  • torna o comportamento mais suscetível a mudanças, já que qualquer modificação na rotina de "adivinhação" pode interromper programas antigos, quase excluindo as possibilidades de refatoração ... desde o início!

E isso é o que me levou à seguinte pergunta:

Ao projetar uma interface (biblioteca, classe, mensagem), você se inclina para o princípio da robustez ou não?

Eu mesmo sou muito rigoroso, usando validação de entrada extensiva em minhas interfaces, e fiquei me perguntando se eu talvez fosse muito rigoroso.

    
por Matthieu M. 16.10.2010 / 15:41
fonte

10 respostas

33

Eu diria robustez quando não introduz ambigüidades .

Por exemplo: Ao analisar uma lista separada por vírgula, se há ou não um espaço antes / depois da vírgula não altera o significado semântico.

Ao analisar uma string guid, ela deve aceitar qualquer número de formatos comuns (com ou sem traços, com ou sem chaves).

A maioria das linguagens de programação é robusta com o uso de espaço em branco. Especificamente em todos os lugares que não afeta o significado do código. Mesmo em Python, onde o espaço em branco é relevante, ainda é flexível quando você está dentro de uma lista ou declaração de dicionário.

Eu definitivamente concordo que se algo pode ser interpretado de várias maneiras ou se não estiver 100% claro o que foi feito, então muita robustez pode acabar sendo uma dor, mas há muito espaço para robustez sem ser ambíguo.

    
por 16.10.2010 / 18:25
fonte
14

Definitivamente não. Técnicas como programação defensiva obscurecem bugs, tornando sua aparência menos provável e mais aleatória, o que dificulta sua detecção, o que torna o isolamento mais difícil.

O Código Sólido de Escrita muito subestimado foi tremendo ao enfatizar repetidamente a necessidade e as técnicas de fazer erros tão difíceis de introduzir ou esconder. Através da aplicação de seus princípios, como "Eliminar o comportamento aleatório. Forçar erros para ser reproduzível". e "Sempre procure e elimine falhas em suas interfaces." os desenvolvedores irão melhorar muito a qualidade de seus softwares, eliminando a ambiguidade e os efeitos colaterais descontrolados que são responsáveis por uma grande quantidade de bugs.

    
por 16.10.2010 / 18:14
fonte
9

A aplicação excessiva de robustez leva você a adivinhar o que o usuário queria, o que está correto até você errar. Isso também requer a crença completamente errada de que seus clientes não abusarão da sua confiança e criarão mensagens aleatórias aleatórias que por acaso funcionam, mas que você não poderá suportar na versão 2.

A aplicação excessiva da exatidão leva você a negar a seus clientes o direito de cometer pequenos erros, o que é correto até que eles se queixem de que suas coisas funcionam bem no produto de seu concorrente e lhe dirão o que você pode fazer com seu padrão de 5.000 páginas tem a palavra "RASCUNHO" ainda rabiscada na capa em giz de cera, e pelo menos 3 especialistas afirmam ser fundamentalmente falho, e 200 especialistas mais honestos dizem que não entendem completamente.

Minha solução pessoal sempre foi depreciativa. Você os apóia, mas diz que eles estão errados e (se possível) o caminho mais fácil para a correção. Dessa forma, quando você desliga o recurso de bugs 10 anos depois, você tem pelo menos o rastro de papel para afirmar que "avisamos que isso pode acontecer".

    
por 15.11.2011 / 12:09
fonte
9

Infelizmente, o chamado "princípio da robustez" não leva a robustez. Tome HTML como exemplo. Muitos problemas, lágrimas, desperdício de tempo e energia poderiam ter sido evitados se os navegadores tivessem estritamente analisado o HTML desde o início, em vez de tentar adivinhar o significado do conteúdo malformado.

O navegador deve simplesmente ter exibido uma mensagem de erro em vez de tentar corrigi-lo nas capas. Isso teria forçado todos os trapaceiros a consertar sua bagunça.

    
por 15.11.2011 / 13:50
fonte
6

Eu divido as interfaces em vários grupos (adicione mais se quiser):

  1. aqueles que estão sob o seu controle devem ser rigorosos (classes geralmente)
  2. APIs da biblioteca, que também devem estar no lado estrito, mas é recomendável validação adicional
  3. interfaces públicas que devem lidar com todo tipo de abuso que vem (geralmente protocolos, entradas do usuário, etc). Aqui a robustez na entrada realmente vale a pena, você não pode esperar que todos consertem suas coisas. E lembre-se, para o usuário, será sua culpa se o aplicativo não funcionar, não a parte que enviou alguma porcaria mal formatada.

A saída deve ser sempre rigorosa.

    
por 15.11.2011 / 18:11
fonte
5

Acho que o HTML e a World Wide Web forneceram um teste real em grande escala do Princípio da Robustez e mostraram que ele é um grande fracasso. É diretamente responsável pela bagunça confusa de quase todos os padrões HTML concorrentes que tornam a vida miserável para os desenvolvedores da Web (e seus usuários) e piora a cada nova versão do Internet Explorer.

Nós sabemos desde os anos 50 como validar o código corretamente. Execute-o através de um analisador estrito e se algo não estiver sintaticamente correto, envie um erro e aborte. Não passe, não colete $ 200, e pelo amor de tudo que é binário não deixe que algum programa de computador tente ler a mente do codificador se ele cometeu um erro!

HTML e JavaScript nos mostraram exatamente o que acontece quando esses princípios são ignorados. O melhor curso de ação é aprender com os erros deles e não repeti-los.

    
por 16.10.2010 / 15:52
fonte
3

Como contraponto ao exemplo de Mason, minha experiência com o Protocolo de Iniciação de Sessão foi que, embora diferentes pilhas pudessem interpretar as RFCs diferentemente (e eu suspeito que isso acontece com todo padrão já escrito), sendo (moderadamente) liberal no que você aceita significa que você pode realmente fazer chamadas entre dois dispositivos. Como esses dispositivos são coisas físicas comuns, em vez de peças de software em um computador, você simplesmente precisa ser liberal naquilo que aceita ou seu telefone não pode chamar outro telefone de uma marca específica. Isso não faz o seu telefone parecer bom!

Mas, se você está escrevendo uma biblioteca, provavelmente não tem o problema de várias partes que interpretam um padrão comum de maneiras mutuamente incompatíveis. Nesse caso, eu diria que seja rigoroso no que você aceita, porque elimina ambiguidades.

O arquivo jargão também tem uma história de terror sobre "adivinhar" um usuário intenção.

    
por 16.10.2010 / 16:50
fonte
3

Você está certo, a regra se aplica aos protocolos e não à programação. Se você fizer um erro de digitação durante a programação, receberá um erro assim que compilar (ou executar, se for um desses tipos dinâmicos). Não há nada a ser ganho ao permitir que o computador adivinhe você. Ao contrário do povo comum, somos engenheiros e capazes de dizer exatamente o que eu quero dizer. ;)

Então, ao criar uma API, eu diria que não siga o Princípio da Robustez. Se o desenvolvedor cometer um erro, eles devem descobrir imediatamente. Naturalmente, se sua API usa dados de uma fonte externa, como um arquivo, você deve ser tolerante. O usuário da sua biblioteca deve descobrir seus próprios erros, mas não de qualquer outra pessoa.

Como um aparte, eu diria que "falha silenciosa" é permitida no protocolo TCP porque, caso contrário, se as pessoas lançassem pacotes malformados em você, você seria bombardeado com mensagens de erro. Isso é simples proteção DoS ali mesmo.

    
por 16.10.2010 / 17:31
fonte
1

IMO, robustez é um lado de um trade-off de design e não um princípio de "preferência". Como muitos apontaram, nada cheira a soprar quatro horas tentando descobrir onde seu JS errou apenas para descobrir que o verdadeiro problema era que apenas um navegador fazia a coisa certa com o XHTML Strict. Ele deixou a página ficar em pedaços quando alguma parte do HTML exibido foi um desastre completo.

Por outro lado, quem deseja procurar documentação para um método que aceita 20 argumentos e insiste em que estejam exatamente na mesma ordem que os locais vazios ou nulos para os que você deseja ignorar? A igualmente robusta maneira robusta de lidar com esse método seria verificar cada arg e tentar adivinhar qual deles era baseado em posições e tipos relativos e, em seguida, falhar silenciosamente ou tentar "sobreviver" com argumentos sem sentido.

Ou você pode aumentar a flexibilidade no processo passando uma lista de pares de valores literais / dicionário / valor-chave de objeto e lidando com a existência de cada argumento à medida que você chega a ele. Para o tradeoff de perf menor, é um cenário de bolo e de comer também.

Sobrecargas de argumentos de maneira inteligente e consistente com a interface é uma forma inteligente de ser robusto sobre as coisas. Assim, a redundância de cozimento é um sistema em que se presume que a entrega de pacotes não será entregue regularmente em uma rede maciçamente complicada de propriedade e operada por todos em um campo emergente de tecnologia com uma ampla variedade de meios potenciais de transmissão.

Tolerar a falha de abjeto, no entanto, especialmente dentro de um sistema que você controla, nunca é uma boa troca. Por exemplo, eu tive que fazer uma pausa para evitar jogar um chiado em outra pergunta sobre colocar o JS no topo ou na parte inferior da página. Várias pessoas insistiram que era melhor colocar JS no topo, porque se a página não fosse carregada completamente, você ainda teria alguma funcionalidade. Páginas de meia-obra são piores do que bustos completos. Na melhor das hipóteses, eles resultam em mais visitantes para o seu site corretamente assumindo que você é incompetente antes de descobrir sobre isso, se a página rebocada é simplesmente devolvida a uma página de erro ao falhar sua própria verificação de validação seguida por um e-mail automatizado Alguém que pode fazer algo sobre isso. Você se sentiria à vontade para passar as informações do seu cartão de crédito para um site que estava sempre preso?

Tentar entregar a funcionalidade de 2010 em um navegador de 1999, quando você poderia apenas fornecer uma página de tecnologia inferior, é outro exemplo de uma troca de design insensata. As oportunidades perdidas e o dinheiro que eu vi desperdiçado com o tempo gasto pelo desenvolvedor em soluções cheias de bugs apenas para obter cantos arredondados em um elemento que paira acima de um fundo gradiente, por exemplo, me afastaram completamente. E para quê? Para fornecer páginas tecnológicas mais avançadas que tenham um desempenho fraco em relação a technophobes comprovados, limitando suas escolhas em navegadores de maior porte.

Para que seja a escolha certa, a escolha de manipular entradas de maneira robusta deve sempre facilitar a vida em ambos os lados do problema, no curto e no longo prazo.

    
por 06.04.2012 / 03:53
fonte
1

Nunca falhe silenciosamente . Além disso, tentar adivinhar o que o usuário de uma API / biblioteca queria, não parece uma idéia ruim. Eu não seguiria isso; ter um requisito estrito, pode expor erros no código de chamada e / ou interpretações erradas sobre sua API / biblioteca.

Além disso, como já foi apontado, depende de quão difícil é adivinhar o que o usuário esperava. Se é muito fácil, então você tem dois casos:

  1. Sua biblioteca deve ser projetada de forma um pouco diferente (renomeie alguma função ou divida-a em duas), para que o usuário possa esperar o que você realmente fornece.
  2. Se você acredita que sua biblioteca foi projetada corretamente, ou seja, com nomes claros / diretos, tente inferir o que o usuário pretendia.

Em qualquer caso que não é 100% óbvio e determinístico, que uma entrada deve ser convertida em outra, você não deve fazer as conversões, por um número de razões já mencionadas (quebrando a compatibilidade na refatoração, menos espanto dos usuários) .

Ao lidar com um usuário final, tentar consertar sua entrada / palpite é muito bem-vindo. Ele é esperado para inserir informações inválidas; este caso é completamente não excepcional. Outro desenvolvedor, porém, não é um usuário simples não técnico. Ele tem o conhecimento para entender um erro, e o erro pode ter significado / ser benéfico para ele. Assim, concordo com você em projetar APIs estritas, enquanto que, naturalmente, o rigor é acompanhado de clareza e simplicidade.

Recomendamos que você leia esta minha questão , de um caso semelhante.

    
por 12.04.2016 / 10:41
fonte

Tags