quinta-feira, 22 de setembro de 2016

User Controls

Existem alguns temas que parecem tão complexos e obscuros que afugentam a grande maioria das pessoas, como se fosse uma selva sombria e úmida. Os poucos que desbravam esta densa vegetação, creio que em busca de uma aventura, acabam como heróis por sua coragem, desprendimento, e principalmente por encontrar as riquezas ocultas.

Esta era minha a sensação quando se falava User Control, um tema oculto e destinado apenas aos mais destemidos, que, sendo sincero, nunca tive muita intenção de abraçar, mas que ao mesmo tempo aguçava demasiadamente a minha curiosidade, e claro admiração.

Acontece que novos caminhos levaram a uma trilha na qual, o que se via a frente era apenas esta densa floresta, e nenhum desvio, a não ser a única opção de ingressar literalmente no meio do mato.

Trilhando um novo caminho

Com o advento do Abstract Editor o que pudemos observar foi que o pouco de HTML que poderíamos recorrer quando o calo apertava, simplesmente foi ocultado em um novo nível de abstração, que simplesmente deixou de aceitar baixarias, ou melhor, 'baixo nível'.

O mesmo editor também causou um bom incômodo, por nos permitir criar as tais maravilhosas interfaces responsivas, porém, com parcos recursos. Até o momento, sem o Work With for Web não saímos do lugar.

Foram muitos artigos aqui no Genexando nos quais apresentávamos algumas formas de produzir conteúdo HTML + CSS na interface, como, por exemplo, textblock.caption, mas mesmo isto, apesar de ser possível, não parece mais ser uma solução elegante e consistente no modelo atual. Nada contra este recurso, ainda o utilizo, mas que tal buscarmos algo novo?

O pior é que a solução para estas questões já estava disponível desde 2007, sob o nome de User Control, a única coisa que faltava era uma boa documentação.

User Control

No meu humilde ponto de vista, User Control acaba de ganhar muita importância neste novo cenário, pois, de repente, nossos recursos foram limitados basicamente aos Common Controls do Toolbox.

A razão é simples, nenhum (ou quase nenhum) User Control atualmente publicado no Marketplace está preparado para o cenário da responsividade. Encontram-se ainda sob a ótica das interfaces Web tradicionais, e vão exigir, no mínimo uma boa revisão por parte dos nossos heróis desbravadores.

Os User Controls também oferecem uma forma muito mais elegante para resolvermos a questão do uso de recursos para construirmos interfaces convincentes, que são as excelentes bibliotecas externas em Javascript que diariamente nos entregam novas funcionalidades, e que caberiam muito bem aos nossos projetos.

Desta forma, com a motivação adequada e certo de que poderíamos sair vivos desta selva, buscamos a ferramenta adequada para enfrentarmos o desconhecido. E o resultado desta aventura, também se mostrou um enorme desafio.

O que é um User Control?

Dificilmente você não utilizou um User Control, é quase impossível uma interface GeneXus sem pelo menos um deles. Porém, em termos estruturais, acredito que pouca gente conheça que é um pequeno projeto de um componente de interface, no qual definimos suas configurações de instalação,  aparência no GeneXus e funcionalidade no navegador do usuário. No mínimo teremos sempre quatro arquivos para registrar todas estas características.

Uma vez construído e instalado, teremos o recurso à nossa disposição no Toolbox do objeto GeneXus. Ou ainda, na propriedade Control Type de atributos e variáveis.

O objetivo fundamental será sempre o de oferecer algum recurso visual ou funcional diferenciado na interface do usuário, e que pode ser um novo controle para ingresso de dados, novos componentes de navegação como menus, navbar, dropdowns, ou mesmo recursos para controlar as ações dos usuários.

Para chegarmos a isto necessitaremos conhecer novos recursos como a linguagem Javascript, CSS, HTML, XML e XSLT. Mas também bibliotecas externas que eventualmente nos forneçam o recurso que desejamos implementar. Além dos próprios arquivos de configuração.

Não é necessário ser um programador profissional destes recursos para se alcançar resultados excelentes, veja meu caso, por exemplo, rs.

User Control: Construindo controles com o GeneXus


