Mostrando postagens com marcador experiência. Mostrar todas as postagens
Mostrando postagens com marcador experiência. Mostrar todas as postagens

09 outubro 2014

(LA) - Lições Aprendidas em projetos de software


O que é LA

“Lições Aprendidas” é “o conhecimento adquirido durante o projeto, que mostra como os eventos do projeto foram abordados ou devem ser tratados no futuro com o objetivo de melhorar o desempenho futuro” (PMBOK 5a Ed.).
Ouça o podcast que comento minha experiência usando o processo de LA em projetos de software. 




09 setembro 2014

O que aprendi com a programação hoje: dia 8 - internacionalização em Javascript

Esse post faz parte de uma série: o que aprendi com a programação, e tudo começou no dia 1.

2/4/95

Você consegue distinguir o formato de data acima? Não se sabe ao certo se o 2 indica o dia e o 4 o mês, pois poderia ser o contrário (1995-04-02 ou 1995-02-04). Sabe-se, no entanto que é um padrão de formato de data usado e aceito tanto nos EUA como na Inglaterra. Segundo destaca esse post, há pelo menos 6 possíveis interpretações. Mas agora veja o formato abaixo, será que o mesmo é familiar para você?

globalização do software (fonte da imagem)
09/09/2014

Provavelmente você terá condição de entender melhor, o formato de data que é mais familiar para você ou aquele que você já conhece. O formato de datas possui diversas representações universais, mas dependendo do país que o pratique, haverá maior familiaridade e facilidade de identificação de sua parte. A mesma coisa ocorre com os usuário do mundo.





Por que esses formatos são relevantes e qual a relação com a programação?
Quando estamos querendo popularizar nosso site ou nosso aplicativo, qual será a sua abrangência desejada? Será global ou continental, regional ou talvez local? Em qual país pretende disponibiliza-lo?  
Essas são apenas algumas das perguntas que terás que responder se desejar publicar um site ou aplicativo universal, no qual temos que levar em consideração o lugar, a cultura, os padrões estabelecidos do idioma do usuário.  Dependendo das suas respostas e de como decidir representar as informações, terás que traduzir os termos e textos contidos para mais de um idioma.

Haverá preocupação também com a moeda local, da representação do dinheiro, além do seu formato de datas considerando onde o usuário está agora, ou seja, a sua localização geográfica. Essa preocupação de representar a informação "correta", dependendo do idioma preferido do usuário, é uma das preocupações mais relevantes para um aplicativo que deseja ser global. Trata-se da tradução e da localização dos dados, e chamamos esse tratamento e implementação de: internacionalização.

Processo de Internacionalização e localização (fonte Wikipédia)

O processo de internacionalização pode ser feito com qualquer software e linguagens modernas, preparando e definindo diversos arquivos de dados para cada idioma pretendido. Geralmente, damos suporte para idiomas mais falados no mundo: Inglês, Espanhol, Mandarim e o idioma nativo da equipe envolvida na produção do software. Mas isso depende sempre da demanda do projeto do cliente, da equipe envolvida e da natureza do que se está fazendo. Além disso, não estou dizendo que é fácil de fazer, uma vez que traduzir conteúdo de qualidade consome esforço que deve ser considerado.

Em projetos com Android e iOS já existem formas padronizadas pelas tecnologias para usar a internacionalização. Basta seguir os procedimentos indicados e que estão detalhados na documentação de ambas. Essas padronizações, favorecem o impacto do esforço envolvido no que tange a codificação dos dados, mas não diminui o esforço de tradução.
Um bom tradutor pode valer mais do que um Google Translate? Essa discussão está fora de questão para o meu blog. :) Mas fique "esperto" sobre isso! 

Como fazer a internacionalização em um projeto Web que utiliza a linguagem Javascript, HTML 5 e CSS? 

Existem várias bibliotecas disponíveis em Javascript e que podem ser usadas. Veja essa discussão no Stackoverflow.com sobre isso.

Em nosso projeto experimentamos utilizar a biblioteca chamada i18Next, e após um pouco de estudo, achamos interessante utilizá-la primeiramente porque é simples, em segundo porque possui integração com outra biblioteca que já estamos utilizando, a conhecida jQuery. E em terceiro lugar, podemos criar mais de um arquivo de tradução usando o formato de dados JSON, um arquivo para cada idioma de tradução.

