↓ Arquivos ↓

Arquivo → November, 2009

Outra causa para o maldito erro “Não é possível abrir mais tabelas” do MS Access com JDBC ODBC Bridge!

Access Malvado!

Como sempre, o Access apronta das suas comigo. Quando achava que já tinha resolvido todos os problemas relacionados ao maldito problema “Não é possível abrir mais tabelas” (veja este link), encontrei outra possível causa para o mesmo no StackOverflow.

O que pode ocorrer é o seguinte: há situações nas quais o seu cliente pode perder conexões com a rede. Quando a conexão é fechada, não necessáriamente é liberado o socket de conexão com os arquivos de conexão com o Access até que seja executado o coletor de lixo do Java.

Ou seja: você fecha a sua conexão, assim como todas as suas instâncias de PreparedStatements e ResultSets, define-as como null mas o driver ainda não as fechou porque perdeu conexão com a rede momentaneamente.

Como picos de rede são comuns em ambientes mais complexos (e não tão complexos assim), a solução é a seguinte: ao trabalhar com Access e Java, execute o garbage colector de tempos em tempos para garantir que as conexões fechadas e nulificadas sejam de fato fechadas no driver ODBC.

A minha pergunta relacionada no StackOverflow pode ser vista aqui com ainda mais detalhes.

Dica: criando XML com Groovy

Criar XML com Groovy é absurdamente simples. Para tal, tudo o que precisamos consiste na classe groovy.xml.MarkupBuilder.

Como o próprio nome já entrega: esta classe utiliza o recurso builder presente em Groovy de uma maneira bastante bacana.

Tudo o que precisamos fazer consiste em passar uma estrutura hierarquica para uma instância de MarkupBuilder e em seguida evocar o método toString().

Sendo assim, vamos começar com um exemplo simples: meus cães.


import groovy.xml.MarkupBuilder

xml = new MarkupBuilder()
xml.canalha() {

cao(nome:"Fraude", raca:"Pinscher?")

cao(nome:"Zé", raca:"Schnauzer")

}
xml.toString() // irá retornar uma string contendo o xml gerado

Repare: óbviamente a classe MarkupBuilder não possui um atributo chamado canalha. O que eu faço consiste em chamar um método com este nome na instância de minha classe. Groovy irá tirar proveito de sua natureza dinâmica (veja este meu post sobre o assunto) e em seguida analizará a estrutura hierarquica que segue o nome do “método”, o que irá gerar o XML abaixo:


<canalha>

<cao nome='Fraude' raca='Pinscher?' />

<cao nome='Zé' raca='Schnauzer' />

</canalha>

Agora, suponhamos que eu queira algo mais. Além de listar meus cães, quero também listar suas vítimas. Basta agir tal como no exemplo abaixo:


import groovy.xml.MarkupBuilder

xml = new MarkupBuilder()

xml.canalha() {

cao(nome:"Fraude", raca:"Pinscher?",

vitimas() {

coitado(nome:'celulares mil')

coitado(nome:'cadeiras')

coitado(nome:'ouvido dos vizinhos')

}

)

cao(nome:"Zé", raca:"Schnauzer",

vitimas() {

coitado(nome:'Fraude')

coitado(nome:'Senhor de muletas')

}

)

}

xml.toString()

E o XML gerado será…


<canalha>

<vitimas>

<coitado nome='celulares mil' />

<coitado nome='cadeiras' />

<coitado nome='ouvido dos vizinhos' />

</vitimas>

<cao nome='Fraude' raca='Pinscher?'>vitimas</cao>

<vitimas>

<coitado nome='Fraude' />

<coitado nome='Senhor de muletas' />

</vitimas>

<cao nome='Zé' raca='Schnauzer'>vitimas</cao>

</canalha>

Dica: iniciando processos em Groovy

Há situações nas quais se torna necessário iniciar processos externos.Em Java, podemos usar a classe Runtime para iniciar novos processos, tal como no código abaixo:


