segunda-feira, junho 30, 2008

Desenvolvimento Multi-Camada Simplificado no C#

A expressão "desenvolvimento multi-camada" é usada com freqüência no
desenvolvimento de software, nem sempre com o mesmo significado. De uma forma geral, a idéia de quebrar um desenvolvimento em camadas tem por objetivos facilitar o desenvolvimento ("dividir para conquistar") e facilitar a substituição de partes do código em eventuais (inevitáveis?) versões futuras.

Neste post estou me referindo à divisão interna em camadas de um aplicativo PC tradicional do tipo client-server (ou seja, estou falando das camadas dentro da camada client). Vamos tomar como exemplo um aplicativo simples, que apresenta na tela uma tabela com as informações de livros que estão armazenadas em uma base de dados. Para simplificar o lado server, vou usar uma base de dados Access (é trivial substituí-la por uma base SQL Server ou qualquer outra acessível pelo ADO.Net).

Já faz bastante tempo que o desenvolvimento deste tipo de aplicação é facilitado pelos ambientes integrados. A maioria deles possui um componente visual que pode ser conectado diretamente a uma base de dados; a maior parte do desenvolvimento é feita clicando e arrastando, como pouca escrita de código. O problema desta solução é que fica tudo misturado em um único fonte. Se quisermos mudar a fonte dos dados ou o componente visual acabamos tendo que refazer tudo.

A solução clássica multi-camada para este tipo de aplicação envolve três camadas:

  • a camada de dados, responsável por acessar a base de dados recuperando e atualizando os dados necessários.
  • a camada de negócios, que define objetos que representam as entidades de negócio e implementam as regras de negócio. Esta camada faz a ligação entre as outras duas.
  • a camada de apresentação (ou interface com o usuário), responsável por apresentar os dados contidos em objetos de negócio.

Desta forma fica mais fácil alterar uma parte da aplicação sem interferir no resto.

A partir da versão 2 do C# e do .Net Framework existe uma forma bastante simples de desenvolver aplicações com estas três camadas. Segue abaixo um passo a passo para fazer a minha aplicação exemplo no Visual Studio 2005.

1) Selecionar File New Project Windows Application, chame a aplicação de AppCamadas.

2) Clicar com o botão direito em Appcamadas no Solution Explorer, selecionar Add Class. Chame a classe de Livro, ela será a nossa camada de negócios. Entre com o código abaixo:

    class Livro
{
private string _titulo;
public string Titulo
{
get { return _titulo; }
set { _titulo = value; }
}

private string _autor;
public string Autor
{
get { return _autor; }
set { _autor = value; }
}

private DateTime _dtEmprestimo;
public DateTime DtEmprestimo
{
get { return _dtEmprestimo; }
set { _dtEmprestimo = value; }
}

public bool Emprestado
{
get { return DtEmprestimo != DateTime.MaxValue; }
}

public Livro() { }
public Livro(string titulo, string autor, DateTime dtEmprest)
{
Titulo = titulo;
Autor = autor;
DtEmprestimo = dtEmprest;
}
}

Note que estamos usando propriedades para controlar o acesso aos membros. Isto permite encapsular uma regra de negócio: livros não emprestados são indicados por uma data de empréstimo igual a DateTime.MaxValue.

3) Build / Build Solution (para a IDE conhecer a classe e suas propriedades)

4) Clicar o botão direito em Form1.cs no Solution Explorer, selecionar Rename, alterar o nome para frmConsulta, confirmar. Esta é a nossa camada de apresentação.

5) Selecionar aba frmConsulta.cs [Design]. Selecionar o form. Alterar a gosto Text, Size, StartPosition.

6) Arrastar do toolbox um DataGridView. Mudar o tamanho para ocupar todo o form. Com o DataGrivView selecionado no form, mudar as propriedades

  • Name: dgvLicros
  • Anchor: Top, Bottom, Left, Right (faz resize automático do grid quando muda tamanho do form)
  • Read Only: True
  • Row Select Mode: FullRowSelect

7) Clicar na seta tinha no alto à direita do grid (smarttag).


Limpar Enable Adding e Enable Deleting. SelecionarChoose Data Source, Add Project DataSource, Object, Next, escolher Livro, Next e Finish.

Neste ponto é que é feita a mágica: o grid foi configurado para apresentar os membros e propriedades públicos da nossa classe. Um objeto BindingSource (criado automaticamente pela IDE) fará a ponte entre o componente de apresentação e a fonte dos dados.

8) Clicar novamente na seta tinha no alto à direita do grid, selecionar Edit Columns. Mover Emprestado para o inicio da lista e remover DtEmprestimo.

9) Clicar com o botão direito em Appcamadas no Solution Explorer, selecionar Add Class. Chamar a nova classe de AcessoBD, esta será a nossa camada de dados. Entre com o código abaixo:

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.OleDb;

