quinta-feira, dezembro 28, 2006

Swing, ame-o ou deixe-o. Não concordo.

Lendo Swing vs. SWT, do Amin Ahmad fiquei bastante indignado com o ponto de vista dele. Na prática, o artigo dele é um contra-ponto (bastante forte) sobre o artigo SWT Happens. Amin parece defender o SWT com unhas e dentes. Mr Ed, parece ser mais pragmático.
Pelo que minha pequena mente percebe, o sr. Amin faz uma comparação entre o Swing e o framework do Eclipse. Daí é Davi contra Golias e isso não serve.
Comparar uma API contra um framework não tem sentido algum. O Swing é uma ótima API MVC, com recursos escaláveis, flexíveis, robusta, estável e com bom (ainda não ótimo) suporte para look and feel. Tem mais coisas, mas isso basta. O SWT é uma contrapartida da IBM que objetiva maior facilidade de desenvolvimento (e por isso seu modelo MVC não é completo), performance mais elevada e comportamento nativo. Na prática, até que me provem o contrário, o SWT é o seguinte: se o controle existe no Sistema Operacional, então o SWT usa ele (tal como o AWT faz o conceito de peered controls); se o controle não existe no SO, então o SWT renderiza ele totalmente (via API 2D) na forma mais parecida com o controle nativo. É do comportamento peered do SWT que surge a necessidade de uma DLL no Windows ou uma SO no Linux para seu funcionamento.
O Swing renderiza tudo sempre. E por isso dizem que ele é mais lento. Mas nem tanto (e tenho dúvidas, às vezes). Bom isso é outra discussão.
Quanto ao artigo, não é possível comparar a API do Swing com um JFace, nem a java.util.prefs com o Preferences Framework do Eclipse. Isso é ridículo.
Concordo que a comunidade Swing carece de uma integração (que deve vir por parte da Sun) para construção de um framework de mais alto nível, com suporte a coisas simples, como construção de Wizards, janelas arrastáveis, agendamento de tarefas e outras coisas mais; todas prontas no framework Eclipse. Entretanto, isso não faz parte do Swing e, portanto, não pode ser comparado.
Acredito que o advento do Eclipse (foi em 2001, isso?) foi como graxa na engrenagem para quem usa Swing. A Sun apostou muito na Web, com as JSPs (e toda a tralha de JSRs associadas) e no Java como middleware, com os EJBs. Nesse cenário, o Swing ficou em segundo plano, apenas na correção de bugs.
Agora com o Java 6 o Swing ganhou algumas melhorias, como o suporte à famosa barra de tarefas. Mas foi só.
O pessoal do Netbeans tá se puxando com o desenvolvimento de soluções de alto nível, tal como existe no Eclipse, mas ainda não está perto, infelizmente. O suporte ao arraste de janelas, padronização de operações, suporte a plugins e a estruturação geral do projeto ainda é bem melhor no Eclipse que no Netbeans.
Mas a engrenagem está girando e agora com ela azeitada, as coisas devem seguir bem mais rápido.
Espero sinceramente que surja logo algo como o Eclipse Framework para o Swing. Nada de coisas como o Jide, o InfoNode ou o rudimentar FlexDoc, mas sim uma coisa prática, fácil de usar e disponível no próprio JDK. Talvez tenhamos que esperar uma JSR, mas isso demora.
Termino dizendo que o sr. Amin foi infeliz no artigo que escreveu e que, embora o Swing tenha limitações, podemos estendê-lo com outros produtos e, daí sim, compará-lo de igual para igual com o Eclipse.

quarta-feira, dezembro 13, 2006

Pontes e Cadastros

Cadastros não são pontes, mas adorariam ser. Pontes nunca, mas nunca gostariam de ser cadastros.

Cadastros são flexíveis, podem ser gerados automaticamente, possuem look & feel, podem ser multiplataforma e mesmo conectar em variados banco de dados.
Pontes são fixas, nascem e morrem no mesmo lugar.
Cadastros podem ser validadados, existem alguns simples, outros complexos e outros muito mais complexos ainda. Não obstante, existem mestre-detalhe, mestre-detalhe hierárquicos, multi-modais e até multi-modais paralelos (progamadores, cuidem os deadlocks!).
Pontes se resumem a isso: peso, altura e largura suportadas.
Cadastros evoluem. A cada versão do software eles podem adicionar recursos, reconsiderar comportamentos, mudar a ordem de tabulação, valores default, teclas de atalho (páro aqui). Podem corrigir erros, aumentar a performance, mudar elementos de interface, mudar conteúdo de elementos e ter inúmeras funcionalidades dispersas em lindos botõezinhos pelos arredores da tela.
Pontes sempre funcionam da mesma maneira: entramos num lado e saimos no outro.
Cadastros podem ter cores variadas, efeitos, gradientes, figuras, sons multimídia e qualquer conteúdo embedded (Flash é "da hora, mano"!).
Pontes, não muito além, são cor de cimento. E só.
Cadastros são construídos por fervorosas sessões de brainstorming, reuniões confusas, entrevoltos em atas, diagramas interacionais, navegacionais, estruturais, etc. Dão ênfase aos argumentos dos analistas, ao choro de projetistas, à alegria dos usuários e à penitência de programadores. Não sem histórico, são vistos como exuberantes consumidores de tempo e dinheiro. E de fato, o são.
Pontes são construídas com base na necessidade: fixa ou não; coberta ou não. E só.

Eu poderia elencar mais uma série de diferenças que, grosso modo, dizem o seguinte: cadastros são graciosos e podem funcionar; pontes são inertes e funcionam. E porque será que uma ponte não gostaria de ser um cadastro?

Pontes não querem ser cadastros
Pontes não querem ser cadastros porque, enquanto os cadastros são balizados pelos adjetivos, as pontes são norteadas por objetivos. E termina aqui a história.
Uma ponte serve para passar de um lado para outro. E pronto. Um cadastro serve para ver e modificar dados. E pronto também, ora essas!

E porque as pontes funcionam e os cadastros simplesmente gostariam de funcionar? Não vou menosprezar nossa classe dizendo que as pontes funcionam porque são feitas por engenheiros; isso porque nós informatas, também conhecemos (ou deveríamos conhecer) Cálculo, Integrais e Derivadas (poderia até argumentar em nosso favor, dizendo que somos nós que construímos os programas que os engenheiros utilizam, mas isso não resolve problema, apenas aquece a discussão).

Pontes não querem ser cadastros por elas têm vantagens:

1. Usuários não reclamam de pontes; de cadastros, todos têm o que falar.
2. Pontes têm vida útil expressa; cadastros sempre podem ser ajustados.
3. Pontes que não funcionam são implodidas; os cadastros são alterados.
4. Pontes que não suportam o peso (ou largura ou altura) recebem uma placa de limite máximo; cadastros são alterados.
5. Pontes têm comprimento fixo; cadastros podem ser redimensionados (aleluia aos gerenciadores de layout e ao saco dos programadores!)

...e a lista segue...

Lógico. Lógico?
Mas que raio de coisa é essa que cada vez mais que eu comparo uma ponte com um cadastro, uma ponte fica parecendo uma coisa tão tosca e mesmo assim não posso dizer que um cadastro é melhor que uma ponte? Um cadastro faz maravilhas, uma ponte não faz nada de mais além de permitir que eu atravesse de um lado para o outro! Porque uma ponte não quer ser um cadastro? Talvez porque tenhamos um círculo vicioso...

O Fim, o Começo e o Ciclo
Pontes são seletas: o usuário deve ser assim, se não for eu não aceito (em suma, tome meia-volta e vai procurar outra ponte, seu ignóbil). Cadastros não submissos, não escolhem o usuário, simplesmente o suportam.

PAUSA PARA O CAFÉ
O Engenheiro valida uma ponte em prancheta, no Design, via cálculo. Ele não coloca um cargueiro sobre uma ponte para testar se ela aguenta o peso. Ele coloca sim, uma placa avisando a tonelagem máxima.
O Informata especifica um conteúdo válido, mas não garante nada para o cadastro. Ele enche de validadores a sua tela e cruza os dedos esperando que a sequência de Murphi não ocorra enquanto ele for o responsável pelo bendito artefato.


Talvez por esse fim inglório é que os cadastros não funcionem (e consequentemente o porquê das pontes serem pontes mesmo). Não sei quem disse que tem que ser assim (na verdade eu sei, foi n-íade {cliente, vendedor, gerente disso, gerente daquilo, gerente daquilo outro, projetista, programador, analista...}, mas não posso dizer...), mas o fato é que é assim e pronto. Esse é o Fim.

E por esse fim tristonho é que, de tão flexível, robusto, etc. (olha os adjetivos aí gente!) é que um cadastro queria ser uma ponte, mas não vice-versa. Sendo ponte, ele seria simples e funcional (e óbvio, seu nome não seria Cadastro, seria Ponte). Por que não exibir cod_cliente ao invés de "Código do cliente" e pronto? Ah, claro! Fosse assim, não seria um cadastro, seria uma ponte!

