Archive for May, 2008

Singletons…

Wednesday, May 28th, 2008

Singleton Considered Stupid

A Completa Irrelevância do Certified Scrum Master

Tuesday, May 27th, 2008

Semana passada o Richard Durnall me chamou para assistir a uma aula que ele deu na University of Melbourne. O Rich é o guru local de Lean e é uma figura.

A aula foi interessante. O curso é o mestrado em alguma das 343.435 ramificações de Tecnologia da Informação, basicamente uma escolinha para CIO-wannabe. Para se ter uma idéia todas as perguntas da sessão foram sobre implantação de ERPs, você via claramente que nenhum dos estudantes tinha a mínima vivencia na indústria e acreditavam piamente nas suas Info Corporate da vida.

A matéria era sobre comparação de metodologias e o Rich não foi o único. Antes dele apresentou um senhor, que é professor da instituição e arquiteto do maior banco da Austrália, onde inclusive tenho conta (brr…). A palestra do senhor arquiteto foi sobre como ele participou da salvação de um projeto de data mining usando o bom e velho waterfall. O único ponto diferente de uma lição clássica sobre como não fazer software foi sobre o uso de técnicas de Six Sigma para avaliação e priorização dos requisitos.

Quando chegou a vez do Rich apresentar Agile/Lean foi um contraste enorme. Na sessão de perguntas:

- Você falou sobre estes métodos ágeis e sobre como eles…er.. não ligam para requisitos. O [cara defendendo waterfall] apresentou um caso real de um grande banco. Você realmente acha que as técnicas de algo como agile podem competir com Six Sigma? [nota: uh?]
- Então, na minha apresentação eu fui bem ralo e essa é uma palestra introdutória, então foi bom você perguntar isso. Eu trabalhei na [top 5 montadora de automóveis], na [maior empresa aérea do mundo] e em alguns bancos. Nas duas primeiras empresas eu fiz parte da implantação de Six Sigma, inclusive eu sou Black Belt. O que eu vi deste processo foi [...] e por isso que agile/lean é uma boa escolha.

Agora pense que em vez de “Six Sigma Black Belt” ele tivesse dito algo como “inclusive eu sou Agile Software Specialist e os problemas de Six Sigma são [...]“. Teria o mesmo efeito?

Outro caso recente e interessante foi no Australian Architecture Fórum em Sydney. O Halvard estava apresentando uma palestra extremamente interessante sobre governança de projetos SOA onde a única ferramenta é um wiki. Em algum momento alguém levanta:

- Ok, ok, isso aí é muito Web 2.0, muito legal mas não é aplicável no meu cenário.
- E qual seu cenário?
- Eu trabalho em um banco, faço parte do grupo de controle de serviços de segurança. Isso de REST, wiki é muito legal mas vocês não entrariam num banco de modo algum!
- Uhm.. interessante você falar disso porque segurança em serviços é uma das minhas áreas de estudo… eu concluí meu Ph. D. em SOA na Universidade de Sydney e meu foco é exatamente segurança. Na verdade, na ThoughtWorks a maioria dos clientes são bancos e, inclusive, tivemos hoje de manhã o arquiteto principal do banco [top 5 banco australiano] falando exatamente sobre como usaram este tipo de técnica para governança num projeto que participei.

Imagine que ele tivesse falado “Eu sou um Wiki Certified Contributor e um RESTafarian Official Gold Partner”. Teria o mesmo efeito?

Por que das historinhas? Para argumentar numa discussão que eu tive com o grande Juan Bernabó sobre a total e completa ausência d sentido em algo como Certified Scrum Master. O Juan argumentou que certificações são valorizadas -e requeridas- pelas empresas. Meus pontos são:

  • Eu não conheço nenhuma pessoa que acredite que um curso de dois dias, sem sequer uma avaliação final –pagou, passou na pratica- deva ser valorizada. Se nós sabemos que a certificação não tem valor por que a venderíamos de outra forma? Agile não é sobre trazer valor e melhorar praticas?
  • O mercado também quer porque quer e acha que precisa de cronogramas detalhados, requisitos esmiuçados e projetos que terminam em uma grande fase de testes. Nós sabemos que isso não traz valor não fazemos apologia a este tipo de coisa, por que com certificação seria diferente? Por que ao invés de combater a ineficiência e a busca por respostas fáceis nós criamos e glorificamos nossos próprios selos?
  • Uma certificação emitida por si mesmo não vale nada. A menos que alguém já acredite que Scrum traz algum valor essa certificação é como acreditar que o Inri Cristo é Jesus porque ele afirma o ser.

