speed

Otimizando a performance de aplicativos Cordova/Ionic Framework

Olá pessoal, nessa última semana tive a boa surpresa de ter meu aplicativo Mini Receitas aceito no showcase do Ionic Framework e o melhor é que ele foi considerado pela equipe do Ionic como um dos Top Apps feitos com o framework. Esse bom resultado me fez refletir em como eles escolhem os aplicativos que vão para o Top Apps e a conclusão que eu cheguei é que como eles não conseguem testar a finalidade de todos os aplicativos até por que eles podem estar em idiomar que eles desconhecem, como o português, o que vale mesmo é a performance e o design.

Não sou nenhum especialista em design, mas depois de meia década trabalhando como front-end eu tenho noção do que não fazer, então acho que não passo vergonha como muitos desenvolvedores (principalmente os que vieram do mundo back-end). No entanto, como não sou especialista nesse assunto prefiro falar pra vocês dois cuidados (banco de dados e animações) que tomei para criar um aplicativo híbrido performático.

Banco de dados

A primeira coisa que eu fiz para otimizar a performance do aplicativo foi efetuar o mínimo de operações possíveis no banco de dados pois essas bloqueiam o DOM e iriam travar minha interface. De início segui as dicas do artigo How To Use PouchDB + SQLite For Local Storage In Your Ionic App da Ashteya Biharisingh e embora isso tenha melhorado muito a performance do meu aplicativo eu ainda tinha problemas nas transições de telas. Principalmente nos primeiros acessos às telas, pois o Ionic ainda não tinha colocado-as em cache.

O que acontece é que quando você realiza o primeiro acesso a uma página não cacheada ou uma que possui o cache desabilitado o seu código consulta o banco e isso causa o bloqueio do DOM. Então o objetivo é evitar que ocorra esse bloqueio. E a forma que encontrei de fazer isso foi carregar todo o banco de dados em cache antes mesmo do usuário acessar a tela que irá utilizá-lo.

Para isso eu criei um serviço chamado Loader que possui um método chamado done que me retorna uma promise. Esse método done é quem carrega todos os dados do banco para o cache como descrito pelo artigo da Ashteya.

Logo, o que precisei fazer (usando alguns recursos do ES6) foi:

services/loader.service.js

/**
  * LoaderService
  */
  
(function() {
  'use strict';

  function LoaderService ($q, RecipesService){
    'ngInject';

    this.done = function() {
      return $q.all([
                RecipesService.getAllRecipes()
              ])
              .then((...args) => args)
              .catch((...args) => args)
    }

  }

  module.exports = LoaderService;
}());

index.run.js

/**
  * Run
  */
  
(function() {
  'use strict';

  function runBlock (Loader, $ionicPlatform, $cordovaSplashscreen) {
    'ngInject';

    $ionicPlatform.ready(function(){
      Loader.done()
            .then(function(){
              $cordovaSplashscreen.hide();
            })
    })

  }

  module.exports = runBlock;
}());

index.module.js

/**
  * Definição do módulo
  */
  
import runBlock from './index.run';

import LoaderService from './services/loader.service';
import RecipesService from './services/recipes.service';

angular.module('miniReceitas', ['ionic', 'ngCordova'])
       .run(runBlock)

       .service('RecipesService', RecipesService)
       .service('Loader', LoaderService);

Note que eu também faço o uso do plugin cordova-plugin-splashscreen , faço isso para que o usuário só possa interagir com o aplicativo após todo o banco de dados estar em cache. Dessa forma ele não percebe o bloqueio do DOM pelas consultas ao banco. O único momento o usuário pode vir a notar algum tipo de bloqueio é ao inserir, alterar ou deletar algum registro no banco. No entanto essas operações normalmente são mais leves que uma query de consulta.

Animações

Animações são muito importantes para que aplicativo ofereçam uma boa experiência para o usuário. Quando estamos criando sites nem sempre nos preocupamos com a performance delas já que computadores possuem muito mais poder de processamento, porém nem sempre trabalhamos com mobile-first, o que é um erro em um mundo onde o usuário passa boa parte do seu dia conectado a internet através de dispositivos móveis.

Enfim, para otimizar as animações nós devemos entender como o CSS é renderizado e para isso eu recomendo a leitura do artigo Entendendo os Reflows. Mas em síntese o que precisamos fazer é evitar Repaints e Reflows. E para evitá-los basta projetar seu CSS com propriedades que não disparem esses eventos.

Você pode, por exemplo, utilizar o transform: translateY ao invés do top ou o bottom para uma animação, pois o top e bottom disparam tanto o Repaint quanto o Reflow. Você pode utilizar o CSS TRIGGERS para consultar se a propriedade css que você está utilizando para suas animações dispara algum desses eventos.

(Bônus) DOM

