terça-feira, 26 de fevereiro de 2008

Argumentos variáveis (varargs) são para os fracos - ou Como o Ensemble lida com isso

Em Caché Object Script (a linguagem padrão pra se desenvolver no Caché da Intersystems) não conseguimos definir métodos que podem ter um número arbitrário de parâmetros, como as VarArgs do Java, ou mesmo as funções com argumentos variáveis do C/C++.

Entretanto, ainda podemos passar como parâmetro, um array ou uma List.

Então, quando me deparo com uma definição de método como esta abaixo... (consta no Adapter EnsLib.SOAP.OutboundAdapter, do Ensemble):

Method InvokeMethod(pMethodName As %String, Output pResult As %RegisteredObject, ByRef pArg1, ByRef pArg2, ByRef pArg3, ByRef pArg4, ByRef pArg5, ByRef pArg6, ByRef pArg7, ByRef pArg8, ByRef pArg9, ByRef pArg10, ByRef pArg11, ByRef pArg12) As %Status


E não estando satisfeito, fui olhar como é que este método estava implementado. Uma pequena amostra abaixo:

        If $D(pArg12)    { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7,.pArg8,.pArg9,.pArg10,.pArg11,.pArg12) }
elseif $D(pArg11){ Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7,.pArg8,.pArg9,.pArg10,.pArg11) }
elseif $D(pArg10){ Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7,.pArg8,.pArg9,.pArg10) }
elseif $D(pArg9) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7,.pArg8,.pArg9) }
elseif $D(pArg8) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7,.pArg8) }
elseif $D(pArg7) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6,.pArg7) }
elseif $D(pArg6) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5,.pArg6) }
elseif $D(pArg5) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4,.pArg5) }
elseif $D(pArg4) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3,.pArg4) }
elseif $D(pArg3) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2,.pArg3) }
elseif $D(pArg2) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1,.pArg2) }
elseif $D(pArg1) { Set pResult = $zobjmethod(..%Client,pMethodName,.pArg1) }
else { Set pResult = $zobjmethod(..%Client,pMethodName) }
$$$sysTRACE("Got Result "_pResult)


Tá certo que pela maneira como foi concebida, essa solução nem é tão ruim assim. Isso porque no caso acima, os parâmetros estão sendo sempre passados por referência.

O que me incomoda nem são os trocentos elseifs, ou a "beleza" do código. É a limitação do número de parâmetros. Tá certo que dificilmente são usados 12 argumentos, mas sempre surgem aquelas situações-limite, e um décimo terceiro argumento pode ser necessário. E aí?

Uma solução é ficar alterando a própria API do Ensemble. Como foi feito neste outro post, sobre um problema no Adapter de SQL.

Uma outra solução é largar mão, e procurar outra ferramenta. =P

Eu acho que essa merecia ir pro The Daily WTF.

segunda-feira, 11 de fevereiro de 2008

Variáveis de contexto no Ensemble BPL - Business Process Language

Trabalhando com o Ensemble, a ferramenta de EAI da Intersystems, as vezes trabalhamos com o que é denominado Business Process, ou processos de negócios.

Business Process (abreviados para BP, de agora em diante) dentro do Ensemble são componentes que encapsulam regras de negócios, modelados visualmente, e que para executarem código real, devem chamar outros módulos "menores". Você pode traçar um paralelo da abordagem dos BPs no Ensemble com o WS-BPEL, substituindo os Web Services por outras construções internas do Ensemble, em especial, os componentes que ele chama de Business Operations (ou BOs, pra encurtar).

De fato, o pessoal marketeiro da Intersystems até mesmo batizou a "linguagem" utilizada no Ensemble de Ensemble BPL (ou E-BPL), uma clara alusão ao WS-BPEL. Apesar do E-BPL ser bem menos complexo e completo do que o WS-BPEL (o "E" faz muita diferença, já que um Executa, e outro não), ele inclui em sua definição a notação de elementos gráficos. Neste aspecto, ele se aproxima do Business Process Modeling Notation, o BPMN.

Qualquer dia falo mais sobre a BPEL/BPMN e o Ensemble BPL, mas hoje quero me focar em algo que acontece especificamente com o BPL do Ensemble, no qual eu trabalho.

(Um BPL de exemplo, na tela de edição do Ensemble)

