segunda-feira, 30 de março de 2015

[Programação Modular] Classes e Interfaces

Uma classe representa uma categoria de elementos, enquanto um objeto representa um elemento específico dessa categoria. Definida apenas no contexto de compilação, a classe define a lógica estática de um programa e, desse modo, relacionamentos entre classes não mudam durante a execução de um programa.


Algumas convenções são comumente adotadas para a programação de classes:
  • classes são declaradas com a primeira letra de cada palavra maiúscula (UpperCamelCase): MinhaClasse;
  • atributos, variáveis locais e métodos são declarados com a primeira letra da primeira palavra minúscula (lowerCamelCase): meuAtributo, minhaVariavel, meuMetodo;

Uma classe é composta atributos métodos. Por não possuir uma estrutura ordenada, as classes devem ser criadas seguindo um padrão lógico, para facilitar a legibilidade do programa.

Igualmente, os objetos (ou instâncias de uma classe) possuem atributos métodos. Estes membros, no entanto, possuem um espaço de memória único para cada instância e sempre que uma nova instância é criada, os procedimentos de inicialização são adotados.

Atributos não precisam ser inicializados e possuem um valor padrão:
  • tipos numéricos: valor 0;
  • tipo boolean: valor false;
  • demais atributos: valor null (referência vazia).

Métodos, por sua vez, acessam ou modificam atributos.Por meio do controle de visibilidade, é possível controlar os níveis de acesso:
  • public
  • protected
  • default
  • private

A palavra this é utilizada para referenciamento do objeto atual

Toda classe possui um ou mais métodos construtores, que são chamados para criação dos objetos. Por padrão, um construtor sem parâmetros é criado. Outros construtores podem ser criados, diferenciando-se apenas a lista de parâmetros (sobrecarga), pois todos os construtores possuem o mesmo nome da classe. Quando um construtor com parâmetros for criado, o construtor padrão (sem parâmetros) não é mais acessível.



Atributos e métodos podem ser estáticos. 

Atributos estáticos não estão associados a uma instância (atributos de classe), sendo compartilhado por essas, ocupando uma posição única na memória. Normalmente utilizados para constantes.



Observe os valores que serão impressos pelo método e note que o atributo é compartilhado entre os objetos c1 e c2:


Métodos estáticos, por sua vez, são acessados diretamente pela classe e não demandam instanciação. Dessa forma, são resolvidos em tempo de compilação, não podendo ser sobrescritos.



Observe que o método Ponto é instanciado. Já o método estático calcNorma não:


As classes em Java podem ser classificadas em internas, abstratas ou finais. 

Classes internas são declaradas dentro de outra classe e podem, dessa forma, acessar seus métodos privados. Este tipo específico de classe é utilizado para substituir a estrutura struct.



Classes abstratas tem como principal característica a impossibilidade de ser instanciada. Este tipo de classe define um conjunto de métodos abstratos totalmente implementados ou parcialmente implementados. Neste último caso, a implementação pode ocorrer nas classes derivadas.


 Observe o exemplo a seguir e note que o método abstrato setarXY é implementado na classe derivada Ponto2D. 



Além disso, tem-se as classes finais, que não podem ser herdadas, o que torna seu comportamento constante. Neste tipo de classe, os atributos operam como constantes e os métodos não podem ser sobrescritos. 


Por fim, tem-se as interfaces, que permitem definir um conjunto de métodos que deverão ser implementados por uma classe. Dessa forma, uma interface funciona como um contrato.

Note no exemplo a seguir que a classe Ponto implementa a interface Imprimivel, por meio da implementação do método imprimirValores (definido na interFace).


O quadro a seguir apresenta uma visão geral e comparativa de classes e interface.


domingo, 29 de março de 2015

[Programação Modular] Programação Orientada a Objetos

A programação orientada a objetos (POO) foi precedida por outro paradigma denominado programação estruturada. Neste, os programas são desenvolvidos utilizando-se três estruturas básicas: 

  • sequência: fluxo contínuo de instruções;
  • decisão: fluxo que é executado se atendida uma condição;
  • iteração: fluxo que é executado enquanto é atendida uma condição.