Ainda não terminei a implementação desse terceiro item, por isso ele está presente apenas como bônus. Mas assim como temos que ter cuidado com a árvore de renderização do CSS, nós também temos que ter cuidado com a do HTML. E uma técnica que vem cada vez mais sendo utilizada para otimizar a performance do DOM é o ato de renderizar apenas os nós visíveis. No caso do AngularJS que cada um dos nós pode possuir uma escopo ligado a ele por meio do two-way data binding isso pode otimizar ainda mais a performance pois remove os listeners dos itens que não estão visíveis, já que eles não estão renderizados.

No Ionic uma diretiva que faz uso dessa técnica é a Collection Repeat e estou trabalhando para implementá-la no novo Slider que foi introduzido na versão 1.2 do framework.

Enfim fim

E é isso, além dessas existem outras otimizações que já citei no artigo 4 Dicas para trabalhar com o Ionic Framework e vocês podem encontrar mais algumas dicas na apresentação Top 10 Performance Techniques for PhoneGap and Hybrid Apps do Christophe Coenraets que ainda continua super atual. Sem contar que no fim das contas é tudo Javascript, logo, otimizações a nível da linguagem são sempre bem vindas, nesse sentido recomendo o artigo 10 Javascript Performance Boosting Tips from Nicholas Zakas do Jon Raasch e o artigo do Addy Osmani entitulado Writing Fast, Memory-Efficient JavaScript.


Ultimamente tenho estudado mais questões relacionadas a engajamento do usuário, promoção de aplicativos e melhoria de ranking nas lojas de aplicativos e achei conveniente fazer um post sobre performance enquanto essas informações ainda estão frescas em minha memória. Espero que esse post possa ajudá-los e caso você utilize alguma outra técnica para otimizar a performance dos seus aplicativos deixe seu comentário abaixo para que possamos disctuir e criar aplicativos cada vez melhores.

I know jQuery

Muito além do jQuery

Por incrível que pareça eu comecei esse artigo no dia 8 de Agosto de 2013 e ele ficou perdido no limbo do meu Google Drive desde então, faltavam alguns exemplos e uma conclusão. Então, eis que o encontrei ao procurar um outro artigo que estava perdido por lá.

Resolvi finalizar e estou postando com mais de 1 ano de atraso mesmo.


Bom galera já tinha um tempo que eu queria falar sobre esse assunto, mas ainda faltava um incentivo para soltar a boiada. E então eis que aconteceu, dispararam o gatilho. E aconteceu em um grupo de desenvolvimento do facebook, o jQuery Brasil. Um iniciante perguntou quais os requisitos necessários de JavaScript para aprender jQuery e um membro respondeu que não era preciso saber JavaScript para aprender. E na hora eu fiquei indignado, mas pensando bem eu acho que ele está certo, muita gente sabe jQuery e não sabe JavaScript. Mas se o jQuery é uma biblioteca JavaScript, logo, quem sabe jQuery sabe JavaScript, certo?

Em teoria era isso que deveria acontecer, mas as bibliotecas e os frameworks existem para criar uma camada de abstração maior e simplificar o trabalho, então em grande parte das vezes as pessoas não aprendem a linguagem e sim a ferramenta, que pode ser uma biblioteca, um framework, uma sdk, etc.

Então esse artigo é dedicado para o pessoal que sabe jQuery e que provavelmente não sofreu para aprender a trabalhar com o DOM (Document Object Model) ou fazer uma requisição ajax usando o XMLHttpRequest.

Primeiramente eu gostaria de lembrá-los que para tudo que o jQuery faz existe algo equivalente em JavaScript, até por que jQuery é JavaScript (sim, vou falar isso várias vezes). Mas eu não vou começar pelo básico, até por que o básico você encontra facilmente no google. Eu recomendo o ótimo artigo do Tárcio Zemel entitulado “Equivalentes nativos de JavaScript para funções jQuery“, onde o autor mostra algumas dessas equivalências.

Quando usar jQuery?

Uma das inspirações para esse artigo foi o artigo I know jQuery. Now what? do Remy Sharp, onde ele levanta alguns pontos sobre quando não usar jQuery e demonstra algumas soluções de problemas sem a utilização de jQuery. Este artigo é mais simples que o do Remy Sharp por isso recomendo a leitura dele, no entanto, é igualmente opinativo.

Bom, esse artigo já está ficando grande e chato e eu nem comecei a parte técnica ainda, então chega de enrolação.

Quando a complexibilidade supera a facilidade

Quando uma grande parte do seu público alvo não utiliza navegadores de última geração fica complicado trabalhar com JavaScript puro já que algumas funções do JavaScript podem não ser compatíveis por terem sido implementadas depois. O pessoal da BBC, no artigo Cutting the mustard, divide os navegadores em dois grandes grupos (Navegadores HTML5 e Navegadores HTML4) para poder exibir uma interface mais rica ao usuário dependendo dos recursos suportados pelo navegador do mesmo.

