ionic

4 Dicas para trabalhar com o Ionic Framework

1 – AngularJS

Originalmente essa não era a primeira dica, mas no decorrer da escrita notei que provavelmente era a dica mais importante. O Ionic é um framework escrito sobre o AngularJS, logo, boa parte das dicas com relação ao AngularJS cabem no Ionic (como a últim dica).

De fato o AngularJS não é o framework SPA mais performático do mercado, ele tem problemas estruturais que remetem ao início de seu desenvolvimento e impactam na performance do mesmo e é um dos motivos da total reescrita do framework para sua segunda versão. Com o passar dos meses (e versões) a equipe do AngularJS conseguiu mitigar vários dos problemas de performance e para que você consiga extrair o máximo do Ionic Framework eu recomendo fortemente que você conheça o AngularJS, seus pontos fortes, problemas, peculiaridades, arquitetura, etc.

E para otimizar a performance de seus apps sugiro que leia a série de artigos Micro tunnings with Angular apps (Parte 1 & Parte 2) do GDE Will Mendes.

2 – Native Scrolling

Uma das grandes sacadas da equipe do Ionic para a versão 1.0 "uranium-unicorn" (eu gosto desse nome), foi a implementação do Native Scrolling, que nada mais é que o scroll padrão dos dispositivos. Mas por que isso é bom? Isso é bom por que no começo do desenvolvimento do framework a equipe optou por desenvolver o scroll em javascript para poder oferecer algumas funcionalidades que não seriam possíveis no contexto daquela época dos dispositivos móveis, como Pull To Refresh, Infinite Scrolling, List Reordering, e Collection Repeat. E, convenhamos, grande parte do sucesso do framework é por causa dessas funcionalidades e de sua facilidade de utilização.

Então os dispositivos móveis evoluíram tanto o hardware quanto o software e após o Android 4.1 (Jelly Bean) e o iOS8 essas funcionalidades se tornaram possíveis graças às atualizações do navegador nativo do Android e da WKWebView no iOS8, pois ambas as plataformas passaram a ter suporte aos eventos de scroll nativo e foi aí que a equipe do Ionic resolveu implementar o Native Scrolling, pois com ele a CPU e a GPU do dispositivo móvel, que não é tão potente quanto a de um PC, não precisará mais processar o JS Scrolling, podendo então se preocupar com o que realmente importa: sua aplicação. O que deixará seu aplicativo mais rápido e resultará numa experiência mais fluída para o usuário.

O Native Scrolling funciona da mesma forma que o atributo overflow-scroll="true" na diretiva <ion-content> e para utilizá-lo basta desabilitar o jsScrolling no ionicConfig:

angular.module('ionicApp', ['ionic']).config(function($ionicConfigProvider) {
  if(!ionic.Platform.isIOS())$ionicConfigProvider.scrolling.jsScrolling(false);
})

A diferença de performance ao utilizar o Native Scrolling é notável e se torna ainda mais perceptível em dispositivos Android. No entanto essa funcionalidade ainda não está 100%. Ela não funciona muito bem com o Keyboard e o Collection Repeat. Portanto não é receomendo que você utilize o Colection Repeat ou um input em uma tela que possua o Native Scrolling ativado.

ps.: O código acima ignora a plataforma iOS pois os eventos de scroll nativos só foram implementados na WKWebView do iOS8 e o Ionic oferece suporte ao iOS7 também, logo, o scroll nativo não funcionará como deveria em todas as versões do iOS. É recomendado o uso do scroll nativo em dipositivos iOS caso o suporte de seu aplicativo seja a partir do iOS8.

3 – Debug remoto e autoreload

Durante o desenvolvimento de uma aplicação é sempre bom possuir boas ferramentas de debug para não desenvolvermos às cegas. E no caso de Aplicativos Híbridos nós podemos contar com o apoio do browser nessa tarefa.

Basta rodar o comando ionic run android -l -c -s. Para maiores informações sobre esse comando acesse o artigo Live Reload All the Things.

4 – Estrutura de diretórios e arquivos

Uma boa estrutura de diretórios e arquivos para seu aplicativo é essencial e, de fato, a estrutura dos templates (blank, sidemenu e tabs) do Ionic não é a melhor, pois conforme sua aplicação vai crescendo fica mais complicado gerenciar todos os seus controllers em um único arquivo e quando você divide esse arquivo em um para cada controller fica complicado gerenciar quais arquivos estão relacionados.

