sábado, 12 de outubro de 2013

MongoDB

     
      Se você desenvolve aplicações para web, provavelmente utiliza banco  de dados relacionais. Nascida há mais de 40 anos, essa estrutura domina o mercado da persistência e dificilmente encontraremos outra forma segura de relacionamentos de dados, transações e etc. Porém com o crescimento da web e  a expansão do volume de dados que nela circula, surgiram algumas necessidades básicas : 
  • Performance
  • Grafos (cruzamentos de informações)
  • Escalonamento ( possibilidade de expansão horizontal )
  • Evitar Single Point  of Failure (falha de conexão com os dados)  

      Para simplificar a complexibilidade da modelagem dos bancos de dados relacionais, e atender as necessidades supracitadas, surgiu  um movimento chamado NOSQL. (Not Only SQL).
      O objetivo desse movimento não é substituir a modelagem relacional, mas adicionar recursos que não são encontrados na mesma. Podemos concluir que NOSQL são sistemas de armazenamentos capazes de suprir necessidades de demandas onde os bancos  de dados relacionais são muito restritos.
      Dentre as inúmeras vantagens do NOSQL, podemos citar o alto desempenho de queries, segurança de dados, escalabilidade, tolerância  à falha,  e por não possuir estrutura definida (schema-free) possui maior flexibilidade na inclusão de dados. Falarei com mais detalhes de todas essas características em futuros posts.





      Em 2007, uma empresa de desenvolvimento web, chamada 10gen, começou trabalhar com uma base de dados que pudesse ser escalada  de acordo com a necessidade. Surgiu então o MongoDB utilizando como modelagem de dados orientada a documentos (Json). 
      Apesar da resistência natural das empresas que utilizam o sistema tradicional de banco de dados relacionais e neles confiam, atualmente grandes  empresas já utilizam NOSQL em seus sistemas, como por exemplo:
*******


SERVIDOR

1.   Para instalar o MongoDB você pode clicar aqui e escolher o seu sistema operacional. Feito a instalação, e criada a variável de ambiente (opcional), mostrarei como ter o primeiro exemplo de uma base de dados no MongoDB. 
Antes subir o servidor do mongo vá até a raiz da unidade C:\ e crie uma pasta chamada data. Dentro dela, crie outra pasta chamada db. Por default, MongoDB armazena arquivos no diretório /data/db.
      Em todas as plataformas, MongoDB “ouve” conexões com os clientes na porta 27017 (default). Se você quiser utilizar outro diretório basta especificar outro path quando for levantar o servidor adicionando  --dbpath <path >.  Assim como pode utilizar outra porta com o comando --port <número da porta>.
2.   Agora você está pronto para subir o servidor do Mongo. Digite no shell  o comando mongod. Serão exibido os seguintes dados da conexão:
paulo@paulo-HP-Pavilion-dv6-Notebook-PC:~$ mongod --dbpath /home/paulo/dat
Tue Oct  8 22:56:28 [initandlisten] MongoDB starting : pid=4069 port=27017 dbpath=/home/paulo/dat 64-bit host=paulo-HP-Pavilion-dv6-Notebook-PC
Tue Oct  8 22:56:28 [initandlisten] db version v2.0.6, pdfile version 4.5
Tue Oct  8 22:56:28 [initandlisten] git version: nogitversion
Tue Oct  8 22:56:28 [initandlisten] build info: Linux batsu 3.2.0-23-generic #36-Ubuntu SMP Tue Apr 10 20:39:51 UTC 2012 x86_64 BOOST_LIB_VERSION=1_49
Tue Oct  8 22:56:28 [initandlisten] options: { dbpath: "/home/paulo/dat" }
Tue Oct  8 22:56:28 [initandlisten] journal dir=/home/paulo/dat/journal
Tue Oct  8 22:56:28 [initandlisten] recover : no journal files present, no recovery needed
Tue Oct  8 22:56:28 [websvr] admin web console waiting for connections on port 28017
Tue Oct  8 22:56:28 [initandlisten] waiting for connections on port 27017
Atente-se para  a linha "... waiting for connections on port 27017"  informando que o servidor está pronto para uma conexão com o cliente.
3.   Abra um outro shell e digite o comando mongo e pronto, você terá no seu shell acesso ao banco de dados default  “test”. 
4.   Para encerrar  o servidor basta digitar Control+C no shell do servidor, ou no shell do mongo digite use admin e o comando db.shutdownServer().

                                  BASE DE DADOS

    Por ser schema-free você não precisar criar um banco de dados antecipadamente com tabelas pré-definadas, basta definir a base de dados que deseja utilizar. Se a mesma já existir será carregada no servidor, caso contrário uma nova será criada automaticamente.