Por padrão o IE8 não suporta o método addEventListener que é um método que fica “escutando” um evento e é executado quando o evento do objeto é acionado. Está presente em todos os navegadores lançados desde 2007, menos no IE8. E isso, teoricamente, implica que se o navegador do cliente suportar esse recurso então esse navegador possui um melhor suporte aos padrões que o IE8.

Logo, se o seu público alvo utiliza esse navegador você deve utilizar jQuery. O que não quer dizer que todos os projetos que não utilizem jQuery ou outras bibliotecas não irão funcionar no IE8 e sim que você deve começar o projeto de forma simples e sem gambiarras.

Quando é necessário agilidade

Isso é uma das principais causas pelo qual os desenvolvedores utilizam bibliotecas e frameworks, agilizar o desenvolvimento. E o jQuery faz isso muito bem. Então não precisamos ficar reinventando a roda.

Como sobreviver sem jQuery?

Desenvolver sem o jQuery pode soar para alguns como reinventar a roda. Mas existem algumas alternativas para se escrever a aplicação sem ele e sem perder tempo.

document.ready

O document.ready, ou simplesmente $(function), é utilizado para executar o JavaScript após o navegador ter compilado o DOM. Fazemos isso pois o JavaScript bloqueia a renderização, mas como estamos falando de alternativas que tal colocar o seu código JavaScript antes da tag ? Dessa forma o DOM já estará compilado.

Caso essa simples ação ainda não resolva o seu problema, o que eu duvido muito, você ainda poderá utilizar o DOMContentLoaded. O DOMContentLoaded é suportado pela maioria dos navegadores.

document.addEventListener("DOMContentLoaded", function(event) {
  //do work
});

querySelectorAll

Anos atrás, quando o jQuery surgiu, ele trouxe uma revolução ao modo de utilizar JavaScript pelo simples fato dele ter simplificado, de forma significativa, a tarefa de selecionar os elementos com os quais queremos trabalhar. Porém o JavaScript evoluiu e hoje nós temos uma maneira igualmente fácil e nativa. É o querySelectorAll que é usado da seguinte forma:

var matches=document.querySelectorAll("div.nota, div.alerta");

Classes

Frequentemente costumamos trabalhar com classes no JavaScript, tanto para selecionar um elemento, quanto para fazer gets e sets do atributoclass em elementos. Normalmente acabamos usando o jQuery. Mas que tal usar as propriedades className e classList?

Formulários

Antigamente para fazer a validação de formulários no navegador nós sempre utilizávamos JavaScript, não existia outra opção. Porém o HTML também evoluiu e atualmente é possível fazer validação de formulários utilizando apenas atributos nos elementos HTML. É possível validar emails com o input do tipo email, definir campos obrigatórios com o atributo required e fazer validações com expressões regulares com o atributo pattern, nos permitindo assim, validar telefones, CPFs, CNPJs, etc.

Animações

O CSS também evoluiu e hoje podemos fazer animações com ele através da propriedade animate, como visto nesse artigo da MDN, e até mesmo utilizar aceleração hardware utilizando o translate3d da propriedade transform como visto nesse artigo do Paul Irish. 
Eu, particularmente, uso bastante essas duas características do CSS3 para deixar as animações nos dispositivos móveis mais fluídas.

Conclusão

Hoje é possível ser produtivo sem utilizar jQuery que embora seja muito prático muitas vezes não é necessário, pois muitas vezes carregamos uma biblioteca inteira para utilizar apenas alguns métodos que já possuem APIs nativas disponíves no JavaScript ou alternativas melhores, mais simples e mais performáticas no HTML e no CSS.

Então sempre que o jQuery não for necessário, evite-o ;)

emmet

Emmet e a automatização no desenvolvimento

Olá, diante da promessa realizada pelo Jean no último post, venho antes de tudo me apresentar:

Bom, recentemente graduei na primeira turma de Sistemas de Informação da UFG, atualmente trabalho no LabTIME/UFG como desenvolvedor frontend e sou um dos sócios e desenvolvedores da Pequi Sistemas. Desenvolvo aplicações com Joomla há mais de 3 anos, entretanto, tenho me dedicado ultimamente em desenvolvimento frontend sem o framework, visto os requisitos dos últimos projetos da Pequi Sistemas e LabTIME/UFG.

O blog é um desafio grande, que me possibilitará compartilhar um poucos das soluções encontradas no decorrer dos trabalhos, mas também influenciará novos estudos que até então não ocorriam com certa periodicidade, é isso!

Automatização no desenvolvimento