Em resumo, eu acho o curso que é dado com o CSM ótimo. Ele abre mentes e é uma fantástica introdução. E só. O certificado emitido por este curso não tem qualquer valor real e propagandear o contrario, ajudando empresas a continuar glorificando certificações sem sentido, vai contra a primeira linha do Manifesto Ágil:

We are uncovering better ways of developing
software by doing it and helping others do it.

O debate completo está aqui.

Nem só de troca de mensagens vivem os objetos

Sunday, May 25th, 2008

Percebi que boa parte das dúvidas quanto ao meu post sobre como objetos não possuem atributos se deve ao fato das pessoas não terem geralmente um conhecimento real sobre o que é troca de mensagens.

Perfeitamente compreensível. Na maior parte dos livros e faculdades as pessoas aprendem que Orientação a Objetos é sobre como utilizar classes e sobre como as funções são chamadas de métodos. Por algum motivo esquecido nas areias do tempo decidiu-se que chamar o método em uma classe era passar uma mensagem e por isso algumas pessoas notoriamente pedantes usam este termo ao invés de dizer apenas “chama a função”.

Bem, os conceitos no parágrafo acima estão errados. Orientação a Objetos não é sobre classes e sim sobre…er… objetos. Você pode ter OO sem ter classes, como JavaScript e Io e pode ter também OO sem mensagens.

Troca de mensagens é um conceito utilizado em diversas áreas, não apenas Orientação a Objetos. Você pode ter um Sistema Operacional baseado neste conceito -como o MINIX por exemplo- ou criar uma arquitetura de computação distribuída como SOAP.

O que distingue a passagem de mensagens é o fato de que o recipiente da mensagem, seja um objeto, um serviço ou um processo, é quem decide o que é feito em decorrência de sua invocação.

Para tentar içar um pouco mais claro eu criei um meta-modelo bem bobinho em Java. Este representa um sistema Orientado a Objetos com classes e passagem de mensagens. O código abaixo mostra como declarar uma Classe calculadora e enviar uma mensagem dizendo para que esta multiplique números.

BlocoDeCodigo bloco = new BlocoDeCodigoImpl<Integer, Integer, Integer>(){
			public Integer executar(Integer a, Integer b){
				return a * b;
			}
		};

		Classe classeCalculadora = novaClasse("Calculadora");
		classeCalculadora.declaraMensagem("multiplique", bloco);

		Instancia calculadora = instanciar("Calculadora");

		assertEquals(8, calculadora.enviaMensagem("multiplique", 2, 4));

Note os passos realizados. Primeiro criamos um bloco de código, uma função. Depois dizemos ao sistema que existe uma classe chamada calculadora. Logo apos registramos o fato de que calculadora responde a uma mensagem executando o bloco que havíamos declarado.

Em termos de semântica, este código é mais ou menos equivalente a este:

public class Calculadora{
 public Integer multiplicar(Integer a, Integer b){
  return a * b;
}
}

Depois nós instanciamos a classe e passamos uma mensagem para ela, o que seria equivalente a:

Calculadora calc = new Calculadora();
calc.multiplicar(2,4);

As classes relevantes:

public class Ambiente {
	static Map<String, Classe> classesDeclaradas = new HashMap<String, Classe>();

	static Classe novaClasse(String nomeDaClasse) {
		ClasseImpl classe = new ClasseImpl(nomeDaClasse);
		classesDeclaradas.put(nomeDaClasse, classe);
		return classe;
	}

	static Instancia instanciar(String nomeDaClasse) {
		return new Instancia(classesDeclaradas.get(nomeDaClasse));
	}
}

public class ClasseImpl implements Classe {

	private final String nome;

	private Map<String, BlocoDeCodigo> mensagens = new HashMap<String, BlocoDeCodigo>();

