Categoria: Desenvolvimento (Página 6 de 8)

Os 10 erros clássicos do desenvolvimento de software

mistakesCom certeza você já se deparou com alguns erros clássicos do desenvolvimento de software. Infelizmente, por diversos motivos, as empresas e os engenheiros de software tem repetidamente falhado em seus projetos por não aprenderem com seus próprios erros. Que tal refletirmos sobre nossos maiores erros para, de alguma forma, evitar repeti-los?

Steve McConnell, um profissional experiente e autor de diversos livros e artigos sobre Engenharia Software, identifica em seu artigo Classic Mistakes os erros mais que ocorrem mais frequentemente. Abaixo, vamos analisar os 10 erros clássicos em projetos de software apontados pelo autor, acrescidos de alguns comentários:

10. Motivação

A motivação tem enorme impacto na produtividade e na qualidade, mas são poucos que adotam práticas efetivas para motivar as pessoas.

Salário não é o único nem o principal fator motivador, pois as pessoas tendem a se acostumar com o que ganham não importa o quanto seja. Programadores gostam de trabalhar com novidades tecnológicas, mas a excitação não dura tanto quanto gostaríamos, principalmente em projetos longos. Não existe uma fórmula mágica, o segredo é investir constantemente nas pessoas, financeiramente ou não.

Colegas mais experientes já me disseram que a motivação correta é um fator chave para o sucesso de um negócio.

9. Pessoas problemáticas

Não lidar com pessoas problemáticas, seja qual for o motivo, afeta a motivação de todos os envolvidos.

Soube de um gerente que teve problemas com o melhor desenvolvedor da equipe. Ninguém sabia se era inveja ou simplesmente o comportamento “normal” dele. Esse desenvolvedor constantemente gritava para toda a empresa ouvir a cada pequeno erro que seus colegas cometiam (como um erro de Português num e-mail), agredia verbalmente os outros desenvolvedores quando considerava suas dúvidas simples demais e interrompia deseducadamente seu gerente em reuniões com clientes e com a administração da empresa. O mal-estar foi generalizado e, embora ele fosse um desenvolvedor tecnicamente excelente, toda a equipe foi afetada negativamente.

8. Barulho

Lugares tumultuados e cheios de gente atrapalham muito a produtividade.

No livro Peopleware, o autor nos apresenta um exemplo de uma fábrica onde avisos eram feitos através de um sistema de auto-falantes, similar ao que ocorre em terminais, aeroportos e grandes lojas. Primeiro toca-se uma espécie de campainha e em seguida alguém fala. Todos os funcionários param o que estão fazendo para prestar atenção ao aviso, perdendo a concentração e levando algum tempo até retomar a produtividade anterior. Na maioria das vezes os avisos eram do tipo “fulano, favor comparecer ao…” e direcionados a apenas uma pessoa.

7. Abandonar o planejamento sob pressão

O cronograma ficou para trás e pressões surgem de todos os lados. A primeira reação é “sair correndo atrás do prejuízo”. Jogamos fora todo o planejamento (processo, testes, etc.) e tentamos entregar as funcionalidades como for possível, resultado num caos infinito de “codifica e arruma” (tentativa e erro).

6. Ignorar as atividades básicas de planejamento

“Pular” direto para a codificação aumenta de 10 a 100 vezes o custo de corrigir o código mal feito.

Não queira ser mais ágil que os métodos ágeis, pois até no agile em geral existe um plano detalhado da iteração (uma ou duas semanas, por exemplo) e um planejamento em alto nível até um certo horizonte do projeto.

Evite fazer em sua mente uma associação do ato de planejar com preencher documentos sem sentido. Planejar é pensar antecipadamente. Refletir sobre um problema antes de colocar a mão na massa irá evitar diversos tropeços.

5. Falta de controle de mudanças

Em média, os requisitos mudam 25% desde a fase de “requisitos definidos” até a primeira versão do sistema. Isso causa um aumento superior a 25% no cronograma. Portanto é necessário controlar as mudanças nos requisitos para limitar mudanças desnecessárias.

Controlar mudanças não consiste em limitar a adequação dos requisitos nem deixar de responder às mudanças em regras de negócio, como alguém pode pensar. O problema é que, se não houver controle, a tendência será um loop de alterações, muitas das quais serão feitas diversas vezes (por exemplo: aumenta fonte, diminui fonte, altera descrição, volta descrição anterior).

4. Síndrome da “bala de prata”

Quando as pessoas focam numa única ferramenta, tecnologia ou metodologia esperando que esta seja a solução para tudo, geralmente ocorre o contrário, a produtividade cai com o tempo.

Trabalhei na migração de um sistema feito na ferramenta chamada Genexus. É uma linguagem de quarta geração, tipo um Access um pouco mais evoluído, que se propõe a gerar telas e cadastros. Não vou entrar no mérito se é possível criar uma arquitetura adequada nessa ferramenta, mas no caso que conheço, apesar de ser muito mais fácil criar cadastros e telas do que em Java, com o tempo o código procedural do Genexus ficou tão complexo que alguns bugs simplesmente não podem ser corrigidos.

3. Informações insuficientes dos usuários

Uma pesquisa realizada em 1994 demonstrou que esta é a causa número um de fracassos em projetos de software.

Não adianta construir perfeitamente a coisa errada. Como engenheiros de software, e não como digitadores de código, nós temos a responsabilidade de compreender o suficiente sobre o domínio da aplicação para traduzir corretamente as necessidades de negócio em um sistema de software.

2. Cronogramas muito apertados

A mesma pesquisa também mostrou que a média de atraso dos projetos é de 220%, causados por cronogramas “agressivos”.

Ao permitirmos que a correria tome conta, as atividades que pensamos poder ignorar no princípio acabam sendo feitas com custo até 100 vezes maior em fases posteriores no projeto.

Além disso, a produtividade das pessoas cai devido à pressão. Alguns gerentes podem discordar, principalmente se estão acostumados a lidar com pessoas preguiçosas. Entretanto, os bons desenvolvedores não irão simplesmente produzir mais de uma hora para outra. Ao contrário, eles já dão o melhor e com a pressão passarão a cometer mais erros.

1. Adicionar mais desenvolvedores

Segundo o autor, este é o engano mais comum. A verdade é que, salvo raras exceções, adicionar pessoas à equipe vai gerar mais trabalho para as que já estavam no projeto, pois elas terão que parar a todo momento para explicar detalhes para os novos desenvolvedores. Dificilmente os novatos alcançarão um nível de produtividade recompensador no tempo esperado.

Eclipse: acabando com alguns erros de validação desnecessários

Erros de sintaxe em bibliotecas Javascript como jQuery e jQuery UI quando estão minimizadas (compactadas)

É uma dor de cabeça ver seu projeto sempre com erro por colocar uma versão minified do jQuery ou jQuery UI. A solução para isso, que aplica-se a qualquer script avaliado incorretamente como tendo um erro, é excluir o arquivo javascript específico da validação do Eclipse.