1.   Vamos criar um banco de dados como exemplo. Digite use escola
paulo@paulo-HP-Pavilion-dv6-Notebook-PC:~$ mongo
MongoDB shell version: 2.0.6
connecting to: test
use escola
switched to db escola
2.   Ao criar o banco de dados "Escola" já pode adicionar o documento desejado. O comando para inserir é db.escola.insert(< documento>); Exemplo:
 
db.escola.insert({_id:01,materia:"portugues",turma:03,professor:"Jose Antonio",idade_professor:25})
db.escola.insert({_id:02,materia:"matematica",turma:06,professor:"Aline Ferreira",idade_professor:29})
db.escola.insert({_id:03,materia:"Fisica",turma:08,professor:"Sabrina Lima",idade_professor:34})
db.escola.insert({_id:03,materia:"Fisica",turma:08,professor:"Sabrina Lima",idade_professor:34})
db.escola.insert({_id:04,materia:"Geometria",turma:09,professor:"Fabiana Moraes",idade_professor:30})
3.   Uma das grandes vantagens da modelagem NOSQL está no schema-free. No exemplo anterior poderia ocorrer de um professor não ter uma turma definida ainda. No banco de dados relacional teríamos que adicionar um campo null. Em MongoDB basta adicionar o documento sem esse campo e por ser schemaless, o mesmo será adicionado no banco “escola”.
db.escola.insert({_id:04,materia:"Geometria",professor:"Claudio Ribeiro",idade_professor:30})
4.   Assim como poderíamos querer salvar para um determinado professor um atributo a mais.
db.escola.insert({_id:06,materia:"Inglês",turma:09,professor:"Marcio Santos",idade_professor:30,cargo_adicional:”coordenador”}).
5.   O comando db.escola.find() mostra todos os dados do banco.
db.escola.find() 
{ "_id" : 1, "materia" : "portugues", "turma" : 3, "professor" : "Jose Antonio", "idade_professor" : 25 }
{ "_id" : 2, "materia" : "matematica", "turma" : 6, "professor" : "Aline Ferreira", "idade_professor" : 29 }
{ "_id" : 3, "materia" : "Fisica", "turma" : 8, "professor" : "Sabrina Lima", "idade_professor" : 34 }
{ "_id" : 4, "materia" : "Geometria", "turma" : 9, "professor" : "Fabiana Moraes", "idade_professor" : 30 }
E o comando db.escola.find().pretty() mostra os mesmos dados em formato de documento chave-valor.
db.escola.find().pretty()
{
 "_id" : 1,
 "materia" : "portugues",
 "turma" : 3,
 "professor" : "Jose Antonio",
 "idade_professor" : 25
}
{
 "_id" : 2,
 "materia" : "matematica",
 "turma" : 6,
 "professor" : "Aline Ferreira",
 "idade_professor" : 29
}
{
 "_id" : 3,
 "materia" : "Fisica",
 "turma" : 8,
 "professor" : "Sabrina Lima",
 "idade_professor" : 34
}
{
 "_id" : 4,
 "materia" : "Geometria",
 "turma" : 9,
 "professor" : "Fabiana Moraes",
 "idade_professor" : 30
}
6.   Para localizar um dado inserido, existem várias sintaxes de queries. Por exempplo : digite db.escola.find({_id:03}) e irá encontrar no banco chamado escola o arquivo com o id 03.
 db.escola.find({_id:03})
{ "_id" : 3, "materia" : "Fisica", "turma" : 8, "professor" : "Sabrina Lima", "idade_professor" : 34 }

Outras queries podem ser mais específicas como db.escola.find({"idade_professor":{$gt:29}}) que encontra os professores com idade maior que 29 anos:
db.escola.find({"idade_professor":{$gt:29}})
{ "_id" : 3, "materia" : "Fisica", "turma" : 8, "professor" : "Sabrina Lima", "idade_professor" : 34 }
{ "_id" : 4, "materia" : "Geometria", "turma" : 9, "professor" : "Fabiana Moraes", "idade_professor" : 30 }

