Estou falando de mais de 20 a 30 milhões de linhas de código, software na escala e complexidade do Autodesk Maya, por exemplo.
Se você congelar o desenvolvimento pelo tempo que for necessário, será possível consertar todos os bugs até que simplesmente não haja um único bug, se isso puder ser verificado por computadores? Quais são os argumentos a favor e contra a existência de um sistema livre de erros?
Porque existe alguma noção de que toda correção que você cria cria mais bugs, mas não acho que isso seja verdade.
Por bugs, eu quis dizer desde os erros mais simples na interface do usuário, até erros preventivos mais sérios que não têm solução alternativa. Por exemplo, uma função de script específica calcula valores normais incorretamente. Além disso, mesmo quando existem soluções alternativas, o problema ainda precisa ser corrigido. Então, você poderia dizer que pode fazer isso em particular manualmente, em vez de usar a função fornecida, mas essa função ainda precisa ser corrigida.
fonte
Respostas:
Como Mikey mencionou, escrever código sem erros não é o objetivo. Se é isso que você está buscando, então eu tenho más notícias para você.
O ponto principal é que você está subestimando enormemente a complexidade do software.
Primeiras coisas primeiro - você está ignorando a imagem maior de como seu programa é executado. Não é executado isoladamente em um sistema perfeito. Até o mais básico dos programas "Hello World" é executado em um sistema operacional e, portanto, até o mais simples é suscetível a erros que possam existir no sistema operacional.
A existência de bibliotecas torna isso mais complexo. Enquanto os sistemas operacionais tendem a ser razoavelmente estáveis, as bibliotecas são uma mistura de coisas quando se trata de estabilidade. Alguns são maravilhosos. Outros ... nem tanto ... Se você deseja que seu código seja 100% livre de bugs, também será necessário garantir que todas as bibliotecas nas quais você executa sejam completamente livres de bugs, e muitas vezes isso simplesmente não é possível. você pode não ter o código fonte.
Depois, há tópicos em que pensar. A maioria dos programas de larga escala usa threads em todo o lugar. Tentamos ser cuidadosos e escrever threads de maneira que as condições de corrida e o impasse não ocorram, mas simplesmente não é possível testar todas as combinações possíveis de código. Para testar isso efetivamente, você precisaria examinar todas as ordens possíveis de comandos passando pela CPU. Ainda não fiz as contas, mas suspeito que enumerar todos os possíveis jogos de xadrez seria mais fácil.
As coisas vão do difícil ao impossível quando olhamos para a própria máquina. CPU's não são perfeitos. RAM não é perfeita. Discos rígidos não são perfeitos. Nenhum dos componentes de uma máquina é projetado para ser perfeito - eles são projetados para serem "bons o suficiente". Mesmo um programa perfeito acabará por falhar devido a um soluço da máquina. Não há nada que você possa fazer para impedir isso.
Bottom line: Você pode escrever "software livre de erros"?
NÃO
Quem lhe disser o contrário não tem noção.
Apenas tente escrever um software fácil de entender e manter. Depois de fazer isso, você pode encerrar o dia.
EDIT: Algumas pessoas comentaram sobre um ponto excelente que eu havia esquecido completamente: o compilador.
A menos que você esteja escrevendo em assembly, é perfeitamente possível que o compilador atrapalhe seu código (mesmo se você provar que seu código é "perfeito").
Uma lista de bugs no GCC, um dos compiladores mais usados: http://gcc.gnu.org/bugzilla/buglist.cgi?product=gcc&component=c%2B%2B&resolution=---
fonte
It is important to note, however, that even all of these steps provide no guarantee of absolute security. It is tempting to believe that a formally specified and proved program should be absolutely correct, but there are several reasons why a proved program may not behave exactly as expected.
- o que significa que não se pode provar que está livre de bugs, mas sim, menos provável que tenha bugs. Um pouco como TDD.Matematicamente, PODE ser possível escrever um software 'sem erros' de tal complexidade, dependendo de como você define 'erros'. Provar que PODE também ser matematicamente possível, projetando um sistema de teste que exercite todas as linhas de código de todas as maneiras possíveis - todos os casos de uso possíveis. Mas não tenho certeza - se você estiver lidando com um sistema que faz cálculos complexos, pode encontrar um 'problema do infinito' ...
Na prática, em um sistema do tamanho e escopo dos quais você está falando, isso é IMPOSSÍVEL . Pode levar mil anos para escrever um sistema 'livre de bugs', e escrever um sistema para provar que levaria exponencialmente mais tempo: você teria que criar todos os casos de uso possíveis e escrever um sistema que testasse cada um - e não acredito que exista uma maneira de determinar se você realmente cobriu todos os casos de uso em um sistema do tamanho e escopo dos quais você está falando em algo semelhante a um período de tempo razoável.
OMI sua pergunta é um pouco mal direcionada: Nosso objetivo como desenvolvedores não é escrever software 'sem erros'. Nosso objetivo é escrever um software utilizável, flexível e fácil de manter .
Utilizável: O sistema atende aos requisitos essenciais para os quais foi projetado. Pode haver erros - mas eles estarão em "casos extremos" - discrepâncias ou aborrecimentos, não erros que comprometam os fundamentos do sistema - robustos.
Manutenção: Os erros podem ser facilmente isolados e corrigidos e NÃO crie novos erros.
Flexível: seu sistema é fácil de mudar e expandir sem redesenho e tempo de inatividade significativos: a maioria das alterações exige simplesmente a adição de uma nova classe ou módulo que se encaixa nos padrões e na estrutura já bem projetados.
Boas práticas de design, boas práticas de controle, bom trabalho em equipe, desenvolvedores conscientes - essa é a fórmula para o BOM SOFTWARE . (não PERFEITO - mas BOM )
fonte
De acordo com este artigo, o software de bordo do Ônibus Espacial chegou muito perto - as últimas três versões do programa de 420.000 linhas tiveram apenas um erro cada. O software foi mantido por um grupo de 260 homens e mulheres. Um grande número dessas pessoas eram verificadores, cujo único objetivo era encontrar erros.
A atualização do software para permitir que o ônibus navegue com os satélites de posicionamento global impactou apenas 1,5% do programa, ou 6.366 linhas de código. As especificações para essa alteração rodavam 2.500 páginas. As especificações para o programa geral preencheram 30 volumes e executaram 40.000 páginas, ou uma média de dez linhas de código por página das especificações.
O orçamento não era um problema - com US $ 35 milhões por ano, eles podiam se dar ao luxo de fazer as coisas corretamente.
fonte
Essencialmente, não, mas você deve fazer o seu melhor de qualquer maneira. Vou explicar o porquê (ou pule para a conclusão, se você não tiver paciência suficiente)
Considere um problema tão trivial quanto a implementação da pesquisa binária. Uma implementação muito popular teve um bug que não foi detectado por cerca de duas décadas. Se vinte linhas levam vinte anos para que o uso livre de bugs seja amplamente utilizado e até supostamente correto, podemos realmente esperar que um programa enorme seja livre de bugs?
Quantos erros podemos esperar que um programa enorme tenha? Um número que encontrei foi "10 defeitos por 1000 linhas" (Code Complete 2nd edition, página 517 - apenas usou um exemplo, sem citar dados). Isso nos dá de 200.000 a 300.000 erros no seu software. Felizmente, temos maneiras de melhorar a qualidade do programa. Testes de unidade, revisões de código e testes manuais comuns são conhecidos por reduzir o número de bugs. Ainda assim, o número ainda será alto.
Se pudéssemos resolver 95% de todos os erros, isso seria incrível. E ainda teríamos de 10.000 a 15.000 bugs no software.
Felizmente, como o software é amplamente utilizado (e, portanto, amplamente testado), serão encontrados erros. Então, gradualmente teremos menos bugs. No entanto, menos erros também significam que os restantes são mais difíceis de encontrar - portanto, não espere uma curva linear na correção de erros. Os últimos erros vai ser muito complicado encontrar e poderia escapar à detecção por vários anos (assumindo que eles estão sempre encontrado).
Você também parece estar assumindo erroneamente que, se o software não mudar, nenhum novo erro será exibido. Se o software depender de bibliotecas de terceiros, novas versões poderão quebrar alguns recursos - introduzindo novos erros, mesmo que o código do aplicativo ainda seja o mesmo. Novos sistemas operacionais também podem interromper um aplicativo que funcionava perfeitamente perfeitamente (consulte o Windows Vista para obter um exemplo popular). Considere também erros do compilador, etc.
Não está claro se as ferramentas à prova de código podem realmente resolver o problema do software de buggy. Certamente não é possível resolver o problema de interrupção de nenhum programa, mas pode ser possível provar que um programa se comporta conforme especificado ... Mas e daí? Talvez o programa de provas tenha um bug. Talvez a especificação em si tenha um erro.
Claramente, podemos reduzir bastante o número de bugs, mas é muito improvável que cheguemos a zero.
(enfase adicionada)
Você está certo. Esta afirmação está errada. Aqui está um exemplo:
Agora, vamos corrigir este bug:
Vejo? Corrigimos um erro e não introduzimos novos.
No entanto, é certamente correto que toda vez que você conserte um erro, arrisque criar um novo, embora esse risco possa ser mitigado (por exemplo, com testes de unidade).
Digamos que, para cada 100 bugs corrigidos, introduzo acidentalmente um novo. Portanto, se eu corrigir 10.000 erros, apresento 100 novos erros. E se eu corrigir esses novos erros, apresento um erro. Mas e daí? O programa agora possui 9.999 bugs a menos, então provavelmente é melhor do que era (assumindo que o novo bug não seja 10.000 vezes pior que os anteriores).
Além disso, a correção de um bug pode expor novos. Mas esses erros também podem ser corrigidos. Se você fizer as coisas corretamente, eventualmente o software estará em um estado melhor do que o iniciado.
Esse comportamento é negligente. Se houver um erro e você pode corrigi-lo. Faça. É claro que você deve fazer o possível para evitar a adição de novos, mas se eu apresentar um pequeno bug para cada 10 erros graves que eu corrigir, esse não é um motivo válido para parar de corrigir erros. De fato, é uma boa razão para continuar corrigindo bugs .
Quanto menos erros você consertar, mais erros permanecerão no seu software, incomodando os usuários. De fato, eles não "voltarão para você no futuro". Eles não vão voltar porque nunca foram embora. A noção de "voltar" está relacionada a regressões. Novamente, é possível reduzir o risco de regressões.
Alguns bugs não podem ser corrigidos porque se tornaram tão amplamente utilizados que as pessoas começaram a depender deles e a correção do bug interromperia o programa para esses usuários. Acontece. No entanto, eles podem realmente ser considerados erros nesse caso?
A mentalidade "conserte um bug, faça um bug" pode estar relacionada ao monstro horrível - código que é tão ilegível e impossível de manter que apenas tocá-lo cria bugs. Se você tem um monstro em sua base de código, pode ser necessário desmonstrificá-lo antes de fazer qualquer coisa.
Finalmente, se você é um péssimo programador, existe o risco de que qualquer coisa que você toque crie novos bugs. Obviamente, isso deixaria programadores seniores nervosos. No entanto, dizendo "Não faça nada. Não toque em nada. Nem respire". provavelmente não é o caminho certo para criar um ambiente de trabalho saudável. A educação é melhor.
Conclusão:
fonte
As razões para não escrever programas sem erros são principalmente econômicas.
Não são métodos matemáticos para provar a correção de um programa. Em um curso de alta qualidade em Ciência da Computação, eles serão mencionados. Existem linguagens de programação inventadas especialmente para esse fim. Em teoria, é possível programar sem bugs .
Sim, existe o hardware imperfeito que às vezes pode mudar um pouco, porque um neutrino disparou de uma supernova distante milhões de anos atrás, por acaso, atingiu seu processador no lugar certo. Ok, toda teoria tem suas suposições e abstrações. Mas, supondo que o processador funcione como anunciado, existem ferramentas matemáticas para garantir que o programa funcione corretamente também.
Algumas respostas altamente votadas neste tópico são enganosas. Por exemplo, o teorema da incompletude de Gödel e o problema de parada implicam apenas que você não pode ter, por exemplo, uma ferramenta automatizada que decida a correção ou a incorreção de qualquer programa. Mas não queremos decidir a correção de nenhum programa, queremos apenas uma prova de correção de um programa específico .
(Analogicamente, apenas porque você não pode escrever um programa para decidir automaticamente a verdade de qualquer teorema matemático, isso não significa que você não pode provar um teorema matemático específico .)
O problema, em vez disso, é este:
Embora seja teoricamente possível escrever um programa sem erros, isso seria muito caro . Escrever um código com uma prova de sua correção é mais complicado do que simplesmente jogar algo em uma parede para ver se ele fica preso. Mesmo se "ver se está preso" for feito por testes de unidade; e muitos programadores nem se importam em fazer isso. A maioria dos programadores nem sabia como fazer isso, o que significa que, como empresa, você teria que contratar empresas mais caras.
Considerando todos os custos, um cliente típico fica mais satisfeito com um software barato que funciona bem 99% das vezes (e 99,9% do tempo após a instalação de atualizações adicionais) do que ter um software talvez mil vezes mais caro que funciona bem com 100% das vezes. A Hora. Além disso, o cliente deseja ter esse software agora , e não em dez ou vinte anos.
Portanto, as pessoas produzem conscientemente um software que tem alguma chance de erros, tentando atingir a combinação ideal em que os erros não são muito frequentes nem muito graves, e a produção é rápida o suficiente e barata o suficiente. A combinação que oferece mais lucro na vida real. (Às vezes, significa até lançar um software cheio de bugs antes que seus concorrentes lançem algo, e apenas lançar uma versão mais decente 2.0 quando seus concorrentes estiverem prontos para lançar sua primeira versão decente.)
Matematicamente falando, você poderia. Economicamente falando, por que alguém faria isso? Isso significaria gastar talvez vinte anos e alguns milhões de dólares. Enquanto isso, os clientes desejam novos recursos e seus aplicativos congelados não podem fornecê-los. Portanto, no momento em que sua versão perfeita estiver pronta, o mercado já estará ocupado por seus concorrentes.
Raciocinar economicamente é bom. Vivemos em um mundo onde dinheiro e tempo importam. Mas apenas porque não fazemos algo por razões econômicas, não devemos falar bobagens sobre como isso não pode ser feito, nem mesmo na teoria. Quem sabe ... talvez em alguns anos teremos algumas novas linguagens de programação e ferramentas que possam tornar correção provando fácil .
fonte
Não.
David Hilbert propôs seu segundo problema de matemática em 1900, que essencialmente pediu ao mundo para provar que a aritmética funcionava como pretendido. Mais tarde, ele propôs " o problema de Entscheidung ", que pedia algo semelhante em termos lógicos. O " primeiro teorema da incompletude " de Kurt_Gödel provou em 1931 que nenhuma teoria da aritmética elementar podia ser consistente e completa. A representação de Alan Turing do problema do Entscheidung como " o problema da parada " levou a questão diretamente ao cerne dessa questão, onde ele provou que é impossível provar se um programa será executado ou não. Dado que a indeciabilidade, também é impossível provar se um programa tem algum erro ou não.
Nada disso liberta os programadores praticantes entre nós de lutar por nenhum erro. Significa apenas que não podemos ter sucesso em geral.
fonte
int main() { return 0; }
Parada de forma trivial e sem erros.Errare humanum est
Mesmo se você escrever código com uma linguagem formal, como o método B , que você pode usar para provar matematicamente que os requisitos são atendidos,
Mesmo se você usar uma linguagem formal de especificação,
Sempre existe uma etapa humana que consiste em extrair as necessidades do usuário de um ou mais cérebros para um computador.
Este passo humano é propenso a erros, e o verme está na maçã.
fonte
Uma proporção justa dos "bugs" que encontrei pode ser mais adequadamente descrita como incompatibilidade entre o design do sistema e a expectativa do cliente.
Agora, se nós chamamos esses bugs ou não, é acadêmico, mas o fato é que uma boa parte do trabalho de manutenção surge como resultado direto da comunicação imperfeita e da mudança nas expectativas dos clientes.
Mesmo que um sistema seja tecnicamente comprovadamente "correto" no sentido de atender a uma especificação (por mais improvável que isso possa ser para o software comercial do mundo real), você ainda terá o problema de corresponder a função do software à sempre atendida pelo cliente. expectativas mutáveis e mal definidas.
Em resumo:
Não.
fonte
Se você tiver uma especificação suficientemente rígida e restrita, poderá provar um programa sem erros, mas apenas com base em suposições não comprováveis sobre o funcionamento correto de tudo o mais no sistema. Isso deixa claro que não há como provar que as especificações seriam consideradas corretas por quem colocou o problema original ou por quem estava usando o serviço.
fonte
Achei a seção No Bugs, de Jim Shore, uma leitura muito útil sobre esse tópico. A forma abreviada: não é possível desenvolver sem produzir bugs - mas podemos trabalhar de maneira a detectá-los o mais cedo possível.
Durante a produção do próprio código. Por exemplo, escrevendo e executando testes de unidade com freqüência durante o desenvolvimento, garantimos constantemente que o código faz o que deve fazer. Além disso, é útil reescrever perpetuamente o código existente de forma a expressar mais claramente o comportamento pretendido do sistema.
No seu caso, no entanto, você está falando de uma base de código já existente com milhões de linhas de código. Se você deseja obter um bug desse sistema livre, primeiro precisa saber o que "é um bug" para este sistema. Você pode escrever conjuntos de testes post-hoc, garantindo a funcionalidade do sistema (se ainda não existir). A rede desses testes pode servir como uma definição aproximada para o comportamento correto do sistema. Mas quanto mais código você tiver, mais esforço será envolvido nesses exercícios. Portanto, a maioria das empresas faz um compromisso: elas vivem com o imperfeito, trabalhando com listas de bugs e manutenção para obter os bugs mais irritantes do sistema.
fonte
Sobre a verificação por parte do computador.
Existem duas maneiras de verificar um programa usando um computador. Um está testando, o outro está usando o sistema de prova.
Assim que testes exaustivos não são possíveis, os testes se tornam incapazes de mostrar que um programa não possui bugs, apenas que possui alguns. (E você tem o problema de mostrar que seus próprios testes não estão testando a presença de erros).
Para usar um sistema de prova, você começa com requisitos formais (e eles próprios podem ter erros, espero que a linguagem usada para os requisitos seja mais adequada para se convencer de que não há erros do que com uma linguagem de programação) e construa / prove com a ajuda dos sistemas de prova de que o programa está livre de bugs (e há a questão de bugs nos sistemas de prova, mas eles se mostraram corretos). O estado da arte atual é um compilador para um subconjunto C (e o subconjunto não é acadêmico ", o CompCert suporta todo o subconjunto MISRA-C 2004 de C, além de muitos recursos excluídos pelo MISRA").
fonte
Não, porque o ambiente de computadores e software em que o aplicativo é executado continuará sendo alterado, mesmo enquanto o código estiver congelado. O sistema operacional continua a evoluir com correções e correções, além dos dispositivos e drivers. Apenas quando você acha que atingiu o ponto de nenhum erro conhecido, a AMD ou a nVidia lançam uma atualização de driver de vídeo que afeta a maneira como você interage com o subsistema de vídeo. Agora, seu aplicativo tem defeitos visuais (como piscar, piscar ou reduzir a taxa de quadros) para clientes que possuem uma determinada placa de vídeo ou configuração (SLI? LOL).
Além do hardware e do sistema operacional, também existem vários produtos de middleware sob os aplicativos mais significativos que também evoluirão além do seu controle e, assim como você coloca seu código em um defeito zero, declara as camadas abaixo de EOL.
A tecnologia evolui, assim como os negócios que a alavancam, e a idéia de "liberar" o código não é possível ou viável. A empresa que solicita um novo conjunto de recursos não responde bem a "temos o código bloqueado enquanto perseguimos todos os erros conhecidos e ninguém relata um defeito de software válido em X meses". Mesmo que a empresa compre essa linha, após X meses, eles perguntarão como os novos recursos estão chegando, e a resposta não pode ser "decidimos estender o congelamento porque a Oracle acabou de lançar um patch e precisamos levar X mais meses para certificar isso ".
Não, em algum momento a empresa procurará uma equipe de desenvolvimento mais flexível que suporte a necessidade de avançar na velocidade da tecnologia. Esse é o problema fundamental que as equipes de desenvolvimento modernas enfrentam.
fonte
Sim, mas você nunca saberá com certeza. Quanto mais você olhar, mais você encontrará. Quanto mais pesado o sistema é usado e mais caixas de aresta são usadas, mais provável você encontrará outra incompatibilidade com a intenção ou especificação original. Isso implica que um bug em si não é uma coisa exata e geralmente dependerá da interpretação, de quão ruim alguém avalia uma anomalia percebida.
É uma coisa confusa. Poucos sistemas são especificados até o último bit. Se um sistema funcionar bem e os usuários não tiverem reclamações (eles não foram corrigidos por nada) e estiverem totalmente adaptados a ele, você também pode chamá-lo sem erros.
fonte
É possível fornecer consistentemente software livre de erros, com disciplina suficiente e cultura de equipe compartilhada. (E código modular bem fatorado, um conjunto abrangente de testes automatizados, inspecionando defeitos e adaptando seu processo, e muitas outras coisas que exigem esforço e humildade, mas pagam mil vezes mais)
Mas, ao fazer isso, geralmente você não pretende construir um sistema de 20 MLOC. Se escrever um código sem erros não é o seu objetivo, também não deve criar um sistema de muitos MLOC.
Meu próprio raciocínio é o seguinte:
Alguma pessoa tem uma necessidade a cumprir. Alguma pessoa (possivelmente a mesma, possivelmente outra) tem um orçamento para atender à necessidade através da criação de software. Todas essas pessoas esperam obter algum benefício pelo seu dinheiro.
A pessoa com um orçamento pagará a algumas pessoas (possivelmente as mesmas, possivelmente diferentes) chamadas de programadores , para que esses programadores transformem parte do tempo acordada em software que atenda à necessidade.
Portanto, esses programadores trabalham para transformar o dinheiro de outra pessoa em software que atenda à necessidade. É sua responsabilidade colocar esse dinheiro em bom uso.
Isso tem as seguintes implicações em relação à sua pergunta:
É tudo sobre o dinheiro, e com razão.
fonte
Sim.
Mas, como você sabe, exige muito esforço para valer a pena.
Antes que eu possa defender minha resposta, precisamos primeiro definir o que é um erro:
Agora, como você já sabe, as boas arquiteturas de software são modulares, para que cada módulo possa ser testado em unidade (ou manualmente, ou o que for) individualmente. Através da disciplina e testes cuidadosos, é possível escrever módulos individuais que não possuem bugs.
"Mas espere!" Eu ouço você protestar: "E se um comportamento inesperado (mas ainda assim correto) de um módulo causar um bug em outro?" Então o bug está no segundo módulo. Os módulos sem erros podem ser tratados como APIs, e as APIs, como você sabe, exigem algum cuidado para serem usadas corretamente.
Escrever código à prova de balas exige amplo conhecimento de casos extremos e lógica de fluxo por parte do desenvolvedor, e a maioria dos desenvolvedores de software não é inteligente o suficiente para aprender ou simplesmente não se importa. Ou, mais frequentemente, eles estão dentro de um prazo.
"Mas me dê um lugar para ficar, e eu mudarei o mundo." - Arquimedes
fonte