Em resumo, você precisa excluir os arquivos javascript da sua lista de fontes, conforme as telas abaixo:

Abaixo, o passo-a-passo com detalhes:

  1. Clique com o botão direito no projeto e, no menu, escolha a opção Properties.
  2. Navegue até o item JavaScript > Include Path e selecione a aba Source.
  3. Selecione o item Excluded na lista e clique em Edit….
  4. Clique em Add Multiple… e selecione os arquivos com problemas
  5. Clique em Finish e em Ok para confirmar

Observação: restrinja essa configuração para bibliotecas conhecidas e confiáveis, evitando a todo custo fazer isso para seus próprios scripts de modo a ocultar erros no seu código.

Erros de validação e sintaxe em XML

Existem muitos problemas diferentes de validação em XML. Tentarei cobrir os mais comuns:

Eclipse não consegue acessar o arquivo de validação (XSD ou DTD)

Por alguma razão, o Eclipse não consegue acessar o arquivo de definição (XSD ou DTD). Logo no início do XML, provavelmente você vai notar que há uma URL para um arquivo com extensão .dtd ou .xsd. Se o estiver offline, sob um proxy ou por qualquer outro motivo o Eclipse não puder baixar esse arquivo, ocorrerá erro de validação e uma possível lentidão até ocorrer um timeout.

Para resolver isso, baixe manualmente o arquivo de definição a partir da URL, acesse a configuração Windows > Preferences… > XML > XML Catalog no Eclipse, clique em Add… e adicione manualmente o arquivo baixado.

URL de arquivo de validação incorreta

Falhas de validação referentes à sintaxe também ocorrem com frequência. Após certificar-se de que está tudo certo no corpo do XML, verifique se as declarações dos arquivos de validação estão corretos na raiz do arquivo (xmlns e xsi:schemaLocation).

Recentemente tive problemas com um arquivo web.xml que estava com uma URL depreciada:

http://java.sun.com/xml/ns/j2ee

Ao invés da atualizada:

http://java.sun.com/xml/ns/javaee

A mensagem de erro era longa, iniciando com “s4s-elt-character: Non-whitespace characters…“. Bastou trocar j2ee para javaee e o erro de validação desapareceu. Na versão 2.5 da API do Servlet, o conteúdo correto da declaração é:

<?xml version="1.0" encoding="UTF-8"?>
<web-app 
	xmlns="http://java.sun.com/xml/ns/javaee" 
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 
		http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" 
	version="2.5">
(...)

Versão de arquivo de validação incorreta

Outro problema que já tive algumas vezes foi com o XML de configuração do Spring Framework. Atualizei a versão do framework e o XML de configuração começou apresentar erros somente quando eu estava offline.

Isso ocorre porque, no caso do Spring, o DTD de validação vem empacotado dentro do jar. Com a URL certa, mesmo offline o Eclipse encontra o arquivo de validação. Mas se mudarmos a versão do jar sem refletir a mudança no XML, o Eclipse vai tentar localizar o arquivo na internet.

Foi preciso apenas trocar a versão do caminho do DTD correspondendo à versão do Spring Framework. Exemplo:

<?xml version="1.0" encoding="UTF-8"?> 
<beans
    xmlns="http://www.springframework.org/schema/beans" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
(...)

Nesse exemplo, a versão 3.0 deveria ser atualizada para 3.1, conforme o upgrade do framework:

<?xml version="1.0" encoding="UTF-8"?> 
<beans
    xmlns="http://www.springframework.org/schema/beans" 
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
(...)

Erros em projetos Maven com o plugin m2e (Maven to Eclipse)

Antes de mais nada, é importante salientar que o m2e é um plugin do Eclipse que o integra ao Maven. Entretanto, o Maven possui seus próprios plugins. Portanto, não confundamos plugins do Eclipse com plugins do Maven.

Project configuration is not up-to-date with pom.xml

O erro mais comum em projetos com a Maven Nature (Natureza Maven, aqueles que ficam com um pequeno “M” no ícone do projeto) é quando o projeto não está atualizado conforme o arquivo de configuração do Maven (pom.xml). A mensagem é  “Project configuration is not up-to-date with pom.xml” e ocorre porque, dependendo das alterações no pom, as configurações de projeto (.project) e do classpath (.classpath), além de outros possíveis plugins do Eclipse, precisam ser atualizadas para refletir o novo pom.

Este é o problema mais simples de resolver, pois basta clicar com o botão direito sobre o projeto, acessar o menu Maven > Update Project… e confirmar.

Plugin execution not covered by lifecycle configuration

Outro erro comum ocorre ao usar um plugin no build do Maven que não seja reconhecido pelo m2e. Aparece a temida mensagem “Plugin execution not covered by lifecycle configuration…“. Isso ocorre porque o m2e não sabe como executar um determinado plugin do Maven dentro do Eclipse.

Anteriormente era necessário acrescentar uma tag um tanto volumosa em nosso pom para informar ao m2e o que ele deve fazer. Já nas versões mais novas do m2e, basta selecionar o erro new view Problems e aplicar um Quick Fix, solicitando ao m2e acrescentar o código necessário automaticamente.

É importante atentar para o fato de que há duas opções de solução: a primeira é acrescentar o código no próprio pom.xml, enquanto a segunda é acrescentar a solução de forma global para os projetos do workspace, o que é bem conveniente no caso de usar um certo plugin em vários projetos.

Para acessar a configuração global de mapeamento de plugins, acesse Window > Preferences… > Maven > Lifecycle Mappings. Nesta tela você pode abrir o arquivo clicando no botão Open workspace lifecycle mappings metadata.

Outros problemas com Maven

Se, ao tentar atualizar o projeto com o Update Project ocorrer algum tipo de exceção, tome as seguintes providências:

  • Verifique se você está sob um proxy. Se estiver, configure seus dados de acesso no arquivo settings.xml seguindo o modelo existente, recarregue as configurações do Maven através do botão de refresh na view Maven Repositories do Eclipse e faça um novo Update Project.
  • Verifique também as versões de dependências entre seus projetos. Uma versão errada pode gerar diferentes erros.
  • Remova do seu arquivo .classpath qualquer entrada que use uma variável, do tipo kind=”var”.
  • Verifique se existe algum outro erro no classpath, pois, por exemplo, uma entrada apontando para um arquivo jar inexistente impede o Eclipse de compilar o projeto. Faça um novo Update Project.
  • Quando a compilação do projeto falha mesmo quando o Maven Dependecies está funcionando (isto é, o classpath está sendo gerenciado corretamente pelo Maven), pode ser que algum jar baixado pelo Maven esteja corrompido. Verifique na sua pasta de repositório (geralmente uma pasta chamada “.m2” dentro da sua pasta de usuário) se os jars usados no seu projeto estão íntegros, abrindo-os com alguma ferramenta como o 7-zip.
  • Verifique na view Problems se existe algum erro no projeto que seja relacionado ao Maven. Procure então na view Error Log por mais detalhes, para tentar encontrar alguma pista sobre a causa. Por fim, se não encontrar a causa, olhe o arquivo de log do m2e no diretório “.metadata\.plugins\org.eclipse.m2e.logback.configuration” do seu workspace.

