Otimização Extrema: Use CDN!

Continuando com a série de artigos relacionados a otimização extrema de sua aplicação, hoje começaremos com a abordagem do uso de cache para diminuir a latência no carregamento de suas páginas.


Com a pequena curva de aprendizado e grande quantidade de bibliotecas para a preparação do front-end, cada vez mais, cresce a quantidade de documentos de estilo e arquivos javascripts anexados a uma página. Com esse crescimento, também cresce vertiginosamente a quantidade de requisições e até mesmo o tamanho do documento que deve ser entregue ao usuário. Como já visto anteriormente em outros artigos, o tempo de carregamento de sua página pode ser um fator decisivo na permanência e decisão de um usuário em sua aplicação/página.

Pensando nisso, algumas gigantes da internet, como Google e Microsoft, criaram um repositório de bibliotecas(js) e frameworks(css) para servi-las de forma otimizada. Esses repositórios, denominados CDN(Content Delivery Network), distribuem bibliotecas como jquery, mootools, prototype e frameworks css, como o twitter bootstrap, com um excelente controle de cache, e ainda em servidores otimizados para entrega de conteúdo estático, como o nginx e lighttpd. Mais a frente vamos ver um artigo em como montar o seu próprio servidor de arquivos estáticos.

A ideia de usar CDNs em seus projetos é a de aumentar consideravelmente a possibilidade de requisições a objetos que já estão em cache, utilizando recursos que foram requisitados em outra requisição, em outro site, a seu favor.

Digamos que o exista um site “exemplo.com”, e no código html do site há a requisição para o carregamento de um código javascript de uma das bibliotecas servidas por uma das CDNs. Quando o usuário acessar a página, o código será carregado para o browser do usuário e colocado em cache, devido as fortes regras que as CDNs tem relacionados a isso. Caso eu use a mesma biblioteca em um projeto, e também usar a CDN, não haverá a necessidade do usuário carregar novamente a biblioteca, já que o arquivo estará em seu cache. Como o controle de cache nos browsers atuais é feito por intermédio do domínio onde tal recurso está alocado, o conteúdo vai estar cacheado e pronto para ser utilizado.

Com o propósito de saber qual a CDN com maior velocidade, e também exemplificar o que disse anteriormente, vou criar dois hosts virtuais(hosta e hostb), em minha máquina e descobrir qual a melhor opção de CDN a ser utilizada em seu projeto.

Urls protocol-relatives

Antes de iniciarmos nossos testes, precisamos dar uma olhada em um ótimo recurso que as CDNs tratadas aqui possui. Esse recurso em questão, trata-se de servir as bibliotecas tanto em http, quanto em https, possibilitando as urls serem montadas sem a especificação do protocolo. Obviamente que isso não é um recurso dos hosts das cdns cedentes, mas sim uma regra que é seguida por quase todos os browsers(todos os browsers modernos seguem), para levar em consideração o protocolo atual da sessão do usuário. Com tal recurso, fica fácil fazer a troca de ambiente sem se preocupar com o que será feito com as urls que seguem outro protocolo, como por exemplo o https.
Se o usuário estiver navegando por algum área de sua aplicação onde não há nenhum tipo de encriptação https, seus links começaram com “http://”, e se em algum momento ele fizer login e todas as páginas que ele visitou passassem a ser servidas pelo protocolo https, como o programador faria para trocar todas as URLS especificando o protocolo seguro?

Fácil! É só ele não se preocupar com isso, omitindo a especificação do protocolo, contruindo url absolutas, mas com relatividade ao protocolo. Veja no exemplo abaixo a ausência do protocolo no início das URL.

Vamos ao testes!

Para nossos testes usaremos três grandes CDNs. A primeira é a do Google, que serve as principais bibliotecas disponíveis atualmente, tais como Jquery, MooTools, Ext, entre outras.

googleapis-1