Engenheiros (mesmo) são como advogados: é assim, o preço é esse e assino em baixo "se e somente se". Informatas são promíscuos, gananciosos... (vou procurar no Aurélio se Informática e termos correlatos não possuem algo como: Veja também > Adjetivo) garantem que tudo vai funcionar. Não poderiam ser humildes (esse adjetivo é bom, me lembra o Scott Ambler) e dizer: olha isso não pode ser assim (entenda-se, vou estudar mais) e eu não vou fazer (entenda-se, não sou ganancioso). Ou você acha que um engenheiro assinaria o projeto de uma ponte se não tivesse plena certeza (em outras palavras, matematicamente correto - e não simplesmente porque compilou...) do que ela faz e, principalmente, do que ela não faz? Isso é o Começo.

Finalmente, os engenheiros fazem pontes e aprendem com os projetos que não funcionam. Os informatas dizem que aprendem. E esse é o Ciclo.

Enfim, vou ser humilde (adjetivos, agrh!) e dizer que não sei a resposta porque os cadastros podem ser tão bonitos (e dá-lhe adjetivos!) e mesmo assim, as quase-feias e inflexíveis pontes não querem como eles.

sábado, dezembro 02, 2006

Projeto de Interfaces : A Relevância em Contexto

Hoje, iniciei um novo projeto. Nas apresentações iniciais para formação da equipe de trabalho, eu e um dos analistas discutíamos ferrenhamente quanto ao uso do Hibernate em aplicações OO: eu favorável, ele contrário.
Seu argumento era que o Hibernate trazia dados desnecessários na grande maioria das vezes, além de não ter a capacidade de fazer operações rowset. Deu um exemplo de cadastro (eu adoro esses exemplos!). Deixei ele falar:

"Nos sistemas OO, geralmente uma tela de cadastro tem relação 1-1 com um objeto de dado (javabean, por exemplo). Assim, quando esse objeto for muito grande e tiver muitas dependências, seu carregamento é demorado, mesmo sendo um objeto só. Veja por exemplo um objetão (palavras dele) com vários relacionamentos n-1 que geram combos. Suponha que essa foreignkey aponte para uma tabela com 1 milhão de registros (sempre usam esse número). Quando o cadastro for exibido, só essa combo demorará vários segundos para ser preenchida. Isso sem contar as outras dependências, que podem ser 1-n e até n-n. Eu prefiro SQL, é muito mais rápido. [E continuou, enquanto seu café esfriava...]

Argumentei várias coisas em favor do Hibernate, como consultas nomeadas, mapeamento explícito, códigos personalizados e, claro, SQL nativo em certos casos. Ele franziu a testa e continuava duvidando, dizendo que seu histórico com tudo isso não era nada agradável...

Foi então que me ocorreu de falar que, de fato, o problema que ele tanto comentava não era o Hibernate, mas sim algo muito anterior a ele. O problema estava no projeto da interface do usuário. Ele fez uma cara estranha, os outros dois analistas puxaram suas cadeiras mais para perto e ele tomou aquele café gelado num gole só. Talvez louco para saber a besteira que eu estava prestes a falar...

Interfaces lentas: a origem do problema
Era sim um problema de interface de usuário, disse eu. Você pode ter um (e na maioria das vezes terá) um objeto associado a uma tela de cadastro, isso até facilita a implementação de patterns, como o Memento e outras coisas, como relações um-para-um entre propriedades e controles, etc. E isso não implica necessariamente em degradação de performance usando o Hibernate. O que você precisa é construir uma interface baseada em contexto de uso, tendo precisa noção da carga de dados realmente necessária para essa interface [gostei da cara dele e dos analistas quando falei isso]. Ele pediu 2 minutos para buscar outro café enquanto um dos analistas encheu um chimarrão nesse meio tempo.

Tentei dar um exemplo simples, e esse mesmo exemplo vou mostrar aqui.

Relevância em contexto
Imagine uma tela bem simples, com uma caixa de seleção (combobox) apenas. Nessa tela, o objetivo do usuário é escolher um entregador de mercadorias e, a partir dessa seleção saber quais são os seus pontos de entrega. Esses pontos de entrega são mostrados em uma listagem, que está logo abaixo, como na figura ao lado:
Aqui, eu disse a ele, está um exemplo do que tu falou: Uma tela que pode ser extremamente lenta, caso muitos registros de entregadores existam (por exemplo, uma empresa internacional que mostre todos os entregadores cadastrados no mundo todo - desculpem, mas foi isso que me veio à mente na hora). Quando essa tela for chamada, provavelmente ela vai demorar alguns bons segundos para carregar. Ele concordou avidamente.
Disse a ele: Aqui está um erro de interface, porque você está carregando muitos registros na combo que, mesmo ordenados, vão ser de difícil manuseio, porque a barra de rolagem fica muito reduzida (item 1 na figura) e, principalmente, porque a maioria dos registros será inútil. Inútil porque o usuário vai escolher somente um deles. Assim, se você tiver 1 milhão de registros, a taxa de acerto da interface para esse controle é de 0,0001% (1 interação de usuário x 1 registro escolhido x 1 milhão de registros na listagem). Continuei.
Como vê, não é o Hibernate que está errado, mas o programador que fez a tela e, antes que ele, o projetista que não especificou como essa caixa de seleção deveria ser carregada.

Melhorando o desempenho
Seria de bom grado se nessa caixa de seleção estivessem presente somentes os registros com maiores possibilidades de serem escolhidos pelo usuário. Ele concordou (os analistas também). Nesse sentido, como no item 1 da figura 2, poderiam ser exibidos na caixa de seleção somente os entregadores vinculados à filial onde o sistema está instalado (uma regra de negócio). Também poderia ser provido um valor padrão (com combo carregada durante sua expansão ao clique do usuário - e mesmo em uma thread auxiliar). Outra alternativa ainda seria o analista ter definido um valor padrão inicial fixo junto ao usuário - item 2 da figura 2. Tudo isso são coisas que os analistas poderiam identificar e propor antecipadamente. São opções inicais boas e simples, disse eu, que melhorariam a taxa de acerto para algo entre 0,2% (1 para ~500 itens na combo) e 15% (considerando um elemento padrão com 10% de corerência e sendo generoso ao admitir que o usuário pode digitar 1 caractere inicial e ter uma faixa de 20 elementos para pesquisar - claro, considerando uma distribuição uniforme dos 500 nomes nas 26 letras do alfabeto ocidental) - uma melhora de 15.000% na taxa de acerto e uma redução de carga de 2000x no BD. Nesse momento, ganhei o público, mas os analistas não gostaram muito de saber que eles poderiam ser culpados da demora na tela (...)

Melhorando um pouco mais o desempenho
Como eu tinha conquistado a atenção, continuei. A interface poderia ser melhorada caso fosse colocado em evidência o contexto do usuário. Além do valor padrão e da exibição dos entregadores vinculados à filial, poderiam ser os elementos da seleção restringidos pelo perfil do usuário em conjunto com seu contexto de uso. Restringir pelo perfil do usuário é simples, marcando os registros selecionados ao longo do tempo e armazenando-os em um cache de segundo ou terceiro níveis (item 3, figura 3). Isso é facilmente implementado por uma LRU (Last Recently Used) em memória, não com objetos nativos do banco (javabeans), mas DTOs (Data Transfer Objects), que são comuns em ambientes enterprise (item 3, figura 1). Outra alternativa, seria utilizar uma LFU (Last Frequently Used) em memória, que marcaria os registros com maior propabilidade de acerto considerando uma média de acerto durante o tempo, e não os últimos utilizados. Mesclar essas duas opções para formar o elemento padrão poderia ser outra tentativa para minimizar o trabalho do usuário.

Quando esses recursos são utilizados, é necessário permitir ao usuário a seleção do restante dos registros, coisa simples de fazer ao providenciar um elemento como "Exibir todos..." (item 2, figura 2), que retornaria o restante dos registros. Mesmo nessa busca, outro cache LRU (ou LFU) poderiam ser utilizados, sendo a ordenação baseada também nesses conceitos (ordenar por LRU ou LFU ao invés de alfabeticamente). Isso tudo, além de reduzir a busca no banco à menos de - sei lá - uma centena de registros (ou mesmo a zero se os LRU e LFU forem bons), elevaria a taxa de acerto a algo superior a 50-60%, ou seja, uma interface 600x mais performática que a primeira.

Conclusões
Terminei dizendo que implementar esses recursos é legal porque a aplicação aprende com o usuário. Ela transforma-se em um ser vivo, e não apenas um monte de retângulos estáticos e coloridos na nossa frente.
Como consequência (não uso trema porque meu teclado é US, sorry), o Hibernate tem menos objetos para carregar e os problemas de tempo de carga simplesmente não ocorrem. Em outras palavras deixamos de perder tempo para resolvê-lo-os para ganhamos tempo (a) evitando-os e (b) dando ao usuário um sistema mais proativo.

Os dois analistas pareciam meio perturbados com o que eu falei. O terceiro, que tinha puxado o assunto, acabara de voltar do limbo para perceber que, novamente, seu café estava frio. Quando à mim, bem, pedi um chimas pro colega da frente, uma vez a nossa cuia estava gelada, idem...