Dessa forma, vamos entender como usar essa biblioteca. Baixe as seguintes bibliotecas i18Next e jQuery, depois poderá referenciá-las no seu código HTML. Abaixo, veja o código HTML que demonstra uso de internacionalização preparado para esse post (no final do post coloquei o link para baixar o exemplo completo):




Insert title here






:

termos específicos:
  • coming:
  • completed:
  • congratulations:
termos comuns:
  • key1:
  • key2:

Agora que já declaramos nossas dependências na tag ..., podemos ver o código que utiliza a tag (data-i18n="chave"), que permite usar o valor associado à chave e descrito dos arquivos de tradução. Já o código abaixo utiliza uma estrutura Javascript criada para representar o uso da biblioteca i18Next:

/*global i18n */

var Internacionalizacao = {

 LANGUAGES_AVAILABLE : [ 'en-US', 'pt-BR' ],

 /*
  * Inicializa arquivo de traducao de acordo com a lib i18Next.
  * Veja mais detalhes aqui: 
  */
 init : function() {
  var language = Internacionalizacao.getLanguage();

  // detecta a lingua do browser e se nao tiver a desejada, setamos uma default
  if (!(Internacionalizacao.LANGUAGES_AVAILABLE.indexOf(language) > -1)) {
   language = Internacionalizacao.LANGUAGES_AVAILABLE[0]; // default en-US
  }


  i18n.init({
   lng : language,
   load : 'current'
  }, function(t) {
   Internacionalizacao.translateElements(t);
  });
 },

 /* 
  * Detecta a linguagem atual do browser do usuario
  * @return linguagem atual, exemplo: pt-BR, en-US... 
  */
 getLanguage : function() {
  var userLang = navigator.language || navigator.userLanguage;
  return userLang;
 },

 /*
  * Funcao que traduz todos os elementos que possuem data-i18n e substitui 
  * pela traduz contida em sua chave. 
  * 
  * O arquivo deve estar em /arquivo_traducao.json>.
  */
 translateElements : function(t) {
  var elements, element;

  elements = document.querySelectorAll('[data-i18n]');

  for (var index = 0; index < elements.length; index++) {
   element = elements[index];
   element.innerHTML = t(element.getAttribute('data-i18n'));
  }
 }
};

// inicializar biblioteca de traducao i18Next durante o load da página
Internacionalizacao.init();


Esse código foi criado com o nome internacionalizacao.js com o objetivo de parametrizar as configurações da biblioteca i18Next. Existem várias opções disponíveis. Veja mais detalhes no site do desenvolvedor aqui.

Por fim, teremos 4 pastas com conteúdos semelhantes a estrutura do arquivo a seguir. Cada pasta, representa um idioma suportado usando um padrão de nomes internacional para representar um idioma_país (ex. pt-BR (português do Brasil), en-US (inglês norte americano), es (espanhol), dev (padrão e comum para o aplicativo como um todo)). Sendo que o "dev" representa neste caso, palavras em comum para qualquer idioma.

{
  "coming": "Em breve teremos novos desafios a ...",
  "completed": "Você completou todos os desafios!",
  "congratulations": "Parabéns!",
  "goal": "Objetivo"
}


Rodando em alguns Browsers, por que nem todos funcionam?

A primeira coisa que demorei a compreender tem haver com a pergunta acima. Os exemplos que estava utilizando não pareciam funcionar. As mensagens de logs que a tela de inspeção de elementos (Debugging) [veja o post do dia 3 para mais detalhe], usando a view de Console, não me permitiram entender o que estava acontecendo. Pior ainda, me levando a crer que eu estava fazendo alguma coisa errada no código ou no uso da biblioteca i18Next. Tentei outras bibliotecas também. Acho que no total, foram umas 8 horas de pesquisas e testes.

Após ler uma dica do desenvolvedor do i18Next, sugerindo que testasse o exemplo do seu site no browser Firefox, me dei conta que eu estava testando apenas no Chrome. Então percebi que o Chrome possui validações de segurança para impedir que códigos maliciosos possam danificar o sistema operacional. Assim, por padrão alguns códigos não tem permissão de rodarem. A menos que usemos um server side instalado em nossa máquina, como Apache, node.js, etc. Neste caso, o browser roda sem problemas.

Rodando no browser Firefox


A imagem acima mostra como o Browser exibe o nosso pequeno exemplo. Veja que no Firefox (acima), o resultado esperado está certo, enquanto que o Chrome (abaixo), não funciona pelo motivo explicado anteriormente.