A modularidade de programas escritos com programação estruturada é obtida com o uso de Tipos Abstratos de Dados, que utilizam funções e acessam dados compartilhados.

As restrições desse paradigma estão exatamente no acesso compartilhado a dados, que limita sua capacidade de expansão e resolução de problemas muito complexos, devido à concorrência existente no acesso aos dados.



Essa limitação é solucionada no paradigma de orientação a objetos, em que a comunicação se dá por mensagens e não por acesso a dados compartilhados.



Outras características relevantes do paradigma de POO é a facilidade de manutenção do programa, pois é possível realizar alterações em apenas um módulo do programa, sem a necessidade de intervenção em todo o código.

Além disso, outros benefícios incluem:

  • maior reaproveitamento de código;
  • maior confiabilidade;
  • melhor gerenciamento;
  • maior robustez.

A modelagem de um problema nesse paradigma considera que tudo é um objeto, que possui um tipo, uma área própria de memória e a capacidade de se comunicar com outros objetos, via mensagem. Objetos encapsulam dados e métodos, provendo um nível de abstração para seus usuários (outros objetos).


Um objeto é uma instância de uma classe, possui uma identidade (referência única que o difere dos demais), um estado (valores que seus atributos assumem) e um comportamento (suas regras para relacionar-se com outros objetos e para alterar seu estado). 

Enquanto a classe representa um módulo do programa, existente em tempo de compilação, um objeto representa uma ocorrência de uma classe, existente em tempo de execução.


A POO possibilita o desenvolvimento de programas modulares. Estes se caracterizam por quatro propriedades principais:
  • decomposição: capacidade de segmentar o programa em módulos que podem ser modificados individualmente, de forma independente. A decomposição fica prejudicada quando há uma forte dependência entre módulos;
  • composição: capacidade de se combinar (acoplar) de forma livre dois módulos distintos;
  • significado fechado: capacidade de se compreender o programa, mesmo sem acesso a todas as suas partes;
  • continuidade: capacidade de se alterar parte da especificação de um programa, modificando apenas alguns módulos.

[Programação Modular] Tipos Abstratos de Dados

Um Tipo Abstrato de Dados, ou TAD, é uma especificação de dados e de um conjunto de operações que podem ser realizadas sobre eles, sendo utilizado para encapsular a informação necessária ao desenvolvimento do programa, provendo níveis de abstração, que permitem o tratamento de problemas complexos.

O TAD é caracterizado, assim, não pelos dados que o compões, mas sim pelas operações que se aplicam sobre ele. Dessa forma, as operações providas pelo TAD ficam visíveis ao usuário e os detalhes de implementação ficam ocultos.


Dessa forma, pode-se modificar a implementação das operações do TAD sem modificar o código que o utiliza. Essa característica também permite que um TAD possa ser reutilizado por diversos programas distintos.

Em linguagens orientadas a objetos, a implementação do TAD é feita por meio de classes. Já em linguagens estruturadas, são utilizadas definições de tipo e implementação de funções.

O TAD permite a chamada programação por contrato (Design by Contract), que consiste na definição de especificações de interface precisas e verificáveis dos componentes de software. Assim, são definidas as condições (obrigações) que um TAD devem cumprir no fornecimento de serviço a seu usuário (contratante).

[Programação Modular] Introdução a Java

Introdução



Criada pela SUN Microsystens em 1995 e mantida pela Oracle desde 2009, a linguagem de programação Java figura como a mais utilizada no mundo, segundo o ranking da IEEE.

Similar à linguagem C++, Java é uma linguagem de programação orientada a objetos e apresenta algumas características de destaque:
  • Portabilidade: possibilita a execução em qualquer ambiente que utilize a máquina virtual Java (Java Virtual Machine), seguindo o princípio "escreva uma vez, execute em qualquer lugar" ("write once, run anywhere").
  • Recursos de rede: extensa bibliotecas de rotina que facilitam a utilização de protocolos de rede.
  • Mutlthreading: facilidade para criação de programas distribuídos
  • Segurança: permite restrição de execução de programas via rede.
  • Fortemente tipada: declaração do tipo é obrigatória.
  • Desalocação automática de memória: por meio de coletor de lixo (Garbage Collector).
  • Não possui aritmética de ponteiros.

