JavaScript is Sexy – dica rápida

Uma dica bem rápida. Hoje (não sei exatamente como), fui parar nesse site JavaScript is Sexy. E achei o site excelente, com vários “roadmaps” para aprender assuntos diferentes mas relacionados ao JavaScript.

Por exemplo, tem um bom roadmap para aprender Node.js com confiança ou então, um outro para aprender JavaScript avançado.

Bom, fica ai a dica rápida.

Integrar é traduzir, não é reproduzir

Eu trabalho fazendo integrações de aplicações web com o SAP há alguns anos já. E existem “alguns padrões” (vou chamar de padrões), que existem no SAP que são bem particulares à esse ERP.

Só para ambientar aqueles que não conhecem nada de SAP, o SAP é um grande ERP e ele possui todo um ecossistema próprio para customização e criação de soluções de negócio. Por exemplo, ele tem uma linguagem própria o ABAP, tem um protocolo de comunicações proprietário, o RFC, entre outras coisas. Fora isso, existe também toda uma cultura particular de desenvolvimento, que honestamente, eu não conheço muito, já que nunca fui um programador ABAP.

A minha questão aqui é, independente do porque, e se esta certo ou não, geralmente quando faço integrações com o SAP encontro coisas que não estou acostumado a ver quando desenvolvo minhas soluções usando outras tecnologias, como por exemplo, .NET e C#.

Por exemplo, em muitas integrações que fiz com o SAP quando chamo uma função remota e essa gera um erro, ao invés de receber um exceção, a chamada é executada com sucesso e uma estrutura de dados (como na imagem abaixo) é retornada preenchida contendo um tipo de erro, um código e possivelmente algumas mensagens. Esse é um padrão usado e que já vi várias vezes.

Retorno de erros no SAP

Obs.: Steven McConnell deve ficar tão orgulhoso disso.

OK, mas qual é o problema disso e o que tem a ver com o que eu faço?

Bom, o problema na minha opinião, é quando esse tipo de padrão começa a vazar para outras aplicações. Tenho que admitir que eu já fiz a minha parte de permitir que isso vazasse. Shame on me!

Mas voltando, se estamos fazendo uma integração com uma aplicação terceira, não importa qual, e ela tem uma particularidade, não precisamos expor essa particularidade, podemos encapsulá-la e mudar o padrão para algo mais genérico, ou que faça sentido para a nossa plataforma de desenvolvimento. Por exemplo, no caso de um Web Service, lançar um SoapException.

Outro padrão comum ao SAP é a nomenclatura de estruturas. Não sei porque, mas encontramos muitas estruturas com esse tipo de nomenclatura.

Nomenclatura no SAP

Talvez isso faça sentido na cabeça de algum alemão louco, mas, voltando ao C#, um nome de variável pode ter até 1023 bytes, isso quer dizer que podemos ser bem mais descritivos que isso. E no caso de um Web Service também, não ha uma limitação especifica para o nome de uma tag XML.

Mais uma vez o ponto é, no momento em que estamos fazendo uma integração, seja qual for a tecnologia utilizada (no meu caso é o BizTalk), esse é o momento de abstrair particularidades, de aplicar boas práticas para quem vai consumir essa integração.

Eu vejo uma integração como uma tradutora. Ela ouve em alemão e traduz para português, ela não traduz algumas partes para português e mantém outras no formato original. Para mim, que não falo nada de alemão, isso só me atrapalharia.

E nem sempre é uma questão de certo ou errado, mas sim de pontos que são mais idiomáticos em uma tecnologia do que em outra. Nesse caso o problema são as traduções literais que muitas vezes não fazem sentido, temos que contextualizar para a tecnologia que estamos usando.

Mais uma vez usando o SAP como bode expiatório exemplo, existem alguns casos em que as strings não podem ter mais do 132 caracteres, por isso vemos estruturas como a anterior que tem campos message1, message2, message3, etc., e, embora isso funcione, é uma limitação daquela plataforma/tecnologia. Esse não é o caso de um XML ou do próprio C#, portanto, passar uma estrutura dessas adiante é simplesmente fazer uma tradução literal e não olhar para o contexto.