java.lang.Runtime.getRuntime().exec("notepad.exe")

O resultado será uma nova instância da classe abstrata java.lang.Process, cujos métodos poderemos acessar e assim direcionar o stream de saída, etc.

Groovy simplifica esta tarefa da seguinte forma: caso queira iniciar um novo processo, digite o nome do comando dentro de uma string e em seguida chame o método execute() embutido pela linguagem dentro desta classe, tal como no exemplo abaixo:


"notepad.exe".execute()  // BEM mais simples, não é mesmo?

O resultado da execução deste método será uma instância de java.lang.Process, exatamente como o exemplo em Java que citei acima.

Sabe: da pra ir além. Você também pode processar a saída de um comando linha a linha se quiser. Supondo que você esteja executando o sistema operacional Linux (ou o Windows com o cygwin) instalado, o código abaixo também seria válido:

<pre class="code-java">def processo= <span class="code-quote">"ls -l"</span>.execute()
processo.in.eachLine { linha -> println linha }</pre>

Não é bacana?

Link útil: acessando bases de dados MS Access com Java

Sempre enrolei pra escrever um post assim, até que encontrei um pronto na internet.

Sendo assim, se você também sofre tendo de acessar o maldito Access usando Java, recomendo que leia o guia abaixo: muito útil.

http://www.planet-source-code.com/vb/scripts/ShowCode.asp?txtCodeId=2691&lngWId=2#SECTION0

Groovy Dinâmico

Fato: mais da metade das pessoas que conheço e programam em Groovy nunca usaram invocação dinâmica de métodos simplesmente por não saber o que é ou simplesmente como funciona. Sendo assim, sem mais delongas, vamos por a mão na massa:

Vamos supor que exista a classe PatoLouco implementada em Java tal como no código abaixo:


class PatoLouco {

public void digaQua() {

System.out.println("Qua!");

}

public void digaQuaQua() {

System.out.println("Qua Qua!");

}

}

Em Java, se quisermos invocar um dos métodos presentes na classe, temos de satisfazer um requisito básico: ele deve estar implementado, pois isto é verificado em tempo de compilação pela linguaem. De acordo com este ponto de vista, temos duas alternativas: ou a própria classe já implementa estes métodos OU a classe implementa uma interface como a descrita abaixo:


public interface Pato {

public void digaQua();

public void digaQuaQua();

}

/*

E seguindo esta lógica, poderemos ter zilhões de tipos diferentes de patos, tal como a classe abaixo.

*/

public class PatoNaoTaoLouco implements Pato {

public void digaQua() {

System.out.println("um qua não tão louco assim");

}

public void digaQuaQua() {

System.out.println("Qual a razão de ter de dizer dois 'quas'?");

}

}

A presença das interfaces nos garante que os métodos serão implementados pelas nossas classes do tipo Pato. Se em um futuro não tão distante quanto parece formos preguiçosos em nossa modelagem e quisermos lidar com galinhas e outros tipos de aves, iriamos criando nossas interfaces, até chegar a um ponto no qual teriamos uma classe tal como a abaixo:


public class AveOrnitorrinca implements Pato, Galinha, Avestruz, Ganso, Aguia, Marreco {

// zilhões de métodos implementados de acordo com as interfaces

}

Linguagens dinâmicas como Groovy resolvem este problema aplicando o “princípio do pato”: se anda como um pato, corre como um pato e ‘fala’ como um pato, é porque é um pato.  Sendo assim, vou apresentar um dos exemplos mais batidos deste principio no código Groovy abaixo:


class Cachorro {

def incomode() {println "Lato sem parar. Au au auuuuu!"}

}

class Gato {

def incomode() {println "Te arranho sem parar. Grite!"}

}

// repare que não há aplicação de herança ou interfaces.
// o código abaixo executará normalmente

