O foco desta pergunta: Alguns softwares executam "trabalho extra" para aumentar a chance de um resultado "eventualmente bem-sucedido / satisfatório", apesar de um ou mais erros internos no software, o que requer um tempo de execução mais longo quando esses erros ocorrem. Tudo isso acontece sem o conhecimento do usuário se o resultado foi bem-sucedido.
Definição de software complexo:
- Contém código gravado por (contribuído de) mais de 10 desenvolvedores durante sua vida útil e não gravado no mesmo período de tempo
- Depende de mais de 10 bibliotecas externas, cada uma com ressalvas
- Uma tarefa típica de software (para gerar um resultado desejado pelo usuário) requer 10 ou mais parâmetros de entrada, onde a maioria deles possui valores padrão, mas são configuráveis se o usuário precisar de controle.
- Mais importante, software que possui a complexidade apropriada em relação à tarefa que está sendo executada, ou seja, não é desnecessariamente complicado .
Editado: O que é complexo? Por favor, veja Há uma grande diferença entre Complexo e Complicado . (link direto)
Definição de redundância / robustez nesta pergunta :
(Robustez adicionada com base nos comentários)
- Se uma tarefa do software falhar quando o conjunto de parâmetros atual foi usado, tente parâmetros diferentes.
- Obviamente, deve haver conhecimento interno de que esses parâmetros "diferentes" usam um caminho de código diferente, possivelmente resultando em um resultado diferente (espero que melhor).
- Às vezes, esse caminho de código diferente é escolhido com base em observações das bibliotecas externas.
- No final, se a tarefa real realizada for ligeiramente diferente da especificação do usuário, o usuário receberá um relatório detalhando a discrepância.
- Finalmente, como os mais de 10 parâmetros configuráveis, a redundância e os relatórios também são configuráveis.
Exemplo de tal software:
- Migração de banco de dados
- Banco de dados de negócios
- Banco de dados de controle de origem, etc.
- Conversão em lote entre um documento do Word e um documento do OpenOffice, PowerPoint e OpenOffice Draw, etc.
- Tradução automática de um site inteiro
- Análise automática de pacote de software, como Doxygen, mas onde a análise precisa ser mais confiável (ou seja, não apenas uma ferramenta de documentação)
- Comunicação de rede, onde os pacotes podem ser perdidos e várias tentativas são esperadas
Esta questão foi originalmente inspirada em Como você lida com código intencionalmente incorreto?
mas agora está focado em apenas uma das causas do inchaço do software. Esta pergunta não aborda outras causas de inchaço do software, como a adição de novos recursos.
Possivelmente relacionado:
Respostas:
Esta é uma questão de negócios, não técnica.
Às vezes, eu estou codificando com pesquisadores ou em um protótipo, portanto, criaremos algo com muito baixa robustez. Se quebrar, nós consertamos. Não faz sentido investir em magia extra se jogarmos fora o código em breve.
Mas se os usuários do seu sistema precisarem ser robustos, você deve construí-lo dessa maneira. E você deve torná-lo robusto especificamente das maneiras que você e eles precisam para maximizar o sucesso a longo prazo, ignorando os tipos de redundância / robustez que eles não precisam.
Geralmente, começo com dificuldade e depois adiciono robustez ao longo do tempo. Frequentemente faço perguntas como essa parte do processo normal de planejamento. Geralmente trabalho no estilo Extreme Programming, onde fazemos uma longa lista de recursos desejados e também incluo recursos de robustez. Por exemplo, "O sistema sobrevive ao fracasso de uma única caixa", se confunde com coisas como "O usuário pode participar usando credenciais do Facebook". Qualquer que surgir primeiro, eu construo primeiro.
fonte
Software complexo normalmente é redundante como você provavelmente sabe, mas obviamente não porque é a melhor maneira de fazê-lo, mas porque os desenvolvedores tendem a "aderir" ao código existente, em vez de tentar entender detalhadamente como o software funciona.
No entanto, se você me perguntasse quanta redundância deve ser aceitável, eu não diria nenhuma. A redundância é um dos muitos efeitos colaterais da complexidade, a arquitetura da simplicidade. Indiscutivelmente, a simplicidade deve ficar em segundo plano se o tempo tiver maior importância, embora eu enfatize que aqueles que argumentam que o tempo é essencial são raramente aqueles que realmente se importam em desenvolver software. Geralmente, o gerente de projetos exige que você faça o trabalho o mais rápido possível, para poder voltar a questões mais urgentes; no entanto, é seu dever como programador saber quando o trabalho está concluído. Acho que o trabalho não está concluído até que você o tenha integrado com sucesso no programa como deveria ser. Talvez o programa seja complicado,
No entanto, deve-se dizer que, ao fazer isso, talvez seja necessário produzir código redundante. Se o projeto já é altamente redundante, pode ser realmente mais simples continuar o padrão, assumindo, é claro, que seu chefe não tem algumas semanas para matar, permitindo que você reestruture todo o projeto.
Edit: À luz da reformulação da pergunta, vou adicionar um pouco sobre robustez. Na minha opinião, a verificação de parâmetros deve ser feita apenas se A) você aceitar um formato muito específico, como um valor de data como uma string ou B), se vários parâmetros puderem entrar em conflito entre si ou forem mutuamente exclusivos.
Em A), os requisitos de que os parâmetros correspondem a um formato específico geralmente são críticos para a necessidade do método (como uma conversão para uma data de uma sequência de caracteres). Tecnicamente, isso ainda pode acontecer no seu programa sem que seja uma necessidade, mas eu encorajo fortemente você a eliminar essas possibilidades e aceitar apenas parâmetros que você sabe que representam o tipo de dados que você está procurando (aceite uma data em vez de uma sequência de caracteres se o O ponto não é converter, por exemplo, se a conversão também precisar ser feita, use um método utilitário para converter a sequência antes de passá-la para o método).
Quanto a B), parâmetros mutuamente exclusivos representam uma estrutura ruim. Deveria haver duas classes, uma que lida com um caso e outra que lida com isso de outra maneira. Todas as operações comuns podem ser feitas em uma única classe base para evitar redundância.
Nas situações em que o número de parâmetros de um método chega a ser 10 ou mais, começo a considerar um arquivo de propriedades que contém todos esses parâmetros que provavelmente não serão alterados com frequência. Se eles mudarem, você pode salvar o padrão no arquivo de propriedades e adicionar um método "setPropertyName ()" que permite substituir o padrão no tempo de execução.
fonte
O software deve perdoar os erros do usuário e completamente intolerante aos erros do programador.
Ou seja, o software deve ser muito robusto e permitir uma recuperação suave para coisas como erros de entrada do usuário e erros de configuração do sistema. No mínimo, uma mensagem de erro amigável informando onde ocorreu o erro (caixa de entrada, arquivo de configuração, argumento da linha de comando, etc ...) e que restrição foi violada ("deve ter menos de X caracteres", "as opções válidas são [X , Y, Z] ", etc ...) Para maior robustez, o software pode sugerir uma alternativa ou usar um padrão razoável (mas sempre deve indicar que não está usando exatamente o que o usuário especificou).
Não consigo pensar em muitas situações em que uma nova tentativa automática com padrões diferentes é justificada, mas existem algumas (a nova tentativa automática para estabelecer um link de comunicação parece razoável). Concordo com @William que este nível de 'redundância' é uma decisão de negócio.
Por outro lado, não deve haver robustez no tempo de execução contra erros do programador. Se houver pré-condições para os parâmetros de uma função, eles devem ser verificados com afirmações, não verificações em tempo de execução. É uma enorme angústia minha ver redundantes checagens e relatórios de erros no mesmo parâmetro três ou quatro níveis na pilha de chamadas:
Essa é apenas uma complexidade desnecessária adicional. Você não deve gastar tempo tentando descobrir como uma função deve lidar com um erro introduzido com o uso incorreto de outra. Se esse é o tipo de 'robustez' a que você está se referindo - você não precisa dele. Substitua-o por afirmações e testes de integração completos.
fonte
É uma coisa de requisitos.
Existe um requisito para robustez?
"Quando o link de comunicação falha, os pacotes incorretos são descartados" "Quando o link continua a operação, nenhuma transação é processada duas vezes"
deve haver casos de uso para recuperação de erros (caso contrário, como você sabe como isso vai acontecer?)
Deixar para os programadores inventarem robustez à medida que avançam (se necessário) resulta em sistemas "mágicos".
Todos os sistemas mágicos se tornam mágicas ruins com o tempo. A correção de erros em segundo plano oculta a ocorrência de falhas, para que as falhas não sejam corrigidas, e o sistema acabará se degradando para um estado de maior entropia; e corra como lixo, pois corrige erros o tempo todo. Você deve ter um limite para impedir que o sistema entre em um estado permanentemente degradado.
fonte
Algumas operações provavelmente justificam uma abordagem "tente novamente", especialmente se dependerem de recursos externos, como um banco de dados. Por exemplo, se um banco de dados não puder ser conectado ou uma consulta falhar, a operação poderá ser repetida várias vezes antes de desistir e lançar um erro para um nível superior. No entanto, em alguma lógica, tentar a mesma coisa várias vezes geralmente é um sintoma de código ruim e pensamento mágico que oculta problemas reais.
fonte