quinta-feira, novembro 30, 2006

Dependências entre Controles : Parte 1

Este é o primeiro de uma série de três posts, nos quais eu falarei sobre dependência de controles nas telas de cadastro.
Nessa colocação inicial, darei uma visão geral do problema e como ele é resolvido no braço. No segundo, vou mostrar como alguns frameworks encaram essa situação. No terceiro e último, é apresentada a proposta do Merlin. Depois de lerem, não hesitem em dar suas opiniões e sugestões.

NOTA: A dependência de controles envolve muitos tipos de elementos de interface (como caixas de texto, seleção, marcação, textos estáticos, etc.) e por isso, para ser mais objetivo, vou tratar de dependências entre caixas de seleção, ou comboboxes. Escolhi elas por dois motivos: primeiro, porque representam elementos de complexidade intermediária se comparados com outros objetos existentes na interface do usuário e, segundo, porque elas a estão há tempo pipocando na minha cabeça, pedindo para serem armazenados em um meio durável, hehehe.

Dependência entre controles, um exemplo
No projeto de formulários, é dito que existe uma dependência entre controles quando o conteúdo ou o estado de um (ou mais) controle(s) depende do conteúdo ou estado de outro(s) controle(s). Essa é uma definição que eu criei, porque não lembro de ter visto algo melhor nos livros que já li.
Para ficar mais claro, veja essa figura:

Essa tela representa o cadastro de uma pessoa,
a qual mora em uma cidade que, por sua vez, pertence a um estado (ou Unidade Federativa - UF). Aqui, o objetivo é simples: ao selecionar um estado, espera-se que a caixa de seleção das cidades exiba somente as cidades que pertencem ao estado selecionado.
Para implementar esse comportamento, a abordagem tradicional, via código, é a seguinte:
  1. Ao carregar o formulário (evento onShow, por exemplo), é carregada a caixa de seleção estado, colocando como valor padrão nenhum ou aquele mais apropriado para o usuário (tal como o projetista definiu). Esse carregamento nada mais é do que um comando de seleção de registros no banco de dados sobre a tabela de estados. A caixa de seleção da cidade está (1) ou sem nenhum dado carregado e nem selecionado ou (2) está carregada com (2.1) os estados pertencentes ao estado previamente carregado com uma cidade padrão selecionada, ou (2.1) sem nenhuma cidade padrão selecionada, ou (2.3) está carregada somente com uma cidade, que é a cidade padrão e esta está selecionada. Variações nesse modelo podem ocorrer, mas o comportamento essencial é esse.
  2. No evento onChange da caixa de seleção do estado ocorre um processamento que seleciona no banco de dados (ou em um cache local) as cidades que pertencem ao estado que acabou de ser selecionado. Dependendo do que o projetista definiu, quando isso ocorre, a caixa de seleção da cidade pode ficar com (1) um valor padrão para o estado selecionado ou (2) ficar posicionada em nenhum.
  3. Modificações na caixa de seleção da cidade não implicam em nada.
No tocante aos dados exibidos nessas caixas de seleção, observa-se os atributos mais comumente reconhecidos pelo usuário, tais como (1) para cidades, o nome e (2) para estados, a sigla ou o nome. Novamente, depende do projetista :-)

As dificuldades
Quanto à complexidade disso, o tipo de processamento a ser executado (regra de negócio) é bastante simples. Tanto que, em algumas IDEs (como o Delphi) existem controles específicos para essa funcionalidade, os quais entram em funcionamento com alguns ajustes de configuração e/ou pequenos trechos de código adicionais. Quando não existente, esse comportamento geralmente é implementado na íntegra pelo programador e reside (quando muito!) em classes utiltárias e genéricas, de forma que possa ser reutilizado quando necessário. Programadores mais avançados (e com tempo de sobra) criam códigos bastante complexos, performáticos e (duvidosamente) estáveis, os quais são empacotados em componentes da casa e reutilizados (expostos?) como obras de arte em vários sistemas. Não obstante, é comum esses componentes terem suas limitações exarcebadas somente quando muito tempo passou desde seu projeto e as consequências para manutenção acabam revindicando todo o tempo que fora "ganho" antes...
Sem considerar esses aspectos (que seguramente muitos desenvolvedores irão me questionar), existe um problema muito mais impactuante e de uma transparência tamanha que passa despercebida pela quase totalidade dos desenvolvedores: retrabalho.

Retrabalho x reuso
Reuso é o ato de utilizar novamente algo que já foi utilizado. É como aquele programador que diz: Pô, para isso eu já tenho uma classe que resolve. É só instanciar esse objeto, chamar aquele método e configurar esses parâmetros que está pronto! Isso é o reuso. E todos amam essa palavra, principalmente quando ele funciona.
Retrabalho é o que o programador acima acabou de fazer. Ele já tinha a solução pronta, mas teve que aplicá-la novamente no novo problema que surgiu.

De certo, muitos vão perguntar: Mas isso é mais do que óbvio. Toda vez que eu tenho um mesmo problema, eu "pego" a solução que já possuo e aplico ela novamente!

E eu, com minha visão pessimista, vou dizer: Isso tá muito trabalhoso ainda! Eu quero uma solução reutilizável, mas que não implique em retrabalho. Tu não tens uma?

Talvez...vamos dar uma olhada na caixa de ferramentas...
[continua]

segunda-feira, novembro 27, 2006

BabelFish Translate: Quero um botão para reverter a tradução

Não entendo muito de inglês e por isso uso frequentemente o BabelFish Translator (que eu considero melhor do que o Google, infelizmente).
Faz tempo que queria comentar isso e agora tive tempo, então lá vai...
Muitas vezes, traduzo um texto de português para inglês (ou o contrário) e o resultado, quando não "soa bem" eu tento traduzir novamente, agora na ordem inversa. Explico:

Traduzo: Texto em português para Text in portuguese. Daí traduzo Text in portuguese para Texto em português novamente. Essa frase é simples, mas muitas vezes as palavras demoram para se encaixar...e por isso faço várias traduções (em conjunto com o Babylon) até chegar a forma que considero a mais adequada.

O problema é que para fazer isso eu preciso manter duas janelas do browser abertas e ficar copiando e colando textos de uma para outra (claro, posso usar a combo de troca de linguagem, mas acho isso mais demorado que um Control-Tab).

Seria de grande valia, um botão como "Reverse translation", que pegaria o texto de resultado e faria uma tradução ao contrário, como:

Texto em português : Translate(portuguese to english) : Text in portuguese : Reverse translation : Texto em português.

Para mim seria uma "mão na roda", não sei para vocês. Mandei um feature request para o Altavista...quem sabe...

domingo, novembro 26, 2006

12.000 por mes, também quer?

R$12.000/mes. Trabalhar no México, com mais U$40 por dia de alimentação, hotel pago e uma passagem por mes pra passear em casa. Não tá ruim, né? Pois é, assim até eu fico com ciúme. Mas digo que fico com mais do que isso: eu fico indignado.
Indignado porque o cara que ganha isso não entende nada de EJB, nem XP, UML, RUP, CMM, anotações e nem tem idéia da existência de coisas como Hibernate, Ajax, Patterns, renderização, instrumentação de código, AOP, XUL e tantas outras coisas que arduamente a gente aprende. Em contrapartida, esse cara simplesmente entende (?) de três letrinhas básicas: SAP.
Sim, sem faculdade, sem inglês ou espanhol, sem noção alguma de gerência de projeto, arquitetura de sistemas e qualquer outra coisa, com 3 cursinhos e uma entrevista já levaram o cara daqui para essa que descrevi logo acima.
Não digo que tenho inveja, mas fico pensando porque a gente que conhece tantas outras coisas, que trabalha muito mais, tem muito mais experiência e uma visão muito maior da TI não consegue essas barbadas?
Eu, com 29 anos, com muito custo consigo uma alocação como projetista pra ganhar nem R$4.500. Luto contra o tempo para terminar o mestrado, dou cursos extras, faço consultoria, palestras e viro as madrugadas projetando e programando em projetos livres para não conseguir chegar nem na metade do que o cara ganha. Alguma coisa tá errada.
Por vezes penso em largar tudo que sei em várias áreas e descambar para esse lado de ERP. Fazer uns cursinhos (um pouco caros, é bem verdade) e ter um retorno "graúdo" a olhos vistos. Me desligo da sopa de letrinhas que domino, páro de ler livros, artigos, desisto dessa história de mestrado e doutorado e me foco em algumas provinhas e certificações e com um pouquinho de inglês e boa vontade, posso beirar os R$20.000.
Mas daí lembro que não gosto de viajar, não tenho muito paciência com essa história de lidar com usuários e, principalmente, minha visão autruísta das coisas me coloca de volta no lugar onde estou hoje: trabalhando sem retorno.
Quero ainda ganhar muita grana, mas quero - principalmente - a satisfação de saber que essa grana veio de coisas que eu criei, como o Merlin, o Magoo, o Jestor e agora, o recém-batizado Melvin. Como dizia um amigo meu, como satisfação de vida estaria o fato de termos montado uma empresa - a nossa empresa - e saber que o pão e o leite que o funcionário aquele leva para seus filhos em casa, foi resultado de uma idéia, um conceito, uma visão que tivemos muitos anos atrás. Uma idéia que teve de ser lapidada, trabalhada durante dias, noites, madrugadas, semanas, meses e talvez anos, mas que enfim, rendera seus frutos.
Sou assim, tenho um pontinho de ressentimento ao ver alguns colegas ganhado muito mais do que eu com muito menos esforço. Mas nem por isso me acrubunho e vou para o time deles. Luto, da minha forma, à minha maneira. Não desisto dos meus ideais e não mudo meu caminho. Por vezes, quem está comigo sofre junto, mas qual seriam os louros de uma vitória sem esforço?
Quando vejo o cara andando com seu 307 novinho, pareço ter uma recaída. Quando o vejo mais novo e com uma morena linda ao seu lado, meu estômago se revira. Mas ei que não largo da minha velha C10 e quanto à morena, não tem problema, pois em casa, mesmo longe, já tenho a minha amada, mãe de meu filho e eternamente apaixonada.
Continuo a trabalhar firme e confiante. Um dia, eu viro o jogo.

