21 de janeiro de 2010

Explorando informações sobre programas em execução

Quem trabalha com desenvolvimento de software certamente já se deparou com a situação de enviar para um Cliente o programa compilado mas esquecer de enviar uma ou mais das bibliotecas dinâmicas (DLLs). Tendo este tipo de problema em mente, passei a buscar algum meio de fazer um levantamento das DLLs necessárias para a execução de um programa.

Como resultado desta busca, acabei me deparando com uma boa surpresa: uma ferramenta chamada Process Explorer. Esta ferramenta era uma das desenvolvidas pela empresa SysInternals mas atualmente pode ser encontrada diretamente no Technet - o site técnico da Microsoft. Digo que foi uma grata surpresa porque esta ferramenta faz muito mais coisas do eu estava procurando, com funcionalidades que realmente podem ser muito úteis para desenvolvedores e profissionais voltados para suporte.

Ao entrar no Process Explorer, ele imediatamente varre os processos que estão em execução em seu computador e os lista num painel na metade superior da interface gráfica, incluindo informações como o nome do fabricante e uma descrição do programa conforme registrado no próprio executável do processo.
Tela do Process Explorer

Clicar com o botão direito do mouse na barra onde estão os nomes das colunas permite selecionar a exibição de outros dados. As colunas disponíveis incluem informações sobre o consumo de memória pela aplicação (virtual, paginada, working set, etc.) dados do handle do processo e dados sobre sua performance (uso da cpu, etc.) e disponibiliza até mesmo qual a conta de usuário sendo usada para a execução.

Clicar com o botão direito do mouse sobre um dos processos dá acesso a outras ações, como modificar a prioridade de execução, suspender a execução temporariamente ou até mesmo interrompê-lo definitivamente. A opção "Propriedades" carrega uma janela onde todas as informações disponíveis sobre o processo são exibidas de forma centralizada (threads, segurança, linha de comando, conexões TCP/IP ativas e outras informações), além de monitorar em tempo real a execução do processo, mostrando gráficos de performance e variação do uso da memória. Ou seja, o Process Explorer é uma espécie de Task Manager turbinado.

Finalmente, selecionar um dos programas da lista faz com que o Process Explorer faça o levantamento de todas as bibliotecas dinâmicas (DLL) que estão carregadas pelo processo no momento. A lista de biblitoecas e os dados coletados sobre elas são então apresentados num outro painel, na parte de baixo da interface gráfica. Como esse painel permite exibir a versão de cada DLL, fica fácil também verificar se as versões carregadas são as corretas e não alguma outra que pode causar erros durante a execução. Ou seja, ajuda a detectar ocorrências de DLL Hell. Para desenvolvedores, esse painel pode ainda mostrar informações sobre o uso de memória por cada uma das bibliotecas e o nome da pasta a partir de onde ela foi carregada.

Um outro recurso interessante é o que permite mostrar todos os arquivos que estão abertos por um processo. Esse recurso pode ser acessado através da opção "Handles", encontrada no menu View e Lower Pane View, sendo que a lista de arquivos substitui a visão de DLLs no painel inferior.

Há ainda um ferramenta de busca no Process Explorer que permite encontrar rapidamente nomes de DLLs, pastas ou arquivos que estiverem em uso em qualquer um dos processos ativos.

O donwload do Process Explorer é gratuito e pode ser feito a partir do endereço http://technet.microsoft.com/en-us/sysinternals/bb896653.aspx.

19 de janeiro de 2010

Design Patterns com Delphi : Proxy - parte 2

Neste post, mostro como transformar em código Delphi as classes envolvidas para construir uma solução usando o pattern Proxy. Para facilitar a clareza, reproduzo abaixo o diagrama UML publicado no post anterior que descreve simplificadamente a solução. Para mais informações sobre o conceito por trás do padrão Proxy, veja o post anterior.
Diagrama UML para Proxy

Para começar, devemos estabelecer o Subject como uma classe abstrata, isto é, ele servirá apenas para demarcar quais são as operações e propriedades disponíveis no nosso Proxy. No diagrama acima, esta classe é o TWSigner:
type
TWSigner = class
{ ... }
public
class function GetTWSigner (AProxy: boolean) : TWSigner;
function Assinar (AXml: String): String;virtual;abstract;
end;