Como estratégia de aprendizagem deste tema peculiar, praticamente tive que ler e interpretar o funcionamento da grande maioria dos User Controls do Genexus Marketplace, entender suas semelhanças e diferenças, e em seguida buscar uma explicação plausível para seu comportamento.

A intensa programação Javascript por muitas vezes ocultavam importantes segredos, assim como as classes CSS que quando em funcionamento também não respondiam a contento, enfim, um cenário muito desafiador.

O Genexus Wiki, uma fonte importantíssima de informação, desta vez não contribuiu muito.

Ao final foi simples chegar a uma conclusão: o tema é muito importante para ficar escondido no mato.  E como resultado desta aventura, resolvi escrever um livro sobre este tema desafiador, principalmente porque o pouco material disponível praticamente pouco me ajudou.

A idéia por traz do livro foi simples: dividir os temas mais complexos em tópicos e apresentar muitos exemplos práticos para reforçar todo conteúdo apresentado. Com isso chegamos a onze capítulos que vão apresentar e desenvolver todos os recursos necessários para se construir seu próprio User Control. E ao término de cada um, uma atividade prática com o objetivo de desenvolver um controle útil com o recurso Bootstrap, ou seja, o mesmo framework utilizado pelo GeneXus para construir as interfaces responsivas.

Um detalhe, não abordo no livro User Controls para Android e iOs, nesta edição limitei a controles para Web.

Então, se você também sofrer da mesma doença: usercontrolitis curiositis, terá a sua disposição um material que eu acredito, irá te ajudar nesta aventura.

Disponível aqui:

https://www.amazon.com.br/User-Control-Desenvolvendo-controles-GeneXus-ebook/dp/B01LZT1NX7/ref=sr_1_5?ie=UTF8&qid=1474121129&sr=8-5&keywords=user+control

https://www.amazon.com/User-Control-Desenvolvendo-controles-Portuguese-ebook/dp/B01LZT1NX7/ref=sr_1_7?s=books&ie=UTF8&qid=1474120886&sr=1-7&keywords=user+control#nav-subnav



quinta-feira, 7 de julho de 2016

Stop o Post

Desculpem o trocadilho, mas a piada já estava pronta, não resisti, e no final das contas STOP e POST combinam perfeitamente com o assunto que eu quero abordar, e, incrível, possuem exatamente as mesmas letras.  Enfim é necessário PARAR um pouco para pensar no POST.

Postando coisas

Existe uma característica nos sistemas Web que permite que tenhamos um excelente mecanismo de persistência nas chamadas ao servidor que consiste no simples ato de colocar uma variável na interface. Parece pouco, mas ao fazermos isso estamos fazendo com que diversas chamadas para a mesma interface mantenha uma informação persistente. Por exemplo, se colocarmos o código de um produto em uma variável na interface, se o usuário pressionar um botão Confirmar, por exemplo, o conteúdo desta estará disponível ao evento de usuário, Refresh e Load do nosso programa Genexus, sem que tenhamos que nos preocupar em buscar alguma coisa no banco de dados, por exemplo.

Esta é uma característica de um formulário Web, e toda interface Genexus é um FORM por natureza, se você olhar no código fonte suas páginas encontrará uma linha que define o mesmo.

<form id="MAINFORM" name="MAINFORM" method="post" ... >

Aliás POST é uma palavra muito bem escolhida pelo Tim Berners-Lee  para representar o que acontece quando o botão Confirmar é pressionado, alias vamos abrir um parenteses aqui, porque graças a ele temos emprego hoje, rs. Mas enfim, o Tim pensou no seguinte, vou montar uma agência de correio no navegador do usuário e simplesmente enviar um pacote do tipo SEDEX para o servidor toda vez que ocorrer um Confirmar, e o que tem dentro deste pacote? todas as variáveis da sua interface e seus conteúdos, e o tal Confirmar (para nós) é o tal Submit para o Tim.  Isso é o tal POST.

Neste ponto ele foi categórico ao afirmar que tudo que estiver na interface em forma de variável deverá ser incluído, humm, parece meio radical, mas no final das contas não temos como dizer ao navegador para não incluir alguma coisa que eventualmente não desejamos neste pacote.