namespace AppCamadas
{
class AcessoBD
{
private const string StrCnx =
@"Provider=Microsoft.Jet.Oledb.4.0;" +
@"Data Source=Livros.mdb;";

public static List GetLivros()
{
List lstLivros = new List();
OleDbConnection cnn = new OleDbConnection(StrCnx);
OleDbCommand cmd = new OleDbCommand
("SELECT * FROM LIVROS", cnn);
try
{
cnn.Open();
OleDbDataReader dr = cmd.ExecuteReader();
DateTime dtEmprest;
while (dr.Read())
{
if (dr["Emprestimo"].Equals(System.DBNull.Value))
dtEmprest = DateTime.MaxValue;
else
dtEmprest = Convert.ToDateTime(dr["Emprestimo"]);
lstLivros.Add (new Livro (dr["Titulo"].ToString(),
dr["Autor"].ToString(),
dtEmprest));
}
cnn.Close();
}
catch
{
// tratamento de erros fica como exercício ao leitor
}
return lstLivros;
}
}
}

Este código é bastante simplista. Os dados extraídos da base de dados são colocados em uma lista de objetos de negócio. O BoundingSource usado na camada de apresentação suporta vários tipos de origem para os dados, graças ao recurso de generics do C# criamos de forma fácil uma lista de livros.

10) Build / Build Solution (opcional, só para ver que não fizemos nada de errado até agora)

11) Selecionar a aba frmConsulta.cs [Design]. Selecionar o form, dar um duplo clique no form (para criar um tratamento para o evento Load). Adicionar a linha abaixo.

            dgvLivros.DataSource = AcessoBD.GetLivros();

12) Digitar F5 (Start) e ver o show!

Embora esta técnica requeira um pouco mais de digitação que uma ligação direta do datagrid à base de dados, ela organiza melhor o código e nós dá uma grande liberdade. Se, por exemplo, quisermos mover a base de dados do Access para o SQL Server, basta alterar a camada de dados, sem mexer nas demais.

O projeto completo, incluindo a base de dados, pode ser baixado daqui.

domingo, junho 29, 2008

Webcomic muito bom: Sluggy Freelance


Ok, este Webcomic já existe a muito tempo, desde 1997. Para quem está conhecendo agora isto é bom, bom significa que tem uma quantidade muito grande de tirinhas para ler.


Sluggy Freelance tem uma base ligeiramente geek, somada a uma boa dose de sátira à cultura pop (o que permite relembrar o que bombava nos anos passados). A maior parte das tirinhas tem a sua piada individual, mas elas estão organizadas em histórias maiores. Usa e abusa do auto-deboche, como nas inevitáveis recaptulações. A arte nas primeiras tirinhas é bem razoável e melhora com o passar do tempo. Tem um tira para cada dia, a do domingo é maior e colorida.

Os personagens cairam bem no meu gosto. Torg é o geek de camisa xadrez, que trabalha como web designer freelance. Riff é o gênio atrapalhado ("Let me check my notes" é o seu bordão). Bun-bun é o belo coelhinho falante, com um gênio terrível e personalidade psicopata (a sua luta épica com o Papai Noel é imperdível - para quem gosta do gênero). Ao longo das histórias outros personagens vão se juntando, como Zoe a vizinha, Aylee a alien de outra dimensão, os demônios da Dimensão da Dor, e muitos mais.

Quem quiser conferir, o site está aqui. Você pode começar a ler pelo começo, uma semana de cada vez, a partir daqui.

Código de Barras - UCC/EAN 128

O UCC/EAN 128 (renomeado mais recentemente para GS1-128) não é exatamente uma simbologia mas sim uma convenção para o formato de informações codificadas com a simbologia Code 128.

Nos posts anteriores desta série não nos preocupamos com o que estava sendo codificado em barras. Não exisitia nenhuma indicação nos dados codificados de qual era a informação, isto tinha que ser assumido pela aplicação que imprime ou lê os códigos. Por exemplo, um mesmo código de barras com conteúdo 081231 pode significar:
  • um código de produto (produto 081231 - rebimbela transversal)

  • um número de documento (contrato 1231 de 2008)

  • uma data de validade (31 de dezembro de 2008)
A situação fica mais complicada quando se deseja codificar mais de uma informação em um mesmo código de barras, principalmente se quisermos a flexibilidade de colocar as informações em qualquer ordem ou deixá-las opcionais.

O UCC/EAN 128 define não somente um estrutura para o conteúdo do código como identificações para os tipos de informação mais comuns.

Um UCC/EAN 128 é codificado com a simbologia Code 128 e deve obrigatoriamente começar com o símbolo FNC1. Em seguida temos uma série de pares . Os identificadores de aplicação (ou simplesmente AIs) são códigos numéricos de 2 a 4 dígitos que identificam a informação que o segue. Alguns AIs exigem informação com tamanho fixo e outros informação com tamanho variável. No primeiro caso um novo par pode vir logo em seguida; no segundo caso é necessário colocar um FNC1 para indicar o fim da informação.

No texto impresso abaixo das barras a convenção é apresentar os AIs entre parenteses; estes parenteses não são codificados nas barras.