Apesar de similar a C/C++, Java não apresenta algumas características presentes nessas linguagens, como arquivos de cabeçalho, herança múltipla, o comando goto, typedef, define, struct.

Máquina Virtual Java (Java Virtual Machine)

O código de um programa Java é convertido para ByteCode, uma forma intermediária de código que é interpretado pela máquina virtual. Essa característica permite que programas java sejam executados em qualquer ambiente que possua a máquina virtual.


A máquina virtual Java está presente no Ambiente de Tempo de Execução Java, conhecido como JRE (Java Runtime Environmet), que agrega ainda as bibliotecas Java. Assim, cada plataforma possui um JRE específico. A máquina virtual Java converte os ByteCodes em código executável de máquina.

Desenvolvimento em Java

Java permite o desenvolvimento de três tipos distintos de programas:
  • Aplication: um programa independente.
  • Applet: um programa que executa acoplado a um browser.
  • Servlet: usado para estender as funcionalidades de um servidor

Para o desenvolvimento de programas em Java, pode-se considerar os seguintes elementos básicos:
  • Operadores: sinais que representam atribuições, cálculos e ordem dos dados.

  • Separadores: são sinais que indicam ou modificam a ordem das operações.

  • Comandos de decisão: permitem que uma sequência de código seja executada se uma condição for satisfeita. Ex.: if-else, switch.
  • Comandos de iteração: permitem que uma sequência de código seja executada até que uma condição seja satisfeita. Ex.: for, while, do-while.

O trecho a seguir apresenta um pequeno programa em Java que imprime na tela: "Hello World!":



Nota: o nome do arquivo e da classe pública devem ser iguais. 
          Arquivo: HelloWorld.java. 
          Classe:  HelloWorld.class.

Um programa Java é organizado como um conjunto de classes e interfaces relacionadas e agrupadas em pacotes. A declaração do pacote deve ocorrer no início do arquivo e, caso não seja feita, todas as classes e interfaces farão parte do pacote default.


Um pacote pode ser importado a outro, permitindo o uso de suas funcionalidades. Para tal, basta utilizar o comando import:


Já a passagem de parâmetros ocorre sempre por valor. Mas objetos são passados por referência e estas, por sua vez, serão passadas por valor, ou seja, Java passa referências de objeto por valor.




No exemplo a seguir, o método alteraPonto tem como parâmetro o objeto Ponto p (uma instância da classe ponto). 





Outro aspecto importante da linguagem é o uso de strings. Diferente do que ocorre em C/C++, em Java strings não são cadeias de caracteres, mas sim objetos (ou instâncias) da classe String. Dessa forma, devem ser declaradas e instanciadas.



Java possui também suporte para o tratamento estruturado de exceções, por meio da classe Throwable. Para tal, os seguintes comandos são utilizados:
  • try: delimita o fluxo normal de execução.
  • throw: inicia a exceção.
  • catch: inicia o tratamento da exceção.
  • finally: adiciona, após o tratamento da exceção, um fluxo que sempre será executado.


Por fim, Java provê suporte para entrada e saída de dados, seja via terminal, seja via leitura e escrita de arquivos.

Entrada e saída de dados via terminal

Saída de dados via arquivo

sábado, 28 de março de 2015

[Programação Modular] Qualidade de Software

Conceito

Segundo o dicionário Michaellis, qualidade é o grau de conformidade de algo a um certo padrão. Já a ABNT NBR ISO 9000:2005, que descreve os fundamentos de sistemas de gestão da qualidade, define a qualidade como sendo o "grau no qual um conjunto de características inerentes satisfaz a requisitos".

Desse modo, a qualidade pode ser medida e comparada. No contexto de desenvolvimento de software, a qualidade é medida pelo grau de conformidade em relação aos requisitos definidos pelo cliente. 