	public ClasseImpl(String nome) {
		this.nome = nome;
	}

	public void declaraMensagem(String nomeDaMensagem, BlocoDeCodigo blocoASerExecutado) {
		mensagens.put(nomeDaMensagem, blocoASerExecutado);
	}

	public String nome() {
		return nome;
	}

	public boolean respondeA(String nomeDaMensagem) {
		return mensagens.containsKey(nomeDaMensagem);
	}

	public BlocoDeCodigo codigoParaMensagem(String nomeDaMensagem) {
		return mensagens.get(nomeDaMensagem);
	}

}

public class Instancia {
	private final Classe minhaClasse;

	public Instancia(Classe classe) {
		this.minhaClasse = classe;
	}

	public Object enviaMensagem(String mensagem, Object... args) {
		Object primeiro = args.length > 0 ? args[0] : null;
		Object segundo = args.length > 1 ? args[1] : null;

		return minhaClasse.codigoParaMensagem(mensagem).executar(primeiro,
				segundo);
	}

	public Classe classe() {
		return minhaClasse;
	}

}

Esse meta-modelo é baseado em troca de mensagens. A classe Calculadora não recebe código a ser executado ela apenas recebe o nome de uma mensagem e parâmetros. Imagine que eu registre o mesmo bloco de código para várias mensagens, ou que eu use recursos de AOP e intercepte a execução do bloco. Nada disso é relevante para quem invoca a mensagem, ele apenas a envia e o que acontece em decorrência disso é responsabilidade do receptor.

Como quase todas as linguagens atuam desta forma pode ser difícil entender o conceito já que nunca se viu nada diferente. Vamos então implementar outro meta-modelo que não usa troca de mensagens mas sim uma outra forma chamada Data-Directed.

Nesta forma de invocar operações em objetos –que, como a anterior não é específica de OO- quem decide qual função será aplicada é o ambiente de execução, o runtime. Quando você invoca uma operação o ambiente vai procurar dentre os métodos registrados qual é o aplicável para aquele objeto e vai executar o método nele. Common Lisp utiliza este recurso de maneira tão poderosa em suas Generic Functions que praticamente elimina a necessidade de coisas como proxies e AOP.

Nosso meta-modelo para Data-Directed é executado dessa forma:

BlocoDeCodigo bloco = new BlocoDeCodigoImpl<Integer, Integer, Integer>(){
			public Integer executar(Instancia instancia, Integer a, Integer b) {
				return a * b;
			}
		};

		Classe classeCalculadora = novaClasse("Calculadora");
		registrarMetodo("multiplique", classeCalculadora, bloco);

		Instancia calculadora = instanciar("Calculadora");

		assertEquals(8, executarMetodo("multiplique", calculadora, 2, 4));

Repare que agora o bloco de código recebe como seu primeiro argumento uma referência para a instancia a qual se aplica (se você já usou java.lang.Method sabe que isso não é incomum quando se desce ao nível de implementação de linguagem). Caso nosso exemplo fosse minimamente usável seria desta forma que o bloco obteria acesso ao objeto em si.

Logo depois criamos a classe como antes mas ao invés de registrar uma mensagem na classe nós registramos um método no ambiente, dizendo que o método se aplica àquela classe. A invocação em si é bem parecida com a anterior.

Na implementação a única classe mais interessante é o Ambiente, que agora é bem mais esperto:

public class Ambiente {
	static Map<String, Classe> classesDeclaradas = new HashMap<String, Classe>();
	static Map<String, Map<Classe, BlocoDeCodigo>> metodos = new HashMap<String, Map<Classe, BlocoDeCodigo>>();

	static Classe novaClasse(String nomeDaClasse) {
		ClasseImpl classe = new ClasseImpl(nomeDaClasse);
		classesDeclaradas.put(nomeDaClasse, classe);
		return classe;
	}

	static Instancia instanciar(String nomeDaClasse) {
		return new Instancia(classesDeclaradas.get(nomeDaClasse));
	}

	static void registrarMetodo(String nomeDoMetodo, Classe tipoEmQueSeAplica,
			BlocoDeCodigo bloco) {
		metodo(nomeDoMetodo).put(tipoEmQueSeAplica, bloco);
	}

