[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":
- algoritmos fonéticos de correspondência de nomes ( Double Metaphone )
- algoritmos de distâncias de string ( distância de Levenshtein )
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.
Respostas:
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.
fonte
{"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.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.
fonte
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".
fonte
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.
fonte
Divido as interfaces em vários grupos (adicione mais se desejar):
A saída deve ser sempre rigorosa.
fonte
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.
fonte
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.
fonte
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.
fonte
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.
fonte
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:
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.
fonte