Concluindo, quando for integrar duas ou mais aplicações, tenha em mente os limites tecnológicos, funcionais e semânticos de cada ponta. Leve em consideração o que é um padrão proprietário e deve ser transformado do que realmente é um padrão de integração e deve ser mantido. Existem inclusive livros que podem nos ajudar com isso.

Loops for in no JavaScript

O JavaScript tem o suporte nativo a loops do tipo for in e, ele funciona de uma forma muito semelhante ao foreach do C# (por exemplo), mas temos que tomar alguns cuidados, por que como tudo no JavaScript, sempre temos uma pegadinha.

Primeiro um exemplo. Se eu quiser iterar por todas as propriedades é métodos de um objeto o código é exatamente o que imaginamos.

var propriedade;
var pessoa = {
    nome: 'Thiago',
    sobrenome: 'Temple',
    dizOla: function() {
        alert('Ola');
    }
};
for(propriedade in pessoa){
    document.writeln(propriedade);
}
//exibe: nome sobrenome dizOla

Esse código produz um retorno com: nome sobrenome dizOla

Se eu quiser exibir somente os atributos e não os métodos, eu preciso adicionar um filtro no loop, dessa forma:

for(propriedade in pessoa){
    if (typeof pessoa[propriedade] !== 'function') {
        document.writeln(propriedade);
    };
}
//exibe: nome sobrenome

Até aqui bem simples.

O primeiro ponto a considerar é que nunca podemos garantir a ordem do retorno de um loop for in. Geralmente isso não importaria muito, como no exemplo anterior, mas no caso de um array, que é também um objeto, isso pode ser importante. Nesse momento é melhor usar mesmo um loop for do que um loop for in.

A segundo ponto a considerar é que o JavaScript tem herança através da propriedade prototype, e que todo objeto herda de Object. Isso é importante porque o JavaScript é uma linguagem dinâmica e, portanto, se alterarmos Object isso vai refletir nos nossos objetos, não importa o momento que alteramos Object. Por exemplo:

var propriedade;
var pessoa = {
    nome: 'Thiago',
    sobrenome: 'Temple',
    dizOla: function() {
        alert('Ola');
    }
};

Object.prototype.naoRelacionado = 'eu nao devia estar aqui';

for(propriedade in pessoa){
    document.writeln(propriedade);
}

//exibe: nome sobrenome dizOla naoRelacionado

No código acima eu defini um objeto chamado pessoa e depois disso eu adicionei um atributo chamado naoRelacionado à Object. Mesmo assim esse atributo foi exibido dentro loop for in. Isso pode vir a ser um problema quando alteramos o prototype de Object em outra parte do código que não esta relacionado ao código que estamos fazendo.

No caso do loop for in, podemos resolver isso com o método hasOwnProperty.

for(propriedade in pessoa){
    if(pessoa.hasOwnProperty(propriedade)) {
        document.writeln(propriedade);
    }
}

//exibe: nome sobrenome dizOla

O método hasOwnProperty verifica se a propriedade foi definida no objeto em questão.

É isso ai.

Construtores de Arrays do JavaScript

Bom, o ano começou, lá se foi o carnaval e agora sim podemos dizer que o ano começou. Pelo menos aqui no blog. Alegre

Bora falar um pouco mais de JavaScript e o que existe de estranho com os construtores de Arrays do JavaScript.

Construtores de Arrays do JavaScript

No JavaScript podemos construir um Array da seguinte forma:

var a = new Array("texto");
console.log(a.length); // 1
console.log(a[0]); // texto

Quando passamos uma string ou outro tipo de objeto para o construtor de uma Array, o JavaScript cria uma array com um item e atribui o valor passado para esse item.

Agora vamos dar uma olhada em outro exemplo:

var a = new Array(3);
console.log(a.length) // 3
console.log(a[0]); // undefined

Quando passamos um número inteiro para o construtor ele cria um array com o número de elementos informados e, todos os elementos criados não tem um valor atribuído a eles, por isso o undefined.

Um terceiro exemplo:

var a = new Array(3.2); // RangeError: invalid array length

Quando passamos um número decimal para o construtor, ele obviamente não cria um array decimal, mas também não cria um array com um só elemento e com o valor passado, o JavaScript retorna um erro para esse comando.

