Olá Pessoal!
Muito se tem falado sobre boas práticas e bom design de código. Se você gosta de trabalhar profissionalmente no seu código e se gosta de facilitar a manutenção do seu código, com toda certeza já precisou aprender sobre alguns padrões e técnicas para isso.
Muitos destes padrões e técnicas são antigos, datados desde 2000 mas infelizmente ainda encontramos grande parte dos códigos com preocupação alguma de manutenibilidade, facilidade de reuso, com bom desempenho, etc.
Isso me motivou a falar um pouco sobre um dos princípios S.O.L.I.D. Este é um acrônimo para Single responsibility, Open-closed, Liskov substitution, Interface segregation e Dependency inversion. Este termo foi criado por Robert C. Martin(Uncle Bob) para unir alguns padrões muito utilizados no Design Orientado a Objetos, que visam facilitar a manutenção, legibilidade e vida do nosso código.
É quase uma arte desenvolver utilizando alguns desses padrões e com toda certeza a próxima equipe a modificar o seu código(inclusive você mesmo!) vai agradecer.
Hoje falaremos sobre o Single Responsiblity Principle, que é um padrão extremamente simples e muitas vezes absurdamente ignorado. A regra é simples: Uma classe só deve ter uma, e somente uma, razão para ser modificada. Simples assim!
Então isso quer dizer que se eu criar somente um método para a minha classe, com toda certeza ela só terá uma responsabilidade certo? Não é por aí. Na verdade o princípio nos diz o que uma classe deve fazer e não como ela deve fazer. Assim, uma classe poderá ser responsável por uma funcionalidade que pode precisar de 5 métodos para tal realização.
Mas vamos analisar um pequeno código para visualizarmos com mais facilidade este princípio:
public class Departamento {
public void calculaNotaFiscal() {
// seu código para calculo da nota fiscal
}
public void calculaPagamentoDeFuncionarios() {
// seu código para cálculo do pagamento
}
public void verificaInadimplenciaDeClientes() {
// seu código para a verificação de inadimplência
}
}
O que esta classe faz? Bom, ela calcula nota fiscal e calcula pagamento e verifica inadimplência. Estes “es” não estão aí atoa. Eles indicam fortemente que a nossa classe tem mais de uma razão para ser modificada, contrariando a nossa simples regra!
Caso o cálculo da nota fiscal precise ser atualizado, modificaremos a classe Departamento. E se o cálculo de pagamento precisar ser melhorado? A classe Departamento também precisará ser modificada.
Observamos aqui que a classe Departamento possui pelo menos 3 motivos para ser modificada e isso não é nada legal. Não será nada divertido modificarmos a classe Departamento toda ver que um requisito for atualizado.
Então para respeitarmos o nosso princípio, poderíamos criar uma classe para cada responsabilidade. Um exemplo seria:
public class NotaFiscal {
public void calculaNotaFiscal() {
// seu código para cálculo da nota fiscal
}
}
public class CalculadoraDePagamento {
public void calculaPagamentoDeFuncionarios() {
// seu código para cálculo do pagamento
}
}
public class VerificadorDeInadimplencia {
public void verificaInadimplenciaDeClientes() {
// seu código para a verificação de inadimplência
}
}
Agora o nosso código ficou muito mais interessante. Cada classe agora tem uma, e somente uma, razão para ser modificada. Lembrando que cada classe poderá conter quantos métodos forem necessários para que a sua funcionalidade seja satisfeita.
Observe também que com Testes de Unidade você tem uma facilidade muito maior para identificar possíveis quebras do Single Responsibility Principle.
Muitas vezes com um simples princípio e com um simples refactoring conseguimos elevar o nível do nosso código e trabalhar de forma muito mais profissional.
É isso pessoal!
Abraços!
Alexandre Gama.
Recentemente precisei migrar alguns projetos que utilizavam SVN para o Git e resolvi fazer um post falando um pouquinho sobre o Git e seu amigão GitHub. Então vamos lá!
Git
Hoje dificilmente um projeto não possui um controle de versão. Se o seu projeto de produção não possui um controle de versão, de verdade, corra para criar um! Sobreviver sem um controle é realmente assustador, digno de um herói, ainda mais com equipes grandes e distribuídas.
Durante muito tempo foi usado o CVS e, em seguida, o SVN veio para corrigir algumas falhas do CVS e adicionar interessantes funcionalidades. Diversos são os motivos para a adoção do Git:
- Branches facilitados e independentes
- Merges facilitados (quem já usou CVS sabe o quão sofrível é realizar merges)
- Mais rápido
- Distribuído
- Pode ocupar menos espaço que um checkout SVN
- Integração com o GitHub
Não entrarei em detalhes sobre estes pontos pois renderiam diversos outros artigos, mas entraremos em detalhes sobre a sua instalação logo mais.
GitHub
O GitHub é a rede para programadores. Nele podemos criar repositórios (públicos e privados) para os nossos projetos, seguir outros desenvolvedores, baixar projetos, modificar projetos, receber atualizações de modificações de projetos, etc.
Diversos projetos grandes já estão no GitHub e você já pode até dar uma olhadinha no código fonte deles! Dentre os projetos encontramos o JQuery, Eclipse, VRaptor, Twitter e muito mais! Abaixo listei alguns repositórios:
E qual a relação do Git com o GitHub?
A relação é simples: os dois se integram de forma bem simples! Podemos criar um repositório no GitHub e simplesmente “commitar” as alterações do nosso projeto git, tornando-o público!
Como exemplo vamos criar um pequeno projeto e torná-lo público no GitHub, utilizando o Git.
Instalando o Git
Como o meu dia a dia é desenvolvendo com Linux (Ubuntu), faremos a instalação neste ambiente. Vamos lá:
Para a instalação basta abrirmos o terminal e digitar:
sudo apt-get install git-core
Ele mostrará o espaço necessário para a instalação e mostrará quais os pacotes que serão instalados. Basta confirmar que todos os pacotes serão baixados e instalados.
Pronto! Nosso Git está instalado. Agora vamos configurá-lo. Nesta etapa você indicará o seu Nome e o seu Email. Ainda no Terminal digite:
git config --global user.name "Seu nome aqui" git config --global user.email "seuemail@seudominio.com"
Para verificar se deu tudo certo basta digitar no Terminal:
git config --global --list
Assim serão listadas as configurações recém criadas.
Agora vamos criar um repositório lá no GitHub. Entre no GitHub, entre no seu perfil e clique em New Repository, colocando o nome do seu projeto, no nosso caso “my-first-project-git”. O projeto criado será público mas é possível criar repositórios privados.
Com o nosso repositório criado no GitHub vamos criar o nosso projeto agora localmente. No Terminal vamos criar um diretório para o nosso projeto e iniciar o repositório do Git:
mkdir my-first-project-git cd my-first-project-git git init
Agora vamos criar um arquivo Readme e adicionar um repositório ao git. Repare que o origin é apenas um apelido para o nosso projeto.
git remote add origin git@github.com:seuloginnogithub/my-first-project-git.git touch README
Tudo certo até aqui. Criamos o nosso projeto no GitHub, criamos o nosso projeto localmente com o Git e agora vamos subir o nosso projeto para o GitHub. Mas antes de subirmos o projeto, precisamos gerar uma chave ssh. Podemos gerar uma chave com o seguinte comando no Terminal:
ssh-keygen -t rsa -C "seu comentario"
Ele mostrará o diretório onde será salva a nossa chave e você também informará uma senha. Pronto! Chave criada! Agora precisamos acessar a nossa conta no GitHub, clicar em SSH Keys e inserir o conteúdo exato que foi gerado na chave. Para pegar o conteúdo basta digitar o seguinte comando:
cat ~/.ssh/id_rsa.pub
Desta forma já podemos acessar o nosso GitHub!
Para adicionar o nosso arquivo Readme e “comitá-lo” basta digitarmos os seguintes comandos:
git add README git commit -m "aqui vai seu comentario"
Repare que neste momento fizemos o commit localmente mas ainda não enviamos para o GitHub. Para enviar basta digitar o seguinte comando:
git push -u origin master
Pronto! Agora você pode acessar o seu GitHub e ver o projeto que acabamos de criar. Simples, prático e divertido!
No próximo artigo avançaremos sobre os comandos mais utilizados pelo Git e como podemos modificar projetos já existentes no GitHub.
Não poderei disponibilizar os projetos privados mas disponibilizarei alguns outros projetos públicos no meu GitHub para podermos compartilhar conhecimento e experiência. Podem seguir =)
Até mais!
Seguindo a ideia do post anterior sobre JSON, hoje vamos a um exemplo mais palpável, real e divertido: Simular uma integração com o famoso Facebook!
O Facebook, assim como diversos sistemas, disponibiliza acesso aos seus recursos através de alguns métodos. A este conjunto de métodos, damos o nome de API.
Como visto no artigo anterior, JSON é um documento com uma estrutura bem bacana de se trabalhar.
Veja o JSON que o Facebook retorna quando chamamos certo método:
{
"id": "19292868552",
"name": "Facebook Platform",
"likes": 4190683,
"category": "Product/service",
"is_published": true,
"website": "http://developers.facebook.com",
"username": "platform",
"founded": "2007",
"mission": "To make the web more open and social.",
"talking_about_count": 98577
}
Interessante não? Muito fácil de ler e encontrar os dados que precisamos. Temos o id, name, likes e muitas outras informações.
Agora imagine que a nossa aplicação precisa buscar os dados de um post específico que foi colocado no Facebook. Podemos imaginar também que precisaríamos persistir esses dados em um banco pra futuras comparações, pesquisas, etc.
No nosso caso usaremos este post para estudo: www.facebook.com/98423808305.
Nao vou prolongar sobre a API do Facebook, mas para usá-la podemos usar o Graph API que o Facebook disponibiliza. Aqui temos o core da API, onde podemos ter diversos métodos para as diversas chamadas que precisamos. Caso você precise desenvolver uma app para o Face, este será o local mais odiado visitado por você! = )
Agora que você já sabe sobre a existência do Graph API, vamos usá-la!
Para o nosso exemplo vamos usar a seguinte URL:
https://graph.facebook.com/98423808305
Repare que ao clicar na URL, já temos o retorno em JSON! Isso mesmo, simples assim! Para o nosso projeto vamos precisar do Id e dos dados do From (Name e Category).
A primeira classe que criaremos é muito simples, somente para conseguirmos fazer uma chamada GET na url acima e receber o seu retorno.
package br.com.artigo.json;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
public class Http {
public String chamaUrl(String url) throws IOException {
URL facebook = new URL(url);
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(facebook.openStream()));
String retornoJson;
StringBuilder builder = new StringBuilder();
while ((retornoJson = bufferedReader.readLine()) != null)
builder.append(retornoJson);
bufferedReader.close();
return builder.toString();
}
}
A segunda classe criada será um POJO que conterá as informações que precisamos (id, name e category) vindas do facebook. Repare que esta classe facilmente poderia ser persistida, bastando inserir as anotações do JPA por exemplo! = )
package br.com.artigo.json;
public class Facebook {
private String id;
private String name;
private String category;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCategory() {
return category;
}
public void setCategory(String category) {
this.category = category;
}
@Override
public String toString() {
return "Facebook [id=" + id + ", name=" + name + ", category="
+ category + "]";
}
}
A terceira classe é a ArtigoJson que será a classe principal. Ela usará a classe Http para fazer a chamada simples da API e trabalhará com o retorno JSON.
package br.com.artigo.json;
import java.io.IOException;
import java.util.Map;
import net.sf.json.JSONObject;
public class ArtigoJson {
private static final String HTTPS_GRAPH_FACEBOOK = "https://graph.facebook.com/98423808305";
@SuppressWarnings("unchecked")
public static void main(String[] args) throws IOException {
//Retorno JSON
JSONObject object = chamadaHttp();
System.out.println(object);
//Retorno dos dados que precisamos
String id = (String) object.get("id");
Map map = (Map) object.get("from"); //Que interessante! Um cast para um Map!
String name = map.get("name");
String category = map.get("category");
//Populando o objeto facebook para persistencia
Facebook facebook = new Facebook();
facebook.setId(id);
facebook.setName(name);
facebook.setCategory(category);
//Impressão do objeto
System.out.println(facebook);
}
private static JSONObject chamadaHttp() throws IOException {
Http http = new Http();
String retornoJson = http.chamaUrl(HTTPS_GRAPH_FACEBOOK);
JSONObject objetoJson = JSONObject.fromObject(retornoJson);
return objetoJson;
}
}
Ao fazer a chamada, podemos ver um trecho do retorno:
{"id":"98423808305",
"from":
{"name":"Coca-Cola","category":"Food/beverages","id":"40796308305"}
}
Olha que simples! Temos neste trecho as informações que precisamos! = )
Como no artigo anterior, podemos fazer uma chamada usando uma chave. Repare que fizemos a primeira chamada usando a chave id:
//Retorno dos dados que precisamos
String id = (String) object.get("id");
Mas o mais interessante nas chamadas é o cast para um Map!
Map map = (Map) object.get("from");
Agora podemos obter os nossos dados pelo próprio Map e popular o nosso objeto facebook!
É isso pessoal! Artigo bem simples para o pessoal que está começando, somente pra mostrar uma das formas de utilização do JSON.
Você também pode encontrar este código no meu Gist Público.
Até mais!
Esta semana percebi que muitos ainda não conhecem ou continuam na dúvida sobre o que é JSON e resolvi contribuir com mais um artigo.
Afinal, o que é JSON?
JSON é basicamente um formato leve de troca de informações/dados entre sistemas. Mas JSON significa JavaScript Object Notation, ou seja, só posso usar com JavaScript correto? Na verdade não e alguns ainda caem nesta armadilha.
O JSON além de ser um formato leve para troca de dados é também muito simples de ler. Mas quando dizemos que algo é simples, é interessante compará-lo com algo mais complexo para entendermos tal simplicidade não é? Neste caso podemos comparar o JSON com o formato XML.
Vamos visualizar esta diferença?
<?xml version="1.0" encoding="UTF-8"?>
<id>1</id>
<nome>Alexandre Gama</nome>
<endereco>R. Qualquer</endereco>
{"id":1,"nome":"Alexandre Gama", "endereco":"R. Qualquer"}
Bom, é notável a diferença. Visualmente o segundo trecho (em JSON) é mais fácil de ler. Mas só existe essa diferença entre os dois? Na verdade não. Podemos listar algumas outras vantagens:
Vantagens do JSON:
- Leitura mais simples
- Analisador(parsing) mais fácil
- JSON suporta objetos! Sim, ele é tipado!
- Velocidade maior na execução e transporte de dados
- Arquivo com tamanho reduzido
- Quem utiliza? Google, Facebook, Yahoo!, Twitter…
Estas são algumas das vantagens apresentadas pelo JSON. Agora vamos ao que interessa: Código! ![]()
Vamos fazer um exemplo extremamente simples nesta primeira parte e avançaremos no próximo artigo, inclusive falando sobre JSON em páginas Web.
Qual biblioteca usar?
Existem diversas bibliotecas para trabalharmos com JSON e Java. Usaremos no nosso estudo o json.jar que você pode baixar tranquilamente neste link
O nosso caso de estudo será simples: Teremos uma classe Carro que será a nossa classe POJO e a classe EstudoJSON que terá o nosso famoso método main.
Classe Carro
package br.com.json;
public class Carro {
private Long id;
private String modelo;
private String placa;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getModelo() {
return modelo;
}
public void setModelo(String modelo) {
this.modelo = modelo;
}
public String getPlaca() {
return placa;
}
public void setPlaca(String placa) {
this.placa = placa;
}
//Aqui fizemos o Override do método toString() para visualizar a impressão com o System.out.println()
@Override
public String toString() {
return "[id=" + id + ", modelo=" + modelo + ", placa=" + placa
+ "]";
}
}
Esta é uma classe simples, onde temos os atributos Id, Modelo e Placa.
Agora teremos a classe EstudoJSON
package br.com.json;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
public class EstudoJSON {
public static void main(String[] args) throws JSONException {
adicaoSimplesDeDados();
}
}
Repare que criamos o método adicaoSimplesDeDados() que conterá o código de exemplo:
private static void adicaoSimplesDeDados() throws JSONException {
//Criação do objeto carro e atribuição dos valores
Carro carro = new Carro();
carro.setId(1l);
carro.setModelo("Celta");
carro.setPlaca("AAA1234");
//Criação do objeto carroJson
JSONObject carroJson = new JSONObject();
//Inserção dos valores do carro no objeto JSON
carroJson.put("id", carro.getId());
carroJson.put("Modelo", carro.getModelo());
carroJson.put("Placa", carro.getPlaca());
//Impressão do objeto JSON
System.out.println(carroJson);
}
Se executarmos este código, veremos que foi impresso no console o seguinte:
{"id":1,"Modelo":"Celta","Placa":"AAA1234"}
Você desenvolvedor mais atento vai reparar que existe um objeto impresso: Um Long! Isso mesmo! Como vimos, o JSON consegue armazenar objetos! Podemos inclusive armazenar um objeto do tipo Carro mesmo:
Modificamos o nosso método main:
public class EstudoJSON {
public static void main(String[] args) throws JSONException {
adicaoSimplesDeDados();
adicaoDeUmObjeto();
}
}
E adicionamos o método adicaoDeUmObjeto():
private static void adicaoDeUmObjeto() throws JSONException {
Carro carro = new Carro();
carro.setId(1l);
carro.setModelo("Celta");
carro.setPlaca("AAA1234");
JSONObject carroJson = new JSONObject();
//Adição do objeto carro
carroJson.put("Carro", carro);
System.out.println(carroJson);
}
Neste caso foi impresso no console o seguinte:
{"Carro":"[id=1, modelo=Celta, placa=AAA1234]"}
Simples não?
Como o JSON trabalha com coleção de pares nome/valor, podemos imprimir um valor específico simplesmente chamando o nome que desejamos.
System.out.println(carroJson.get("Modelo"));
Veja que neste caso queremos somente o modelo do carro, bastando fazer a chamada get(“nome que desejamos”)!
Conclusão
É isso pessoal! Vimos as vantagens do JSON e vimos como é simples começar a trabalhar com ele. Nos próximos artigos veremos exemplos mais complexos e veremos algo mais real onde faremos chamadas à API do Facebook!
Você também pode encontrar este código no meu Gist Público.
Abraços!
Fala pessoal!
Pois é! Fiquei um bom tempo longe, muito longe do blog devido aos milhares de compromissos. Este é um total quick post só pra avisar que o blog não morreu e que estou voltando a escrever neste fim de ano e que pretendo escrever sobre diversos assuntos, principalmente as Tecnolgias, Frameworks, Bibliotecas, Linguagens, etc que vim trabalhando ao longo deste ano.
Dentre os vários assuntos estarão
Java,
Ruby,
PHP,
Tuning de banco,
NoSQL,
JavaScript,
HTML 5,
JQuery,
VRaptor,
JSF,
JPA,
TDD,
BDD,
Padrões de Projetos,
Cloud Computing
e muito mais!! Também farei overviews, críticas e sugestões dos eventos que participarei para podermos trocar mais informações ainda! =)
É isso pessoal, um simples aviso e espero contar com a ajuda de todos para termos artigos de qualidade! =)
Abraços!
Fala pessoal!
Sim, assunto batido! Model View Controller! Mas é muito comum encontrarmos pela internet tutoriais um pouco estranhos, visões às vezes que parecem particulares, diagramas errados e alguns ainda com dúvidas.
O conceito do MVC é extremamente simples mas a sua visualização não é lá tão trivial assim. O artigo tem 2 objetivos principais: Relembrar a teoria e mostrar uma visualização simplificada do conceito.
Então vamos lá!
Entendendo o papel do M – Model
Pessoal, a idéia é simples: Quando pensamos em regras de negócio, estamos pensando no Modelo da aplicação. Basicamente é isto. No Model podemos ter validações, acesso a banco, acesso à arquivos, cálculos, etc.
O usuário, por exemplo, coloca um produto em um carrinho de compras e é no Model que faremos o cálculo final do pedido(descontos, juros), que validaremos a conta do usuário, que calcularemos o frete, que validaremos o endereço e por aí vai.
Mas como o usuário seleciona um produto em um carrinho de compras por exemplo? Como insere um Endereço para a entrega? Na View!
Entendendo o papel do V – View
A View só existe por um único motivo: Mostrar dados! Na prática isso nunca muitas vezes não acontece, mas deveria! Você que já desenvolveu em Delphi/VB com toda certeza já viu regras em um botão. Você que já desenvolveu em Java também já viu centenas de regras nas páginas JSP ou espalhadas em Servlets que criam as páginas. Isso é feio! O dia que precisarmos mudar de JSP para JSF ou GWT simplesmente não mudaremos!
Mas e agora? Entendido o conceito básico do Model, como a View passa os valores digitados/selecionados para o Model? Passa direto? Não!
Entendendo o papel do C – Controller
Aqui temos um maestro! Temos regras de negócio no Controller? Não! Temos visualização no Controller? Não! O Controller simplesmente delega para o Model as solicitações da View. O Controller é burro no sentido de regras de negócio da aplicação. Ele é responsável por saber quem está pedindo algo e a quem enviará este algo!
O Controller conhece a View e conhece o Model mas o Model não conhece a View, porém a View observa o Model e este avisa quando seus dados foram atualizados, para a View mostrá-los.
Ok! Depois dessa frase bagunçada, nada como um pequeno esquema para entendermos melhor:
Veja como é simples com o diagrama acima:
O Controller conhece a View e conhece o Model. Isto porque ele recebe as requisições do usuário da View e envia para o Model fazer algo com estas requisições. Exemplo: O usuário quer saber o endereço de uma residência a partir de um cep digitado.
O Model simplesmente recebe a requisição, faz toda a mágica (persiste dados, valida informações, etc) e fica com os dados prontos (atualizados) para serem visualizados novamente pela View.
A View fica observando o Model e quando este é atualizado, a View mostra os dados atualizados para o usuário.
E o Model acaba não conhecendo ninguém!
Legal! E por que eu trabalharia desta forma?
Porque, além de elegante, é profissional! Mas se você não se convenceu com estes argumentos, podemos ter outro: é Seguro! Temos aqui uma separação bem clara entre a Visualização e as Regras de Negócio. Caso você queira modificar uma regra, como um cálculo de juros, você precisaria apenas modificar o seu Model (e espero que em um só local! =) ) e não precisaria se preocupar com a visualização.
O mesmo vale para a View. Caso você queira modificar uma tela inteira, não precisaria se preocupar com as regras e sim somente com a tela.
Um outro motivo muito forte é que você pode querer disponibilizar os seus métodos em um WebService por exemplo e com uma separação clara do seu modelo, isso seria facilitado, e muito! Imagine que você tenha uma aplicação Web e outra Desktop (JSF e Swing por exemplo) mas que façam a mesma coisa. Seria muito ruim ter funcionalidades iguais nos dois ambientes pois teríamos que manter as duas iguais. Uma forma seria disponibilizar as funcionalidades em um ponto único e acessá-las nas duas aplicações. Com uma separação clara do modelo poderíamos disponibilizar estas funcionalidades por um WebService, Rest, EJB, etc.
Finalizando
O MVC é um padrão de arquitetura que existe, a grosso modo, para facilitar a manutenção da nossa aplicação, facilitar a adição de funcionalidades e facilitar a testabilidade da aplicação.
Se você ainda escreve regras de negócio nas suas páginas/forms, tente desenvolver com este padrão e veja a diferença na manutenção e na adição de funcionalidades.
No próximo post veremos um exemplo simples de implementação de uma funcionalidade utilizando o padrão MVC e veremos como é simples melhorarmos a nossa aplicação deixando-a profissional.
É isso pessoal! Abraços!
Fala pessoal!
Idéia
Neste artigo continuaremos a série sobre Algoritmos! No primeiro artigo resolvemos 3 problemas bem simples, utilizando a idéia de pseudocódigo, onde podemos visualizar melhor os passos para a resolução de um problema e não precisamos conhecer nenhuma linguagem de programação nesta etapa.
Neste segundo artigo vamos resolver o primeiro problema apresentado anteriormente, já utilizando Java e C.
Pra você que está iniciando os estudos e não conhece muito bem a sintaxe das linguagens não se preocupe pois a idéia desta série é mostrar os passos para a resolução de um problema e vamos usar essas linguagens só para os problemas não ficarem tão vagos!
Vamos lá!
Quebrando em pequenos pedaços
Conforme havia dito no artigo anterior, podemos dividir um problema em passos para chegar na sua resolução final. A idéia de divisão de um problema em problemas menores já é antiga e facilita muito a nossa vida, pois podemos pensar na resolução de “mini-problemas”, deixando de lado a visão macro do problema. Após a resolução dos pequenos problemas, o problema maior é resolvido através da união destes.
Primeira resolução
Para o nosso primeiro código, vamos atacar o problema 1 do artigo anterior. Vamos lembrá-lo:
“Problema: Fazer a divisão de um número por outro. Se o resultado for positivo, imprimir o número encontrado pela divisão, caso seja negativo, imprimir zero. Caso o divisor seja zero, imprimir o valor -1.”
No artigo anterior também vimos a resolução deste problema através de um fluxograma e também criamos um pseudocódigo com a intenção de fazer qualquer pessoa entender o objetivo que gostaríamos de atingir, que é a resolução do problema acima.
Ambiente
Com o problema em mãos, vamos fazer o passo a passo da resolução já utilizando as duas linguagens citadas, pra que possamos visualizar o fluxo em um nível mais baixo.
Para o Java, utilizarei o Eclipse e para o C utilizarei o DevC++. Particularmente não gosto do DevC++ e uso o GCC do Ubuntu, mas o DevC++ é bem utilizado pelos que estão começando. O Eclipse talvez não seja o mais usado pelos iniciantes (o comum é usarem editores simples) , mas ele é muito conhecido. Fique à vontade para desenvolver no NetBeans, JCreator, JBuilder, etc.
Relembrando
Esqueça a sintaxe do código abaixo caso você não a entenda agora. O ponto forte aqui pra você que está começando é entender o conceito, a lógica, a idéia. Pense na situação simples: Pra você pedir um cafezinho, você segue alguns passos, como encontrar um local, chamar o garçom, escolher o café, ver o preço e pedir. E você vai fazer exatamente a mesma coisa se estiver no Brasil, Japão ou na África e só vai mudar o idioma, a “sintaxe”!
Portanto, entender os passos neste momento é muito mais útil e fundamental que entender a sintaxe, a linguagem.
Primeiro código em Java
Vamos criar o nosso primeiro código em Java. Para isso, vamos criar uma classe com o nome de “DivisaoDeNumeros“. Esta é a classe que irá conter a nossa lógica para a resolução do problema. Com a classe criada, vamos criar o método “main” para podermos executar a aplicação, ou seja, imprimir os dados.
//Classe que trata das divisões de números public class DivisaoDeNumeros { public static void main(String[] args) { } }
Agora com a classe e o método principal criados, vamos fazer o passo a passo do artigo anterior, porém escrevendo em código! Pra não ficar uma leitura muita cansativa e demorada fazendo cada passo, escrevi o código inteiro e comentei cada passo no próprio código.
public class DivisaoDeNumeros { public static void main(String[] args) { //Criamos um objeto Scanner para capturar o que foi digitado Scanner input = new Scanner(System.in); //Imprime mensagem para a inserção do primeiro valor System.out.println("Insira o valor do dividendo: "); //Guarda o valor digitado pelo usuário na variável dividendo int dividendo = input.nextInt(); //Imprime mensagem para a inserção do segundo valor System.out.println("Insira o valor do divisor: "); //Guarda o valor digitado pelo usuário na variável divisor int divisor = input.nextInt(); //Verifica se o valor do divisor é igual a zero if (divisor == 0) { //Imprime o valor -1 caso o divisor seja zero System.out.println("-1"); } //Verifica se o valor do cálculo da divisão é negativo else if ((dividendo / divisor < 0)) { //Imprime o valor 0 caso o resultdo da divisão seja negativo System.out.println("Valor encontrado: 0"); } else { //Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão System.out.println("Valor calculado: " + dividendo / divisor); } } }
Você pode perceber que a execução está bem simples! Pelos comentários, podemos ver que passamos pelo “passo a passo” do artigo anterior, mas desta vez não escrevemos um pseudocódigo e sim um código em Java que podemos executar. Se você não está acostumado com a sintaxe, perceba que não foi difícil de entender o conceito, a idéia por de trás do código.
Esta é uma possível solução do problema, e não única. Podemos ter outros passos pra resolução! Mas será que se só trocarmos as condições (if’s / else if’s) teremos o mesmo resultado? Que tal tentar dar uma olhada no código abaixo e ver qual o problema?
import java.util.Scanner; public class DivisaoDeNumeros { public static void main(String[] args) { //Criamos um objeto Scanner para capturar o que foi digitado Scanner input = new Scanner(System.in); //Imprime mensagem para a inserção do primeiro valor System.out.println("Insira o valor do dividendo: "); //Guarda o valor digitado pelo usuário na variável dividendo int dividendo = input.nextInt(); //Imprime mensagem para a inserção do segundo valor System.out.println("Insira o valor do divisor: "); //Guarda o valor digitado pelo usuário na variável divisor int divisor = input.nextInt(); //Verifica se o valor do cálculo da divisão é negativo if ((dividendo / divisor < 0)) { //Imprime o valor 0 caso o resultdo da divisão seja negativo System.out.println("Valor encontrado: 0"); } //Verifica se o cálculo é positivo else if (dividendo / divisor > 0) { //Imprime o resultado do cálculo caso o resultado seja positivo System.out.println("Valor calculado: " + dividendo / divisor); } //Como o resultado não é positivo e nem negativo, podemos supor que o divisor é zero else { //Imprime o valor -1 pois o divisor é zero System.out.println("-1"); } } }
Erro! Veja como não precisamos entender a linguagem/sintaxe pra saber que este código terá problemas. Se olharmos com mais “carinho” vamos perceber que o código, na primeira condição, já tenta calcular a expressão. Se você inserir o valor zero para o divisor, teremos um erro no caso do Java que é o “java.lang.ArithmeticException: / by zero”, ou seja, não existe divisão por zero matematicamente falando e claro que na execução o Java vai reclamar.
Perceba que na resolução não basta simplesmente trocarmos as condições. Os passos para a resolução de um problema devem ser bem definidos e bem pensados para que nenhuma regra seja violada.
Código em C
Abaixo temos o código em C, que é muito usado nos cursos de introdução à computação.
#include<stdio.h> #include<stdlib.h> int main() { //Declaração das variáveis para guardar os valores int dividendo; int divisor; //Imprime mensagem para a inserção do primeiro valor printf("Digite o valor do dividendo:"); //Guarda o valor digitado pelo usuário na variável dividendo scanf("%d", ÷ndo); //Imprime mensagem para a inserção do segundo valor printf("\nDigite o valor do divisor:"); //Guarda o valor digitado pelo usuário na variável divisor scanf("%d", &divisor); //Verifica se o valor do divisor é igual a zero if (divisor == 0) { //Imprime o valor -1 caso o divisor seja zero printf("-1\n"); } //Verifica se o valor do cálculo da divisão é negativo else if ((dividendo / divisor < 0)) { //Imprime o valor 0 caso o resultdo da divisão seja negativo printf("Valor encontrado: 0\n"); } else { //Como o divisor não é zero e o cálculo não é negativo, imprime o resultado da divisão printf("Valor calculado: %d \n", (dividendo / divisor)); } //Pausa a execução system("PAUSE"); }
Entendimento do conceito x Sintaxe da linguagem
Volto a lembrar que não foi preciso entender 100% a sintaxe para entender o que está acontecendo. Nos comentários do código vimos o “passo a passo” para a resolução do algoritmos e basicamente traduzimos logo em seguida para a sintaxe utilizada no Java e no C.
Devemos lembrar também que não existe somente um passo para a resolução do problema e você pode ficar à vontade pra modificar os códigos acima, criando outros passos!
Finalizando
Neste artigo vimos a resolução de um problema usando Java e C e a idéia principal é entender o conceito! Entendido o problema e os passos para a resolução dele, traduzí-lo para a linguagem é o “mais fácil”. Podemos entender muito de uma linguagem, mas se não conseguirmos resolver um problema com passos bem definidos, não conseguimos fazer nada.
Nos próximos artigos desta série vamos resolver alguns problemas mais complicados (este foi bem simples, apenas para a introdução) e em breve vou falar sobre assuntos mais específicos, como Pilhas, Filas, Tempo de Algoritmo, etc.
Estes códigos você também pode encontrar em:
Código em Java
Código em C
Abraços!!!
Com este breve artigo(breve mesmo!) vou falar sobre o conceito de Inversão de Controle, que muitos confundem com Injeção de Dependência. É justo, já que no primeiro momento os dois conceitos são bem parecidos.
O que é a Inversão de Controle (IoC)?
Basicamente, a Inversão de Controle é uma forma diferente que temos para manipular o controle sobre um objeto. É um padrão. Gosto de pensar na Inversão de Controle como sendo a mudança de conhecimento que uma classe tem em relação à outra.
Gosto de ver um trecho teórico com um trecho de código, então vamos ver desta forma!
Vamos imaginar uma classe bem simples, onde precisamos gravar um Log em um arquivo após Vender um Produto.
Então podemos ter a seguinte classe bem simples:
public class VendaDeProduto { public void vendeProduto(Produto produto) { //Todo o código para a venda do produto... Log log = new Log("Arquivo.txt"); log.grava(produto); } }
Mas qual o problema?
Razoável o exemplo. Uma classe facilmente encontrada em qualquer código. Eu sou ruim para perceber problemas em uma classe só de vê-la, então vou imaginar uma situação real: Percebemos que a classe Log precisa do arquivo onde será gravado o Log correto? Agora vamos imaginar que o nome do arquivo será mudado para “ArquivoLog.txt”! Muito fácil, basta mudar o nome correto? Vamos então abrir a classe VendaDeProduto e mudar!
Putz! Aqui que está o problema! O que a classe de Venda tem a ver com isso? Na verdade, nada! Ou pelo menos não deveria ter. Para uma modificação na classe Log fomos obrigados a modificar algo dentro da classe de Venda e isso não é legal. Neste momento foi fácil modificar, mas e se tivéssemos 30 classes utilizando a classe Log? Quais as chances de esquecermos uma?
No pequeno exemplo acima vimos um detalhe importante: A classe VendaDeProduto sabe demais sobre a classe Log. A classe VendaDeProduto sabe criar a classe Log. Pior, a classe de vendas sabe que a classe Log precisa do nome de um arquivo! E isso não é justo com a classe VendaDeProduto.
A responsabilidade dela é somente de fechar uma venda. Portanto podemos ver um alto acoplamento de classes neste minúsculo código.
Um problema mais a fundo
Pra você que desenvolve com TDD, como faríamos por exemplo para fazer um teste com a classe VendaDeProduto quando precisarmos “mocká-la”? Simplesmente não conseguimos, justamente por ela criar o objeto Log! E não vale você que conhece o PowerMock inventar algo!
Resolvendo o problema
É aqui que entra a Inversão de Controle. Vamos literalmente inverter este controle na classe VendaDeProduto. Em vez de deixarmos a responsabilidade da criação da classe Log para a classe VendaDeProduto, vamos dar a ela esta dependência. Vamos injetar esta dependência nela. E olha o que apareceu para nós: Injeção de Dependência.
Daí muitos confundirem e acharem que os dois são a mesma coisa. Como você pode ver, vamos resolver o problema desta classe Invertendo o Controle, utilizando a Injeção de Dependência. Simples assim!
Vamos resumir: Injeção de Dependência é apenas uma forma para resolvermos a Inversão de Controle.
Temos algumas formas interessantes de Injeção de Dependência e vou falar da mais comum(em um próximo post falarei de outras!): O Constructor Injection, ou seja, injetamos uma dependência de uma classe através do construtor desta classe.
Vamos novamente exemplificar este trecho de teoria com um pouco de código. Para sermos mais coerente, vamos melhorar um pouco mais o nosso código anterior, utilizando a Injeção de Dependência!
public class VendaDeProduto { private Log log; public void VendaDeProduto(Log logVenda) { this.log = logVenda; } public void vendeProduto(Produto produto) { //Todo o código para a venda do produto... log.grava(produto); } }
Olha como ficou interessante, elegante e simples! A classe VendaDeProduto precisa da classe Log para criar um Log mas neste código a classe VendaDeProduto recebeu uma instância da classe Log! Ou seja, agora ela não se preocupa mais com a criação da classe Log e simplesmente a usa.
Como a classe Log é criada agora? Não sei! E nem precisamos saber! A única coisa que precisamos é uma instância da classe Log para trabalharmos, independente de como ela foi criada!
Agora pra você que trabalha com TDD ficou muito mais simples pois basta “mockar” a classe Log, passá-la pelo construtor e fazer os testes normais da sua classe!
Finalizando
Desta forma diminuimos o acoplamente entre as nossas classes e a manutenção fica facilitada e, além de elegante, agora temos uma classe testável. Só não está mais elegante pois não estamos Injetando uma implementação de uma Interface, mas este é um assunto para outro post!
É isso pessoal, apenas uma pequena dica simples em um artigo simples para deixarmos o nosso código o mais próximo possível do que deve ser: Profissional!
Abraços pessoal!
Fala Desenvolvedores!!!
Neste artigo teremos a continuação da parte III da série sobre TDD. A idéia deste artigo é continuar comentando um pouco mais sobre os Testes de Unidade e também falarmos sobre os Testes de Unidade em relação ao comportamento dos nossos objetos. Também falaremos sobre o conceito de Mock de Objetos, que é extremamente importante no TDD.
Já vou adiantar que você ficará chateado com o que faremos para “Mockar” os nossos objetos, mas prometo que em seguida ficaremos muito felizes com uma solução bem mais bacana para isso. Calma! o conceito de “Mockar” objetos aparecerá logo logo!
Para iniciar este artigo, vamos fugir um pouco do conceito citado acima e fazer a funcionalidade de divisão de dois números para verificarmos a possibilidade de fazer Testes esperando que alguma Exceção ocorra. Isso mesmo! Por algum motivo você deseja lançar uma Exceção caso algo de errado aconteça e podemos fazer isso com o JUnit, apresentado no artigo anterior.
Teste da divisão
A funcionalidade é simples: Fazer a divisão de dois números. Lembrando: É um caso simples e isolado onde a intenção é você imaginar um caso real da sua aplicação.
Então vamos para o Teste!
Mas aqui começaríamos com aquele conceito de BabySteps, onde faríamos passos curtos para chegarmos à solução, correto? Correto, porém os BabySteps não são uma regra xiita que devemos seguir à risca. Segundo o próprio Kent Beck em seu livro sobre TDD, os BabySteps são para quando realmente não temos confiança suficiente em escrever determinado código. Como ele cita também, não devemos desenvolver com BabySteps a todo momento e sim devemos ficar felizes por podermos fazê-lo quando desejarmos.
Agora que lembramos disso, vamos correr um pouquinho mais no código e escrever um pouco mais rápido que no artigo anterior, porém sinta-se à vontade para colocar a sua velocidade:
Adicionando o método de Teste à nossa classe de CalculadoraTeste:
public class CalculadoraTeste { @Test public void deveriaDividirDoisValoresPassados() throws Exception { int valorA = 6; int valorB = 2; Calculadora calculadora = new Calculadora(); int divisao = calculadora.divide(valorA, valorB); assertEquals(3, divisao); } }
E na nossa classe Calculadora, vamos escrever o nosso método de produção:
public class Calculadora { public int divide(int valorA, int valorB) { return valorA / valorB; } }
Legal! Agora podemos rodar o nosso Teste e vê-lo passando. Uma observação simples: Não comentei nos artigos anteriores mas só para ter certeza que é de conhecimento de todos, vou comentar: Rodamos os nossos Testes clicando com o botão direito na classe de Teste, selecionando Run As e em seguida selecionando o JUnit Test.
Agora temos um Teste verde na nossa frente!
Maravilha! Finalizamos? Não.
E quando esperamos por uma exceção?
Vamos atormentar os professores de matemática e fazer a seguinte alteração na nossa classe de Teste:
public class CalculadoraTeste { @Test public void deveriaDividirDoisValoresPassados() throws Exception { int valorA = 6; int valorB = 0; //divisão por zero! Calculadora calculadora = new Calculadora(); int divisao = calculadora.divide(valorA, valorB); assertEquals(?, divisao); } }
O que fizemos: atribuímos o valor zero à variável valorB. E o que esperamos no nosso assertEquals? Não tenho noção! Podemos esperar tudo, menos um valor! Sendo assim, na sua aplicação, você poderia mostrar uma mensagem para o usuário solicitando gentilmente que ele insira um valor coerente. E como podemos fazer um Teste esperando uma exceção? Vamos lá!
Teste esperando por uma exceção
Podemos usar um parâmetro na própria anotação do JUnit (@Test) para indicar qual a exceção que estamos esperando receber. Assim teríamos o seguinte código para o nosso Teste:
public class CalculadoraTeste { @Test public void deveriaDividirDoisValoresPassados() throws Exception { int valorA = 6; int valorB = 3; Calculadora calculadora = new Calculadora(); int divisao = calculadora.divide(valorA, valorB); assertEquals(2, divisao); } @Test public void deveriaLancarUmaExcecaoIndicandoFalhaAoDividirUmNumeroPorZero() throws Exception { int valorA = 6; int valorB = 0; Calculadora calculadora = new Calculadora(); int divisao = calculadora.divide(valorA, valorB); assertEquals(0, divisao); } }
Mas infelizmente ao rodar, temos uma barra vermelha:
Agora sim podemos fazer o nosso Teste passar adicionando o parâmetro à anotação do JUnit (@Test):
public class CalculadoraTeste { @Test(expected = ArithmeticException.class) public void deveriaLancarUmaExcecaoIndicandoFalhaAoDividirUmNumeroPorZero() throws Exception { int valorA = 6; int valorB = 0; Calculadora calculadora = new Calculadora(); calculadora.divide(valorA, valorB); } }
E agora sim temos a barra verde para o nosso Teste:
Este foi um caso simples para mostrar como é possível trabalhar com Testes que devem verificar exceções. Podemos estender este conceito para outros momentos, como fazer um Teste que não deveria esperar uma exceção que já esta poderia ser tratada pela nossa classe Calculadora, pois fazer da forma acima não é tão interessante.
Agora vamos melhorar os nossos testes!
Indo mais além
Até agora fizemos testes bem simples e a idéia é imaginarmos outras funcionalidades em nossas aplicações reais de forma a desenvolvê-las desta forma.Claro que uma classe do tipo Calculadora não é o melhor dos exemplos, mas optei pela simplicidade até agora.
De qualquer forma, tenho certeza que sua aplicação poderá ter muitas funcionalidades que, se bem isoladas, serão também passíveis de testes semelhantes.
Agora podemos avançar um pouco mais! Começamos o artigo com uma nova palavra: “Mock”.
Definição simples: Um Mock é basicamente um objeto falso, que é capaz de simular as dependências de um objeto e é capaz de simular determinadas ações desse objeto.
Por que é usado? Para testar o comportamento de outros objetos desejados.
Por que gostaríamos de testar o comportamento de outros objetos? Justamente para termos certeza de que tudo ocorreu conforme pensamos. Vamos imaginar a seguinte situação: Temos uma aplicação onde cada vez que excluímos uma pessoa, um log é gerado no banco no banco de dados com o nome da pessoa que foi excluída.
Como poderíamos ter certeza que a geração do log realmente vai ser chamada e que nada de ruim acontecerá no caminho?
Podemos fazer este teste usando exatamente um Mock da classe de Log. Vamos fazer o código mais simples que vier na nossa cabeça:
//Classe do nosso Teste public class PessoaTeste { @Test public void deveriaCriarUmLogQuandoUmaPessoaForExcluida() throws Exception { Pessoa pessoa = new Pessoa(); pessoa.setNome("Alexandre"); PessoaController pessoaController = new PessoaController(); pessoaController.exclui(pessoa); // Como saberemos se realmente o "criaLog" será chamado? } }
//Nosso Controller public class PessoaController { private PessoaDAO pessoaDAO; private Log log; public PessoaController() { pessoaDAO = new PessoaDAO(); log = new Log(); } public void exclui(Pessoa pessoa) { PessoaDAO.exclui(pessoa); log.criaLog(pessoa.getNome()); } }
//Nossa classe de criação de Logs public class Log { public void criaLog(String nomeDaPessoa) { // Código para criar um Log no banco, em um txt, etc... } }
Eu sei, eu sei. Abandonamos aqui algumas boas práticas mas é em prol de um entendimento melhor da situação. Logo logo vamos melhorar um pouco mais este código.
Voltamos à mesma pergunta: Como vamos saber se a criação do Log foi chamada? Vamos criar um Mock da nossa classe de criação de Logs!
O nosso Mock deve simular o funcionamento da funcionalidade, ou seja, ele não conterá código algum, será apenas para verificarmos se ele foi chamado.
Uma idéia seria criarmos uma classe que estende da nossa classe de Log, mas seremos um pouquinho melhores que isso e vamos criar uma Interface para implementarmos.
Assim poderíamos ter:
//Nossa Interface de criação de Logs public interface GeradorDeLog { public void criaLog(String nomeDaPessoa); }
Podemos então ter a seguinte classe horrorosa:
//Mock da nossa classe de Log public class LogMock implements GeradorDeLog { private String nome; @Override public void criaLog(String nomeDaPessoa) { this.nome = nomeDaPessoa; } public String getNome() { return nome; } }
Mas temos um detalhe: O nosso Controller está com uma dependência forte que é a classe Log sendo instanciada diretamente pelo Controller. Isso impossibilita o uso do nosso Mock. Então vamos melhorar um pouquinho o Design da nossa aplicação.
Opa! Olha o TDD nos “obrigando” a melhorar o Design da nossa aplicação!
Vamos então aplicar um princípio bem importante que é a Inversão de Controle através da Injeção de nossas Dependências. Vamos enviar então o nosso GeradorDeLog para o Controller através do construtor.
Assim teremos:
//Nossa classe de Teste public class PessoaTeste { @Test public void deveriaCriarUmLogQuandoUmaPessoaForExcluida() throws Exception { Pessoa pessoa = new Pessoa(); pessoa.setNome("Alexandre"); LogMock nossoLogMock = new LogMock(); PessoaController pessoaController = new PessoaController(nossoLogMock); pessoaController.exclui(pessoa); assertEquals(pessoa.getNome(), nossoLogMock.getNome()); } }
//Nosso Controller public class PessoaController { private PessoaDAO pessoaDAO; private GeradorDeLog log; public PessoaController(GeradorDeLog log) { this.pessoaDAO = new PessoaDAO(); this.log = log; } public void exclui(Pessoa pessoa) { PessoaDAO.exclui(pessoa); log.criaLog(pessoa.getNome()); } }
E olha que temos aqui, um teste passando!
Recapitulando: Muitas vezes precisamos testar o comportamento dos nossos objetos. No nosso caso qual é o comportamento? A criação de um Log quando uma pessoa é excluída. Mas não queremos criar um Log de verdade quando fizermos o teste de exclusão e sim queremos verificar se o método da criação do Log foi chamado.
Para fazermos isso, usamos um objeto “Mockado” que é um objeto que simula o comportamento do nosso objeto. É, a grosso modo, um objeto falso que não tem inteligência.
Assim, pelo Teste, na exclusão de uma pessoa um Log é gerado pois ao chamar o método de exclusão, o método de criação do Log também é chamado, ou seja, nada de errado acontece pelo caminho.
Para uma visão geral do nosso Teste, vamos listar os nossos passos:
- Criamos a nossa classe de Teste PessoaTeste
- Criamos as classes: PessoaController, Log, Pessoa
- Sentimos dificuldade para fazer o teste no Controller pois ele estava muito acoplado com a classe de Log
- Criamos a Interface GeradorDeLog para a nossa classe de Log implementá-la
- Fizemos a nossa classe LogMock também implementar a Interface GeradorDeLog
- Passamos para o nosso Controller a nossa classe de Log “Mockada”, por Injeção de Dependência pelo construtor
- Identificamos pelo assertEquals se o método de geração de Log foi realmente invocado, verificando se o nome no Log era o mesmo nome da Pessoa
Finalizando
Legal! Conseguimos fazer o nosso Teste rodar, melhoramos um pouco o Design da nossa Aplicação aplicando a Inversão de Controle (mas podemos refatorar para algo bem melhor, claro!) mas acabamos ficando com essa classe horrorosa que é a LogMock.
Mas esta idéia não é só feia! Essa idéia só poderá ser usada caso tenhamos objetos simples. Imagine que temos um objeto que instancia outro objeto e este também instancia outro objeto e cada um tem diversos métodos. A nossa vida se resumiria a criar classes de Mock e isso não é legal.
É neste ponto que podemos usar Frameworks para isso. Podemos “Mockar” as nossas dependências através destes Frameworks sem precisar criar outras classes para isso!
Mas este assunto é para o próximo artigo, onde trabalharemos com estas mesmas classes utilizando dois Frameworks bem bacanas do mercado!
Abraços pessoal!!!
Fala Desenvolvedores!!!
Servlets! Nesta série de artigos pretendo falar um pouco sobre os Servlets de uma forma simples e prática e falando também na teoria, que dará uma base melhor quando estiverem nascendo os nossos primeiros códigos com Servlets.
A idéia é também evoluir este assunto para outro assunto bem interessante, o JSP! Vocês verão mais pra frente que, a grosso modo, o JSP é convertido em Servlets.
Tá Alexandre, mas já que os artigos falarão sobre Servlets, nada mais justo que começar o primeiro falando sobre o motivo do nascimento dos Servlets.
Então vamos lá!
O problema!
Como toda boa idéia, os Servlets surgiram justamente a partir de um problema: A necessidade de exibição de páginas geradas dinamicamente na Web.
E por que? Por que no começo tínhamos páginas estáticas, ou seja, páginas muito simples em HTML que não eram capazes de retornar respostas de acordo com as requisições dos usuários.
Resumindo a história: No começo tínhamos diversos servidores que continham diversas páginas HTML estáticas que simplesmente acessávamos seu conteúdo e agora temos páginas que nos respondem dependendo da nossa pergunta, ou seja, capazes de enviar diferentes tipos de respostas dinamicamente.
Solução interessante: CGI
CGI. O Common Gateway Interface (CGI) foi criado justamente para contornar este problema. Qual era a idéia do CGI? Receber a requisição do cliente e gerar páginas web dinamicamente, exatamente como queríamos!Uau! Como? Podíamos escrever programas em CGI que poderiam ser executados a partir de parâmetros passados pelo navegador. Sendo um pouco mais ortodoxo, temos scripts CGI que entendem os parâmetros passados pelo navegador e assim podem enviar uma página web para o navegador criada dinamicamente, de acordo com estes parâmetros.
Exemplo simples: Com CGI podemos fazer uma solicitação via web e um programa CGI pode ler dados de um banco de dados a partir da nossa requisição e devolver uma página HTML com estes dados.
Uma curiosidade é que poderíamos escrever os programas usando por exemplo PHP, C, ASP e Perl.
Mas em Java também temos algo semelhante, os Servlets!
Servlets
Basicamente os Servlets funcionam desta mesma forma: Podem gerar páginas dinamicamente, de acordo com as requisições do usuário.
Os Servlets são da plataforma Java e nada mais são que Classes onde podemos criar objetos e trabalhar com eles, gerando páginas HTML dinamicamente.
Assim, basicamente poderíamos ter o seguinte processo:
Mas já vou te desanimar: Não é uma boa prática trabalharmos gerando páginas HTML diretamente com Servlets!
Você verá nos próximos artigos que trabalhar desta forma é um tanto quanto trabalhoso! No começo estamos felizes e tranquilos com a forma, mas logo percebemos que para algo mais complexo os Servlets tornam a nossa vida mais dura e caótica e não estou exagerando!
E por que saber sobre Servlets então? Por que você pode precisar dar manutenção em algum sistema baseado em Servlets (existem muitos!) e por que temos Frameworks que convertem seus dados em Servlets, como o famoso JSP. Além do mais é bem bacana nós desenvolvedores sabermos com o é o funcionamento por de trás dos Frameworks.
Assim, a grosso modo, o estudo sobre Servlets acaba se tornando um estudo sobre geração de páginas criadas dinamicamente mas em um nível mais baixo.
Servlet Container?
Você pode ter ficado em dúvida sobre o que seria o Servlet Container na figura. Temos um bem famoso e tenho certeza que você já ouviu falar ou usou: O Tomcat! Ele pode ser o nosso Servlet Container para usar os Servlets, ou seja, precisamos de um container para desenvolver com Servlets.
Um Servlet Container pode, por exemplo, gerenciar o ciclo de vida de uma Servlet, dar suporte à segurança, trabalhar com Multithreading, etc. Poderemos detalhar melhor o trabalho de um Servlet Container ao longo dos posts.
Os Servlets trabalham com o conceito de request/response e na figura seria exatamente a requisição específica e resposta específica respectivamente. Apesar de ser bem comum trabalharmos com Servlets com o protocolo HTTP, podemos trabalhar com outros protocolos que seguem este conceito de request/response.
Por que Servlets e não CGI então?
Existem alguns detalhes interessante que nos fazem escolher os Servlets em relação ao CGI, apesar deles terem a mesma idéia de funcionamento.
Segue uma figura com um pequeno comparativo:
Claro que temos outros motivos para o uso do Servlet em relação ao CGI (como serem em Java) e também podemos nos aprofundar nos motivos citados acima. Mas este é um assunto para um futuro post!
Finalizando
Pois é, vamos finalizar sem códigos mesmo. Mas fique tranquilo, este post foi apenas para introduzir a idéia sobre Servlets para podermos escrever código sabendo o que estamos fazendo e não simplesmente escrevermos linhas de códigos e esperarmos algum resultado.
Já no próximo post falaremos sobre as Classes que poderemos trabalhar e faremos o nosso pequeno primeiro exemplo! Para provar que trabalhar criando dinamicamente páginas com Servlets não é algo aconselhável e bacana, também faremos outros exemplos mais complexos, para realmente abandonarmos a idéia de trabalhar somente com Servlets, caso esta idéia apareça!
Abraços pessoal!!!