	static Object executarMetodo(String nomeDoMetodo, Instancia instancia,
			Object... args) {
		Map<Classe, BlocoDeCodigo> tiposAceitaveis = metodo(nomeDoMetodo);
		if (!tiposAceitaveis.containsKey(instancia.classe()))
			throw new RuntimeException("Metodo inexistente");

		BlocoDeCodigo bloco = tiposAceitaveis.get(instancia.classe());

		Object primeiro = args.length > 0 ? args[0] : null;
		Object segundo = args.length > 1 ? args[1] : null;

		return bloco.executar(instancia, primeiro, segundo);
	}

	private static Map<Classe, BlocoDeCodigo> metodo(String nomeDoMetodo) {
		if (!metodos.containsKey(nomeDoMetodo))
			metodos.put(nomeDoMetodo, new HashMap<Classe, BlocoDeCodigo>());

		return metodos.get(nomeDoMetodo);
	}

}

Agora não apenas registra as classes mas também os métodos que são aplicáveis à cada classe e faz a invocação dos métodos em si.

Estes exemplos são bem educacionais, sem muita aplicação pratica, mas como já vimos em posts passados o fato de se usar message-passing ou Data-Directed ou properties, ou componentes ou qualquer outra coisa interfere no modo como devemos projetar nosso software. Existe uma vasta literatura sobre este tema mas ainda assim é uma das coisas mais desconhecidas pelo programador profissional.

Domain-Driven Design é Simples: Basta Chamar DAOs de Repositórios

Thursday, May 22nd, 2008

Um fenômeno notado no Oriente e no Ocidente é a notável incapacidade de se entender o que raios é Domain-Driven Design. Na minha opinião isso é causado elo fato de que para chegar num nível onde DDD te ajuda você já precisa ter uma base formada e essa base não é comum. Eu vejo muitas pessoas tentando entender a solução quando na verdade elas deviam estar tentando chegar ao problema primeiro.

Uma das conseqüências deste comportamento é a síndrome do Padrão-de-Prata. Todo mundo sabe que Não existe bala de prata mas, hei, ninguém falou nada sobre padrões (ou frameworks, ou plataformas…) então, buscando respostas fáceis é comum se associar Domain-Driven Design aos padrões Entity, Repository, Value Object e amigos.

O que parece bem difícil de entender é que o ponto todo não é usar os padrões e sim porque você os usa. As técnicas dos padrões em si é muito antiga e o livro não traz nada de novo exceto sobre como utiliza-los para atingir o Domain-Driven Design. O que qualquer tópico no GUJ sobre o assunto (e mesmo na lista sobre Domain-Driven Design) não parece entender é que os padrões são um meio e não um fim.

Eu já repeti algumas vezes que você pode utilizar todos os padrões do Eric Evans e ainda assim não usar DDD. Nos últimos meses eu vivi um exemplo claro.

O cliente em questão é uma empresa de comunicação. Ela produz algo que você pode simplificar como um jornal de classificados. Os jornais em si são gerenciados e impressos por um sistema antigo e uma equipe de mais de 30 pessoas foi destacada para criar a versão online deste.

Como o sistema é antigo ele não oferece qualquer interface para conexão, logo a solução encontrada foi acessar o banco de dados diretamente. Como os dados continuam sendo inseridos pelo sistema antigo (e este não muda desde 1998) não existe muito problema nisso.

O projeto possui um time excelente, um dos grupos de pessoas mais capacitadas com quem já trabalhei, mas ainda assim não conseguiam andar. A velocidade da entrega das histórias estava bem abaixo do esperado e o nível de retrabalho era ridiculamente grande, mesmo com clientes on-site. Apos verificar que se a deadline não fosse cumprida eles teriam corte no orçamento chamaram consultores para avaliar a situação.

A primeira coisa que um consultor pensa quando chega num lugar desse é que eles não estão seguindo um processo ágil de verdade. É extremamente comum entrar numa empresa “Agile de carteirinha”e ver um processo que na verdade é composto por mini-waterfalls, tão comum que a solução default é mudar o processo. Não era o caso. O processo era legitimamente ágil, da análise de negócios à homologação, e a equipe, como disse, era excelente.