Uma prática um pouco melhor

A melhor forma de criar arrays no JavaScript é usando o construtor implícito dele, por exemplo:

var a = ["texto"]; // Cria um elemento e atribui o valor a ele

var b = [1, 2, 3]; // Cria um array com 3 elementos e com os valores 1, 2 e 3

Um problema simples de resolver esse, não é?

Validação com jQuery Validation

008_jQuery_Validate_thumb

Validação com jQuery Validation O jQuery validation é um plugin para fazer validações de formulários. Nesse video mostro como fazer algumas validações como: campos obrigatórios customizações de mensagens validações de tipos de dados específicos como data, email e números validações …Continue lendo…

Tratamento de exceções em JavaScript

Sim, existe tratamento de exceções em JavaScript. Não é uma funcionalidade muito conhecida e, por isso talvez, não muito utilizada. Mas existem os blocos try/catch dentro do JavaScript e o comando throw. E funciona de uma forma bem similiar ao C#.

var comErro = function() {
    throw {
        name: 'CustomError',
        message: 'Um erro muito grave para ser tratado'
    };
};

try {
    comErro();
}
catch(e) {
    console.log(e.name + ' - ' + e.message); //CustomError - Um erro muito grave para ser tratado
}

Apesar do JavaScript não ser tipado, existe uma convenção que diz que todo objeto de erro deve conter ao menos duas propriedades: name e message. Acho que os nomes das propriedades são auto-explicatórios.

Obviamente, nada nos impede de adicionar outras propriedades com mais detalhes sobre o erro.

Tipos de erro do JavaScript

Por padrão o JavaScript tem internamente seis tipos diferentes de erro que ele pode gerar.

EvalError Usado quando a função eval() é usada de uma maneira incorreta
RangeError Usado quando uma variável numérica excede uma faixa de valores permitida
ReferenceError Usado quando é feita uma referência invalida à um objeto
SyntaxError Usado quando existe um erro de sintaxe
TypeError Usado quando o tipo da variável não é o mesmo que o esperado
URIError Usado quando as funções encodeURI() e decodeURI() são usadas de uma maneira incorreta.

Isso serve apenas como referência, como mostrei no exemplo anterior, podemos criar os nossos próprios tipos de erro sem problemas.

Construtores de objetos de erro

Por fim, o JavaScript também tem alguns construtores para os objetos que podemos usar para retornar um erro, por exemplo, eu poderia reescrever a exemplo acima da seguinte forma:

var comErro = function() {
    var error = new Error('Um erro muito grave para ser tratado');
    error.name = 'CustomError';
    throw error;
};

try {
    comErro();
}
catch(e) {
    console.log(e.name + ' - ' + e.message); //CustomError - Um erro muito grave para ser tratado
}

Esse código gera exatamente o mesmo resultado que antes, o único detalhe que quero ressaltar é que se eu não tivesse feito:

error.name = 'CustomError';

o nome do erro seria Error.

Como o objeto Error, temos também um construtor para cada tipo de erro do JavaScript: EvalError, TypeError, ReferenceError, etc.

Ajax com jQuery

Ajax com jQuery

Ajax com jQuery Existem diversas formas de fazer ajax com jQuery. O jQuery é muito versátil e poderoso, mas também é capaz de tornar algumas atividades que antes eram tediosas em códigos simples e curtos, ainda mais com a ajuda …Continue lendo…

Funções de callback no JavaScript

O que são funções de callback?

Uma função no JavaScript é um objeto, isso quer dizer que a gente pode passar uma função como parâmetro para outra função. Quando passamos uma função como parâmetro para outra, a função passada como parâmetro é uma função de callback.

Por exemplo:

var pessoa = function(nome, dizerOla) {
    dizerOla(nome);
};
var olaNoConsole = function(nome) {
    console.log(nome); // 
}
pessoa('Thiago', olaNoConsole);

No código acima, eu defini uma função chamada pessoa e outra olaNoConsole. A função pessoa recebe uma string com um nome e uma função de callback que ela vai usar para fazer uma saudação. Repare que, quando passo a função olaNoConsole como parâmetro, eu não utilizo parêntesis. Os parêntesis executam a função, então nesse momento que eu não quero executar a função, eu não os utilizo.
A função de callback pode ser também uma função anônima como no exemplo abaixo:

var pessoa = function(nome, dizerOla) {
    dizerOla(nome);
};
pessoa('Thiago', function(nome) {
    alert('Ola ' + nome);
});

A mesma função pessoa agora recebendo uma função anônima que faz um alert como saudação.

Por quê?

Por que fazer uso de funções de callback? Acho que o exemplo acima deixa claro que a principal vantagem é o reuso sem causar acoplamento. No caso a função pessoa nunca sabe como é feita a saudação, tudo o que ela sabe é que tem que chamar a função de callback passando um parâmetro. Foi possível trocar a saudação de console para alert sem alterar a função pessoa.

Um exemplo um pouco mais útil é quando fazemos loops de elementos, por exemplo, vamos supor que eu queira consultar todos os meus campos texto na página, fazer alguma coisa com cada um deles e no fim retornar a lista de campos.

var listaCampos = function() {
    var campos = document.getElementsByTagName("input");
    var totalItens = campos.length, i;
    for (i = 0; i < totalItens; i++) { 
        // algo bem complexo com cada campo
    }
    return campos;
};

Depois disso eu decido que eu quero que cada campo tenha uma borda vermelha, porque eu quero destacar esses campos. Eu poderia pegar o retorno dessa função, fazer um for em cada item de novo e adicionar a borda.

var campos = listaCampos();
var totalItens = campos.length, i;
for (i = 0; i < totalItens; i++) { 
    campos[i].setAttribute("style", "border: 1px solid red");
}

O problema com essa solução é que eu fiz dois loops, um quando peguei os campos e um quando quis deixá-los com a borda vermelha. É possível ser mais simples (e mais rápido) do que isso, eu poderia alterar dentro do for original da função listaCampos e adicionar a linha para deixar os campos com a borda vermelha.

var listaCampos = function() {
    var campos = document.getElementsByTagName("input");
    var totalItens = campos.length, i;
    for (i = 0; i < totalItens; i++) { 
        // algo bem complexo com cada campo
        campos[i].setAttribute("style", "border: 1px solid red");
    }
    return campos;
};

O problema dessa segunda opção é que se eu quiser usar essa função listaCampos em outra parte no meu código, eu sempre vou ter os campos com a borda vermelha. E nem sempre eu quero vermelho, pode ser que em outro ponto eu queria azul! Aí entra o callback.

var campoVermelho = function(campo) {
    campo.setAttribute("style", "border: 1px solid red");
};

var listaCampos = function(callback) {
    var campos = document.getElementsByTagName("input");
    var totalItens = campos.length, i;

    if (typeof callback !== 'function') {
        callback = false;
    }

    for (i = 0; i < totalItens; i++) { 
        // algo bem complexo com cada campo
        if(callback) {
            callback(campos[i]);
        }
    }
    return campos;
};

listaCampos(campoVermelho);

No código acima, a primeira coisa que eu fiz foi criar a função de callback que espera um campo como parâmetro e faz com que a borda desse campo fique vermelha. Depois, na função listaCampos eu alterei a função para que ela receba um parâmetro, que vai ser uma função de callback.

Em seguida eu testo para ver se uma função foi realmente passada (já que no JavaScript os parâmetros não são obrigatórios). Dentro do loop, se a função de callback foi passada como parâmetro, eu a executo.

Nesse caso agora se eu quisesse que os campos tivessem a borda azul era só criar uma outra função que fizesse isso e passar como parâmetro para a função listaCampos. A função listaCampos continua sendo genérica e pode ser utilizada por outras. Melhor que isso, é uma função que faz uma coisa só e não está com a funcionalidade acoplada a ela.

Funções de callback e escopo

Dito isso, agora vem a parte um pouco mais complicada que é a parte do escopo com as funções de callback. Imagine que ao invés de passar uma função, eu tenho um objeto e eu passo um método desse objeto como callback para a função listaCampos.

