29 de janeiro de 2010

Amazon libera SDK para o Kindle

Na mesma semana que a Apple anunciou o lançamento de seu tão aguardado tablet PC - o iPad, a Amazon libera ferramentas para que terceiros possam criar aplicações e conteúdos para o dispositivo de leitura Kindle.

Apesar de ter saido na midia que alguns analistas acreditam que o iPad não substituirá o Kindle, é difícil não ver essa liberação como um movimento da Amazon para trazer para o seu lado produtores de conteúdo. Apesar do Kindle ser um aparelho exclusivamente para leitura (com tecnologia bem mais confortável para esse fim), o iPad é um computador e, como tal, pode ser usado para leitura e para muitas outras coisas, justificando uma preocupação da Amazon.

De acordo com a notícia publicada na InfoWorld, o SDK abre a possibilidade de que sejam desenvolvidas aplicações que exibam conteúdo dinamicamente:

A Amazon anunciou na última quinta-feira (28/01/2010) um kit de desenvolvimento de software para o Kindle, que habilita desenvolvedores de software a construir e carregar "conteúdo interativo" no aparelho.

O kit oferece acesso a interfaces de programação, ferramentas e documentação para construção de conteúdo para o Kindle. O kit também trás programas de exemplo e um simulador para construção e teste de conteúdos, simulando o comportamento do Kindle em computadores com sistema Mac, Windows ou Linux.

As possibilidades de conteúdo incluem livros de viagem que podem sugerir atividades baseado nas condições do tempo atuais ou de eventos que estejam programados no local, livros de culinária que recomendem um cardápio baseado no número de convidados de uma festa e histórico de alergia dos convidados, jogos com palavras, quebra-cabeças, etc. Os desenvolvedores poderão construir seus conteúdos e torná-los disponíveis através da loja do Kindle, a ser aberta ainda essa ano.

"O kit de desenvolvimento para o Kindle abre muitas possibilidades -- nossa expectativa é sermos surpreendidos pela inventividade dos desenvolvedores", declarou Ian Freed, vice presidente do Amazon Kindle.

Os desenvolvedores poderão disponibilizar seus conteúdos no sistema sem fio 3G do Kindle, através da rede Amazon Whispernet e exibí-los no papel eletrônico de alta resolução do aparelho. Esse papel se parece com papel de verdade e permite leitura da mesma maneira, diz a empresa. O Kindle contam também com um bateria que dura sete dias com a rede sem fio ativada.

Os participantes de um programa beta limitado no mês que vem poderão fazer o download do SDK, terão acesso ao suporte a desenvolvedores, poderão testar seus conteúdos no Kindle e submeter o conteúdo finalizado. Uma lista de espera para o programa também será oferecida.

Kindle e Kindle DX são leitores portáteis que permitem o download de livros, revistas, blogs e documentos pessoais através de rede sem fio e exibem esse conteúdo num visor com uma tinta eletrônica.

O texto original em inglês pode ser encontrado neste link.

26 de janeiro de 2010

Um Factory Method mais flexível em Delphi

No ano passado, eu mostrei aqui no blog o funcionamento do Design Pattern criacional chamado Factory Method. A implementação apresentada naquela ocasião seguia a solução tradicional para este pattern, isto é, exigia a criação de uma função - o método Factory - que, baseada nos valores de um ou mais parâmetros, decidia qual classe deveria ser instanciada.

No entanto, essa abordagem tem uma característica que pode se tornar um inconveniente em certas situações: o Factory Method obrigatoriamente tem que conhecer de antemão todas as classes que forem passíveis de serem criadas por ele. O "conhecer" aqui significa que o constructor de cada classe é chamado diretamente dentro da função Factory.

Neste momento, por exemplo, estou montando uma infraestrutura que a ABC71 usará para criar programas de assistência à implantação do nosso ERP. Dependendo do assistente desejado, os tipos e as quantidades de passos incluidos em cada programa vão variar. Por isso, o Factory Method tradicional não satisfaz plenamente já que ele exigiria que eu incluísse todos os tipos de passos possíveis em todos os programas, o que deixaria esses programas muito maiores do que deveriam.

