MVC: Supostas perguntas frequentes

segunda-feira, 29 de junho de 2009 às 22h12 BRT

P. Por que um tópico sobre “supostas perguntas frequentes”?
R. Dois motivos: 1. É incrível a quantidade de gente perguntando as mesmas coisas em fóruns por aí. 2. É incrível gente com anos trabalhando que simplesmente erra feio nesse negócio de MVC. E eu tava pensando em fazer um post épico, como havia feito anteriormente, mas como ainda tá “assando”, resolvi fazer um outro post épico sobre isso daqui.

P. O que é MVC?
R. Háááá! Ainda bem que perguntou, acredita que tem gente que faz cara de conteúdo ao ouvir essas três letras? Enfim, deixa pra lá. MVC é um pattern usado, geralmente, para apresentações visuais de uma aplicação. Por ser pattern, implica que MVC também é uma descrição de uma solução para um problema recorrente; e que também não é uma receita de bolo para ser seguido de olhos vendados. O nome segue a sigla das três “coisas” que a aplicação vai ser dividida:

Model: é como o seu programa seria se o usuário fosse um “über-geek” e pudesse manipular o sistema fazendo simples classes com main() invocando as funções desejadas. Ou seja, é o domínio do seu sistema.
View: é o que o Homer Simpson do seu usuário vê: uma representação visual do domínio realizado pelo model.
Controller: é o que fica entre o model e a view. Entre várias coisas, ele faz o que o model não deve fazer: manipular a view.

Implicação: o Controller conhece a View e o Model, a View conhece o Model, e o Model não conhece ninguém.

P. Model, View e Controller são camadas, certo?
R. Não, na realidade, nunca vi ninguém por nome nesses “troços”. Sério! Às vezes, ouvi dizer que eram componentes, outros que eram camadas. Não acho nenhum dos dois nomes apropriados. Componentes remetem ao modismo do início da década de 00 de se usar “componentes reusáveis” por “operários” em “fábricas de softwares” (eca!). Ou então a um outro modismo de componentes distribuídos como COM+ ou EJB (daqueles antigão). Nenhuma das duas coisas deram certo, e o MVC não tem nada a ver com isso. E camadas refere-se a um estilo de design para dividir um domínio grande, que pode ser feito num software com ou sem interface visual.

A real é que, na dúvida, o pessoal dá um jeito não dizer em que Model, View e Controller são classificados.

P. Mas perái! M, V e C são camadas sim! Model é a de persistência, View, a de apresentação e Controller, de negócio!
R. Nããããão, tá loco! Ponha uma coisa na sua cabeça: os objetivos tanto da divisão em camadas, quanto do MVC são distintas: a primeira tem o objetivo de controlar dependências, a segunda, de representar um domínio visualmente. Não são a mesma coisa, e nem dá para unificá-las em um modelo único. Algumas classes suas serão uma coisa do ponto de vista do MVC e serão outra coisa do ponto de vista das camadas.

P. O Controller serve para controlar o sistema?
R. Não, o nome controller é que é confuso, e remete a alguns programadores o “objeto deus” (God Object) ou o “objeto bolha-assassina” (Blob Object). Porém, objetos deuses são anti-patterns, ou seja, soluções aparentemente ideiais para problemas recorrentes que causam mais problemas ainda. Quando vier à sua cabeça “Controller”, pense-o como “Input Controller” (controlador de entrada), e este “coiso” deve fazer, estritamente, as seguintes atividades:
- ouve eventos;
- obtém os parâmetros de entrada desejados da View;
- obtém do Model um domínio (invariavelmente, este está num meio persistente);
- chama um método do domínio;
- escolhe a view a ser renderizada, fazendo “bind” de algum domínio do Model.

Não raro, programadores pouco experientes colocam, no “Controller”, lógicas de negócio ou tranformações de objeto para a view. Não é isso, remova esses códigos e ponham nos seus devidos lugares.

P. Ouvi falar de um tal de Model 2, ele é diferente do MVC?
R. Model 2 é uma adaptação do MVC, usando tecnologias padrão do J2EE como era conhecido no início da década de 00 (ou seja: Struts ou Servlet e JSP). O nome é puramente mercadológico, servia para diferenciar do “Model 1″, que era a utilização exclusiva de JSP para construção da aplicação web (assim como era o ASPão e o PHP). Por ser intimamente relacionado com tecnologias ultrapassadas, toda a burocracia da época está no Model 2, como Form Beans e XMLs, manipulação direta de mapas de escopos; sem falar de domínios fracos, normalmente misturados no meio da view ou das queries do banco. Minha recomendação: esqueça Model 2, porque você pode aprender MVC por outros meios.