Enfim, se tudo que é definido na interface em formato variável é devolvido ao servidor no POST então deve haver alguma diferença no tamanho do tal pacote caso tenhamos uma única e singela variável ou uma duzia delas na interface não? E este é o ponto que precisamos parar pra pensar, porque ao colocarmos uma duzia de variáveis na interface estaremos aumentando o preço do SEDEX, pois como sabemos uma carta simples de até 60g custa apenas um selinho de R$ 1,70, mas um pacotão de 500g vai custar R$9,10, e claro, neste mundo capitalista, tudo custa alguma coisa para alguém, inclusive o passe gratuito de ônibus para os estudantes do Passe Livre.

Onde está o custo das coisas?

Nosso programa Genexus roda no servidor correto? na interface do usuário roda o resultado do processamento deste programa, correto? Então temos duas fases na qual ocorrem processamentos, no servidor em primeiro lugar e em segundo lugar no navegador do usuário. Vou recorrer a um desenhinho (meio tosco) para mostrar isso.



  1. Neste esquema o usuário solicita alguma coisa ao servidor (1), neste caso temos a latência da internet que atrapalha um pouco e vai consumir alguns segundos para que seu pedido chegue. 
  2. O servidor, quando recebe alguma tarefa, dispara o processamento da mesma (2), e eventualmente ocorrerá chamadas ao banco de dados (3) para que alguma informação adicional seja adicionada. Teremos aqui diversos elementos que contribuirão no custo, desde a capacidade do servidor (memória, processador), como também a quantidade de pedidos que o mesmo responde por segundo, pois muita gente poderá estar solicitando coisas simultaneamente, e todas devem ser processadas para serem devolvidas. Mais pedidos simultâneos, mais consumo de recursos do servidor e eventualmente mais problemas de desempenho desta infra-estrutura.
  3. Ao término do processamento começa o processo da agência de correios, pois o servidor montará um pacote para enviar ao navegador, e claro, poderá ser um pacote pequeno ou grande de acordo do que foi programado, ao término da montagem o mesmo é enviado ao navegador (4). Se tínhamos uma latência no item (1) teremos a mesma amplificada pelo tamanho do pacote na fase (4), portanto, se diminuirmos ao máximo esta resposta, será melhor, pois vamos chegar próximo ao tempo minimo que é exatamente o tempo da solicitação (1).
  4. No navegador teremos que pegar o pacote recebido pelo servidor e processá-lo para transformar numa imagem a ser apresentada para o usuário (5)  e se tudo estiver certinho, a mesma será apresentada na interface (6). Aqui os desenvolvedores normalmente não se preocupam muito, mas se o usuário estiver rodando um Windows XP com 2Mb de memória RAM, o desempenho da interface no navegador Nestcape vai ficar bem ruinzinho, se a coisa for muito complexa para a maquininha resolver.


O segredo de um bom desempenho até aqui é diminuir ao máximo o tamanho do pacote entre o navegador e o servidor, pois com isso poderemos melhorar todos os pontos, pois menor resposta = menor necessidade de processamento, menor tamanho do pacote, enfim, o Steve Jobs já falou isso e alguns ouviram, a simplicidade é tudo.

Bom, vamos ao problema. Acontece que se pegarmos o POST do Tim, e colocarmos na equação teremos algo 'a mais', pois, quando retornarmos ao servidor, passo (1), quando pressionarmos Confirmar vai acontecer que ao tempo de latência anteriormente avaliado agora teremos que colocar também a montagem do pacote no navegador e a transmissão do mesmo ao servidor (1), além da necessidade de processar o pacote recebido na execução do script (2).

Pacotes do Genexus

Considerando que você tem usado o Genexus de forma regular e normal, com seus controles Attributes, Grids e FreeStyleGrids, ..., e de vez em quando reclama do desempenho da coisa, preciso te informar uma coisa, o problema talvez não esteja na sua lógica, na lógica do Genexus de criar queries para o BD, ou mesmo programar C# e Java, mas exatamente na sua interface.