var listaCampos = function(callback) {
    var campos = documente.getElementsByTagName("input");
    var totalItens = campos.length, i;

    if (typeof callback !== 'function') {
        callback = false;
    }

    for (i = 0; i < totalItens; i++) {
        // algo bem complexo com cada campo
        if(callback) {
            callback(campos[i]);
        }
    }

    return campos;
};

var customCampo = {
    'cor': 'red',
    'defineCor': function(campo){
        campo.setAttribute('style', 'border: 1px solid ' + this.cor);
    }
};

listaCampos(customCampo.defineCor);

No exemplo acima, o objeto customCampo tem um método defineCor que eu passo como callback para a função listaCampos. O problema é que o método defineCor usa this para fazer acesso ao valor da propriedade cor. Mas, a função listaCampos faz parte do objeto global e portanto nesse momento this vai fazer acesso ao objeto global também.

A solução para esse caso é sempre que passar uma função de callback, passar também o objeto que será o contexto da função de callback.

listaCampos(customCampo.defineCor, customCampo);

E aí eu preciso modificar também a função listaCampos

var listaCampos = function(callback, ctx) {
    var campos = documente.getElementsByTagName("input");
    var totalItens = campos.length, i;

    if (typeof callback !== 'function') {
        callback = false;
    }

    for (i = 0; i < totalItens; i++) {
        // algo bem complexo com cada campo
        if(typeof callback === 'function') {
            callback.call(ctx, campos[i]);
        }
    }

    return campos;
};

Isso resolve o problema, mas quando chamamos a função listaCampos temos que informar duas vezes o objeto customCampo:

listaCampos(customCampo.defineCor, customCampo);

Existe uma forma um pouco mais elegante para isso, a gente pode chamar a função listaCampos dessa forma:

listaCampos('defineCor', customCampo);

E aí alteramos a função listaCampos para:

var listaCampos = function(callback, ctx) {
    var campos = documente.getElementsByTagName("input");
    var totalItens = campos.length, i;

    if (typeof callback === 'string') {
        callback = ctx[callback];
    }

    if (typeof callback !== 'function') {
        callback = false;
    }

    for (i = 0; i < totalItens; i++) {
        // algo bem complexo com cada campo

        if(typeof callback === 'function') {
            callback.call(ctx, campos[i]);
        }
    }

    return campos;
};

var customCampo = {
    'cor': 'red',
    'defineCor': function(campo){
        campo.setAttribute('style', 'border: 1px solid ' + this.cor);
    }
};

Um pouco mais elegante.

Por hoje é só, espero que tenha sido útil!

Se você tem ou quer ter um blog, você precisa ler esse livro

Eu terminei de ler há alguns dias e resolvi fazer uma análise do livro Technical Blogging: Technical BloggingTurn Your Expertise into a Remarkable Online Presence por Antonio Cangiano. Ainda estou digerindo tudo que aprendi nesse livro e já pondo em prática algumas várias coisas.

É um dos livros com a maior quantidade de dicas praticas que já li. Diversas dicas e ideias de uso imediato. Para quem usa, ou planeja usar, o WordPress como plataforma é ainda mais útil. O livro apresenta vários plug-ins que vão facilitar a vida na hora de escrever, ajudar a trazer mais performance para o site, trazer mais facilidade e valor para os usuários que vão ler o blog.

Produzindo conteúdo

Os capitulos 5 e 6 “Creating Remarkable Content” e “Producing Content Regularly” são ótimos para dar ideias e abrir a mente para a produção de conteúdo diversificado e com regularidade.

Promovendo seu blog

As dicas para promover o blog do capitulo 7 foram extremamente valiosas. Eu sempre tive pra mim que SEO era uma daquelas coisas irrelevantes, que simplesmente funciona e pronto, bom, não é exatamente assim. Além disso, eu passei a olhar as estatísticas de visita do site de uma outra forma.

Para empresas e blogs em grupo

Se você faz um blog para sua empresa ou grupo, essa parte também não foi esquecida, embora, para blogs como esse isso não faça tanta diferença.

Para concluir essa breve análise do livro Technical Blogging; esse foi um livro que eu comprei sem esperar muita coisa dele, achando que não ia tirar muito proveito. Me enganei. Eu comecei a ler e não parei enquanto não terminei. Ótimo, eu recomendo.