Como pode ser visto na imagem acima, o tempo de espera( do momento do pedido até o início da entrega), foi de 202ms, fazendo com que o tempo da CDN do google, nos testes efetuados, seja o pior. Mas se você considerar a quantidade de aplicações/sites utilizando o serviço, esse valor é aceitável. Por outro lado, sem dúvida alguma essa CDN vence todas as outras por compressão. A biblioteca foi entregue em apenas 32k, de um total de 90k, sem compressão. Na imagem abaixo, utilizei outro host(hostb), para demostrar como a biblioteca já está carregada ao browser do usuário e não será requisitada novamente.

googleapis-2

Partindo para nosso segundo teste, utilizaremos a da Microsoft, que ao meu ver é a mais limitada. Além da padrão Jquery, possui em seu arquivo alguns plugins da mesma biblioteca, e a biblioteca para se trabalhar com o MVC da tecnologia .NET.

aspnetcdn-1

Confesso que me supreendi com os resultados da CDN da Microsoft. O tempo de espera foi de apenas 32ms, ignorando o tempo em que o browser procurava o DNS! Mas isso pode significar que a CDN é pouco usada. Mas infelizmente esse ganho na espera é neutralizado com o tempo baixando a biblioteca, como pode ser visto.

aspnetcdn-2

A última CDN que utilizaremos é a disponibilizada pela CloudFlare, denominada cdnjs. Em relação a quantidade, é sem dúvida alguma a melhor. Enquanto escrevia esse artigo havia 268 objetos sendo disponibilizados pela empresa.

cdnjs-1

Essa CDN pode ser problemática em sua aplicação! Apesar de seu tempo de espera não ser o pior, o tempo de download foi bem ruim comparado aos outros dois. Além disso, três em dez vezes que executei os testes, o host apresentava problemas com a conexão. Por algum motivo obscuro, não resolvendo o DNS. Use-a, mas com cautela.

cdnjs-2

Terminado os testes, podemos concluir algumas coisas:

  1. Na maioria das vezes, é mais rápido carregar um objeto de uma CDN que do seu próprio host;
  2. A CDN com maior performance definitivamente é a do google. Porém, nada lhe impede de carregar uma outra biblioteca para completar sua aplicação, como por exemplo, da cdnjs.
  3. Utilize sempre as URLs “protocol-relatives”. Você nunca sabe quando sua aplicação possa passar a servir em protocolo seguro. Isso pode lhe evitar retrabalho futuro. Além disso, pode ser sensível, mas querendo ou não diminui o tamanho do seu documento omitindo o protocolo.
  4. Apesar da grande quantidade de bibliotecas agregadas ao repositório da CDN disponibilizada pela CloudFlare, definitivamente ela é a CDN menos eficiente.

Terminado este artigo, lhe faço uma pergunta: Você utiliza sua biblioteca javascript conscientemente? Jquery é a solução para todos os seus problemas? Esse é o assunto de nosso próximo artigo.

Otimização extrema: Otimizando e reduzindo o seu CSS

Continuando com a série de artigos relacionados a otimização extrema de sua aplicação, hoje vamos continuar falando sobre os arquivos CSS. Algumas das técnicas abaixo podem parecer besteira, mas vão lhe poupar grandes problemas relacionados a performance de sua aplicação. Então vamos lá!


Use CSS Sprites

Como já disse no artigos sobre CSS Sprites, eles podem ser bastante úteis e economizar banda com a baixa quantidade de requisições que serão feitas por seu documento requisitando objetos para sua aplicação.

Não utilize a regra @import!

Existem duas formas de básicas de se anexar um documento CSS a um documento

A primeira é usando a tag link, para anexar os documentos, um por um, utilizamos o atributo href para anexar cada um dos documentos css.

A segunda, é utilizando a regra import do CSS.

Pode parecer interessante utilizar a opção @import, por diversos motivos, desde utilizar somente um arquivo css para linkar todos os seus outros documentos, até diminuir o número de caracteres para anexá-los. Segundo um artigo de 2009, utilizar @import é incrivelmente ineficiente se comparador com o a tag link. Então não a use! Não se deixe enganar por qualquer outra coisa.