Dentre os inúmeros operadores de busca estes são os mais comuns: $gt(maior que), $gte(maior ou igual que), $lt (menor que) $lte (menor ou igual que), $ne(diferente), $in e &nin (está e não está em uma base de dados, respectivamente).

7.   Para alterar os dados:

db.escola.update({professor:"Aline Ferreira"},{$set:{turma:7}})
O primeiro campo faz a query e encontra o professor  com nome "Aline Ferreira" e altera o campo determinado no $set.

8.    Para excluir um determinado campo :

db.escola.remove({_id:1})

    Nos próximos posts falarei sobre otimização de queries com Index; os driver do MongoDB para a linguagem Java (faremos um CRUD em java utilizando a base de dados do MongoDB).Até breve.

quinta-feira, 3 de outubro de 2013

O que há de novo no Java 7




    Bem no meu primeiro post, vamos falar sobre as novidades trazidas pelo Java 7. Muitos desenvolvedores, inclusive eu, ainda desenvolvem usando o Java 5 ou 6 e se perguntaram o que o Java 7 vem trazendo de novidade para a linguagem. Algumas novidades são bem interessantes, como o uso de Strings em uma instrução switch, a nova API para manipular arquivos, gerenciamento de recursos automático dentro de um try/catch, dentre outras. Resumidamente, vamos falar sobre algumas:
public void processaProduto(Produto produto) {
        String status = produto.getStatus();

        if (status.equalsIgnoreCase(NOVO)) {
              // faz alguma coisa com o produto novo
        } else if (status.equalsIgnoreCase(SEMINOVO)) {
              // faz alguma coisa com o produto seminovo
        } else if (status.equalsIgnoreCase(USADO)) {
              // faz alguma coisa com o produto usado
        }
}

     Não vou entrar no mérito de questionar se essa seria melhor forma de fazer. O ponto aqui é que essa era forma de testarmos várias condições antes. Se tivermos muitas condições, o trabalho será enorme. No Java 7 podemos trabalhar com o switch melhorado que recebe uma String como argumento:

 public void processaProduto(Produto produto) {
            String status = produto.getStatus();

            switch (status) {
                case NOVO:
                    // faz alguma coisa com o produto novo
                    break;
                case SEMINOVO:
                    // faz alguma coisa com o produto seminovo
                    break;
                case USADO:
                    // faz alguma coisa com o produto usado
                    break;
                default:
                    break;
             }
   }
  Nesse caso,o status é sempre comparado com o case usando status.equals(case)

Diamond Operator

    Muitas vezes nos deparamos com o compilador reclamando de tipos quando trabalhamos com Generics. Por exemplo, se quisermos trabalhar com um mapa onde a chave é uma String e o valor uma lista de Produto. Teríamos algo assim:


Map<String, List<Produto>> mapa = new HashMap<String, List<Produto>>();
  
    Essa declaração é um pouco confusa pra quem não está habituado com a sintaxe. Além disso, ela é um pouco redundante. Precisamos colocar os tipos nos dois lados da atribuição. A partir do Java 7 podemos omitir os tipos da direita. Algo assim:


Map<String, List<String>> mapa = new HashMap<>();

  O compilador deduz pelos tipos da esquerda quais são os tipos da direita.

Gerenciamento automático de Recursos 

      Geralmente quando trabalhamos com conexões de banco, arquivos, etc devemos encerrar o recurso após o uso. Para isso usamos um bloco try/catch/finally para fechar cada recurso.


  try{
          Recurso file = new Recurso("arquivo");
          // faz alguma coisa com o recurso
      }catch(IOException e){
          // loga a exceção
      }finally{
          try {
              file.close();
          } catch (IOException e) {
              // loga a exceção
          }
      }

      O Java introduziu uma nova feature para gerenciar os recursos de forma automática. Funciona de uma maneira bem simples, basta declarar os recursos no try. A sintaxe é a seguinte:


 
 try(Recurso file = new Recurso("arquivo")){
           // faz alguma coisa com o recurso
      }catch(IOException e){
          // loga a exceção
      }

      Múltiplos recursos podem ser declarados também. Basta separá-los por ponto-e-vírgula.

      try(Recurso file1 = new Recurso("arquivo1"); Recurso file2 = new Recurso("arquivo2") ){
           // faz alguma coisa com o recurso
      }catch(IOException e){
          // loga a exceção
      }

      Dessa forma não precisamos fechar o recurso já que eles passam a ser fechados automaticamente assim que o bloco try for executado.
     Vale notar que não é todo recurso que pode ser gerenciado automaticamente. Apenas os recursos que implementam a interface java.lang.AutoCloseable podem ser gerenciados automaticamente.

