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

45

[Aviso: esta pergunta é subjetiva, mas eu preferiria 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:

Seja conservador no que você envia; seja liberal no que você aceita.

Concordo que, para o design de um protocolo de comunicação amplo, isso faça sentido (com o objetivo de permitir uma extensão fácil), no entanto, sempre achei que sua aplicação ao HTML / CSS era uma falha total, cada navegador implementando seu próprio ajuste silencioso detecção / comportamento, tornando quase impossível obter uma renderização consistente em vários navegadores.

Percebo, porém, que ali a RFC do protocolo TCP considera "Falha Silenciosa" aceitável, a menos que seja 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 morderam desenvolvedores, de cima para baixo:

  • Inserção de ponto e vírgula em Javascript
  • Conversões internas C (silenciosas) (que não seriam tão ruins se não fossem truncadas ...)

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 para ajudar os usuários no processo de recuperação de erros, apresenta algumas desvantagens quando aplicada ao design da interface da biblioteca / classes:

  • é um tanto subjetivo saber se o algoritmo adivinha "certo" e, portanto, pode ir contra o Princípio da Mínima Surpresa
  • torna a implementação mais difícil, portanto, mais chances de introduzir bugs (violação do YAGNI ?)
  • isso torna o comportamento mais suscetível a alterações, pois qualquer modificação na rotina de "suposição" pode interromper os programas antigos, quase excluindo as possibilidades de refatoração ... desde o início!

E foi isso 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 próprio tendem a ser bastante rigorosos, usando ampla validação de entrada em minhas interfaces, e fiquei pensando se talvez fosse muito rigoroso.

Matthieu M.
fonte
Gostaria de saber qual é a diferença entre HTML e dados gerais? O princípio da robustez é sobre comunicação. Um escreve - um lê. Por que a comunicação em rede é diferente da visual ou da API? Eu tenho um exemplo de API em que o princípio de ser liberal no que aceitamos simplifica a vida dos usuários que são programadores , reduz o tamanho do código e, portanto, melhora o desempenho + elimina bugs. Veja stackoverflow.com/questions/18576849
Val
@ Val: na verdade, seu exemplo não corresponde. "ser liberal no que você aceita" não é apenas uma questão de base / derivada, está indo além disso e também aceitando (e interpretando) dados levemente errôneos.
Matthieu M.
Como mostrar algum caso não mostra esse caso?
Val

Respostas:

34

Eu diria robustez quando não introduz ambiguidades .

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

Ao analisar um guia de string, ele deve aceitar qualquer número de formatos comuns (com ou sem hífens, 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 em que isso 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.

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

Davy8
fonte
1
Concordo que a robustez quando não custa muito vale a pena.
Matthieu M.
2
Até a lista separada por vírgula causa problemas, como: o mecanismo javascript do chrome e do firefox parece aceitar {"key": "value",}como válido, o IE não. Muitas vezes me deparei com esse problema em particular até melhorar meu processo de compilação com JSlint.
22411 keppla
2
@keppla é um problema de implementação e não de design. Não tenho certeza se isso é legal pela especificação javascript e o IE não está seguindo, ou se esse é um "recurso interessante" que o FF e o Chrome adicionaram, mas no Python é especificado para ser válido e implementado como tal. Se especificado como válido e não funcionar, é uma implementação defeituosa. Se não for especificado, não deve ser realmente confiável (embora, por uma questão de praticidade, se não funcionar em um navegador principal, também pode ser considerado que não está na especificação se você não controlar o usuário)
Davy8
7
@ Davy8: A vírgula à direita parece ilegal ( stackoverflow.com/questions/5139205/… ). Eu não quero confiar nisso, meu argumento é que, quando pessoas suficientes aceitam a entrada, ela se torna um padrão de fato (porque não se percebe que se trata de um erro), o que leva a algo que encontramos em HTML: que os erros tornam-se tão comuns que você não pode mais ignorá-las como insatisfação.
keppla
1
@keppla, isso deve estar falhando no moz e no Chrome. Como um desenvolvedor principalmente de JS, isso me irrita com isso (isso costumava acontecer no Moz, pelo menos). Isso torna a depuração mais difícil, não mais fácil. O IE está fazendo o que deveria fazer. Fail @ código incorreto. HTML é uma coisa. Não precisamos dessa porcaria em uma linguagem de script. É um exemplo de aplicação terrível do princípio Robust, que é algo em que os fornecedores de navegadores se destacam.
amigos estão dizendo sobre erik
15

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

A imensamente subestimada Writing Code Solid foi tremenda ao enfatizar repetidamente a necessidade e as técnicas de tornar os bugs tão difíceis de introduzir ou ocultar. Através da aplicação de seus princípios, como "Eliminar o comportamento aleatório. Força os bugs a serem reproduzíveis". e "Sempre procure e elimine falhas em suas interfaces". os desenvolvedores melhorarão enormemente a qualidade de seu software, eliminando a ambiguidade e os efeitos colaterais não controlados responsáveis ​​por uma grande quantidade de bugs.

Huperniketes
fonte
9

A aplicação excessiva de robustez leva a você adivinhar o que o usuário queria, o que é bom até você errar. Também requer a fé completamente equivocada de que seus clientes não abusarão de sua confiança e criarão jargões aleatórios que simplesmente funcionam, mas que você não poderá oferecer suporte na versão 2.

A aplicação excessiva de correção leva a que você negue a seus clientes o direito de cometer erros menores, o que é bom até eles reclamarem que suas coisas funcionam bem no produto do seu concorrente e dizer o que você pode fazer com o padrão de 5.000 páginas que tem a palavra O "DRAFT" ainda rabiscou a capa em giz de cera, e pelo menos três especialistas afirmam ter falhas fundamentais e mais 200 especialistas honestos dizem que não entendem completamente.

Minha solução pessoal sempre foi preterida. Você os apoia, mas diz que eles estão fazendo errado e (se possível) o caminho mais fácil para a correção. Dessa forma, quando você desativa o recurso de bug dez anos depois, você tem pelo menos a pista do papel para afirmar que "nós o avisamos que isso pode acontecer".

Deworde
fonte
+1 por descontinuação , é realmente um conceito importante e estou surpreso que tenha sido negligenciado até agora.
Matthieu M.
9

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

O navegador deve simplesmente exibir uma mensagem de erro em vez de tentar corrigi-la debaixo das cobertas. Isso teria forçado todos os assaltantes a arrumar sua bagunça.

ThomasX
fonte
Citando a mim mesmo (deve estar ficando velho): "no entanto, sempre achei que sua aplicação ao HTML / CSS era um fracasso total"
Matthieu M.
3
É verdade, mas a mesma tolerância a falhas também ajudou a tornar a Web tão popular.
MaR
Os fornecedores do navegador falharam nesse. Com os doctypes, tivemos a capacidade de fazer nossa própria escolha nesse sentido, mas no final do dia tudo acabou se comportando da mesma maneira, desde que você tenha declarado qualquer tipo de documento. Agora eles acham que um conjunto hiper-complexo de regras exigentes a seguir em relação a como lidar com falhas é a solução? Eu acho que eles não estão conseguindo identificar o problema.
Erik Reppen
Você está dizendo que o fail-fast, que é o oposto de "robusto", é mais eficiente.
Val
@MaR: é isso mesmo? Muito disputável, muito mais provável que os recursos fossem importantes.
Deduplicator
6

Divido as interfaces em vários grupos (adicione mais se desejar):

  1. aqueles que estão sob seu controle devem ser rigorosos (classes normalmente)
  2. APIs de biblioteca, que também devem ser estritas, mas recomenda-se uma validação extra
  3. interfaces públicas que devem lidar com todos os tipos de abuso que ocorrem (normalmente protocolos, entradas do usuário etc.). Aqui a robustez na entrada realmente compensa, você não pode esperar que todo mundo conserte suas coisas. E lembre-se, para o usuário, a culpa será sua se o aplicativo não funcionar, não a parte que enviou uma porcaria mal formatada.

A saída deve ser sempre rigorosa.

MaR
fonte
5

Penso que o HTML e a World Wide Web forneceram um teste em larga escala do Princípio da Robustez no mundo real e mostraram que é um fracasso maciço. Ele é diretamente responsável pela confusão confusa dos padrões HTML quase concorrentes, que tornam a vida miserável para desenvolvedores da Web (e seus usuários) e piora a cada nova versão do Internet Explorer.

Sabemos desde a década de 1950 como validar o código corretamente. Execute-o através de um analisador rigoroso e, se algo não estiver sintaticamente correto, gere um erro e aborte. Não passe, não colete US $ 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 seus erros e não repeti-los.

Mason Wheeler
fonte
4
@ ChaosPandion: acho que o problema não está no próprio Internet Explorer, mas em todas as páginas da web não-padrão que foram aceitas pelas versões anteriores e com as quais todos agora têm que conviver ... e tentar acomodar com mais ou menos sucesso.
Matthieu M.
5
Na verdade, acho que a equipe do IE está na pior posição possível de todos os desenvolvedores de navegadores. Joel resume muito bem meus pensamentos .
Dean Harding
3
Isso pode ter tornado a vida miserável para desenvolvedores e designers, mas então ficaríamos presos a um padrão estático e em evolução muito lenta - duvido que a Web seja como agora. Os verdadeiros vencedores são as pessoas que navegam na web e, no final das contas, são as pessoas que contam.
FinnNk
4
Além disso, embora o princípio da robustez possa dificultar a vida dos desenvolvedores da Web, é difícil chamar a World Wide Web (agora parte integrante de quase todas as principais instituições do planeta) um enorme FAILURE .
deworde
3
"Sabemos desde a década de 1950 como validar o código corretamente. Execute-o através de um analisador rigoroso e, se algo não estiver sintaticamente correto, gere um erro e aborte". Para aplicar isso a um cenário do mundo real: se eu estraguei um único ícone na extremidade direita da minha página logo abaixo do corte, desistir de toda a página é uma ótima maneira de enviar alguém procurando em outro lugar, por causa de um problema que eles nem teriam notado. Sim, você pode argumentar que eu não deveria ter cometido o erro. Mas isso pressupõe que eu ainda não fui ao seu concorrente mais robusto e não estou mais atendendo às suas ligações.
deworde
3

Como um contraponto ao exemplo de Mason, minha experiência com o Session Initiation Protocol foi que, embora pilhas diferentes interpretassem as RFCs relevantes de maneira diferente (e eu suspeito que isso aconteça com todos os padrões já escritos), ser (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 oposição a partes de software em um desktop, você simplesmente precisa ser liberal no que aceita ou o telefone não pode ligar para outro telefone de uma determinada marca. Isso não faz o seu telefone parecer bom!

Mas se você estiver escrevendo uma biblioteca, provavelmente não terá o problema de várias partes interpretarem um padrão comum de maneiras incompatíveis. Nesse caso, eu diria ser rigoroso no que você aceita, porque remove ambiguidades.

O Jargon File também tem uma história de horror sobre "adivinhar" a intenção do usuário.

Frank Shearar
fonte
História muito divertida :) Sei que você pode precisar de mais liberdade ao tentar interagir com os sistemas existentes, pois, se não funcionar, você será responsabilizado.
Matthieu M.
De fato, se o seu telefone não funcionar com a maioria dos outros telefones, ele está com defeito .
SamB 28/03
1
@ SamB: Substitua ruim por quebrado .
deworde
3

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

Portanto, ao projetar uma API, eu diria que não segue o Princípio da robustez. Se o desenvolvedor cometer um erro, ele deve descobrir imediatamente. Obviamente, se sua API usa dados de uma fonte externa, como um arquivo, você deve ser indulgente. O usuário da sua biblioteca deve descobrir seus próprios erros, mas não os de outras pessoas.

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

Nota para pensar em um nome
fonte
1
"Se você digitar um erro de digitação durante a programação, receberá um erro assim que compilar". Apresento a milhões de AVISOS do compilador que um compilador padrão cuspirá, enquanto ainda produz tarefas perfeitamente executáveis.
deworde
1

Na IMO, a robustez é um lado de um compromisso de design, não um princípio de "preferência". Como muitos apontaram, nada fede como explodir quatro horas tentando descobrir onde seu JS deu errado, apenas para descobrir o problema real, apenas um navegador fez a coisa correta com o XHTML Strict. Ele deixou a página em pedaços quando uma parte do HTML exibido foi um desastre completo.

Por outro lado, quem deseja procurar na documentação um método que use 20 argumentos e insiste que eles estejam exatamente na mesma ordem com espaços reservados vazios ou nulos para os que você deseja pular? A maneira igualmente terrível e robusta de lidar com esse método seria verificar todos os argumentos e tentar adivinhar qual deles era baseado em posições e tipos relativos e depois falhar silenciosamente ou tentar "se contentar" com argumentos sem sentido.

Ou você pode aumentar a flexibilidade do processo, passando uma lista de pares de objetos literal / dicionário / valor-chave e manipular a existência de cada argumento à medida que o obtém. Para uma troca muito pequena de perf, isso é um bolo e também comemos.

Sobrecarregar argumentos de maneira inteligente e consistente em interface é uma maneira inteligente de ser robusto quanto às coisas. O mesmo ocorre com a redundância em um sistema em que se supõe que a entrega de pacotes falhe regularmente em uma rede extremamente complicada, de propriedade e administrada por todos em um campo emergente de tecnologia com uma ampla variedade de possíveis meios de transmissão.

Tolerar falhas abjetas, no entanto, especialmente dentro de um sistema que você controla, nunca é uma boa escolha. Por exemplo, eu tive que tomar um fôlego para evitar um chiado em outra pergunta sobre colocar JS na parte superior ou inferior da página. Várias pessoas insistiram que era melhor colocar JS no topo, porque, se a página falhar ao carregar completamente, você ainda terá alguma funcionalidade. As páginas com metade do trabalho são piores que bustos completos. Na melhor das hipóteses, eles resultam em mais visitantes no seu site, assumindo com razão que você é incompetente antes de descobrir sobre ele do que se a página interrompida for simplesmente devolvida para uma página de erro ao falhar em sua própria verificação de validação, seguida por um e-mail automático para alguém que pode fazer algo sobre isso.

Tentar entregar a funcionalidade 2010 em um navegador de 1999, quando você poderia apenas fornecer uma página de tecnologia inferior, é outro exemplo de uma troca imprudente de design. As oportunidades desperdiçadas e o dinheiro que vi desperdiçado com o tempo do desenvolvedor gasto em soluções alternativas, apenas para obter cantos arredondados em um elemento pairando acima de um fundo gradiente! @ # $ Ing, por exemplo, me surpreenderam completamente. E para quê? Fornecer páginas de alta tecnologia com desempenho baixo a tecnofóbicos comprovados, limitando suas escolhas em navegadores de ponta.

Para que seja a escolha certa, a opção de lidar com os dados de maneira robusta deve sempre facilitar a vida dos dois lados do problema, na IMO de curto e longo prazo.

Erik Reppen
fonte
4
"para um método que leva 20 argumentos"> não há necessidade de procurar mais, depois de 5/6 o método está errado . Obrigado pela resposta embora :)
Matthieu M.
1

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

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

  1. Sua biblioteca deve ser projetada de maneira 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, nomeação clara / direta, tente inferir o que o usuário pretendia.

De qualquer forma, não é 100% óbvio e determinístico, que uma entrada deva ser convertida em outra; você não deve fazer as conversões por vários motivos já mencionados (quebra de compatibilidade na refatoração, menor espanto dos usuários).

Ao lidar com um usuário final, tentar corrigir sua entrada / palpite é muito bem-vindo. Ele deve inserir informações inválidas; Neste caso, é completamente não excepcional. Outro desenvolvedor, no entanto, não é um usuário não técnico simples. Ele tem o conhecimento necessário para entender um erro, e o erro pode ter significado / ser benéfico para ele. Portanto, concordo com você no design de APIs rigorosas, enquanto, é claro, o rigor é acompanhado por clareza e simplicidade.

Eu recomendaria que você lesse esta minha pergunta , de um caso semelhante.

K. Gkinis
fonte