Upload
bardia
View
31
Download
2
Embed Size (px)
DESCRIPTION
Impacto do uso de design by contract no desenvolvimento de sistemas: um estudo de caso. Frederico Silva Guimarães 04/11/2005. [email protected]. Agenda. Motivação e Objetivo Design by Contract Assertivas e Tratamento de Erros Java C/C++ Estudo de Caso Conclusões. - PowerPoint PPT Presentation
Citation preview
Impacto do uso de design by contract no desenvolvimento de
sistemas: um estudo de caso
Frederico Silva Guimarães
04/11/2005
Frederico Silva Guimarães <[email protected]>
Agenda
• Motivação e Objetivo
• Design by Contract
• Assertivas e Tratamento de Erros– Java
– C/C++
• Estudo de Caso
• Conclusões
Frederico Silva Guimarães <[email protected]>
Motivação e Objetivo
• Mostrar a experiência que tivemos com o uso de assertivas no desenvolvimento de aplicações comerciais
– Por que Java e C++?
• Pois são largamente utilizadas hoje em dia (e são as linguagem que usamos normalmente)
– Por que essa experiência é importante?
• Mostrar que assertivas têm grande utilidade, mesmo sendo pouco utilizadas
• Mostrar que o uso de assertivas pode fazer a diferença entre o sucesso e o fracasso de um sistema
• Mostrar um caso real de uso de assertivas (o assunto é bastante explorado no meio acadêmico, entretanto no meio comercial o mesmo não acontece)
Frederico Silva Guimarães <[email protected]>
Design By Contract (DBC)
• Contrato estabelecido entre um construto e seus clientes
– Cliente: garantir condições ou propriedades antes de invocar métodos do construto
– Construto: depois da execução, garantir que condições ou propriedades serão verdadeiras
• Contratos são formado por um conjunto de assertivas que definem o comportamento de um construto e de seus métodos
• No DBC os contratos são executáveis, escritos na própria linguagem de programação, ou em alguma meta-linguagem
• Conjunto de assertivas executáveis
Frederico Silva Guimarães <[email protected]>
Design by Contract (DBC)
• Um contrato tem três elementos essenciais
– Pré-condições
– Pós-condições
– Invariantes
Frederico Silva Guimarães <[email protected]>
Assertivas - Java
• Possui uma estrutura própria para o uso de assertivas– assert <expressão booleana> [: <mensagem de erro> ]
• assert value != null;
• assert value instanceof List : values.getClass().getName();
– Quando a expressão booleana é falsa, levanta um AssertionError com a mensagem de erro
– Os asserts normalmente estão desligados, deve-se executar o programa passando um parâmetro extra (-ea) para ligar as assertivas
• java –ea –cp <CLASSPATH> <MAIN CLASS> <ARGS>
– Só disponível a partir da J2SE1.4
• Códigos usando J2SE 1.3 ou menor– Usamos “ifs” e levantamos exceções em caso de falha
• Normalmente IllegalArgumentException e IllegalStateException
Frederico Silva Guimarães <[email protected]>
Assertivas – C/C++
• Não possui nenhuma estrutura própria para o uso de assertivas
• Usamos “ifs” e chamamos uma função em caso de falha
– Normalmente essa função loga/mostra o erro e aborta o programa
Frederico Silva Guimarães <[email protected]>
Tratamento de erros - Java
• Padronizado: todos os erros levantam um Throwable
– Exception
• RuntimeException
– Error
• Estrutura try..catch..finally permite pegar um Throwable (um qualquer ou um especifico), e tratar o erro
• O Throwable traz informações sobre o erro:
– Possui um stacktrace mostrando a execução (inclui linhas e métodos) até o momento que o erro ocorreu
– O próprio nome da classe diz, de modo geral, qual foi o erro
• IOException, ArrayIndexOutOfBounds, NullPointerException, OutOfMemoryError
– Possui uma mensagem sobre o erro
• por exemplo o índice inválido no ArrayIndexOutOfBounds
Frederico Silva Guimarães <[email protected]>
Tratamento de Erros – C/C++
• Os erros fazem:
– O programa “voar”
• Ex: acessar uma variável nula
– ou funcionar de maneira errada
• Ex: acessar um índice inválido de um array, mas ainda assim acessar um espaço válido de memória
– Em ambos os caso, não se tem nenhuma informação sobre o que aconteceu ou onde aconteceu
• Executando em modo debug em algumas IDEs é possível ter uma idéia de onde ocorreu o erro (caso ele não ocorra em uma biblioteca externa), mas ainda é impossível saber que erro ocorreu
Frederico Silva Guimarães <[email protected]>
Tratamento de Erros – C/C++
• Em C++ existe a estrutura try..catch, que não costuma ser usada
– Sua utilização pode gerar problemas como vazamentos de memória
– A maior parte das bibliotecas (incluindo a std) não fazem uso do throws
• A bibliotecas XercesC faz uso dela
– Erros, como acesso inválido de memória, fazem o programa “voar” ao invés de levantar uma exceção
– Não há padronização:
• Qualquer coisa, até mesmo um int ou string pode ser levantado
• Métodos não são requeridos a declarar os tipos que podem levantar como exceção
Frederico Silva Guimarães <[email protected]>
Tratamento de Erros – C/C++
• Em C/C++, as funções/métodos costumam ter código de retorno para informar se houve algum erro durante a execução (ao invés de levantar exceções)
Frederico Silva Guimarães <[email protected]>
Exemplo - Java
public static void copyFile( File sourceFile, File targetFile )throws IOException
{assert sourceFile != null;assert sourceFile.exists() : “File doesn’t exists:
”+sourceFile. getAbsolutePath();assert sourceFile.isFile() : “File is a directory: ”+sourceFile.
getAbsolutePath();assert targetFile != null;...
}
• Caso não utilizássemos assertivas, se algum dos argumentos fosse inválido, o código levantaria uma exceção (NullPointerException, FileNotFoundException, etc..)– Essa exceção nos daria quase as mesmas informações que o
AssertionError
Frederico Silva Guimarães <[email protected]>
Exemplo - C++
int32 UtiltitesIO::copyFile( QFile* sourceFile, QFile* targetFile ){
if(sourceFile == NULL){
return RET_CODE_SOURCE_FILE_IS_NULL; //1}else if(targetFile == NULL){
return RET_CODE_TARGET_FILE_IS_NULL; //-1}else if(!sourceFile->exists()){
return RET_CODE_SOURCE_FILE_DOES_NOT_EXIST; //3}...return RET_CODE_OK; //0
}
• Caso não houvesse assertivas, se algum dos argumentos fosse inválido, o programa “voaria”
Frederico Silva Guimarães <[email protected]>
XmlParser
• Projeto consistiu em traduzir, de Java para C++, um código que lê e escreve certas classes em xml (cerca de 170 classes)
– Usando bibliotecas Log4cxx e XercesC
• O projeto teve uma equipe de 4 pessoas, e o tempo era escasso
– Houve uma preocupação em traduzir o código rapidamente, para depois testá-lo
• O código foi traduzido sem qualquer código extra em relação a versão Java
• Em especial, não foi colocada nenhuma assertiva ou tratamento de erro além do que existia no código Java (que eram poucos)
Frederico Silva Guimarães <[email protected]>
XmlParser
• A tradução foi rápida
– Parte foi automatizada por um programa (em Java) que gerava um esboço do .cpp e do .h a partir dos .java
• Quando começaram os testes, começaram os problemas. Muitos erros, mas que em Java:
– Não aconteciam
• EX: variáveis não inicializadas
– Em C++, elas recebem um valor aleatório
– Em Java, recebem null, 0 ou false;
– Geravam erro de compilação
• Ex: funções que devem retornar valores, mas não retornam valores em todos os caminho possíveis
Frederico Silva Guimarães <[email protected]>
XmlParser
double getVal(int code){
switch (code){
case 0:return ...;
case 1:return ...;
case 2:return ...;
case 3:return ...;
}//Cadê o return para code != {0, 1, 2, 3}
}
Frederico Silva Guimarães <[email protected]>
XmlParser
• Quando começaram os testes, começaram os problemas. Muitos erros mas que em Java:
– Lançam exceções específicas:
• Acessar uma variável nula
– Em C/C++ o programa “voa”
• Typecast errado
– Em C/C++ o programa vai “voar” (ou não!!!!) quando algum método ou atributo for acessado
• Acesso inválido de memória (índice inválido de um array)
– Em C/C++, o comportamento do programa é indeterminado
Frederico Silva Guimarães <[email protected]>
XmlParser
• Gastou-se uma boa parte do projeto (2 meses), apenas na descoberta e tratamento dos erros
• Como normalmente o programa “voava” em funções das bibliotecas externas, era necessário depurar o programa passo a passo, não só para tentar descobrir o que houve, mas também para descobrir aonde ocorreu o erro
– E, normalmente, a real causa era um dos erros citados anteriormente
• Muitos desses erros poderiam ter sido evitados (ou mais facilmente descobertos) se tivessemos inserido assertivas pelo menos em alguns pontos chave do código durante a tradução
Frederico Silva Guimarães <[email protected]>
Gip-View
• Sistema para inspeção de dutos
– Para comparação:
• O sistema possui cerca de 210 classes
– Dessas, 80-90 foram parcialmente reutilizadas de outro projeto que também foi desenvolvido utilizando assertivas
• O sistema foi desenvolvido por 3 possoas
– 2 delas comuns aos dois projetos
• Foi desenvolvido desde o início com o uso de assertivas
• Em 2 meses, já havia uma versão beta do sistema
• Desses dois messes foram gastos 2-3 semanas em testes e integração com a ferramenta de inspeção
Frederico Silva Guimarães <[email protected]>
Gip-View
• Em todo o desenvolvimento o programa “voou” apenas 5 vezes (mas caiu várias vezes em assertivas ), apenas 1 vez na mão do cliente (ainda durante a fase de testes)
• Em cada uma dessas vezes que o programa “voou”, o tempo gasto com a descoberta e o conserto do erro foi drasticamente maior do que quando alguma assertiva falhava
• E, normalmente, quando a causa do erro era descoberta, via-se que ele poderia ter sido evitado (ou encontrado mais facilmente) com o uso de assertivas
Frederico Silva Guimarães <[email protected]>
Gip-View
• O sistema continua em desenvolvimento
– Novas funcionalidades estão sendo adicionadas
• Ele já se encontra em uso a alguns meses e tem se mostrado bastante estável
– Já foi inclusive usado em inspeções reais
Frederico Silva Guimarães <[email protected]>
Gip-View – Ligando/Desligando Assertivas
• Maneira mais comum: Usando DEFINES
#ifdef GIP_USE_ASSERTS
if ( value == NULL )
{
ClErrorManager::abortProgram(“mensagem“);
} // if
#endif
• Problemas– 8 ou 80: Ou todas as assertivas ou nenhuma
• Seria possível usar vários defines para níveis de assertivas e para classes ou grupos de classes, mas isso dificultaria muito a manutenção e configuração
– Necessidade de re-compilação do código para ligar/desligar assertivas
Frederico Silva Guimarães <[email protected]>
Gip-View – Ligando/Desligando Assertivas
• Solução: Usar a configuração do log da aplicação como configuração das assertivas
• O log é feito através da biblioteca log4cxx que é uma implementação em C do log4j da Apache
– É configurado em arquivo de configuração (log4j.properties)
– Mensagens logadas podem ser de 5 níveis
• FATAL > ERROR > WARN > INFO > DEBUG
• É possivel desligar todas as mensagens, ou desligar apenas mensagens abaixo de um determinado nível
Frederico Silva Guimarães <[email protected]>
Gip-View – Ligando/Desligando Assertivas
– Configuração hierarquica dos Loggers
• Cada Logger recebe um nome na criação
– Logger * LOG = Logger::getLogger(<nome>);
• Logger com o nome br.com.gip.Utilities herda configurações de:
– br.com.gip, br.com, br, e do Logger raiz (root)
• Permite facilmente ligar ou desligar um grupo de Loggers ao alterar o nível permitido para as mensagens
Frederico Silva Guimarães <[email protected]>
Gip-View – Ligando/Desligando Assertivas
• Definimos um nível para cada assertiva
• Se as mensagens daquele nível não estiverem habilitadas no Logger daquela classe, aquela assertiva não é testada
Frederico Silva Guimarães <[email protected]>
Exemplo
int32 UtiltitesIO::copyFile( QFile* sourceFile, QFile* targetFile ){
if(LOG->isInfoEnabled()){
if(sourceFile == NULL){
return RET_CODE_SOURCE_FILE_IS_NULL; //1}else if(targetFile == NULL){
return RET_CODE_TARGET_FILE_IS_NULL; //-1}else if(LOG->isDebugEnabled()){
if(!sourceFile->exists()){
return RET_CODE_SOURCE_FILE_DOES_NOT_EXIST; //3
}}
}...return COPY_FILE_OK; //0
}
Frederico Silva Guimarães <[email protected]>
Conclusões
• Em Java é possível ter boas informações sobre os erros ocorridos sem o uso de assertivas (principalmente assertivas simples), no entanto o uso de assertivas pode ajudar ainda mais na descoberta da causa e localização dos erros
• Já em C/C++ o uso de assertivas é uma necessidade, sem elas fica muito difícil/trabalhoso a descoberta da causa e a localização de erros
Frederico Silva Guimarães <[email protected]>
Referências
• DBC: Bertrand Meyer. Applying Design by Contract. In Computer IEEE 25 (10), October 1992, pag 40-51.
• DBC: B. Venners, Contract-Driven Development - A Conversation with Bertrand Meyer, Part III, Artima Software site, March 2004.
• QT: http://www.trolltech.com/products/qt/index.html
• XercesC: http://xml.apache.org/xerces-c/
• Log4j: http://logging.apache.org/log4j/docs/
• Log4cxx: http://logging.apache.org/log4cxx/