Usar a regra imports pode fazer com que a ordem dos elementos da página seja alterada, fazendo com que o CSS tenha alguma demora para carregar, e assim fazendo a página ter uma demora significativa de renderização. Além disso, se você utilizar a tag link e regras import na mesma página, o que deve ser carregado por imports, só aconteçam quando o que tiver que ser carregado pelo link terminar, aniquilando seu paralelismo.

USE A TAG link

Combine todos os seus estilos em apenas um arquivo

Temos a ideia de separar as CSS em diversos arquivos com a intenção de organizá-los por objetivo. Por exemplo, existirá um arquivo para a disposição dos elementos na tela, outro para a tipografia, outro para cores e outro para hacks. Isso é só um exemplo, já coisas mais absurdas, onde cada página do site tinha um css diferente, causando mais de 20 requisições de arquivos desnecessariamente.

SEMPRE agrupe todos os seus arquivos CSS em apenas um, assim você vai economizar nas requisições http feitas ao servidor, além disso lhe economizará tempo debugando seus estilos se algum não estiver de acordo com o esperado.

Caso ainda assim você ache interessante utilizar os arquivos separados por motivo de organização, existe um recurso do Apache que pode lhe auxiliar. Esse recurso é um módulo include, comumente chamados de SSI(Server Side Includes). Em suma, o que o módulo fará por nós é concatenar todos os arquivos que quisermos em apenas um, em tempo de processamento.

Para que o módulo funcione, primeiramente precisamos ativá-lo! Se você estiver usando o ubuntu, o comando abaixo fará a ativação e restart do apache.

Com o módulo ativado, iremos colocar todos os arquivos css likados, como o exemplo abaixo, dentro de um outro arquivo css. Para o exemplo abaixo, peguei todos os arquivos do framework CSS Blueprint e os coloquei em um diretório chamado css.

Com o documento CSS preparado, nosso próximo passo é criar ou editar o arquivo .htaccess. Explicando a grosso modo, se ele casar o arquivo screen.css em alguma requisição, o módulo includes é ativado e é passado por um filtro, chamado INCLUDE.

Se você tiver feito tudo correto, quando linkar o screen.css ao seu documento html, você não verá os includes, mas sim um arquivo contendo todos os arquivos css que você gostaria de incluir. Caso contrário, vá ao arquivo de logs do seu apache e veja qual o erro está acontecendo.

Essa técnica gera um problema de performance, se você tiver prestado bastante atenção. Todas as vezes que o arquivo screen.css for chamado, haverá uma ativação do módulo includes e o arquivo será construido. Isso pode ser bastante estressante para o servidor, ainda mais se houver uma grande quantidade de arquivos a serem incluídos.

Como alternativa para esse módulo, usando o linux, o simples comando abaixo fará o arquivo css estaticamente, cabe a você toda vez que modificar algum arquivo dentro do diretório css rodá-lo novamente.

Externalize seus arquivos CSS

Com externalizar, quero dizer colocar em um arquivo independente! De modo algum incorpore seus estilos ao documento HTML. Colocando em um arquivo independente, e um bom controle de cache, asseguramos que o arquivo não vai ser requisitado toda vez que a página for carregada, assim economizando uma grande quantidade de banda. Mais uma vez digo: USE A TAG link

Sempre coloque seus arquivos CSS no topo(header)

Colocando seus documentos de estilo dentro da tag header(no topo, é claro) você garante que a página carregue progressivamente, dando a sensação que a página está sendo carregada com mais rapidez. Além disso, você evita que seja mostrada uma página branca ou pior, partes do sistema sendo carregados sem estilo e deformando toda a página, até que o documento de estilo é carregado e tudo é corrigido.

Lembre-se: A experiência do usuário em sua aplicação é muito importante.

Use a forma contraídas das regras CSS

Algumas regras CSS possuem formas contraídas. Segue exemplos:

Agrupe estilos similares

Quando você está há algum tempo desenvolvendo uma aplicação, ou mesmo dando manutenção em uma aplicação legada, é fácil encontrar em um documento de estilo elementos que tem as mesmas regras aplicadas repetidas vezes, ou mesmo parte das regras iguais. Agrupe-os e use a maravilha das regras em cascata a seu favor!