E sabe porque? imaginemos um Grid na interface contendo um conjunto de 10 variáveis, a respeito de seu cadastro de clientes, e ainda, a pedido do usuário, apresentemos 200 registros de clientes ao mesmo tempo. Teríamos um pacotinho formado por 10 x 200 x o tamanho em bytes de cada variável, a ser processada no servidor e enviada ao navegador. E.... do navegador ao servidor quando você pressionar algum evento do tipo POST. Ou seja, a informação em formato variável na interface será devolvida ao servidor no POST, e nosso grid pesadão vai também ser enviado ao servidor de volta, e sabe porque? somente para voce ter um for each line in GRID.

Desta forma,, temos a beleza do comando for each line denegrida pela queda significativa de desempenho necessário para que a informação da interface seja devolvida ao servidor. Fazer o que, como falei antes não existe passe de ônibus livre.

Testando

Se você tiver um programa que te apresente um timeline com o tempo de resposta do servidor, normalmente os navegadores atuais dispõem de um recurso assim, poderá, construindo um webpanel com um Grid cheio de coisas, medir o tempo gasto na chamada GET e posteriormente na chamada POST.

Construindo uma interface de testes é simples, escolha uma tabela que contenha muitos registros, e monte um GRID recuperando um conjunto significativo deles. Em seguida faça variações neste GRID para diminuir o que será devolvido ao servidor.

Caso 1) Montei um webpanel simples com um GRID utilizando atributos com 10 colunas e 500 registros e obtive os seguintes tempos de resposta.

tempoenviadosrecebidos
1o GET01.46766729.882
2o GET01.01563129.827
3o GET
01.019
63129.827
1o POST
01.086
196.09828.605
2o POST01.038196.85828.605
3o POST01.049196.85828.605

Caso 2) O mesmo conjunto de colunas, mas desta vez montando o mesmo GRID com variáveis.

tempoenviadosrecebidos
1o GET03.499631    46.311
2o GET03.02263146.311
3o GET03.06463146.311
1o POST03.025136.44744.244
2o POST02.942137.56444.244
3o POST02.906137.56444.244


Já é possível perceber o problema quando se olha as linhas GET e POST em ambos os testes. A coluna enviados mostra bem que no POST as informações que estão no navegador são enviadas ao servidor.

Um detalhe interessante é que com variáveis o Genexus produz mais código, aproximadamente 54% maior.

O tempo também é influenciado, ou seja com atributos é menor, minha teoria para isso é a necessidade das alocações no Genexus, para se atribuir cada variável e se executar o LOAD acaba gastando mais recursos de processamento.

Normalmente nos preocupamos com a primeira carga da interface, mas se você observar, o envio da informação ao servidor a partir desta primeira carga é que pesa.

O que fazer?

Diminua sua interface, use menos variáveis, não utilize o GRID.
Não deixe o Automatic Refresh ligado, ao invés disto prefira um botão para realizar a filtragem dos registros.
Não carregue Grids com informações 'default', ou seja, aguarde a pessoa definir o que deseja ver.



Os dados que alcançamos são meio estranhos, e cabe um estudo mais aprofundado para identificar porque os POSTs são exageradamente grandes. Os tempos também sofreram influência, apesar dos pacotes terem dimensões parecidas, enfim, precisaremos abordar a questão em um outro artigo.


Por enquanto, recomendamos juízo no POST.






quarta-feira, 6 de julho de 2016

MathML

Precisa expressar alguma função matemática? Conhece o MathXML?

Pois é, acabei esbarrando por acaso nesta notação e gostei bastante do resultado. Como temos muitos professores que utilizam Genexus, vamos dar uma palhinha neste assunto.

O que é?

O MathML é uma linguagem de notação que resulta em uma imagem que normalmente é utilizada para produzir uma expressão matemática. De maneira geral,

A organização que está apoiando a iniciativa é o W3C, ISO, ou seja, é um assunto sério. Ver:


Esta linguagem é dependente dos navegadores que devem implementar a interpretação das definições da especificação.

Como usar em Genexus

Será necessário produzir um conteúdo HTML para apresentar a fórmula matemática, uma forma de fazer isso em Genexus é incluir no Caption de um Textblock.  Utilizamos uma variável &expressao do tipo Character(100) para criar a expressão.

