A influência da Arquitetura
Apresentação:
Este artigo foi publicado no XXIX SECOP – Seminário Nacional de Informática Pública, realizado em novembro de 2001 em Natal, Rio Grande do Norte. Depois dessa data, outros trabalhos foram realizados na CELEPAR a respeito do mesmo assunto, mas seus resultados não estão refletidos neste documento. Por exemplo, constatamos que o ganho de desempenho observado no experimento descrito pelo artigo não se repete quando a aplicação é implementada em ambiente web, pois tal ganho deve-se à incorporação dos serviços do MTS através do uso de componentes. Esse artifício não é necessário em ambiente web porque as páginas ASP executam sob o IIS que já está integrado ao MTS. Isso significa que os resultados apresentados por este artigo são verdadeiros, mas referem-se apenas a sistemas cliente/servidor de duas ou múltiplas camadas.
Resumo:
Visando aprimorar a qualidade dos produtos de software desenvolvidos pela CELEPAR, realizou-se um experimento enfocando a influência da arquitetura na qualidade do produto. Os clientes envolvidos foram o DETRAN-PR, órgãos executivos de trânsito do Estado e prestadores de serviços do setor público e da iniciativa privada que participam do processo de controle de infrações de trânsito. O escopo do sistema é o tratamento financeiro de infrações do CTB (Código de Trânsito Brasileiro), incluindo o pagamento de multas pelo infrator, a relação com o sistema bancário e o repasse financeiro entre as instituições envolvidas no processo. As tecnologias de suporte ao experimento foram o processo unificado, a UML e a tecnologia de componentes da Microsoft (COM). Desenvolveu-se um módulo do aplicativo em diversas versões, mudando apenas as características arquiteturais de uma versão para outra, e foram obtidos produtos finais com diferentes características de qualidade. A partir desses resultados, definiram-se recomendações para o processo de desenvolvimento de sistemas da CELEPAR.
1. Introdução:
A qualidade exigida de um produto de software desenvolvido sob medida varia em função de diversos fatores. Quanto mais rigorosos os requisitos de qualidade e mais complexo o produto a ser desenvolvido, maior a necessidade de se aplicar teorias e ferramentas que garantam a satisfação desses requisitos.
Realizou-se um experimento na CELEPAR com o propósito de evidenciar a influência da arquitetura na qualidade de sistemas de informação transacionais. Este artigo propõe-se a apresentar os resultados práticos desse experimento, incluindo algumas recomendações para os desenvolvedores de sistemas de informação transacionais.
O sistema ao qual está relacionado envolve o DETRAN-PR, órgãos executivos de trânsito distribuídos pelo Estado e prestadores de serviços do setor público e da iniciativa privada que participam do processo de controle de infrações de trânsito. O escopo do sistema é o tratamento financeiro de infrações do CTB (Código de Trânsito Brasileiro), incluindo o pagamento de multas pelo infrator, a relação com o sistema bancário e o repasse financeiro entre as instituições envolvidas no processo.
A fim de avaliar a influência da arquitetura na qualidade do produto de software, implementaram-se várias versões de um módulo desse sistema. A linguagem de programação, os algoritmos, o sistema gerenciador de banco de dados, as máquinas e a infra-estrutura de rede utilizados para a execução das diferentes versões do aplicativo foram sempre os mesmos. A única característica que mudou de uma versão para outra foi sua arquitetura física, ou seja, o empacotamento do software, o tipo de interface utilizado pelos seus componentes, o nível de distribuição dos componentes, entre outros aspectos que constituem a arquitetura do sistema.
Foram geradas seis versões do aplicativo, uma utilizando arquitetura em duas camadas e as outras cinco utilizando múltiplas camadas. Executaram-se todas essas versões do sistema e foram comparadas algumas das suas características de qualidade, comprovando, por meio de critérios objetivos, a hipótese de que a arquitetura influi de forma direta e significativa na qualidade do produto final. A partir desses resultados, definiram-se recomendações para o processo de desenvolvimento de sistemas da Celepar. As tecnologias de suporte ao experimento foram o processo unificado [3], a UML [2] e a tecnologia de componentes da Microsoft [4].
Mais detalhes sobre esse experimento serão apresentados no corpo deste artigo, que está assim organizado: a seção 2 apresenta características de qualidade de software, conforme a norma NBR 9126 [1], e determina quais dessas características pertencem ao escopo do experimento; a seção 3 descreve o experimento propriamente dito, mostrando os procedimentos adotados, as arquiteturas avaliadas e os resultados obtidos; a seção 4 traz um resumo das recomendações definidas para o processo de desenvolvimento de sistemas da CELEPAR; finalmente, a seção 5 apresenta as conclusões do trabalho.
2. Características de Qualidade de Software
A norma NBR 9126 define as seguintes características de qualidade de software: funcionalidade, confiabilidade, usabilidade, eficiência, manutenibilidade e portabilidade. Cada uma dessas características está subdividida em subcaracterísticas, conforme segue:
Funcionalidade: conjunto de atributos que evidenciam a existência de um conjunto de funções e suas propriedades especificadas. As funções são as que satisfazem as necessidades explícitas ou implícitas. Subcaracterísticas:
-
Adequação: atributos do software que evidenciam a presença de um conjunto de funções e sua apropriação para as tarefas especificadas.
-
Acurácia: atributos do software que evidenciam a geração de resultados ou efeitos corretos ou conforme acordados.
- Interoperabilidade: atributos de software que evidenciam sua capacidade de interagir com sistemas especificados.
- Conformidade: atributos do software que fazem com que o software esteja de acordo com as normas, convenções ou regulamentações previstas em leis e descrições similares, relacionadas à aplicação.
- Segurança de acesso: atributos do software que evidenciam sua capacidade de evitar o acesso não autorizado, acidental ou deliberado, a programas e dados.
Confiabilidade: conjunto de atributos que evidenciam a capacidade do software de manter seu nível de desempenho sob condições estabelecidas durante um período de tempo estabelecido. Subcaracterísticas:
-
Maturidade: atributos de software que evidenciam a freqüência de falhas por defeitos no software.
-
Tolerância a falhas: atributos do software que evidenciam sua capacidade em manter um nível de desempenho especificado nos casos de falhas no software ou de violação nas interfaces especificadas.
- Recuperabilidade: atributos de software que evidenciam sua capacidade de restabelecer seu nível de desempenho e recuperar os dados diretamente afetados, em caso de falha, e o tempo e esforço necessário para tal.
Usabilidade: conjunto de atributos que evidenciam o esforço necessário para se poder utilizar o software, bem como o julgamento individual desse uso, por um conjunto explícito ou implícito de usuários. Subcaracterísticas:
-
Inteligibilidade: atributos do software que evidenciam o esforço do usuário para reconhecer o conceito lógico e sua aplicabilidade.
-
Apreensibilidade: atributos do software que evidenciam o esforço do usuário para aprender sua aplicação (por exemplo: controle de operação, entradas, saídas).
-
Operacionalidade: atributos do software que evidenciam o esforço do usuário para sua operação e controle de sua operação.
Eficiência: conjunto de atributos que evidenciam o relacionamento entre o nível de desempenho do software e a quantidade de recursos usados, sob condições estabelecidas. Subcaracterísticas:
-
Comportamento em relação ao tempo: atributos do software que evidenciam seu tempo de resposta, tempo de processamento e velocidade na execução de suas funções.
-
Comportamento em relação a recursos: atributos do software que evidenciam a quantidade de recursos usados e a duração de seu uso na execução de suas tarefas.
Manutenibilidade: conjunto de atributos que evidenciam o esforço necessário para fazer modificações especificadas no software. Subcaracterísticas:
-
Analisabilidade: atributos do software que evidenciam o esforço necessário para diagnosticar deficiências ou causas de falhas, ou para identificar partes a serem modificadas.
-
Modificabilidade: atributos do software que evidenciam o esforço necessário para modificá-lo, remover seus defeitos ou adaptá-lo a mudanças ambientais.
-
Estabilidade: atributos do software que evidenciam o risco de efeitos inesperados ocasionados por modificações.
-
Testabilidade: atributos do software que evidenciam o esforço necessário para validar o software modificado.
Portabilidade: conjunto de atributos que evidenciam a capacidade do software ser transferido de um ambiente para outro. Subcaracterísticas:
-
Adaptabilidade: atributos do software que evidenciam sua capacidade de ser adaptado a ambientes diferentes especificados, sem a necessidade de aplicação de outras ações ou meio além daqueles fornecidos para esta finalidade pelo software considerado.
-
Capacidade para ser instalado: atributos do software que evidenciam o esforço necessário para sua instalação num ambiente especificado.
-
Conformidade: atributos do software que o tornam consonantes com padrões ou convenções relacionadas à portabilidade.
- Capacidade para substituir: atributos do software que evidenciam sua capacidade e esforço necessário para substituir um outro software, no ambiente estabelecido para esse outro software.
O trabalho apresentado neste artigo demonstra que o investimento em arquitetura de software aprimora as seguintes características de qualidade: funcionalidade (interoperabilidade, segurança de acesso), eficiência (comportamento em relação ao tempo, comportamento em relação a recursos), manutenibilidade (analisabilidade, modificabilidade) e portabilidade (capacidade para ser instalado, capacidade para substituir).
3. Descrição do Experimento
O sistema enfocado neste experimento chama-se TFIC (Tratamento Financeiro de Infrações do CTB), foi desenvolvido com base no processo unificado (RUP – Rational Unified Process) e utilizou a UML (Unified Modeling Language) para modelar os artefatos de software produzidos. Sua implementação fundamenta-se em plataforma Microsoft e emprega a tecnologia de componentes disponível nessa plataforma. O experimento é apresentado, a seguir, em três subseções: atividades realizadas, arquiteturas avaliadas e resultados obtidos.
3.1 Atividades Realizadas
Inicialmente, definiram-se os detalhes do processo de negócio, em conjunto com representantes dos diversos órgãos envolvidos. Em seguida, os requisitos do software foram capturados, por meio de casos de uso, os ciclos de vida dos objetos de negócio mais complexos foram especificados, utilizando diagramas de transição de estados, e a integração com sistemas já existentes foi representada, por meio de diagramas de colaboração. As informações a serem armazenadas foram identificadas e registradas em diagramas de classes. Realizaram-se três iterações a fim de obter a especificação completa do sistema a ser desenvolvido e, ao final de cada uma delas, houve um amplo processo de revisão, contando com a participação de usuários dos diversos órgãos envolvidos e dos analistas de sistemas responsáveis pelas aplicações com as quais o TFIC deveria integrar-se.
A partir desse ponto, fez-se um estudo aprofundado da plataforma Microsoft e da sua tecnologia de componentes, com o objetivo de definir a arquitetura do software. Identificaram-se alternativas arquiteturais, que foram representadas por meio de diagramas de seqüência e de componentes, e implementaram-se essas arquiteturas para efeito de avaliação.
Utilizando-se procedimentos de recorte e colagem de código fonte, garantiu-se que as funcionalidades e os algoritmos de cada arquitetura avaliada fossem exatamente os mesmos, variando apenas as características arquiteturais, ou seja, a distribuição das classes em componentes, dos componentes em processos, dos processos em máquinas, as características físicas das interfaces dos componentes, entre outras.
O desempenho de cada arquitetura foi aferido automaticamente por programas de teste, que simulavam a interação de usuários com o sistema. Para tanto, arquivos de parâmetros de transações foram gerados, contendo informações equivalentes às que seriam digitadas pelos usuários, os quais eram lidos aleatoriamente pelos programas cliente e submetidos à execução pelo servidor de aplicação. Realizaram-se testes com diversas máquinas cliente, as quais trabalharam tanto de forma isolada quanto de forma concorrente, a fim de avaliar o comportamento do sistema sob cargas de trabalho diferenciadas. As arquiteturas testadas e os resultados obtidos estão descritos a seguir.
3.2 Arquiteturas Avaliadas
O experimento relatado neste artigo avaliou seis arquiteturas diferentes para o TFIC, sendo uma delas baseada em duas camadas e as outras cinco baseadas em três camadas. A seguir as figuras 1 e 2 representam a topologia dessas arquiteturas.
A arquitetura em duas camadas não utiliza componentes de software, nem as facilidades do servidor de aplicação. Constitui-se, simplesmente, de programas cliente escritos em Visual Basic acessando banco de dados. A maior parte da lógica do negócio encontra-se em stored procedures, visando melhor desempenho da aplicação.
As arquiteturas em três camadas utilizam-se dos serviços de transação e de segurança fornecidos pelo servidor de aplicação COM (Microsoft Component Model). Toda a lógica de negócio foi implementada usando componentes que residem nesse servidor e boa parte do acesso aos dados é feita através de stored procedures.
Figura 1 – Arquitetura em 2-camadas
Figura 2 – Arquitetura em 3-camadas
A figura 3 acima, mostra a alternativa monolítica da arquitetura em três camadas (CS3M – Cliente/Servidor 3-Camadas Monolítico). Nessa versão, as lógicas de negócio e de acesso a dados estão reunidas em um único componente, rodando no mesmo processo. Do ponto de vista lógico, elas não estão misturadas, porque um componente subdivide-se em classes e isso permite uma boa organização do código. Existem duas variações para essa arquitetura: a primeira implementa a comunicação entre o cliente e o componente servidor através de recordsets 1 (CS3M); a segunda, através de arrays (CS3MAr). A versão com arrays executa menos round-trips 2 e, por conseqüência, é bem mais eficiente.
1 recordset é uma coleção de dados retornada por um comando de acesso a um banco de dados.
2 round-trip é a passagem de controle de um objeto cliente para um servidor, retornando ao cliente.
Figura 4 - Diagrama de componentes para a arquitetura CS3D com múltiplas thread
A figura 4, mostra a alternativa distribuída com múltiplas threads da arquitetura em três camadas (CS3D – Cliente/Servidor 3-Camadas Distribuído). Nessa versão, a lógica de negócio está em um componente separado da lógica de acesso a dados e esses componentes executam também em processos separados. Isso traz maior independência entre as camadas, favorecendo o reuso dos componentes e organizando de modo mais adequado a estrutura da aplicação. Existem, também, duas variações para essa arquitetura: a primeira implementa a comunicação entre o cliente e os componentes de negócio através de recordsets (CS3D); a segunda, através de arrays (CS3DAr). É importante destacar que cada pacote presente nesse diagrama tornar-se-á um processo independente em tempo de execução, instanciando diversos componentes (DLLs) no mesmo espaço de memória, e que os pacotes do tipo library terão seus componentes instanciados no processo do objeto que os cria (in-process). Essa é mais uma característica que facilita reuso e que contribui para eficiência, uma vez que componentes executando no mesmo processo não dependem de protocolos de comunicação.
Nessa arquitetura, tanto o pacote de negócio quanto o pacote de banco de dados estão com múltiplos componentes porque a implementação foi feita em Visual Basic, que utiliza o componente como unidade básica de distribuição de software em threads. Com o objetivo de usufruir dos benefícios do processamento multithreaded, definiu-se um componente (uma DLL) para cada caso de uso do sistema e, também, um componente para cada tabela de banco de dados. Essa arquitetura apresentou um bom desempenho, mas não se mostrou vantajosa em relação à versão monolítica, devido ao custo inerente a instanciação muito freqüente de um número grande de componentes.
Analisando os pontos positivos e negativos da arquitetura CS3DAr com múltiplas threads, gerou-se uma sexta e última arquitetura, representada na figura 5, que se mostrou a mais adequada em todos os aspectos (segurança, desempenho, organização, reuso, etc.), em se tratando de implementação com Visual Basic. Essa arquitetura, basicamente, conserva a idéia de dois pacotes e uma library da anterior, mas reduz o número de seus componentes (DLLs). Se a implementação fosse em C++ ou em linguagem equivalente, do ponto de vista de gerência de threads, teríamos configurado cada caso de uso como uma classe do componente de negócio, rodando em thread separada e, da mesma maneira, cada tabela do banco de dados.
Figura 5 - Diagrama de componentes para a arquitetura CS3D com uma thread
A próxima seção deste artigo apresenta os resultados obtidos no experimento.
3.3 Resultados Obtidos
Conforme já foi dito, o trabalho apresentado neste artigo demonstra que o investimento em arquitetura de software aprimora as seguintes características de qualidade: funcionalidade (interoperabilidade, segurança de acesso), eficiência (comportamento em relação ao tempo, comportamento em relação a recursos), manutenibilidade (analisabilidade, modificabilidade) e portabilidade (capacidade para ser instalado, capacidade para substituir). Seguem os resultados obtidos em relação a cada uma dessas características:
-
Interoperabilidade (funcionalidade): o uso de um modelo de componentes na base da arquitetura do sistema, o COM, traz independência de linguagem de programação, compilador e sistema operacional, ou seja, basta que os componentes sejam compatíveis com o COM para serem interoperáveis. Além disso, a integração com sistemas já existentes se faz por meio de interfaces rigorosamente especificadas, garantindo, ao mesmo tempo, interoperabilidade entre plataformas diferentes e independência entre os sistemas (por exemplo, a alteração no banco de dados de uma aplicação não irá gerar impactos na outra).
-
Segurança de acesso (funcionalidade): implementada de maneira totalmente declarativa, não havendo nenhuma linha de código para tratar aspectos de segurança. Para tanto, utilizaram-se os serviços de segurança ofertados pelo COM e pelo serviço de transação do Windows. As vantagens dessa abordagem são a simplicidade e a flexibilidade da solução, assim como o fato de fundamentar-se em produtos fornecidos pela indústria de software, em contraste a soluções sob medida. As soluções da indústria tendem a ser mais robustas, mais sofisticadas, evoluem com maior agilidade e não exigem manutenção no código fonte da aplicação quando evoluem. Outro aspecto importante de segurança é o fato da arquitetura selecionada esconder da camada de apresentação o esquema de banco de dados.
-
Comportamento em relação ao tempo (eficiência): a arquitetura em duas camadas mostrou-se bastante eficiente em cenários de baixa demanda, o que lhe garante um espaço na engenharia de software, pois é mais simples e mais fácil de testar. Entretanto, em cenários de alta demanda apresentou tempo de resposta inaceitável. Em contraste a esse resultado, a arquitetura de três camadas selecionada, que já tinha um bom tempo de resposta em ambiente de baixa demanda, em muitas circunstâncias, melhorou seu desempenho sob alta demanda e, em outras, aumentou pouco o tempo de resposta, demonstrando-se bastante robusta. Para demonstrar os resultados, os dados foram tabulados e diversos gráficos foram gerados, visando a análise do desempenho das arquiteturas.
-
Comportamento em relação a recursos (eficiência): destaca-se o compartilhamento das conexões de banco de dados, que é um recurso muito caro para o processamento, o qual só foi possível em função da arquitetura selecionada, assim como a economia dos recursos de rede, uma vez que as interfaces dos componentes foram projetadas, propositadamente, de modo a realizar o mínimo de round-trips possível e a proporcionar o marshaling/unmarshaling3 mais eficiente possível.
3 marshaling/unmarshaling processo de codificação/decodificação de dados para trafegar em rede.
-
Analisabilidade (manutenibilidade): a divisão da aplicação em componentes e dos componentes em classes permite identificar mais rapidamente o ponto de falha, pois facilita o isolamento das partes dos sistema. Isso foi possível observar durante a fase de testes, que exigiu diversas modificações no código inicialmente gerado.
- Modificabilidade (manutenibilidade): a divisão da aplicação em componentes e dos componentes em classes torna cada unidade de código bem menor do que em uma abordagem monolítica, de modo que o esforço para modificar o código é pequeno e o potencial de inclusão de erros nessa modificação é reduzido. Isso também foi possível observar durante a fase de testes.
-
Capacidade para ser instalado (portabilidade): os componentes de negócio são instalados e configurados em um servidor de aplicação centralizado, simplificando os processos de instalação da aplicação e de gerência de configuração do sistema. Além disso, a organização em componentes facilita a instalação parcial da aplicação em outros servidores, proporcionando balanceamento de carga.
-
Capacidade para substituir (portabilidade): o conceito de componentes foi criado com o objetivo de montar aplicações a partir de peças predefinidas e de substituir essas peças de forma estática ou dinâmica. A tecnologia da Microsoft, que utilizamos nesse projeto, proporciona essas características.
Adicionalmente, foi alcançado o reuso, característica essa que afeta a produtividade da organização e, por esse motivo, é extremamente importante e perseguida pelos engenheiros de software. O processo de desenvolvimento empregado permitiu identificar possibilidades de reuso desde a fase de análise de requisitos; a tecnologia adotada, em conjunto com a arquitetura definida para o sistema, permitiram implementar os componentes da aplicação de forma reusável, pois delegam aspectos de segurança e de gerência de transação ao servidor de aplicação, adaptando-se facilmente a mudanças de requisitos por parte de clientes diferentes.
4. Recomendações para o Processo de Desenvolvimento
O experimento TFIC foi útil pelo aprendizado e pela identificação de uma série de recomendações para o processo de desenvolvimento de software da CELEPAR, como, por exemplo, as listadas abaixo:
-
Habilitar a verificação de acesso fornecida pelo serviço de transação, tanto no nível de pacote quanto de classe.
-
Criar uma conta específica para a execução dos componentes, a qual deve ter acesso ao banco de dados da aplicação. Configurar os usuários que terão acesso aos componentes. Dessa forma, nunca um usuário do sistema poderá acessar diretamente o banco de dados, apenas através dos componentes.
- Criar uma classe de acesso a dados para cada tabela do banco de dados. Reunir todas as classes que acessam o mesmo banco em um único pacote, para que possam compartilhar conexões. Esse pacote deve ser do tipo server, ou seja, executará em um processo separado.
- Se a linguagem de programação na qual o aplicativo é implementado utilizar componentes como unidades básicas a serem distribuídas em threads, como é o caso do Visual Basic, transformar cada caso de uso em um método de uma classe de negócio e reunir classes dessa natureza em um ou poucos componentes de negócio do tipo server. Entretanto, se a linguagem de programação utilizar classes como unidades de distribuição em threads, como é o caso do C++, transformar cada caso de uso em uma classe e direcionar cada um deles para uma thread diferente. Essas classes de negócio devem ser reunidas em um ou poucos componentes de negócio do tipo server. Os casos de uso reusáveis do sistema devem ser implementados em pacotes do tipo library, a fim de que executem no mesmo processo dos objetos que os instanciam.
-
O comportamento transacional dos componentes deve ser configurado da seguinte forma: a) não suporta transação: aplica-se a componentes contendo classes cujos métodos não fazem acesso a banco de dados; b) requer transação: aplica-se a componentes que atualizam o banco de dados, mas que não representam casos de uso; c) requer nova transação: aplica-se aos componentes contendo casos de uso que atualizam o banco de dados.
-
Os parâmetros de retorno de um método devem ser passados por referência, quando o cliente e o servidor encontram-se no mesmo processo. Se eles estão em processos diferentes, deve ser privilegiado o uso de passagem de parâmetro por valor e retorno de função, a fim de obter melhor desempenho.
-
Coleções de objetos devem ser passadas através de arrays, em vez de recordsets, uma vez que com essa abordagem reduz-se o número de round-trips de uma navegação para 1, otimizando o uso da rede e melhorando o desempenho.
-
Evitar, sempre que possível, modificação nas interfaces já disponíveis de um componente. Isso gera um trabalho de ajustes bastante considerável.
5. Conclusões
Apresentou-se um experimento que demonstra a possibilidade de aprimorar a qualidade de produtos de software a partir da definição de uma boa arquitetura. Esse experimento baseou-se no RUP, na UML e na tecnologia de componentes da Microsoft, para oferecer ao DETRAN-PR uma nova solução de tratamento financeiro de infrações do CTB. As principais características de qualidade endereçadas foram funcionalidade, eficiência, manutenibilidade e portabilidade, além de uma característica importante de produtividade, que é o reuso.
A continuidade desse trabalho envolve diversas atividades, entre as quais destacam-se: a investigação criteriosa de outras plataformas tecnológicas que suportem essa abordagem (JAVA e CORBA); a identificação ou construção de ferramentas CASE para especificar arquiteturas de software embutindo a semântica da plataforma tecnológica subjacente; e o uso de ferramentas para geração parcial de código.
Referências
[1] ASSOCIAÇÃO BRASILEIRA DE NORMAS TÉCNICAS. NBR 13596, Tecnologia da Informação – avaliação de produto de software – Características de Qualidade e Diretrizes para o seu uso. Rio de Janeiro, 1996.
[2] BOOCH G.; RUMBAUGH J.; e JACOBSON, I., The Unified Modeling Language user guide. Reading: Addison Wesley, 1998.
[3] Jacobson, I., Booch G. e Rumbaugh J., The Unified Software development process. Reading: Addison Wesley, 1999.
[4] KIRTLAND, M.; Projetando soluções baseadas em componentes. Rio de Janeiro: Campus, 2000.