Pensando nisso a comunidade do AngularJS criou uma recomendação, chamada Best Practice Recommendations for Angular App Structure, para facilitar no desenvolvimento de Aplicações AngularJS, segundo ela o melhor é organizar seus diretórios e arquivos por funcionalidades e páginas, um exemplo simples seria algo como:

sampleapp/
    app.css
    app.js
    app-controller.js
    app-controller_test.js
    components/
        bar/                        "bar" describes what the service does
            bar.js
            bar-service.js
            bar-service_test.js
        foo/                        "foo" describes what the directive does
            foo.js
            foo-directive.js
            foo-directive_test.js
index.html

Acredito que essas 4 dicas são essenciais para melhorar a performance e a qualidade de aplicativos criados com o Ionic. Em breve voltarei com mais dicas referentes a acesso às APIs do dispositivo, PouchDB, Sincronização com webservice REST, etc.

herança

Entendendo herança no JavaScript

O javascript é uma linguagem orientada a objeto porém diferente da maioria das linguagens orientada a objeto em que a herança é baseada em classes no javascript é baseado em prototypes. Você pode construir uma "emulação" de classes com JavaScript através de funções.
JavaScript não tem classe apenas objetos, isto é, você instacia novos objetos a partir de outros obejtos.

prototype faz referência a todas as propriedades e métodos herdados do objeto pai, incluindo seu prototype.

Ele pode ser pensado como uma lista ligada referenciando o elemento anterior na lista.Um dos principais aspectos da herança de prototype é que se você alterar uma propriedade herdada ou método de um objeto, 
essas mudanças vai refletir nos seus filhos mesmo depois de terem sido criados. Isso porque os filhos remetem as propriedades e métodos do pai.

Outro aspecto importante é que você pode mudar o prototype de qualquer um dos objetos globais. Porém é perigoso, e considerado uma má prática pois objetos globais são definidos por um padrão, por isso fazer que se eles comportarem de outra forma pode ser perigoso e perder seus beneficios.

Vamos há um simples exemplo:

 

ECMAScript 5 introduziu o novo método: Object.create(). Invocando este método podemos criar novos objetos.O prototype destes novos objetos é o primeiro argumento do método:

Este método utiliza um objeto como parâmetro e retorna um novo objeto, e elimina a necessidade de acessar diretamente a propriedade prototype.

var pai = { 
	a: 10,
	b: 50,
	//Object.prototype = {a:10, b:50}
	//pai ---> Object.prototype ---> null
	metodo: function(message) {
		console.log('Eu sou o '+ message);		
	},
};

var filho = Object.create(pai); 
//filho ---> pai ---> Object.prototype ---> null
var neto = Object.create(filho);
//neto ---> filho ---> pai ---> Object.prototype ---> null
console.log(neto.a);   	//vai imprimir 10
pai.a = 20;		//Atribui 20
console.log(neto.a);   	//vai imprimir 20
console.log(filho.a);  	//vai imprimir 20
filho.metodo('filho');  //"Eu sou o pai".
neto.metodo('neto');    //"Eu sou o neto"

 

Para familiarizarmos melhor, vamos fazer uma analogia:

 

var pai = { //Objeto
	a: 10,
	b: 50
};

var filho = Object.create(pai); //criando um objeto e herdando tudo do Objeto pai

 

Seria o mesmo que em Java da seguinte forma:

Class pai { //Classe
    a: 10,
    b: 50
}
Class filho extends pai { //Herdando tudo da classe pai.

}

 

Enquanto a propriedade prototype é usada pela linguagem para construir a cadeia prototype, ainda é possível atribuir qualquer valor a ela. No entanto, os primitivos serão simplemesmente ignorados quando atribuídos como prototype.

 

function Foo() {}
Foo.prototype = 1; // sem efeito
Foo.prototype      //1
Foo.prototype.1    //lança um erro.

 

Este é um exemplo trivial, mas vamos falar de performance.O tempo de pesquisa de propriedades em que estão no alto da cadeia de prototype pode ter um impacto negativo no desempenho, e isso pode ser significativo no seu código em que o desempenho é algo critico. Além disso, tentar acessar propriedades inexistentes irá sempre percorrer a cadeia prototype inteira.

Uma característica inconveniente que é frequentemente usada é estender Object.prototype ou um dos outros contruídos em prototype.
Essa técnica é chamada monkey patching e quebra o encapsulamento. Enquanto é usada por frameworks populares como o Prototype, ainda não há uma boa razão para sobrecarregar tipos internos (built-in types) com funcionalidades adicionais não padrão.
A única boa razão para estender um prototype interno é para transportar as funcionalidades para novos motores JavaScript; por exemplo, Array.forEach.


