Para quem acha que o título deste post esta contraditório, lamento informar, mas você esta completamente equivocado.
Você conhece algum especialista? De preferência algum que esteja ai pertinho de você.
Se conhece por exemplo um especialista em Java ou .NET, chega pra ele e pergunta se ele conhece algum dos seguintes assuntos:
Acredito que a resposta vai ser sim para todos, ou pelo menos a grande maior parte destes itens. E isto são só coisas genéricas, imagina se começarmos a detalhar a sopa de letrinhas existente no mundo Java EE ou no .NET.
Pois é mais ou menos isto que estou querendo dizer, um especialista precisa saber um monte de coisas para se tornar um especialista em uma delas.
A forma mais fácil que eu conheço para melhorar muito e muito rápido a qualidade do código que você escreve em uma linguagem é aprendendo outra linguagem de programação.
Tem gente que diz que o ideal é aprender uma linguagem nova por ano, e com certeza, o período da minha vida profissional que eu mais melhorei foi quando aprendi várias linguagens em um período curto de tempo.
Quando eu era mais novo (coisa de velho escrever isto
) o meu chefe na época disse que um especialista é alguem que sabe cada vez mais sobre cada vez menos, e que um super especialista é alguem que sabe absolutamente tudo sobre absolutamente nada …
Ach oque este conceito esta um pouco desatualizado, até por que por este conceito, um super especialista é o cara que sabe absolutamente tudo sobre absolutamente nada.
Pelo menos na minha opinião, eu espero que um especialista em Java por exemplo, consiga criar um pacote EAR padrão Java EE para uma aplicação composta por dois módulos web e três módulos EJB além de algumas bibliotecas utilizadas por todos os módulos.
Para fazer isto, o cara vai ter que conhecer no mínimo muito XML, vai ter que saber o que são meta dados, vai ter que saber quais meta dados foram definidos via anotações no código e quais ele vai querer sobre escrever com XML. Vai ter que conhecer a estrutura de um arquivo EAR, a estrutura de um arquivo WAR e qual a diferença entre um arquivo jar de uma biblioteca e de um módulo EJB.
Para entender direito o que ele ta fazendo, ele vai ter que conhecer o protocolo HTTP, por conseqüência o protocolo TCP e o IP. Além de precisar entender de RMI que é utilizado para chamada dos EJBs, RMI também funciona sobre TCP.
Se o servidor for rodar em cluster, é necessário saber como este cluster esta configurado, a maior parte dos servidores Java EE utiliza o protocolo IIOP/IP, o mesmo do corba, já que pela especificação Java EE todo EJB pode ser chamado utilizando CORBA também, e que o IIOP/IP permite roteamento muito mais fácil do que o RMI direto.
E isto tudo só para começar.
Se o especialista em java precisar também configurar o servidor de aplicações também ai aumenta bastante a quantidade de coisas que ele vai ter que saber só para poder ser chamado de especialista em Java e nem chegamos na parte de desenvolvimento ainda …
Claro que isto ainda é só a minha opinião, mas para ser um especialista em java, o cara tem que saber muito bem Orientação a Objetos, Reflexão, Refactoring e mais Refactoring, AOP, a diferença entre excessões checadas e não checadas, para que serve cada tipo de collection, todas as classes no mínimo dos pacotes java.lang e java.util e mais um monte de outras coisas.
Só para finalizar.
Vocês não vão conseguir se tornar especialistas em nada da noite para o dia. Isto vai demorar bastante, e mesmo que você queira ser especialista em .NET por exemplo, você vai ter que estudar muitas outras coisas.
A pior coisa que tem é programador bitolado que acha que a única linguagem/ferramenta/time/religião que presta é a que ele conhece agora …
(isto foi um misto de dicas com desabafo
)
Tags: conceito, lprodjava, produtividade
Como eu ja comentei em outro post o Guice é um framework de injeção de dependências muito fácil de utilizar.
Depois de utilizar o Guice por algum tempo, comecei também a utilizar alguns recursos de AOP do Guice, e como é muito fácil de utilizar, acho que alguns de vocês podem aproveitar isto (se é que alguem ainda lê este blog cheio de poeira
).
Para quem não sabe o que é AOP segue uma rápida introdução:
AOP = Aspect Oriented Programming ou Programação Orientada a Aspectos
Aspectos são uma forma de de isolar partes de um problema e reutilizar as soluções deste problema em diversos pontos do software que tenham o mesmo problema.
Um exemplo disto, o exemplo mais batido depois do logging, é o controle de transações …
Em todo o código de negócio na sua aplicação deve existir inicio e fim de transações, o que na verdade é uma dependência da regra de negócio mas não faz parte de verdade da regra de negócio sendo implementada.
Então este é um bom candidato a ser implementado como um aspecto, da mesma forma que é feito no EJB3 por exemplo, que é remover o código de controle de transações de dentro do código de negócios, e adicionar um marcador no código informando como se deseja que a transação se comporte para aquele trecho.
Para ficar mais claro de uma olhada neste exemplo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package example; import java.math.BigDecimal; public class CodigoDeNegociosImpl { private InterfaceParaOutroServico outroServico; private ControleDeTransacoes transacao; public void metodoDeNegocios(String parametro1, int parametro2, BigDecimal parametro3) { transacao.inicia(); try { algumMetodo(parametro1); outroMetodo(parametro2); agoraUmCalculo(parametro3); transacao.commita(); } catch (Exception e) { transacao.fazRollback(); } } private void algumMetodo(String parametro1) { outroServico.metodoDeNegocio(parametro1); } private void outroMetodo(int parametro2) { // implementa regra de negocio } private void agoraUmCalculo(BigDecimal parametro3) { // faz um calculo complicado } } |
Este é um código bem simples, onde dentro do “metodoDeNegocios” existe código para iniciar e finalizar transações.
O código esta bem simplificado, mas imagine uma situação um pouco mais complicada, onde por exemplo, dentro de “outroServico.metodoDeNegocio” também fosse necessário participar da mesma transação, mas apenas se a transação ja estivesse iniciada, caso contrario seria necessário criar uma nova transação, o código começaria a ficar cada vez mais complicado, e este é um código que não faz parte da regra de negócios sendo implementada por estes métodos. Agora imagine se fosse possível resolver estes problemas simplesmente alterando o código para o seguinte:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | package example; import java.math.BigDecimal; import com.google.inject.Inject; public class CodigoDeNegociosImpl implements CodigoDeNegocios { @Inject private InterfaceParaOutroServico outroServico; /* (non-Javadoc) * @see example.CodigoDeNegocios#metodoDeNegocios(java.lang.String, int, java.math.BigDecimal) */ @PrecisaDeTransacao public void metodoDeNegocios(String parametro1, int parametro2, BigDecimal parametro3) { algumMetodo(parametro1); outroMetodo(parametro2); agoraUmCalculo(parametro3); } private void algumMetodo(String parametro1) { outroServico.metodoDeNegocios(parametro1); } private void outroMetodo(int parametro2) { // implementa regra de negocio } private void agoraUmCalculo(BigDecimal parametro3) { // faz um calculo complicado } } |
Não seria bem mais simples? (Antes que alguem pergunte, eu acabei de criar a anotação @PrecisaDeTransacao)
Podemos também imaginar outro problema. A aplicação tem um requisito que diz que o tempo total de cada chamada ao “metodoDeNegocio” deve ser logado, e também devem ser logadas todas as chamadas a “outroServico.metodoDeNegocio” informando o tempo total de execução do método.
A forma padrão de fazer isto é em cada um dos métodos que precisa do tempo logado, adicionar código no inicio e no final do método para fazer este registro, mas utilizando AOP é possível fazer sem tocar no código das classes.
Na AOP este logging e o controle de transações, são chamados de “preocupações transversais da aplicação”, ou seja, são aspectos da aplicação que permeam o código de diversas classes, mas não pertencem realmente as partes do código “sujas” por estes “aspectos”.
Ninguem vai programar puramente orientado a aspectos, mas AOP é uma excelente forma de contornar limitações de linguagens burocraticas demais, como o Java.
OK, mas o que o Guice tem a ver com isto?
Bom, o Guice possibilita a implementação de recursos simples de AOP utilizando a criação dinâmica de proxies para as classes gerenciadas por ele.
Acha que eu falei grego? Bom, vamos fazer um exemplo simples então.
Todos vocês sabem que anotações não fazem absolutamente nada, certo? Anotações são apenas metadados, ou dados extras que decoram o código com mais informações.
Então, vamos aproveitar os dados extras adicionados no exemplo anterior, e vamos implementar o controle de transações utilizando AOP e o Guice.
Primeiro vamos criar um modulo com a configuração básica da aplicação:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package example.guice; import com.google.inject.AbstractModule; import example.CodigoDeNegocios; import example.CodigoDeNegociosImpl; import example.ControleDeTransacoes; import example.InterfaceParaOutroServico; import example.impl.ExemploDeTransacoes; import example.impl.OutroServicoComRegrasDeNegocio; public class BasicAppModule extends AbstractModule { @Override protected void configure() { bind(ControleDeTransacoes.class).to(ExemploDeTransacoes.class); bind(InterfaceParaOutroServico.class).to(OutroServicoComRegrasDeNegocio.class); bind(CodigoDeNegocios.class).to(CodigoDeNegociosImpl.class); } } |
As classes “ExemploDeTransacoes” e “OutroServicoComRegrasDeNegocio” estão em branco, apenas implementam as interfaces correspondentes sem nenhum código nos métodos.
Até aqui não temos nenhuma novidade, código Guice padrão.
Mas vamos agora criar um outro modulo apenas para a configuração de AOP para deixar tudo bem separado.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | package example.guice; import java.lang.reflect.Method; import org.aopalliance.intercept.MethodInterceptor; import com.google.inject.AbstractModule; import com.google.inject.matcher.Matcher; import com.google.inject.matcher.Matchers; import example.PrecisaDeTransacao; import example.aop.LoggingInterceptor; import example.aop.TransactionInterceptor; public class AOPConfigModule extends AbstractModule { @Override protected void configure() { MethodInterceptor transactionInterceptor = new TransactionInterceptor(); bindInterceptor(Matchers.any(), Matchers.annotatedWith(PrecisaDeTransacao.class), transactionInterceptor); MethodInterceptor loggingInterceptor = new LoggingInterceptor(); Matcher<? super Method> machMethodsByNameMatcher = new MatchMethodsByNameMatcher("metodoDeNegocio"); bindInterceptor(Matchers.any(), machMethodsByNameMatcher, loggingInterceptor); } } |
Agora explicando um pouco o código deste modulo.
Estamos utilizando o metodo “bindInterceptor” que configura o Guice para criar um proxy das classes e métodos que fecharem com os dois matchers passados (o primeiro para classes e o segundo para metodos).
Os matchers são como filtros, eles servem para informar ao Guice onde devem ser aplicados os interceptors.
A classe com.google.inject.matcher.Matchers do Guice facilita bastante a vida provendo diversos matchers prontos, mas nenhum deles leva em consideração o nome do metodo como queriamos fazer para o logging, então eu criei um matcher novo, vejam o código a baixo e verifiquem que é bem simples.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package example.guice; import java.lang.reflect.Method; import com.google.inject.matcher.AbstractMatcher; public class MatchMethodsByNameMatcher extends AbstractMatcher<Method> { private String methodName; @Override public boolean matches(Method method) { return methodName.equals(method.getName()); } public MatchMethodsByNameMatcher(String methodName) { super(); this.methodName = methodName; } } |
O único metodo que precisa ser implementado é o “matches” que faz as comparações no objeto “Method” recebido e retorna true ou false.
Depois disto, a parte mais importante é a implementação do “MethodInterceptor”. Vamos dar uma olhada no código do interceptor de logging.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package example.aop; import org.aopalliance.intercept.MethodInterceptor; import org.aopalliance.intercept.MethodInvocation; public class LoggingInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation invocation) throws Throwable { long start = System.currentTimeMillis(); try { return invocation.proceed(); } finally { long end = System.currentTimeMillis(); System.out.format("%s.%s - %d\n", invocation.getThis().getClass().getName(),invocation.getMethod().getName(),end-start); } } } |
O Guice utiliza as interfaces para aop da aopalliance, as mesmas que as primeiras versões do spring framework, então se você tem algum código AOP que parou de funcionar no spring, migre para o Guice ![]()
Brincadeiras a parte, as unicas interfaces que você precisa realmente conhecer são:
org.aopalliance.intercept.MethodInterceptor – interface que define apenas o método invoke, que sera chamado no lugar de qualquer método interceptado por esta classe.
Exatamente isto, o método invoke sera chamado no lugar do “metodoDeNegocios”.
O invoke recebe como parâmetro uma instância de org.aopalliance.intercept.MethodInvocation:
Que possui informações sobre a chamada atual, como pro exemplo os parâmetros que estão sendo passados para o método, o método que esta sendo chamado, em qual classe, em que instância da classe, …
E possui o método “proceed()” que chama o método real, neste caso o “metodoDeNegocios”.
O resto é só implementar a lógica do interceptor, neste caso capturar o tempo de execução do método, ou seja, o tempo de execução do “proceed()”.
Não vou implementar o interceptor de controle de transações por que não é este o objetivo do post, e alguem iria querer utilizar um exemplo simples em produção em algum momento
Agora só falta criar uma clase para inicializar a aplicação e chamar o método de negocios
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | package example; import java.math.BigDecimal; import com.google.inject.Guice; import com.google.inject.Injector; import example.guice.AOPConfigModule; import example.guice.BasicAppModule; public class AOPTest { public static void main(String[] args) { Injector injector = Guice.createInjector(new BasicAppModule(),new AOPConfigModule()); CodigoDeNegocios obj = injector.getInstance(CodigoDeNegocios.class); obj.metodoDeNegocios("a", 3, new BigDecimal(200l)); } } |
Neste código não tem muita novidade para quem leu o primeiro post sobre o Guice.
O output deste código deve ser algo parecido com:
example.impl.OutroServicoComRegrasDeNegocio$$EnhancerByGuice$$eda06b1.metodoDeNegocios - 16 example.CodigoDeNegociosImpl$$EnhancerByGuice$$54b1222d.metodoDeNegocios - 16
Com isto podemos ver que o Guice altera as classes para poder implementar o AOP.
Para finalizar algumas considerações:
Acho que era isto por enquanto, como este não foi o post mais detalhado que ja escrevi até hoje, espero que tenham muitas perguntas, podem perguntar nos comentários que eu respondo o mais rápido possível.
Para quem ficar com preguiça de copiar e colar os códigos, ou estiver enfrentando algum problema por eu ter esquecido de colocar alguma coisa no post segue a Aplicação de exemplo Guice/AOP que desenvolvi enquanto escrevia o post.