E você? Tem algum erro/problema misterioso em seus projetos do Eclipse? Comente!

Construindo objetos de forma inteligente: Builder Pattern e Fluent Interfaces

building-with-legosA Orientação a Objetos é constantemente mal utilizada. Sem o devido treino, temos a tendência de raciocinar de forma estruturada.

Esse problema está tão enraizado que muitas vezes encontramos dificuldades nos pontos mais fundamentais da programação, tal como a construção de instâncias de objetos um tanto mais complexos que beans simples. Como consequência, nosso código fica difícil de manter e mais propenso a erros.

Portanto, todo desenvolvedor deve estudar Padrões de Projetos (Design Patterns), já que estes ajudam a resolver os problemas mais comumente enfrentados e nos dão o treino necessário para pensarmos sobre os problemas mais complexos. Além disso, existem outras técnicas, como as Interfaces Fluentes (Fluent Interfaces), que ajudam a criarmos código mais legível e, dessa forma, aumentam a produtividade e diminuem a propensão a erros.

Criando um objeto (the dummy way)

Suponha que precisamos criar um objeto com diversos atributos “opcionais”. Vamos usar uma pizza como exemplo (um dos exemplos clássicos para ilustrar padrões de projetos). Já vi muitos construtores de “pizza” por aí da seguinte forma:

public class Pizza {

	private int tamanho;
	private boolean queijo;
	private boolean tomate;
	private boolean bacon;

	Pizza(int tamanho) {
		this.tamanho = tamanho;
	}

	Pizza(int tamanho, boolean queijo) { 
		this(tamanho);
		this.queijo = queijo;
	}

	Pizza(int tamanho, boolean queijo, boolean tomate) {
		this(tamanho, queijo);
		this.tomate = tomate;
	}

	Pizza(int tamanho, boolean queijo, boolean tomate, boolean bacon) {
		this(tamanho, queijo, tomate);
		this.bacon = bacon;
	}

}

Diga a verdade, você já faz isso em algum momento? E pode ficar pior se acrescentarmos construtores com combinações e ordenação diferentes de parâmetros!

A sobrecarga é interessante quando temos algumas poucas variações de parâmetros e há poucas mudanças no conjunto de atributos. Porém, chega uma hora que nem sabemos mais o que está acontecendo. Quanto tempo você já perdeu inspecionando conteúdo de classes de terceiros para entender que valores deveria usar? Exemplo:

new Pizza(10, true, false, true, false, true, false, true, false...)

Que tipo de pizza é essa mesmo? 😯

Criando um objeto com Builder Pattern

Alerta: antes que alguém fique agitado porque este exemplo diverge do Builder Pattern originalmente publicado no GoF, leia o livro com atenção, pois os próprios autores propõem implementações alternativas dos padrões de projeto e afirmam categoricamente que estes devem ser adaptados de acordo com o contexto. É sério, está escrito lá, acredite ou não.

public class Pizza {

	private int tamanho;
	private boolean queijo;
	private boolean tomate;
	private boolean bacon;

	public static class Builder {

		// requerido
		private final int tamanho;

		// opcional
		private boolean queijo = false;
		private boolean tomate = false;
		private boolean bacon = false;

		public Builder(int tamanho) {
			this.tamanho = tamanho;
		}

		public Builder queijo() {
			queijo = true;
			return this;
		}

		public Builder tomate() {
			tomate = true;
			return this;
		}

		public Builder bacon() {
			bacon = true;
			return this;
		}

		public Pizza build() {
			return new Pizza(this);
		}

	}

	private Pizza(Builder builder) {
		tamanho = builder.tamanho;
		queijo = builder.queijo;
		tomate = builder.tomate;
		bacon = builder.bacon;
	}

}

Aplicando o padrão de projeto Builder, temos agora um objeto “construtor” para o objeto Pizza. A classe Pizza está um pouco mais complexa, mas confira como ficou elegante a forma de temperarmos:

Pizza pizza = new Pizza.Builder(10)
                       .queijo()
                       .tomate()
                       .bacon()
                       .build();

É muito mais fácil de codificar com essa API e entender o que está acontecendo.

O Builder Pattern é muito utilizado em boas bibliotecas que disponibilizam APIs intuitivas e fáceis de aprender, como construtores de XML e o Response do JAX-RS, por exemplo.

Composição de Objetos

Outro ponto onde temos dificuldades encontra-se na criação de objetos que são compostos por vários objetos. Como exemplo, vamos montar um pedido com alguns itens para um cliente:

public class Pedido {

	List<Item> itens;
	Cliente cliente;

	void adicionarItem(Item item) {
		itens.add(item);
	}

	void setCliente(Cliente cliente) {
		this.cliente = cliente;
	}

	void fechar() {
		// ...
	}

}

O uso fica assim:

Pedido p = new Pedido();
p.setCliente(new Cliente("José"));
p.adicionarItem(new Item("Motocicleta", 1));
p.adicionarItem(new Item("Capacete", 2));
p.fechar();

Embora, neste exemplo, nosso código esteja relativamente simples, um objeto mais complexo dificultaria ao desenvolvedor entender o código. Mas, estou certo, podemos fazer muito melhor que isso!

Interface Fluente

A “mágica” das Interfaces Fluentes está em encadear métodos que retornam a instância do próprio objeto, evitando repetições desnecessárias no código “cliente”. Abaixo, o exemplo anterior foi ligeiramente modificado:

public class Pedido {

	List<Item> itens;
	Cliente cliente;

	Pedido com(int quantidade, String nome) {
		itens.add(new Item(nome, quantidade));
		return this;
	}

	Pedido para(String nome) {
		cliente = new Cliente(nome);
		return this;
	}

	void fechar() {
		// ...
	}

}

O uso fica assim:

new Pedido()
	.para("José")
	.com(1, "Motocicleta")
	.com(2, "Capacete")
	.fechar();

Muito mais limpo, com maior clareza e intuitivo, não é mesmo?

Classes Utilitárias

Temos ainda classes utilitárias com seus métodos estáticos, usadas nos mais diversos pontos da arquitetura de um sistema. Elas causam problemas quando mal planejadas, pois a tendência é acumularmos muitos métodos sobrecarregados com diferentes objetivos que infectam todo o código. Então, sem perceber, perdemos o controle, já que agora todo o sistema está acoplado a tais classes e alterações acabam impactando onde não esperamos.