O exemplo abaixo descreve claramente o agrupamento quando todas as regras são idênticas!

O exemplo acima pode ser reescrito da seguinte forma:

No exemplo abaixo, usamos a herança para configurar o botão e adicionamos cores ao texto dos elementos

Omita o desnecessário!

Existe uma série de recursos que você pode usar para diminuir ainda mais o tamanho do seu arquivo CSS.

Reduza o número de quebras de linha

Como dito no artigo sobre CSS Sprites, existe uma ferramenta chamada yumcompressor, que faz uma série de otimizações em seu código CSS. Uma dessas é a remoção de todos os espaços e quebras de linhas do código. Como o browser ignora completamente os espaços e quebras de linha você removê-los sem nenhuma dó!

Remova o último ponto e vírgula

O último ponto e vírgula das regras aplicado a qualquer elemento pode ser eliminado. Veja o exemplo abaixo para esclarecer:

Use comentários simples

Não utilize comentários gigantescos como o abaixo! Além de não trazer nenhum tipo de ajuda real ao que está sendo feito pelo arquivo, faz com que o arquivo cresça desnecessariamente! Pessoas “letradas” em CSS não precisarão de nenhum tipo de auxílio explicativo para suas regras. CSS é auto-explicativo. Seria como documentar a expressão ‘1+1=2’.

Simplifique a forma hexadecimal das cores

Além da forma contraída de expressar regras, como visto anteriormente, existe uma forma de expressar cores em hexadecimal contraidamente.

O código abaixo pode tranquilamente ser trocado pelo seu posterior.

Remova a medida usada!

Quando você estiver escrevendo alguma regra que tenha o valor 0(zero), não há necessidade de explicitar qual a medida que está sendo usada, afinal px, pc, em, não terão sentido se você está utilizando ZERO. Por que afinal, zero será zero em qualquer uma dessas medidas.

Assim termino as técnicas de otimização extrema relacionadas a CSS. Espero que o que foi informado nesses dois artigos lhe ajude na construção de sua aplicação. Se vocẽ ainda não leu o artigo anterior falando sobre CSS Sprites, aconselho a ler.

Otimização Extrema: Maximizando o uso de CSS Sprites

Começando a série de otimização extrema de seu site ou aplicação, iremos caminhar inicialmente pela otimização de itens relacionados ao front-end. Temos que ter um conhecimento inicial sobre como os browsers funcionam quando relacionado ao paralelismo de itens que são buscados do servidor.

Por padrão, os browser do mercado atualmente buscam paralelamente no máximo 8 ítens, incluindo páginas (x)html, folhas de estilo, arquivos javascript e imagens. Levando isso em consideração, quanto maior a quantidade de itens a serem carregados, maior será o tempo gasto para o carregamento da página. Óbvio, não é?

Em alguns browsers, o acesso a informação de quantas requisições simultaneas são feitas pelo browser é feita de modo tranquilo, como por exemplo no firefox. Entrando nas configurações do browser, digitando about:config na barra de endereços, e confirmando a mensagem de que você sabe o que está fazendo, procure pela diretiva network.http.max-persistent-connections-per-server, e claramente você pode ver que o ítem está com o valor seis, mostrando que o browser só vai buscar seis itens por vez. Você, é claro, pode mudar esse valor, mudando para quaisquer que seja o valor de itens que você queira que o browser busque por vêz. É claro que isso só vai mudar pra você, e não para todos os usuários que utilizarem seu serviço.

network.http.max-persistent-connections-per-server

Os servidores http em geral, tem diversas rotinas que farão automaticamente o tratamento das requisições, com a proposta de otimizar seus serviços, economizando recursos do servidor onde ele está alocado. Mas eles não são tão inteligentes assim. É seu trabalho como programador front-end, disponibilizar seus documentos de forma que o browser e o servidor trabalhem de forma otimizada.