Como já disse diversas vezes, o Ensemble foi construído sobre o Caché (o que os marketeiros da Intersystems chamam de banco de dados pós-relacional e blá-blá), e é todo baseado nele. Por isso, herda do Caché também algumas definições, nem sempre muito explícitas. E é isso o que estava ocasionando uns erros aqui...

No BPL, podemos criar algumas variáveis no "contexto" do Business Process (BP). Essas variáveis podem ser tanto objetos como tipos básicos, e podem ser usadas para qualquer coisa.

Pois bem, um dia desses, um BP começou a dar erros, depois de eu ter adicionado um Business Operation (BO). Entretanto, nada relacionado ao BO, ele estava correto. Estava dando erro no BP mesmo.

Olhei no log de eventos do Ensemble, e logo uma linha vermelha dizia o motivo: uma variável de contexto, definida como %String, estava acusando erro de tamanho; o tamanho máximo estava definido como 50, e a string tinha tamanho superior a isso.

Como disse num post anterior, ao se definir algo como %String, o Caché/Ensemble acaba automaticamente estipulando um limite máximo pra sua string, e até nesta versão que uso (Caché 5.2, Ensemble 4.0), esse tamanho é 50.

Entretanto, isso não explicava porque o erro começara a aparecer somente depois da adição de um novo BO ao BP... Mas alguns testes depois, e tudo começou a fazer sentido.

Vejamos: Com apenas uma BO, podemos atribuir à variável um String extremamente grande, sem nenhum erro. Se você adicionar outra BO, vai dar erro. Por que?

(Assim não dá erro.)

Porque quando se usa apenas uma BO, todo o processo da BP permanece em memória. E em memória, você pode fazer quase tudo o que quiser. Até violar alguma constraint da classe, como o tamanho de um campo. Ou atribuir uma String a um campo %Date

(Assim dá erro.)

Quando você adiciona uma segunda BO, parte do processamento é gravado em disco (não sei porquê, mas suspeito que seja para "pausar" e recuperar o estado depois...). E quando se grava em disco, o Caché antes faz as checagens nos campos das classes. E isso inclui o tamanho de uma %String...

A solução? Colocar um (MAXLEN=32000) na definição da variável no contexto.


Infelizmente, no meu BP "real", esta tática não funcionou. Ao fazer isso e mandar compilar, o Caché simplesmente entrava num loop infinito e travava o Studio (pra quem não sabe, o Studio é a "IDE" do Caché/Ensemble). Não descobri o motivo ali, e como estava com pressa, contornei o bug com outra solução (ou seja, gambiarra, para os íntimos).

Entretanto, no meu BP de testes, funcionou perfeitamente... Vai entender...

sexta-feira, 25 de janeiro de 2008

Java Gateway no Ensemble e alternativas via Web Services

Já mencionei num post anterior sobre Criptografia em Caché/Ensemble, que precisei usar criptografia. Como a API do Caché/Ensemble não contemplava nem de longe o que eu precisava (e mesmo a versão mais nova - que eu não uso - contempla, apesar de ter melhorado), fui em busca de outras soluções.

Como já havia trabalhado com Java, e sabia que tinha uma boa e vasta API, pensei porque não usá-la? Vasculhando na documentação, achei o recurso do Java Gateway, do Ensemble, que nas próprias palavras da Intersystems é:

"... um jeito fácil do Ensemble interoperar com componentes Java. O Java Gateway pode instanciar objetos java externos e manipulá-los como se fossem objetos nativos do Ensemble."

Como isso acontece? Bem, o Ensemble gera alguns "proxies" para as classes Java que você quer manipular. Estes proxies são classes dentro do Ensemble, em Caché Object Script (COS), que fazem chamadas ao Java Gateway. O Java Gateway nada mais é que um conjunto de classes/objetos que fazem a comunicação entre uma JVM (máquina virtual Java) e as classes do Ensemble. Dê uma olhada na figura abaixo, que mostra como é a arquitetura dessa solução:



Se você já estudou Sistemas Distribuídos, ou tem uma noção de como EJBs trabalham, deve reconhecer o design desta solução. O que o Java Gateway faz é nada menos que um pequeno "framework" (Middleware, na realidade) de chamadas remotas. Neste caso, o cliente é dentro do Ensemble e o objeto remoto, dentro da JVM. Simplificadamente, o processo é o seguinte:

- No Ensemble, você efetua uma chamada a um método da classe proxy.
- A classe proxy serializa/transforma os parâmetros para serem enviados via TCP/IP para a instância do Java Gateway que deve estar rodando em uma JVM (não necessariamente na mesma máquina).
- As classes do Java Gateway dentro da JVM recebem uma conexão TCP/IP, identificam que é uma chamada de um método, e reconstroem os parâmetros para serem reconhecidos em Java.
- Através de reflection, fazem a chamada ao objeto Java.
- O objeto Java retorna do método, possivelmente com algum valor.
- Esse valor passa pelo processo de serialização/transformação, e é enviado via TCP/IP para o Ensemble.
- A classe proxy recebe o valor pela conexão TCP/IP, transforma o(s) valor(es) para o formato usado no Caché e retorna para quem efetuou a chamada.

Nota: o processo de formatar/transformar/serializar os dados para serem enviados via rede, e o seu inverso, na literatura de Sistemas Distribuídos é geralmente chamado de marshaling/unmarshaling.

Pois bem, a descrição de todo o processo é muito legal, muito bonita, mas a implementação de qualquer middleware não é trivial, mesmo num ambiente restrito, como é o Java Gateway (só um tipo de cliente, um tipo de objeto servidor, e outros). Por isso, a ocorrência de bugs não é de todo inesperada.

E é exatamente isso o que aconteceu: bugs, bugs e mais bugs. Utilizando o Java Gateway na mesma máquina que rodava o Ensemble (não testei com uma JVM remota), a maioria das vezes, travava tudo. Depois de uma ou duas chamadas, a máquina parava de responder. Algumas vezes, só o Ensemble, mas em outras, congelava todo o computador, de maneira que só reiniciando no dedão.

Conclusão: desisti de usar o Java Gateway. Depois de dois dias investigando sem sucesso, e sem pista do que poderia estar acontecendo, desisti (note que a classe em Java era bem simples, servindo de proxy para umas funções de criptografia, e funcionava perfeitamente bem numa JVM stand-alone). No meu caso particular, achei melhor implementar o algoritmo de criptografia nativamente em Caché Object Script.

Mas nem sempre isso é possível, ou mesmo vantajoso. Imagine implementar em COS tudo o que já foi implementado em Java ou PHP, por exemplo, em termos de bibliotecas. Impraticável.

Eis que uns tempos atrás, na lista de discussão de Caché, o Rob Tweed compartilhou uma idéia que ele teve, e que está na thread Extending Cache using PHP.

O que ele fez? Simplesmente montou uma página em PHP simples, que retornava algo do tipo:

retorno=valor

Usando a classe %Net.HttpRequest, ele estabeleceu uma conexão para a página PHP, obteve o retorno, e simplesmente fez um parsing simples de "retorno=valor" usando a função $PIECE. Um esquema bem simples.

Se você anda por dentro das últimas notícias, deve ter notado que esse esquema é bem parecido (na verdade, praticamente uma simplificação) de arquiteturas Web Services utilizando chamadas estilo REST. Implementando-se um padrão para a troca de valores (em vez de uma String customizada, um XML ou JSON), você estaria construindo a sua primeira arquitetura Web Service REST =P.

Veja que esta abordagem não se limita a utilizar PHP, podendo implementar a página web com qualquer linguagem/plataforma, passando por Java e Ruby.

E apesar de haver algumas implicações não mostradas, por exemplo, falhas na conexão, re-tentativas de acesso, segurança, etc., pelo menos você tem liberdade para cobrir quais casos se aplicam ao seu ambiente. Por exemplo, se o servidor que roda o PHP estiver na mesma máquina que o Caché/Ensemble, não precisará lidar com falhas de conexão. No caso de uso do Java Gateway, você provavelmente também lidará com essas implicações, a diferença é o nível de controle que você terá, bem menor. E claro, estará sujeito a bugs que você provavelmente não terá como de lidar/corrigir.

Ainda no espírito de Web Services, o Caché provê algum suporte ao que se convencionou chamar de estilo ou stack WS-*, que utiliza padrões mais robustos, e consequentemente mais complexos (WSDL, UDDI, WS-Security, entre outros). Para problemas simples, talvez seja pedir demais, mas a idéia permanece a mesma: extender as capacidades do Caché/Ensemble usando invocações de provedores externos.

