quinta-feira, 28 de fevereiro de 2008

Nova propaganda para o Caché

Olhem a imagem da propaganda do Caché...


E você, meu caro desenvolvedor, cansado das tabajarices que encontra no Caché? Cansou de ouvir o pessoal de marketing dizendo 'bla bla bla', e você encontrar só bug? Não, não é bug. É feature.

Pois esta é a imagem que reflete melhor o que eu tenho encontrado:



Imagem via UsuárioCompulsivo, neste post: Não é bug... É recurso.

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...