A imagem a seguir ilustra as dificuldades em se obter qualidade no desenvolvimento de software:


Além dos objetivos claros que motivam a preocupação com a qualidade (como atender às necessidades do cliente), outros aspectos podem ser observados. Investimentos adequados em qualidade representam redução de custos, tanto na etapa de desenvolvimento, quanto na manutenção e evolução de sistemas. Isto porque uma maior conformidade do sistema com os requisitos definidos pelo cliente implica em um menor número de intervenções para correções e ajustes, bem como facilita a execução de correções e a ampliação de funcionalidades.

Já no contexto da Engenharia de Software, Pressman define qualidade como a "conformidade a requisitos funcionais e de desempenho explicitamente declarados, a padrões de desenvolvimento claramente documentados e a características implícitas que são esperadas de todo software profissionalmente desenvolvido".

Fatores e Padrões de Qualidade

Compreendido o conceito de qualidade, deve-se analisar, então, quais fatores podem ser utilizados para se medir o nível de qualidade de um software. McCall apresenta três grupos de fatores de qualidade: operação, revisão e transição.




Os fatores de operação (ou utilização) compreendem:
  • correção: cumprimento dos requisitos especificados;
  • confiabilidade: entrega das funcionalidades (ou do comportamento) esperado;
  • integridade: controle de acesso e modificação;
  • usabilidade: esforço necessário para uso;

Já os fatores de revisão (ou alteração) compreendem:
  • manutenibilidade: esforço necessário para depuração e correção;
  • flexibilidade: esforço necessário para modificação;
  • testabilidade: esforço necessário para realização de testes;

Por fim, os fatores de transição (ou adaptação) compreendem:
  • portabilidade: esforço necessário para uso do software em plataformas distintas;
  • reusabilidade: capacidade de uso de módulos, ou mesmo segmentos, do software em outros programas;
  • interoperabilidade: esforço necessário para integração com outros softwares.

Os fatores de qualidade podem ser agrupados em dois conjuntos, sob a perspectiva de quem os percebe, o usuário (padrões externos) ou o desenvolvedor (padrões internos). Os fatores de operação são percebidos pelo usuário, enquanto os fatores de revisão e transição são percebidos pelo desenvolvedor.

Já a norma internacional ISO/IEC 9126, é baseada em seis características: funcionalidade, confiabilidade, usabilidade, eficiência, manutenibilidade e portabilidade.




A característica funcionalidade compreende a capacidade do software de prover funções que atendam às necessidades explícitas e implícitas e abrange as seguintes subcaracterísticas:

  • adequação: capacidade de prover um conjunto apropriado de funções para tarefas e objetivos determinados;
  • acurácia: capacidade de prover os resultados (ou efeitos) corretos/acordados;
  • interoperabilildade: capacidade de interagir com outros sistemas;
  • segurança de acesso: capacidade de proteger informações e dados, negar acesso não autorizado e fornecer acesso autorizado;

A característica confiabilidade compreende a capacidade do software de manter um nível de desempenho especificado e abrange as seguintes subcaracterísticas:
  • maturidade: capacidade de evitar falhas decorrentes de defeitos;
  • tolerância a falhas: capacidade de manter um nível de desempenho especificado em caso de defeitos;
  • recuperabilidade: capacidade de recuperar seu nível de desempenho e os dados impactados em caso de falha.

A característica usabilidade compreende a capacidade do software ser compreendido, aprendido, operado e atraente ao usuário e abrange as seguintes subcaracterísticas:
  • inteligibilidade: capacidade de o usuário compreender se o software é adequado (a suas necessidades) e como ele pode ser usado;
  • apreensibilidade: capacidade de possibilitar ao usuário aprender sua aplicação;
  • operacionalidade: capacidade de possibilitar ao usuário operá-lo e controlá-lo;
  • atratividade: capacidade de ser atraente ao usuário.