Rodando browser Chrome


Moral da história: em programação para Web, não use somente um Browser para realizar seus testes. Utilize os mais recentes, usando diferentes resoluções de telas. Os principais browsers são ilustrados na imagem abaixo:

Browsers (fonte)

O que aprendi com a programação usando a internacionalização é que podemos tornar nossa aplicação mais globalizada, considerando a região e localização do usuário. Assim, espera-se maior aceitação do aplicativo, além de considerar uma maior abrangência de sua comercialização, podendo expandir sua distribuição geográfica. 

Também aprendi que temos que tomar cuidado com os termos usados na tradução, pois o significado de uma palavra mal traduzida pode expressar outro significado, correndo risco de errar, e no pior caso, cometendo uma grande gafe ou equívoco.
A programação com javascript usando internacionalização torna o processo bem mais fácil, mas somente do ponto de vista técnico. Isso não garante conteúdo traduzido de qualidade. 

Outras estratégias também podem ser usadas para realizar a internacionalização tais como, usar imagens e metáforas visuais para representar significados. Mas isso deve ser ponderado ainda mais, pois se uma imagem vale mil palavras, errar essa representação da imagem pode representar 1000 problemas. Você tem ideia do quanto isso pode lhe custar? Mas isso é um assunto que transcende esse post. Talvez possa ser discutido em outra ocasião.

Se gostou desse post, tiver críticas ou sugestões, ou mesmo se souber de algum material que complemente o assunto discutido aqui, sinta-se encorajado em contribuir, comentando ou compartilhando em sua rede social, expandindo ainda mais nosso papo que não se encerra aqui.

:)

Os códigos fontes dos exemplos criados para esse post podem ser baixados aqui.


04 setembro 2014

O que aprendi com a programação hoje: dia 7 - Parse.com

Esse post faz parte de uma série: o que aprendi com a programação, e tudo começou no dia 1.

A plataforma Parse fornece uma solução de back-end completa para o um aplicativo móvel. Segundo a sua documentação, o objetivo do Parse é eliminar totalmente a necessidade de escrever código do servidor ou manutenção de servidores. Hoje vou abordar um pouco sobre essa tecnologia que permitiu validar uma funcionalidade de nosso projeto, no qual, dependia da infraestrutura de server side.

Para contextualizar, escute o áudio que preparei para que você entenda melhor o contexto da nossa necessidade em questão, pelo qual foi necessário encontrar soluções alternativas como serviços (SAAS).



A ideia é eliminar a dependência da infraestrutura de servidor para armazenar os dados dos diferentes clientes, que rodam nosso aplicativo em seus celulares. Com o Parse, podemos viabilizar essa estrutura com pouco esforço. O objetivo é minimizar a configuração e rapidamente começar a construir seu aplicativo com JavaScript e HTML5 em Parse.

Site do Parse.com com tradução Google Translate

Apps

Em Parse, você cria um aplicativo para cada um de seus aplicativos móveis. Cada aplicativo tem seu próprio ID e sua chave de cliente JavaScript, assim você poderá usar na sua aplicação web. Sua conta no Parse pode acomodar vários Apps. Isto é útil mesmo se você tiver um aplicativo, uma vez que você pode implantar versões diferentes para teste e produção.

Acesse o site do Parse, crie uma conta e cadastre seu aplicativo. Leia a documentação que ele possui para entender melhor.

Dependências

O JavaScript SDK do Parse, praticamente não necessita de quaisquer bibliotecas externas. A única exceção é a classe do Parse.View, que exige que você forneça jQuery ou jQuery compatível $ método.

Modelo de Objetos (Parse.Object)

Armazenamento de dados em Parse é construído em torno Parse.Object. Cada Parse.Object contém pares de chave-valores de dados JSON-compatíveis. Este dado é sem esquema, o que significa que você não precisa especificar de antemão que existem chaves em cada Parse.Object. Você simplesmente define qualquer pares de chave-valor que você quer, e a infraestrutura do Parse irá armazená-la.

Por exemplo, digamos que você está acompanhando altas pontuações para um jogo. Um único Parse.Object poderia conter:

pontuacao: 20500, nomeJogador: "Douglas Frari" , faseAtual: 3

As chaves devem ser sequências de caracteres alfanuméricos. Os valores podem ser strings, números, boleanos, ou mesmo matrizes e dicionários - qualquer coisa que pode ser JSON codificado.