Existe uma longa lista de AIs definidos a nível mundial pela GS1. Alguns deles estão na tabela abaixo:



De posse de uma tabela dos AIs suportados, uma aplicação pode fazer o 'parse' de um código de barras UCC/EAN-128, extraindo os dados que lhe interessam (independente da sua posição no código) e descartando demais.

sexta-feira, junho 27, 2008

Trocando o HD

Já fazem alguns anos que venho optando pela compra de micros Dell. O preço é bastante razoável, as máquinas são bem construídas e quando precisei da assistência técnica em garantia ela funcionou de forma adequada.

Uma característica da Dell é que ela sempre tem algumas configurações em oferta, com bom preço, porém pequenas mudanças na configuração levam a acréscimos grandes. Por este motivo, quando comprei o meu micro atual (em 2005) acabei ficando com o HD de 40GBytes ao invés de optar por um maior. Como consequência, estava a cerca de um ano com algo entre 10 e 20% de espaço livre e tranferindo com frequência as coisas mais antigas para Cds e DVDs.

Resolvi finalmente trocar o HD por um maior, de 250GB. Sim trocar, pois o meu micro tem um gabinete compacto, onde só cabe um HD.

Transferindo os dados

Meu objetivo foi ter no novo HD uma única partição, com todo o conteúdo anterior e um monte de espaço livre. Embora existam vantagens em ter vária partições, minha experiência é que sempre acaba ficando uma partição lotada e outra vazia.

Este problema aconteceu no ano passado com o micro do meu pai e na ocasião eu comprei uma cópia do Partition Commander. Fui durante anos usuário de um outro produto da mesma companhia (System Commander) que facilita a instalação de vários sistemas operacionais em um mesmo HD, ocultando e restaurando dinamicamente as partições. O Partition Commander tem por finalidade principal permitir redimensionar e mover partições, ele inclui o Copy Commander que é o que utilizei para transferir os dados.

O primeiro, e mais trabalhoso, passo foi montar os dois HDs em um micro. Embora o meu micro tenha dois conectores SATA na placa mãe, ele tem somente um conector de alimentação, o que me obrigou a fazer a cópia no micro da minha filha. Os micros Dell posuem um mecânica muito bem feita: dá para abrir e retirar os drives sem precisar de nenhuma ferramenta. A parte trabalhosa foi soltar todos os cabos do micro da minha filha para colocá-lo em cima da mesa.

Com os dois HDs instalados, bootei um CD com o Partition Commander, selecionei o Copy Commander e a opção "Copy to new drive". O software automaticamente percebeu qual era o drive vazio e copiou todo o conteúdo do outro, redimensionando a partição. O processo demorou pouco mais de 20 minutos, porém durante a conferência final apresentou uma mensagem de erro, informando que o HD novo não estava respondendo. Seguindo as instruções na tela, desliguei e religuei o HD e ele foi em frente. E parou uma segunda vez. Novo liga e desliga do HD e conseguiu ir até o fim.

Montei o HD novo no meu micro e fiz o boot por ele. O Windows detectou que algo tinha mudado e começou a fazer um checkdisk. E travou. Insistindo uma segunda vez, ele conseguiu ir em frente. Nos dias seguintes o HD continuou estranho, culminando com uma tela azul (aperentemente um erro no acesso ao HD durante uma operação de paginação de memória). O jeito era trocar o HD, mas antes de devolver eu quis apagar os meus dados.

Apagando um HD

A maioria dos usuários sabe que apagar um arquivo pode não impedir que alguem veja os seus dados depois (mesmo que você esvazie a lixeira depois). Quando você apaga um arquivo, a maioria dos sistemas operacionais apenas anota que o espaço que ele ocupava está agora livre, sem mexer nos dados que estavam gravados.

Como apagar completamente um HD? Isto depende de quão paranóico você é. Sobrepor todo o conteúdo de um HD com zero pode ser suficiente para a maioria das pessoas, mas existem técnicas com o potencial de recuperar os dados sobrescritos. A wikipedia tem um descrição curta do assunto com uma lista de algumas ferramentas.
Desta lista escolhi o DBAN. Basta baixar a imagem do CD, gravá-lo, bootar por ele e digitar autonuke no prompt para automaticamente apagar de forma definitiva todos os HDs ligados ao micro, "no questions asked". Sim, é um perigo! O processo todo leva várias horas (felizmente o meu HD não engripou no meio).

O Segundo HD

Dominadas as técnicas, foi muito rápido repetir a cópia com o segundo HD. Ele vem funcionando muito bem... Exceto por vibrar um pouco, o que está causando um barulho irritante. Se achar uma solução que seja útil para outros eu coloco no blog.

Retomando

Parece que já está virando uma tradição do blog dar umas paradas longas e depois explicar que foi devido ao trabalho e da família. Desconfio que tive também um certo "bloqueio de escritor" pois tenho uma meia dúzia de textos inacabados e mais de uma dúzia de idéias para posts.

Vamos ver se nas próximas semanas consigo colocar no blog pelo menos uma parte de todo este material acumulado.