Vejamos um exemplo de uma típica classe com rotinas de tratamento de datas:

public class Data {

	public static Date converteTextoParaData(String dataStr) {
		try {
			return new SimpleDateFormat("dd/MM/yyyy").parse(dataStr);
		} catch (ParseException e) {
			return null;
		}
	}

	public static String converteDataParaTexto(Date data) {
		return new SimpleDateFormat("dd/MM/yyyy").format(data);
	}

	public static Date avancarDiasCorridos(Date dataInicial, int dias) {
		Calendar c = Calendar.getInstance();
		c.setTime(dataInicial);
		c.add(Calendar.DATE, dias);
		return c.getTime();
	}

}

Eis como ficaria uma manipulação simples de data usando essa classe:

String inputDateStr = "28/02/2013";
Date inputDate = Data.converteTextoParaData(inputDateStr);
Date resultDate = Data.avancarDiasCorridos(inputDate, 30);
String resultDateStr = Data.converteDataParaTexto(resultDate);

Entediante. Vamos refatorar a classe com o conceito de Interface Fluente:

public class Data {

	private Date data;
	public Data(String dataStr) {
		try {
			data = new SimpleDateFormat("dd/MM/yyyy").parse(dataStr);
		} catch (ParseException e) {
			throw new IllegalArgumentException(e);
		}
	}

	public String toString() {
		return new SimpleDateFormat("dd/MM/yyyy").format(data);
	}

	public Data avancarDiasCorridos(int dias) {
		Calendar c = Calendar.getInstance();
		c.setTime(data);
		c.add(Calendar.DATE, dias);
		data = c.getTime();
		return this;
	}

}

E o uso fica assim:

String resultDateStr = new Data("28/02/2013").avancarDiasCorridos(30).toString();

Simples, não?

Nota: considere este como um exemplo de estudo. O uso do new para instanciar objetos é discutível, assim como o uso da classe java.util.Date.

Conclusões

Simplificar o código não é luxo. Trata-se de uma necessidade na luta contra a crescente complexidade dos sistemas de software.

A utilização de padrões de projetos como o Builder Pattern e técnicas como a Fluent Language nos auxiliam nessa empreitada, além de tornar a codificação mais simples e agradável.

Outro ponto positivo é que, ao utilizar objetos específicos para tratar problemas comuns, como no exemplo de Fluent Language, fica mais fácil manter o foco da responsabilidade das classes. Com métodos estáticos, a tendência é acrescentar novos métodos indiscriminadamente, enquanto com um objeto “inteligente” temos uma melhor percepção dos limites.

Leitura Obrigatória

Para ler mais sobre Fluent Interfaces, acesse http://martinfowler.com/bliki/FluentInterface.html.

Além disso, todo desenvolvedor deve ler o livro Design Patterns: Elements of Reusable Object-Oriented Software. Infelizmente, o livro é um tanto antigo e os exemplos podem ser um pouco “chatos” para desenvolvedores web, pois muitos aplicam-se à construção de GUI de aplicativos desktop.

Especificamente para quem está iniciando em Java, uma leitura mais leve é o Head First Design Patterns. É mais fácil de entender, porém incompleto. Não espere encontrar todos os padrões em detalhes. Muitos deles só constam no final como uma espécie de resumo.

Integração com Web Sevices usando Axis e inspecionando o conteúdo da mensagem SOAP

É comum realizarmos integrações entre sistemas através de Web Services tradicionais. Na minha empresa, em particular, usamos o Apache Axis, uma implementação Java do protocolo SOAP (Simple Access Object Protocol).

Observação: tratando-se de prover serviços de integração, eu, particularmente, escolheria o protocolo REST, mas quando acessamos serviços de terceiros não temos muita escolha, não é?

Irei descrever, em alto nível, os passos que geralmente realizamos para implementar a integração.

Requisitos

Antes de mais nada precisamos do arquivo WSDL (Web Servcie Definition Language), o qual define todos os serviços disponíveis, parâmetros e tipos de dados utilizados.

Algumas vezes recebemos a URL do end point, isto é, o endereço do Web Service. Por exemplo:

http://servidor:8080/app/webservices

Neste caso, obtemos o arquivo WSDL acresentando um parâmetro ao endereço, assim:

http://servidor:8080/app/webservices?wsdl

Gerando o client

O primeiro passo de implementação é gerar as classes de domínio e as interfaces stub usando o plugin do Eclipse WTP. (Siga os links para maiores detalhes)

Os objetos client são gerados com base no WSDL e assim o acesso ao Web Service se dá como uma chamada de método local, usando objetos locais, via RPC (Remote Procedure Call). A conversão dos objetos de e para XML no formato SOAP, além do transporte na rede é feito de forma transparente para o desenvolvedor.

Testando

O testes de integração com serviços de terceiros, pelo menos no nosso caso, não é algo viável de automatizar, pois não termos controle sobre o ambiente, nem acesso direto.

Para verificarmos se o serviços estão sendo acessados corretamente, criamos uma classe de teste com valores fictícios. O modelo do código ficou mais ou menos assim:

ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service service = serviceFactory.createService(
        new ServicoServiceLocator().getServiceName()
    );
ServicoSoapStub stub = new ServicoSoapStub(
        new java.net.URL("http://site.com.br/app/ws"), 
        service
    );
ClasseRetorno retorno = stub.executarServico(
        new ParametroServico(...)
    );

Este link contém mais alguns que você pode usar como modelo para o seu Web Service.

Analisando o conteúdo da mensagem SOAP

Num caso específico, o cliente enviou exemplos de mensagens XML no protocolo SOAP e quisemos verificar se as mensagens geradas pelo Axis a partir do nosso código eram equivalentes em conteúdo.

Para inspecionar o Axis e ver o conteúdo da mensagem, adicionei os jars do log4j, commons-logging e commons-discovery. Também acrescentei na configuração do log (log4j.properties) a seguinte linha:

log4j.logger.httpclient.wire.content=DEBUG

Dessa forma, foram adicionadas mensagens no LOG com todo o conteúdo enviado pelo Axis.

Processos feitos para o fracasso

imagesO universo da tecnologia da informação é repleto de processos. Temos processos para desenvolvimento de software, prestação de serviços, gerenciamento de projetos (específicos ou não de software), garantia de qualidade e até para preparar o cafezinho da cozinha.

Note que não estou me referindo exatamente a modelos de processos como waterfall (cascata), iterativo, incremental, evolucionário, espiral e de prototipação, nem de metodologias ou frameworks de processos como Scrum, XP, RUP, ITIL, COBIT, CMMI ou MPS.BR. Todos estes possuem seu valor e nos dão uma base para definir o processo que adotamos no dia-a-dia nos mais diversos aspectos, incluindo artefatos, atividades e boas práticas fundamentais.

O foco deste artigo é no processo implementado em nosso ambiente de trabalho, o qual somos (algumas vezes) obrigados a seguir. 