instancias = [new Gato(), new Cachorro()]

for (instancia in instancias) {

instancia.incomode()

}

A saída que teremos será:


Lato sem parar. Au au auuuuu!
Te arranho sem parar. Grite!

Uma solução muito mais limpa do que em Java não é mesmo? Isto porque a verificação dos métodos é feita em tempo de execução. Na realidade, é possível ir além. Observe o código abaixo:


class CachorroLouco {

def lata() {println "Au!"}

def deite() {println "Deitado"}

def role() {println "Rolando!"}

def digaIsto(isto) {println isto}

}

/* Criei uma matriz de strings contendo os nomes dos métodos acima*/
nomeDosMetodos = ["lata", "deite", "role"]

/* E agora, um pouco de "mágica" */

cao = new CachorroLouco()

for (metodo in nomeDosMetodos) {

cao."${metodo}"()

}

// Claro, o código abaixo também é válido

cao."lata"()

// E com parâmetros, seria a mesma coisa:

cao."digaIsto"("Isto!")

Não é legal? Passando uma string para a minha instância, em tempo de execução eu posso invocar métodos dinâmicamente, o que abre uma gama imensa de possibilidades.

O que acontece se o método não existir?


new CachorroLouco()."faca_algo_impensado"()

// Groovy me dará esta saida:

No signature of method: CachorroLouco.faca_algo_impensado() is applicable for argument types (...)

Uma excessão do tipo groovy.lang.MissingMethodException será disparada. No entanto, podemos resolver este problema sobrescrevendo o métodomethodMissing em nossa classe, tal como no exemplo abaixo:


public class CachorroLouco {

def methodMissing(String name, args) {
println "O método ${name} não foi implementado seu perdido!"
}

//  restante da classe abaixo

}

Quando um método não é encontrado em uma classe, Groovy irá executar este método que, se for sobrescrito, poderá lidar com o seu caso específico. E neste momento você me pergunta: e se for uma classe implementada em outra linguagem, como Java, por exemplo: como lidar com esta situação?

Ai entra a nosso amigo (ou seria amiga?) ExpandoMetaClass

Groovy nos permite incluir novos comportamentos em classes já existentes. Fazemos isto usando a meta classe ExpandoMetaClass, que nos permite adicionar novos métodos, construtores e propriedades usando a sintaxe da closure que já conhecemos.

Sendo assim, o código abaixo é perfeitamente válido:


String.<strong>metaClass</strong>.sempreImprimaIsto = { ->

println "Sempre imprimirei isto"

}

"sou uma nova string".sempreImprimaIsto() //método incluido na hora.

// Lembra dos codecs de string do Grails? Funcionam exatamente assim.

Em nosso caso, bastaria injetar o método methodMissing em nossa classe CachorroLouco, exatamente como no exemplo abaixo:


CachorroLouco.metaClass.methodMissing = {String methodName, args ->
println "O método não existe"
}

É ou não é MUITO legal?

Armadilhas: o desenvolvedor interface

No dicionário kiconiano acabo de incluir um novo termo: desenvolvedor interface, cuja definição é:

“desenvolvedor que acidentalmente acaba se tornando a interface dos seus sistemas”

Esta é uma situação comum em empresas nas quais TI é um meio e não um fim: ocorre quando os realmente interessados pelo resultado final de um sistema (normalmente relatórios) não o utilizam diretamente, mas sim através daquele que o desenvolveu.

Você sabe quando esta situação ocorre ao ouvir frases como “ei Fulano: será que você pode enviar para o meu e-mail o relatório X?” e este não é um novo tipo de relatório, mas sim aquele que o usuário precisa esporádicamente já faz algum tempo.

No frigir dos ovos, o que ocorre é a inclusão de uma nova camada no sistema: o desenvolvedor, tal como no esquema abaixo:

O desenvolvedor deixa de ser o profissional responsável por desenvolver e criar soluções e passa a ser mais uma camada do sistema: a sua interface. É fato: o cliente sempre quer o resultado final, porém ao cair neste tipo de situação, o que obtém é muito mais caro que o inicialmente proposto (afinal de contas, o “tal do sistema” não funciona sem a presença do “desenvolvedor”).

Já passei por uma situação similar (e vejo alguns companheiros passando pela mesma) e, após me concentrar nas questões abaixo, fica nítido que ao menos em 90% dos casos a culpa é nossa.

Pergunte-se:

Você tem certeza de que seu software é fácil de usar?

Muitas vezes o produto gerado é tão complexo que o usuário final fica com medo de se aproximar. Lembre-se: o que é fácil para você não necessáriamente o é para o resto do mundo.

Fórmula kiconiana: software difícil = atividade tediosa = mais um desenvolvedor que vira interface.

Seu usuário sabe usar o sistema?

Resolvida a primeira possibilidade, segue a segunda: será que você treinou o seu usuário corretamente? A documentação do seu sistema é legível para seres humanos comuns (leia-se: que não trabalham na área de TI)?

Seu sistema é de fato confiável?

Ponha-se na situação do seu usuário. Ele sabe usar o seu software, que considera até agradável. Porém, ao tentar executar determinada tarefa, se depara com uma mensagem de erro (claro: sempre no pior momento possível). O primeiro pau do seu software após ter sido homologado destrói 70,837373% da confiança inicial.

Caso o problema não seja resolvido efetivamente e rápido, o usuário se sentirá mais confortável pedindo a você utilize o software em seu lugar (e neste caso, é inclusive sua obrigação).

Pior: imagine que os resultados obtidos estejam errados. Neste caso, além  de gerar os resultados para seu cliente, terá também de comprovar a validade dos mesmos! E acredite: não será uma única vez.

Foi criado um sistema ou uma gambiarra?

Eis a pergunta desagradável. Normalmente o “sistema” é na realidade aquela “rotina” ou “macro” feita para suprir uma necessidade de momento que se tornou periódica. De fato: seu usuário não é obrigado a saber como executar scripts ou macros do Excel. E a solução é simples: transforme a gambiarra em sistema.

Além do questionamento

Acredito que um fato simples normalmente é ignorado por muitos desenvolvedores interface: quanto mais independente um sistema for do seu criador, maior o grau de satisfação do seu cliente. Sei que parece incrível pra muitos, mas já ouvi diversas vezes de alguns pilantras desenvolvedores que se o cliente não estiver preso, não há como garantir o próprio sustento. Eita falácia! Software bem feito requer menos manutenção, que torna seu cliente mais feliz, que o indicará para outros trabalhos. Simples assim.

O desenvolvedor é uma interface sim: entre a idéia do cliente e a geração de uma solução para a mesma. Uma coisa é criar soluções, outra se tornar um botão.

A estética do software

Recentemente reli A Beleza das Máquinas de David Gelernter: um livro cujo tema dentro da ciência da computação é raríssimo: estética, que sempre foi um dos meus assuntos preferidos (tente definir o que é de fato o “belo em si” e provávelmente você também se apaixonará pelo assunto).

A primeira vez que li este livro foi em 2002 (publicado no Brasil em 2000) e esta releitura foi fascinante pelo fato de que tanto o mundo como eu mudamos radicalmente de lá pra cá. É nítido um certo deslumbramento com os “computadores de mesa” presente no texto, o que chega a ser engraçado para nós, que vivemos em uma sociedade na qual os mesmos começam a sair de cena ao serem substituídos por telefones celulares com os quais sequer sonhávamos em 2000. Por outro lado, as asserções estéticas do autor continuam válidas: e como!