Cada Parse.Object é uma instância de uma subclasse específica com um nome de classe que você pode usar para distinguir diferentes tipos de dados. Por exemplo, poderíamos chamar a pontuação mais alta como um objeto de nome GameScore.

Salvando objetos

Vamos dizer que você deseja salvar o GameScore descrito acima para o Parse Cloud. Poderia fazer assim:

var GameScore = Parse.Object.extend("GameScore");
var gameScore = new GameScore();
 
gameScore.set("score", 1337);
gameScore.set("playerName", "Sean Plott");
gameScore.set("cheatMode", false);
 
gameScore.save(null, {
  success: function(gameScore) {
    // Execute any logic that should take place after the object is saved.
    alert('New object created with objectId: ' + gameScore.id);
  },
  error: function(gameScore, error) {
    // Execute any logic that should take place if the save fails.
    // error is a Parse.Error with an error code and description.
    alert('Failed to create new object, with error code: ' + error.message);
  }
});


Recuperando os dados

Pode-se recuperar os objetos usando uma forma simples, porém, com muitas possibilidades para fazer filtros. Veja essa página com dicas: https://parse.com/docs/js_guide#objects-retrieving

 var GameScore = Parse.Object.extend("GameScore");
  query = new Parse.Query(GameScore);
  query.limit(10);
  // Sorts the results in descending order by the score field
  query.descending("score");

  query.find({
   success : function(results) {
    console.log("Successfully retrieved " + results.length
      + " scores.");
    // Do something with the returned Parse.Object values
    var object, i;

    for (i = 0; i < results.length; i++) {
     object = results[i];
     console.log(object.id + ' - '
       + object.get("playerName") + ': '
       + object.get("score"));
    }

   },
   error : function(error) {
    console.log("Error: " + error.code + " " + error.message);
   }
  });
 
Essa foi a dica do Parse.com, um serviço como alternativa a servidores externos.

Aprendi que esses serviços estão sendo muito usados por aplicativos móveis em Android e iOS, pois oferecem transparência e simplicidade aos desenvolvedores, reduz custos de desenvolvimento e eliminam a necessidade de manter um servidor externo. 

Além disso, não há preocupações com a hospedagem e manutenção desse server side. Mas nem tudo são flores. Para serviços externos mais complexos, talvez o Parse não seja tão interessante. Mas isso é tópico para se investigar por demanda em futuros posts.

02 setembro 2014

O que aprendi com a programação hoje: dia 5 - persistência em Javascript

Esse post faz parte de uma série: o que aprendi com a programação, e tudo começou no dia 1.

Imagine como seria usar um sistema que não guardasse suas informações? Ao tentar acessar seus dados e sempre que você quisesse manipular uma informação, se não estivessem armazenados, você teria que cadastrá-los antes de utilizá-los. Isso seria possível, porém bastaria reiniciar o sistema que haveria necessidade de repetir o processo anterior. Portanto, guardar informações em um sistema, tecnicamente chamada de persistência, é uma funcionalidade essencial em qualquer programa.



Um dos primeiros tablets que eu me lembro e que foram lançados no mercado, isso se podemos considerá-lo tablet, chamado Palm, possuía vários recursos interessantes para sua época, tal como uma caneta, tela com toque, programas de agenda e aplicativos com ênfase em produtividade (tais como notas, calculadora, calendário, ...). No entanto, se a bateria descarregasse, as informações previamente escritas seriam perdidas. (só os primeiros modelos) Não demorou muito para uma solução ser proposta como uma memória externa para permitir manter os dados persistentes. É claro que a experiência mostrou que esse tipo de funcionalidade deve ser integrada de forma transparente aos usuários, ou seja, deve ser utilizado de forma natural, sem que o usuário perceba, assim como você utiliza a sua memória cerebral para guardar informações.

Os programas feitos para internet usando HTML e tecnologias para Web, têm propostos diferentes abordagens para realizar uma forma de persistência. Cada linguagem propõe diferentes mecanismos. Talvez a mais simples e conhecida seja aquela abordagem de HTML, usando os chamados Cookies. Estes são apenas um conjunto de dados agrupados na representação de chave e valor, no qual a chave é uma forma de associar a informação e o valor é a própria informação propriamente dita. Essa informação é gerenciada usando o Browser do usuário e tem sido usado até hoje pela simplicidade. Porém, em termos de segurança podemos questionar o seu uso.