Nossos próximos passos serão para diminuir ao máximo a quantidade de requisições que o browser vai fazer ao servidor. Se o que você está trabalhando tende a ter bastante acesso, vale muito a pena diminuir o número de requisições HTTP que serão feitas.

minha-lista-coisas

O html gerado na imagem acima, é o objeto dos nossos testes. Montei um pequeno documento linkando um documento css, relacionando três imagens a três classes distintas. O documento em questão ilustra uma situação normal em interfaces, onde um item tem ações diversas relacionadas, e essas ações estão relacionadas semióticamente com uma imagem.

Aqui vamos começar nossa nossa primeira otimização no documento css, iremos minimizá-lo removendo tudo o que é desnecessário para o browser, como por exemplo, espaços. Para tal, utilizaremos a ferramenta yuicompressor. Como você pode ver abaixo, o código fica um pouco ilegível para nós, mas para o browser continua sendo o mesmo documento.

Fazer isso pode se tornar uma tarefa bem chata, ainda mais se você tem uma grande quantidade de arquivos CSS(o que desencorajo, em um post mais a frente vou falar disso), então se o projeto no qual você está trabalhando possui integração contínua, e como servidor o jenkins, não custa nada configurá-lo para fazer esse trabalho para você. A tarefa que o ant deve executar pode ser algo como o código que você digita no seu prompt de comando:

Como você pode ver na imagem abaixo, em uma página simples, composto de um documento htmt, uma folha de estilo e três imagens geraram cinco requisições HTTP, onde 4.23KB foram transferidos e houve 26ms para os elementos serem carregados na página.

É pouco, se você levar em consideração as conexões atuais, e claro que o exemplo é apenas uma situação que quase não existe, uma página com 5 registros e somente esses estilos. Em aplicações e sites de verdade podemos multiplicar sem nenhum medo esse número por 100. Olhando mais intrinsecamente para esse exemplo, com relação ao custo dessa página para a empresa que o servirá, a quantidade de tráfego que essa página gera é descomunal(!) se você multiplicar por 10000 usuários, e 100000, 1000000!

Ok ok! Exagerei um pouco! Já que é uma página simples, mas sempre pense que a sua aplicação é feita de diversos documentos sendo carregados, e tudo o que você puder fazer para tornar a experiência do usuário mais ágil, é um ganho para alguém!

sprite-without-sprite

Ok! Vou comprimir meus arquivos CSS. E o tal dos CSS Sprites?

Se você trabalha com front-end e nunca ouviu falar dessa técnica definitivamente você tem problemas em suas aplicações! A técnica consiste em juntar várias imagens em apenas uma, assim diminuindo o número de requisições http feitas para o servidor. O próximo passo é mapear a posição de cada item dentro do arquivo CSS. Para gerar o sprite, utilizei um serviço muito interessante chamado spritegen. Testei o alinhamento horizontal e vertical na tentativa de conseguir algum ganho em relação ao tamanho da imagem, mas permaneceu o mesmo.

sprite

Abaixo, mapeamos nossa imagem como mencionado.

Como já aprender como compactar o código css, vamos aplicar o compressor nesse aqui também!

A imagem abaixo ilustra claramente nosso ganho. Além de agora termos carregado somente 2.69KB(quase metade do tamanho anterior), nossa página levou apenas 13ms para ser carregada. Metade do tempo que levava para ser carregada anteriormente. Além disso, Diminuímos de cinco requisições para apenas 3!

sprite-with-sprite

Ok! Entendi! Mas e temos como melhorar isso? SIM!

Há alguns posts atrás, mostrei uma técnica onde usamos a codificação base64 para diminuir o número de requisições http feitas ao servidor, e agora vamos aplicar a mesma técnica em nosso sprite, incorporando a imagem ao documento CSS.

Utilizei o código que está anexado ao post mencionado para gerar a imagem codificada e o código abaixo quando anexado ao documento CSS.

Vamos comprimir esse código também, para obtermos ainda mais performance da nossa aplicação.