P. O MVC da Web é diferente do MVC do Desktop?
R. Sim, existem duas diferenças: 1) um Controller de Desktop recebe eventos de clique do mouse, de teclado, de botões e outros componentes; um Controller de Web recebe exclusivamente eventos de submissão. Consequência: aplicações Desktop são orientadas a eventos, enquanto aplicações Web, orientadas a fluxos. Tudo que uma aplicação web entende é uma “stringona” com os dados de um suposto formulário (não dá pra saber se o cliente é humano ou que viu a interface gráfica) e que precisa devolver uma nova “stringona” para o cliente que, supostamente, renderiza para algum desenho gráfico. A aplicação Desktop sabe exatamente os eventos recebidos e pode agir diferentemente para cada um deles. 2) A View de Desktop mantém sincronia constante do Model (através do pattern Observer), qualquer alteração que o usuário fizer no model através de um painel, será refletida imediatamente em outros painéis que, porventura, estejam visualizando o mesmo Model. Na Web, não existe nada disso, a partir do momento em que o usuário está diante de uma tela, essa representação do Model estará desconectada do Model real e o usuário não saberá quanto (e se) o Model mudou. O único momento de mudança é quando o usuário aperta F5, mas isso implica num evento consciente do usuário, não numa coisa automática, como as aplicações Desktop de qualidade fazem.

P. Estava pensando em fazer um MVC distribuído, penso que o Model ficaria no Server e a View, no Client; só não sei onde ficaria o Controller, tem alguma sugestão?
R. Antes de mais nada, não existe MVC distribuído. O erro da sua pergunta baseia-se numa premissa equivocada, a de que é possível esconder a distribuição na aplicação. Não pode, e pra piorar, muitas “vendors” no passado (e ainda no presente) vendem soluções onde você poderia chamar um objeto remoto como se fosse local. Mas na real, chamadas locais e remotas somente são iguais quando ocorre sucesso, não quando ocorrem falhas, como queda na rede, versões incompatíveis ou falhas de autenticação/autorização.