Agora vamos há um exemplo em que adicionamos propriedades ao objeto pai e disponibilizando aos filhos.

 

var pai = { 
	a: 10,
	b: 50
};

var filho = Object.create(pai);
var neto = Object.create(filho);

console.log(neto.a);   //vai imprimir 10
pai.c = 'Olá';	       //Adiciona a propriedade c e atribui o valor "Olá"
console.log(neto.c);   //vai imprimir 'Olá'
console.log(filho.c);  //vai imprimir 'Olá'

 

Como visto os filhos herdam as propriedades do pai mesmo já tendo sido criados antes das modificações.

 

Como a definição de ojeto global : Object.create() só foi definida apartir do ECMAScript 5, temos uma maneira de contornar a situação para navegadores que não suportam:

 

if (typeof Object.create !== 'function') {
	Object.create = function (o) {
		function F() {}
		F.prototype = o;
		return new F();
	};
}


Concluindo, é essencial entender o modelo de herança baseado em prototype antes de escrever códigos complexos que fazem uso dela. Além disso, esteja ciente do tamanho das cadeias prototype no seu código e quebre elas, se necessário, para evitar possíveis problemas de desempenho ou seja prudende e use Closures ao invés de prototypes. Outro ponto, os prototypes nativos nunca devem ser estendidos a menos que seja por uma questão de compatibilidade com novas funcionalidades JavaScript.

javascript-design-patterns-cover

Module Pattern e privacidade com JavaScript

Pois bem, imagine você trabalhando com uma grande aplicação JavaScript e muitos
desenvolvedores. E você precisa encontrar uma maneira de encapsular seçoes de códigos 
para que eles tenham um namespace privado sem que haja conflitos com o código 
existente.

Como você faria isso? Ora! com Módulos (Module Pattern)

Module pattern usa "funcões imediatas" para criar uma Closure para todo
seu código encapsulado. Você pode ter membros privados e até mesmo publicar APIs publicas

Vamos a um exemplo básico:

var Modulo = (function() {
	var _variavelPrivada = "Esta é privada";
	var _outraVariavelPrivada = "Eu também sou privada";
	public = {}; //Este objeto será retornado.

	function _metodoPrivado() {
		console.log("Este método é privado");		
	};

	public.acessarMetodoPrivado = function(){
		_metodoPrivado();
	};

	public.propriedadePublica = "Esta é uma propriedade publica";
	public.metodoPublico = function() {
		console.log("Este é um método publico");		
	};
	return public;	
})()

console.log(Modulo._variavelPrivada);       //imprime "undefined".
Modulo._metodoPrivado;                      //Lança um erro ao executar.
console.log(Modulo.propriedadePublica);     //imprime "Esta é uma propriedade publica"
Modulo.metodoPublico(); 		    //imprime "Este é um método publico"

 

 

Acessando Métodos privados

E o JavaScript é impressionante pois nos permite invocar métodos privados
através de nossos métodos publicos, observe:

Modulo.acessarMetodoPrivado();	     //imprime "Este método é privado"

O padrão Module Pattern é um excelente exemplo de usar Closure para
gerenciar escopo. Dentro do Módulo existe um âmbito privado que é protegido
de modificação.

Isso não é  tudo, você pode ainda extender o Modulo facilmente através 
de outra "funcão imediata". Tudo que você tem a fazer é passar o Modulo 
original como um novo argumento para a "funcão imediata". Vejamos:

 

var Modulo2 = (function(Modulo){
	//Acesso ao módulo
	Modulo.metodoPublico();
	return Modulo;
})(Modulo)

 

Conforme o código acima, o Modulo2 tem todas propriedades e métodos publicos do Modulo e pode assim acessá-los.

 

var Modulo2 = (function(Modulo){
	//Outro método
	Modulo.novoMetodo = function() {
		console.log("Novo método");	
	};
	return Modulo;
})(Modulo || {})


console.log(Modulo);  //Imprime Object {propriedadePublica: "Esta é uma propriedade publica", metodoPublico: function, novoMetodo: function}

 

Vemos que o método foi adicionado ao módulo inicial(Modulo).

 

Contudo o Padrão de Projeto Module é altamente flexivel por fazer 
grande uso de caracteristicas dinâmicas do JavaScript. É também usado nas bibiotecas
JavaScript modernas, por exemplo JQuery.

Por fim é isso amigos, essa é mais uma boa prática de JavaScript
Mais conhecimentos avançados e padrões de projetos estão por vir aqui neste blog fiquem ligados.