Teste unitário com múltiplas threads no JUnit

Em um projeto que participo, há um conjunto de EJBs stateless reponsáveis por atender chamadas. Foi preciso disponibilizar para todas as camadas um contexto de mensagens cujo escopo é uma chamada ao serviço. Como não seria possível usufruir de um bean com escopo de Request, que exigiria trabalhar com beans stateful, simulei esse contexto através de ThreadLocal. Conforme a teoria, esse recurso “provides thread-local variables (…) each thread has its own, independently initialized copy of the variable.

Por ser um ponto crítico do sistema, desejei criar um teste automatizado para garantir o comportamento ao longo das mudanças. Em linhas gerais, o teste deveria criar várias threads utilizando seus contextos de mensagens e certificar que eles não se sobrepusessem. Durante a prospecção soube que o framework TesteNG fornece a opção de testes com múltiplas threads, mas julguei que seria um teste muito simples para precisar de uma biblioteca adicional.

Dessa forma, meu teste com JUnit da seguinte forma:

import org.junit.Assert;
import org.junit.Test;

public class ContextoTest {

    private static final int QTD_THREADS = 1000;

    @Test
    public void contextoDeveSerExclusivoDaThread() throws InterruptedException {

        Thread[] threads = new Thread[QTD_THREADS];
    
        // Cria e roda as threads
        for (int i = 0; i < QTD_THREADS; i++) {
            threads[i] = new ThreadTeste();
            threads[i].start();
        }

        // Aguarda a execução de todas das threads
        for (Thread t : threads) {
            t.join();
        }
    }

    class ThreadTeste extends Thread {

        @Override
        public void run() {
            Contexto.inicializar();

            // Dorme por um tempo aleatório para forçar paralelismo
            esperarUmTempoAleatorio();

            // Adiciona o nome da thread corrente no contexto
            Contexto.adicionarMensagem(Thread.currentThread().getName());

            // Contexto deve ter apenas 1 mensagem, contendo nome da thread
            Assert.assertEquals(1, Contexto.getMensagens().size());
            Assert.assertEquals(Thread.currentThread().getName(), Contexto.getMensagens().get(0));
        }

