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;