A tese consiste no fato de que sim: o problema estético também se aplica à ciência da computação. Porém, ao contrário da estética geral com a qual já estava acostumado, e que nunca conseguiu definir o belo com exatidão, no contexto do software esta é cirurgica. É belo no software o conciso e simples, ou seja, quanto mais bem definida for a função do mesmo, e mais simples for o seu uso, melhor será a nossa experiência estética. Parece óbvio, não é mesmo?

Como ameaça à beleza de um produto, o autor aponta um mal que aflinge a nós desenvolvedores: a nossa tendência quase irracional de incluir novos recursos em nossos produtos, aumentando assim significativamente o seu escopo de utilização e, como consequência, sua complexidade. O exemplo apontado é o Word que inicialmente era um processador de textos simples e fácil de usar mas que, com o passar do tempo, e a inclusão de novos recursos, foi se tornando cada vez mais complexo e distante do seu objetivo original: editar textos.

Trazendo esta releitura para os dias atuais, não pude deixar de fazer algumas comparações com softwares/sites/serviços que utilizamos atualmente e me perguntar: belo ou feio? O software/serviço é portanto considerado belo se for respondido “sim” a duas perguntas: o seu objetivo é simples e bem definido? é fácil de usar?. A segunda pergunta parece ser subjetiva demais: sendo assim, imagino minha mãe usando os produtos abaixo.

Dropbox (www.dropbox.com):
Objetivo: compartilhar e sincronizar arquivos entre diferentes computadores. Mais simples impossível.
Fácil de usar? Demais: tudo o que preciso fazer consiste em armazenar os arquivos a serem compartilhados em um diretório específico.
Veredito: lindo

Google:
Objetivo: encontrar conteúdo na web. Simples.
Fácil de usar? Sim, é só digitar o que se deseja encontrar.
Veredito: lindo.

Twitter:
Objetivo: possibilitar às pessoas publicarem suas idéias em apenas 140 caracteres e acompanhar outros usuários do serviço. Simples.
Fácil de usar? Nem tanto: todas as pessoas que conheço que ficaram viciadas no serviço utilizam algum cliente para acessar o serviço ao invés do próprio site.
Veredito: bonitinho (quase feio. os clientes são até belos, mas o pai deles nem tanto)

Firefox:
Objetivo: navegador web. Simples.
Fácil de usar? Sim, não há grandes complicadores no navegador. No entanto, com a inclusão de plugins o bichinho acaba se tornando um monstrinho cheio de coisas piscando pra você o tempo inteiro.
Veredito: belo com tendência a Michael Jackson.

Planilha eletrônica:
Objetivo: criar tabelas com células interligadas ou não entrei si visando calcular valores e prever resultados ou simplesmente organizar informações no formato tabular. Posteriormente, acabaram em inúmeros casos sendo usadas como aplicações ou bancos de dados. Simples? Nem um pouco!
Fácil de usar? Conheço poucas pessoas que dominem de fato o uso do Excel.
Veredito: horrívelmente deformado pelo mal uso

Um ponto interessante no texto é a dificuldade que a beleza do software possui de ser aceita. Segundo o autor, esta dificuldade seria resultante do fato de softwares estéticamente agradáveis serem considerados “brinquedos” pela maioria (“afeminados” é a palavra usada pelo autor) e, portanto, não serem levados a sério. E é ai que as coisas melhoraram.

Observando todo este buzz sobre Web 2.0, o que podemos observar é que sim: as aplicações estão mais simples e também mais fáceis de serem usadas. Logo, o software atualmente é mais belo E, a resistência citada pelo autor foi vencida, o que beneficia muito a nós, usuários, e também a mim, que não vou precisar gastar horas explicando minha mãe a como usar estes serviços. :)

PS: vale a pena comprar o livro hoje? Só se for pra ver como era o mundo antes do ano 2000. Ele se resume em apenas dois fatos: software belo é conciso e simples E há dificuldade em se aceitar esta beleza (esta segunda tese nem sequer vale mais tanto assim)

Get Adobe Flash playerPlugin by wpburn.com wordpress themes