        private void esperarUmTempoAleatorio() {
            try {
        	Thread.sleep((long) (1000 * Math.random()));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

Um ponto interessante é introduzir algum grau de desordem no paralelismo, oque foi feito fazendo a thread dormir por um tempo aleatório antes de realizar o teste. Além disso, é primordial fazer join() das threads criadas ao fim do teste unitário para certificar que o JUnit não prosseguirá para outros testes enquanto ainda existem threads rodando do teste atual.

Configurando um projeto mínimo com Drools 6 no Maven

Em um projeto que participo surgiu a necessidade de utilizar um motor de regras de negócio para fornecer ao cliente a possibilidade de gerenciar as regras de um processo por conta própria. Como o sistema é em Java, o Drools, mais especificamente o sub-produto Drools Expert, se mostrou uma opção interessante, principalmente pela possibilidade de criar uma Linguagem Específica de Domínio (DSL).

Ao estudar a ferramenta na Web, percebi uma vasta gama de tutoriais, cada um com sua forma de criação e configuração do projeto, muitas vezes ainda apegado a versões inferiores a 6 da ferramenta.

Apresento aqui uma forma bem enxuta, usando o Eclipse como IDE e o Maven como gerenciador de dependências e builds:

1. No Eclipse, criar um projeto Maven, pulando a seleção de arquétipo.

2. No pom.xml do projeto, colocar como dependências o drools-compiler, bem como uma biblioteca de log compatível com SLF4J (sugiro a Logback), conforme o trecho abaixo:

	<dependencies>
		<dependency>
			<groupId>org.drools</groupId>
			<artifactId>drools-compiler</artifactId>
			<version>6.3.0.Final</version>
		</dependency>
		<dependency>
			<groupId>ch.qos.logback</groupId>
			<artifactId>logback-classic</artifactId>
			<version>1.1.5</version>
		</dependency>
	</dependencies>

3. Sugiro ainda que no pom.xml você determine como configuração de build a versão do Java desejada, aqui no caso a 1.7. Para isso faça conforme o trecho abaixo:

	<build>
		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>3.5</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
				</configuration>
			</plugin>
		</plugins>
	</build>

2. Acionar botão direito no projeto, Maven > Update Project para que o Eclipse perceba as novas configurações

3. Criar o arquivo src/main/resources/META-INF/kmodule.xml com o conteúdo:

<?xml version="1.0" encoding="UTF-8"?>
<kmodule xmlns="http://jboss.org/kie/6.0.0/kmodule" />

4. Criar o arquivo src/main/resources/regras.drl com o conteúdo:

rule "olá"
	when
		$texto : String()
	then
		System.out.println("Olá "+$texto);		
end

5. Criar uma classe executável para testar. Ex:

import org.kie.api.KieServices;
import org.kie.api.runtime.KieContainer;
import org.kie.api.runtime.KieSession;

public class Main {
	
	public static void main(String[] args) {
		
		KieServices ks = KieServices.Factory.get();
		KieContainer kcontainer = ks.getKieClasspathContainer();				
		KieSession ksession = kcontainer.newKieSession();
		
		String texto="Rafael";		
		ksession.insert(texto);
		
		ksession.fireAllRules();				
	}
}

6. Se desejar utilizar o plugin do Drools no Eclipse, que facilita algumas tarefas mas não é essencial, instale os artefatos desejados do update site:
http://download.jboss.org/drools/release/6.3.0.Final/org.drools.updatesite/

No meu github coloquei um exemplo completo de Drools usando tanto DRL (linguagem de regra do Drools) e DSL (linguagem específica de domínio) para aplicar regras de negócio num exemplo de carrinho de compras com descontos no preço e no frete: https://github.com/rafaelodon/poc-drools

O Ciclo de Sabotagem das Tecnologias de Desenvolvimento de Software

Esses dias eu estava super cliché, meio crítico com o fato de surgir tanta tecnologia nova o tempo todo. Praticamente a cada 4 anos a gente precisa se renovar para não ter o aspecto técnico do currículo anulado nos 4 anos seguintes. Tudo bem que muitas dessas novidades advém de um movimento natural promovido pelas grandes inovações (desenvolvimento mobile por exemplo). Mas é comum assistir tecnologias morrendo e dando lugar a outras que produzem o mesmo resultado, sem justificativas convincentes.

Por um instante cheguei a formular a hipótese que na verdade isso era um fenômeno de procrastinação coletiva promovido pelo [in]consciente coletivo dos profissionais de TI, que acham super recompensador gastar seu tempo tendo que reaprender como fazer o mesmo de forma diferente. Talvez tenha um pouco disso também. Mas pensando melhor, percebo também um padrão de sabotagem  que é descrito no ciclo abaixo:

#1 –  The dawn of man: Surge uma Nova Tecnologia ®, ainda incipiente , mas que promete suprir uma deficiência do ferramental vigente.

#2 – O buzz: A Nova Tecnologia ® atrai a atenção de acadêmicos e entusiastas que se aproveitam do pioneirismo para surfar na crista da onda, publicando em revistas, palestrando em eventos, etc. Mas tudo se resume ao buzz. O mercado corporativo ainda olha com desconfiança.

#3 – Mordendo a maçã: Versões novas são lançadas, boas práticas são disseminadas, cursos, artigos, tutoriais, tópicos em fóruns, perguntas e respostas saturam a web. Convencidos pelos gurus, vai surgindo na manada de profissionais espectadores o desejo de adotar a Nova Tecnologia ®, tanto pelo prazer de aprender algo novo quanto pela necessidade de manter seus currículos atualizados.

#4 – As invasões bárbaras: Com o mercado de trabalho recheado de defensores da Nova Tecnologia ®, corporações de impacto passam a adotá-la em projetos relevantes que apresentam desafios reais, em escala real. E esses projetos introduzem um outro fator crucial: a pressão por prazo. Prazo leva à pressa que leva ao aumento de recursos. Nesse clima, uma manada de profissionais sub-qualificados e por vezes sub-remunerados, forçam pro-ativamente o uso indiscriminado da Nova Tecnologia ®. Tudo é resolvido da forma mais imediata o possível, com muita gambiarra, sem avaliar alternativas, sem conhecer recursos avançados, buscando resultados rápidos que salvem o projeto (e também seus empregos). Julgando-se produtivos e confortáveis com a Nova Tecnologia ®, está formado um batalhão de martelos que acha que tudo é prego.

#5 – Sodoma e Gomorra: Com o colapso de grandes projetos que adotaram a Nova Tecnologia ®, começam a sair cases de insucesso, artigos que condenam seu uso e o famoso anúncio: “a Nova Tecnologia ® morreu“. Por mais que os gurus afirmem que são os profissionais que usaram de forma errada, e que as novas versões incluam recursos que suprem as deficiências e introduzem melhorias, a tecnologia continua estigmatizada por suas restrições conceituais e efeitos colaterais do uso costumeiro.

#6 – Let’s twist again: Volte ao Passo #1.

Arquiteto ou apenas bom desenvolvedor?

Sempre fui crítico com o rótulo arquiteto de software. Se a gente parar pra pensar, é um nome um tanto quanto mal escolhido. Na engenharia civil, o arquiteto é o desenhista do prédio, o artista do concreto. Oscar Niemeyer rabiscava formas modernistas no papel e pouco se importava em como aquilo viraria realidade, o que de fato seria um problema para os engenheiros.

Bozzetto-della-sede_imagelarge
Esboço de Niemeyer.

Já na área de software, quem costuma imaginar coisas difíceis de por em prática é o cliente, o demandante. Para executar suas idéias mirabolantes há de se contar com super-heróis capazes de eleger plataformas, tecnologias, protocolos, padrões, componentes, topologias e de projetar como isso tudo vai conversar. O curioso é que o nome que se dá para esse super-herói é justamente arquiteto de software.

Eu particularmente acredito que essas atribuições sejam apenas a descrição de um bom desenvolvedor, ou para ser mais justo ao argumento, um bom engenheiro de software. O curioso é que quase não se vê o termo engenheiro de software circulando em vagas de emprego no mercado brasileiro. Acredito que isso se dê por alguns fatores.

O primeiro deles advém da própria distinção que os desenvolvedores gostam de ter em relação às demais engenharias. Há todo um brio envolvido no domínio da arte de desenvolvedor sistemas, principalmente quando você fica anos estudando muito além da programação. Talvez não queiramos ser confundidos com engenheiros civis ou mecânicos. Enquanto isso, na mão contrária do nosso ego, o mercado de trabalho acha ótimo que nos consideremos apenas desenvolvedores, uma vez que engenheiros tem conselho, piso salarial e algum respeito perante a sociedade. Engenheiros constroem prédios. Nós “mexemos” com informática.

Mas então, se formamos uma manada de desenvolvedores egocêntricos, quem são os famosos arquitetos de software? Pessoalmente ainda acho que um arquiteto é nada mais nada menos que um bom engenheiro de software, com experiência, senso crítico e visão micro e macro sobre a pilha de tecnologias envolvidas num sistema. O que percebo é que os que se dizem arquitetos buscam nesse rótulo uma distinção, não querem ser confundidos com meros programadores, uma atividade mais básica. Da mesma forma, os desenvolvedores também não querem se responsabilizar por decisões que irão assombrar o projeto pelo resto dos dias, podendo trazer impactos diretos na performance e disponibilidade do sistema. E é nesse contexto que a arquitetura de software vai se tornando ocultista e mística, fazendo com que os programadores se distanciem do que deveria ser o grande objetivo: se tornar um excelente profissional.

Abandonando os rótulos, o fato é que todo sistema desenvolvido terá uma arquitetura, quer você queira ou não. Cabe a você deixar de ser um simples fabricador de telas e querer absorver e contribuir com as decisões técnicas dos projetos em que você colabora. Busque formar o tal senso crítico, viver experiências, conhecer e experimentar as tecnologias de forma contínua. Não perca de vista o norte da excelência, independente do nome que eles inventam para ela.

O Ócio Nocivo nas Redes Sociais

Aqui vou eu fazer um post criticando os posts da Internet. Mas creio ser uma contradição razoável.

Talvez você, assim como eu, esteja sentindo mais desprazer do que prazer ao usar as redes sociais. Mas antes de abonimá-las, lembremo-nos de que o mal quase sempre está no homem, nunca nas coisas. O pai da aviação, Santos Dumont, suicidou-se aos 59 anos, angustiado por ver seu invento usado em guerra. E nós? Que uso estamos dando para esse ambiente moderno de fácil comunicação que é a Internet? Sob essa luz lanço um desafio: vamos trocar esse novo vício de ficar contemplando por horas a timeline e os perfís das pessoas no Facebook por outra atividade, de preferência fora da Internet? O prêmio é ser feliz.

Vá ler livro ou uma revista, pode até ser de fofoca, ou mesmo um quadrinho antigo da Turma da Mônica. Aprenda um instrumento musical, ou pratique uma nova música. Aprofunde-se em outro idioma. Veja um filme ou uma série. Tire um cochilo no sofá. Arrume uma gaveta. Separe roupas que você não usa para um bazar beneficente. Imprima as fotos daquela viagem, faça um álbum e convide alguém pra ver. Visite um parente. Cuide de uma planta. Adote um animal. Faça uma caminhada até à padaria e espere a próxima fornada quentinha do pão. Cozinhe uma receita nova. Lave a louça, se estiver afim. Debruce na varanda ou sente-se no banco da praça e veja o vai-e-vem das pessoas. Monte um quebra-cabeça. Faça um artesanato. Faça uma planilha com as finanças. Organize na prateleira os livros que você nunca vai ler por ordem alfabética de autor. Depois reorganize-os por ordem de tamanho, ou cor. Olhe pro teto ou pro chão por horas, imaginando o que fazer caso ganhasse na mega-sena, mesmo que você nunca jogue. Enfim. Só não se perca novamente lá nas redes sociais, colhendo infelicidades gratuitas o tempo todo.

Tá certo que toda tecnologia sofre críticas quando surge, e já sobrevivemos a muitas delas: televisão, telefone, computador pessoal, video-game, celular e a própria Web. Mas algo me sugere que o ócio já foi muito menos nocivo para a nossa psique antes de toda essa hipnose nas redes sociais. Talvez não estejamos preparados para tamanha facilidade de interação social que essas plataformas nos proporcionam. Pensar, discutir e argumentar é saudável. Mas decididamente não precisamos conhecer a opinião de todos sobre tudo o tempo todo, assim como não precisamos formar e emitir opinião sobre tudo o tempo todo. Essa pressão está nos implodindo!

Evitar log de LoginException quando usuário errra senha

Passamos a conviver com um número excessivo de exceções de login do JAAS no Jboss EAP 6.0.1 quando algum usuário errava a senha. Essas exceções não indicam erros do sistema propriamente ditos, e estavam enchendo o log e tornando difícil a análise de outros problemas de produção.

Login failure: javax.security.auth.login.LoginException: Login Failure: all modules ignored
	at javax.security.auth.login.LoginContext.invoke(LoginContext.java:921) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.access$000(LoginContext.java:186) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext$4.run(LoginContext.java:683) [rt.jar:1.6.0_45]
	at java.security.AccessController.doPrivileged(Native Method) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.invokePriv(LoginContext.java:680) [rt.jar:1.6.0_45]
	at javax.security.auth.login.LoginContext.login(LoginContext.java:579) [rt.jar:1.6.0_45]
	...

A opção foi abaixar o nível de log do pacote org.jboss.security para FATAL para todo o Jboss. Isso pode ser feito no standalone.xml seguinte na seção de logging:

<subsystem xmlns="urn:jboss:domain:logging:1.1">
    ...
    <logger category="org.jboss.security">
        <level name="FATAL"/>
    </logger>
    ...
</subsystem>