Olhando a imagem abaixo de relance não vemos muitas diferenças, mas muita coisa mudou se relacionado aos exemplos anteriores! Conseguimos diminuir ainda mais o tamanho de nossa tranferência. Agora temos somente 2.34KB! Se você é um grande observador vai ver que o tempo continua inalterado, ainda em 13ms. Porém existe uma diferença aí. O tempo de load foi menor. Apesar da ferramenta que utilizei dizer que houve três requisições, apenas duas foram feitas. Como a imagem está dentro do documento CSS não há necessidade do browser fazer uma terceira chamada, isso pode ser observado pelo recurso gráfico que a ferramenta me fornece. Se você obsevar atentamente, na requisição os documentos localhost(azul), css.css(verde) possuem um rastro de cor clara que relaciona o tempo que o browser fez a chamada ao servidor até a entrega. Agora observe a terceira chamada(roxo). Não possui rastro, por que não houve nenhuma requisição feita para o browser. Não era necessário, a imagem estava codificada dentro do arquivo de CSS que já havia previamente sido carregada.

sprite-sprite-base64

Com o que fizemos do início até agora, conseguimos além de diminuir o tempo de carregamento da página, o tamanho final somando todas os ítens que foram requisitados e além disso o número de requisições. Passamos de cinco para apenas duas.

Essa técnica pode ser bem trabalhosa inicialmente, mas pode gerar ganhos inacreditáveis se aplicados a interfaces onde existem muitos itens semióticos. Observando ainda um pouco mais, seu documento CSS pode crescer de tamanho, porém, se aplicadas as técnicas de compressão do arquivo como visto nesse artigo, você pode até diminuir seu tamanho comparando a soma do arquivo css mais os diversos arquivos de imagem que podem existir em sua aplicação.

Existe ainda um outro artifício para ser aplicado para tornar essa técnica ainda mais eficaz! O controle quase nazista do cache dos arquivos de sua aplicação. Mas isso é assunto para outro artigo!

Otimização extrema: Construindo aplicações otimizadas

Com a facilidade de se construir páginas para a internet, seja blogs, pequenos aplicativos para algum fim específico ou ainda grandes aplicações, em algum momento, aqueles que desenvolvem tal aplicação vão acabar esbarrando na questão do “sistema lento”. Isso por que, a necessidade pela rapidez da entrega das informações é tão grande que pode significar em perdas de cifras ou a total desistência dos usuários do site/aplicação pela demora que a informação é entregue.

Há algum tempo venho pensando nessa questão como sendo um dos principais problemas da ineficiência dos sistemas que são projetados atualmente. A grande maioria dos programadores/engenheiros/designers não trabalham em conjunto por que em algum momento foi decidido que seus trabalhos são atividades que são em momentos distintos e então não há necessidade de revisão dos seus trabalhos. Mal esses sabem que seu trabalho feito com algum tipo de despreocupação em algum momento relacionando a otimização ou mesmo a falta de conhecimento de que tal decisão no projeto pode afetar a velocidade que essa informação vai ser entregue, pode tirar uma aplicação do ar pro conta da demora na entrega!

Por experiência, já vi alguns sistemas que inicialmente o projeto parecia perfeito. Vários diagramas de classes explicando detalhadamente por que X padrão de projeto estava sendo implementado naquela parte de código para resolver tal problema, regras de negócios maravilhosas, limitando ao máximo a questão de segurança dos dados que serão inseridos no banco de dados, e finalmente o documento de interface. Mas em nenhum documento dos que passava algum tempo lendo para implementar tudo o que foi pensando previamente vi a preocupação com a qualidade e rapidez com que as informações são entregues ao usuário final.

No final me sobra uma dúvida: No final das contas, de quem é a responsabilidade pela questão velocidade da entrega da informação? Arquiteto, desenvolvedor, designer? Todos juntos?

Levando isso em consideração, hoje inicio um compendio de dicas que afetam todas as disciplinas, desde a infraestrutura até o designer. Não vou seguir uma linha lógica para publicação dos artigos, até por que não existe um pensamento linear. Levando isso em consideração, o primeiro artigo é para os designers.

Front-end