Event Start
 &expressao   = '  <math xmlns="http://www.w3.org/1998/Math/MathML">'
 &expressao  += '    <mrow>'
 &expressao  += '      <mi>a</mi>'
 &expressao  += '     <mo>⁢</mo>'
 &expressao  += '      <msup>'
 &expressao  += '        <mi>x</mi>'
 &expressao  += '        <mn>2</mn>'
 &expressao  += '      </msup>'
 &expressao  += '      <mo>+</mo>'
 &expressao  += '      <mi>b</mi>'
 &expressao  += '      <mo>⁢ </mo>'
 &expressao  += '      <mi>x</mi>'
 &expressao  += '      <mo>+</mo>'
 &expressao  += '      <mi>c</mi>'
 &expressao  += '    </mrow>'
 &expressao  += '  </math>'
 textblock1.Caption = &expressao
Endevent


O resultado é interessante.



Atenção! nem todos os navegadores dão suporte ao recurso, o recém lançado Vivaldi, por exemplo, não consegue interpretar a coisa ainda.


Formatando com casas decimais

Resultado de imagem para Cultureinfo image
Um problema que enfrentamos no Genexus, na construção de relatórios impressos (PDF, por exemplo), é a impossibilidade de aplicarmos uma mascara que formate milhares e casas decimais a um certo número, isto para que saia dentro dos padrões dos diversos países.

Quando programamos WebPanels e outras interfaces temos alguns recursos que auxiliam na apresentação, como User Controls, Thousand Separator e Pictures, porém quando falamos em impressão PDF os recursos ficam escassos.

Um mesmo valor de 1000 apresentado no sistema Português-Brasil e Americano, deveria resultar em um número apresentado no seguinte formato:

    R$ 1.000,00
    U$ 1,000.00

Infelizmente não conseguimos fazer isso com muita facilidade.

Como Resolver?

Quando esgotamos as possibilidades poderemos então recorrer aos universitários, e existem algumas formas de fazer isso, optei por programar diretamente na linguagem C# que possui uma classe chamada CultureInfo que resolve bem esta parada. A solução final pode ser feita de duas maneiras, programando diretamente no código de nosso procedimento ou mesmo criando uma classe externa na linguagem nativa que importaremos com o External Object.  Ambos os recursos já exploramos aqui no Genexando.

Nosso exemplo seguirá a programação direta no código, porém já salientamos que esta prática não é boa, pois o objeto ficará refém da linguagem programada, e no caso de um novo environment que venha a ser criado posteriormente com outra linguagem de programação estaremos inviabilizando a operação. Cuidado com este tipo de solução porque uma das melhores características do Genexus é a independência tecnológica e este tipo de alternativa afeta de forma significativa a troca de gerador. Se ao invés de programar direto voce optar por uma classe externa com uma DLL que faça a operação, melhor.

Para utilizar a classe CultureInfo será necessário conhecer o código que representa o país e código da região, normalmente formado por duas letras seguida de um hífen e posteriormente o código da região, como por exemplo: pt-BR.

Apresentamos a seguir alguns desses códigos.

en-USEnglish (USA)
pt-BR Portuguese (Brasil)
es-ESSpanish (Spain)
ja-JPJapanese (Japan)
zh-TWChinese (Taiwan)
zh-CNChinese (PRC)
zh-HKChinese (Hong Kong SAR)
zh-SGChinese (Singapore)
zh-MOChinese (Macao SAR)

Programando a coisa

Para programar o formatador precisaremos de uma procedure, que chamaremos de FormatNumber, que definimos com o seguinte:

Rules:
parm(in:&valor, out:&final);

Source:
csharp decimal number = [!&valor!];
csharp [!&final!] = number.ToString("N",new System.Globalization.CultureInfo("en-US"));

Variables:
&valor   Numeric(12.2) // por exemplo!
&final   Character(20)

Utilizando

Para utilizar o conversor será simples, bastando chamar a procedure passando o numero a ser formatado, e recebendo uma string com o valor

&Resultado= FormatNumber(&ValorAFormatar)

O resultado será uma string que poderá ser incorporada ao PDF com o formato da moeda que se deseja apresentar.