Apos alguns dias fazendo pair programming percebi uma coisa errada com o vocabulário. Era extremamente difícil entender conceitos simples da aplicação e cada reunião que se ia o vocabulário era diferente. Daí vamos analisar o caso melhor.

O banco de dados em questão, como era de se esperar numa aplicação legada, trazia um bando de regras de negocio embutidas em flags absurdos. O time fez um fabuloso trabalho criando um mecanismo que transformava dados do domínio antigo para o novo, formando um excelente Context Map.

Dentro do domínio o código era extremamente enxuto, fazendo uso de JPA e Spring para deixar o Domain Model apenas com regras de negocio. Eles usam Repositories como interfaces para DAOs que implementam a lógica JPA de maneira bem interessante.

Ainda assim a velocidade era ridícula. 5 pares e apenas 4 pontos por iteração(semanal). Após verificar que o problema não era nem o processo nem o código em si só restava continuar pareando para tentar ver o que estava acontecendo.

Um dia, após reescrever a mesma funcionalidade duas ou três vezes, meu par e eu saímos para um café na Starbucks. Enquanto conversávamos eu perguntei:

- Mas quando é que vocês vão começar a outra parte do sistema?
- Outra parte?
- Sim, a parte que substitui o legado…
- Ah. Não, não vamos.
- Não?
- Quer dizer, vamos sim mas ele não vai ficar muito diferente, na verdade para nós do sistema web a única diferença é que eles vão disponibilizar um web service ao invés do banco de dados…
- Mas vocês não vão mudar aqueles conceitos legados para o modelo novo?!?
- Conceitos legados? Aqueles não são conceitos legados, são os conceitos que nossa indústria usa. Se você parar de usar aqueles termos seus clientes não vão entender o que está falando…

E aí eu entendi o problema da comunicação. Na retrospectiva eu levantei um ponto e conversamos sobre o problema.

A coisa era bem simples, em verdade. Os usuários internos do sistema são vendedores. Quando você vende um anuncio você fala em estilos e estes estilos são padronizados nacionalmente. O sistema antigo, por pior que seja, tem os estilos e os outros conceitos editoriais modelados mas nós não tínhamos isso no sistema web. O nosso domínio, por mais bonito e bem-feitinho, foi criado pensando na melhor forma de disponibilizar dados na Internet e por isso o nosso modelo não falava a língua do usuário. Os usuários falavam os conceitos do modelo antigo e para entender o que eles diziam nós tínhamos que fazer todo o mapeamento para o que aquilo representava em código.

Com apenas algumas iterações para um grande release não há a menor possibilidade de mudar todo o domínio. A solução vai ser implementar as mudanças de maneira incremental, toda vez que código novo é escrito ou código antigo refatorado caminha-se para o novo modelo, que é algo parecido com o abaixo.

Este foi um exemplo real do que não é Domain-Driven Design. Todos os desenvolvedores desta empresa possuíam o livro do Evans nas suas baias, não existia BO ou VO no sistema e as Camadas eram bem definidas. Ainda assim a linguagem do código não era a linguagem do usuário e sem isso você pode até ter um modelo Orientado a Objetos de alta qualidade mas não tem Domain-Driven Design.

Trilha de Livros: Desenvolvedor

Tuesday, May 20th, 2008

Esta então é a prometida lista de livros para desenvolvedores. Claro que não é nenhuma lista exclusiva ou “o guia definitivo”, apenas minha recomendação de leitura, partindo do principio que você já sabe programar em uma linguagem como Ruby, C# ou Java.