Em conversas com colegas de trabalho, ao pronunciar a palavra mágica “processo”, geralmente ocorrem duas reações: uma gargalhada ou uma cara feia. No primeiro caso, o riso é acompanhando de desdém, tipo: ” se pelo menos tivéssemos um processo de verdade…”. Do outro lado, estão os que ficam quase irados: “não entendo porque nos fazem perder tempo com esses processos que não servem pra nada!”

Mas e aí? Você se encaixa em um desses grupos? O processo é um obstáculo no seu trabalho? Ou talvez você esteja do outro lado, criando processos para sua equipe ou empresa e acredita que certas atividades são de grande importância, mas não consegue se fazer entender. Vamos analisar alguns desses aspectos nos tópicos a seguir.

Quando realmente sofremos com o absurdo

angry-computer-large

Para ilustrar o sofrimento que alguns desenvolvedores tem de aturar, irei descrever exemplos de alguns dos piores casos de processos, ou de motivos para a definição deles, que já testemunhei:

Ditadura
Alguém da diretoria quer “controlar melhor” as atividades, culminando em algo excessivo e desnecessário. Houve um caso onde o chefe queria relatórios de atividades dos funcionários com detalhes em minutos! Por quê? Vai saber…

Labirinto
Processo confuso e redundante. Além de mandar e-mail, preencher documentos e incluir informações no sistema de controle, ainda é necessário imprimir e assinar um documento. Nesse tipo de processo, o desenvolvedor sempre é “culpado” por esquecer algum dos passos “essenciais” do processo.

Surpresa
Tudo está normal, de repente, você dá de cara com o processo.

Certa vez, ao  solicitar o envio de um script de correção urgente ao cliente, responderam-me:
– “Onde está o documento de envio?”
– “Que documento?”, repliquei.
E então, a surpresa:
– “Houve uma reunião com a diretoria hoje e recebemos ordens de, a partir de agora, não enviar nada ao cliente que não esteja acompanhados do respectivo documento de envio.”
Bem, restou-me correr atrás de alguém que pudesse me dizer do que isso se tratava… ordens são ordens, não é?

Morto-vivo
Às vezes o processo é essencial, outras nem tanto. Você leu o tópico anterior? Algum tempo depois disseram que o tal documento não era mais necessário. Isso mudou intermitentemente algumas vezes. Já aconteceu de você ficar perdido em como sua empresa funciona?

“Garantia” de Qualidade
Neste ponto alguém pode até argumentar em contrário, devido às boas práticas que alguns processos agregam. Porém, já presenciei casos onde um determinado processo foi adotado para tentar diminuir o número de defeitos num sistema! Primeiro, de forma geral, a burocracia apenas deixa o programador mais nervoso. Além disso, os desenvolvedores eram pouco experientes, então seria melhor investir em treinamento ou incluir pessoas mais maduras no projeto.
Em outra situação, um funcionário que recebeu a incumbência de uma atividade simples estava errando repetidamente, semana após semana. Ele simplesmente devia copiar alguns valores de uma planilha e fazer a inclusão no banco de dados, mas frequentemente os valores do sistema ficavam errados. Seu superior não sabia o que fazer. Seria de propósito? Seria uma total falta de inabilidade? Seria falta de comprometimento? O gerente tentou resolver a situação com um “processo” onde o funcionário problemático teria que “prestar contas” de suas ações. Obviamente isso não resolveu.

Marketing
Determinados certificados relacionados a processos (como CMMI e MPS.BR) colaboram para o status das empresas. Logo algumas investem tempo e dinheiro em práticas e documentações inúteis a fim de aumentar sua credibilidade para com clientes em potencial, sem se preocupar efetivamente com a qualidade de seus produtos ou com a queda de produtividade. Resta aos funcionários ficar até mais tarde para cumprir as exigências adicionais.

Processos servem para alguma coisa, afinal?

O processo é uma ferramenta. Como tal, ele deve ser usado para que os envolvidos e a organização como um todo alcancem seus objetivos. Estes objetivos devem estar alinhados às metas da organização, aos requisitos dos clientes e com as exigências dos órgãos regulatórios.

Um grande problema é que os requisitos e exigências são por vezes conflitantes. Por exemplo, para o cliente, as entregas de correções devem ser imediatas. Entretanto, do ponto de vista de qualidade, é necessário haver revisão e testes, que oneram razoavelmente o tempo necessário para entregar algo. Nos ambientes mais desorganizados, o desenvolvedor pode executar um script diretamente em produção. Por outro lado, em algumas empresas os usuários estão acostumados a ficar dias parados porque as correções não podem ser aplicadas sem uma série de aprovações de diferentes setores.

O processo pelo processo

Um dos maiores erros na engenharia de software é adotar um processo sem um motivo concreto, porque é “legal”, a última moda. Pior, alguns acreditam que determinado processo é a solução para as dificuldades do dia-a-dia. Ainda há aqueles que ficam tão impressionados com um determinado processo que tentam adotá-lo integralmente, com toda sua carga de artefatos e atividades.

Muitos gerentes e diretores acreditam que podem resolver os problemas de gerenciamento simplesmente adotando uma nova abordagem de processos. Eles não conseguem entender porque seus subordinados são tão avessos e resistem tão intensamento a mudanças. Por que será?

É uma questão de mentalidade

Por que resistimos aos processos e reclamamos deles? Por que alguns relatam um “renascimento” ao adotar processos ágeis? Por que os gerentes estão sempre impondo novos processos?

Existem conflitos de expectativas e entendimento. Considerando que não haja absurdos no processo, os desenvolvedores reclamam porque não entendem a necessidade da diretoria. Por que parece que quando um programador é promovido a gerente ele se “converte ao lado negro da força”? Na verdade ele simplesmente amadureceu e percebeu a importância de um gerenciamento adequado. Nós, desenvolvedores, devemos procurar amadurecer e compreender os desafios de nossos superiores, pois assim poderemos contribuir de forma mais efetiva em nosso trabalho e, quem sabe, os gerentes não sentirão a necessidade de criar processos rígidos para resolver seus problemas.

Por outro lado, os gerentes devem entender que processos não resolvem os problemas por si mesmos. Analogamente ao nosso governo, criar leis duras e colocar o exército nas ruas não irá mudar a mentalidade do povo, embora a opressão possa dar a impressão de maior organização e controle. Fazer “a coisa certa” é um desafio gigante, mas conseguir a sincera colaboração e motivação dos envolvidos é algo que não tem preço.

E os processo ágeis? Os “agilistas” relatam que métodos ágeis podem aumentar em diversas vezes a produtividade da equipe, a qualidade, deixar o cliente mais satisfeito e os desenvolvedores mais felizes e realizados. Será que realmente não seria o caso de existir um processo “bala de prata”, isto é, que garantisse o sucesso?

