Stop o Post
Autor: Douglas Oliveira | Publicado: 2016-07-07T10:08:00-07:00

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. &nbsp;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.

&lt;form id="MAINFORM" name="MAINFORM" method="post" ... &gt;


Aliás POST é uma palavra muito bem escolhida pelo Tim Berners-Lee &nbsp;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. &nbsp;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.






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.&nbsp;
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.
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).
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) &nbsp;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&nbsp; &nbsp;&nbsp;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.