Este guia é bem genérico, sem tentar se especializar em nada e sem tentar abranger mais que o mínimo necessário. Espere modificações nesta lista.

  1. Operating Systems: Design and Implementation: Este ode não ser o melhor livro sobre Sistemas operacionais –ou pelo menos não o mais didático- mas eu gosto bastante. A maioria dos conceitos básicos de um Sistema Operacional está presente mesmo nas máquinas virtuais e seja como for, antes de abstrair você precisa entender como seu computador funciona. Claro que se você cursou SO na faculdade e, principalmente, se lembra de como memória virtual, filesystems e demais funcionam pode passar por este item –eu acho que uns 5% dos desenvolvedores que conheço se enquadram nisso, entretanto.
  2. Fundamentals of Object-Oriented Design in UML: Este livro ensina métricas e princípios básicos para desenvolvimento de sistemas Orientados a Objetos. Se você passou por projeto estruturado provavelmente conhece o autor e algumas de suas métricas.
  3. Head First Design Patterns: Uma introdução suave aos Design Patterns. A vantagem em começar com este ao invés do clássico (que é o próximo na lista de qualquer modo) é que você não tem que lidar logo de cara com Smalltalk e C++. Aprender um conceito não-tão-simples quanto Design Patterns enquanto tenta entender uma sintaxe fora do dia-a-dia é criar complexidade acidental.
  4. Design Patterns: Elements of Reusable Object-Oriented Software: Apesar de não ser indicado ao iniciante eu não acredito que voc6e consiga ir muito longe sem ler este livro. Pelo menos as narrativas são fundamentais para entender as motivações e a evolução do conceito de patterns. A falta desta leitura faz com que pessoas cometam erros grotescos.
  5. Agile Software Development, Principles, Patterns, and Practices: (em versão Java ou .Net) este livro traz uma visão bem pratica sobre alguns aspectos mais teóricos da Orientação a Objetos. Como u organizo pacotes? Qual o problema em ter dependências e como me livro delas? Devo sempre retornar null? O que significa herança na pratica?
  6. Refactoring: Improving the Design of Existing Code: Conforme você for entendendo mais sobre design de software vai sentir uma vontade enlouquecedora de apagar todo o seu sistema e começar de novo. Antes de sair por aí cometendo carreiracídio leia este livro, ele vai te ensinar a fazer pequenas mudanças que melhoram a qualidade do sistema e identificar código que fede.
  7. Patterns of Enterprise Application Architecture: A maioria dos patterns que você teve contato até aqui tratam de design em um nível micro. Como classes interagem, como elas colaboram e como gerenciar seus problemas. Este livro, entretanto, fala sobre padrões em um contexto mais amplo, sobre arquitetura de software.
  8. Domain Driven Design: Os livros até então falam de sotware pelo software. Como criar uma classe, como gerenciar dependências entre classes… mas ninguém te mostrou o que deve ser uma classe e o que não deve. Eric Evans supre esta demanda mostrando uma abordagem simples e eficiente para criar domínios que se aproximam do mundo real.
  9. POJOs in Action e/ou Applying Domain-Driven Design and Patterns: With Examples in C# and .NET: É normal que exista uma certa dificuldade em levar estes conceitos para o dia-a-dia. Estes livros não são indispensáveis mas eles ajudam bastante a entender como aplicar conceitos, ainda que algumas vezes de maneira “não canônica” mas ainda assim eficaz.
  10. The Pragmatic Programmer: From Journeyman to Master: Infelizmente muitas vezes, especialmente em consultorias de três letrinhas e faculdades McDonald’s, não temos um ambiente sadio para nos ensinar como programadores profissionais se comportam. Este genial livro traz uma boa parcela deste conhecimento condensado. Eu adicionaria o The Art of UNIX Programming, especialmente para aqueles que vêm de uma cultura drag’n'drop para o mundo real
  11. Ship it! A Practical Guide to Successful Software Projects Este livro é bem interessante para entender como um desenvolvedor utiliza ferramentas simples como controle de versão e issue tracker. Ótimo par aquém está profissionalizando uma empresa.
  12. Agile and Iterative Development: A Manager’s Guide Antes de você se dedicar a estudar mais uma metodologia de desenvolvimento em específico uma boa idéia é ler este livro, que traz um apanhado de diversas metodologias e as compara.

Objetos não são atributos + funções

Sunday, May 18th, 2008

Quando simplificamos demais ao ensinar conceitos acabamos criando problemas que demoram anos para se resolver, se é que são resolvidos. Um exemplo que eu observei hoje foi como algumas pessoas pensam sobre objetos.

