segunda-feira, 30 de dezembro de 2013

REST - Última Aula Prática - Resumo final

Vamos resumir essas doze aulas práticas que vimos e a partir do zero recriarmos todo nosso projeto (obviamente sem os fontes do CRUD, que como presente de Natal estão em um arquivo para ser baixado) através de 10 passos:

Passo 1: Instalar o Node.js.

Passo 2: Instalar o MongoDB.

Passo 3: Criar uma pasta para receber os dados do MongoDB (por exemplo C:\mongodb_data).

Passo 4: Levantar o MongoDB:
mongod --dbpath "C:\mongodb_data"
Passo 5: Instalar o Express:
npm install -g express@2.5.8
Passo 6: Criar a pasta do projeto (por exemplo app):
express app
Passo 7: Adicionar o Mongoose (biblioteca de conexão do banco) ao projeto no arquivo package.json na raiz do projeto:
...
  , "dependencies": {
      "express": "2.5.8"
    , "jade": ">= 0.0.1"
    , "mongoose": "2.6.5"
  }
}
Passo 8: Instalar o projeto, digitar o seguinte comando dentro da pasta app:
npm install
Passo 9: Baixar o arquivo com os fontes do projeto e descompactar substituindo os arquivos.

Passo 10: Na pasta app/server executar o servidor:
node server.js
Pronto já podemos ver nossa aplicação funcionando em qualquer navegador através do endereço http://localhost:3000/. Alguns detalhes bem impressionantes. Primeiro, toda a estrutura do banco de dados é criada automaticamente no momento do primeiro acesso. Segundo, é um sistema totalmente portátil, basta copiar essa pasta app completa para uma pendrive e executar novamente o servidor em qualquer máquina (desde que o MongoDB e o NodeJS estejam instalados - passos de 1 a 4).

Obrigado e até a próxima
Fernando Anselmo

domingo, 29 de dezembro de 2013

REST - Aula Prática - Excluir os Dados

Chegamos na última parte do nosso CRUD e para finalizarmos nosso projeto vamos eliminar os livros.

Mudar a Camada de Visão


Adicionamos mais um botão na tela da listagem dos dados. No arquivo index.html, na seção dos botões, inserimos a seguinte codificação:
   ...
    <div class="btn-group" ng-hide="nome == ''">
     <a class="btn btn-large" ng-click="excluir()">Excluir</a>
    </div>
   ...
Este botão será visível somente quando um livro for selecionado na listagem. Ao ser pressionado, chama a função excluir do arquivo controller.js. Adicionamos dentro da ListaCtrl (que controla a janela de listagem) uma função com a seguinte codificação:
function ListaCtrl($scope, $http) {
  ...
  $scope.excluir = function() {
    if ($scope.nome != '') {
      $http.delete('/excluir/' + $scope.nome)
        .success(function(data) {
          if (data == 'err') {
            alert("Houston, temos um problema");
          } else {
            alert("Livro Excluído...");
          }
          document.location.reload(true);
      })  
    }
  }  
}
Ao ser chamada, esta função executa o método delete da variável $http no qual é passado (como no processo da pesquisa da alteração) um caminho com o nome do livro selecionado. Verificamos a resposta se obteve ou não sucesso para eliminar o livro. O comando final reload é usado para reprocessar a página e fazer desaparecer da listagem o livro excluído.

Mudar a Camada de Dados