Se você observar a literatura dos “agilistas”, perceberá que antes de alcançar qualquer nível de sucesso, houve uma mudança de mentalidade geral dos envolvidos. Mas, quando o processo ágil falha, logo dizem que ele não foi seguido corretamente. Há uma certa verdade nisso, pois sempre que falhamos é porque não fizemos as coisas como deveriam ser feitas. Porém isto também se aplica a todos os processos.

Conclusões

Enquanto, em nosso trabalho, não pararmos de correr desenfreadamente em qualquer direção, pensando apenas em entregar código e se livrar do fardo que os superiores nos colocam, nunca iremos amadurecer, crescer profissionalmente e ter o prazer de entregar software bem feito.

Devemos rever nossos conceitos e despertar para a realidade do que estamos fazendo, não apenas continuar a repetir indefinidamente e irrefletidamente o que já praticamos vez após vez.

Devemos usar o processo como um aliado para nossos objetivos, que deve intervir em caso de necessidade e não como lei primordial. A chave para o sucesso do projeto (e do processo também), consiste em:

  • Transparência: o desenvolvedor merece saber e deve entender a razão do processo;
  • Confiança: o processo não deve ser feito baseado na desconfiança entre as partes ou resultará em um mal-estar geral;
  • Equilíbrio: embora virtualmente fosse bom controlar tudo o que ocorre na empresa, o processo deve ser apenas bom o suficiente para cumprir seus objetivos.

Lembre-se: o processo pode tanto contribuir como obstruir o desenvolvimento de software.

Para refletir: como saber se seu processo foi feito para o fracasso?

Pense nas atividades que devem ser executadas. Se o sentimento que lhe vier à mente for equivalente a quando você precisa fazer uma ligação de cancelamento de serviços (TV a cabo, celular, …), então provavelmente as pessoas farão tudo ao seu alcance para evitá-lo!

Se você está nessa situação (e é fã de Star Trek) vai entender que “resistir é inútil!”

Comportamento recursivo inesperado no SQL Server

Como todo desenvolvedor, provavelmente você já perdeu horas com um problema que beira o bizarro até perceber que era algo muito simples.

Uma colega estava testando um sistema onde uma procedure era acionada e, após algum tempo, ocorria um erro “Maximum stored procedure, function, trigger, or view nesting level exceeded (limit 32)”.

O erro refere-se ao limite de chamadas empilhadas ou recursivas, por exemplo, uma função que chama outra, que chama outra e assim por diante. Entretanto, a procedure não tinha nenhuma chamada desse tipo.

Analisei por alguns segundos os script de criação da procedure, algo como:

CREATE PROCEDURE MINHA_PROC (...) AS
BEGIN
... conteúdo ...
END
EXEC PROCEDURE MINHA_PROC [valores de teste]

Então lembrei de uma “pegadinha” de sintaxe. Para o SQL Server, o conteúdo de uma procedure é tudo o que está entre o CREATE e o “GO”. É o equivalente à barra invertida no Oracle.

Repare que no código de exemplo não existe um GO, pois o desenvolvedor assumiu que o bloco BEGIN/END demarcaria a procedure, mas não é o caso. O comando “EXEC” usado para testar a procedure acabou incluído como parte dela e, quando executada, criou chamadas recursivas até estourar o limite.

Solução? Tão simples quando um “GO”:

CREATE PROCEDURE MINHA_PROC (...) AS
BEGIN
... conteúdo ...
END
GO
EXEC PROCEDURE MINHA_PROC [valores de teste]

Uma forma simples de contar registros e limpar tabelas de uma base de dados

Uma colega estava com alguns backups de uma base de dados SQL Server para realizar testes e queria diminuir o tamanho das bases limpando tabelas de log e operacionais, mantendo apenas as configurações do sistema. O problema é que as bases eram tão grandes que ultrapassavam o limite de 10 GB estabelecido na versão SQL Express 2008.

Ele não precisava e nem queria entender a estrutura de tabelas, então sugeri uma maneira rápida e simples de identificar tabelas com muitos registros e uma forma de excluí-las rapidamente.

A query abaixo retorna vários selects que exibem o total de registros de cada tabela de um banco de dados:

