Descobri recentemente o Design by Contract (DbC) e considero uma maneira extremamente interessante de escrever código. Entre outras coisas, parece oferecer:
- Melhor documentação. Como o contrato é a documentação, é impossível ficar desatualizado. Além disso, como o contrato especifica exatamente o que uma rotina faz, ajuda a dar suporte à reutilização.
- Depuração mais simples. Como a execução do programa para no momento em que um contrato falha, os erros não podem se propagar e a asserção específica violada será presumivelmente destacada. Isso oferece suporte durante o desenvolvimento e a manutenção.
- Melhor análise estática. DbC é basicamente apenas uma implementação da lógica Hoare, e os mesmos princípios devem ser aplicados.
Os custos, em comparação, parecem ser bastante pequenos:
- Digitação extra com os dedos. Desde que os contratos têm que ser explicitados.
- É necessário algum treinamento para se sentir confortável com a redação de contratos.
Agora, familiarizando-me principalmente com o Python, percebo que é de fato possível escrever pré-condições (apenas lançando exceções para entrada inadequada) e é ainda possível usar asserções para testar novamente certas pós-condições. Mas não é possível simular certos recursos, como 'antigo' ou 'resultado', sem alguma mágica extra que seria considerada não-pitonica. (Além disso, existem algumas bibliotecas que oferecem suporte, mas, no final das contas, entendi que seria errado usá-las, como a maioria dos desenvolvedores não.) Suponho que seja um problema semelhante para todos os outros idiomas (exceto, é claro) Eiffel).
Minha intuição me diz que a falta de apoio deve ser resultado de algum tipo de rejeição da prática, mas a pesquisa on-line não foi proveitosa. Gostaria de saber se alguém pode esclarecer por que a maioria das linguagens modernas parece oferecer tão pouco apoio. O DbC é defeituoso ou muito caro? Ou é apenas obsoleto devido à programação extrema e outras metodologias?
fonte
Respostas:
Indiscutivelmente, eles são suportados em praticamente todas as linguagens de programação.
O que você precisa são "afirmações".
Estes são facilmente codificados como "if":
Com isso, você pode escrever contratos colocando essas afirmações no topo do seu código para restrições de entrada; aqueles nos pontos de retorno são restrições de saída. Você pode até adicionar invariantes em todo o seu código (embora não faça parte do "design by contract").
Então, eu argumento que eles não são comuns porque os programadores são muito preguiçosos para codificá-los, não porque você não pode fazê-lo.
Você pode torná-los um pouco mais eficientes na maioria dos idiomas, definindo uma constante "booleana" em tempo de compilação e revisando um pouco as instruções:
Se você não gosta da sintaxe, pode recorrer a várias técnicas de abstração de idioma, como macros.
Algumas linguagens modernas fornecem uma boa sintaxe para isso, e é isso que acho que você quer dizer com "suporte à linguagem moderna". Isso é apoio, mas é bem fino.
O que a maioria das linguagens modernas ainda não fornece são asserções "temporais" (sobre estados arbitrários anteriores ou seguintes [operador temporal "eventualmente"]), que você precisa para escrever contratos realmente interessantes. As declarações IF não ajudarão você aqui.
fonte
super
método e, possivelmente, jogar fora os resultados se desejar apenas verificar os contratos sem duplicação. Isso realmente ajuda a implementar código limpo compatível com LSP.Como você diz, o Design by Contract é um recurso da Eiffel, que há muito tempo é uma daquelas linguagens de programação que são bem respeitadas na comunidade, mas que nunca foram usadas.
O DbC não está em nenhuma das linguagens mais populares porque é relativamente recente que a comunidade de programação convencional aceitou que adicionar restrições / expectativas ao seu código é algo "razoável" a ser esperado dos programadores. Agora é comum os programadores entenderem o quão valioso é o teste de unidade, e isso fez com que os programadores aceitassem mais colocar código para validar seus argumentos e obter benefícios. Mas há uma década, provavelmente a maioria dos programadores diria "isso é apenas trabalho extra para coisas que você sabe que sempre vai ficar bem".
Eu acho que se você fosse ao desenvolvedor médio hoje e falasse sobre pós-condições, eles acenariam entusiasticamente e diriam "OK, isso é como um teste de unidade". E se você falar sobre pré-condições, eles diriam "OK, isso é como validação de parâmetro, o que nem sempre fazemos, mas, você sabe, acho que está tudo bem ..." E então, se você falar sobre invariantes , eles começavam a dizer "Nossa, quanta sobrecarga é essa? Quantos bugs mais vamos capturar?" etc.
Então, acho que ainda há um longo caminho a percorrer antes que o DbC seja amplamente adotado.
fonte
Falso.
É uma prática de design . Ele pode ser incorporado explicitamente no código (estilo Eiffel) ou implicitamente no código (na maioria dos idiomas) ou em testes de unidade. A prática de design existe e funciona bem. O suporte ao idioma está em todo o mapa. Está, no entanto, presente em muitos idiomas na estrutura de teste da unidade.
É caro. E. Mais importante, existem algumas coisas que não podem ser comprovadas em um determinado idioma. A terminação de loop, por exemplo, não pode ser comprovada em uma linguagem de programação, requer uma capacidade de prova de "ordem superior". Portanto, alguns tipos de contratos são tecnicamente inexprimíveis.
Não.
Usamos principalmente testes de unidade para demonstrar que o DbC é cumprido.
Para Python, como você observou, o DbC vai em vários lugares.
A docstring e os resultados do teste de docstring.
Asserções para validar entradas e saídas.
Testes unitários.
Mais distante.
Você pode adotar ferramentas alfabetizadas de estilo de programação para escrever um documento que inclua suas informações de DbC e que gere scripts limpos de teste de unidade Python plus. A abordagem de programação alfabética permite que você escreva uma boa peça de literatura que inclua os contratos e a fonte completa.
fonte
there are some things which cannot be proven
. A verificação formal pode ser ótima, mas nem tudo é verificável! Portanto, esse recurso realmente restringe o que a linguagem de programação pode realmente fazer!Apenas adivinhando. Talvez parte da razão de não ser tão popular seja porque "Design by Contract" é marca registrada da Eiffel.
fonte
Uma hipótese é que, para um programa complexo suficientemente grande, especialmente aqueles com um objetivo em movimento, a massa de contratos em si pode se tornar tão problemática e difícil de depurar, quanto mais do que apenas o código do programa. Como em qualquer padrão, pode haver um uso após retornos decrescentes, bem como vantagens claras quando usado de maneira mais direcionada.
Outra conclusão possível é que a popularidade das "linguagens gerenciadas" é a prova atual do suporte a design por contrato para os recursos gerenciados selecionados (matriz limitada por contrato, etc.)
fonte
A razão pela qual a maioria dos idiomas tradicionais não possui recursos de DbC no idioma é a relação custo-benefício da implementação, que é alta para o implementador de idioma.
um lado disso já foi examinado nas outras respostas, testes de unidade e outros mecanismos de tempo de execução (ou mesmo alguns mecanismos de tempo de compilação com meta-programação de modelos) já podem lhe dar grande parte da bondade do DbC. Portanto, embora haja um benefício, provavelmente é visto como bastante modesto.
O outro lado é o custo, o ajuste retroativo do DbC em um idioma existente provavelmente é uma mudança muito grande e muito complexa para inicializar. É difícil introduzir nova sintaxe em um idioma sem quebrar o código antigo. Atualizar sua biblioteca padrão existente para usar uma alteração tão abrangente seria caro. Portanto, podemos concluir que a implementação de recursos DbC em um idioma existente tem um alto custo.
Eu também observaria que conceitos que são basicamente contratos para modelos e, portanto, um pouco relacionados ao DbC, foram retirados do padrão C ++ mais recente, pois mesmo após anos de trabalho neles, foi estimado que eles ainda precisavam de anos de trabalho. Esse tipo de mudança grande, ampla e abrangente nos idiomas é muito difícil de ser implementada.
fonte
O DbC seria usado mais amplamente se os contratos pudessem ser verificados em tempo de compilação, para que não fosse possível executar um programa que violasse qualquer contrato.
Sem o suporte do compilador, "DbC" é apenas outro nome para "verificar invariantes / suposições e lançar uma exceção se violada".
fonte
Eu tenho uma explicação simples, a maioria das pessoas (incluindo programadores) não deseja trabalho extra, a menos que ache necessário. Programação aviônica em que a segurança é considerada muito importante, eu não vi a maioria dos projetos sem ela.
Mas se você está pensando em programação para sites, computadores ou dispositivos móveis - falhas e comportamentos inesperados às vezes não são considerados ruins e os programadores apenas evitam trabalho extra ao relatar erros e depois corrigi-los é considerado adequado o suficiente.
Esta é provavelmente a razão pela qual acho que Ada nunca foi escolhido fora do setor de programação de aviação, porque é preciso mais trabalho de codificação, embora Ada seja uma linguagem incrível e, se você deseja criar um sistema confiável, é a melhor linguagem para o trabalho (exceto SPARK, proprietário) idioma baseado em Ada).
O projeto de bibliotecas de contrato para C # foi experimental pela Microsoft e é muito útil para a criação de software confiável, mas nunca ganhou impulso no mercado, caso contrário, você já os teria visto como parte da linguagem C # principal.
As asserções não são iguais ao suporte totalmente funcional para condições pré / pós e invariáveis. Embora ele possa tentar emulá-los, mas uma linguagem / compilador com suporte adequado faz uma análise da 'árvore de sintaxe abstrata' e verifica erros de lógica que simplesmente não podem ser feitas.
Edit: Eu fiz uma pesquisa e as discussões relacionadas a seguir podem ser úteis: https://stackoverflow.com/questions/4065001/are-there-any-provable-real-world-languages-scala
fonte
Principalmente os motivos são os seguintes:
fonte