terça-feira, novembro 21, 2006

Campeonato de CVS


Tempos atrás (não lembro onde, acho que foi no JavaNET), tinha um ranking dos commits de CVS mais exóticos que o pessoal tinha feito nos projetos. Tinha muita coisa legal. Ganhou um cara que tinha feito um commit e no conteúdo desse ele acabava xingando a si mesmo por ter feito o commit. Muito estranho.
Bem, aqui na 3Layer muitas vezes os commits são feitos e a gente não sabe bem o que escrever. Porém, nesse que fiz acabei escrevendo algo que achei legal colocar aqui.
Perda de tempo, talvez, mas vale como histórico :-)

quinta-feira, novembro 16, 2006

Pisando no Google

Estava na aula quando me lembrei que o Bhertier estaria dando uma palestra tipo invite to Google no auditório verde da UFRGS. Quando sai da aula fui lá ver o que o cara tava falando. E gostei.
A visão do Google que objetiva a experiência do usuário como resultado final e o modelo horizontal de suas aplicações eram coisas que eu não tinha parado para pensar. Bem, quem vê a tela branca do Google e sua enorme eficácia de resultado (tanto na experiência visual quanto na experiência [quase que maravilhosamente] exata de seus resultados pode ter uma idéia. Mas não tem idéia de coisas como essas abaixo:

Deixa que eu chuto (ops, que eu monto!!!)
Você sabia que o Google é o quinto maior montador de computadores do mundo? Sim, o Google compra hardware de baixo nível (placas, HDs, etc.) e monta seus computadores (ou melhor dizendo, super clusters de computadores), incluindo até a escrita da BIOS, uma versão específica de linux e camadas (e mais camadas) de software para garantir disponibilidade, digamos, eterna. Sistemas de guarnição monitoram a si mesmos e avisam detalhadamente cada pequenino erro no gigantesto e distribuído computador virtual. Milhares de processadores distribuídos em vários de centros de processamento. O cara do suporte simplesmente recebe um avison no desktop: Ei panga, vai lá no slot 1542 do módulo 32 e troca o HD. O panga vai, tira o HD pifado (ou qualquer outro elemento que deu falha) e coloca outro. Pronto. O sistema automaticamente instala tudo de novo (até um SO novo no HD se precisar) e coloca ele pra bombear. Tudo hot deploy, claro. Minha dúvida sobre o acesso da 20 bilhões de páginas foi sanada. Um nodo central recebe a query do usuário e distribui ela para o cluster. Cada elemento do cluster possui uma parte dos índices para as páginas e processa a query. O cluster retorna as páginas obtidas da query e o nodo central funde os resultados e manda para o usuário. O nodo central opera em memória (e que memória) e os índices dos clusters possuem algoritmos próprios (ou seja, não existe nenhum SQL por trás - mas isso todo mundo já sabia, eu acho:-)

O início
Saber que tudo isso foi baseado numa idéia simples de convergência de grafos parece história da carochinha, mas foi isso mesmo. O projeto que rodava tranquilo no quarto do Larry e do Sergey na Universidade de Stanford, rapidamente esgotou a capacidade não só do prédio dos alunos, mas também do laboratório de informática da Universidade e logo mais o todo o link de Stanford. Resultado? Rua!!! Ou melhor, garagem para eles (parece que essa história de criar empresas de TI em garagem é vício). Olhando pelas fotos, me lembro bem do tempo que eu estava no prédio da JH Santos fazendo o projeto Mentor: comida no lado do teclado, algumas CPUs velhas no chão, olhos esbugalhados de noites em claro e muita esperança...ah, quem dera.

"O hoje"
Hoje o Google tem dezenas de serviços, centenas eu acho. Embora a maioria seja beta ou esteja no labs ou mesmo que a maioria das pessoas não conheça, podemos dizer que o Google é dono da informação. Informação preciosa essa, tal como a AOL descobriu quando decidiu liberar seus logs de acesso (...) Eu particularmente, sempre adorei o Google, desde que o Luis Fétido me mostrou aquela página branca pura "OOOOO" na parte de baixo.

"Pisando no Google"
Ah, antes que eu termine, de hoje em diante estou literalmente pisando no Google porque, sim, eu também ganhei um chinelão 43 deles.

segunda-feira, novembro 06, 2006

Programando aos pedaços

Antes de passar para vocês o que acho que será o futuro dos sistemas, vou retomar o assunto de ligar controles e eventos à regras de negócio que ainda não existem...
Todo mundo está acostumado a programar da seguinte maneira: dadas as regras de negócio definidas (pelo analista) e detalhadas (pelo projetista), essas são programadas (pelo programador) conforme as especificações contidas no processo de software (se existir, ahahaha). Isso significa que o programador vai construir a interface do usuário e ligá-la às regras de negócio através de pontos específicos: os eventos dos controles. Isso nada mais é que o modelo MVC, regra básica em aplicações desktop ou web.
A interface do usuário (IU) está sendo construída. Os eventos já estão definidos no pacote gráfico/controlador em uso (Swing, SWT, Strus, JSF, Ajax...) e são simplesmente estendidos ou utilizados. E as regras de negócio ou já estão prontas em componentes escaláveis (EJBs, Webservices, JMS, etc.) ou estão em classes simples mesmo. Ou se não estão, serão, assim como a IU, criadas on demand. Em outras palavras, tudo que você usa para criar o sistema ou precisa estar pronto naquele momentou ou você cria na hora. Isso é a programação tradicional. Todos fazem isso.
Mas já pensaram em programar a IU e ligar ela a uma regra de negócio que - seguramente - estará disponível somente daqui a 3 semanas?
Vou dar um exemplo simples: O programador está criando um cadastro para uma financeira e o projeto gráfico (as telas) está pronto, bem como o projeto navegacional. Como o programador é "bala", a tela está praticamente pronta. Falta, porém, o analista e o usuário decidirem se dentro da fórmula do imposto sobre operações do tipo XPTO (que ainda não se sabe se é esse o nome mesmo!!! - me desculpem os usuários e analistas) será feito usando a tabela de cálculo X ou Y ou se será uma "mescla" da fórmula existente no último sistema da casa (...)
O programador pergunta ao seu gerente: E aí, o que eu faço agora? Eu poderia colocar a tela em produção hoje, mas como ainda não tenho essa regra de negócio definida, não sei o que fazer. O gerente responde: Toca outra tela...quando eles se decidirem você termina isso [subentende-se aqui: volta daqui a 3 semanas; procura o TODO que você colocou no código-fonte (colocou mesmo?); modifica os comandos navegacionais do controlador (vários XMLs) que faziam a página A ir para a C diretamente - sim, porque agora que a página B com o cálculo do financeiro está pronta e o esquema o fluxo do sistema muda de novo, testa, empacota redeploya e, ufa, vai tomar um cafezinho).
Minha pergunta é: Não seria mais interessante o programador ter feito algo como:

Agent.bind("btnCalcular", "click", "calcularImpostoSobreOperacoesXPTO")

E colocar a aplicação em funcionamento 3 semanas antes sem se preocupar como a regra do imposto será implementada? Simplesmente quanto ela estivesse pronta, a aplicação detectaria isso e ligaria o botão, o evento e a regra transparentemente.
É justamente isso que acontece quando o Merlin é usado para fazer o binding de regras denegócio: não importa se a regra está progamada ou não, o binding é feito e quando a regra estiver disponível a coisa simplesmente acontece.
Extrapolando esse conceito, fábricas de software poderiam criar sistemas de forma totalmente fragmentada, colocando-os em funcionamento mesmo que seus "pedaços" não estivessem disponíveis ainda.
Essa proposta não é nova para mim. Na verdade, o projeto Jestor, data de mais de 3 anos e é uma coisa que ainda quero desenvolver.
Obviamente, o exemplo que dei é uma minimização do assunto, pois aspectos diversos, como segurança, contexto de execução e outros estão envolvidos. Mas o importante é dizer que o Merlin já suporta a ligação de regras de negócio mesmo se elas ainda não estiverem disponíveis.
Se tudo correr bem, depois do Merlin, do Magoo e do projeto X (desculpem, ainda não tenho nome ainda para o gerador de relatórios que vai usar as bases do Merlin para renderizar os famigerados reports dos sistemas), o Jestor será a chave para fechar a arquitetura que tenho em mente.
Claro, devem correr mais uns 5 anos ainda, mas quando o Dolphin já for a JRE padrão nos sistemas operacionais, o Jestor bem que poderia ser um pacote estável pronto para download em algum repositório público como o SourceForge ou JavaNet.

terça-feira, outubro 31, 2006

Sem comentários

Terminei o último post dizendo que eu ia falar sobre o que imagino como o futuro (da forma de desenvolvimento) dos sistemas e aplicações. Porém, uma coisa triste aconteceu depois que eu resolvi instalar o BSPlayer para ver o primeiro episódio de Taken, do Spielberg: Blue Screen no Windows!
Passei a madrugada e o dia inteiro tentando recuperar a instalação, mas não teve jeito. Depois de muito suar e uma pilha de backups em DVD, acabei reinstalando o Windows (na verdade, nesse momento, ele tá no meio da instalação ainda - agora to usando o outro note com Linux, o que detesto).
Assim, depois dessa história triste, não vou desperdiçar um assunto tão interessante como o futuro da programação em um post escrito com o coração machucado (...)
Mas pra não deixar você triste, vou recapitular a questão dos agentes e sua implicação no tocante à ligação tardia entre controles, eventos e regras de negócio.
Quando eu disse que existia uma consequência do uso dos agentes em relação ao baixo acoplamento e alta coesão, entende-se que, ao usar agentes para formar a tríade controle-evento-ação, isso se dá de forma que não existem dependências sintáticas no código-fonte do sistema. Em palavras de programador (o que eu gosto), não existem declarações import na classe de bean. Veja isso abaixo:

package a.b.c.d;

public class Cliente {

@Agent("focusLost", "validarDescricaoPessoalDoCliente")
String descricaoPessoal;

}

Nesse pequeno exemplo, a classe bean Cliente possui uma propriedade chamada descricaoPessoal, a qual é mapeada durante a execução do sistema para um controle do tipo caixa de texto (bom, pelo menos esse é o comportamento inicial previsto do Merlin, mas pode mudar...). A esse controle, está ligada à ação validarDescricaoPessoal, a qual é invocada quando ocorrer o evento focusLost do controle, ou seja, quando o foco de trabalho do usuário sair do controle de texto referente à propriedade em questão.
A pergunta que surge aqui é: O que é essa ação? Uma ação nada mais é do que uma regra de negócio e, como tal, está implementada em um método qualquer.
Os métodos que implementam as regras de negócio podem estar em qualquer lugar: dentro do próprio bean, em um EJB, em um WebService ou, pasmem, podem ainda nem existirem fisicamente!
No nosso exemplo simples, a regra de negócio, ops, ação, poderia ser implementada como:

package x.y.w.z;

public class RegrasDeValidacao {

public void "validarDescricaoPessoalDoCliente" {
JTextBox descricaoPessoal = (JTextBox) Merlin.getControl("cliente.descricaoPessoal");
if (descricaoPessoal.getText().indexOf("http://")) {
JOptionPane.showMessageDialog("Você não pode colocar endereços web nesse campo.");
descricaoPessoal.requestFocusInWindo();
}
}
}

Essa regra simplesmente evita que o usuário digite um endereço web dentro do campo de descrição do cliente, exibindo uma mensagem de aviso e colocando o foco no controle novamente.
Percebe-se aqui que a ligação entre o evento focusLost e a regra de negócio validarDescricaoPessoalDoCliente é feita com o uso dos nomes baseados em texto puro, ou seja, Strings. Ao olhar o código da classe Cliente, percebe-se que a mesma não importa o pacote x.y.w.z que contém a regra de negócio. Ela também não importa nenhum pacote java.awt nem javax.swing, que conteriam o evento de foco. De forma análogoa, a classe RegrasDeValidacao não importa o pacote a.b.c.d para ter acesso ao controle da tela a ser renderizado. Na prática, isso significa que, em tempo de compilação, nenhum dos elementos da tríade controle-evento-ação se conhece.
É desse comportamento "aberto" que surge a pergunta: E se o programaodor escrever "ffocusLost" ao invés de "focusLost", ou "validarDescricaoPessoalCliente" ao invés de "validarDescricaoPessoalDoCliente", ou qualquer outro erro simples de digitação? A consequência é que o agente não conseguirá efetuar a ligação entre os elementos da tríade. Como resultado, a regra não será executada.
Bem, isso é extremamente perigoso, pois não temos como validar as se as ligações entre os controles, eventos e regras de negócio estão consistentes. Isso não é um ponto contra, uma vez que, usando a abordagem tradicional do Swing, a coisa fica toda consistida em tempo de projeto, pois as regras estão contidas em classes que implementam interfaces pré-definidas?
A resposta, felizmente é não. Como vou mostrar no próximo post existem meios de fazer essa validação antes do sistema executar.

domingo, outubro 29, 2006

Cada dia parece que sei menos

Nos últimos três dias fiquei na Internet procurando coisas mais empolgantes do que meus estudos de mestrado. Pra variar um pouco, procurei assuntos relacionados ao Merlin :-)
A sensação do momento é o Ajax. Na verdade faz tempo isso, mas tudo bem. Pensando nisso e no Java 6 que tá por vir e que conterá o Rhino como implementação padrão para scripting (subentenda-se aqui Javascript ou ECMAscript), me dediquei a repensar o mecanismo de scripting que estava implementando no Merlin. Por padrão, portei as idéias sobre Event Driven Programming da Eiffel para o meu framework e, de quebra incorporei o suporte a duas coisas que eu acho importante: inicialização de propriedades e ligação de scripts, ora bolas!
A inicialização de propriedades é uma funcionalidade importante quando não queremos que os controles gerados assim o sejam com base nos valores default computados pela dupla Configuração-Histórico. Nesse sentido, o Agente associado ao controle, além de ligar eventos e ações (como é o padrão em Eiffel), também permite coisas como "quero esse controle com fundo verde, fonte verdana itálica 11pt, texto branco e borda de 2px laranja" tudo isso em uma linha de comando, como essa:

@Agent(
property = "
background=Color.green;
font=new Font(\"verdana\",Font.ITALIC,11);
foreground=Color.white;
border=BorderFactory.createLineBorder(Color.orange,2)"
)
String nome;

Já a associação de scripts aos elementos de interface é uma comodidade versátil, como comenta John O'Conner em Scripting for the Java Platform (embora o exemplo que ele deu não me convenceu muito).
Por padrão, a engine do Merlin usa o BeanShell como interpretador de scripts. O BeanShell é um interpretador simples e otimizado, muito bom para as tarefas de corriqueiras de interface de usuário, como cópia de valores, arraste e aplicação de efeitos simples e validações. Linguagens como o Groovy, Javascript e outras que a JSR223 deve guiar também devem ser suportadas transparentemente pelo esquema que bolei. Em outras palavras, os agentes apontam para um script, seja ele interno (uma string) ou um mapeamento para um recurso externo (um arquivo ou endereço de rede, sei lá). De qualquer forma, basta ter o interpretador instalado que darei um jeito de detectar o tipo de script e automaticamente executá-lo.
Na prática, eu ampliei o conceito de agentes do Eiffel ao mesmo tempo que mantive a simplicidade e o baixo acoplamento, o que é muito bom (mas tem consequências que vou falar em outro post).
Entretanto, o termo Agente ainda não me convenceu muito...fica parecendo aqueles caras chatos do Matrix. Vou ficar pensando e se eu achar outra palavra melhor, o Eclipse me ajuda com um Control+Shift+R...
Tem mais coisas que fiz nesses últimos dias também, como ativar os lembretes via celular no Google Gmail (e aprender que existe um tal padrão iCal também), reativar o meu Netvibes e ficar mais uma noite sem dormir (se meu médico ler isso ele me puxa a orelha, no mínimo).
Bem, mas o que eu queria falar mesmo é sobre o futuro (futuro que eu prevejo) da programação, do desenvolvimento de sistemas e a própria forma com que encaramos as aplicações e a forma de usar os computadores. Mas isso eu falo no próximo post.
Att.

quinta-feira, outubro 26, 2006

Merlin, SBES e 3Layer

Semana passada, fui para o SBES 2006 apresentar o Merlin na Sessão de Ferramentas. Fiquei uma semana em Florianópolis, mas infelizmente não deu pra ir na praia porque o tempo nublado não ajudou nada...
Sobre o evento, vou ser sincero: eu esperava mais.
Tinha uns 200 participantes no total e alguns standes "meia-boca" de empresas como Google e Microsoft. Pra quem já foi num evento como Software Livre (que ocorre em Porto Alegre), o SBES não é nem a metade. Mas tudo bem, o público é outro...o SBES é cheio de doutores, mestrandos e afins (Isso me lembra Kpax: doutor, doutor, doutor, doutor). Pra quem gosta...
Na sessão que o Merlin foi apresentado, o organizador disse que 66 ferramentas concorreram esse ano e 21 foram eleitas para serem apresentadas e publicadas nos anais do evento. As 3 melhores ganharam premios de 6, 5 e 3 mil reais. Infelizmente o Merlin não foi uma delas - ficamos em quinto. Mas tudo bem, eu penso diferente...
E penso diferente porque, embora eu seja mestrando, sou no âmago um programador. E como programador, não vejo nada de útil naquela panacéia de ferramentas de gerência de requisitos que foram apresentadas (na prática, a cada 3 ferramentas, 2 eram para esse fim...). Não que não sejam úteis, mas as propostas que eu vi eram fracas (eu, como arquiteto ou analista aqui na 3Layer nunca usaria uma ferramenta que, para cadastrar um requisito fosse necessário preencher mais ou menos 10 campos adicionais, como prioridade, tempo, estimativa, custo, analista 1, analista 2, desenvolvedor, sub-requisitos, etc, etc, etc, etc....enfim....quero uma ferramenta para otimizar e não para complicar). Pior que isso, de que adianta ferramentas isoladas que não se integram com outras soluções (CASEs, banco de dados, gerenciadores de emails, diretórios de serviços, recursos adicionais, mecanismos de autenticação e outros que tenho na casa?). XMI? Que piada. Os apresentadores mesmo (em off, é claro) comentaram que o XMI não dá conta do recado...
Bom, enfim. Falando do Merlin...minha apresentação não ficou muito boa (sou muito perfeccionista, eu sei), mas expor todo o Merlin em 15 minutos é outra piada. Só pra apresentar o conceito de realimentação e as técnicas envolvidas daria mais de uma hora....mas tudo bem, é uma forma de melhorar meu poder de abstração e comunicação.
E por falar na apresentação do Merlin, vou disponibilizá-la no site do projeto para download (me cobrem).
E hoje páro por aqui porque o sono tá pegando.

sábado, setembro 02, 2006

JGoodies: Uma opção?

Há tempos atrás (uns 3 anos quase) eu havia trabalhado com o JGoodies Form, para testar seu gerenciador de layout. Embora eu tenha gostado dos resultados, a complexidade era enorme comparado aos meus (recursivos) agrupamentos de JPanels que eu fazia com os gerenciadores mais simples do Swing (com ênfase para o Border e Flow). Isso era na época dos primórdios do Merlin. Mas eu não estava contente.
Depois de navegar bastante, eu "achei" o TableLayout em um fórum da Sun. Era um gerenciador muito parecido com os famigerados tables da web (com os TD e TR). Mas ele funcionava bem. Possibilitava várias coisas que o GridBagLayout do java exigia dezenas (ou mesmo centenas) de ajustes. Ele era bem mais simples. E enfim coloquei o TableLayout como implementação padrão do gerenciador de layouts do Merlin.
Mas como a implementação está mais parada que água de poço (devido várias coisas, infelizmente) e o tempo anda, não posso dar o luxo de ficar esperando as coisas melhorem para eu começar a procurar mais alternativas. Assim, uma reportagem da Java Magazine me chamou a atenção para o JGoodies novamente.
Hoje, passei as últimas horas da madrugada mexendo em algumas coisas dele e implementando uma telinha bem simples, como essa ai ao lado.
Ela não tem nada de mais, mas mostra algumas coisas, como o alinhamento, o tamanho dos campos, o espaçamento, o redimensionamento e o uso de separadores (títulos) entre grupos de controles. Essa tela foi feita com o gerenciador do JGoodies e aplicado um look and feel Plastic3D.
O TableLayout também permite um layout como esse. Mas ele pára por aí. O JGoodies facilita o uso de separadores, de bordas externas (para os controles não ficarem grudados nas bordas do formulário) e é otimizado para o uso de várias resoluções, com formatos diferentes de redimensiomanto (dialog units - dlu, inches, centímetros, milímetros e pixels nativos). Ele também vem com fábricas e métodos auxiliares. Tudo isso facilita a aplicação dele.
Mas ele não é simples e exige um bocado de esforço mental, papel, lápis e borracha. Muita borracha para esboçar as telas antes de programar qualquer coisa.
Bem e o "keko"? Ou seja, e o que tudo isso significa? Significa que é mais uma coisa para eu decidir.
A vantagem do JGoodies é que ele tem mais coisas, como o binding de controles e é claro, os validadores. Tudo isso tem que ser pensado e repensado. Não sei, mas como muita coisa existe para ser implementada, o JGoodies é uma boa.

Links
JGoodies
TableLayout

terça-feira, agosto 22, 2006

Model-based generation

O dia de hoje não foi dos mais produtivos mas, enfim, fiz algo de útil que eu já deveria ter feito há algumas semanas: comecei a procurar artigos para a minha dissertação - os mesmos que eu já tinha e foram sei lá para aonde quando meu HD pifou...
Os tipos de artigos que procuro, em sua maioria, são relativos à geração baseada em modelos (model based generation), o que é justamente a tecnlogia que o Merlin utiliza para geração das telas de cadastro. O que difere muito (e isso eu posso garantir que é em 100% dos artigos e textos pesquisados até o momento) é que, enquanto o Merlin objetiva somente telas de cadastro (as interfaces CRUD), todas as abordagens estudadas buscam obstinadamente a geração de qualquer tipo de interface de usuário. Para isso os autores sugerem diversos modelos-base: modelos de tarefa (task models), modelos de interação (interaction models), modelos de domínio (domain models) e outros elementos, como camadas abstratas de controles, de eventos, de regras e um sem-número de outros recursos, todos visando alguma forma de abstração que permita minimizar o esfoço de programação e aumentar a eficácia das suas propostas.
Na prática, o que eu vejo como conclusão de toda essa panacéia é (i) a redundância de idéias, as quais vagueiam por caminhos diferentes buscando um objetivo comum; (ii) a total falta de aderência a padrões de mercado, uma vez que cada solução define (e advoga como a melhor) um padrão próprio e principalmente (iii) a quase total inutilidade da solução em ambientes reais de desenvolvimento. Sei, a expressão é forte mas, como desenvolvedor de sistemas - o que sou, não vejo aplicabilidade nenhuma delas nos meus cenários de trabalho: são soluções acadêmicas que projetam expectativas e não inserem suas propostas em cenários reais.
O Merlin, é uma ferramenta de geração de IU baseada em modelos, mas como princípio básico eu assumo que não quero gerar qualquer tipo de interface, mas sim - e somente - interfaces do tipo tela de cadastro. E isso simplifica muito as coisas. Com foco nesse tipo de IU, podemos abdicar de complexos modelos extras e balizar toda a geração em um modelo essencial, que está presente sempre: 0 modelo de objetos (de persistência) do sistema. Além disso, qualquer decoração no modelo (que visa aumentar a semântica) é feita com base em padrões de mercado, como o Java Annotations e em frameworks consagrados, como o Hibernate, o EJB e agora, talvez o JBoss Seam. Ainda, com vistas a manter a sintonia com o mercado, o projeto evolui com vistas as novas especificações que ainda estão bem no início, como o Java Bindings (JSR 295) e o Swing Application Framework (JSR 296) além, é claro, de compatibilidade total com tecnologias já em uso, como o Groovy, o BeanShell, AOP e conceitos bem-formados, como a programação baseada em eventos (Event Driven Programming, do Eiffel).
Mas isso tudo não é garantia de sucesso e é justamente por isso que a gente perde madrugadas lendo tutoriais, baixando artigos diversos e, muitas vezes (infelizmente), colocando eles no lixo, porque infelizmente as pessoas esquecem que frameworks devem ser usados no dia-a-dia e não somente terem seus conceitos publicados em sites, conferências e revistas especializadas.

domingo, agosto 13, 2006

Sobre a média do histórico

No último post, eu falei sobre o uso de estimativas para o histórico e que isso não era trivial. De fato, a computação de médias sobre valores do histórico é algo que deve ser pensado com calma. Por exemplo, vamos supor que o sistema S1 teve o campo "Usuario.nome" mapeado para "Nome do usuário" e no sistema S2 esse campo foi mapeado para "Nome" simplesmente. No sistema S3, qual será o valor que o sistema de histórico deve sugerir para esse campo? Com uma média simples, o valor poderia ser 50% para cada e, na prática o sistema de histórico, nesse caso, não ajudaria nada.
Pois bem. Eu imagino que o sistema de histórico deve usar uma escala temporal ascendente de pesos para o cálculo. Como assim? É simples, as coisas que são mais recentes devem ter um peso maior. No caso acima, o valor inferido pelo sistema de histórico deveria ser o valor de S2, ou seja, em S3 a sugestão para "Usuario.nome" seria "Nome".
Mas qual o argumento para isso? O argumento é simples: evolução. Em outras palavras, considero que a cada novo desenvolvimento a equipe incorpora conhecimento ao sistema, de forma que as novas decisões são as mais consistentes. Nesse sentido, as decisões tomadas para o sistema S2 são mais relevantes que as tomadas para o sistema S1. Claro, existem aspectos que fogem ao escopo do problema (o sistema S3 pode ter sido construído com mais pressa e menos cuidado; a nova equipe de desenvolviemento tem menos experiência no negócio; estagiários foram contratados; etc, etc e etc.). Mas isso não tem como saber, a não ser que seja parâmetro de configuração e, nesse caso entramos no problema do grafo infinito de escolhas...Deixa pra lá.
A questão que surge aqui é a seguinte: Quais os pesos que devem ser aferidos para cada ponto no histórico? Pode ser uma escala linear, como "S1=x, S2=2x, S3=3x", uma escala com valores exponenciais, como "S1=x^1, S2=x^2, S3=x^3" ou alguma outra. Na prática, acho que a linear seria mais interessante e menos agressiva. Outra alternativa seria deixar isso na configuração, de forma que o desenvolvedor tenha liberdade de optar por qual escala utilizar e que pesos associar a cada ponto do histórico. Mais um tópico a ser estudado.

quinta-feira, agosto 10, 2006

Aonde eu andava?

Tempo passou até que eu voltasse a escrever. E coisas ocorreram nesse meio tempo. E como ocorreram. Mas deixamo-as de lado e vamos falar de assuntos relacionados à...telas de cadastro, claro.
Estou pensando no Merlin para dizer a verdade. E para ser mais exato, no mecanismo de realimentação dele.
O Merlin, brevemente, é um gerador de telas de cadastro baseado em modelos. Em palavras de programador, como eu gosto, ele lê, em tempo de execução e via reflexão, o modelo de dados (as classes POJO) do sistema e, usando uma série de heurísticas e outras regras, ele renderiza (e esse é o termo que acho mais correto) as interfaces de usuário para edição de dados, ou, no jargão dos desenvolvedores, as telas de cadastro. Em suma é isso, mas na prática o negócio é bem complexo. Mas funciona. E como funciona.
Muitas abordagens semelhantes (embora todas essas gerem código - e o Merlin não) tentam fazer coisas parecidas. Mas elas são mais complicadas (e nada práticas). Mas e a realimentação? O Merlin baseia-se em um esquema de realimentação de contexto. Em palavras mais simples, o Merlin considera todo o histórico de desenvolvimento para gerar uma tela de cadastro. Por exemplo, se no sistema S1, você disse que o campo "br.com.minhaEmpresa.sistemaS1.modelo.beans.Usuario.descricao" deve ser renderizado na tela (de cadastro) como "Descrição do usuário", lá no sistema S2, S3...Sn, quando ocorrer algo parecido, o Merlin vai "se lembrar" disso e vai fazer isso automaticamente pra você. Veja a figura abaixo:
Na verdade, o Merlin "se lembra" de tudo. E mais. Ele usa um mecanismo federado para isso. Isso significa que, caso sua empresa (de desenvolvimento de software) tenha filiais espalhadas por cidades, estados ou mesmo em países diferentes, você pode configurar uma federação e o histórico de qualquer um desses lugares será compartilhado entre todos. Mas para isso funcionar, é necessário um compartilhamento de informações muito grande. Na prática, o classpath de todas as aplicações desenvolvidas (S1, S2, S3, Sn) em todas as filiais, deve ser compartilhado. E ai as coisas começam a ficar complicadas. Nesse ponto entram mecanismos de gerência de escrita, de versionamento, de modificação, de atualização do histórico, de propagação de modificações e, óbvio, de segurança. E isso são somente alguns problemas envolvidos.
O Merlin é tema da minha dissertação de mestrado e, a realimentação deve ser um dos capítulos do trabalho. E imagino que será o maior deles (e bem desproporcional, para dizer a verdade). Tenho planos na cabeça de como fazer isso, mas são somente planos. Preciso diagramar, testar e implementar muito antes de tomar uma decisão. Preciso estudar sobre o próprio conceito de federação, sistemas de métricas e estimativas (sim, pois um histórico não é somente uma média aritmética de pontos - a coisa é bem mais complicada. Vou falar disso em outro post), mecanismos de armazenamento e configuração, propagação e técnicas de mensageria, cache e persistência. E isso são somente alguns itens da "famosa" realimentação.
Deve ser por isso que nenhuma outra ferramenta que eu tenha pesquisado até agora implementou isso. Em suma, para dizer a verdade, somente um dos artigos comentou, veja bem somente comentou, que seria interessante o uso de informações históricas a fim de tornar as ferramentas mais pró-ativas. Bem, e tudo isso foi somente um ponto dentro do Merlin, que é um dos meus a fazeres no momento. Que esses próximos 4 meses sejam longos. Bem longos.

domingo, maio 28, 2006

Outra noite sem dormir

Agora são 8:20 da manhão e, enfim, isso coloca eu em outra noite sem dormir. Mas daqui a pouco estou indo.
Hoje terminei de olhar os links que eu começei a olhar 3 dias atrás (eu adoro o Control-Click no Firefox que vai abrindo abas após abas e a gente não "consegue" fechá-lo sem anter ler tudo que elas dizem - olha que elas têm mais links...).
Bem, olhei coisas como o http://www.thinkfree.com, que permite criar documentos do Office Online. Muito legal mesmo, com recursos inimagináveis antes do Ajax e dos Applets Java. Os caras conseguiram imitar o pacote Office grandiosamente. Claro, precisamos uma boa conexão de Internet, mas isso não é coisa difícil hoje. Vale a pena. Olhei alguns sites sobre CSS, como o http://cssbeauty.com, que tem boas dicas sobre CSS (pra gente tirar idéias e copiar mesmo) e daí acabei indo pro Emule (normal) baixar alguns livros "for dummies" pra mim.
Depois, passei pelo last.fm, e criei uma conta lá pra ouvir uns bons countries. Site bom, com muita informação de ranking de músicas, rádios online e bookmarks. Gostei. Aproveitei pra baixar uns livros sobre Ajax e não me contive, acabei brincando com o GWT novamente. Embora um erro "panga" no compilador dele me estressou um pouco, uma olhada no fórum me resolveu o problema. Claro, versão beta, mas com um fórum ativo as coisas se resolvem logo. Depois instalei o Google Notebook e a taskbar do Google, cuja qual tem de mais interessante o recurso pra ativar o Gmail como software padrão para envio (quando se clica em links de email).
Fui para página personalizada do meu Google e adicionei algumas coisas sobre Java, Eclise, J2EE, Ajax, tecnologia, Nasa, Ciência, Filmes e coisas do gênero. Um link do MyEclipse com suporte para o Matisse me chamou a atenção e acabei indo para ele. Baixei a versão development do MyEclipse (adoro essas versões, parece que a gente é desbravador...) pra testar o port do Matisse nele. Mas isso me levou para updates no meu Eclipse (mais precisamente para uma versão > 3.2RC4) e no final das contas eu já estava com o GetRight bombando downloads de todo uma plataforma nova: JBoss 4.0.4, JBossIDE 1.5.1, JBossCache e as novas especificações JSR do Java. Acabei perdendo um tempão organizando arquivos localmente e apagando coisas antigas.
Finalmente, olhando o JBoss Seam (veja um tutorial aqui) me levou ao Merlin e ao Apache Beehive. Se eu considerar o Merlin como projeto pioneiro de 2001, eu considero o Seam e o Beehive cópias expúrias do Merlin, uma vez que (podem querer provar o contrário) a idéia de ambos é fazer um model-based development, onde a navegação (controle) do sistema é definida já nas classes POJO (Javabeans) do sistema, via anotações (JSR 175) e arquivos de configuração. Ah, se eu tivesse uns 200 programadores para fazer o Merlin pra mim!
Agora, continuo com o country rolando no last.fm (mas com o VLC cheio de buffer pra dar conta da rede Virtua, que tá uma droga - embora tenha melhorado durante a noite e agora de manhã....mas ainda tá muito longe daqueles 2Mb que eles me prometeram).
So...café, banho e cama.

sábado, maio 27, 2006

JavaOne e mais Ajax

Ajax
Ontem o tempo estava bom para pesquisar e resolvi dar uma olhada como andavam as coisas sobre Ajax pelo mundo a fora. Claro, muita coisa existe e, obviamente, não dá pra olhar tudo. Assim, vai abaixo os comentários sobre o que eu andei olhando e minhas percepções.
Vários frameworks e APIs existem para o Ajax, como o Backbase, Dojo, Rico, GWT, DWR e outros. O DWR eu já tinha ouvido falar e consiste em uma API que permite a chamada de métodos remotos assincronamente, usando as funções de callback, as quais eu já comentei no post passado. Basicamente o DWR é composto de um conjunto de scripts que são atachados a página e um componente que roda no servidor, ou um servlet. Ele cuida do marshalling de dados entre as partes e as funções callback são o elo de ligação entre o java e o javascript. Bom, mas isso todo framework Ajax faz! OK, mas o DWR possui soluções boas e exemplos de como integrá-lo a outros componentes mais "pesados", como o JSF e o Struts. Outra API é a Backbase. Ela também oferece os recursos do DWR mas agrega componentes próprios, os quais funcionam como taglibs do JSF. Fora isso ambos são iguais. O Rico é outro framework que objetiva RIA (Rich Internet Applications) com Ajax. Olhando os exemplos do site, mais parece que os caras estão tentando fazer um "Power Point" com as aplicações. Vi muito efeito de drag-and-drop, mas muito pouco sobre coisas úteis para desenvolvedores de sistemas de dados, como integração com frameworks (JSF, Struts, WebWork, ...) ou interação com elementos de back-end (EJBs, Webservices, ...). O Dojo é mais num no cenário. Achei o site bastante "fraco", principalemente para algo "ajaxiano". Finalmente, achei o GWT, ou melhor dizendo o Google Web Toolkit. Mesmo na versão beta, esse vale um post no Coisiboa. Em suma, com ele você pode até esquecer que programa na web - nada mais de HTML se não quiser. Ele possui um framework próprio de componentes UI, tal como o Swing. Também possui um bom suporte a eventos e, pasmem, traduz seu código-fonte em Java para Javascript com muita precisão. O Ajax vem embutido (pra variar) com as funções callback. Também tem uma boa documentação, exemplos e utilitários para criar aplicações de template e projetos no Eclipse (mas não é um plugin, é um utilitário de linha de comando). Obviamente, tem limitações: não suporta sintaxe Java 5, faz restrições em funcionalidades e APIs nativas do Java (como List, Threads...) e tem que cuidar coisas como serialização de objetos. Fiz uma aplicação de teste com ele e gostei do resultado.

JavaOne
O JavaOne rolou esse mês e, claro, o assunto não poderia ser outro: o J2EE 5 e o Mustang. O J2EE saiu e muitas coisas estão para mudar. Dicas sobre como usar corretamente (os famosos) blueprints nos vastos recursos da plataforma (annotações, defaults, injeção de recursos, ...) e como integrar ferramentas foram tópicos discutidos nas sessões do evento. Sobre o Mustang as boas novas foram, claro, para os recursos desktop. O suporte nativo para TrayIcon, o gerenciador de layout GroupLayouyt (que ainda deve ser incluso), e a classe Desktop, para integração nativa de recuros do SO. Outros "improvements" menores como ajustes na API 2D e gerenciamento de threads do Swing. Ben Galbraith ainda deu boas dicas sobre como usar as Actions do Swing (e isso me lembra muito o que estou implementando no Merlin) e como externalizar recursos como layout e aparência no Swing com o uso de CSS. Finalizando, indicou fortemente o uso de gerenciadores de layout como o GroupLayout (do Matisse Netbeans) e o FormLayout (do JGoodies).

Como disse, o Ajax veio pra ficar. Quer saber mais sobre ele é só procurar no Google. Um bom início é o Ajaxian e o Ajax Resource Developer Center. O J2EE 5 pra mim não é novidade, pois já usamos ele a um bom tempo na 3Layer. O que muda é que agora as coisas podem acontecer "sem poréns". O Mustang tá no forno. Não me atrevi a usar ele na íntegra, pois "core" é "core". Assim, somente no ambiente de teste. Sabe como é: é bom, mas temos tempo ainda.

Alguns links relacionados
http://java.sun.com/javaone/sf/sessions/general/javablueprints_thursday.jsp
http://java.sun.com/javaone/sf/sessions/general/mustang_thursday.jsp
http://java.sun.com/javaone/sf/sessions/general/eight_ways_dev_swing.jsp
http://java.sun.com/javaone/sf/sessions/general/intro_ajax.jsp
http://java.sun.com/javaone/sf/sessions/general/sun_friday.jsp
Prototipe JavaScript Framework
Scriptaculous (outro framework Ajax)

segunda-feira, maio 01, 2006

Ajax: A revolução nos cadastros?

Esse é meu primeiro post no site. Nem sei porque estou escrevendo agora, porque tenho prova amanhã e não estudei nada - fiquei o dia inteiro fazendo frame na tela (clique com o mouse em um lugar que não tem nada no desktop e arraste para qualquer lugar que não tenha nada: pronto, você fez um frame!).
Bem, o que quero falar é sobre o Ajax e sua relação com Java. Assim, parece que o assunto não tem muito a ver com telas de cadastro, mas é bem ao contrário.
Ajax nada mais é que um nome bonito para uma tecnologia velha (HTML dinâmico + Java Script). Na prática o Ajax padroniza (?) tipos de controles de tela (em frameworks, como o Backbase) e operações (eventos, como clicar, arrastar, passar o mouse, etc.). Essa padronização á baseada em conjuntos (enormes) de arquivos de JavaScript que fazem operações diretamente no modelo DOM (Document Object Model) da página. O DOM é uma árvore em memória que é a representação de todos os elementos que aparecem na tela do usuário (botões, imagens, tabelas, texto, etc.).
O legal nessa tecnologia é que as chamadas dos métodos javaScript ocorrem em segundo plano. Assim, enquanto o usuário está digitando algo em uma caixa de texto, um código JavaScrips (ops, Ajax) pode estar enviando um arquivo para o servidor ou adicionando itens em uma caixa de seleção.
Devido a proliferação do Ajax, estamos entrando na chamada Internet 2, ou Web dinâmica. (Sobre isso tenho um comentário. Internet 2 e Web Dinâmica é uma coisa de se pensar. Anos atrás quando se falava em Internet 2 esperava-se que ela fosse conhecida como Web Semântica, ou seja, um lugar onde houvesse menos redundância de informações e os resultados dos buscadores - como o Google - tivesem menos resultados e mais confiabilidade. Porém, vejam como realmente as coisas mudam...).
Continuando. O Ajax é bom, embora ainda seja complicado e não seja um padrão (pois não existe uma especificação - qualquer empresa cria um framework com suas regras).
E o Java? A relação do Ajax com o Java é muito estreita. Geralmente os desenvolvedores utilizam o Ajax para tornar os sistemas mais rápidos, pois o usuário não precisa esperar para ver o resultado de uma ação (por exemplo, ele não precisa clicar no botão "Salvar" para que os dados que ele digitou sejam validados, tudo ocorre em segundo plano com o suporte do Ajax).
O problema é que os dados que o usuário digitou precisam ir para algum lugar, provavelmente serem salvos em um banco de dados. E aí as coisas complicam, pois o Ajax não faz esse trabalho. Para esse trabalho é usado o Java. Assim, é necessário um mapeamento de dados que estão no domínio do Ajax para o domínio do Java, o qual vai efetivamente salvá-los no banco de dados.
E é esse o ponto que considero o Ajax ainda incipiente. Para resolver esse problema ele implementa o conceito de funções de callback. Trocando em miúdos, o Ajax funções são passadas como parâmetros de um lado para outro e é nesse ponto que as conversões de dados ocorrem.
As funções callback sempre foram um problema para mim. Lembro delas quando trabalhava com Delphi e precisava usá-las para enumerar os handles (janelas) do sistema. Isso era preciso porque a API do Windows não disponibiliza um método que retorna uma lista dos handles abertos, mas sim uma função chamada GetHandle que espera como parâmetro a função callback. Assim, uma interação entre a API do Windows e a função callback que eu programei acontece. É nessa função callback que os handles do sistema são computados. O processo é complicado, eu sei. E é o mesmo princípio com o Ajax e o Java...
Funções callback ao meu ver são uma solução ruim para um problema que na verdade não foi bem explorado. E não foi explorado porque não existe um trabalho unificado, que culminaria com uma especificação.
Bom, e o que as telas de cadastro tem a ver com tudo isso? Tudo.
O princípio básico de preenchimento de telas de cadadastro vai mudar radicalmente na web. Em suma, os usuários não vão mais submeter dados errados para os servidores. Tudo que for enviado já terá sido validado no próprio cliente. Além disso, questões de usabilidade serão afetadas. Por exemplo, o número de cliques necessários para enviar os dados de uma tela de cadastro vai reduzir, bem como n tempo necessário para preenchê-las. Outro aspecto é que muito código que antes estava no servidor será migrado para o lado cliente. É uma nova fase da luta thin clients x fat clients (clientes magros x clientes gordos). O que pode ocorrer é, novamente, duplicação de regras de negócio (sistemas de legado ainda precisam manter as regras de negócio - diga-se principalmente validação - no lado servidor, porém novas interfaces de cliente já saem com essas regras duplicadas am código Ajax. Isso acontece porque regras simples como tamanhos mínimos, máximos, obrigatoriedade e testes com expressões regulares não envolvem o servidor remoto e são integralemnte processadas pelo Ajax. Mas elas também devem estar presentes no servidor remoto, uma vez que acessos por sistemas de legado ainda podem ocorrer.).
Com o tempo, o Ajax vai melhorar e as coisas devem convergir (eu espero). Se eu pudesse pedir algo, seria uma especificação e uma implementação de referência, tal como existe para o JSF. Como isso não pode ser pedido pra ninguém, o jeito é testar vários frameworks e esperar que algo melhor que as funções callback apareca no mercado.