Literais numéricos com "_"

     Quem já não se pegou contando os zeros de um número muito grande, digamos, 10000000000. É difícil identificar sem contar os zeros da direita pra esquerda. Uma melhoria bem útil é podermos separar os grupos de zeros com "_". Podemos declarar os números como abaixo:

      int mil = 1_000;
ou
      int mil = 1000
. .
      int umbilhao = 1_000_000_000
ou
      int umbilhao = 1000000000

Melhora no tratamento de exceções

        O Java 7 introduziu a funcionalidade chamada de multi-catch para lidarmos com código que trata múltiplas exceções. Suponha um código que trata múltiplas exceções. Faríamos da seguinte forma:

         try {
             metodoquelancaexcecoes();
         } catch (Excecao1 e) {
                // trata a Excecao1
         } catch (Excecao2 e) {
                // trata a Excecao2
         } catch (Excecao2 e) {
                // trata a Excecao3
         }
Agora a versão melhorada:
         try {
             metodoquelancaexcecoes();
         } catch (Excecao1 | Excecao2 | Excecao2 e) {
                // trata as três exceções
         }
Nada impede de termos uma mistura das duas formas:
         try {
             metodoquelancaexcecoes();
         } catch (Excecao1 e) {
                // trata a Excecao1
         } catch (Excecao2 | Excecao2 e) {
                // trata as duas exceções restantes
         }

    Bem essas foram algumas das melhorias na linguagem. Existem outras é claro. Outra bem legal é a nova API para trabalhar com arquivos. Talvez em um post futuro eu fale sobre isso. Para ver todas as melhorias, o link é esse http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html.

quarta-feira, 25 de setembro de 2013

Mockito - Framework de teste para Java

Mockito

Framework que facilita o uso de mocks em testes unitários em Java

O que são teste unitário?

Teste de unidade é toda a aplicação de teste nas assinaturas de entradas e saídas de um sistema, consiste em validar dados válidos e inválidos via I/O (entrada/saída) sendo aplicado por desenvolvedores ou analistas de teste.
Uma unidade é a menor parte testável de um programa de computador. Em programação procedural, uma unidade pode ser uma função individual ou um procedimento. Idealmente, cada teste de unidade é independente dos demais, o que possibilita ao programador testar cada módulo isoladamente.
FONTE: Wikipédia
IDEIA: Testar a menor unidade testável.

Pirâmide de Testes - por Jason Huggins

O que são mocks?

Objetos pré-programados com informações que formam uma especificação das chamadas que esperam receber.


Exemplos práticos

Como criar um mock

List singleMock = mock(List.class);
List singleMock = mock(Foo.class);
@Mock private ArticleCalculator calculator;

Como simular um retorno

when(mockedList.get(0)).thenReturn("first");
when(mockedList.get(1)).thenThrow(new RuntimeException());
when(person.getAddress(anyString())).thenReturn("deep");
person.getAddress("the docks");

Como verificar se o método foi chamado

verify(mockedList).add("once");
verify(mockedList, never()).add("never happened");
verify(mockedList, atLeastOnce()).add("three times");
verify(mockedList, atLeast(2)).add("five times");
verify(mockedList, atMost(5)).add("three times");

Mock x Spy

Mock 

Todos os métodos são mocks, ao menos que se configure para ser chamado o método real.
Foo mock = mock(Foo.class);
when(mock.someMethod()).thenCallRealMethod();

Spy 

Todos os métodos são reais, ao menos que configure um retorno para o mesmo.
List spy = spy(List.class);
when(spy.size()).thenReturn(100);

Não existe bala de prata!



Frameworks não vão resolver todos os seus problemas. 

A necessidade de criar muitos mocks, de fazer chamar muitos "when" e "verify" para fazer um teste de unidade é um alerta para a arquitetura do seu código.