É comum que seja ensinado no primeiro contato das pessoas com orientação a Objetos que objetos representam atributos e funções embaladas no mesmo saco. Bom, isso é uma simplificação extrema utilizada para fazer com que quem conheça programação procedural trabalhe com objetos de maneira mais simples, mas é uma simplificação tão grosseira que atrapalha algumas pessoas para o resto da vida.

Objetos não possuem propriedades + funções, eles possuem estado + comportamento. Você provavelmente vai usar atributos (i.e. variáveis de instancia) e funções (de instancia também) para implementar isso mas é um detalhe de implementação, não algo que deva ser exposto.

Um agravante deste problema são propriedades. Sejam propriedades bem resolvidas como as do C# ou meia-boca como do Java, elas representam apenas mais uma mensagem que o objeto recebe (já que ambas as linguagens são baseadas em troca de mensagens) e não “atributos” do objeto.

get/set em Java são herança de um modelo de componentes. Componentes não são necessariamente objetos, o que a (finada?) especificação JavaBeans fez foi utilizar classes Java para implementar componentes gráficos. Como não havia metadados (annotations em Java) naquela época o melhor era adotar uma convenção, daí os setXxx e getXxx da vida.

O problema é que este idioma saiu do controle. Ao invés de utilizarmos um método que faça sentido dentro do domínio preferimos criar um get/set burro, típico de arquiteturas BOLOVO.

Por exemplo, suponha que você possua uma classe Pedido que possui um status. Quando alguém vai atualizar o status do pedido para “finalizado” qual idioma é mais comum?

//1) set/get
pedido.setStatus(Pedido.Status.FINALIZADO);

//2) Mensagem
pedido.finalizar();

Creio que você concorda comigo que o primeiro é de longe mais utilizado. Qual o problema com ele? Como dissemos antes, Java é uma linguagem baseada em troca de mensagens. Uma mensagem é algo que o objeto recebe e decide o que fazer, no caso de Java isso acontece quando chamamos um método. Quem deve decidir o que deve ser feito não é o cliente e sim o destinatário da mensagem. Quando você diz setStatus(Status) você está dizendo para a classe que quer que os status dela seja o especificado. Pensa bem, é isso que você quer?

O que você quer em verdade é que o pedido seja finalizado. Como isso é feito, se muda status ou não, não é papel do código cliente, é papel do objeto (e deve ser documentado, especificado e verificado através de testes unitários).

Da mesma forma, quando você executa um getStatus() no objeto o que você faz com isso? Exceto em alguns casos específicos, um método getXxx() só deveria ser utilizado porque você precisa executar algo com ele que não vai envolver mudança de estado, como por exemplo exibir numa interface gráfica. Se você faz um getXxx() porque baseado no retorno você chama uma lógica ou outra provavelmente você está fazendo algo errado, já que é uma violação gritante da Lei de Deméter.

O que eu deveria fazer, então? Suponha que eu tenha o seguinte código:

public void notificarMudancaEm(Pedido p){
 if(p.getStatus().equals(Pedido.Status.FINALIZADO){
     servicoEmail.enviamensagemConclusao(p);
 }
}

Isso parece bem razoável, não? A lógica de enviar um e-mail de conclusão não está no Pedido e sim em algum serviço próprio para isso. Ele provavelmente é um observador do pedido e cada vez que você chama setStatus() esta é notificado. Num caso real recente eu estava trabalhando numa aplicação legada com o código exatamente como o acima. De repente alguém decidiu que um Pedido também está finalizado se estiver em status CANCELADO.

Essa é a hora em que o programador xinga a mãe do analista de negócios e vai caçar um email de três meses atrás que contem uma documentação, assinada em sangue, que contraria isso. O gerente de projetos vê aquilo, dá um sorriso e manda um email para o cliente daquela consultoria de três letrinhas dizendo que é uma mudança de escopo e que vai precisar de 50 horas a mais para isso. Ele diz ao programador que na verdade só tem 5 horas porque as outras 45 ele vai usar como desculpa quando o projeto atrasar. De quem é a culpa?

Bom, de quem é a culpa é assunto para outro post mas eu te garanto que não é da Orientação a Objetos. O problema no código acima (e certamente este código está repetido em milhões de outros lugares) é que ele não cumpre o princípio básico de deixar o objeto ser responsável pela sua própria vida. Você precisa saber se o pedido está finalizado mas ao invés de perguntar isso ao objeto você pergunta qual seu status.

Imagine que ao invés do código acima você possuísse algo mais… OO:

public void notificarMudancaEm(Pedido p){
 if(p.isFinalizado()){
     servicoEmail.enviamensagemConclusao(p);
 }
}

E suponha que você tenha que alterar o que FINALIZADO significa. Qual é mais fácil?

É este tipo de coisa que você perde ao transformar objetos em atributos+funções. Ao invés de pensar “quais são os atributos deste objeto?” pense “quais mensagens este objeto responde?”.

Mais sobre o Australian Architecture Fórum – Melbourne

Saturday, May 17th, 2008

Com mais calma agora, volto a falar do evento. O fórum foi patrocinado pela IASA, que possui um capítulo bem forte em Melbourne. A idéia é prover mais mesas redondas do que apresentações, minha palestra foi uma das três únicas que não seguiam este formato.

Eu cheguei atrasado e fui direto para uma mesa redonda sobre REST x SOAP. O apresentador/moderador era claramente tendencioso a favorecer REST e, apesar de adorar essa arquitetura, eu acho que isso foi uma falha grave. A parte boa foi que diversas pessoas tentaram defender SOAP usando argumentos bem interessantes. Nenhum deles me convenceu inteiramente mas me fizeram pensar sobre alguns cenários onde usar REST seria reinventar SOAP, ainda que mais coeso.

Minha apresentação foi bem interessante, eu não sei estimar tempo de palestras em inglês ainda e acabei usando apenas 30 minutos dos 50 esperados. Isso acabou sendo bom porque houveram muitas perguntas, especialmente sobre os widgets em JavaScript. No final da apresentação eu tive uma conversa muito interessante com uma pessoa que foi arquiteto de um dos principais canais de TV australianos e é impressionante como os cenários e problemas são os mesmos.

Durante o resto do dia eu fiquei no stand da ThoughtWorks conversando com as pessoas. Foi bem interessante ver o que os arquitetos presentes pensam da ThoughtWorks e fazer contatos profissionais, tanto para possíveis futuros colegas quanto para futuras oportunidades de projetos.

Uma coisa engraçada em eventos ora do Brasil é que apesar de nos consideramos os seres mais sociais do universo conhecido nossos ventos são sobre grupinhos. As pessoas não interagem com desconhecido. Nos eventos aqui e em outros países, no entanto, é tudo sobre networking. Chega a ser meio constrangedor você está saindo do banheiro e alguém fala um “Oi, eu sou X, quem é você?”.

Segunda-feira eu embarco para Sydney para mais um dia de evento. Isto é algo também interessante, como o evento é durante a semana e Melbourne e Sydney são cidades distantes o mesmo evento ocorre nos dois lugares.

Estes últimos dias (meses?) foram bem corridos e eu fico feliz de pelo menos esta tarefa se concluir.

Apresentação no Australian Architecture Forum 2008

Friday, May 16th, 2008

A apresentaçao em Melbourne acabou de terminar. Foi bem interessante e o evento em si está sendo uma experiência diferente. É algo mais como mesas redondas do que apresentações, mais sobre isso depois.

Aproveitando, agradecendo novemente ao Antônio Carlos pela liberação dos nomes e marcas, a apresentação ia ficar bem sem graça sem os screenshots :)

Australian Architecture Forum 2008

Thursday, May 1st, 2008

Falando em coisas agitadas, fui convidado para palestrar no Australian Architecture Forum 2008. O título é “Lightweight SOA Through Web Widgets” e falar de SOA com REST num evento onde vai estar presente o impagável Jim Webber é algo bem diferente.

Como meu Google Analytics diz que ese blog é acessado por pessoas aqui na Austrália fica o convite.

XFN++

Thursday, May 1st, 2008

1) Acabo de descobrir que o Rafael Pereira, o mineiro que mais entende de vídeo, tem um blog cheio de coisas que você deveria saber antes de colocar as palavras “vídeo” e “internet” na mesma frase.

2) O Rodrigo deve estar de folga agora