Conclusão: para extender as capacidades do Ensemble, prefira outras alternativas, como a utilização de Web Services, do que o uso do Java Gateway. Como o Java Gateway também cria um processo separado para a execução da JVM, não existem ganhos significativos em relação ao uso de um outro servidor leve, como por exemplo, um Tomcat. Em suma, talvez o Java Gateway tenha servido há algum tempo atrás, mas hoje em dia, deve ser usado somente em caso de código legado que faça uso deste.

Em tempo: a versão nova do Ensemble parece não ter novidades em relação ao Java Gateway, pelo menos não encontrei nada olhando a documentação da nova versão.

quinta-feira, 10 de janeiro de 2008

SQL Adapter no Ensemble - probleminha

Faz tempo que não posto nada, mas hoje vi algo que me fez postar.

Até agora, usando o Ensemble da Intersystems, não havia ainda precisado usar um adaptador de entrada SQL (ou no original em inglês, um SQL Inbound Adapter). OK, estou indo muito rápido no assunto. Se você já conhece a estrutura do Ensemble, pule os dois parágrafos abaixo.

O Ensemble é uma ferramenta que serve como várias coisas, entre elas Enterprise Service Bus (ESB) (assim ele é vendido pelo pessoal de marketing, mas você deve conhecer o pessoal de marketing...), mas é mais tipicamente um Enterprise Application Integration (EAI) (uma abordagem mais realista do produto). O que ele basicamente faz é servir de "ponte" para que dois ou mais sistemas possam se comunicar. E eles podem se comunicar de diferentes maneiras, desde troca de arquivos e tabelas de banco de dados, até interfaces mais "modernas", como mensagens SOAP (com Web Services), etc... Como cada sistema tem uma interface de comunicação, o Ensemble provê adaptadores (ou Adapters no original), que são interfaces entre os diferentes tipo de protocolos/estilos de comunicação e o ambiente interno do Ensemble.

Por exemplo, você pode ter uma aplicação legada que produza somente arquivos texto como saída, e quer fazer uma espécie de "mashup" desses arquivos com dados de outro sistema, que persiste as suas informações num banco de dados, e exibir a saída dessa "mistura" num XML via Web Service. Neste caso, pode-se usar o Ensemble com um Adapter de arquivo, para conversar com a aplicação legada, um Adapter SQL para conversar com o banco de dados, e um Adapter SOAP para exibir o resultado em XML.

Voltando ao assunto principal do post...

O Adapter SQL permite que se coloque uma consulta SQL, que executa de tempos em tempos, e ele "aciona" outro componente do Ensemble (um Business Service), enviando cada linha da consulta retornada.

É uma boa idéia, mas como de costume, alguns problemas apareceram...

Pra começar, vamos ver uma parte da classe do Adapter SQL:

Class EnsLib.SQL.InboundAdapter 
Extends (Ens.InboundAdapter, EnsLib.SQL.Common)
[ ClassType = "", ProcedureBlock ]
{

/// The Base query string that will
/// be repeatedly executed to look for new rows
Property Query As %String [ Required ];

...


A propriedade Query, um %String, guarda a consulta SQL que será executada. Entretanto, não é qualquer consulta que pode ser realizada. Veja a consulta abaixo:

SELECT id_tabela, campo1, campo2 FROM grande_tabela WHERE algum_campo <= 10

Supondo que a tabela mencionada exista, bem como os campos, essa consulta deveria funcionar. Entretanto, observe o que acontece quando se tenta colocar a consulta na configuração do Adapter:


Depois de pesquisar um pouco, vi que o problema estava na classe do Adapter SQL. Note que a propriedade Query foi definida como %String. Entretanto, o que pode não ser tão visível é a restrição que isso impõe. Ao se definir uma propriedade como %String, automaticamente é estipulado também um tamanho máximo que aquela String poderá conter. Caso você não defina manualmente, o Caché/Ensemble usa um valor padrão, no caso, 50. Como a consulta acima tem mais de 50 caracteres, acontece o erro mostrado na figura.

Para reparar esse "erro", abri a classe, alterei o código fonte (só acrescentei um parâmetro na propriedade, mostrado abaixo) e recompilei. E pronto!

Class EnsLib.SQL.InboundAdapter 
Extends (Ens.InboundAdapter, EnsLib.SQL.Common)
[ ClassType = "", ProcedureBlock ]
{

/// The Base query string that will
/// be repeatedly executed to look for new rows
Property Query As %String(MAXLEN = 500) [ Required ];

...


UPDATE1: Esqueci de mencionar que isso foi feito na versão 4 do Ensemble, a que utiliza o Caché 5.2. Não tenho, nem testei a versão mais nova (2007.1) pra ver como se comporta.

UPDATE2: Aqui vai o link para um pdf sobre SQL Adapters. Apesar de ser para a versão mais nova do Ensemble, muita coisa vale para a versão mais antiga: Using SQL Adapters with Ensemble - version 2007.1.2

quarta-feira, 28 de novembro de 2007

Entrevista de Emprego

Um ótimo texto sobre carreira e entrevistas de emprego, visto no Teorias Cobalísticas, creditado ao grande Max Gehringer:

Quem mandou perguntar?

Há anos, com a coloboração de colegas recrutores de pessoal, eu venho colecionando respostas reais dadas por candidatos a emprego. Mas só recentemente descobri que a coleção pode ter a finalidade prática de confortar os aflitos. Quando alguém diz: "Não sei, acho que fui mal na entrevista", e aí vê essas preciosidades verbais, percebe que não foi tão mal assim. Alguns exemplos:

Entrevistador - E então, você está construindo uma networking?
Candidato - Veja bem, eu não sou engenheiro, sou administrador.

Entrevistador - Como você administra a pressão?
Candidato - Ah, tranqüilo. 1 por 7, no máximo 12 por 8.

Entrevistador - Manter sempre o foco é muito importante. E me parece que você tem alguns lapsos de concentração.
Candidato - O senhor poderia repetir a pergunta?

Entrevistador - Como você se sente trabalhando em equipe?
Candidato - Bom, desde que não tenha gente dando palpite, me sinto muito bem.

Entrevistador - Como você se definiria em termos de flexibilidade?
Candidato - Ah, eu faço academia. Sou capaz de encostar o cotovelo na nuca.

Entrevistador - Nós somos uma empresa que nunca pára de perseguir objetivos.
Candidato - Que ótimo. E já conseguiram prender algum?

Entrevistador - Vejo que você demonstra uma tendência para discordar.
Candidato - Muito pelo contrário.

Entrevistador - Em sua opinião, quais seriam os atributos de um bom líder?
Candidato - Ah, são várias coisas. Mas a principal é ter liderança.

Entrevistador - Noto que você não mencionou sua idade aqui no currículo.
Candidato - É que eu uso óculos, e isso me faz parecer mais velho.
Entrevistador - E qual é a sua idade?
Candidato - Com óculos ou sem óculos.

Entrevistador - Quais seriam seus pontos fracos?
Candidato - Ah, é só o joelho. Até tive de parar de jogar futebol.

Entrevistador - Há alguma pergunta que você queira me fazer?
Candidato - Eu parei meu carro aí na rua. Será que eu vou ser multado?

Entrevistador - Por que, dentre tantos candidatos, nós deveríamos contratá-la?
Candidato - Eu pensei que responder a isso fosse seu trabalho.

Entrevistador - Como você pode contribuir para melhorar nosso ambiente de trabalho?
Candidato - Bem, eu começaria trocando a recepcionista, que é muito feia.

Entrevistador - Quando digo "sucesso" qual é a primeira palavra que lhe vem à mente?
Candidata - Pode ser duas palavras?
Entrevistador - Pode
Candidato - Milho. Nário.

Entrevistador - Várias pessoas que se sentaram aí nessa mesma cadeira hoje são gerentes.
Candidato - Puxa, o fabricante da cadeira vai ficar muito feliz em saber disso.


Tentei verificar se esse texto é mesmo de autoria do Mr. Max (em tempos de Internet, o que mais se vê é texto creditado erroneamente), mas o máximo que consegui foi esta página, creditando o texto ao Max Gehringer, e dizendo que fora publicado na revista Exame.

segunda-feira, 26 de novembro de 2007

Listas em Cache - problemas

Como eu já havia comentado no post anterior, e o comentário do Carlos reforçou, ao se usar listas ou arrays do Caché, temos o problema do tamanho destas. Como o Carlos bem falou, quando estamos inserindo itens numa lista em memória, tudo ocorre bem. O problema é quando vamos salvar a classe que mantém essa lista.

Por que disso? A resposta passa por como o Caché persiste os objetos. No post anterior comentamos que as listas/arrays são do tipo serial, herdando de %SerialObject. Isso quer dizer que elas vão "embutidas" dentro de outros objetos ao serem persistidas, ou seja, essas classes não têm um ID próprio.

Olhem como fica um objeto persistido da classe que o Carlos passou no comentário, contendo no exemplo abaixo, uma lista com dez elementos:

^Teste.EstouroD(1) = $lb("",11,$lb(1,2,3,4,5,6,7,8,9,10))

Note como a lista vai "serializada" dentro da classe. Como no Caché um objeto persistido é na verdade um valor numa global, e valores nas globais são basicamente grandes Strings, ficamos limitados a objetos menores que 32Kb no total, já que esse é o limite de uma String (pelo menos até a versão 5.2).

Se tivermos uma classe com muitas propriedades, e cada propriedade for muito grande, se esse objeto for serializado dentro de uma lista, o tamanho da lista vai ficar ainda mais enorme. Nestes casos, vale a pena deixar a classe persistente, assim na lista vão ficar guardados os IDs dos objetos, e não os objetos em si serializados.

De qualquer jeito, se a sua lista contiver muitos valores, o erro deve persistir. Nestes casos, o negócio é abandonar um pouco a abordagem OO e partir para gerenciar dados nas globais mesmo.

P.S. Em outro comentário, o Carlos fala sobre o %System.Encription, pra resolver os problemas em relação a criptografia em Caché. Realmente, eu não tinha visto essa classe, e o help não ajudou muito, pq eu havia procurado pelo DES, e a classe só tem suporte para o AES (considerei o DES como sendo o menor denominador comum em casos de criptografia, por ele ser um dos mais antigos, bem documentados e relativamente fácil de implementar).

No caso, o AES não iria adiantar, porque no lado cliente, só tinhamos suporte pro DES. Mas, fica aqui a dica.

quarta-feira, 14 de novembro de 2007

Não se trata disso

Resposta genial, ilustra muito bem a sociedade e o tipo de educação que temos hoje em dia, retirado do blog Circuito Integrado da Folha:

Cerf estava em uma conversa, digamos, mais animada com um dos participantes da mesa, que argumentava que o Google deveria filtrar o conteudo usando a qualidade e credibilidade como criterios tambem.

"O Google nao se trata disso", disse Cerf.

"Mas para meu filho de nove anos o Google eh a verdade, ele diz: esta no Google", --rebateu o palestrante.

"Entao o problema nao eh com o Google, eh de criacao", rebateu Cerf, para aplausos de partes dos presentes e constrangimento de outros."


(Velhinho esperto - foto retirada da biografia no ICANN)

Só pra constar, Vinton Cerf é um dos vice-presidentes do Google, e um dos criadores do TCP/IP, que é uma das bases da Internet, ou seja, que possibilita vc ler isso agora.

sábado, 3 de novembro de 2007

Listas em Cache

Listas em Caché - abordagem orientada a objeto

Ao contrário do Java, no Caché da Intersystems não temos uma grande API quando se trata de estruturas de dados de coleções (listas, filas, conjuntos, árvores, etc). De fato, quando trabalhamos com orientação a objeto no Caché, basicamente existem dois conceitos de coleção: as listas e os arrays.

Vamos verificar então o que listas e arrays significam para o Caché. Listas são, como o nome bem indica, listas de objetos (como aqueles que você escreve) ou de tipos básicos (como %Integer ou %Float). Cada elemento de uma lista é associado a uma posição da lista. Neste caso, listas em Caché são bem parecidas com listas em Java (em termos de interface, de implementação não dá pra comparar bem, já que em Java podemos ter listas como ArrayList ou LinkedList.

Em Caché, a classe abstrata %Collection.AbstractList fornece a interface básica pela qual podemos trabalhar com listas. Adaptada da documentação, o código abaixo ilustra a criação de uma lista, quatro inserções de elementos nesta lista, e como podemos percorrer a lista, recuperando seus elementos:


; instancia nova lista
Set list=##class(%ListOfDataTypes).%New()
; adiciona quatro elementos na lista
Do list.Insert("DArtagnan")
Do list.Insert("Athos")
Do list.Insert("Porthos")
Do list.Insert("Aramis")
; percorre a lista
For i=1:1:list.Count() Write list.GetAt(i),!



Arrays no Caché, por outro lado, são bem diferentes do que o nome pode sugerir (pelo menos pra mim, que vim de linguagens como Java, Pascal, C/C++). Arrays do Caché são como objetos da interface Map do Java, eles necessitam além do elemento a ser guardado na estrutura (objeto ou tipo básico de dados), uma "chave" associada, para você acessar o elemento. Essas estruturas são muito úteis ao implementar coisas como tabelas de Hash, assim como a Hashtable.

Nada melhor que um exemplo para esclarecer, por isso vamos ver o exemplo adaptado da documentação da classe %Collection.AbstractArray, que serve como interface para as classes de array no Caché:

; instancia um objeto array 
Set arr=##class(%ArrayOfDataTypes).%New()
; coloca itens no array - o segundo parâmetro é a "chave"
Do arr.SetAt("red","color")
Do arr.SetAt("large","size")
Do arr.SetAt("expensive","price")
; iteração no array
Set key=""
For Set value=arr.GetNext(.key) Quit:key="" Write key,":",value,!



(Notem que o método SetAt, correspondente ao put do java.util.Map, tem os parâmetros invertidos com relação a este, enquanto no put a chave vem como primeiro parâmetro, no SetAt a chave vem no segundo.)

Em ambos exemplos acima, usamos tipos de dados básicos como elementos nas lista e array, mas poderíamos ter usado objetos. Para isso, ao invés de termos usado %ListOfDataTypes e %ArrayOfDataTypes, usaríamos %ListOfObjects e %ArrayOfObjects, respectivamente.

Quando usamos coleções como propriedades de classes, podemos ou declarar a propriedade explicitamente como objeto das classes de Array/List (como faríamos como qualquer outra classe), ou então podemos declarar assim:


; uma lista de %Strings:
; em vez de: Property Colors As %ListOfDataTypes
Property Colors As List Of %String


Vale lembrar que esses objetos arrays e lists são do tipo Serial, ou seja, herdam de %SerialObject, e que portanto vão "serializadas" dentro de outra classe, se forem persistidas. Se a sua lista for muito grande, ou mesmo que a lista não tenha muitos elementos, mas os seus elementos sejam %SerialObject, pode ocorrer um erro de MAXSTRING.

Considere a classe abaixo:


Class Teste.Estouro Extends %Persistent [ ClassType = persistent ] {

Property lista As list Of %String;

ClassMethod teste(qtde as %Integer)
{
set a = ##class(Teste.Estouro).%New()
w a.%Save()
For i=1:1:qtde {
do a.lista.Insert(i)
}
w a.%Save()
}
}


Experimente chamar de uma janela de terminal o método teste, passando diferentes valores. Ao se passar uns 10000, você já pode conferir o erro de MAXSTRING. Lembrando que isso vale para versão 5.2 do Caché. Ouvi dizer que na versão 2007, o limite de tamanho de Strings aumentou, então esse tipo de erro deve ocorrer menos frequentemente, mas não cheguei a verificar na documentação isso.

quarta-feira, 31 de outubro de 2007

Dicas de como fazer um bom curriculo

Originalmente iria postar só no outro blog, mas achei que valia apena postar aqui tb.

E aproveitando o embalo das tirinhas trabalhadores (assunto do outro blog), mais um post sobre o duro mercado de trabalho, aquele que a gente faz pra ganhar o leitinho (esperamos que não adulterado) para as crianças XD.

Desta vez, umas dicas para quem está precisando fazer ou atualizar o currículo. O texto abaixo foi retirado da revista Você S/A do mês passado, setembro de 2007. Se você não lê, eu aconselho, é uma das poucas revistas (tirando os meus quadrinhos/mangás, claro) que eu compro na banca.

Bem, esse post foi inspirado mesmo na folha online, que coincidentemente deu essas dicas, que também ajudarão a você formar um currículo nota dez (e se graças a isso ganhar um empregão, eu aceito um presentinho =P):


Então, sem mais delongas, aqui vai:

O currículo certo e o errado

Saiba como evitar os problemas que podem tirar o seu nome da disputa por uma vaga antes mesmo da entrevista
Por Françoise Terzian

Passar para a segunda fase de um recrutamento que começou com a seleção de currículos requer atenção a detalhes. Fotos inadequadas, português errado e letras coloridas chegam a derrubar um em cada quatro currículos enviados por candidatos a uma vaga. "Recebemos 180 000 currículos ao ano e 25% deles são descartados por ser muito longos ou conter erros gramaticais", diz Augusto Costa, diretor- geral da Manpower no Brasil. A consultoria de recursos humanos, de São Paulo, atende empresas como Motorola e Michelin. Aqui, Augusto e outros especialistas em recrutamento apontam quais são os sete erros fatais de um currículo. Sem eles, suas chances de conseguir a vaga aumentam. Veja, abaixo, exemplos resumidos de um currículo bom e de outro ruim.

(Um currículo bem feito)

(E outro nem tanto - veja as dicas abaixo)

EVITE

FOTOS E RG
  • Só mande foto (3x4 comportada, claro) se isso for pedido por quem está fazendo a seleção. "E nunca inclua o número do RG e CPF no currículo", diz Mara Turolla,consultora da Career Center,empresa de recolocação.

POLUIÇÃO VISUAL
  • Nada de firulas: a melhor apresentação são folhas brancas simples e fontes Arial ou Times New Roman — mais clássicas.

ERROS DE PORTUGUÊS
  • São os mais comuns — como os que estão marcados em amarelo ao lado — e podem reprovar um bom candidato. "Demonstram que ele foi desleixado.Ou que não sabe escrever", diz Augusto, da Manpower.

FALAR DIFÍCIL
  • Informações demais fazem o selecionador gastar tempo — e a média que eles dedicam a um currículo é 40 segundos. Não vá escrever que fez curso de datilografia, tampouco. "Prolixidade mascara as informações relevantes", diz Alexandre Ullmann, gerente de recrutamento da CPM Braxis, empresa de tecnologia da informação.

MENTIRAS
  • Há quem diga que concluiu um curso sem ter realmente chegado ao fim. Vale o mesmo para dizer que é fluente em inglês. Por fim, errar nas datas de permanência nas empresas acaba levantando suspeitas do entrevistador.

FALTA DE FOCO
  • Realce seus resultados numéricos mais do que as tarefas que você desempenhava. Em vez de "analisava as estratégias de marketing", use "elevei as vendas da empresa em 15% após analisar a concorrência".

DESTACAR O INÍCIO DA CARREIRA
  • Deixar os últimos empregos para o fim pode fazer seu currículo ser descartado prematuramente.As informações devem vir em ordem decrescente."Se sua carreira for muito longa, saliente os cargos mais recentes", diz Augusto Puliti, gerente da consultoria Michael Page.

...Fim da matéria

Não deixem de ler a Você S/A. E não, não estou ganhando nada pra fazer essa propaganda. XD

P.S. No título a palavra 'currículo' está sem acento, pro blogger não comer o 'i' da palavra no link que ele gera.

segunda-feira, 29 de outubro de 2007

A falta que um ROWNUM faz...

Hoje precisava calcular a média de um campo dentro de uma tabela no Caché, da Intersystems. A lógica era até bem simples: eu precisava ver a média dos preços das últimas N compras, depois de uma certa data.

O Oracle tem a pseudo-coluna ROWNUM, o que facilita bastante. Num SQL do Oracle, eu teria algo parecido:

SELECT AVG(PRECO)
FROM COMPRAS
WHERE DATA > '01/01/01' AND ROWNUM <= 20
ORDER BY DATA DESC


Neste exemplo simples, estamos pegando a média dos preços das 20 últimas compras, efetuadas depois do dia 01/01/01. Bem simples, não?

Fui procurar algo parecido no Caché, mas não encontrei nada. Bem, tem algumas coisas, como o nro de linhas retornadas numa consulta, ou mesmo o TOP, usado no SELECT. Infelizmente, nenhuma solução apareceu, então resolvi fazer um cursor (ou poderia tb ter feito um ResultSet, se quisesse), e iterar pela consulta e calcular a média 'na mão'.

Bem, a consulta ficou mais ou menos assim:

SELECT TOP 20 PRECO
FROM COMPRAS
WHERE DATA > '01/01/01'
ORDER BY DATA DESC


Notem o 'TOP 20', que diz que a consulta só precisa me retornar os 20 primeiros resultados. Infelizmente, não dá pra usar no WHERE, que é onde eu precisaria, para executar a função agregada de média, AVG.

Não vou descrever como eu fiz para iterar na consulta com cursor, e calcular a média, até porque isso é relativamente fácil, e eu já estou muito cansado hoje.

Fui.