Se você realmente precisar de uma aplicação distribuída (ex.: uma aplicação Desktop em C# conversando remotamente com um servidor Tomcat) você terá um MVC para o Client (o Model são Active Records que se comunicam com o Server, a View é o módulo onde se instancia componentes e o Controller, os métodos que entende os eventos) e um outro MVC para o Server (o Model são entidades, com seus services e mapeamento objeto-relacional, a View é XML, JSON, um formato binário ou outro qualquer e o Controller é o que entende requisições remotas).

P. Tenho uma aplicação Web, gostaria de reaproveitar o Controller se precisasse mudar minha aplicação para Desktop, como fazer isso?
R. Não faz. O controller é intimamente ligado à view, ou seja, nova view, novo controller. A origem do seu problema pode ser Controllers agindo como God Objects (ver aqui), e a solução seria um refactoring, não um Controller multi-uso.

P. O que o framework MVC faz? Age como Controller?
R. Quase. Lembra da lista citada acima sobre o que um Controller faz? Veremos o que um framework faz sozinho e outros que depende da ajuda manual do programador:
- ouve eventos (framework);
- obtém os parâmetros de entrada desejados da View (framework, obtidos via DI);
- obtém do Model um domínio (manualmente);
- chama um método do domínio (manualmente);
- escolhe a view a ser renderizada, fazendo “bind” de algum domínio do Model (parcialmente pelo framework, a escolha da view pode ser sobreescrita manualmente).

Há tentativas de algumas comunidades para criarem um framework onde o Controller deixa de existir, mas acredito que não funciona em todos os casos e dependem de models fixados a um padrão imposto ao framework.

Frameworks vão além, é claro, pois proveem funcionalidades adicionais como helpers para views e outras coisas.


São essas as perguntas que eu consegui imaginar. E você? Tem alguma dúvida sobre MVC além dessas daqui?

Já usou Memcached?

sábado, 2 de maio de 2009 às 17h02 BRT

Cache não é algo que os programadores desconhem. Quem esteve numa universidade, e teve uma aula séria de Arquitetura de Computadores, sabe que a memória é disposta numa hierarquia de caches. E quem já programou em Java, já ouviu falar de inicialização tardia, muito usado em singletons (apesar de não ser só para isso): Leia o restante desta entrada »

Aprenda Java EE 6, agora! (3)

domingo, 22 de março de 2009 às 19h22 BRT

Seguindo o post anterior, continuaremos a aplicação de AgendaMedica. Lembra do que faltava? Precisávamos de um conceito de Consulta, que não havia no nosso modelo. E precisávamos que a consulta tivesse uma característica melhor do mundo real, como, por exemplo, não permitir duas consultas no mesmo horário e não permitir consultas fora do horário do médico.
Leia o restante desta entrada »

Aprenda Java EE 6, agora! (2)

terça-feira, 24 de fevereiro de 2009 às 17h49 BRT

Dessa vez, estarei utilizando a versão b37 do Glassfish v3. Por causa disso, você vai ter que fazer alterações à mão no plugin do Eclipse para o servidor Glassfish. Na versão b36 havia as pastas web e ejb dentro de module. Agora, todos os jars estão dentro de module, sem distinção de pastas.

Primeiro, feche o Eclipse. Iremos copiar o plugin do Glassfish e descompactá-lo, para alterar o seu arquivo de configurações. No Linux eu fiz assim, supondo que ECLIPSE_HOME seja uma variável onde aponta para a pasta do Eclipse: Leia o restante desta entrada »

Aprenda Java EE 6, agora!

domingo, 15 de fevereiro de 2009 às 18h44 BRT

Quando fiquei craque no Java, a versão do “Enterprise Edition” era ainda 1.4. Eu aprendi a versão 5, logo depois do lançamento do Glassfish. Mas agora estou fazendo algo diferente, não vou esperar a versão Java EE 6 sair, vou aprender as coisas tão logo as novidades apareçam.

E você também pode fazer isso. Pegue uma versão promoted do Glassfish no site deles, que, assim como o Lost, tem sempre uma versão nova nas quartas à noite, que você baixa na quinta. A última versão, que estou usando nesta semana, é a b36.

Baixe a última versão disponível e descompacte num lugar que você achar apropriado. No Eclipse, na hora de instalar o servidor, basta escolher a opção “Glassfish v3 Prelude” (se você não usava Glassfish, na tela de novo servidor há uma opção de baixar os adaptadores para outros servidores). Pronto!

Eu vou fazer uma aplicação de exemplo, que é uma agenda de consultório médico. É babaca, mas tem uma regras óbvias que não dá pra ser tratado com o velho CRUD.

Vamos lá. Crie um “Dynamic Web Project” cujo Runtime seja o “Glassfish v3 Prelude”, vou chamá-lo de AgendaMedica. Não sei como vocês lidam com testes no Eclipse, mas costumo criar um novo projeto Java que referencia o projeto que estou interessado em testar. No caso, criarei também o projeto Java AgendaMedicaTeste. Após criado, dê <Alt> + <Enter> sobre o projeto, clique em “Java Build Path”, vá na aba “Projects” e adicione o projeto AgendaMedica.

No projeto AgendaMedicaTeste, eu já criei um método de testes pra realizar a consulta:

package br.com.objectzilla.agendamedica;
 
import java.util.Calendar;
 
import org.junit.Assert;
import org.junit.Test;
 
public class AgendamentoTeste {
 
	@Test
	public void pacienteMarcaHoraComMedico() {
		// um paciente...
		Paciente paciente = new Paciente();
		paciente.setNome("Maria");
 
		// um médico...
		Medico medico = new Medico();
		medico.setNome("Dr. Gregory House");
 
		// ambos agendam um horário
		Agendamento agendamento = new AgendamentoImpl();
		Calendar horario = Calendar.getInstance();
		horario.set(2009, Calendar.MARCH, 5, 17, 00, 00);
 
		agendamento.marcaConsulta(medico, paciente, horario);
 
		// agora, médico tem consulta com paciente marcada às 5
		Paciente pacienteMarcado = medico.consulta(horario);
		Assert.assertEquals(paciente.getNome(), pacienteMarcado.getNome());
	}
}

Beleza, mas o código não compila, né? Ora, não seja por isso. Vá criando as classes clicando nos erros com o botão direito do mouse, só não se esqueça de colocar as classes no projeto AgendaMedica. No caso, Agendamento é uma interface e o restante são classes.

Bom, tente rodar o script de teste (clique com botão direito sobre a classe e dê Run As… > JUnit Test). Vai dar erro, óbvio! Por isso, convido a você a escrever código nas classes até o script rodar com sucesso. Não se preocupe, se você não conseguir ou não tiver paciência, no final do post eu mostro o link onde você pode baixar o código.

Agora, vamos transformar a interface Agendamento em um Stateless Session Bean. Não precisa nem mover pra um projeto próprio, pois agora os EJBs podem ser “deployados” em aplicações WAR. Basta adicionar @Local na interface (a v3 ainda não possui suporte a @Remote), assim:

@Local
public interface Agendamento {
	// ...
}

E adicionar @Stateless na classe que implementa:

@Stateless
public class AgendamentoImpl implements Agendamento {
	// ...
}

Pronto, faça o deploy do projeto web no servidor Glassfish v3 e veja o seguinte log aparecer:

INFO: Bound Java:Global name [business view] : java:global/AgendaMedica/AgendamentoImpl#br.com.objectzilla.agendamedica.Agendamento
INFO: Bound Java:Global name [single business view] : java:global/AgendaMedica/AgendamentoImpl

Repare em como é realizado o binding com o JNDI. A partir da versão 6, não será mais uma implementação específica de contêiner. Todos os servidores de aplicações, se quiserem ser homologados para Java EE 6, deverão dispor seus EJBs, em contextos JNDI, de acordo com o seguinte padrão:

java:global[/<application-name>]/<module-name>/<bean-name>#<interface-name>

Onde:

<application-name> é opcional, refere-se ao nome do pacote EAR (não tem no nosso caso).

<module-name> é o módulo onde está o EJB (AgendaMedica).

<bean-name> é o nome do bean (AgendamentoImpl).

<bean-name> é o nome do bean (AgendamentoImpl).

<interface-name> é o nome completo da interface que implementa o bean (br.com.objectzilla.agendamedica.Agendamento).

O leitor atento deve ter reparado: está sendo feito dois bindings para o EJB! Isso também faz parte do padrão. Se o bean implementar apenas uma interface, um alias será criado onde o nome da interface não aparece.

Já que criamos o Session Bean, seria interessante se usássemos, não é não? Vamos fazer um Servlet, mas não precisa tomar o susto de configurar o wer.xml, pois basta criar um classe que herde de HttpServlet e adicionar uma anotação de acordo com o seguinte código:

@WebServlet(value="/agendamento")
public class AgendamentoServlet extends HttpServlet {
 
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
			IOException {
 
	}
}

Após o deploy, basta digitar http://localhost:8080/AgendaMedica/agendamento e você vai ver… uma tela em branco. Normal, a gente não fez nada mesmo. Agora, vamos preencher o doGet() com uma chamada ao método de marcarConsulta() de agendamento. Eu também injetei uma instância de EJB.

@WebServlet(value="/agendamento")
public class AgendamentoServlet extends HttpServlet {
 
	@EJB
	private Agendamento agendamento;
 
	@Override
	public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException,
			IOException {
 
		String nomeMedico = req.getParameter("medico");
		String nomePaciente = req.getParameter("paciente");
		int hora = Integer.parseInt(req.getParameter("hora"));
 
		// criando médico
		Medico medico = new Medico();
		medico.setNome(nomeMedico);
 
		// criando paciente
		Paciente paciente = new Paciente();
		paciente.setNome(nomePaciente);
 
		// criando horário
		Calendar horario = Calendar.getInstance();
		horario.set(Calendar.HOUR, hora);
		horario.set(Calendar.MINUTE, 0);
		horario.set(Calendar.SECOND, 0);
 
		// chamando método de agendamento
		agendamento.marcaConsulta(medico, paciente, horario);
 
		PrintWriter pw = resp.getWriter();
		pw.format("Eu juro que marquei consulta para o paciente %s, com o médico %s, na hora %d.",
				medico.getNome(), paciente.getNome(), horario.get(Calendar.HOUR));
 
 
	}
}

Se você rodar http://localhost:8080/AgendaMedica/agendamento?medico=Jose&paciente=Adolfo&hora=14, vai ver que a aplicação mostra uma mensagem na tela que não diz se foi, ou não foi, feito algo. Precisaria de uma tela de consulta, mas só dá pra fazer isso se nossa aplicação persistisse os objetos entre as requisições, o que atualmente não ocorre.

Vou fazer isso no próximo post, onde apresentarei mais novos recursos e novas funcionalidades na aplicação pra que ela finalmente funcione de verdade.

Quem quiser, pode ir alterando a aplicação por conta própria, deixei no repositório GitHub em http://github.com/leonardoverissimo/javaee-6-application/tree/master.

Filho de feio inteligente com gostosa burra

terça-feira, 10 de fevereiro de 2009 às 23h06 BRST

Seguinte, na segunda-feira (09/fev), eu vi um PDF sobre uma experimentação de tipagem estática em Python. Não que eu esteja duvidando da capacidade dos caras que fizeram a apresentação, até porque, mexer com linguagens não é para qualquer um, mas sei lá, o fato de muita gente ter dado um “up” no Reddit implica que muita gente sonha com uma linguagem cuja tipagem é tanto estática quanto dinâmica.

Isso me preocupa, sabia? A impressão que dá é que as pessoas sonham com uma espécie de uma linguagem meio-termo, que acabasse com as guerras nerdísticas e que fosse a única que reinaria soberana sobre todos as outras. E uma que fosse estática e dinâmica, ao mesmo tempo, seria a candidata ideal. Infelizmente, tenho que te contar a triste realidade: tipagem estática e dinâmica são antagônicas, tipo água e vinho.

Você já programou em C++? Então, quem conhece o troço sabe que existem vários paradigmas conflitantes entre si. Um paradigma é a programação procedural com conteineres STL, outro é a programação orientada a objetos e outro é programação por templates. Todos bem diferentes, e cuja mistureba só pode ser feita com bastante cuidado por gente que não tem amor à própria vida. Sim, é realmente complicado programar em templates e depois tentar usar OO, é complicado usar o paradigma C quando boa parte do código já está com a sintaxe do C++. E eu desconfio que a mesma coisa pode ocorrer com essas linguagens que misturam tipagem estática e tipagem dinâmica. Vamos fazem uma experimentação com Groovy? Primeiro: o que acontece quando compilamos (com groovyc) o seguinte trecho?

// recebe um objeto de tipo indefinido
def imprima(valor) {
    println valor
}
 
// objeto de tipo "String" numa referência de tipo "String"
String msg = "Olá"
 
// objeto de tipo "String" passado para parâmetro sem tipo
imprima msg

Sucesso, é perfeitamente possível passar um objeto qualquer numa referência sem tipo.

Mas, e se invertermos, assim?

// recebe um objeto de tipo "String"
def imprima(String valor) {
    println valor
}
 
// objeto de tipo "String" numa referência sem tipo
msg = "Olá"
 
// objeto de tipo "String" passado para parâmetro de tipo "String"
imprima msg

Sucesso também, o compilador não reclama quando uma referência String recebe um objeto de uma referência sem tipo. E se chutarmos o balde, definindo a função imprime() recebendo um int?

// recebe um objeto de tipo "int"
def imprima(int valor) {
    println valor
}
 
// objeto de tipo "String" numa referência de tipo "String"
String msg = "Olá"
 
// objeto de tipo "int" passado para parâmetro de tipo "String"
imprima msg

Acha que dá erro de compilação? Dá nada! Compila com sucesso também! Não existem casos específicos para isso. Em Groovy, os tipos não são decididos em tempos de compilação. Erros de tipos só são descobertos quando você executa o código com tipagem divergente.

Não tenho nada contra linguagens de tipagens estáticas, nem de dinâmicas. Só acho que cada um deve estar no seu quadrado. Muito se fala que, com linguagens “mistas”, como Groovy, se obtém os benefícios da tipagem estática com os benefícios da tipagem dinâmica. Será mesmo? Vamos pensar: Em minha opinião, a vantagem da tipagem estática é a possibilidade de reduzir erros causados por atribuições errôneas, impossibilitanto até mesmo e existência do código executável; a desvantagem é que os tipos estáticos causam um engessamento da aplicação (a famosa dúvida: “como trocar a classe, uma vez que as referências são da classe antiga?”), e cuja solução (criação de classes abstratas e de interfaces) precisa ser feita no começo do desenvolvimento.

A vantagem da tipagem dinâmica (de novo, em minha opinião) é possibilitar um código mais flexível pois, como as referências não se comprometem com tipos, uma nova classe com os mesmos contratos de uma antiga sempre será substituível por esta. A desvantagem é que, principalmente com APIs públicas ou com equipes dispersas, torna-se mais difícil definir um contrato dos métodos e classes.

Veja, Groovy não tem aquela vantagem de uma linguagem estática. Se você retornar, em uma função, um valor de tipo diferente, é possível quebrar o código em algum outro lugar e você nem perceber. Significa que precisará de uma grande suíte (e de uma forte cultura) de testes unitários, como qualquer linguagem dinâmica.

E também não tem aquela vantagem de uma linguagem dinâmica. Tipos não são garantias de que métodos obedeçam estritamente um contrato. Em linguagens “puramente” dinâmicas, como não há tipos nas referências, é permitido uma certa flexibilidade do que se pode ou não pode aceitar. Exemplo, em Ruby, poderia ter métodos que recebem valores válidos, não importando seu tipo.

# classe hipotética Triângulo
# válido
t = Triangulo.new :tipo=>:retangulo
 
# válido também, por que não?
t = Triangulo.new "tipo"=>"retangulo"
 
# válido
t.hipotenusa 10
 
# válido, por que não?
t.hipotenusa "10"
 
# opa! erro! O método lança exceção!
t.cateto_oposto -4

Tá vendo, os métodos podem tanto receber String quanto números, o importante é o valor resultante ser um número natural. O pensamento da tipagem limita essas espertezas, pois fica-se o tempo todo imaginando: “Não! Esse método tem que receber uma ‘classe X’!” (Pior que o indivíduo se esquece até da diferença entre objeto e classe.). Como Groovy não vai incentivar ninguém a abandonar os tipos em tudo quanto é canto, também não se receberá os benefícios das linguagens dinâmicas.

Então, pra amarrar com o título acima. Sou da opinião de que Groovy é ruim… não, corrigindo… de que Groovy é a pior linguagem do mundo porque, ao unir o feio inteligente (a tipagem estática) com a gostosa burra (a tipagem dinâmica), não se deu origem a um filho bonito e inteligente, como era de se esperar.

Foi pior, o filho é feio e burro.

Existe dicotomia entre prazo e qualidade?

terça-feira, 27 de janeiro de 2009 às 21h40 BRST

Minha opinião: não.

Um projeto não anda mais rápido com menos qualidade ou mais lento com mais qualidade. Os profissionais que defendem a tese de que qualidade interfere no prazo do projeto, costumam se alienar nos Gantt Charts. Pois, quando ocorre uma redução na qualidade, os gráficos apresentam “progressos” que inexistem, porque não é progresso de fato, é apenas um trabalho que será adiado mais pra frente, sempre antes do prazo de entrega. Queda de qualidade apenas cria mais impedimentos para a conclusão do software, não encurta o seu tempo.

Na maioria das vezes, os profissionais não sabem definir, em seu prójeto de software, o que é qualidade. Não raro, pra algumas pessoas, a qualidade é definida como a produção de um diagrama extenso no Rose, a definição detalhada de padrões, as checagens intermitentes que garanta que nada saiu do lugar, o padronização de codificação… Desculpe, mas nada disso tem a ver com qualidade.

Permita-me explicar: na verdade, uma das coisas que determina a existência de projetos atrasados é a desconfiança. Sim, é um fator humano, não técnico. A desconfiança faz com que aquilo que, em condições normais, seria ridículo, se torne perfeitamente plausível num ambiente hostil.

Exemplos em desenvolvimento de software: o programador que (re)escreve toda a conversa por e-mail (pois há a desconfiança de que o outro lado mude de idéia); o manda-chuva que escreve uma aplicação “amarrada” (pois não há garantia de que os programadores juniores escrevam corretamente); o arquiteto que escreve toneladas de documentação (numa eventual cobrança dos superiores, ele pode comprovar que fez o trabalho corretamente); o especialista que encontra um nicho de trabalho numa equipe e não faz outra coisa (garante que ele não será cobrado por problemas no profuto final); o gerente que põe um prazo apertado (para garantir que não haverá “corpo-mole”).

Ou seja, todos desconfiam de que seus pares possam um dia puxar o teu tapete, de que seus subordinados mintam e não entreguem o esperado, de que seus superiores não te dê suporte e não torele as mínimas faltas, de que os clientes tentem enrolar e te trapacear… A solução adotada por muitos são os infindáveis documentos que devem ser assinados com sangue por ambas as partes, as verificações e reverificações de procedimentos, a mentira, a cortina de fumaça, as desculpas de que “isso é assim mesmo”… Todo esse trabalho só existe por causa da desconfiança, trabalho esse que consome tempo que consome dinheiro que não servirá pra nada no produto a ser entregue (como se diz por aí: não “agrega valor”).

A solução é simples, a princípio. Se existe desconfiança, crie um ambiente de confiança. Dããã! Fazer isso não é tão simples, e depende de tolerância, respeito mútuo, valorização de um time ao invés de um indivíduo. Cuidar da confiança é bem melhor do que as firulas que servem apenas para remediar situações específicas que não atacam o mal pela raiz. Parece até que as pessoas procuram buscam curar o câncer receitando analgésicos!

Você é um ítem de mercado!

quarta-feira, 21 de janeiro de 2009 às 23h25 BRST

Isso mesmo! Não vá hastear a bandeira vermelha lutando pela condição injusta que os programadores são tratados. Para o mercado de trabalho, você é um produto que possui valor. Também não fique triste, você não tem que se conformar, você pode ficar por cima. Vou te dar alguns exemplos:

1.
Você é um agricultor, e a produção na roça é seu único meio de sustento. Como sua produção é revertida em dinheiro, você está mais interessado em cultivar aquilo que te oferece o maior retorno. Mas o problema é: o que cultivar? Imagine que num determinado ano a batata está com preços lá nas alturas. Com isso, você passará o ano cultivando batatas. No ano seguinte, você vende o seu produto para receber a grana alta que estava tanto sonhando… porém o valor recebido está bem abaixo do esperado.

Por que isso? O que aconteceu? Simples, você não foi o único que olhou o preço alto das batatas. Todos olharam! E o que essa multidão fez? Plantaram batatas! E com tantas batatas disponíveis no mercado, o preço individual caiu. Simples regra econômica. Os poucos que se deram bem, foram aqueles que não cultivaram batatas, mas algodão, cuja produção diminuiu de um ano pra outro.

Agora mude as palavras, ao invés de agricultor, leia programador. Ao invés de batata, leia qualquer tecnologia ou buzzword da moda, como SOA ou Cloud Computing. Perceba que no momento em que você ouvir uma expressão da moda, levará um ano (tá, mais ou menos) para você ficar muito bom. Até lá, aquilo que você estudou não será uma área tão bombada, e seu salário permanecerá igual ao que era antes. Ruim, não?

Por que você resolveu aprender aquele conteúdo na primeira vez que o viu? Necessidade de se adequar ao mercado? Minha opinião, você não pode ser tudo aquilo que a sopa de letrinhas das ofertas de emprego lhe pedem, esqueça! Quando se pede muita coisa, fica-se a sensação de que a consultoria está buscando um Chuck Norris, um herói que faça o impossível possível. Tenha como guia aquilo que você faz e gosta. Exemplo: surgiu a API do Android, uma biblioteca que permite construir aplicativos para o sistema operacional dos futuros celulares. Deveria eu aprender essa API? Talvez até faça sucesso, mas o que eu faço (e gosto) é programar aplicativos que rodam em servidores, nunca me interessei por aplicações móveis. Então, colocarei esse framework como baixa prioridade na lista das coisas que gostaria de aprender. Porém, existem programadores que já conhecem Java ME ou que sonham em trabalhar com celulares, que talvez encontrem uma motivação maior do que eu encontraria para aprender o Android.

E se o framework fizer sucesso? Vou deixar perder essa oportunidade? Sim, pois não conheço dispositivos móveis, e não é a área que eu gosto mais.

2.
Qual a diferença entre Bohemia e Itaipava? Não sou conhecedor tanto assim do universo etílico, mas posso afirmar uma coisa: a primeira é mais cara que a segunda. Por que? Bohemia é supostamente de qualidade superior em relação às outras cervejas. Não só isso, essa qualidade é perceptível aos consumidores da bebida, fazendo com que estes paguem mais caro sem reclamar. De fato, para a AmBev, não custa muito mais produzir Bohemia do que produzir Antarctica. Muito provavelmente, a companhia mantém uma margem de lucro baixa para as cervejas mais populares, compensando a perda com as cervejas mais elaboradas. É fato que, para os poucos que não se importam em pagar mais caro e que apreciam uma boa bebida, o preço pago a mais não é uma ofensa, mas ao contrário, chega a ser considerado justo e até credita-se a ter um melhor custo-benefício. Bohemia é o que se pode chamar de produto premium, que não é limitado às cervejas, existindo em vários segmentos de mercado onde o produto final não é uma commodity.

Agora, se você é um produto, por que não ser então um produto premium? Ser premium significa simplesmente que você oferece mais valor ao seu empregador, e portanto recebe mais por isso; mas não porque você resolveu dar uma de machão e ficou trabalhando 14 horas por dia, mas porque você é diferenciado. Tá, eu sei, a maioria das empresas não dão a mínima, tomam mesmo é Kaiser. Mas e se existir 1% onde o ambiente onde não é assim? Não vale a pena ser diferenciado?

Mas como ser diferenciado? Duas dicas (que não são as únicas):

- leia um livro de computação por ano: sério, a absoluta maioria dos programadores não fazem isso, um livro por ano é garantia certa de estar bastante acima dos outros. Se precisa te indicação, reduzo a dois livros: The Pragmatic Programmer, e Patterns of Enterprise Application Architecture.

- aprenda inglês: leva tempo, uns cinco anos ou mais (e não há cursinhos que focam “na conversação” que vai reduzir esse tempo), mas não é algo que vai se perder no tempo e ficar ultrapassado.

3.
Carro: existe o ano do modelo. Roupas: existe a estação. Computadores: existe incremento de mais e mais velocidade e capacidade.
A indústria, a partir do século XX aprendeu a incrementar seus produtos de tempos em tempos. Alguns podem pensar que isso é esperteza dos empresários para fazerem os consumidores comprarem mais. Mas, se pensarmos bem, quando o consumidor possui um produto que estragou ou quebrou, e quer comprar um novo, ele não tem o desejo de comprar a mesma coisa, prefere comprar algo melhor do que ele tinha. Então, é do interesse de tanto dos empresários quanto dos consumidores que os produtos ofertados mudem com o tempo.
Nossa área também vive essa constante de mudanças. O tempo passa e novas bibliotecas, novos frameworks, novas linguagens surgem e, embalados por “vendors” ou por evangelistas, eles são ofertados ao mercado. Não raro, os programadores ficam numa batalha contrária, reclamando do excesso de frameworks, da modinha de linguagens, do fluxo incessante de alterações… Melhor seria se essa multiplicação de novas coisas terminassem, não é mesmo?

Discordo! Seu problema é não entender princípios e padrões existentes em cada tecnologia. Por exemplo, vários frameworks seguem o mesmo padrão MVC, várias linguagens seguem o paradigma de orientação a objetos, outras linguagens seguem o paradigma funcional, mecanismos de persistência costumam apresentar os atributos “sujos” e o cache de requisições numa mesma transação. Aprender aquilo que está por trás de tecnologia é a melhor maneira de, quando algo novo e melhor surgir, você não fique perdido. Há um “problema”: abstrair conceitos de ferramentas só é possível quando você se defronta com mais de um tipo de linguagem ou framework. Infelizmente, a maioria apenas conhece uma linguagem (Java), apenas um banco (Oracle), apenas um mecanismo de persistência (Hibernate) e apenas um framework (Struts). Se é esse seu caso, corra atrás de aprender uma segunda opção. E se conseguir abstrair, as terceiras e quartas opções serão bastante fáceis.

Closure: em Java (?)

quarta-feira, 14 de janeiro de 2009 às 21h35 BRST

Esse post é uma continuação da série Closure, que também já falou de C++.

Java tem closure? Como assim? Bom, a linguagem tem mais alguns truques que dá pra se aproximar melhor de closure do que C++, mas ainda é bem distante de linguagens onde closures é uma coisa natural (tanto é que os javeiros mal usam essa sintaxe). Enfim, e ainda por cima, precisarei utilizar a principal muleta das linguagens chinfrins: design patterns.
Leia o restante desta entrada »

Desempenho / Escalabilidade: a última carta dos idiotas

segunda-feira, 12 de janeiro de 2009 às 22h29 BRST

Meu, hoje, 12/01, quase tive um ataque cardíaco (não, não tive não, é brincadeira). Duas coisas que eu vi, uma na Mundo Java, outra no GUJ, me deixaram com raiva.

Vamos à Mundo Java primeiro que, como sempre, está excelente. Hoje vi só a matéria sobre EJB e Spring (muito boa), porém houve um pequeno trecho que me deixou de estômago embrulhado (ênfases são minhas):

Anti-pattern em injeção de dependência
Com a facilidade e praticidade do EJB 3.0, alguns desenvolvedores acabam deixando de lado a preocupação com a escalabilidade e gerenciamento de recursos do container, anotando toda e qualquer classe do sistema para se beneficiar da injeção de dependência. Isso não é uma boa prática porque cada objeto anotado com @Stateless existirá um novo recurso para ser gerenciado pelo servidor de aplicações.

Um exemplo prático dessá má utilização de injeção de dependências no ambiente EJB é a implementação do design pattern Data Access Object (DAO) como um EJB. Dependendo do design do software, cada funcionalidade do sistema irá conter um DAO e essa funcionalidade será um Session Bean para se beneficiar do recurso de injeção de dependência do servidor de aplicações. Para evitar esse problema, uma solução seria injetar o EntityManager diretamente nos session beans, por meio da anotação @PersistenceContext, ou utilizar o design pattern Abstract Factory.

Primeiro, vamos à bronca: você não está programando em C, nem precisa ouvir os malucos que programam nessa linguagem. Fim da bronca.

Segundo, existe dois problema na definição de um Stateless Session Bean (SLSB): um que a anotação não é sobre o objeto (isso ainda não existe na linguagem), mas na classe; e dois que, quando você cria um SLSB, não há a criação de um recurso, mas de váááários recursos em pool. Se você olhar na configuração do Glassfish, verá que por default é possível ter até 1024 instâncias de SLSB no pool.

Terceiro, sabe qual a justificativa para isso ser um anti-pattern? Escalabilidade, só isso! Não é problema de code smell, de código que gera resultados imprevisíveis, de problemas de manutenção…, nem nada! Simplesmente ES-CA-LA-BI-LI-DA-DE! Agora, o pool de instâncias de SLSB não existe para se ganhar escalabilidade? Se tiver problemas com isso, vai nas configurações de seu servidor e mude os parâmetros do container EJB! Outra solução é comprar mais memória ou, se for mais sério, fazer load balance de mais de um servidor.

Pior ainda, a alternativa ao “anti-pattern” é “injetar o EntityManager diretamente nos session beans”, o que fatalmente acarretaria códigos macarrônicos com métodos gigantescos e difíceis de ler. Ou então, “[utilize] o design pattern Abstract Factory” que, pelo que já vi usado no contexto do EJB, é POG!; pois é usado um único EJB para o Factory, que devolveria os DAOs necessários, que por sua vez, tem código muito mais idiota para se pegar o EntityManager do que se fosse feito por SLSB!

Gente, use SLSB para DAO também! Que mal há nisso? Escalabilidade não é! Acho que no fundo, as pessoas sentem saudades do tempo em que cada camada tinha seu framework, tipo: era Struts para a apresentação, EJB para a camada de negócio, Hibernate para a persistância… Hoje estamos se aproximando da era onde os SLSB podem ser usados até na camada de apresentação (Seam / Web Beans)! E ninguém passou a escrever código horrível por causa disso! Por que raios ainda ficar nesse pensamento?


Vamos ao tópico do GUJ, maldito! (Não você que é maldito! O tópico!) (link) O cara parecia que quer defender com unhas e dentes que usar static é melhor que criar instâncias, polimorfismo…, enfim, essa coisa linda que é o OO.

Bom, o que sei é que usar static a torto e a direito no Java EE dá merda, pois é um static por class loader, e os servidores de aplicações possuem vários class loaders, cada um com potencialidade de carregar a classe e ter seu próprio static. Segundo, que com métodos static não dá pra fazer muita coisa que o Java EE oferece (EJB, por exemplo). Terceiro, que é idiota mesmo, coisa de gente que não sabe OO.

Agora, sabe a justificativa para usar static? O cara acredita que é mais rápido, simplesmente isso! Quer dizer, dava muito bem pra gerar um código bom, usando OO, e comprar uma máquina de configuração muito boa. Muito melhor do que se matar em otimizações minúsculas de veracidade duvidosa.

Aliás, vou dar um guideline para se fazer otimizações:

1. Pergunte ao cliente se está achando o sistema lento. Se a resposta for não, fim do guideline.

2. A compra de mais memória, mais disco ou mais blade custa menos que o pagamento de uma equipe de desenvolvedores? Se sim, vá na Santa Efigênia e fim de guideline.

3. Meça a duração usando vários casos possíveis.

4. Faça a alteração e meça de novo.

5. Se a nova medida não for muito menor que a medida antiga, jogue suas alterações no lixo e volte ao passo 4.

6. Caso contrário, comite a alteração e dê por encerrado (por enquanto).


Os dois casos me deixam perplexos: é como se para se justificar alguma coisa que não sabe bem o porquê, ao invés de ir mais a fundo e pesquisar, diz-se apenas que a altenativa “ruim” tem problemas de desempenho ou escalabilidade! Simples assim! E esquece que esses dois tipos de problemas está mais relacionado à arquitetura, à característica do sistema, ao “conjunto da obra” e muito pouco sobre a tecnologia ou o paradigma em si. Por muito escarcéu, muita gente escolhe o Barrabás.

Agora, por que as pessoas usam o argumento do desempenho / escalabilidade? Tenho duas teorias:

1. Alguns programadores aprenderam apenas uma determinada tecnologia em sua carreira. Quando esta tecnologia começa a sumir, eles passam a ter um certo desdém pelo novo, classificando pelos mais variados adjetivos. Alguns deles simplesmente não colam. Porém, o que, às vezes, fica marcado, é dizer que tal coisa não tem desempenho ou não tem escalabilidade, e por uma única razão: é difícil provar a menos que se meça com os próprios olhos. E como muita gente não faz isso, fica-se no benefício da dúvida.

2. Alguns programadores trabalham em ambientes péssimos de trabalho, a principal é a ausência de decisão e autonomia. Normalmente, as decisões são concentradas em pouquíssimas pessoas, e que nem sempre são as mais qualificadas. Os “artefatos” que saem das mãos dessas pessoas são os famosos diagramas de UML, bastando o programador codificar. (O mais imbecil nisso é que os “eleitos” escrevem diagramas tão detalhados que poderiam ter feito o negócio direto em código, e que haveria a mesma abstração. Mas não fazem código porque delegar essa atividade pra alguém é a melhor maneira de camuflar seus próprios erros.) E como o programador não tem a liberdade necessária para fazer seu trabalho, só lhe resta uma coisa intelectual para fazer: otimizar. Pena que será imperceptível para os olhos dos outros. Pena que o próximo a dar manutenção será ele mesmo.