Para resolver esse inconveniente, fiz uma pequena alteração no Factory Method original para que ele usasse uma lista de ponteiros para funções indexada pelo nome da classe que a função é capaz de criar. Quando quero instanciar uma determinada classe, informo ao Factory o nome dela. O Factory, então, recupera o ponteiro para a função associada e chama essa função para criar a instância correta. Para isso funcionar de acordo, as classes disponíveis devem ser adicionadas à lista. No caso do Assistente citado, as próprias classes de cada tipo de Passo se registram na lista, de modo que apenas aqueles passos necessários em cada programa são de fato incluidos.

O primeiro passo para implementar essa solução foi declarar um tipo "ponteiro para função" com os parâmetros necessários para se criar qualquer Passo para o Assistente:
{ AObj são dados que o construtor do passo pode usar para gerar a instância, podendo ser um nó XML ou outro dado relevante. }
TWPassoCreationFnc = function (AWizMan: TWWizardManager; AObj: TObject): TWPasso;

O primeiro parâmetro representa o gerenciador do Assistente onde o Passo deve ser criado, enquanto o segundo parâmetro é genérico, podendo conter qualquer informação relevante para o construtor da classe.

Em seguida, montei uma função para incluir na lista de tipos de passos disponíveis uma associação entre o nome de uma classe e a função que a constrói. Uma outra função permite construir um passo a partir do nome de sua classe. Ambas estão listadas abaixo:
procedure RegisterPassoInFactory (AClassName: String; AConstructor: TWPassoCreationFnc);
var idx : integer;
begin
idx := _FactoryPassos.Add (AClassName);
_FactoryPassos.Objects [idx] := @AConstructor;
end;

function CreatePassoFromFactory (AWizMan: TWWizardManager; AClassName: String; AObj: TObject) : TWPasso;
var lConstructor: TWPassoCreationFnc;
idx : Integer;
begin
idx := _FactoryPassos.IndexOf (AClassName);
if (idx >= 0) then
begin
@lConstructor := _FactoryPassos.Objects[idx];
Result := lConstructor (AWizMan, AObj);
end
else
Raise Exception.Create('Classe desconhecida: ' + AClassName);
end;

Observe que nos pontos onde o ponteiro para função é parte de uma atribuição eu utilizo um arroba (@) para me referir a ele. A sintaxe @lConstructor evita que a função (ou procedimento) seja chamada, indicando que eu estou apenas recuperando o endereço onde ela está na memória. Depois que o ponteiro foi recuperado, uso-o para fazer uma chamada à função que ele representa, passando-lhe os parâmetros conforme declarado no início. Para completar esta etapa, declarei a lista global na área implementation da minha unit e usei os blocos initialization e finalization dela para, respectivamente, criar e destruir tal lista.
implementation

var

_FactoryPassos : TStringList;

{ ... }
initialization
_FactoryPassos := TStringList.Create;

finalization
FreeAndNil (_FactoryPassos);
end.

Com isso, o cenário está preparado. Agora resta fazer com que cada classe que eu queira construir dessa maneira seja apropriadamente registrada na lista. Veja um exemplo para um passo cuja classe foi denominada TWPassoOpcao:
implementation

function CreateWPassoOpcao (AWizMan: TWWizardManager; AObj: TObject): TWPasso;
begin
Result := TWPassoOpcao.Create (AWizMan);
end;

{ ... }
initialization
RegisterPassoInFactory ('TWPassoOpcao', CreateWPassoOpcao);

end.

O mesmo terá que ser feito para as outras classes que denotam passos. Neste exemplo, eu omiti o uso do parâmetro AObj mas, no contexto onde isso é aplicado aqui na ABC71, esse parâmetro é um nó de uma estrutura XML a partir da qual os passos são criados. No entanto, como ele é um TObject, pode representar qualquer outra informação que seja necessária para criar com sucesso a instância da classe.

Esta implementação permite, agora, que cada programa assistente seja compilado apenas com os passos que ele realmente vai precisar, bastando fazer chamadas à função CreatePassoFromFactory para criá-los.

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.