A característica eficiência compreende a capacidade do software apresentar desempenho adequado, relativo à quantidade de recurso usados, e abrange as seguintes subcaracterísticas:
  • comportamento em relação ao tempo: capacidade de fornecer tempo de resposta e processamento ou taxa de transferência apropriados;
  • utilização de recursos: capacidade de usar tipos e quantidade apropriadas de recursos;

A característica manutenibilidade compreende a capacidade do software de ser corrigido, melhorado ou adaptado e abrange as seguintes subcaracterísticas:
  • analisibilidade: capacidade de permitir o diagnóstico de falhas e a identificação das partes a serem reparadas;
  • modificabilidade: capacidade de permitir a implementação de uma modificação;
  • estabilidade: capacidade de evitar efeitos inesperados decorrentes de uma modificação;
  • testabilidade: capacidade de permitir sua validação, após implementada uma modificação.

A característica portabilidade compreende a capacidade do software de ser transferido de um ambiente para outro e abrange as seguintes subcaracterísticas:
  • adaptabilidade: capacidade de ser adaptado para diferentes ambientes;
  • capacidade para ser instalado: capacidade de ser instalado em um ambiente específico;
  • coexistência: capacidade de coexistir com outros softwares independentes e compartilhar recursos comuns;
  • capacidade para substituir: capacidade de substituir outro software com o mesmo propósito e no mesmo ambiente

Todos as características abrangem ainda a subcaracterística conformidade, que compreende a capacidade de estar de acordo com normas, convenções ou regulamentações legais relacionadas ao fator.

Métricas

Métricas estão associadas ao software (ou processo) e permitem medir uma subcaraterística, ou seja, quantificar valores para avaliar a qualidade. Assim é possível comparar dois softwares quanto a um padrão de qualidade específico.

Pode ser difícil relacionar métricas e padrões de qualidade:



Qualidade Necessária por Tipo de Software

Cada tipo de software apresenta um níveis de qualidade desejada para cada fator de qualidade. Desse modo, uma aplicação para gestão de locadoras irá requerer menor eficiência que um sistema embarcado utilizado em satélites.



Anti-fatores de Qualidade

Assim como se definem os aspectos desejáveis de um software para que os requisitos do cliente sejam atendidos, é possível definir os aspectos indesejáveis chamados de anti-fatores de qualidade. Como exemplo, podemos citar as seguintes características:

  • rigidez: grande interdependência entre módulos do software;
  • imobilidade: incapacidade de reutilização.
Qualidade no Desenvolvimento


Uma abordagem para análise da qualidade no desenvolvimento envolve a avaliação das habilidades do programador no que tange ao projeto (reúso de código, adoção de padrões de projeto, qualidade da documentação, execução de testes, domínio de ferramentas e linguagens), à depuração (identificação de erros, otimização de desempenho) e ao trabalho em grupo (estimativas de esforço, uso de código de terceiros).

No entanto, de um modo geral, a qualidade de um processo de desenvolvimento de software pode ser medida por seu nível de maturidade. Neste contexto, o Modelo de Maturidade em Capacitação e Integração - CMMI apresenta-se como um modelo de referência baseado nas melhores práticas para desenvolvimento e manutenção de produtos.




Por sua relevância, o CMMI será tratado neste blog em um conjunto de artigos específicos.

Garantia de Qualidade

A Garantia de Qualidade de Software (SQA-Software Quality Assurance) é definida por Sommerville como sendo um arcabouço para se atingir a qualidade de um software. Já Pressman a define como sendo um padrão sistemático e planejado de ações exigidas para garantir a qualidade de um software.

Assim, a SQA visa garantir que os requisitos especificados, de produto e de processo, foram atendidos.

Para tal, os seguintes aspectos são observados:
  • Aplicação de métodos, técnicas e ferramentas.
  • Aplicação de padrões de produto (componentes do software) e processo (desenvolvimento do software).
  • Controle de alterações.
  • Medições de qualidade.
  • Anotações e manutenção de registros.

Em linhas gerais, a garantia de qualidade permite comparar o que está sendo feito com o que deveria estar sendo feito, permitindo a eliminação dessa diferença.