Com isso assentado, podemos então partir para a implementação das duas classes que satisfazem essa interface, a saber o TWSignerProxy e o TWRemoteSigner. O TWRemoteSigner é quem efetivamente se comunica com o serviço remoto de assinatura enquanto o TWSignerProxy é um Proxy para a classe de comunicação remota e que postergará a conexão até que esta seja de fato necessária:
type
TWSignerProxy = class(TWSigner)
protected
_Signer: TWRemoteSigner;
{ ... }
public
function Assinar (AXml: String): String;override;
end;

TWRemoteSigner = class(TWSigner)
protected
_Connected : boolean;
{ ... }
public
function Conectar (AHost: String; APort: integer): boolean;
function Desconectar : boolean;

function Assinar (AXml: String): String;override;
end;

{ ... }
implementation
{ ... }

function TWSignerProxy.Assinar (AXml: String): String;
begin
{ Cria a instância para comunicação remota, se ainda não foi criada }
if _Signer = Nil then
_Signer := TWRemoteSigner.Create;

{ Faz a conexão, se ainda não fez }
if not _Signer._Connected then
_Signer.Conectar (ObterHost, ObterPort);

{ Repassa o comando de assinatura para a classe de comunicação remota }
Result := _Signer.Assinar (AXml);
end;

Veja no código acima que a conexão remota só é estabelecida pelo Proxy quando estritamente necessária. A funcionalidade de um Proxy poderia incluir ainda outros tratamentos com o intuito de minimizar esperas, reduzir uso de memória e outros recursos ou ainda fazer validação de credenciais de um usuário antes de lhe dar acesso a determinada informação. Por exemplo, poderia criar um cache local, armazenando internamente certos dados e usá-los quando necessário no futuro para evitar a criação de novas instâncias de classes, conexões remotas ou a carga de um arquivo.

Os padrões de projeto não são soluções isoladas, estanques. Quero dizer com isso que é bastante frequente envolver dois (ou até mais) dos padrões para se projetar a solução para um único problema computacional. No exemplo desenvolvido neste post, por exemplo, é interessante determinar em tempo de execução qual a classe que deve ser instanciada para suprir a referência de TWSigner na nossa classe client. Este é claramente o cenário apropriado para se usar um Factory Method:
class function TWSigner.GetTWSigner (AProxy: boolean) : TWSigner;
begin
if AProxy then
Result := TWSignerProxy.Create
else
Result := TWRemoteSigner.Create;
end;

Com essa Factory, a classe Client pode decidir se quer ou não usar o Proxy. Para o caso, por exemplo, do programa Cliente estar em execução na mesma máquina que o Servidor de assinaturas pode ser mais interessante instanciar diretamente a classe de assinatura. Isso é possível porque ambas as classes respeitam a mesma interface.

Para usar isso tudo, a classe TWBusinessObj - que é nosso Client para esse exemplo - deve obter a instância necessária de TWSigner através da Factory. Com isso, ela desconhece os detalhes de implementação desse signer; para ela, basta que a assinatura de que ela precisa seja feita corretamente.
TWBusinessObj = class
protected
_Signer: TWSigner;

public
procedure DoOperacao;
end;
{ ... }

procedure TWSBusinessObj.DoOperacao;
var lAssim : String;
begin
{ ... }
{ Cria a instância para assinatura. Não dá pra saber de antemão se é a versão Proxy ou a versão remota ... }
if _Signer = Nil then
_Signer := TWSigner.GetTWSigner (_UsaProxy);

lAssin := _Signer.Assinar (AXml);

{ ... }
end;


14 de janeiro de 2010

Design Patterns com Delphi : Proxy - parte 1

Dos Design Patterns estruturais estabelecidos pelo GoF no livro Design Patterns, ficou faltando tratar neste blog apenas o padrão Proxy. O termo "proxy" pode ser traduzido como "procuração", isto é, a autorização para alguém - no caso, um objeto computacional - agir no lugar de outro. O conceito por trás desse padrão é justamente este: fornecer um objeto substituto que controle o acesso ao objeto real.

