O Laércio Queiroz me entrevistou sobre DSLs. O resultado você vê no blog dele.
Archive for the ‘programando’ Category
Entrevista sobre Domain-Specific Languages
Tuesday, January 29th, 2008Você Pergunta: RAD
Thursday, January 24th, 2008Uma pessoa me escreveu um email sobre o tópico anterior. Novamente não vou citar nomes porque não pedi permissão (e não tenho motivos para expôr esta):
Shoes, beleza cara?
Então, lendo sobre a discussão sobre o Maker eu cheguei no seu blog e li sobre RAD.
Aquela ferramenta no NetBeansLixo pra fazer GUIs é um RAD? Ele desenvolve parte de um software, eu sei, não é um modelo de processo de desenvolvimento, né??Enfim, acredito que existam mais algumas por aí como Maker e queria saber da sua opinião: todas essas ferramentas são RADs e todas elas cometem gafes? Onde quero chegar é na pergunta: Hoje em dia, SEMPRE teremos um desenvolvedor por trás da solução?
É que eu sou totalmente contra essas ferramentas de gerar códigos automáticos… não confio muito nessas coisas… prefiro eu mesmo fazer os códigos, mas tenho a dúvida: estou muito antiquado (no sentido de muito atrasado e não acompanhando as tecnologias que estão evoluindo hoje) ou estou no caminho correto?
Bom, se você respondeu que sim na primeira pergunta (do NetBeans sobre GUIs), a principal desvantagem das ferramentas RAD (se é isso que aquele Lixo é) é a manutenção e evolução, certo? Uma vez, fazendo um trabalho pra faculdade, tive que usar aquele NetBeans. Quando fui usar Refactoring… nossa cara, que coisa mais chata… tive que refazer praticamente toda a interface gráfica.
Abraço.
Apesar de usar, eu odeio o termo RAD. Ele significa um grupo enorme de coisas e ao mesmo tempo não significa nada. O livro Software Development: Building Reliable Systems define RAD:
For the last ten years, many software projects have incorporated the use of “Rapid Application Development” methodologies in an effort to decrease development times. RAD, as it is generally referred to, incorporates an umbrella of methodologies based on spiral, iterative development technologies. RAD techniques range from the simple use of GUI development tools to quickly build prototypes, to processes incorporating complete, cross-functional business analysis. [...]
Então vou considerar que você quer dizer por RAD “ferramentas geradoras de código” do contrario este post nunca vai acabar. Sim, o Matisse do Netbeans é uma ferramenta geradora de código.
Ferramentas geradoras, em geral, são úteis quando não querem dominar o mundo. Eu adoro quando o Hibernate ou o Rails gera meu DDL SQL e eu não tenho que escrever CREATE TABLE. Eu adoro quando o Eclipse gera meus getters e setters e coisa do tipo. O problema é que esses geradores não costumam sobreviver num projeto de verdade.
O grande problema do gerador de código padrão, como o citado, é que ele possui diversos vazamentos de abstração. O Joel Spolsky fala especificamente sobre geradores:
The law of leaky abstractions means that whenever somebody comes up with a wizzy new code-generation tool that is supposed to make us all ever-so-efficient, you hear a lot of people saying “learn how to do it manually first, then use the wizzy tool to save time.” Code generation tools which pretend to abstract out something, like all abstractions, leak, and the only way to deal with the leaks competently is to learn about how the abstractions work and what they are abstracting. So the abstractions save us time working, but they don’t save us time learning.
Como pode-se perceber pelas discussões citadas o mercado destas ferramentas é… complicado. Um desenvolvedor que entende como a plataforma funciona (Java EE, no caso) dificilmente se encantaria pela ferramenta. Ele pode utilizar algo como um Spring IDE para gerar arquivos de configuração mas sabe que isso não é tão simples assim.
Os programadores mais recentes na plataforma Java podem não ter consciência disso mas uma ferramenta chamada xdoclet era muito usada quando sofríamos diariamente com EJBs 2.1. O que o xdoclet faz é gerar código, ele gerava todo o mapeamento do EJB (uns 3 arquivos XML diferentes, pelo menos) a partir de anotações JavaDoc (não existia Java 5 naquela época). O xdoclet era a salvação da lavoura, conseguia abstrair muitos problemas mas.. não era perfeito, nem pretendia.
Eu já trabalhei em projeto onde 50% do código era gerado pelo xdoclet e do restante ele não dava conta. A ferramenta não possui o tal do round-tripping então não dava para misturar código gerado com modificado. A solução foi optar por uma arquitetura que isolava as duas partes em módulos diferentes e só conseguimos chegar até ela porque –como disse o Joel- sabíamos como a ferramenta funcionada. Essa é uma ferramenta de automação, não de “geração automática de sistema”. Ela automatiza o trabalho que você teria, não te livra do fato de conhecer o que… bem… é sua profissão.
Acho que o Matisse se enquadra neste tipo.
O problema é que essas ferramentas –e seus persuasivos vendedores- dizem que irão abstrair todo o desenvolvimento. Para os cenários ideais elas podem fazer todo o prometido mas não houve até hoje uma ferramenta que conseguisse real sucesso fora dos casos mais simples e isso porque não é assim que construímos sistemas hoje. Nossos sistemas são uma salada de linguagens, conceitos, mapeamentos e configurações que uma ferramenta deste tipo não consegue acompanhar.
O que geralmente elas fazem é te prender à uma ou algumas arquiteturas genéricas que servem razoavelmente para alguns casos -geralmente sitezinhos CRUD de intranet- mas não para todos ou sequer para a maioria. Como arquitetura não é commodity não se pode simplesmente aplicar a mesma estrutura em todos os cenários.
Apos algum tempo em TI você começa a entender que o dia-a-dia desse mercado é um grande “mais do mesmo”. Você sempre está criando as mesmas coisas. Da última vez que contei eu já tinha criado uns sete gerenciadores de conteúdo web. Dá para utilizar a mesma arquitetura em todos? Não. Uns eram simples formulários, outros se integravam com back-ends complicados, outros era assíncronos, outros tinham integração com legado… cada um tinha uma história. Se há oito anos atrás eu comprasse uma ferramenta dessas e a tivesse aplicado nestes projetos eu teria que fazer personalização (i.e. sair do maravilhoso mundo do fluxograma) a cada projeto.
Mas eu estou falando de desenvolvimento de software de um tipo, não do mercado todo. Quando estive na faculdade pela última vez (antes da segunda fuga) estudei com uma pessoa de 43 anos que desde os anos 80 vive fazendo software em coisas como CLIPPER para lojinhas e boutiques. Ele não ganha mal. Pelo que entendo dos softwares deste tipo (já trabalhei neste ramo) a arquitetura é quase sempre a mesma. Talvez ele se favorecesse de algo assim nos seus negócios, apesar de que eu ainda acharia um risco desnecessário.
Então sim, hoje precisamos de desenvolvedores para projetar um sistema. Desenvolver sua arquitetura, seu design e verificar para que tudo seja eito da maneira mais adequada para o projeto (que nem sempre é a técnica mais adequada). Mas e o futuro?
O futuro prevê o uso de ferramentas de um nível mais alto, mas de maneira diferente. O ponto crucial é que essas ferramentas não são geradores de código Java (ou C#, ou Ruby ou o que for), elas mudam a visão sobre o código. Ferramentas como Domain-Specific Languages aumentam o nível da linguagem não tornando-a mais abstrata apenas mas sim levando para perto do negócio. Ferramentas de visualização criam pontos de vista diferenciado sobre o mesmo artefato, dependendo de com que olhos se enxerga.
Tudo indica que para desenvolver softwares no futuro o desenvolvedor não terá o mesmo papel que tem hoje. Ao invés de criar o código do sistema em si iremos criar as ferramentas que dão suporte à criação de sistemas pelos usuários.
Seja qual for o futuro ele não é sobre gerar código. Isso nós já fazemos à décadas e serve apenas como quebra-galho para nos livrar da complexidade que nós mesmo criamos.
Programação RADioativa
Sunday, January 20th, 2008Há alguns anos, quando era consultor independente, eu fui chamado por uma empresa bem grandinha do ramo de telefonia. Eles tinham produtos em C++ e queriam migrar para o Java. Na verdade já haviam migrado, mas estavam com problemas.
A primeira tentativa deles foi transferir toda a parte gerencial do sistema -que era vendido por alguns milhões de Euros- para Java. Para fazer esta etapa eles haviam contratado há um ano uma consultoria especializada canadense. Os canadenses sugeriram a compra de uma ferramenta RAD -por um acaso de outra empresa canadense- que permitiria que os desenvolvedores C++ criassem a aplicação em pouco tempo. Em três meses, tempo recorde, a aplicação já estava rodando no cliente, em produção. Durante os testes eles verificaram que a coisa era muito lenta mas como o mercado de telefonia tem muito dinheiro eles simplesmente aumentaram o número de máquinas.
A coisa foi passando até que alguém foi fazer a primeira manutenção. O sistema era um grande catálogo de assinantes, dependentes e registros de ligação, as regras pesadas mesmo ficavam no sistema em C++. As primeiras manutenções foram correção de bugs. A ferramenta funcionava dentro do Eclipse, você definia um modelo de entidades parecido com o modelo relacional, depois dizia quais operações precisava (criar, ler, listar, etc.), isso gerava o código. Se você precisasse de uma regrinha de negócio diferente, digamos que cada vez que um novo cliente fosse adicionado alguém recebesse um email, ia ter que alterar o código gerado. Como a aplicação -como todas- tinha suas peculiaridades muito código era escrito a mão. Mesmo assim o ato de criar toda a infra-estrutura (o scaffolding) poupava muito tempo.
Qual não foi a surpresa quando alguém reparou que a ferramenta só gerava código, ela não o lia de volta? Se você alterar o código e fizer alguma alteração o fornecedor deu duas escolhas:
- Alterar o código usando a ferramenta gráfica, regerar o código e depois adicionar novamente nossas alterações
- Abandonar a ferramenta e fazer tudo no código
Neste ponto que eu fui chamado. O fornecedor sugeria fortemente a segunda opção, por incrível que pareça. Eu concordei com eles, recomendei ao cliente que assumisse o prejuízo de ter escolhido uma ferramenta ruim e refatorasse o sistema enquanto inseria novas funcionalidades.
O mundo adora ferramentas RAD. Elas provocam a ilusão de que você não precisa de conhecimento ou de um profissional para criar programas. Não é assim que a banda toca.
Essas ferramentas surgem todos os anos. Todos se dizem revolucionários, quase nenhum diz que é um gerador de código, e todos dizem que servem para 87% dos casos. Puro marketing.
Geradores deste tipo existem há décadas. É até engraçado que o mais novo representante desta leva se gabe de ‘revolucionar’ usando o conceito de programação visual por fluxograma. Ahm? Isso existe praticamente desde que surgiram IDEs gráficas. Qualquer coisa que gere código via UML vai ter um fluxograma. A diferença é que não vai ter só fluxogramas, exatamente porque essas coisas foram abandonadas.
Na UML utilizamos o diagrama de atividades para um fim muito específico: representar transição entre estados dos objetos. É um dos diagramas mais raramente utilizados em um projeto OO simplesmente porque ele é procedural demais. Um sistema OO foca na interação entre objetos, não em algoritmos em si -que estão encapsulados dentro dos objetos.
Ao utilizar um fluxograma como unidade principal do seu sistema você está abandonando a OO. Isso pode ser uma coisa boa, depende do caso. para sistemas genéricos décadas de pesquisa da indústria apontam que Orientação a Objetos traz os melhores resultados na modelagem de negócios. Para um caso específico (BPM por exemplo), fluxogramas podem ser melhor. Estas ferramentas vendem trinta anos de retrocesso em modelagem.
Ainda assim, elas oferecem um bom scaffolding, não? Você não precisa saber nada sobre arquitetura, basta gerar o código na ferramenta! Bem, não exatamente. A maioria destas ferramentas vai seguir o exemplo acima: possuem poucos pontos de extensão e quando possuem não conseguem se integrar a eles. A primeira pergunta a fazer para um fornecedor desses é se a ferramenta suporta round-tripping. Round-tripping é o ato de gerar o código na ferramenta, editar o código e a ferramenta ser capaz de lidar com o código alterado. Quase nenhum RAD possui esta característica.
Outro problema é a arquitetura. Eu tenho certeza que uma arquitetura web simples pode ser utilizada por 87% dos casos mas tenho mais certeza ainda que cada um destes casos vai evoluir de uma maneira diferente. A arquitetura tem que ser flexível o suficiente para permitir todas estas formas de evolução. Obviamente que nenhuma destas ferramentas oferece nada parecido. Nós já vimos antes sobre o problema de se estabelecer uma arquitetura única para tudo, o problema com estas ferramentas é muito pior. Quando se define uma única arquitetura para todos os sistemas de uma empresa é ruim mas o que estas empresas estão vendendo é uma arquitetura única que funcionaria em diversos tipos de aplicações de diversos domínios sem sequer saber as necessidades delas antes.
Infelizmente em busca do cálice sagrado as empresas e -pior ainda- governos vão continuar gastando dinheiro nestes engodos. Eles prometem inovação mas fazem retrocesso de três décadas no tempo. Como conseguem montar um CRUD em 30 minutos são vendidos como a última bolacha do pacote, e lá vão os gerentes desinformados comprar estas coisas.
Se você está procurando este tipo de ferramenta esqueça qualquer um desses produtos ‘revolucionários’. Para começar entenda que a Ciência da Computação ainda não tem uma resposta definitiva para você. Sinto muito, estamos trabalhando nisso (é uma das partes da minha pesquisa). O campo mais avançado nesta área chama-se MDA. Eu não acredito em MDA mas isso não me faria negar que ela é a proposta mais plausível para este tipo de ferramenta atualmente. MDA possui implementações livres e proprietárias, é um padrão do OMG, utiliza UML, é baseado em um conceito de transformação de modelos e não de geração de código, é extremamente extensível e pode ter as características de produtividade dessas ferramentinhas de garagem. Só não baseie sua estratégia nele.
Os problemas de MDA: (1)ele eleva o nível de abstração mas não gera programação intencional e (2)ele usa uma ferramenta que não foi criada para isso, UML. São problemas muito menores do que os que você vai enfrentar com estes softwares ‘revolucionáros’ de ‘programação por fluxograma’.
Não caia no conto do vigário.
Engenharia de Build
Tuesday, January 15th, 2008Eu já trabalhei em projetos com vários tipos de sistemas de build. Uns usam um build completamente automático, uns usam um build interativo (um jeito carinhoso para se referi à porcaria do build em que você tem que apertar ‘enter’ constantemente). Uns demoram 1 minuto ou menos, outros 59 minutos. E alguns nem sistema de build criam! Acham que usar a função ‘Export as JAR’ da IDE é algo aceitável (dica: não é).
A maioria dos projetos tinha ma coisa em comum: não levavam o build a sério. O build de uma hora que mencionei começou com segundos e passou para minutos em algum tempo. Lembro numa reunião onde um grupo de desenvolvedores levantou a questão de que estávamos chegando em 30 minutos, todos na empresa ficaram preocupados. Aí a coisa esfriou e ninguém fez nada, nem ninguém reparou quando esse build chegou em uma hora.
A primeira medida aplicável é tratar o build como parte do seu software, como seu código. Praticamente todos os grandes projetos que participei tinham builds desnecessariamente complexos. Já vi casos onde arquivos build.xml eram gerados on-the-fly através de transformações XSTL, já vi empresas com frameworks de build, onde seu build.xml tem que importar um build.xml criado pela sempre infame ‘equipe de arquitetura’, já vi builds que usam Mavem como se fosse ant e até mesmo um build.xml que usava AWK para fazer a maioria das coisas. Tudo isso é mau sinal.
Seu build deve ser simples. Rake, ant, maven, make não importa: simples. Arquitete-o como faria com sua aplicação: divida em módulos e crie um arquivo de build para cada módulo. Idealmente deve ser possível fazer o build de um módulo em isolamento. No topo, crie um arquivo que faz o build de toda a sua aplicação apenas chamando os builds de cada módulo. Pense na interface dos seus builds, nos parâmetros de entrada e de saída. Encapsule seus módulos.
Testes unitários devem ser executados imediatamente após a compilação (se existente). Se o build falhar porque o teste unitário não passou é melhor que isso seja rápido e não após gerar o pacote de instalação. Testes de integração rodam após esse e os de aceitação na sequência.
Cuidado com testes de aceitação e integração. Pense no que você está testando, já vi casos onde a maioria dos testes de aceitação apenas repetia o que os testes de integração já faziam. Não esqueça que o papel dos testes de desenvolvedor não é substituir a homologação, você como desenvolvedor testa em caixa-branca e sabe quando um teste substitui o outro
Mantenha os artefatos gerados em diretórios temporários até que sejam copiados para seu destino final. Não misture artefatos temporários (arquivos .class soltos, por exemplo) com artefatos versionados (código-fonte). Use os .cvsignore da vida com sabedoria.
Pense sempre no desenvolvedor novato. Quanto tempo o novato precisa para ter um build funcionando na máquina dele? Se a resposta for mais que uma hora você precisa refatorar o build. Convencer os analistas de negócio e clientes que o build deve ser refatorado é duro. Provavelmente é a parte do código onde eles menos vêm valor. Antes de usar a força (ou a clandestinidade) para fazer suas mudanças tente ter uma conversa séria, tente msotrar o valor preto-no-branco.
O build de 60 minutos citado era um problema real. Enquanto o CruiseControl executava o bichinho o desenvolvedor tinha que ficar de braços cruzados porque poderia haver um problema n o commit dele e ia ser bem ruim identiicar o que houve se ele continuasse alterando o fonte. Também, após 60 minutos já haviam vários outros commits na fila, o próximo build levaria mudanças de muitas pessoas diferentes. O assunto era levantado requentemente para o ciente, que ignorava.
A solução que nosso time deu foi interessante. Começamos a escrever em um mural tempo que perdíamos com o build. Em algumas semanas descobrimos que pelo menos 8 horas de deenvolvimento por dia eram perdidas no processo. Fizemos uma estimativa de quanto de código poderia ser entregue usando essas horas desperdiçadas e fomos conversar novamente com o cliente. A postura foi outra, vendo os números as pessoas começam a dar valor. Conseguimos 8 horas por semana para trabalhar no build, o que ez com que ele reduzisse para 30 minutos. Não é o ideal, pelo contrario, mas 30 minutos a menos já foi suficiente para entregarmos mais valor e, principalmente, levantar a moral das pessoas.
Expressividade no Código
Friday, December 28th, 2007Um post no GUJ mais uma vez rende uma resposta maior do que se supunha. A thread em si é bastante útil mas existe muito ruído então vou tentar sumarizar:
Vocês pegam códigos que te faz passar horas e horas tentando entender o que está sendo feito? Valores que você nem imagina de onde estão vindo?
Eu sou muito ruim ou isso é normal?
E logo surge alguém sugerindo que deveria haver documentação. Existem casos onde documentação, seja JavaDoc, especificação funcional ou etc. é fundamental mas neste caso é diferente. JavaDoc, especificação textual e etc. devem ser uma fonte importante quando que está interessado nessa informação não vai lero código, é como reutilizar uma biblioteca ou um framework. Ninguém quer abrir o Spring para entender como utilizá-lo, precisamos de documentação para isso.
Um cenário completamente diferente é quando você recebe de presente um código já existente para dar manutenção. Neste caso o código tem que fazer sentido, tem que dizer algo. Tem que ser expressivo, mostrar suas intenções claramente.
NOTA: O trecho abaixo foi escrito direto no editor de texto, sem ajuda de compilador ou IDE. Por favor me corrijam.
Qualquer programador meia-boca sabe sua linguagem. Sabe o domínio dela. Veja o trecho abaixo:
abstract class A{
public abstract int d(){
}
}
class B extends A{
int z= 0;
int x=-1;
public B(int z, int x){
this.z=z;
this.x=x;
}
public int d(){
if(z==15) return x + x* 0.15;
esle return x;
}
}
Você entendeu muito bem, tenho certeza, que A é uma classe abstrata implementada por B. Que B tem um construtor que recebe dois inteiros, os armazena e usa numa computação simples com uma ramificação abaixo. Ótimo.
Imagine que você recebeu um email do seu usuário dizendo: “Precisamos fazer com que clientes do sexo feminino que comprem mais de R$1000,00 ganhem 10% de desconto.”. Tente implementar isso no código acima enquanto eu vou almoçar.
E aí, terminou? Sim, sim, claro que é impossível sem saber d que se trata. Então depois de procurar bastante você encontra no diretório onde fica a documentação do projeto um arquivo que pode te ajudar a entender. Após umas cinquenta páginas de diagramas de alto nível inúteis explicando tudo que acontece no container web você chega a uma descrição de algo como:
A classe A tem a lógica abstrata de uma venda. As vendas são sempre feitas de acordo com critérios específicos por isso existem classes que implementam vendas específicas. No momento (01/10/2003) só existe uma implementação, na classe B, que é a venda para uma pessoa física.
A primeira coisa que você pensa é: se desde 2003 ninguém precisou de outra implementação para que essa maldita classe abstrata? Mas ants de mexer no código precisamos entendê-lo, então vamos em frente.
O méodo e questão recebe três argumentos: a quantdade em reais vendida, o sexo da pessoa (segundo código vindo do mainframe na tabela ETXS32) e se a compra é casada ou não (um booleano).
De acordo com o caso de uso UC171 o sexo do comprador é utilizado para aplicar descontos.
TABELA ETXS32
15 -> masculino
22 -> femininoSe a compra for casada o processamento é feito delegando para outra classe, mantendo o padrão Strategy, Composite e Adapter do Decorator. Note que o Chain of Responsibility do Bridge é usado com Visitors para passar as instâncias de Flyweight pelos Interpreters[...]
Após a sequência de buzzwords de padrões é bom parar. Acho que a informação necessária já está aí em cima e olha que não se passaram nem 4 horas de procura! Vamos lá: recebemos o valor, o sexo segundo um código numérico sem lóica que vêm de outro sistema. Também é passado um boolean.. cadê o boolean?
Procurando no histórico deste arquivo no CVS (poxa vida, eles ainda usam CVS!) você vê que no meio de 2005 alguém tirou o boolean de lá com um comentário ‘Removido compra casada. Ninguém usa isso e ninguém entende isso. Ninuém vai sentir falta’. Acho que a pessoa estava correta mas ela esqueceu que existem uns 300 documentos que precisam ser revistos porque todos fazem referência a esta tal venda casada, do caso de uso, diagrama de domínio até diagrama de deployment. Cada mudança simples implica em editar 300 documentos… provavelmente mais tempo atualizando a tal documentação que o código… dá pra culpar o desenvolvedor?
Bom, agora você entende o que o código faz ao menos. Ele está aplicando um desconto de 15% para homens, você não conseguiu achar isso no caso de uso mas se ninguém está reclamando em produção é porque deve ser assim mesmo. Amanhã (afinal, você perdeu o dia inteiro hoje na ‘documentação’ do sistema) você faz a mudança.
Novo dia e você está pronto para alterar este código. Hmm… alterar pode ser muito rápido e sujo ou devagar e bem feito. Como disse o Uncle Bob recentemente sujo nunca é rápido então você opta pelo caminho com mais qualidade (e mais ético).
Como desenvolvedores profissionais escrevem testes (e gerar você deve começar por aí. Você sabe muito pouco sobre este sistema e o teste vai te dar alguma garantia que a menos esta pequena parta que está mexendo vai continuar funcionando após suas modificações. Vamos lá:
class TestVenda extends TestCase{
public void testDeveAplicarDescontoSeSexoDoCompradorForMasculino(){
B vendaParaUmHomem = new B(15, 100);
assertEquals("Valor final sofreu 15% de desconto", 85, vndaParaUmHomem.d());
}
public void testDeveNaoAplicarQualquerDescontoSeVendaNaoCaiEmNenhumaPromocao(){
B vendaParaUmHomem = new B(9999, 1);
assertEquals("Valor final intacto", 1, vndaParaUmHomem.d());
}
}
Os testes executam. Agora vamos alterar um pouco esta classe, pensando no pobre coitado que for mexer nela após você. Vamos começar agregando nomes mais expressivos:
abstract class VendaAbstrata{
public abstract int vender(){
}
}
class Venda extends VendaAbstrata{
static final int NAO_INFORMADO = -1;
static final int MASCULINO = 15;
static final int FEMININO = 22;
int sexoDoComprador= NAO_INFORMADO;
int valorDaCompra=-1;
public B(int sexoDoComprador, int valorDaCompra){
this.sexoDoComprador=sexoDoComprador;
this.valorDaCompra=valorDaCompra;
}
public int vender(){
if(sexoDoComprador==MASCULINO) return valorDaCompra - valorDaCompra* 0.15;
esle return valorDaCompra;
}
}
Já está bem melhor, não? Compare com a primeira versão do código Os testes passam? Então é hora de commitar (eu acho esse neologismo horrível mas alguém sugere algo melhor?).
Vamos para o segundo round: pequeno refactoring. Já é possível fazer a alteração neste código mas anda temos tempo para deixá-lo um pouquinho mais legível, mais claro, mais expressivo. Vamos alterar:
abstract class VendaAbstrata{
public abstract int vender(){
}
}
class Venda extends VendaAbstrata{
static final int NAO_INFORMADO = -1;
static final int MASCULINO = 15;
static final int FEMININO = 22;
int sexoDoComprador= NAO_INFORMADO;
int valorDaCompra=-1;
public B(int sexoDoComprador, int valorDaCompra){
this.sexoDoComprador=sexoDoComprador;
this.valorDaCompra=valorDaCompra;
}
public int vender(){
int valorFinalDaCompra = aplicarDescontosSobreValorDaCompra();
return valorFinalDaCompra;
public int aplicarDescontosSobreValorDaCompra(){
int valorComDesconto= valorDaCompra;
if(sexoDoComprador==MASCULINO)
valorComDesconto = descontarPorcentagem(15, valorDaCompra);
return valorComDesconto;
}
public int descontarPorcentagem(int porcentagem, int valorOriginal){
return valorOriginal * (porcentagem / 100.0);
}
}
Agora que tal esta versão do código + teste unitário contra a versão antiga + trezentos documentos e especificações? A implementação da regra nova ficou fácil? Acho que sim, tanto que deixo como exercício ao leitor, bem como algumas dezenas de refactorings que vão deixar o código acima decente.
A resposta curta para a thread do GUJ é: geralmente o problema não é seu mas de quem escreveu o código.
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
-Martin Fowler, “Refactoring: Improving the Design of Existing Code “
Usando Netbeans Para Editar Código Ruby? Ainda não…
Sunday, December 9th, 2007Essa semana no trabalho resolvemos (meu par e eu) ceder aos outros 3 pares que trabalham conosco (a rotação de pares infelizmente é baixa por alguns critérios internos) e tentar usar o Netbeans para editar Ruby (ninguém na equipe ou na empresa sonha em usar esta ferramenta para Java). Eu já havia conversado com um pessoal no escritório da TW sobre isso e me pareceu bom dar uma chance.
O Eclipse RDT era nossa ferramenta mas desde que a Aptana “comprou” (usando o antigo vocabulário do Marc Fleury, que Zahl o tenha) o projeto usá-lo é um problema só. Ninguém morre de usar mas dá raiva.
Então vamos lá. Um download gigantesco (normal para as IDEs inchadas de hoje em dia…) e temos o bicho rodando. A versão mais recente, claro. Ops, JVM capotou na primeira tentativa, vamos tentar de novo. Ok, funcionou.
Quase uma semana usando a ferramenta eu posso dizer que o editor para Ruby está muito melhor que qualquer versão do RDT. O code complete, syntax highlight, tudo muito bem. Aí você começa a ter os problemas quando sai do editor (afinal, uma IDE é um ambiente integrado, certo?). A integração com SVN é uma piada, é m parto fazer checkouts e commitar coisas. Os diffs e logs são bem burrinhos. A navegação entre abas e entre arquivos é custosa e muitas vezes não funciona (me parece que você só consegue transitar entre os X últimos arquivos que mexeu). Criar uma source folder para Ruby? Isso não faz sentido. Em Ruby geralmente tudo é código-fonte, da sua task rake até a configuração do banco de dados. Os atalhos de teclado são razoáveis, você só precisa se dar conta que está numa espécie de mundo bizarro do Eclipse, os atalhos são a mesma coisa só que com ALT em vez de CTRL ou coisa assim (para quem fez a migração pra Mac isso não é novidade).
Minha conclusão final é que o editor do Netbeans para Ruby (ao contrário de para Java) é infinitamente superior ao do Eclipse RDT. O problema é que não só o editor faz a IDE, se for para não er o ambiente integrado eu prefiro usar emacs. Acho que dados os pontos fracos de cada um tanto faz ficar com Eclipse ou Netbeans. Eu não ficaria com nenhum.
No Mac eu uso o maravilhoso Textmate. No Windows e Linux eu passei algumas semanas brincando com o OpenKomodo e ele é muito bom, traz os benefícios do Textmate para o ‘PC’ (hoje em dia tudo é PC mas vocês entenderam…)
Modelo de Negócios e Tecnologia
Sunday, December 2nd, 2007Há alguns anos eu trabalhava para uma grande empresa que cria produtos em um nicho muito específico. Dá última vez que eu vi alguém fazer uma estatística 90% dos produtos eram em C, 5% em C++ (”muito lenta”) e o restante em PERL, Python e Java.
A coisa que eu mais gostava sobre essa empresa era como o modelo de negócios deles era movido por inovação. Quando alguém tinha uma boa idéia ele era convidado a montar um protótipo em laboratório que seria oferecido à clientes. Haviam muitos ganhos para os bem-sucedidos, meu chefe, diretor regional de tecnologia, subiu ao seu cargo após duas idéias convertidas em produto (além de ganhar uma boa grana).
No entanto, apesar da inovação presente nos novos produtos lançados simplesmente não havia inovação técnica. Não importa o software, tudo era feito em C. Eu fui contratado para um novo time que cuidava das alicações Java. Estas aplicações só foram criadas porque os clientes exigiam interfaces web e RMI para os produtos da empresa e porque contratar programadores C sempre foi um problema. Mesmo trabalhando basicamente com Java (e naquela época o sonho de todo mundo era arrumar um emprego “100% Java, nada de PHP ou VB”) boa parte do meu trabalho era escrever e testar interfaces em C que se comunicavam com o sistema “de verdade” (o feito em C).
Certa vez me mandaram por 10 dias, que viraram 20, numa viagem de trabalho. O lugar não era muito amigável com turistas então passei boa parte do tempo no quarto de hotel tentando entender a televisão. Como não tinha Internet liberada eu passava no dia baixando PDs e páginas completas para ler à noite e nos fins-de-semana. Com o tempo pensei: e se eu reconstruisse o sistema em Java? Obviamente que não consegui reproduzir o sistema todo dado o tempo mas se o sistema antigo tinha 5% em Java eu consegui que fosse unas bons 30%. Chegue no escritório doido para mostrar ao meu chefe.
Obviamente foi um banho de água fria. A pessoa ficou feliz por eu me interessar pelos projetos internos e disse que iria ver o sistema, um dia. Esse dia nunca chegou. Após alguns meses eu pedi demissão da empresa.
Dia desses estava falando com um amigo que ainda trabalha lá e soube que 50% dos clientes foram embora. Na época que eu trabalhava nessa empresa ela tinha quase que o monopólio de um dado tipo de sistema, com tempo concorrentes foram surgindo. O sistema da empresa era claramente superior aos outros mas era muito menos flexível. Ele era muito bom no que fazia mas quando precisávamos que ele fizesse a coisa um pouquinho diferente o projeto durava meses. Os concorrentes chegaram com linguagens como C++ e Java e apesar de não terem um produto com 10 anos de bons serviços prestados eles conseguiam mudar rapidamente.
Há dez anos a escolha por utilizar C e IPC de UNIX na mãozona era certa. Nenhuma plataforma da época oferecia o desempenho aceitável. Infelizmente as pessoas acabam construindo as piores coisas do mundo com desculpa de performance e o sistema era completamente monolítico e depende tanto do SO que mudar de uma versão minor para a outra leva um ano com um time de 3 pessoas completamente dedicados.
Se esta empresa acompanhasse os movimentos da indústria veria que existiam plataformas que já ofereceriam performance aceitável (eu já trabalhei em sistemas Java mais eficientes que aquele em ouros lugares) e que iriam oferecer a flexibilidade necessária. Infelizmente só repararam isso quando a concorrência invadiu o mercado.
A empresa continua com produtos ótimos em suas idéias mas ninguém consegue esperar 2 anos para colocar algo no ar. As coisas mudaram e escolher a tecnologia certa para cada caso é cada vez mais o qe define sucesso ou fracasso de um projeto. Ou de uma empresa.
Programadores Profissionais Escrevem Testes, Ponto Final.
Wednesday, October 31st, 2007O tópico já tem oito páginas. Acho que chega à 10. Por mais que minha mão coce para comentar lá eu não vou, simplesmente porque já tive problemas demais com o pessoal do Mentawai.
De qualquer forma sempre me preocupa a possibilidade de algum desenvolvedor ler o tópico e pensar “Poxa, se esses caras que fazem todos estes frameworks não usam testes por que eu vou usar?”.
Desenvolvedores profissionais escrevem testes. Simples assim.
Uma pessoa que não ganha milhões de dólares mas escreveu uma das obras mais clássicas deste ramo deixa bem claro em sua primeira aula que programar é gerenciar complexidade. Nós precisamos gerenciar complexidade o tempo todo, por isso criamos funções, objetos e tudo mais. Não adianta, mesmo Einstein teve que provar que suas fórmulas e execuções estavam corretas, que poderiam ser verificadas. Na faculdade aprende-se isso desde as cadeiras básicas (e o fato de ser esquecido como “coisa teórica inútil” me faz novamente perguntar sobre o valor do ensino formal).
Existe uma grande diferença entre fazer Test-Driven Development e testar. TDD é sobre modelagem de objetos e especificações, não sobre testes (tanto que Behaviour Driven Development está se consolidando como algo mais eficiente que TDD) apesar de que no final você acaba ganhando uma suíte de testes de graça.
É muito difícil achar um projeto open-source relevante que não tenha testes. Na verdade os projetos decentes só aceitam um relatório de bug ou um patch se vier acompanhando por um caso de testes. Imagine uma aplicação feita colaborativamente por diversas pessoas, como saber que o que eu acabei de fazer commit não vai quebrar o que você modificou ontem? Boas práticas de orientação a Objetos? Não se iludam, OO não foi feita para este tipo de verificação! Com boas práticas você consegue minimizar o impacto de mudanças diminuindo dependências mas você não vai ter certeza disso.
Eu sinceramente não sei que técnica é essa que faz programação defensiva evitar testes. Eu já li bastante sobre Orientação a Objetos e programação defensiva e não vi nada deste tipo, pelo menos não vindo de uma fonte com um mínimo de credibilidade. Um exemplo simples, imagine que o framework web imaginário Pagai possui um código parecido com este:
Acao acaoSendoExecutada = controladorPrincipal.acao(requisicao.acaoDesejada());
Simples, não? Agora imaginemos que o código do método acao(String) seja algo assim:
public Acao acao(String pathInvocado){
//verifica se acao possui o formato desejado, deve ter uma barra e deve ter dois itens separados por barra apenas
if((pathInvocado.indexOf("/") == -1) || (pathInvocado.split("/").size < 2)) throw new IllegalArgumentException("Path invocado ["+pathInvocado+"] nao possui o formato adequado (consulte a documentacao XYZ)");
//lógica...
}
Isso é programação defensiva: eu não estou aceitando o que me passam, eu verifico se é o que deveria e se for eu continuo, se não eu paro ali mesmo e deixo alguém tomar conta do problema, seja a classe em questão ou alguma outra mais acima.
Imagine que eu por engano commitei um código que utilize “” em vez de “/” nesta requisição. Se for numa parte central do código é bem possível que uns testezinhos peguem mas imagine que é utilizado apenas em um caso específico e que, por um acaso, eu baseei meu sistema de controle de jatinhos particulares 9meu chefe tem muitos jatinhos) nele. Quando eu fiz o comit não alertou. Quando eu fiz o build não alertou. Quando eu fiz meus testezinhos não alertou. Quando foi para a produção eu tive erro.
Ok, acontece. Programadores de qualquer tipo cometem erros. Eu vejo o problema muito rapidamente e o corrijo, temos uma versão beta em 15 minutos no ar, fantástico. Aí daqui há um mês outro programador comete o mesmo erro. Quando fizer o build não vai alertar. Quando fizer seus testezinhos não vai alertar. Quando for para a produção… Isso não é profissionalismo.
O que eu preciso é de uma suite de testes, unitários e de integração, que me digam que o sistema está incorreto já no processo de build, sem lançar jars beta, alfa ou gama.
Mas se tem um argumento nessa história toda que realmente me irrita é quando as pessoas dizem que “num mundo capitalizado não há tempo para testes” ou que “o cliente não quer saber como é feito, ele quer que funcione”. O cliente realmente não quer saber como funciona, ele quer que funcione. Mas ele também não vai querer saber que você alterou uma classe que usava barra para barra invertida e tudo parou de funcionar, ele quer que o problema não aconteça e se acontecer que seja corrigido rapidamente. Se seu sistema não tem qualidade -e testes fazem parte de qualidade- você não consegue isso. TI gasta fortuna das empresas reescrevendo sistemas simplesmente porque não foram feitos por profissionais, e profissionais se preocupam com a qualidade do que fazem. E isso inclui testes.
Não seja um amador.
Arquiteturas Simples Duram Mais
Wednesday, October 24th, 2007Um amigo outro dia me perguntou que tipo de arquitetura eu usaria num caso bem peculiar. Basicamente ele foi encarregado de definir a arquitetura corporativa de um grande banco, ou seja: definir hoje a forma como aplicações serão construídas pelas próximas décadas. Basicamente ele vai se ro cara que vai ser xingado por algumas centenas de programadores nos próximos tempos, não importa que arquitetura escolha.
Há poucos dias atrás falamos aqui sobre arquiteturas de referência e seu efeito danoso. Geralmente quando alguém tem à frente um desafio desse ele logo pensa em um modelinho que mostra obriga o uso de uma meia dúzia de frameworks e padrões (clássico moderno: Struts/JSF e JPA, clássico vintage: Struts 1.1 e EJB/DAO). Para melhorar ainda é incorporado um conjunto de classes “utilitárias” feitas com práticas que talvez tenham servido para um projetinho piloto mas hoje em dia só atrapalham.
Ainda assim uma arquitetura corporativa é algo interessante. Quando empresas grandes não possuem uma macro-arquitetura acabam crescendo de maneira desordenada e criando dezenas de aplicações redundantes e gambiarras de integração entre sistemas. Note no entanto que uma arquitetura corporativa não é uma arquitetura de referência, a arquitetura corporativa não fala sobre como implementar aplicações mas sim provê guias sobre como integrá-las, define as relações previstas em no ecossistema que é uma grande empresa.
Quais são as melhores macro-arquiteturas que você conhece? Eu consigo pensar em algumas: Apache, UNIX, World Wide Web… Nestes ecossistemas aplicações novas surgem, são alteradas e morrem todos os dias há décadas, um sistema criado com a tecnologia mais recente de 2007 vai rodar tranqüilamente neste ambiente. Por quê?
Porque estas arquiteturas se baseiam em primitivas e contratos, não em especificações rígidas. Criar um módulo para o Apache , um programa para rodar em UNIX ou uma site é basicamente criar um programa de computador em uma das plataformas suportadas que obedeça a um contrato.
Uma boa arquitetura corporativa vai definir algumas políticas e contratos para a aplicação se relacionar com o meio-ambiente e só isso. No caso do banco, poderíamos definir que uma aplicação deve disponibilizar via uma interface POX/REST seus WebServices, que ela deve utilizar a API do Mogile FS para guardar dados em disco, que cache deve ser feito utilizando a API do memcached.
E se o arquiteto quiser sair do padrão? Ótimo, saia, mas ele deve oferecer compatibilidade com o ambiente.
E se eu já tiver comprado um sistema que faz WebServices via SOAP? Eu preciso criar um meio de disponibilizar estes serviços via POX/REST também. Pode ser uma adaptador simples, um ESB, o que quer que seja. É como quando você compra um equipamento eletrônico com tomada americana, você não vai mudar uma tomada na sua casa para o padrão exótico, vai é comprar o adaptador necessário para plugar ele nas tomadas do seu ambiente.
Mas e se não precisarmos de filesystem distribuído? E se já estivermos utilizando uma solução de cache que faz mais sentido nesta aplicação?
Ótimo, use. O uso de filesystem X, cache Y, banco de dados Z deve ser um guia. Toda vez que alguém precisar de uma solução de cache, filesystem, etc. ele olha o guia da empresa, se não servir ele usa algo que sirva. O que importa é que o uso fique encapsulado no sistema. Imagine que ao invés do Oracle 10g eu resolva usar um MySQL na minha aplicação. Está ótimo mas eu devo manter essa peculiaridade interna à minha aplicação. Os outros sistemas que vierem a se comunicar com o meu não devem precisar saber sobre a existência deste banco, eu não posso usar este banco para comunicação entre aplicações (o que já é uma coisa péssima para se fazer de qualquer forma).
O que importa é:
- O arquiteto tem liberdade para resolver seu problema da maneira mais adequada
- O novo sistema é compatível com o meio-ambiente
Para ser um bom arquiteto não é necessário ter tanta experiência assim, basta saber olhar os casos de sucesso e aproveitar o que funciona. Geralmente as técnicas utilizadas nestas arquiteturas são também catalogadas como Padrões Arquiteturais em livros. Um bom arquiteto tem que ser um ávido leitor de livros e de código.
Conexão Java 2007
Tuesday, October 23rd, 2007Mais um ano vai, outro ano vem e o Conexão Java está aí. Este é certamente o evento mais descolado da comunidade Java do Brasil.
O CJ é um grande encontro entre as pessoas que participam em fóruns como o GUJ, o PortalJava e o RioJUG. O foco do evento são os mini-cursos que agem na formação de novos profissionais. Bem, formação não exatamente, ninguém sai de um curso de meioa dúzia de horas especialista em nada mas é uma boa oportunidade de ter contato mão-na-massa com algumas tecnologias e técnicas.
Este ano a estrela do evento é ninguém menos que Carlos Villela. Radicado em Londres pela ThoughtWorks há… bem, há alguns anos… o cv vem falar de algo bem atual: o declínio dos arquitetos monoglotas.
Também teremos algo um pouco diferente. Possivelmente deve haver um repeteco da minha palestra sobre arquitetura do JustJava 2007 (infelizmente sem o Paulo que vai estar de férias) mas enquanto isso é confirmado ficamos com mais uma atração: Oficina do Arquiteto.
Essa é uma idéia meio maluca que acabamos de fechar, vai funcionar mais ou menos assim: alguém traz uma arquitetura -seja de um projeto existente, livre ou de uma empresa, ou desenhado na hora- e nós debatemos esta. Na conversa vão sobrar padrões arquiteturais, guidelines e uma boa dose de bate-papo sobre o que nós, arquitetos, estamos fazendo por aí. Se você já tiver alguma idéia me adiante por email para organizar melhor as coisas, eu vou preparar algumas arquiteturas clássicas para usarmos quando não houver nenhuma na roda. A idéia é bem simples: debate, informação e diversão.