No arquivo funções do banco, adicionamos a função excluir (abaixo da função modificar):
exports.excluir = function (req, res) {
  livroModel.remove({nome: req.params.nom}).exec(function(err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
O comando remove do banco é usado para eliminar um registro com base nos parâmetros passados, funciona de mesma forma como o comando find já visto.

Mudar a Camada do Servidor


Adicionamos ao servidor a nova rota para exclusão:
app.delete('/excluir/:nom', routes.excluir);
E agora nos resta adicionar esse caminho no arquivo de rotas para disparar a função do banco, realizado através da seguinte codificação:
exports.excluir = function(req, res) {
  livro.excluir(req, res);
};
Pronto, observamos que a exclusão é o mais simples dos processos, assim, concluímos a letra D do nosso CRUD e com isso finalizamos nosso projeto. Espero que todas essas lições possam ser bem proveitosas para ajudar a divulgar a arquitetura REST.

Obrigado e até a próxima
Fernando Anselmo

quinta-feira, 26 de dezembro de 2013

REST - Aula Prática - Alterar os Dados (Parte 2)

Nesta segunda parte, iremos realizar a alteração dos dados a partir do formulário com o livro selecionado.

Mudar a Camada de Visão


Procedemos as seguintes adições no arquivo controller.js na função EditarCtrl:
function EditarCtrl ($scope, $http) {
  ... 

  $scope.modificar = function() {
    $http.put('/modificar/' + $scope._id, $scope.livro).success(function(data) {
      if (data == 'err'){
        alert("Houston, temos um problema");
      } else {
        alert("Livro Modificado...");
        window.location = '/';
      }
    })  
  }  
}
Esta função é chamada pelo botão Modificar do formulário que por sua vez passa o ObjectID e o livro modificado pelo formulário. Por que não passar o "nome"? Porque senão este campo não poderia ser alterado, a menos que optássemos por manter mais uma variável não editável contendo o nome não alterado. Após o livro ser alterado no banco retornamos (com o comando window.location) para a tela principal.

Mudar a Camada de Dados


Agora vamos proceder a modificação do livro no banco. No arquivo de funções, inserimos a seguinte função (abaixo da função procurar):
exports.modificar = function (req, res) {
  livroModel.update({_id: req.params.id},
    {nome: req.body.nome, autor: req.body.autor}).exec(function(err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
Com base no id passado, procedemos um comando update do banco. Este comando é dividido em duas partes, a primeira corresponde ao dado de localização e a segunda os campos a serem alterados. Se comparássemos com SQL a primeira parte seria o WHERE enquanto que a segunda os campos do SET.

Mudar a Camada do Servidor


No arquivo do servidor adicionamos a nova rota que recebe o parâmetro "id":
app.put('/modificar/:id', routes.modificar);
E terminamos com a adição do caminho para a chamada da tela no arquivo de rotas para chamar a função de banco criada:
exports.modificar = function(req, res) {
  livro.modificar(req, res);
};
Após o usuário alterar os dados na tela dispara a função modificar para a rota indicada passando a ObjectID e o livro como objeto encapsulado no corpo da requisição (request), exatamente por este motivo o método PUT é o mais indicado para alteração. Com essa concluímos a letra U e na próxima finalizaremos o nosso CRUD com a exclusão dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 23 de dezembro de 2013

REST - Aula Prática - Alterar os Dados (Parte 1)

Optei por dividir a alteração por ser um tanto complexa (nada para morrer de susto). Nesta primeira parte, chamamos o formulário com o livro selecionado. Não pretendo me repetir deste modo, recomendo que veja a postagem anterior para tirar qualquer dúvida sobre qual arquivo modificar (que serão os mesmos e na mesma sequência).

Mudar a Camada de Visão


Adicionamos um botão na tela da listagem dos dados (abaixo do botão de Novo), na página que produz a listagem dos livros:
    ...
    <div class="btn-group" ng-hide="nome == ''">
     <a class="btn btn-large" href="/editar/{{nome}}">Editar</a>
    </div>
    ...
Este botão somente é visível ao selecionarmos um livro da listagem. Existe um evento ng-click="select(livro)" na tag "tr", que na Controller desta página, dispara a função select que atribui a variável $scope.nome a descrição do livro selecionado. Nosso próximo passo consiste em criar um formulário chamado quando o caminho editar for executado. Na pasta \views criamos a página editar.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/js/angular.min.js"></script>
  <script src="/js/controllers.js"></script>
 </head>
 <body ng-app ng-controller="EditarCtrl">
  <div class="container">
   <h2>Livro Selecionado</h2>
   <form ng-model="livro" name="livroform" class="form-horizontal">
    <div>
     <label for="nome" class="label" style="margin-right:6px;">Nome:</label>
     <input id="nome" placeholder="{{livro.nome}}" ng-model="livro.nome" />
    </div>
    <br />
    <div>
     <label for="autor" class="label" style="margin-right:6px;">Autor(es):</label>
     <input id="autor" placeholder="{{livro.autor}}" ng-model="livro.autor" />
    </div>
    <div class="form-actions">
     <button ng-click="modificar()" class="btn btn-primary">Modificar</button>
     <a href="/" class="btn">Voltar</a>
    </div>    
   </form> 
  </div>
 </body>
</html>
É quase uma cópia do formulário para a inserção do livro, alguns desenvolvedores optam por um único formulário e procedem as mudanças dinamicamente. Para não complicar demais, preferi deixá-los separados. Adicionamos a seguinte função no arquivo controller.js que responde a este formulário:
function EditarCtrl ($scope, $http) {
  $scope._id = 0;
  $scope.livro = {};
  var caminho = document.URL;
  caminho = caminho.substring(caminho.lastIndexOf('/'));
  $http.get('/lista/livro' + caminho).success(function(data) {
    $scope._id = data[0]._id;
    $scope.livro.nome = data[0].nome;
    $scope.livro.autor = data[0].autor;
  })
}
Da mesma forma que fizemos para listarmos vários livros, executamos uma função do banco que retorna (de modo Json) o registro selecionado.

Mudar a Camada de Dados


Necessitamos criar uma função para retornar um determinado livro. No arquivo de funções do banco, inserimos a seguinte função (abaixo da função gravar):
exports.procurar = function (req, res) {
  livroModel.find({nome: req.params.nom}).exec(function(err, livro) {
    if (err) { return console.log(err); }
    return res.json(livro);
  });
}
Não vamos brincar com ID's (que será utilizado somente no momento de proceder a alteração). Neste momento, poderíamos até passar a ObjectID, entretanto isso ficaria bem estranho no caminho URL (outras das pequenas regras de REST - Caminhos reconhecíveis pelo usuário), aqui trafegamos somente o que o usuário reconhece que é o nome. A função find localiza registros por qualquer parâmetro passado (é como um SELECT de SQL), vejamos alguns exemplos:

  • find({idade:{$gt:18}}) - Registros que possuem o campo idade maior que 18
  • find({valor:{$gt:50,$lt:100}}) - Registros que possuem o campo valor maior que 50 e menor que 100
  • find({editora :'OReilly'}).where('valor').gt(50).lt(100) - Registros que possuem o campo editora com o valor 'OReilly' e o campo valor maior que 50 e menor que 100
  • find({editora :'OReilly'}).limit(2)- Os dois primeiros registros que possuem o campo editora com o valor 'OReilly'
Acredito que já deu para sentir o que podemos produzir com a função "find".

Mudar a Camada do Servidor


No arquivo do servidor adicionamos duas novas rotas para chamar a tela e outra para disparar a função do banco criada, ambas recebem o parâmetro "nom":
app.get('/editar/:nom', routes.editar);
app.get('/lista/livro/:nom', livro.procurar);
E finalizamos com a adição do caminho para chamar a tela no arquivo de rotas:
exports.editar = function(req, res) {
  fs.readFile('../views/editar.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};
O que acontece? O usuário seleciona um determinado registro da listagem e em seguida pressiona o botão Editar, este dispara a rota "/editar/nome" que chama o formulário. Através da "Controller" uma nova rota é disparada a "/lista/livro/nome" que executa a função procurar e fornece uma página Json com o registro selecionado, este é carregado para a variável $scope.livro e mostrado na página. Na próxima continuamos nosso CRUD com a segunda parte da modificação dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

sábado, 21 de dezembro de 2013

REST - Aula Prática - Inserir os Dados

Antes de começarmos é muito importante que veja a postagem anterior sobre a nova organização do projeto. Existem várias maneiras de realizarmos um CRUD, optei pela mais simples, a listagem dos dados e três botões o primeiro chama a tela para inclusão de registros, o segundo chama a tela para a modificação de um registro selecionado na listagem e o último elimina o registro selecionado na listagem.

Mudar a Camada de Visão


Dessa vez vamos mudar da visão ao servidor, nosso primeiro passo consiste em adicionar um botão na tela da listagem dos dados, para isso no arquivo \views\index.html adicionamos a seguinte codificação:
   ...
   <h2>Meus Livros</h2>
   <div class="btn-toolbar">
    <div class="btn-group">
     <a class="btn btn-large" href="/novo">Novo</a>
    </div>
   </div>

   <label for="criteria" class="label" style="margin-right:6px;">Pesquisar</label>
   ...
Devemos observar o local onde este botão será inserido. Nosso próximo passo consiste em adicionar o formulário a ser chamado quando este botão for pressionado. Na pasta \views criamos uma página chamada novo.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/lib/angular.min.js"></script>
  <script src="/javascript/controllers.js"></script>
 </head>
 <body ng-app ng-controller="NovoCtrl">
  <div class="container">
   <h2>Novo Livro</h2>
   <form ng-model="livro" name="livroform" class="form-horizontal">
    <div>
     <label for="nome" class="label" style="margin-right:6px;">Nome:</label>
     <input id="nome" ng-model="livro.nome" size="80" />
    </div>
    <br />
    <div>
     <label for="autor" class="label" style="margin-right:6px;">Autor(es):</label>
     <input id="autor" ng-model="livro.autor" />
    </div> 
    <div class="form-actions">
     <button ng-click="criar()" class="btn btn-primary">Salvar</button>
     <a href="/" class="btn">Voltar</a>
    </div>    
   </form> 
  </div>
 </body>
</html>
Temos então um formulário para fornecer os dados a um objeto de Livro. Devemos lembrar que a arquitetura REST prega a utilização dos seguintes métodos:
  • POST para o evento de inclusão dos dados;
  • PUT para o evento de alteração dos dados; e 
  • DELETE para o evento de exclusão dos dados.
Respeitaremos essas indicações, no arquivo \sist\javascript\controllers.js adicionamos a função NovoCtrl (abaixo da função ListaCtrl) que gerencia esta página:
function NovoCtrl ($scope, $http) {
  $scope.criar = function() {
    $http.post('/criar', $scope.livro)
      .success(function(data){
        if (data == 'err'){
          alert("Houston, temos um problema");
        } else {
          alert("Livro Incluído...");
        }
        $scope.livro={};
    })  
  }  
}
Criamos uma função de escopo chamada criar que é utilizada pela tela (na Controller tudo o que é de $scope pode ser compartilhado com a tela), e ao ser chamada executa o método post da variável $http com a passagem do caminho e um objeto de Livro. Verifica a resposta se obteve ou não sucesso para inserir o novo livro.

Mudar a Camada de Dados


No arquivo \views\dados\livroFuncoes.js adicionamos a função gravar (abaixo da função listar):
exports.gravar = function (req, res) {
  var novoLivro = new livroModel({
    nome:req.body.nome,
    autor:req.body.autor
  });
  novoLivro.save(function (err) {
    if (err) {
      callback(err);
    } else {
      res.send();
    }
  });
}
Através do corpo da requisição (variável req) temos os dados do formulário. Certa vez me perguntaram se não era necessário gravar um id, perguntei se desejava trabalhar totalmente Orientado a Objetos ou não, não existem ids em OO (isso é coisa de banco relacional que precisa de chaves primárias para localizar registros), o que existe é o ObjectID que é mantido e controlado pelo banco, e com esse só vou me importar ao alterar um registro. Para adicionarmos um novo (repare o comando new) objeto no banco, disparamos o método save que envia se a informação foi ou não incluída no Banco.

Mudar a Camada do Servidor


Precisamos de mais duas pequenas alterações, no arquivo \server\server.js adicionamos as novas rotas (na seção "Rotas do Sistema"), uma para chamar a tela e outra para disparar a função do banco:
app.get('/novo', routes.novo);
app.post('/criar', routes.criar);
E por fim adicionamos esses caminhos no arquivo \routes\index.js através da seguinte codificação:
exports.novo = function(req, res){
  fs.readFile('../views/novo.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};

exports.criar = function(req, res) {
  livro.gravar(req, res);
};
Já podemos inserir os registros em nosso banco (ou seja, concluímos a letra C), na próxima continuamos o nosso CRUD com a primeira parte da modificação dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 16 de dezembro de 2013

REST - Aula Prática - Arrumar o Projeto e Listar os Dados

Na postagem anterior vimos como colocar os dados no MongoDB, só que ao rever os arquivos anteriores descobri que deixei algumas coisas um tanto mal organizadas (o que pode prejudicar lá na frente) então permita-me nesta postagem arrumar o projeto para finalizarmos nosso CRUD.

Qual editor utilizar?


Essa é uma dúvida que muitas pessoas me fazem. Qualquer um serve entre o NotePad++ ao Eclipse, prefiro usar um editor intermediário, como o Free JavaScript Editor que possui inclusive autocomplete de código. O mais famoso deles se chama Sublime Text, muitos professores que usam Mac o utilizam, existem versões para Windows e Linux também, só que o preço da licença (70 dólares) chega a assustar muitas pessoas.

Arrumar a Camada do Servidor


Trocamos o nome do arquivo do servidor para server.js e o colocamos na pasta \server, com a seguinte codificação:
if (!process.env.NODE_ENV) process.env.NODE_ENV='development'

var express = require('express'),
  routes = require('../routes'),
  livro = require('../dados/livroFuncoes.js');

var app = module.exports = express.createServer();

app.configure(function(){
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use('/css', express.static(__dirname + './../public/stylesheets'));
  app.use('/js', express.static(__dirname + './../public/javascripts'));
});

// Ambientes
app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
  app.use(express.errorHandler());
});

// Rotas do Sistema
app.get('/', routes.index);
app.get('/lista/livro', livro.listar);

// Ativar o Servidor
app.listen(3000);
console.log("Servidor está executando na porta %d em modo de %s", app.address().port, app.settings.env);
Na primeira linha, definimos o modo que o servidor é iniciado em development (desenvolvimento) ou production (produção), veja na seção ambientes as diferenças (aqui basicamente se mostrará ou não uma trilha de erro completa). Em seguida vemos as bibliotecas de uso e a configuração do servidor. O caminho das rotas de acesso e o inicio do servidor na porta 3000.

Para completar a definição desses caminhos, na pasta \routes existe por padrão um arquivo chamado index.js, devemos deixá-lo com a seguinte codificação:
var fs = require('fs'); 
 
exports.index = function(req, res){
  fs.readFile('../views/index.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
};
Este arquivo contém os caminhos (as rotas) do sistema, e indica qual arquivo é chamado, no servidor deixamos apenas as indicação dos caminhos para este arquivo.

Arrumar a Camada de Dados


Agora vamos organizar os arquivos que fazem a comunicação com o banco MongoDB. Na pasta principal \app criamos uma pasta chamada \dados e adicionamos o arquivo livroFuncoes.js com a seguinte codificação:
banco = require('./livroDb.js'),
exports.listar = function (req, res){
  livroModel.find().exec(function(err, livro) {
    if (err) { return console.log(err); }
    return res.json(livro);
  });
} 
Este arquivo é responsável por todas as funções de acesso a tabela (em breve teremos a inclusão, alteração, exclusão), neste momento, possui uma única função que retorna uma listagem dos dados do arquivo em formato Json. Criamos, também nesta pasta, um arquivo chamado livroDb.js com a seguinte codificação:
mongoose = require('mongoose');

// Conexão com o Banco 
mongoose.connect('mongodb://localhost:27017/livro');
var db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', function calbckcallback() {
    init();
});

function init() {
    schema = new mongoose.Schema({
      nome: {type: String, unique: true},
      autor: String
    });
    livroModel = mongoose.model('Livro', schema);
}
Este era o nosso antigo arquivo db.js. Aqui temos uma conexão com o banco e a função init() que determina como é a estrutura da tabela.

Arrumar a Camada de Visão


Copiamos todo o conteúdo da pasta \sist para a pasta \views. Nesta pasta \views:
  • Copiamos o arquivo \css\bootstrap.css para a pasta \public\stylesheets e eliminamos a pasta \css.
  • Copiamos os arquivos \javascript\controllers.js, \lib\angular.min.js e \lib\angular.min.js.map para a pasta \public\javascripts e eliminamos as pastas \javascript e \lib.

Na pasta \views criamos o arquivo index.html com a seguinte codificação:
<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="/css/bootstrap.css">
  <script src="/js/angular.min.js"></script>
  <script src="/js/controllers.js"></script>
 </head>
 <body ng-app ng-controller="ListaCtrl">
  <div class="container">
   <h2>Meus Livros</h2>
   <label for="criteria" class="label" style="margin-right:6px;">Pesquisar</label>
   <input id="criteria" type="search" ng-model="criteria">
   <table class="table table-striped table-hover table-bordered">
    <thead>
     <th>Título</th>
     <th>Autor(es)</th>
    </thead>
    <tr ng-repeat="livro in livros | filter:criteria | orderBy:'nome'"
        ng-click="select(livro)" ng-class="{'info': nome == livro.nome}">
     <td>{{livro.nome}}</td>
     <td>{{livro.autor | uppercase}}</td>
    </tr>
   </table>
  </div>
 </body>
</html>
Mostramos uma listagem principal dos dados conforme vimos anteriormente no arquivo hello.html. Preferi republicá-lo neste outro arquivo para completarmos nossa padronização da codificação e não restar mais nenhuma dúvida. O próximo arquivo fica na pasta \views\javascript, é o arquivo controllers.js e possui a seguinte codificação:
function ListaCtrl($scope, $http) {
  $scope.nome = '';
  $http.get('/lista/livro').success(function(data) {
    $scope.livros = data;
  })
  $scope.select = function(livro) {
    $scope.nome = livro.nome;
  }
}
Esta função acessa o Json e obtém os dados para carregar a variável $scope.livros para o preenchimento da tabela. A função select será utilizada quando na seleção de um registro (para as funções de alteração e exclusão).

Nossa estrutura final ficou com o seguinte formato:
/app - Pasta raiz do projeto
 /dados - Camada de Dados
  livroDB.js - Acesso ao MongoDB
  livroFuncoes.js - Funções da tabela "livros"
 /public
  /images - imagens do projeto
  /javascripts - bibliotecas e controllers
   angular.min.js - Biblioteca do AngularJS
   angular.min.js.map - Mapeamento do AngularJS
   controllers - Arquivo de Controller para o AngularJS
  /stylesheets
   bootstrap.css - Arquivo de estilos do Bootstrap
   style.css - Arquivo de estilos criado por padrão
 /routes
  index.js - Contém as rotas do sistema
 /server - Camada do Servidor 
  server.js - Inicia o servidor (na linha de comando: supervisor server.js)
 /views - Camada de Visão
  index.html - Janela principal do sistema
A única pasta que está faltando é a \node_modules que são os módulos utilizados como: express, mongoose e supervisor. Essa organização foi necessária para podermos continuar com nossos estudos.

Com esta implementação podemos ver os dados que foram inseridos no banco (ou seja, concluímos a letra R), na próxima postagem continuaremos nosso CRUD com a inserção dos dados na tabela.

Obrigado e até a próxima
Fernando Anselmo

segunda-feira, 9 de dezembro de 2013

REST - Aula Prática - Brincar com o MongoDB

Nosso projeto atualmente se encontra com a seguinte configuração, já temos o AngularJS, Bootstrap e Node.js, esse último sendo comandado pelo Supervisor, além disso sua funcionalidade é uma única tela capaz de listar os dados que estão no servidor (app.js). O problema é que na camada de Dados temos o "fake" de uma lista que não armazena nada.

Já falei sobre o MongoDB e agora vamos nos aprofundar muito mais nesse banco e seu relacionamento com o Node.js. Já publiquei uma postagem sobre esses dois juntos e recomendo fortemente que leia-o antes de se aventurar aqui pois odeio ser repetitivo.

Tipos Suportados

Um detalhe super interessante no uso do MongoDB com Javascript é a quantidade de tipos nativos que são suportados ou convertidos, vamos a eles:

  • Float é de 8 bytes e diretamente conversível para o tipo Number do Javascript
  • Double Class para uma classe representando um valor float, útil quando se utiliza coleções onde é necessário a garantia que os valores são sempre em ponto flutuante.
  • Integer32 e Integer64 é um pouco mais complicado, pelo fato que o Javascript representa todo número acima dos 64 bits como float, resultado que o máximo valor do inteiro está em 53 bits. O MongoDB possui dois tipos de inteiros, de 32 bits e 64 bits. Resultado que o driver (Mongoose) vai encaixar bem o valor de 32 bits, e se tiver que promovê-lo para 64 bits enquadrá-lo em 53 bits, se puder. Se não for possível retornará uma instância da Long class para evitar a perda de precessão.
  • Long class permite armazenar os inteiros de 64 bits.
  • Três tipos que possuem um mapeamento direto para JavaScript:
    • Date trabalho com datas.
    • RegExp trabalho com expressões regulares
    • String tipo caractere (codificada em UTF-8)
  • Binary Class armazenagem dados grandes.
  • Code Class funções javascript, pode fornecer um escopo para executar esse método.
  • ObjectID Class contém um identificador de documento MongoDB (o equivalente a uma chave primária)
  • DBRef Class inclusão de uma referência em um documento apontando para um outro objeto
  • Symbol Class especificar um símbolo, não é realmente relevante para Javascript, mas para idiomas que suporta o conceito de símbolos.

Adicionar os Dados do MongoDB

Siga a postagem anterior para configurar o projeto com o MongoDB (adicionar o Mongoose ao projeto e o arquivo db.js para realizar a conexão). Com isso pronto inicie e acesse o console do MongoDB e digite os seguintes comandos (pressione Enter ao final de cada uma das linha):
use livro
db.livros.save({nome:'Effective Java', autor:'Joshua Bloch'})
db.livros.save({nome:'Year without Pants', autor:'Scott Berkun'})
db.livros.save({nome:'Confessions of public speaker', autor:'Scott Berkun'})
db.livros.save({nome:'JavaScript Good Parts', autor:'Douglas Crockford'})
db.livros.save({nome:'AngularJS', autor:'Brad Green & Shyam Seshadri'})
db.livros.save({nome:'Node.js in Action', autor:'Mike Cantelon, TJ Holowaychuk & Nathan Rajlich'})
db.livros.save({nome:'Node: Up and Running', autor:'Tom Hughes-Croucher & Mike Wilson'})
Pronto, nesse momento temos a nossa base de livros e autores no MongoDB, próximo passo é fazê-la aparecer na tela. Como sei que deseja tentar realizar isso primeiro deixarei como exercício para nosso próximo encontro.

Obrigado e até a próxima
Fernando Anselmo


sábado, 23 de novembro de 2013

REST - Aula Prática - AngularJS e NodeJS com Supervisão

Começamos nossa aplicação, porém quero entender alguns detalhes: Primeiro, por quê estamos usando o "Bootstrap" se quase não estamos utilizando um layout decente? Segundo, toda vez que mudamos algo no servidor teremos que derrubá-lo e iniciá-lo novamente? E terceiro, cadê a vantagem em usar o "AngularJS"? Do jeito que está acho que um simples HTML resolve. Armei algumas perguntas e nesta postagem pretendo corrigí-las.

Usando Realmente o Bootstrap e o AngularJS

Antes de mais nada quero confessar que sou um leitor compulsivo, então vamos mudar um pouco o escopo dessa aplicação de "discos" para "livros". Alteramos a variável ficheInfo no arquivo app.js para a seguinte variável:

var fichaLivro=[
  {nome:'Effective Java', autor:'Joshua Bloch'},
  {nome:'Year without Pants', autor:'Scott Berkun'},
  {nome:'Confessions of public speaker', autor:'Scott Berkun'},
  {nome:'JavaScript Good Parts', autor:'Douglas Crockford'},
  {nome:'AngularJS', autor:'Brad Green & Shyam Seshadri'},
  {nome:'Node.js in Action', autor:'Mike Cantelon, TJ Holowaychuk & Nathan Rajlich'},
  {nome:'Node: Up and Running', autor:'Tom Hughes-Croucher & Mike Wilson'}
]
...
app.get('/api/ficha', function(req, res) {
  res.json(fichaLivro);
});

Devemos pensar que em breve esses dados virão do MongoDB (em um próximo artigo). Vamos manter essa tabela relativamente simples, com o nome do livro e seus respectivos autores, apenas para não termos que nos preocupar em aprender comandos complexos do banco (o objetivo é aprender Arquitetura REST). Modificamos o arquivo hello.js de forma a armazenar os dados da página JSON gerada em uma variável:

function lstControl($scope,$http){
  $http.get('/api/ficha').success(function(data){
    $scope.livros = data;
  })
  $scope.index = -1;
  $scope.select = function(index) {
    $scope.index = index;
    $livro = $scope.livros[index];
  }
}

Um novo método select armazena um livro selecionado na tabela para fins de modificação. Por fim, trabalhamos sobre o HTML, iremos utilizar às praticidades do Bootstrap e do AngularJS como se deve, modificamos o arquivo hello.html para:

<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.css">
  <script src="lib/angular.min.js"></script>
  <script src="javascript/hello.js"></script>
 </head>
 <body ng-app ng-controller="lstControl">
  <div class="container">
   <h2>Meus Livros</h2>
   <div class="btn-toolbar">
    <div class="brn-group">
     <a class="btn btn-large" href="">Editar</a>
    </div>
   </div> 
   <label for="criteria" class="label" style="margin-right:6px;">Pesquisar</label>
   <input id="criteria" type="search" ng-model="criteria">
   <table class="table table-striped table-hover table-bordered">
    <thead>
     <th>Título</th>
     <th>Autor(es)</th>
    </thead>
    <tr ng-repeat="livro in livros | filter:criteria | orderBy:'nome'"
        ng-click="select($index)" ng-class="{'info': $index == index}">
     <td>{{livro.nome}}</td>
     <td>{{livro.autor | uppercase}}</td>
    </tr>
   </table>
  </div>
 </body>
</html>

Toda a especificação CSS3 virá do Bootstrap, logo no começo temos um DIV que pertence a classe "container" que é a principal, então todos os outros elementos seguirão esta informação. Ganhamos uma barra de botões (futuramente será utilizada para I-A-E). Nossa tabela recebeu mais um item no qual podemos filtrar os livros (seja pelo título ou autor), isso acontece graças a um filtro (filter) do elemento ng-repeat. A tabela também está ordenada (orderBy) pelo campo 'nome'. Todos esses novos detalhes são realizados dinamicamente através do Ajax. Outra brincadeira foi quanto ao nome dos autores, que agora aparece sempre em letras maiúsculas (observe o 'uppercase'). Podemos selecionar cada elemento da tabela (futuramente para editar/excluir) que será destacado dos outros (através da ng-class), para realizar isso, capturamos o ng-click que é enviado para o método select que guarda este registro.

Supervisor

O que se entende por "hot-deploy"? É a capacidade de um servidor detectar se ocorreram mudanças em seus arquivos e disponibilizar para o cliente uma nova versão da aplicação. Supervisor é um pequeno script para o Node.js, simplesmente fica "escutando" as mudanças no código, e em caso positivo realiza um "hot-deploy", porém sem se preocupar com vazamentos de memória ou se certificar de limpar todas as referências inter-módulo, ou seja, excelente para um ambiente de desenvolvimento mas terrível para um de produção. Podemos proceder sua instalação pelo NPM da seguinte forma:

npm install supervisor -g

E agora iniciamos o servidor com:

supervisor app.js

Qualquer alteração em qualquer arquivo, será automaticamente detectada e servidor será reiniciado. Como dever de casa para a próxima lição, tente fazer com que ao clicar no botão editar seja chamado um formulário contendo o livro.

Obrigado e até a próxima
Fernando Anselmo

sexta-feira, 15 de novembro de 2013

REST - Aula Prática - AngularJS e NodeJS

Até o presente momento aprendemos como utilizar um monte de softwares de modo independente e agora começamos a juntar todas às ideias. Porém, gostaria de lembrar que REST é uma Arquitetura e que pode ser aplicada a qualquer software, escolhi JavaScript simplesmente para mostrar que é possível criar um sistema interessante com essa tecnologia.

Considere as postagens passadas como pré-requisitos obrigatórios.

Montando o Ambiente

Inicialmente precisamos baixar o AngularJS, para isso digite:
bower install angular

Veja mais referências sobre o Bower na postagem anterior. Para montarmos a estrutura do nosso sistema digite

express app
cd app
npm install

Crie dentro da pasta "app" a seguinte estrutura de pastas:

/sist
   /css
   /javascript
   /lib

Copie os seguintes arquivos:

  • Para a pasta "css" copie o arquivo "bower_components\bootstrap\docs\assets\css\bootstrap.css"
  • Para a pasta "lib" copie o arquivo "bower_components\angular\angular.min.js"

Pronto, toda a estrutura do nosso projeto já está montada.

AngularJS através do Servidor NodeJS

Começamos nossa aplicação na pasta "app", modifique o arquivo app.js:

var ficheInfo=[
  { id:1, nom:"Paulinho", prenom:"Moska" },
  { id:2, nom:"Maria", prenom:"Gadú" },
  { id:3, nom:"Cássia", prenom:"Eller" }
]

var express = require('express'),
  routes = require('./routes'),
  fs = require('fs');

var app = module.exports = express.createServer();

app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.static(__dirname + '/public'));
  app.use('/javascript', express.static(__dirname + '/sist/javascript'));
  app.use('/lib', express.static(__dirname + '/sist/lib'));
});

app.configure('development', function(){
  app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});

app.configure('production', function(){
  app.use(express.errorHandler());
});

// Rotas do Sistema

app.get('/', function(req, res) {
  fs.readFile('./sist/hello.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
});
app.get('/api/affiche', function(req, res) {
 res.json(ficheInfo);
});

app.listen(3000);
console.log("Express server listening on port %d in %s mode", app.address().port, app.settings.env);

Lembramos que este arquivo é o "tiro inicial" do nosso servidor. As modificações neste arquivo foram:

  • A criação de uma lista de artistas com a seguinte estrutura: id, nome e sobrenome.
  • A adição da FS para lermos arquivos.
  • A disponibilização de uso das duas pastas contidas na pasta "sist"
  • A modificação da rota padrão "/" para a execução do arquivo "hello.html".
  • A adição da rota "/api/affiche" que gera uma saída em formato JSON da nossa lista de artistas criada inicialmente.

Uma das características de um sistema REST é a pré-descrição da arquitetura de GET e POST, ou seja, todas as rotas devem existir como identificação no servidor. Na pasta "sist" crie um arquivo chamado "hello.html" e adicione as seguintes linhas:

<!doctype html>
<html>
 <head>
  <meta Charest="UTF-8">
  <title>Teste AngularJS/NodeJS</title>
  <link rel="stylesheet" type="text/css" href="css/bootstrap.css">
  <script src="lib/angular.min.js"></script>
  <script src="javascript/hello.js"></script>
 </head>
 <body ng-app ng-controller="monControl">
  <h3>Listagem dos Cantores</h3>
  <div ng-repeat="a in artistas">
   <p>{{a.id}}. {{a.nom}} {{a.prenom}}</p>
  </div>
 </body>
</html>

Como visto na aula de Listas com o AngularJS, temos a tag "ng-repeat" que interage com coleções. Na pasta "javascript" crie um arquivo chamado "hello.js" e adicione as seguintes linhas:

function monControl($scope,$http){
 $http.get('/api/affiche').success(function(data){
  $scope.artistas = data;
 })
}

No controller "monControl" carregado para a variável de escopo "list o resultado da chamada da pasta "/api/affiche" que será produzida via JSON através do NodeJS. É dessa forma que ocorre a interação entre o NodeJS e o AngularJS, o servidor produz um conteúdo e o cliente obtém através de uma URL. Agora resta apenas executar a aplicação com o comando:

node app.js

Acesse o endereço: http://localhost:3000/, e veja a aplicação funcionando.

Obrigado e até a próxima
Fernando Anselmo

quarta-feira, 30 de outubro de 2013

REST - Aula Prática - Controles com o Bower

Antes de começarmos vamos concordar em pelo menos um item: Tudo o que já vimos até aqui é bem interessante, porém ter que controlar todos esses pacotes na mão vai acabar virando um verdadeiro círculo do Inferno de Dante (me desculpe acabei me viciando no livro de Dan Brown). São muitos pacotes para conseguirmos uma aplicação completa. Durante as minhas pesquisas, descobri um aplicativo (também feito em JavaScript) chamado BOWER que é um gerenciador de pacotes para a Web.

Para usá-lo, devemos seguir alguns pré-requisitos como a necessidade do software GIT, que é um sistema de controle de versão distribuído e um sistema de gerenciamento de código fonte muito comum para quem utiliza o Linux. E também precisaremos do NodeJS já instalado. Vamos colocar em ordem nossos pré-requisitos:

  • Instale o GIT for Windows
  • Instale o NodeJS

Uma vez pronto, podemos começar e instalar o Bower. Em uma tela de comandos digite:

npm install -g bower

O NPM foi instalado junto com o NodeJS, informe-se mais nos artigos anteriores (a opção -g significa "instalação global"). Uma vez que o Bower foi instalado corretamente podemos usá-lo para instalar e manter quaisquer pacotes que sejam necessários. Por exemplo se desejamos brincar com a jQuery. Proceda da seguinte forma:

bower install jquery

Observe que criada uma pasta chamada "bower_components" no qual contém todos os arquivos necessários para usarmos a última versão estável da jQuery. Podemos manter todos os pacotes baixados com um simples comando:

bower update

Também podemos rapidamente verificar quais são os pacotes que temos com o comando:

bower list

Ou, se desejarmos, desinstalar qualquer pacote com o comando:

bower uninstall <nome_pacote>

Acha que isso tudo é bobeira? Pois bem, na aula passada comentei sobre o projeto AngularStrap, se ficou curioso descobriu que entre o projeto existe uma série de dependências entre: jQuery, BootStrap e AngularStrap. As escolhas são, baixar corretamente e acertar todos os pacotes ou resolver tudo com o seguinte comando:

bower install angular-strap

E utilizar corretamente todos os pacotes necessários para montar a página HTML de modo a utilizar o objeto TimePicker:

<!DOCTYPE html>
<html>
 <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link 
   href="bower_components/bootstrap/docs/assets/css/bootstrap.css" 
   type="text/css" rel="stylesheet"  />
  <link 
   href="bower_components/angular-strap/vendor/bootstrap-timepicker.css" 
   type="text/css" rel="stylesheet" />
  <script type="text/javascript" 
   src="bower_components/jquery/jquery.min.js"></script>
  <script type="text/javascript" 
   src="bower_components/bootstrap/docs/assets/js/bootstrap.js"></script>
  <script type="text/javascript" 
   src="bower_components/angular-strap/dist/angular-strap.js"></script>
  <script type="text/javascript" 
   src="bower_components/angular-strap/vendor/bootstrap-timepicker.js"></script>
 </head>
 <body>
  <div class="input-append bootstrap-timepicker">
   <input id="timepicker1" type="text" class="input-small">
   <span class="add-on"><i class="icon-time"></i></span>
  </div>
  <script type="text/javascript">
   $('#timepicker1').timepicker();
  </script>
 </body>
</html>

Sem querer bancar o chato, prefiro a coisa mais prática.

Obrigado e até a próxima
Fernando Anselmo

terça-feira, 15 de outubro de 2013

REST - Aula Prática - AngularJS, Bootstrap e Listas

Uma das piores características sobre um sistema HTML, é um sistema HTML feio. Existem milhares de possibilidades através do CSS3 e não é necessário ser/ter um maravilhoso Artista Gráfico para conseguir compor algo decente. O projeto Bootstrap é um daqueles que aparecem para salvar a alma de muitos projetos medíocres. Contém arquivos em formato CSS3 para criar um layout bem definido.

Para o nosso segundo trabalho com o AngularJS, baixe o Bootstrap e crie o nosso projeto conforme o seguinte conjunto de pastas:

 \exemplo
     \css
        bootstrap.min.css
     \script
        angular.min.js

Na pasta exemplo, crie um arquivo chamado "notas.html", com a seguinte codificação:

<!doctype html>
<html ng-app>
 <head>
  <title>Anotações do Dia</title>
  <meta charset="utf-8">
  <link rel="stylesheet" href="css/bootstrap.min.css">
  <script src="script/angular.min.js"></script>
  <script src="script/notas.js"></script>
  <style type="text/css">
   .feito-true {
    text-decoration: line-through;
    color: red;
   }
  </style>  
 </head>
 <body>
  <div class="container" ng-controller="NotasController">
   <div class="row">
    <div class="page-header">
     <h1>Lista de Coisas a Fazer</h1>
    </div>
   </div>
   <div class="row">
    <table class="table table-striped">
      <thead>
     <tr>
       <th>Título</th>
       <th>Horário</th>
       <th>Realizado?</th>
     </tr>
      </thead>
      <tbody>
     <tr ng-repeat="nota in notas" class="feito-{{ nota.feito }}">
       <td><strong>{{ nota.titulo }}</strong></td>
       <td>{{ nota.horario }}</td>
       <td><input type="checkbox" ng-model="nota.feito"></td>
     </tr>
      </tbody>
    </table>
   </div>
   <div class="row">
    <form class="form-inline" name="frmNota">
      <input type="text" ng-model="nota.titulo" placeholder="Título">
      <input type="text" ng-model="nota.horario" placeholder="Horário">
      <button class="btn btn-primary" ng-click="adicionarNota()">Adicionar Nota</button>
    </form>
   </div>
  </div>
 </body>
</html>

E na pasta script crie um arquivo chamado "notas.js" com a seguinte codificação:

function NotasController($scope) {
 $scope.notas = [
  {titulo: 'Bater o Ponto', horario: '08:00 AM', feito: false},
  {titulo: 'Tomar Café', horario: '09:20 AM', feito: false}
 ];

 $scope.adicionarNota = function () {
  $scope.notas.push({titulo: $scope.nota.titulo,
         horario: $scope.nota.horario,
         feito: false});
  $scope.nota.titulo = $scope.nota.horario = '';
 };
}

O AngularJS cria uma lista com base em um array de elementos, sejam estes quais forem, no caso teremos 3 campos: titulo, horario e feito (realizado). Na página HTML montamos uma tabela usando a tag ng-repeat que percorre cada elemento da lista. Criamos um formulário que ao ser executado chama a função adicionarNota que insere um novo elemento a partir dos dados do formulário com o comando push e limpa os dados da tela.

Um exercício para ajudar a desenvolver seu potencial. O campo "horário" ficou um tanto estranho na tela já que o ideal seria mais interativo. Recomendo que conheça o projeto AngularStrap, uma mistura entre o AngularJS e o Bootstrap com algumas séries de novas tags criadas para facilitar alguns trabalhos. Na página, encontramos uma série de exemplos e entre eles um elemento chamado Timepicker.

Obrigado e até a próxima
Fernando Anselmo

quinta-feira, 10 de outubro de 2013

REST - Aula Prática - Node.JS e MongoDB

Nesta segunda parte da aplicação REST, entenderemos o que vem a ser o Node.JS e como inserir dados no banco MongoDB. A IBM publicou um dos melhores e dos mais esclarecedores artigos sobre o que exatamente é o Node.js?. Resumidamente, o Node é uma plataforma de software que liberta JavaScript do navegador e permite que seja usado como uma plataforma de desenvolvimento de software em aplicações Server-Side. Executa sobre um motor ultra-rápido do Chrome, V8, e acrescenta em uma biblioteca rápida e robusta de módulos de I/O de rede assíncrona. Tendo como foco principal a construção de alto desempenho, um servidor altamente escalável e aplicativos cliente para o "Real Time Web". Uau. Aposto que pelo menos ficou curioso, então vamos brincar.

Criando a Aplicação com Express

No site oficial do Node.js baixe e instale o servidor. Vamos brincar em um esquema um pouco diferente de um simples 'Hello World', abra uma janela de comandos e instale o Express:

npm install -g express@2.5.8

Para manter uma organização, criaremos uma pasta para hospedar os projetos, por exemplo C:\rest. Dentro desta digite o seguinte comando para criar nosso projeto:

express notas

Finalize a configuração com:

cd notas
npm install

Então, temos nosso primeiro projeto em C:\rest\notas. Vamos baixar os drivers para acessarmos nosso banco, para tanto altere o arquivo package.json, da seguinte forma:

{
  "name": "Notas", 
  "version": "0.0.1",
  "private": true,
  "dependencies": {
    "express": "2.5.8",
    "jade": ">= 0.0.1",
    "mongoose": "2.6.5"
  }
}

Adicionamos uma dependência ao Mongoose (que é o driver para o MongoDB), instale através do seguinte comando:

npm install

Estamos com o esqueleto da aplicação totalmente montada. O Express funciona quase como o 'Maven', só que ao invés de Java utiliza uma dependência de pacotes com JavaScript e JSON. Editamos o arquivo app.js na raiz do projeto e adicionamos as seguintes linhas:

var express = require('express'),
  routes = require('./routes'),
  fs = require('fs'),
  NotaModel = require('./models/NotaModel.js');

...

app.configure('production', function(){
  app.use(express.errorHandler());
});

app.get('/form', function(req, res) {
  fs.readFile('./form.html', function(error, content) {
    if (error) {
      res.writeHead(500);
      res.end();
    } else {
      res.writeHead(200, { 'Content-Type': 'text/html' });
      res.end(content, 'utf-8');
    }
  });
});

app.post('/gravar', function(req, res) {
  var titulo = req.body.titulo;
  var descricao = req.body.descricao;
  NotaModel.gravarNota(titulo, descricao, function(err, user) {
    if (err) throw err;
      res.redirect('/form');
  });
});
...

Criamos duas chamadas: "/form" e "/gravar". A primeira traz um formulário HTML enquanto que a segunda recebe os dados deste formulário e grava no banco. Criamos, nesta mesma pasta (que é a raiz do nosso projeto), um arquivo chamado form.html com a seguinte codificação:

<h1>Minhas Notas</h1>
<form action="/gravar" method="post">
  <div>
    <label>Título:</label>
    <input type="text" name="titulo"/><br/>
  </div><div>
    <label>Descrição:</label>
    <textarea row="3" col="60" name="descricao"></textarea>
  </div><div>
    <input type="submit" value="Gravar Nota"/>
  </div>
</form>

Este formulário recebe os dados e quando submetido executa a chamada a ação "/gravar". No meu site publiquei um documento chamado MongoDB com Java, recomendo que baixe e leia para ter melhores referências sobre este banco.

Na camada com o MongoDB

O próximo passo é criar um arquivo de configuração para acessar o MongoDB. Na raiz do projeto criamos uma pasta chamada \lib, nesta um arquivo chamado db.js com a seguinte codificação:

var mongoose = require('mongoose');
var Schema = mongoose.Schema;
module.exports.mongoose = mongoose;
module.exports.Schema = Schema;
connect();

function connect() {
  var url = 'mongodb://localhost:27017/notas';
  mongoose.connect(url);
}
function disconnect() {
  mongoose.disconnect()
}

Temos dois métodos neste script, um para conectar e outro para desconectar o banco. Na url de conexão passamos o endereço do servidor, a porta e o nome da base de dados (que se não existe, será criada). Próximo passo é criarmos a tabela (que no MongoDB é chamado de Coleção). Na raiz do projeto criamos uma pasta chamada \models, nesta um arquivo chamado NotaModel.js com a seguinte codificação:

var db = require('../lib/db');

var NotaSchema = new db.Schema({
  titulo: {type: String, unique: true},
  descricao: String
})

var MinhaNota = db.mongoose.model('Nota', NotaSchema);

module.exports.gravarNota = gravarNota;

function gravarNota(titulo, descricao, callback) {
  var instance = new MinhaNota();
  instance.titulo = titulo;
  instance.descricao = descricao;
  instance.save(function (err) {
    if (err) {
      callback(err);
    } else {
      callback(null, instance);
    }
  });
}

Executar a aplicação

Inicie o servidor do MongoDB (veja no PDF disponibilizado como proceder) e o servidor do Node.JS com o seguinte comando:

node app.js

Acesse o endereço http://localhost:3000/form para testar a aplicação e cadastre algumas notas. Em seguida acesse o servidor do MongoDB e digite os seguintes comandos:

show dbs [e verifique que existe uma base chamada notas]
use notas
show collections [e verifique que existe uma coleção chamada notas]
db.notas.find() [e observe os dados que foram digitados]

Então é isso, agora podemos nos divertir persistindo dados no MongoDB através de um servidor puramente JavaScript.

Obrigado e até a próxima
Fernando Anselmo

terça-feira, 8 de outubro de 2013

REST - Aula Prática - AngularJS

Vi no Facebook um artigo bem interessante sobre um workshop para ensinar como criar sistemas inteiros apenas com Javascript. Com um pequeno escopo de softwares entre eles o AngularJS, Node.js e utilizando o MongoDB. O que mais me interessou foi a frase final "O aluno terminará o workshop entendendo como cada parte se integra para criar uma aplicação REST". E isso ativou todas minhas antenas (ou meus Eus), então fomos (eu e meus Eus) atrás de toda a informação possível sobre essas ferramentas (apesar de já conhecer muito bem o MongoDB).

Os artigos que pretendo postar aqui sobre essa junção vem com base em um documento chamado "Créer une <<application web>> avec AngularJS, nodeJS et mongoDB" v110813 - Brouillon (fiquei meio perdido quanto ao autor mas, acredito se tratar de David Roche), além disso dou graças aos livros da O'Reilly e Manning que me ajudaram a tirar muitas dúvidas. Então vamos juntos travar conhecimento do Rest através de uma aplicação prática ao invés de ficarmos somente na teoria.

Vamos começar pelo AngularJS que é um framework JavaScript, open source e desenvolvido pela Google. Este framework segue o modelo MVC (model-view-control) e foi a base de construção do Gmail e GoogleDoc. O AngularJS possui algumas características bem interessantes entre elas os atributos "ng-", para produzirmos nosso primeiro exemplo baixe o arquivo "angular.min.js". Para facilitar nosso estudo, criamos a seguinte estrutura de pastas:

\exemplo
   \script
       angular.min.js
       exemplo01.js
   exemplo01.html

Edite o arquivo exemplo01.js e insira os seguintes códigos:

function meuControle($scope){
  $scope.minhaVariavel="Famoso Hello World !";
} 

E para o arquivo exemplo01.html, insira os seguintes códigos:

<!doctype html>
<html ng-app>
 <head>
  <title>Teste do AngularJS</title>
  <script src="script/angular.min.js"></script>
  <script src="script/exemplo01.js"></script>
 </head>
 <body>
  <h1 ng-controller="meuControle">{{minhaVariavel}}</h1>
 </body>
</html>

O atributo ng-app define que este é um programa AngularJS, e o atributo ng-controller informa que o escopo da aplicação está definido com base em um determinado controlador. Um dos princípios base do AngularJS é a nomeação da data-binding, isto é, a capacidade de modificar informações da parte HTML através do JavaScript. Só que essa modificação se faz nos dois sentidos: HTML para JavaScript quanto JavaScript para HTML.

Adicione mais duas linhas ao HTML (ou crie um outro arquivo chamado exemplo02.html, copie as mesmas linhas deixando o <body> vazio):

...
  Outra Variável: <input type="text" ng-model="outraVariavel" size="30" placeholder="Insira o valor da Variável" />
  <h1>{{outraVariavel}}</h1>
 </body>
</html>

E na medida que digitamos um valor na caixa de texto, este aparece simultaneamente em tela. Como o outro valor advém de um controlador, devemos criar um formulário e submetê-lo. Então adicione (ou crie um outro arquivo chamado exemplo03.html e deixe o <body> idêntico ao exemplo01.html) as seguintes linhas:

  <form ng-submit="modificarVariavel()">
   Minha Variável: <input type="text" ng-model="valorForm" size="30" placeholder="Insira o valor da Variável" />
   <input class="btn-primary" type="submit" value="Mudar"/>
  </form>
 </body>
</html>  

Também precisaremos modificar o arquivo exemplo01.js para o seguinte conteúdo:

function meuControle($scope){
  $scope.minhaVariavel="Famoso Hello World!";
  $scope.modificarVariavel = function() {
    $scope.minhaVariavel = $scope.valorForm;
    $scope.valorForm = '';
  };
} 

A ideia é tremendamente simples, uma vez que o formulário for submetido será chamado a função "modificarVariavel" que troca o valor de "minhaVariavel" pelo conteúdo do campo "valorForm" e limpa o campo "valorForm". Porém observe que não funcionou. O que está errado? Tente descobrir antes de continuar lendo...

Observe que o atributo "ng-controller" está definido somente para a tag "h1", pode-se dizer que o controle só atende a esta tag então, para solucionar o problema retire esse atributo desta tag e coloque-o na tag "body", deixando o seguinte código:

<body ng-controller="meuControle">
Obrigado e até a próxima
Fernando Anselmo

domingo, 6 de outubro de 2013

Mineração de Dados - Arquitetura do Hadoop

Na postagem anterior, instalamos o Hadoop que é uma plataforma para o fornecimento de armazenamento distribuído e capacidades computacionais. O Hadoop foi concebido para corrigir o problema de escalabilidade que existia na Nutch um pesquisador e rastreador de código aberto. Nessa época a Google havia publicado diversos artigos que descreviam um problema com o sistema de arquivos distribuídos, o GFS (Google File System) e o MapReduce, uma estrutura computacional para o processamento em paralelo.

A implementação bem sucedida desses papéis do Nutch resultou em dois projetos separados, o segundo se tornou o Hadoop, e foi criado como um projeto da Apache.

Componentes do Hadoop

HDFS é o componente de armazenagem de Hadoop. Um sistema de arquivos distribuído é modelado com base no GFS. HDFS é otimizado para um alto rendimento e funciona melhor quando a leitura/escrita e realizada em arquivos grandes (gigabytes e maiores). Para suportar esta transferência o HDFS aproveita grandes (para um sistema de arquivos) tamanhos de bloco e otimizações pesquisa de dados para reduzir o I/O de rede.

Escalabilidade e disponibilidade são também características chaves do HDFS, conseguida em parte devido à replicação dos dados e da tolerância a falhas. HDFS é tolerante a falhas de software e hardware, e automaticamente replica os blocos de dados dos nós que falharam.

MapReduce é um framework de computação distribuídos baseada em lote (batch). Permite paralelizar o trabalho ao longo de uma grande quantidade de dados brutos, tais como combinar web logs com dados relacionais de um banco de dados OLTP para o modelo como os usuários interagem com o site. Este tipo de trabalho poderia levar vários dias ao utilizar as técnicas convencionais de programação em série, porém, é reduzido a poucos minutos.

O modelo MapReduce simplifica o processamento em paralelo ao abstrair as complexidades envolvidas no trabalho com sistemas distribuídos, como a paralelização computacional, a distribuição do trabalho e ao lidar com hardware/software confiáveis. Com essa abstração, o MapReduce permite que o programador se concentre em atender às necessidades de negócios, ao invés de perder tempo em complicações de um sistema distribuído.

Arquivos de Configuração do Hadoop

  • hadoop-env.sh - configurações específicas do ambiente. Na instalação configuramos o JAVA_HOME. Também podemos especificar opções da JVM para vários componentes do Hadoop, personalizar os diretórios e os locais dos arquivos do master e dos slaves.
  • core-site.xml - contém os itens de configuração do Hadoop ao nível do sistema, como a URL do HDFS, o diretório temporário e os locais de script de suporte de reconhecimento de clusters.
  • hdfs-site.xml - configurações como o total de replicação de arquivos, tamanho do bloco, e quais permissões são aplicadas.
  • mapred-site.xml - configurações como o número padrão para a redução de tarefas, padrão mínimo/máximo de tamanhos de memória e execução especulativa.
  • masters - lista com os hosts que estão no servidor. Devemos ter cuidado pois ao iniciar o Hadoop é lançado o NameNode e JobTracker no host local a partir do qual emitimos o start, e em seguida o SSH para todos os nós que estão neste arquivo para iniciar um SecondaryNameNode.
  • slaves - lista com os hosts que são escravos do Hadoop. Ao iniciar o Hadoop é localizado o SSH de cada host neste arquivo e lançado os DataNode e TaskTracker daemons.

Agora que já entendemos o que é o Hadoop e como funciona seu mecanismo podemos partir para novas atividades em breve.

Obrigado e até a próxima
Fernando Anselmo

PS.
Conheça mais sobre o GFS em http://research.google.com/archive/gfs.html.
Conheça mais sobre o MapReduce em http://research.google.com/archive/
mapreduce.html.

Mineração de Dados - Hadoop no Windows (com Cygwin)

O Apache Hadoop é um banco extraordinário e feito especialmente para Big Data. Em vários sites pode-se obter as características deste banco. Porém um detalhe, foi criado para Linux, o que pretendo fazer é em uma máquina exclusivamente Windows 7 (sem nenhuma espécie de emulador) rodar este banco. Para isto vamos precisar do Cygwin. (Lembro: que por ser um banco feito em Java é necessário que a JDK tenha sido instalada corretamente antes de começarmos).

1º Passo: Instalando o Cygwin


Baixe e execute o instalador do Cygwin até o momento que for solicitado os pacotes. Nesta tela pesquise (search) cada um dos seguintes pacotes marcando todas suas opções (troque aonde estiver escrito skip):

  • openssh
  • openssl
  • Tcp_wrappers
  • Diffutils
Deixe prosseguir e finalizar a instalação. Ao término pode desmarcar a opção "Add icon to Start Menu".


2º Passo: Configurando o Cygwin


Entre no ícone criado do Cygwin e digite o comando: ssh-host-config, digite a seguinte configuração:

  • privilege: yes (ENTER)
  • new local account: yes (ENTER)
  • install ssh as service: yes (ENTER)
  • value of CYGWIN: (somente pressione ENTER)
  • different name: no (ENTER)
  • create new privilege: yes (ENTER)
  • Entre com uma senha
No Windows, ative o serviço: CYGWIN sshd


3º Passo: Configurando o Hadoop


Baixe no site do Hadoop o arquivo hadoop-[versão atual]-bin.tar.gz e coloque-o na pasta do seu usuário (C:\users\seu_usuário), pois esta é a pasta que o Cygwin utiliza por padrão.

Para descompactar o arquivo, retorne ao Cygwin e digite: tar xzvf hadoop-[versão atual]-bin.tar.gz. Após o término da descompactação, entre na pasta do Hadoop através do gerenciador de arquivos e selecione a pasta conf. Edite (como por exemplo Notepad++) agora os seguintes arquivos:

a. hadoop-env.ssh

Existe uma linha comentada da localização da JAVA_HOME, remova o comentário (#) e corrija com a localização correta da pasta aonde está instalada a JDK. Por exemplo:

export JAVA_HOME=C:/arquiv~1/Java/jdk1.7.0_01

Lembrando que no Linux não existe a pasta "Arquivos de Programas" que deve ser trocada para seu nome simples "arquiv~1"

b. core-site.xml

Adicione para a tag <configuration> o seguinte conjunto:

<configuration>
  <property>
    <name>fs.default.name</name>
    <value>hdfs://localhost:9000</value>
  </property>
</configuration>

c. hdfs-site.xml

Adicione para a tag <configuration> o seguinte conjunto:

<configuration>
  <property>
    <name>dfs.replication
    <value>1
  </property>
</configuration>

d. mapred-site.xml

Adicione para a tag <configuration> o seguinte conjunto:

<configuration>
  <property>
    <name>mapred.job.tracker</name>
    <value>localhost:9001</value>
  </property>
</configuration>

4º Passo: Iniciando o Ambiente


De volta ao Cygwin, digite: cd hadoop-[versão atual]. Precisamos verificar se podemos criar uma nova keygen, use o seguinte comando:

$ ssh localhost

Realizado todos os procedimentos digite:

$ ssh-keygen -t dsa -P '' -f ~/.ssh/id_dsa 
$ cat ~/.ssh/id_dsa.pub >> ~/.ssh/authorized_keys
$ exit

Somente na primeira vez, precisamos distribuir os arquivos de sistema, para tanto digite:

$ bin/hadoop namenode -format

Para iniciar o Hadoop digite:

$ bin/start-all.sh

Para testar se esta tudo funcionando, abra um navegador e digite o seguinte endereço: http://localhost:50070, e como resposta a página do Hadoop aparecerá. Agora já estamos com o nosso banco instalado e funcionando, futuramente vamos realizar alguns testes.

Obrigado e até a próxima
Fernando Anselmo

PS. Para interromper o Hadoop digite:

$ bin/stop-all.sh



sábado, 28 de setembro de 2013

REST - Modelo de Maturidade de Richardson

Durante a sua apresentação Justice Will Take Us Millions Of Intricate Moves no QCon San Francisco 2008, Leonard Richardson propos uma classificação para os Web Services. O Modelo de Maturidade de Richardson (RMM - Richardson Maturity Model) propõe três níveis de maturidade com base no suporte deste serviço para URI, HTTP e Hipermídia.

Nível 0 - Service end point communication

É caracterizado pelos serviços que possuem uma única URI, e utiliza um método único HTTP (tipicamente POST). A maioria dos Web Services baseados em (WS-*) utilizam um único URI para identificar um ponto final, e o protocolo HTTP POST para transferir as cargas baseadas em SOAP, efetivamente ignorando o resto dos verbos HTTP.

Nível 1 - Resource based communication

O próximo nível de maturidade emprega muitas URI mas um simples verbo HTTP. A chave da fundamental da divisão entre estes tipos de serviços rudimentares e o Nível 0, é que o nível de um serviço pode expor inúmeros recursos lógicos, enquanto que o Nível 0 todas as interações são realizadas através de um único (grande, complexo) túnel de recursos. Neste nível as interações são através da inserção dos nomes da operação e os parâmetros em uma URI, em seguida, transmitir essa URI para um serviço remoto, normalmente via HTTP GET.

Nível 2 - HTTP verbs based communication

Este nível acolhe inúmeros recursos URI endereçáveis​​. Esse apoio aos serviços vários dos verbos HTTP em cada recurso é exposto. Incluído neste nível serviços como CRUD são realizados, onde o estado dos recursos, que representam tipicamente entidades empresariais, podem ser manipulados através da rede.

Nível 3 - Hypermedia communication

Este nível de serviço suporta a noção de hipermídia como motor do estado para um aplicativo. Ou seja, as representações podem conter links URI para outros recursos que possam ser de interesse para os consumidores. O serviço leva os consumidores através de uma trilha de recursos e obtém como resultado as transições de estado da aplicação.

Resumidamente, este modelo define três níveis para se trabalhar com a arquitetura Web, porém consideramos que apenas o Nível 3 trabalha com a arquitetura REST:
  • Nível 1 (Recursos) - Lida com a complexidade e utiliza o termo dividir e conquistar, quebra a extremidade de um serviço grande em vários recursos.
  • Nível 2 (Verbos HTTP) - Introduz um conjunto padrão de verbos HTTP de forma que possamos lidar com as situações semelhantes, da mesma forma, com a remoção de variação desnecessária.
  • Nível 3 (Controle Hipermídia) - Permite a descoberta, e proporciona uma forma de criar um protocolo mais auto-documentado.
Obrigado e até a próxima
Fernando Anselmo

PS. Um excelente artigo sobre este tema pode ser acessado aqui.

quinta-feira, 26 de setembro de 2013

REST - Fundamentos da Arquitetura RESTful

O termo REST se originou através de um trabalho de Doutorado chamado Architectural Styles and the Design of Network-based Software Architectures, nele o Dr. Roy Thomas Fielding escreve:
"A REST (Representational State Transfer) é pretendida como uma imagem do projeto da aplicação se comportará: uma rede de websites (um estado virtual), onde o usuário progride com uma aplicação selecionando as ligações (transições do estado), tendo como resultado a página seguinte (que representa o estado seguinte da aplicação) que está sendo transferida ao usuário e apresentada para seu uso."
Este trabalho pode ser facilmente encontrado na Web e sua leitura é bastante interessante. As ideias e termos que descrevem sistemas "RESTful" podem ser encontrados em sua essência neste documento, sem os formalismos propostos pelos interesses diversos que tentam deturpar no intuito de tentar vender algo. Seus conceitos são uma excelente demonstração que pode ser utilizado como referência para uma implementação de um sistema Web. Em linhas gerais uma URL (Uniforme Resource Locator) é utilizada para identificar e expor um serviço RESTful. Imaginemos isso um ponto de início a uma publicação de qualquer coisa que contenha um serviço REST. E possua como retorno algo como XML, JSON ou qualquer formato hipermídia.

Então podemos pensar em REST em um conjunto de princípios que definem como os padrões Web, HTTP e URIs devem ser usados. A promessa é que ao aderir aos princípios REST e projetar uma aplicação, obteremos um sistema que explora a arquitetura da Web em toda sua potencialidade. A habilidade de poder obter uma informação em diferentes termos é possível por causa de uma separação do nome dos recursos advindos de um formulário.

REST é melhor utilizado para sistemas desacoplados de informação que devem produzir e consumir para várias fontes de tecnologias. Podemos definir suas propriedades como:

  • Alta performance
  • Escalável
  • Generalista
  • Simples
  • Fácil modificação
  • Extensível
Talvez já tenhamos ouvido falar dessa promessa em várias outras tecnologias, a pequena diferença é que REST nada tem a ver com linguagem, software e não é uma biblioteca (como ITIL) trata-se simplesmente de uma Arquitetura. Siga e tenha seus benefícios, não siga e estará fazendo qualquer outra coisa.

Obrigado e até a próxima
Fernando Anselmo

PS. Desculpe pela demora de artigos pois estava me aprofundando em duas tecnologias que me interessam Data Mining e REST. Então, me desculpe se daqui para frente serei meio tendencioso em manter esses dois assuntos sempre presentes neste blog. Seja bem vindo ao começo do futuro.

terça-feira, 10 de setembro de 2013

Apresentações - O Poder das Imagens

Um dos livros que mais amei ter escrito foi "O Guia para o Palestrante Empresarial", o criei como uma espécie de auto biografia na tentativa de poder expor o que aprendi nestes mais de 20 anos em que ministro apresentações e palestras.


Não pretendo lançar uma nova versão deste livro, não por ter esgotado o assunto, mas simplesmente por ter outros planos em mente. Só que vou aproveitar-me deste blog e publicar alguns "complementos" deste livro (não se preocupe, não terá de comprá-lo para entender o assunto).

Em 1970, a revista Scientif American publicou o resultado de um interessante experimento feito por Ralph Haber. Este experimento consistia em mostrar uma série de 2.560 slides de fotografias para uma pessoa a velocidade de uma a cada 10 segundos. Em cálculos simples em 7 horas todos os slides seriam vistos, porém foi mostrado em um período de vários dias. Após o último slide ter sido mostrado, foi realizado um teste que consistia em saber se a pessoa conseguiria reconhecê-los. Incrivelmente, a média atingida ficou entre 85% a 95% de reconhecimento.

Só que este experimento foi além, e, novamente, foram mostradas novas imagens só que agora a uma velocidade de uma por segundo. E por incrível que isso possa parecer o resultado final foi idêntico, ou seja, Haber demonstrou que o cérebro humano possui uma capacidade incrível para reter imagens.

Pensando de modo prático, qual a vantagem disso? Imagine a realização de uma apresentação para sua empresa, seja de um novo produto, seja de um novo sistema. Se deseja que as pessoas retenham as informações apresentadas se utilize de imagens ao invés de palavras. Deixe-me propor um teste simples, sem retornar seus olhos ao início deste texto quais foram as primeira palavras lidas (título não incluído)? Difícil não? Prova que dificilmente o cérebro armazena palavras. Obviamente que se lembra (em geral) do que leu até aqui (e poderia sem problemas fazer um resumo) pois é assim que nosso cérebro guarda as palavras, imagine isto como uma "Ficha Resumo". Agora feche os olhos e recorde da imagem colocada.

Resumidamente, ao ler um livro podemos fazer um resumo de um capítulo mas dificilmente lembraríamos de todas as palavras. Já o funcionamento é bem diferente para uma revista em quadrinhos, isto é, conseguiremos lembrar da maioria dos desenhos do primeiro ao último quadrinho, e muitas vezes até de determinados detalhes (faça um teste).

Então quando for estudar ou mostrar uma ideia pense em organizar sua apresentação em forma de imagem, seu cérebro recordará muito mais facilmente. Um site que vem conquistando muitos adeptos dia a dia chama-se Mural.ly e consiste em um organizador e apresentador de ideias totalmente visuais, tente e divirta-se.

Obrigado e até a próxima
Fernando Anselmo

quinta-feira, 5 de setembro de 2013

Gimp - Degradês e Transparências

Uma dos detalhes que mais me fascinam em trabalhar com o Gimp é a facilidade quanto a criação de efeitos de Degradês e a realização de Transparências. Vejamos duas pequenas lições:

Obter Fundo Degradê

  1. Vamos partir de uma imagem com fundo branco.
  2. Escolher para Foreground Color uma cor qualquer (primeiro dos quadrinhos nas cores na Toolbox).
  3. Selecionar a ferramenta Bucket Fill (Shift+B) e clicar na imagem.
  4. Selecionar a ferramenta Blend (L) e clicar na imagem o ponto de origem, arrastar e soltar em outra posição (é possível conseguir diversos tipos de degradê).
Dica: Com a ferramenta Bucket Fill selecionada, podemos usar:
  • Ctrl+, para preencher com Foreground Color
  • Ctrl+. para preencher com Background Color
  • Ctrl+: para preencher com Pattern selecionado

Criar Transparências

  1. Abrir uma imagem qualquer
  2. Verificar se o canal Alfa está definido (Layer | Transparency | Add Alpha Channel).
  3. Com as ferramentas de seleção, definir a área que não ficará transparente.
  4. Pressionar Ctrl+I para inverter a seleção.
  5. Pressionar Ctrl+X para cortar a imagem.
  6. Salvar em formato gif ou png (jpg não aceita transparência).
Em aulas passadas vimos como usar degradês em imagens, o interessante de dominarmos essas técnicas é que podemos combiná-las para criar colagens de fotos, então como exercício busque na Internet 5 ou 6 imagens de seu artista favorito, ou pegue fotos de sua família e realize uma montagem. Garanto que será um belo presente.

Obrigado e até a próxima
Fernando Anselmo


terça-feira, 3 de setembro de 2013

Finanças - Médias e a HP-12C

A HP-12C é uma calculadora sensacional tratando em se tirar médias aritméticas, e extremamente simples também, vamos imaginar que ganhamos os seguintes benefícios realizando serviços de consultoria: 1. R$ 538,00, 2. R$ 490,00, 3. R$ 348,00, 4. R$ 670,00 e 5. R$ 480,00. Para fazer esses cálculos proceda da seguinte forma:
f SST   -> Limpar a memória de média
538     -> Digite o primeiro valor
E+      -> Aparece 1,00 no visor
490     -> Digite o segundo valor
E+      -> Aparece 2,00 no visor
348     -> Digite o terceiro valor
E+      -> Aparece 3,00 no visor
670     -> Digite o quarto valor
E+      -> Aparece 4,00 no visor
480     -> Digite o quinto valor
E+      -> Aparece 5,00 no visor
g 0     -> Aparece 505,20
Então a média do valor é R$ 505,20. Tome cuidado pois esta é a Média Aritmética Simples, ou seja, a soma de todos os valores (R$ 2.526,00) e a divisão pela quantidade total (5 serviços). Também podemos obter o valor do Desvio Padrão usando a seguinte função:
g .     -> Aparece 115,99
Sabemos que em trabalhos de consultoria existe uma outra variável extremamente importante que é as horas. Vamos imaginar que ocorreram as seguintes durações para as respectivas consultorias: 1. 3 horas, 2. 2 horas, 3. 1 hora, 4. 3 horas e 5. 2 horas. Podemos dizer que isso são os pesos de cada serviço, dessa vez precisamos da Média Aritmética Ponderada e resolvemos da seguinte maneira:
f SST       -> Limpar a memória de média
538 ENTER 3 -> Digite o primeiro valor, pressione a tecla ENTER e seu peso
E+          -> Aparece 1,00 no visor
490 ENTER 2 -> Digite o segundo valor, pressione a tecla ENTER e seu peso
E+          -> Aparece 2,00 no visor
348 ENTER 1 -> Digite o terceiro valor, pressione a tecla ENTER e seu peso
E+          -> Aparece 3,00 no visor
670 ENTER 3 -> Digite o quarto valor, pressione a tecla ENTER e seu peso
E+          -> Aparece 4,00 no visor
480 ENTER 2 -> Digite o quinto valor, pressione a tecla ENTER e seu peso
E+          -> Aparece 5,00 no visor
g 6         -> Aparece 537,45
Ou seja, podemos dizer que ganhamos em média R$ 537,45/hora de consultoria realizada. Desta forma tome cuidado para não perder dinheiro em seus próximos serviços. Sei que nosso assunto acabaria aqui, mas como sou chato ainda existem mais duas médias.

Cálculo da Média Harmônica


Essa média equivale ao inverso da média aritmética dos inversos de n valores. Para simplificar vamos usar 3 número: 1. 87, 2. 42 e 3. 53, realizamos o cálculo da seguinte forma:
3 ENTER   -> Quantidade total de números
87        -> Primeiro valor
1/x ENTER -> Obtemos seu inverso
42        -> Segundo valor
1/x +     -> Obtemos seu inverso e adicionamos ao valor anterior
53        -> Terceiro valor
1/x +     -> Obtemos seu inverso e adicionamos ao valor anterior
÷         -> Dividimos para obter o resultado 55,38

Cálculo da Média Geométrica


Essa média é calculada com a multiplicação de todos os valores e a extração da raiz do índice n deste produto. Usaremos os mesmos números anteriores e realizamos o cálculo da seguinte forma:
87 ENTER -> Primeiro valor
42 x     -> Segundo valor e multiplicamos pelo anterior
53 x     -> Terceiro valor e multiplicamos pelo anterior
3 1/x    -> Total de valores e obtemos o inverso
yx       -> Elevamos pelo valor anterior para obter o resultado de 57,86
Obrigado e até a próxima
Fernando Anselmo


domingo, 1 de setembro de 2013

Mineração de Dados - Técnicas de Integração de Dados

Em curto espaço de tempo, os resultados da mineração de dados podem ser rentáveis. Com centenas de gigabytes de dados a Integração de Dados pode fornecer uma visão unificada dos dados de negócios que poderiam estar espalhados por toda a organização. Este ponto de vista unificado pode ser construído com a utilização de uma variedade de técnicas e ferramentas.

As técnicas mais comuns de integração de dados são:

  • Consolidação de Dados - consiste na captura dos dados de vários fontes de origem e sua integração em um único repositório de dados persistente. Esse armazenamento pode ser utilizado para análise ou geração de relatórios, ou pode servir como uma nova fonte de dados para outras aplicações (por exemplo, nas ferramentas de ECM - Enterprise Content Management).
  • Federação de Dados - fornece uma visão virtual única de um ou mais arquivos de dados de origem. Relacionado a problemas de aplicativos de negócios para uma determina consulta, neste caso devemos recuperar os dados de repositórios adequados, integrá-los para coincidir com o ponto de vista virtual e definir as consultas para enviar os resultados para o aplicativo de negócios solicitante. Por definição, Federação de Dados obtém os dados dos sistemas de origem por demanda. Qualquer transformação de dados necessária é realizada como os dados são recuperados a partir da origem (por exemplo, nas ferramentas de EII - Enterprise Information Integration).
  • Propagação de Dados - cópia dados de um local para outro. Este modelo de aplicações trabalham com dados on-line, ou seja, são orientados a eventos. Atualizações são realizadas para o sistema de origem podem ser propagadas de forma assíncrona ou síncrona no sistema destino (por exemplo, nas ferramentas de EAI - Enterprise Application Integration e EDR - Enterprise Data Replication).
Segundo alguns modelos de Integração de dados, existe uma quarta técnica:
  • Abordagem Híbrida. As técnicas utilizadas por aplicações de integração de dados dependem tanto requisitos de negócios quanto da tecnologia. É comum um aplicativo de integração de dados usar uma abordagem híbrida, que envolve diversas técnicas de integração de dados (por exemplo, nas ferramentas de CDI - Customer Data Integration).
Em artigos posteriores voltaremos a tratar mais sobre o assunto de Data Mining, pois as ferramentas de mineração de dados podem responder perguntas de negócios que tradicionalmente eram muito complicadas para resolver.

Obrigado e até a próxima
Fernando Anselmo

quinta-feira, 29 de agosto de 2013

Mineração de Dados - ETL 2

Espero que tenha ficado claro os conceitos de ETL na postagem anterior. Recapitulando o essencial:
  • Extract - Extrair de diversas fontes de dados.
  • Transform - Transformar para otimizar as transações de negócio.
  • Load - Carregar para dentro do DW.
É muito complicado para o AD (Administrador do Banco de Dados) se conectar as diferentes variantes existentes dos bancos de dados atuais sem o uso de uma ferramenta, ainda mais que no caso dos BD (bancos de dados) as bases são constantemente alteradas ou existe uma nova necessidade a ser integrada. Resultado: qualquer trabalho manual necessitaria ser refeito.

O principal valor das empresas são as informações (diversas pessoas pregam que são seus colaboradores, este conceito é correto pois eles detêm anos de entendimento do negócio). Assim, necessidade de negócio torna-se um termo restrito que significa o núcleo das informações que os usuários finais precisam para realizar, ou seja, as decisões de negócio. Podemos listar outro requisito de modo a ampliar este conceito de necessidade de negócio, a exigência de identificar o conjunto de fontes de informação dinâmicas, esse é o objetivo que a equipe de ETL deve resolver em um DW.

Notamos que muitos conceitos foram adaptados, uma vez que o DW tornou-se vítima de seu próprio sucesso. A evidente compreensão e uma variável que deve ser examinada nas necessidades do negócio como uma atividade central da equipe de ETL. O atraso decorrente entre uma transação comercial e sua visão no DW deve drasticamente reduzido. Para muitas organizações, esse atraso é considerado inaceitável. Podemos considerar o DW como missão crítica, pois seus dados são enriquecidos dos diversos sistemas de informação que são utilizados para processar as transações de negócio.

Então, o essencial mesmo é que ETL poupa tempo e dinheiro e por isso está rapidamente se transformando na ovelha branca e de olhos azuis para quem sonha em ter um DW ágil. "Codificar Manualmente" pode ainda ser a forma mais comum de integração de dados. Porém, isso exige horas e horas de desenvolvimento e experiência para criar uma inteligência de negócio. Obter, no momento preciso, a informação que a empresa necessita e acionar diretamente essa escolha da fonte de dados é a magia que muitos querem aprender.

Obrigado e até a próxima
Fernando Anselmo

terça-feira, 27 de agosto de 2013

Mineração de Dados - ETL

As vagas de emprego que publico semanalmente na revista Segunda Empregável realmente tem me impressionado, não apenas pela qualidade das empresas anunciantes como também dos profissionais que estão sendo procurados e entre estes, dois perfis se destacam: Analista e Desenvolvedor de ETL.

Rapidamente vamos entender o que vem a ser ETL? É a sigla para Extract-Transform-Load (Extrair, Transformar e Carregar). Essas vagas se referem a um profissional que tenha conhecimento de um Data Warehouse (DW), pode-se dizer que é uma especialidade do DBA, uma evolução, também conhecido como um explorador, porém o termo que melhor se encaixa seria um Minerador de Dados.

Já expus alguns artigos neste blog sobre mineração de dados, só que o conceito de DW é um pouco mais profundo e quero neste artigo apenas expor a ideia do que vem a ser o processo de ETL. No conceito devemos entender que:
  • Extrair - refere-se a selecionar quais dados são interessantes de serem analisados, por exemplo, para criar a "Nuvem de Palavras" que publico nas estatísticas da revista tenho que deixar de lado algumas palavras que não interessam ao contexto geral.
  • Transformar - como obter os dados chaves do DW, limpá-los e refatorá-los de modo que isso possa interessar ao cliente e qual é o formato mais apresentável.
  • Carregar - construir com os dados transformados novas estruturas mais interessantes e manipuláveis com as informações necessárias.
Espera um pouco, porque tem que ser um profissional especializado nisto? Um DBA não realizaria este serviço? Calma, vamos compreender um simples plano de ação para a implementação de um ETL (tentei simplificar o conceito e as tarefas):
  1. Criar um Diagrama de alto nível do fluxo de fonte/destino
  2. Testar, escolher e implementar uma ferramenta de ETL
  3. Delinear as transformações complexas, geração das chaves e a sequência para cada tabela de destino e pensar nas dimensões.
  4. Construir e testar a dimensão estática
  5. Construir e testar os mecanismos de mudança de uma dimensão
  6. Construir e testar as dimensões restantes
  7. Construir e testar as tabelas iniciais de fatos e de automação
  8. Construir e testar a atualização parcial
  9. Construir e testar os agregados
  10. Projetar, construir e testar a automação ETL
Notamos então que em breve vai surgir mais um profissional que será especializado em Testes de ETL, por enquanto isto ainda está como uma função do Analista. O passo 2 deste plano é bem interessante pois existem várias ferramentas, algumas muito profissionais (e caras) e outras simples (e gratuitas), nesse segundo grupo podemos dar asas aos nossos estudos. Busquei no Source Forge algumas dessas ferramentas e recomendaria três para começar CloverETL, KETLTalend Open Studio for ESB.

Isso não é tudo e acredito que apenas comecei a arranhar a superfície, em breve voltaremos a esse assunto, neste meio tempo, comece hoje mesmo baixando uma ferramenta que se sinta agradável para iniciar nesta interessante área.

Obrigado e até a próxima
Fernando Anselmo



domingo, 25 de agosto de 2013

Finanças - CAPM e HP-12C auxiliando nos estudos

CAPM é a sigla em inglês para Capital Asset Pricing Model (Modelo de Precificação de Ativos) e fornece uma fórmula que permite calcular o retorno esperado de um título com base em seu nível de risco. A fórmula é a taxa livre de risco mais beta vezes o resultado da diferença entre a taxa do mercado e a taxa livre de risco. Isto é:
tF + B(tM - tF)

Onde: tF - Taxa livre de risco (%)
      B - Beta
      tM - Taxa do mercado global de ações (%)
Devemos entender que Beta (B) é um valor de risco global do investimento num grande mercado (por exemplo se a empresa é um Beta 2,0 então ela é 2 vezes mais arriscada). É possível encontrar este valor em Yahoo Finance, por exemplo o beta da Oracle Corporation (ORCL) é 1,52. Uma taxa livre de risco (tF), seria a taxa que se espera em um investimento que se presume não ter risco envolvido.


Agora vamos usar a HP-12C para criar um programa que nos retorne o CAPM:
f [P/R]   -> Entrar no modo de programação
f [PRGM]  -> Apagar os programas em memória
[STO] 2   -> Guardar o número digitado na área 2
[RCL] 0   -> Obter o valor guardado na área 0
[RCL] 1   -> Obter o valor guardado na área 1
-         -> Subtrair um pelo outro
[RCL] 2   -> Obter o valor guardado na área 2
x         -> Multiplicar pelo resultado anterior
[RCL] 1   -> Obter o valor guardado na área 1
+         -> Somar pelo resultado anterior
f [P/R]   -> Sair do modo de programação
Um programa bem simples. Para usá-lo armazenamos o valor de tM (usaremos por exemplo 13.4%) na posição 0 e o valor de tF (usaremos por exemplo 4%) na posição 2 antes de executar o programa com o valor do Beta (usaremos por exemplo o 1,52 da Oracle), isto é:
1º) 13.4 [STO] 0
2º) 4 [STO] 1
3º) 1.52 [R/S]
E como resposta teremos 18,29%, neste mercado a taxa de retorno do investimento é aceitável, pois o resultado é maior que a tM.

Concordo que até o presente momento isto está financeiro demais e sem muita utilidade prática (a não ser para quem investe em ações). Permita-me então supor que desejamos aprender uma tecnologia lançada por uma determinada empresa X qualquer, sabemos que o período de estudos pode durar muito tempo e a pergunta é: Vale a pena? A resposta será sim se esta empresa apresenta um bom valor de mercado e uma baixa taxa de risco ou seja, um CAPM compensador o suficiente para investirmos nela o que temos de mais precioso o nosso tempo.

Obrigado e até a próxima
Fernando Anselmo