use NOME_BASE
go
select 'select ''' + name + ''', count(*) from ' + name from sys.tables

Basta executar esse código, substituindo o nome da base a ser usada, copiar o resultado gerado e executá-lo.

Esta query gera deletes para cada tabela, no caso de ser necessário limpar a base toda:

select 'delete from ' + name from sys.tables

A versão usando truncate:

select 'truncate table ' + name from sys.tables

Planning Poker existe, sem brincadeira

No último post, mencionei um tal de planning poker e um colega achou que era parte da brincadeira. Para quem não conhece, talvez a frase em questão talvez não tenha feito tanto sentido:

Coloque uma equipe de juniors num processo ágil, eles vão começar a estimar usando planning poker e provavelmente vão continuar jogando poker até o final do projeto.
Para quem já conhece é chover no molhado. Mas vamos lembrar que ainda existem muitas pessoas que desconhecem completamente os processos ágeis ou apenas ouviram falar deles. E nem sempre é culpa é do indivíduo em si, pois quantos formandos saem de um curso de Ciências da Computação sem nem ouvir falar desse assunto. Isso aconteceu comigo. O único contato com Engenharia de Software foi uma disciplina cujo conteúdo consistia em alguns capítulos do Pressman.

Infelizmente muitas universidades não contam com professores que possuem experiência de mercado, outras vezes a grade curricular não ajuda. Existem professores que ensinam o mesmo conteúdo há tantos anos que dá a impressão de que a tecnologia não evoluiu. Outros são inexperientes e adotam um livro guia, apenas resumem o conteúdo.

O que é Planning Poker?

É uma forma de criar estimativas. 

Estimação é uma atividade fundamental de todo processo ágil. A cada início de iteração (sprint), as estórias de usuário (requisitos) que serão implementadas precisam ser detalhadas e estimadas. Esta é uma tarefa realizada em conjunto por todo o time (equipe).

Com o Planning Poker a tarefa de estimar pode ser mais interessante e divertida, o entendimento dos requisitos é melhor entendido pela equipe e há motivos para se acreditar que tenha bons resultados.

Adaptei uma explicação de como a técnica funciona do site www.crisp.se, detalhada a seguir.

Estimativas sem Planning Poker

Há um problema típico com as estimativas em equipe. Vamos supor que estamos na Reunião de Planejamento do Sprint e o Product Owner diz:

Pessoal, qual o tamanho dessa estória de usuário aqui?

Então a equipe começa a pensar sobre o tamanho dessa estória (em homem-dia nesse caso):

Sem Planning Poker - Passo 1

O sr. 

A acredita que ele sabe exatamente o que deve ser feito e acha que levará 3 dias. Os senhores C são mais pessimistas. D e E estão pensando em qualquer outra coisa. Então o sr. A se antecipa e diz: “vai levar 3 dias”.

Sem Planning Poker - Passo 2

Isso deixa 

B e C confusos, duvidando de suas estimativas. O sr. E volta a si e nem sabe o que está sendo estimado, enquanto D continua cochilando. Quando o Product Owner pergunta ao resto da equipe sobre suas estimativas, todos acabam sendo influenciados por A, que respondeu primeiro, e respondem:

Sem Planning Poker - Passo 3

Estimando com Planning Poker

Agora, imagine cada membro a equipe segurando o seguinte maço de cartas:

Cartas Planning Poker

Vamos refazer a estimação. O 

Product Owner diz: “Pessoal, qual o tamanho dessa estória de usuário aqui?” Mais uma vez, a equipe começa a pensar.

Com Planning Poker - Passo 1

Desta vez, ninguém se antecipa. Cada um seleciona uma carta contendo sua estimativa e a deixa virada sobre a mesa. Depois que todos colocam suas cartas, os senhores 

D e E acordam. Eles admitem que dormiram e perguntam qual estória está sendo estimada, pois é difícil chutar estimativas dessa forma. Quando todos terminam, as cartas são viradas simultaneamente, revelando as estimativas de cada pessoa.

Com Planning Poker - Passo 2

Ops! Houve uma grande divergência. A equipe, principalmente o sr. 

A e o sr. C, precisam discutir a estória e porque suas estimativas estão tão distintas. Depois de alguma discussão, o sr. A percebe que esqueceu algumas tarefas importantes que deveriam ser incluídas na estória. O sr. C percebe que, com o design que o sr. A apresentou, a estória pode ser menor que 20. Depois de 3 minutos de conversa, um novo round de estimação é feito para a mesma estória:

Com Planning Poker - Passo 3

Houve convergência, ainda que parcial. Então eles concordam que uma estimativa de valor 5 deve estar próxima o bastante e partem para a próxima estória.

Porque essa estranha série de números?

Cartas Os números grandes tem menos granularidade. Por quê? Porque não há o número 21, por exemplo? Algumas razões:

  • Aumentar a velocidade o processo de estimação limitando a quantidade de escolhas (número de cartas).
  • Evitar a falsa sensação de precisão (acurácia) para as estimativas mais altas.
  • Encorajar a equipe a dividir grandes estórias em menores.

Uma estimativa alta (maior que 20, por exemplo), geralmente significa que a estória não foi bem compreendida. Seria uma perda de tempo discutir se a estória vale 19, 20 ou 22,5. A estória é grande e pronto. Se for necessário detalhar a estória, deve-se quebrá-la em estórias menores.

Cartas Especiais

A carta “zero” significa que a estória já foi implementada ou que ela é ínfima, consistindo talvez em alguns minutos de trabalho.
A carta “interrogação” (“?”) significa que a pessoa não tem absolutamente nenhuma ideia. Nada. É raro acontecer, mas se a frequência aumentar a equipe deve discutir mais as estórias e tentar chegar a um melhor entendimento.
A carta “xícara de café” significa: “Estou cansado demais para pensar. Vamos fazer uma pausa”.

PSP – Personal Software Process

Não espere qualidade da sua empresa, seja a qualidade!

De quem é a culpa da má qualidade dos softwares?

Acho que todos já ouvimos falar sobre modelos de maturidade como CMMI ou MPS.BR e processos como o RUP, Scrum ou XP. Quase sempre isso vem acompanhado de comentários críticos e pessimistas de como a nossa empresa está longe de ser maduro e prover produtos de qualidade.

Por outro lado, mesmo empresas que investem em maturidade do processo muitas vezes esquecem que ele não é uma bala de prata. Não existe processo ótimo sem ótimas pessoas. É um mito industrial a possibilidade de criar um processo perfeito que seja independente do nível e da maturidade dos indivíduos envolvidos.

Isso pode ser bem observado na literatura sobre processos. Processos “pesados” ou rígidos são recomendados quando há equipes imaturas, sem experiência e disciplina adequadas. Já com equipes experientes, maduras e disciplinadas quase não existe necessidade de processo.

Por isso é que os processos ágeis, por exemplo, somente são recomendados quando há pessoas muito competentes envolvidas no projeto. Como disse meu orientador: “coloque uma equipe de juniors num processo ágil, eles vão começar a estimar usando planning poker e provavelmente vão continuar jogando poker até o final do projeto”.

O mesmo é aplicável a empresas que disponibilizam salas de entretenimento, por exemplo. Muita gente gostaria de trabalhar no Google e ter uma sala com vídeo-game, mas o que geralmente não se pensa é que qualquer vaga nesse tipo de empresa são preenchidas por pessoas maduras e focadas, que possuem muito compromisso e dedicação.

Resumindo, a culpa pela falta de qualidade e organização em uma empresa é compartilhada por todos os níveis da mesma. Porém, em teoria, todos sabem o que as empresas deveriam fazer.

Mas o que cada um pode contribuir, individualmente ou em equipe?

Após criador o CMM, Watts Humphrey aplicou todos os seus princípios até o nível 5 em projetos individuais durante 3 anos, financiado pelo SEI (Software Engineering Inistitute). Assim surgiu o Personal Software Processos (PSP). Enquanto o CMM ou CMMI é aplicado ao processo de engenharia de software de uma organização, o PSP organiza o trabalho individual de um engenheiro de software.

Antes de pensar numa certificação CMMI, as empresas deveriam focar em melhorar os indivíduos que a compõe através do PSP. Quando as pessoas amadurecem e passam a utilizar um processo pessoal de desenvolvimento por saberem que é algo bom, então adotar um modelo como CMMI é natural, pois elas já absorveram sua filosofia e não é necessário forçar ninguém a usar boas práticas de desenvolvimento que de outro modo não se entenderia a razão.

Mas o que é o PSP, afinal?

É um processo de desenvolvimento de software pessoal, que você e eu podemos adotar como engenheiros de softwares (desenvolvedores), independente do tipo de projeto e de onde trabalhamos.

O PSP é baseado nos seguintes princípios de qualidade e planejamento:

  • Todo engenheiro de software é diferente; para serem mais efetivos, os engenheiros precisam planejar o seu trabalho e devem basear os seus planos em seus próprios dados pessoais.
  • Para melhorar consistentemente seu desempenho, os engenheiros precisam usar pessoalmente processos bem definidos e com medição.
  • Para produzir produtos de qualidade, os engenheiros precisam se sentir pessoalmente responsáveis pela qualidade dos seus produtos. Produtos superiores não são produzidos por acaso; os engenheiros devem batalhar para fazer um trabalho de qualidade.
  • Custa menos encontrar e corrigir erros cedo em um projeto do que mais tarde.
  • É mais eficiente prevenir defeitos do que encontrá-los e corrigi-los.
  • O jeito certo é sempre o mais rápido e o mais barato de fazer o trabalho.

Enfim, os engenheiros de software devem adotar um processo pessoal bem definidos, medir e registrar o tempo que gastaram em cada atividade e a qualidade do produto que entregaram, ajustar o processo através dos dados obtidos para melhorar os próximos projetos e atividades, além de focar na qualidade do trabalho que desempenham.

A estrutura do PSP

A figura acima mostra o fluxo conceitual do PSP. Através dos requisitos, usa-se “scripts” como guia em cada case do processo (planejamento, modelagem, revisão da modelagem, codificação, revisão da codificação, compilação, testes e finalização). Em cada fase, dados de tempo e defeitos são coletados e consolidados com o que foi planejado, permitindo a avaliação do processo atual.

O PSP também provê boas práticas e guias para os diversos aspectos do processo pessoal: planejamento, coletagem de dados, qualidade (medição e prevenção), modelagem, disciplina pessoal, etc. Não entrarei em detalhes sobre cada um desses itens neste artigo, mas vamos a um exemplo.

A fim de prevenir defeitos num software o PSP estabelece o gerenciamento da qualidade através de três práticas:

  1. Anotar as causas dos erros que já ocorreram e usar esses dados para aperfeiçoar o processo de modo que esse tipo de defeito não ocorra mais, ou seja, que não se cometa os mesmos erros novamente.
  2. Usar método de modelagem e notação adequados para contruir o modelo completo, pois isso força o desenvolvedor a pensar e entender todo o domínio, o que resulta em menos enganos.
  3. Uma consequência direta do item 2: com o modelo completo e entendido, gasta-se menos tempo codificando, o que reduz a quantidade de erros. Estudos realizados em 298 projetos demonstraram que os engenheiros introduzem 1,76 erros por hora no design e 4,20 erros por hora na codificação, logo, quanto menos código melhor.
O maior desafio do PSP, o mesmo de qualquer processo, é que as pessoas que o adotam continuem a usá-lo com o passar do tempo. Uma forma de ajudar nisso é manter um ambiente que facilite ao indivíduo usar o processo. Para isso o SEI criou o Team Software Process (TSP), que, aplicado numa empresa, fornece aos engenheiros o ambiente disciplinado que eles precisam para o uso contínuo do PSP.

Resultados

A seguir, o gráfico de “Acurácia da Estimação de Esforço” demonstra que na medida em que o indivíduo progride no uso do PSP, ele fornece estimativas mais próximas da realidade. Após 10 programas desenvolvidos as estimativas melhoraram em aproximadamente duas vezes.

Já o gráfico de “Melhoria no Nível de Defeitos” demonstra que, na medida em que se usa o PSP, menos erros são introduzidos nas fases anteriores, ou seja, gasta-se menos tempo corrigindo problemas.

Por último, o gráfico de “Resultados de Produtividade” mostra que não houve mudança significativa no desempenho.

A conclusão do estudo, realizado com 298 projetos pequenos, é que o PSP ajuda a melhorar as estimativas e melhorar a qualidade através da redução de defeitos, embora a produtividade em linhas de código permaneça a mesma. Isso faz muito sentido, já que a melhoria na programação está mais relacionada com o conhecimento da linguagem e a lógica do desenvolvedor, os quais podem ser desenvolvidos através de estudo dirigido.

Fonte: http://www.sei.cmu.edu/library/abstracts/reports/00tr022.cfm

Inserção em massa no SQL Server

Como inserir vários registros em uma tabela com valores sequenciais? Por exemplo, como podemos obter uma série de datas?

A resposta mais simples seria utilizar um cursor ou laço (loop), mas a execução de ambos é demasiadamente lenta para muitos registros. O desempenho máximo somente será obtido se a inserção for feita de uma só vez em um comando INSERT. Para isso, podemos usar uma tabela auxiliar com valores sequenciais de forma que possamos usar esses valores para derivar aqueles que necessitamos. Mas como obter tal tabela?

Uma das formas de unir velocidade e praticidade é criar uma tabela com um campo IDENTITY. Entretanto, não gosto da ideia de criar uma tabela física para auxiliar em operações completamente ortogonais às funcionalidades do sistema.

Opção fácil para poucos registros

A tabela MASTER..SPT_VALUES possui números sequenciais de 0 (zero) a 2047 e é nativa do SQL Server. O exemplo abaixo insere 2000 linhas com datas sequenciais de uma só vez:

INSERT INTO DATAS (DATA, DIADASEMANA)
SELECT DATEADD(d, NUMBER, @DATAINICIAL), DATEPART(DW,DATEADD(d, NUMBER, @DATAINICIAL))
FROM MASTER..SPT_VALUES
WHERE TYPE='P' AND NUMBER BETWEEN 0 AND 1999

Portanto, com essa tabela é possível fazer uma inserção em massa utilizando a coluna NUMBER e alguma função que calcule o valor do campo a partir do valor sequencial. No exemplo, a função DATEADD gera datas a partir da @DATAINICIAL, até 2000 dias à frente, e também armazena o dia da semana de cada data.

Porém, há uma questão sobre o uso de uma tabela do usuário MASTER, pois ela pode não ser acessível para você. E se não houver possibilidade de obter a devida permissão?

Utilizando uma tabela auxiliar em memória

Um outro método muito eficiente, mas que exige um pouco de Transact-SQL, é usar uma Variável do tipo TABLE. Confira o seguinte exemplo:

DECLARE @T TABLE (NUMBER INT)
DECLARE @I INT, @LIMITE INT

SET @I = 0
SET @LIMITE = 25000
WHILE @I < @LIMITE
BEGIN
    INSERT INTO @T (NUMBER) VALUES (@I)
    SET @I = @I + 1
END

Este código leva menos de 1 segundo para executar e cria uma tabela na memória com números de 0 a 24.999. Usando ainda o exemplo de geração de datas, podemos inserir 25 mil linhas de uma só vez, como mostra o novo exemplo abaixo:

DECLARE @DATAINICIO DATETIME
SET @DATAINICIO = '2001-01-01'
SELECT DATA, DATEPART(DW, DATA)
FROM (SELECT @DATAINICIO + NUMBER DATA FROM @T) T

Conclusão

Já usei várias vezes esse recurso para melhorar o desempenho de cálculos financeiros que envolvem parcelas, justo e vencimentos em feriados. Certa vez consegui diminuir o tempo de execução de uma procedure de cálculos, que levava 20 minutos para inserir 23 mil registros, para cerca de 20 segundos, gerando 150 mil registros.

Embora para alguns os exemplos acima possam soar como algum tipo de gambiarra, o conhecimento e a correta aplicação de tais recursos podem ser essenciaus quando as restrições de desempenho são prioridade.

Página 6 de 8

Creative Commons O blog State of the Art de Luiz Ricardo é licenciado sob uma Licença Creative Commons. Copie, compartihe e modifique, apenas cite a fonte.