O cenário típico para aplicação do padrão Proxy aparece quando há algum tipo de restrição para acessar o objeto real, justificando que a criação dele seja postergada até que o objeto seja de fato necessário. Por exemplo, se há necessidade de carregar uma imagem muito grande ou se o objeto tem que ser acessado remotamente ou ainda se o acesso ao objeto depende de o usuário ter ou não permissão para isso. Assim, o objeto que age por procuração tem oportunidade de tomar as providências necessárias para acessar o objeto real e, então, repassar para ele os comandos recebidos.

Quando o cenário envolve o gerenciamento de objetos cuja duplicação é muito dispendiosa (usa muita memória, por exemplo) ou até mesmo impossível, é comum adaptar o padrão Proxy e usá-lo de uma forma mais flexível, misturada como o FlyWeight.

Como exemplo prático, imagine a situação em que você tem diversas estações habilitadas a enviar a Nota Fiscal Eletrônica para o site da Receita Federal mas o Certificado Digital necessário para assinar os documentos está disponível apenas no servidor, sendo que há um objeto publicado remotamente no Servidor que é capaz de realizar a assinatura. Para o programa nas estações, é possível implementar um "proxy" para acessar o objeto do Servidor. Segue um esquema UML mostrando a solução para esse exemplo usando o pattern Proxy:
Diagrama UML para Proxy

A nomenclatura para as classes envolvidas na solução típica para o Proxy é a seguinte:
O Subject é uma classe abstrata que apenas introduz o comportamento esperado tanto para o objeto real quanto para seu "Proxy", isto é, a interface desejada para esses objetos. No diagrama, esse é o papel da classe TWSigner.
O Proxy é a classe que age como um substituto para a classe real de objetos. É muito comum, portanto, que ela própria gerencie o ciclo de vida do objeto real, criando-o e destruindo-o no momento apropriado. Por isso, deve armazenar uma referência ao objeto real. O objetivo do Proxy é repassar ao objeto real os comandos solicitados, preparando antes o terreno para que a execução seja feita. Para isso, deve tomar providências tais como realizar conexões remotas, execução de tarefas demoradas ou validação de credenciais do usuário no momento mais oportuno, de forma que isso tudo é feito apenas se for estritamente necessário.
Como o Proxy reproduz fielmente a interface publicada pelo Subject, ele pode, se for necessário, ser substituido pela própria classe real de modo que esta será usada no lugar do Proxy. A classe TWSignerProxy age como Proxy no diagrama acima.
Real Subject é a classe que efetivamente realiza as operações estipuladas pela interface Subject. Esse é o papel exercido pelo TWRemoteSigner no exemplo.
O Client é a parte do programa que faz uso da interface estabelecida pelo Subject. Para ele, é indiferente qual instância está de fato sendo usada, uma vez que tanto o Proxy quanto o RealSubject implementam a interface. Este papel é desempenhado pela classe TWBusinessObj no diagrama do exemplo.

Este tipo de abordagem onde as chamadas a funções de um objeto são encapsuladas em outro objeto é parecido com o padrão Adapter. A diferença crucial está no fato que no Adapter a interface das classes envolvidas são diferentes entre os objetos pois o objetivo é permitir que se troque o objeto interno quando há necessidade sem precisar modificar o resto do programa. Já no Proxy, ambos os objetos compartilham a mesma interface, sendo que o objeto externo apenas redireciona as chamadas para o objeto interno.

No próximo post, mostro a criação das classes Delphi para implementar essa solução.

12 de janeiro de 2010

Padrão para manter localmente dados de aplicações Web

O W3C (World Wide Web Consortium) acaba de publicar no início de Janeiro de 2010 o rascunho de um Padrão para permitir armazenar localmente e de forma estruturada dados utilizados em aplicações Web. O documento publicado define APIs para publicar e recuperar as informações como um banco de dados convencional. Assim, quando uma API que siga o padrão proposto for implementada, será possível criar aplicações para a internet quer armazenem suas informações localmente na máquina do usuário, abrindo a possibilidade desse usuário acessar mais tarde a mesma aplicação sem ser obrigatório que ele esteja conectado à internet.
Reproduzo abaixo a matéria que saiu na InfoWorld sobre o assunto:

O W3C (World Wide Web Consortium) publicou o rascunho de um conjunto de APIs com as quais aplicações Web poderão um dia armazenar dados estruturados para uso em acesso offline.

O padrão proposto, recentemente rebatizado de Indexed Database API, fornecerá uma interface para que os desenvolvedores de aplicações Web possam ter um banco de dados associado ao navegador do usuário, permitindo acesso a contéudo mesmo estando desconectado da internet, diz Philippe Le Hégaret, chefe do Web Services Coordination Group no W3C.

Tipicamente, as aplicações Web atuais, como clientes de email ou Agendas na Web, desenham os dados do usuário a partir de um banco de dados acessível pela rede. Em alguns casos, entretanto, o usuário pode querer usar a aplicação num momento em que não esteja conectado a essa rede. As aplicações Web poderão utilizar essas APIs (interfaces de programação de aplicações) para armazenar cópia dos dados no próprio navegador.

"O tratamento do banco de dados residirá diretamente no navegador," diz Le Hégaret. A API é baseada em Java Script e fornecerá os meios para que os desenvolvedores de aplicações Web armazenem os dados no navegador e possam submeter consultas para recuperá-los. O padrão proposto permitirá que você associe valores a uma chave e que você acesse esses valores através da chave", diz Le Hégaret.

Hoje, os desenvolvedores de aplicações Web criam suas próprias abordagens para armazenar dados offline. Com o novo padrão, assumindo que ele seja adotado pelos fabricantes de navegadores, o armazenamento de dados pode ser efetuado pelo navegador ao invés de ser feito por cada aplicação. "O navegador se encarregará de gerenciar o banco de dados," Le Hégaret diz.

A ideia de padronizar o armazenamento offline de dados está alinhada com o objetivo global do W3C de transformar o uso da Web de uma simples plataforma de visualização de conteúdo estático para algo capaz de hospedar aplicações mais ricas baseadas na internet. O armazenamento offline é um componente que está sendo assumido pelo grupo de trabalho para Aplicações Web do W3C, cuja meta é estabelecer um grupo de padrões que os navegadores devem adotar para facilitar o desenvolvimento de uma Web com interações mais ricas.

O padrão Indexed Database API, antes conhecido como WebSimpleDB API, não é o único conjunto de APIs que o W3C está devenvolvendo para armazenamento offline. Ao menos um outro padrão está ativamente sendo construido. "O Web Storage também pode ser usado para guardar conjuntos menores de dados offline. Entrento, ele não objetiva guardar grandes quantidades de dados", Le Hégaret diz.

O W3C vem trabalhando no rascunho de um terceiro padrão, chamado Web SQL Database, que é muito parecido com o Indexed Database API, de acordo com Le Hégaret. A diferença entre ambos é que Web SQL se restringe a armazenar dados formatados como SQL, enquanto o Indexed Database API pode trabalhar também com bancos de dados não-relacionais. Entretanto, os trabalhos com o Web SQL Database aparentemente estão em suspenso.

O grupo planeja analisar o rascunho por mais alguns meses antes de submetê-lo uma última vez para comentários. Após juntar os comentários de desenvolvedores, fabricantes de navegadores e do próprio W3C, o W3C publicará o padrão proposto como uma recomendação. Ficará, então, a critério de cada fabricante de navegador se irá ou não implementar a tecnologia em seu produto.

O Indexed Database API é "um bom candidato para implementações interoperáveis e independentes", diz Pablo Castro, uma arquiteto de software do grupo do SQL Server da Microsoft, em seu blog. "Estamos trabalhando em compreender a API, dando retornos ao grupo para Aplicações Web do W3C e criando implementações experimentais para explorar o espaço", escreveu ele.

O texto original da matéria (em inglês) pode ser encontrado neste link.