Produtividade e automatização são palavras que caminham juntas no processo de desenvolvimento, entretanto, automatizar é um trabalho dispendioso, que exige estudos e experiência. Tratando-se de frontend, muitas vezes, criamos blocos/fragmentos que serão reutilizados e/ou importados no decorrer da aplicação. O artigo a seguir trata de um "kit de ferramentas" que foi criado para auxiliar no desenvolvimento, principalmente para os desenvolvedores que utilizam de HTML / XML e CSS.

O Emmet foi criado como Zen Coding, a princípio, um projeto proposto por Vadim Makeev em abril de 2009 e posteriormente desenvolvido por Sergey Chikuyonok, no mesmo ano. Após três anos de desenvolvimento o nome do projeto alterou-se para Emmet, não perdendendo nenhuma de suas características. 

Por que usar o Emmet?

  1. Sintáxe simples e intuitiva – http://docs.emmet.io/cheat-sheet/

  2. Documentação clara – http://docs.emmet.io/
  3. Plugin compatível com inúmeros editores: (ex: Eclipse, Netbeans, Brackets, Espresso, Coda, Sublime Text e outros)

Como usá-lo?

Atualmente eu tenho utilizado o Espresso (apenas para Mac) como editor, apesar de ser pago é uma ferramenta que cumpre com o que promete, logo é perceptível a leveza e simplicidade da ferramenta, atrelado a funcionalidades importantes como conexão SSH e FTP, mas editores para mac é assunto para outro post!

Visto que o Espresso não é multiplataforma, a seguir algumas instruções para instalação do plugin utilizando o editor Sublime Text 2 (download aqui).

Como instalar o Emmet no Sublime Text 2

  1. Abra Sublime Text 2;

  2. Acesse: Preferences > Browse Packages;

  3. Coloque dentro da pasta Installed Packages o arquivo de instalação do Sublime Package Control (download aqui) que servirá para instalar outros plugins que poderão ser necessários;

  4. Reinicie o Sublime Text 2;
  5. Acesse: Preferences > Package Control > Install Package;

  6. Busque por Emmet e reinicie, se for solicitado.

Comandos básicos

Em um arquivo html:

  • Digite: h1 (e pressione tab)
  • Resultado: 

    <h1><h1>
  • Digite: nav>ul>li*5 (e pressione tab)
  • Resultado:

    <nav>
    	<ul>
    		<li></li>
    		<li></li>
    		<li></li>
    		<li></li>
    		<li></li>
    	</ul>
    </nav>
  • Digite: ! (e pressione tab)
  • Resultado:

    <!doctype html>
    <html lang="en">
    <head>
    	<meta charset="UTF-8">
    	<title>Document</title>
    </head>
    <body>
    	
    </body>
    </html>

Em um arquivo css

  • Digite: ml:10 (e pressione tab)
  • Resultado:

    margin-left: 10px;
  • Digite: bdrs:10 (e pressione tab)
  • Resultado: 

    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 10px;
    

Caracteres importantes e seus significados

  • # – Id ex: a#teste

  • . – class ex: a.teste

  • > – Filho ex: ul>li

  • + – Irmão ex: ul>li+li#segundo

  • ^ – Pai ex: p>span^span.destaque

  • {texto} – conteúdo da tag ex: a{texto}

Através destes pequenos exemplos podemos perceber o quanto o Emmet pode ser útil e simples no desenvolvimento de uma aplicação. Entretanto, por mais que tenhamos várias opções, dois aspectos devem ser destacados:

  • Todos os atalhos rementem a CSS, HTML e XML, logo outras tecnologias, previamente não podem ser atendidas;
  • A sua aplicação exigirá alguns trechos específicos/exclusivos

(Nestes casos, entra mais uma funcionalidade do Emmet).

Criando os próprios atalhos

No Sublime Text 2:

  • Acesse: Preferences  >  Browse Packages?;
  • Acesse o arquivo: Packages > Emmet > Emmet.sublime-settings.

No arquivo existirá o seguinte exemplo:

"snippets": {
		// "html": {
		 //	"abbreviations": {
		 //		"example": "<div class='example' title='Custom element example'>"
		 //	}
		 //}
	},

Este é um exemplo que ao ser descomentado, poderá ser testado:

  • Digite: example
  • Resultado: <div class='example' title='Custom element example'>

Para criar fragmentos próprios replique todo o trecho e edite, a seguir um exemplo de condicional JSP:

"snippets": {
		 "html": {
		 	"abbreviations": {
		 		"cursor": "<core:if test='${teste = teste}'></core:if>"
		 	}
		 }
	},

Conclusão

Atender os prazos estipulados pelos clientes é quase sempre uma tarefa árdua. Visto isso, as técnicas de modularização somadas as ferramentas que automatizam o desenvolvimento tornam-se imprescindíveis para um desenvolvimento ágil, a fim de atender as demandas.