A proposta dos Cookies são simplicidade para armazenar e recuperar a informação quando necessário. O grande problema, talvez seja porque se diferentes browsers forem utilizados, em diferentes sistemas operacionais, por diferentes plataformas de hardware, temos uma necessidade de utilizar as linguagens de programação e suas tecnologias de banco de dados. Mas neste caso, para onde vai nossa simplicidade?

Neste sentido, o armazenamento de persistência em HTML 5 não se propõe a resolver o problema do parágrafo anterior, mas tornar ainda mais simples a forma que o Cookie propôs, ou seja, manter a possibilidade para registrar dados usando chave e valor. Só que agora, na minha opinião, usando de forma padrão para que todos que desejarem usar HTML utilizem uma maneira em comum de se fazer isso, permitindo maior compatibilidade e reuso.

Em HTML 5 podemos escolher persistir a informação em duas áreas: área de sessão e a área local.

A área de sessão mantém os dados salvos em memória RAM enquanto a sessão do navegador estiver ativa. No momento que o Browser é fechado os dados armazenados nesta área serão apagados automaticamente. Na prática os dados irão para o "céu dos computadores".

Já a área chamada de local, os dados poderão permanecer persistentes após o Browser ser fechado. Isso permite manter e recuperar os dados associadas a chaves específicas. Então se você precisa salvar os dados e recuperá-los quando a sua página é carregada, use essa área, tecnicamente conhecida como localStorage.

Vejamos um exemplo de trecho de código Javascript para fazer a persistência usando um método setar(minhaChave,meuValor):

 function set(key, data) {
  if (window.hasOwnProperty('localStorage')) {
   window.localStorage.setItem(key, data);
  }
 }


A dinâmica dessa verificação é simples. A função set(key,data) possui dois parâmetros com a chave desejada e um valor para associar com essa chave. O bloco da condição IF verifica se o atual usuário já possui a área de local disponível para ser utilizada. Caso afirmativo, podemos usar o atributo do objeto window.localStorage invocando a função setItem(...).

 function get(key) {
  if (window.hasOwnProperty('localStorage')) {
   return window.localStorage.getItem(key);
  }
 },


A forma para recuperar a informação é ainda mais simples. Só precisamos saber qual a chave que contém os dados associados com a chave apropriada. O cuidado aqui é criar chaves específicas para informações específicas. Evite nomes de chaves complicados ou com caracteres especiais. Pense em um nome de variável para renomear suas chaves.

Uma estrutura que achamos interessante utilizar e poderia ser usado através de um arquivo Javascript chamado persistencia.js:

var Persistencia = {

 property : 'localStorage',

 set : function(key, data) {
  if (window.hasOwnProperty(Persistencia.property)) {
   window.localStorage.setItem(key, data);
  }
 },

 setHash : function(key, data) {
  Persistencia.set(key, JSON.stringify(data));
 },

 get : function(key) {
  if (window.hasOwnProperty(Persistencia.property)) {
   return window.localStorage.getItem(key);
  }
 },

 getHash : function(key) {
  var data = Persistencia.get(key);

  if (data) {
   return JSON.parse(data);
  }
 },

 remove : function(key) {
  if (window.hasOwnProperty(Persistencia.property)) {
   window.localStorage.removeItem(key);
  }
 },

 clear : function() {
  if (window.hasOwnProperty(Persistencia.property)) {
   if (localStorage.length > 0) {
    localStorage.clear();
    console.log("clear function");
   }
  }
 }

};



Implementação da persistência


Que tal um pouco de prática?

Vamos complementar nosso exemplo de animação anterior e adicionar uma informação de forma persistente. Contar a quantidade de cliques na tela e manter essa informação persistente na área local. Assim, no momento que acessar o HTML da animação do nosso exemplo, a última atualização realizada deverá ser exibida na tela. Caso desejar resetar o valor atualmente persistente, pode utilizar o comando abaixo usando a ferramenta DevTools, na área de Console:

localStorage.clear();

Para baixar todos os arquivos com seus códigos fontes acesse aqui.

A imagem ao lado demonstra a execução do arquivo Bola.html que pode ser baixado, junto com os demais arquivos, no link indicado acima.

Se você tiver alguma sugestão de tópico, sugestão ou crítica, fique a vontade para comentar ou solicitar aqui.