Você realmente precisa de um banco de dados? Conheça o XPrevail .

 

By Fernando Vasconcelos Mendes

 

 

            Resumo: Este artigo tem por objetivo falar um pouco sobre o conceito de prevalência e como ela pode ser uma alternativa ideal ao uso de banco de dados em várias situações. Conheceremos o XPrevail , um framework de prevalência open source desenvolvido em Delphi for .NET e como seus recursos podem possibilitar uma programação simples e moderna. Meu desejo é que esse artigo atue como uma carta de apresentação do projeto XPrevail a nossa comunidade de desenvolvimento de software.


Download do exemplo aqui.
Download do XPrevail.
 

 

O que é prevalência?

 

O conceito de prevalência foi originalmente idealizado pelo brasileiro KlausWuestefeld e concretizado no projeto Prevayler , uma implementação em Java. Ele é uma união de antigos conceitos já aplicados isoladamente em outros cenários.


Como mencionei no resumo, a utilização da prevalência é uma alternativa ao uso de banco de dados. Com ela, todos os objetos de negócios ficam persistidos na memória e há garantia de que eles serão recuperados fielmente caso haja alguma queda de energia ou falha na aplicação. Dentre as principais vantagens do uso de prevalência podemos citar:

 

- O grande ganho de performance para consultas;

- A drástica redução de custos de uma solução (elimine aqui custos de servidor par o banco de dados (hardware), licenças do software servidor de banco de dados, custo operacional de manutenção e etc);

- Induz um desenvolvimento verdadeiramente orientado a objetos (na minha opinião a mais interessante).

 

Não deixe de visitar a seção “ O que é?” nosite do projeto XPrevail .

 

Conceitos chaves

 

Para entendermos o funcionamento geral da prevalência é importante que antes conheçamos alguns termos comumente utilizados dentro desse conceito, dessa forma, vejamos a seguir os principais deles.

 

PrevalenceEngine : Trata-se de uma classe interna dos framework’s de prevalência, que é responsável por todo o processo de execução, registro e recuperação das alterações realizadas no PrevalentSystem . Muitas vezes a referenciamos simplesmente como “ engine ”. Veremos mais adiante que o XPrevail disponibiliza quatro tipo de engines diferentes, cada um com suas particularidades.

 

PrevalentSystem : Uma classe definida pelo usuário que deve referenciar todos os objetos de negócios da aplicação, ou seja, os objetos que serão persistidos. Os objetos nela referenciados serão serializados quando for solicitado ao PrevalenceEngine um snapshot. Dessa forma, qualquer objeto fora dessa classe terá seu estado perdido.

 

Snapshot : É o processo no qual o PrevalenceEngine serializa todo o PrevalentSystem (na realidade veremos mais adiante que o XPrevail suporta o trabalho com múltiplos PrevalentSystem ’s), tal qual ele está no momento da solicitação. Isso dá origem um novo arquivo de snapshot, e torna desnecessária a leitura dos arquivos de log de operações anteriores.

 

Operation : Pelo conceito original proposto pela prevalência, toda alteração a ser realizada nos objetos mantidos por um PrevalentSystem deve ser feita através de objetos de classes que implementam a interface IOperation definida pelo framework. Essas instâncias são passadas ao PrevalenceEngine para registro e execução. No projeto prevayler a interface equivalente chama-se Transaction . (ver em manifest mais detalhes).

 

Fluxo de execução da prevalência

 

Para entendermos melhor o conceito, vou descrever agora qual seria o fluxo de execução de uma aplicação prevalente. Imagine que tenhamos apenas uma classe de negócio numa dada aplicação, a classe Client . Vamos aos passos para tornar essa aplicação prevalente.


1. Precisamos definir uma classe que manterá referência a nossos objetos Client , ela será nosso   PrevalentSystem e poderia chamar-se Clients .


2. Deveremos declarar uma referência para oPrevalenceEngine e inicializá-la , momento no qual será exigida a informação de qual classe será o PrevalentSystem , naturalmente devemos informar Clients .


3. Ainicialização do PrevalentSystem deve ser solicitada ao PrevalenceEngine , através da propriedade PrevalentSystem . Ela retornará uma instância da classe Clients com um estado exatamente igual ao da última execução (caso tenha havido uma).


4. Como foi mencionado, qualquer alteração noPrevalentSystem , para prevalecer é exigido que seja feita através de objetos de classes que implementem a interface IOperation . Assim, podemos declarar duas classes, uma chamada AddClient e outra chamada RemoverCliente , ambas implementando a interface IOperation . Respectivamente elas seriam utilizadas para adicionar e remover objetos Cliente doPrevalentSystem . (Ao longo desse texto poderemos ver o que o XPrevail propõe para uma programação mais simples e intuitiva, não exigindo a criação dessas classes auxiliares)


5. Para adicionar um cliente, precisamos agora criar uma instância da classe AddClient , passando em seu construtor as informações necessárias a execução de sua tarefa. Devemos então solicitar ao PrevalenceEngine que execute essa operação. Isso envolverá a serialização  do objeto  AddClient em um arquivo destinado ao  log de operações e posteriormente sua execução, onde de fato ocorrerá a adição do cliente.


6. Digamos que após executarmos várias vezes o item 5, além de também termos realizados algumas remoções de clientes, teremos então um PrevalentSystem contendo uma determinada quantidade de objetos Client . O arquivo de log de operações conterá uma versão serializada de todos os objetos (que implementam IOperation ) que efetuaram alterações no PrevalentSystem , exatamente na mesma ordem em que eles ocorreram.


7. Caso nesse ponto ocorresse uma falha de energia. Nossa aplicação deveria ser reposta no ar, tão logo o ambiente tenha sido re-estabelecido. No momento da inicialização do PrevalenceEngine , ele irá ler todos os arquivos de log de operações gerados. Ele deserializará todos os objetos contidos nos arquivos e irá executá-los novamente. Atente para o detalhe que os objetos mantidos nesse arquivo são os da classe AddClient , não os da classe Client . O PrevalenceEngine está constantemente registrando as alterações realizadas nos objetos de negócios, não os objetos de negócio em si.


8. Tendo a aplicação voltado ao ar e seu estado anterior recuperado , poderíamos gerar mais algumas alterações no PrevalentSystem e solicitar um snapshot. Nesse momento o PrevalenceEngine irá gerar um arquivo novo, não um de operações, mas um especificamente para o snapshot. Esse arquivo conterá uma versão serializada do PrevalentSystem inteiro, ou seja, efetivamente de todos os objetos de negócio. Digamos que após o snapshot, fizemos mais algumas alterações no estado do PrevalentSystem e ocorreu outra falha de energia.


9. Quando nossa aplicação solicitar a inicialização do PrevalenceEngine , ele buscará pelo mais recente snapshot gerado. De posse dele, ele deserializará seu conteúdo e obterá uma versão do PrevalentSystem . Feito isso, pegará todos os arquivos de log de operações posteriores ao último snapshot e re-executará todas as operações em cima do PrevalentSystem obtido anteriormente. Isso resultará em um PrevalentSystem tal qual existia antes da falha, da forma mais otimizada possível.

 

Exigências da prevalência

 

A prevalência possui dois requisitos obrigatórios a serem atendidos pelos objetos de negócios que serão persistidos, eles devem ser serializáveis  e determinísticos . Um objeto determinístico é aquele que submetido a uma mesma série de alterações, numa mesma ordem, sempre resultará num mesmo estado final. A classe que representa o PrevalentSystem , obviamente, também precisa ser serializável . No .NET a forma mais simples e eficiente de tornar uma classe serializável é através do atributo SerializableAttribute .


Os conceitos envolvidos na prevalência estão estabelecidos de tal maneira a executar as tarefas de uma forma otimizada, isso refletiu em questões como:


Serializar as alterações nos objetos de negócio, no lugar deles próprios, isso diminui significativamente a quantidade de espaço em disco necessário para garantir o estado do PrevalentSystem .

- Não ter qualquer tipo de indexação nos arquivos gerados, afinal o objetivo não é simular um banco de dados, mas sim eliminá-lo. Dessa forma, concentrou-se apenas no processo de serialização e recuperação de objetos.

- A recuperação de um PrevalentSystem através de seu snapshot é extremamente mais rápida que a recuperação através do log de operações. É fácil perceber o motivo, através de um snapshot ele deserializa  o PrevalentSystem como um todo, diretamente, já com o log de operações, ele precisa deserializar todos os objetos de operações e executá-los novamente. Por isso é recomendado realizar snapshots periodicamente, mas tenha cuidado, durante o snapshot de um PrevalentSystem ele não pode ser alterado.

 

Um outro detalhe importante, como todos os objetos são mantidos em memória, para trabalhar de forma eficiente com prevalência é preciso ter memória RAM suficiente para hospedar todos os objetos de negócio do sistema.


Espero que tenham notado que percorrendo os passos descritos anteriormente não temos nenhuma instrução SQL envolvida. Um efeito colateral positivo do conceito de prevalência é que somos obrigados a encarar com mais seriedade a orientação a objetos, pois será apenas com ela que trabalharemos. Usamos nossa própria linguagem de programação para realizar consultas, podemos trazer e manipular os dados de qualquer forma.

 

O que é o XPrevail ?

 

O XPrevail é uma camada .NET de prevalência de objetos, amigável e extendida , implementada em Delphi for .NET. O framework é compatível com qualquer linguagem .NET, além de ser freeware e opensource . O tópico ManifestoXPrevail traz os motivos pelo qual oXPrevail existe, bem como seus diferenciais frente a outras implementações de prevalência.

 

Grande parte dos diferencias buscado por mim, frente aos outros frameworks de prevalência, foram em prol de uma programação mais natural, provendo um framework tão transparente e menos intromicivo quanto fosse possível. Procurei deixar o modelo de programação com o  XPrevail de tal maneira que uma aplicação ficasse menos dependente dele, facilitando a troca do mecanismo de persistência sem grandes esforços.

 

Vejo a persistência como um aspecto isolado de um software, não devendo influenciar significativamente em seu modelo, arquitetura e implementação. Essa ideologia foi uma constante durante a modelagem e implementação do XPrevail . Esses objetivos levaram-me a fazer algumas coisas de forma diferente, além de adicionar alguns pequenos recursos.

 

Dentre os principais diferencias trazidos pelo XPrevail posso destacar as seguintes:

 

Múltiplos PrevalentSystem's

 

O XPrevail traz o MultiSystemsPrevalenceEngine , capaz de trabalhar com múltimplos PrevalentSystem ’s baseados emproxy ’s transparentes do .NET. Esse tipo de engine traz a grande vantagem de não precisar definir objetos para realizar todas as alterações no PrevalentSystem , essas alterações podem ser feitas através de métodos definidos no próprio PrevalentSystem . As chamadas a esses métodos são interceptadas e automaticamente convertidas em objetos que são, da maneira tradicional, serializados e executados.

 

Ele possibilita uma boa separação de responsabilidades, de modo que cada PrevalentSystem mantenha operações apenas sobre objetos logicamente relacionados. Além disso, podemos usar as classes gerentes do próprio sistema como os PrevalentSystem's , não precisando criar uma global envolvendo-as.

 

De forma resumida, o uso de múltiplos PrevalentSystem's ajuda a termos um código amigável e elegante, mais condizente com a boa programação orientada a objetos.


Cobertura sobre todos os objetos de negócios

 

O XPrevail introduz, através do ExtremePrevalenceEngine , a possibilidade de interceptar todas as requisições realizadas aos objetos de negócio e automaticamente transformá-las em objetos apropriados, serializá-los e executá-los. Com isso, podemos trabalhar de forma completamente transparente, acessando os objetos de negócios e modificando-os diretamente, sem a intervenção de uma classe externa, nem mesmo de um  PrevalentSystem .

 

Esse é um importante passo no processo de tornar o uso do XPrevail mais amigável ao código cliente, com  algumas poucas exigências, poderemos fazer a prevalência dos objetos de negócios, mesmo para alterações realizadas diretamente neles. Isso também contribui para uma forma de programação mais natural e menos dependente do XPrevail ou do conceito de prevalência (Veja em roadmap a intenção doXPrevail em suportar persistência em banco de dados relacionais também).


Suporte programação orientada a aspectos – AOP

 

  Outra característica bem interessante trazida pelo XPrevail é a possibilidade de utilizar um modelo de desenvolvimento baseado nos conceitos da programação orientada a aspectos, muitas vezes referenciada simplesmente como AOP. Grande parte do framework é baseado em proxy ’s , por sua vez, na interceptação de código, princípio básico da AOP. Dessa forma, como eu já vinha utilizando uma abordagem similar para comunicação entre proxy ’s e classes internas do framework, foi apenas questão de publicar uma maneira do código cliente obter recursos dessa abordagem, tão logo eu percebi esse potencial. 


Os engines do framework que implementam a interface IAspectsSupport , atualmente o MultiSystemsPrevalenceEngine e o ExtremePrevalenceEngine , disponibilizam meios de registrar e desregistrar aspectos (qualquer objeto que implemente a interface IAspect ) .


O XPrevail disponibiliza dois aspectos implementados, em versão pré-liminar, que podem já ser utilizados livremente pelo código cliente , são eles o TraceAspect e ProfileAspect . Respectivamente, eles são capazes de registrar chamadas a métodos em cima dos objetos de negócios e registrar os tempos levados para execução dos mesmos. Esse é um recursos extremamente útil e poderoso, certamente ele será ainda bem desenvolvido nas versões futuras do XPrevail (ver roadmap ).

 

Não deixe de visitar a seção “ Manifesto” nosite do projeto XPrevail .


Trabalhando com o XPrevail

 

Veremos agora um exemplo completo de utilização do ExtremePrevalenceEngine , o principal PrevalenceEngine do XPrevail , nele é onde encontramos a real essência do framework. Antes de prosseguir, uma leitura dos tutoriais Hello Prevalence e Hello Prevalence 2 , nosite do projeto XPrevail , pode ajudar bastante o entendimento do exemplo que aqui desenvolveremos.

 

Definindo o modelo de objetos

 

Antes de pensar na persistência precisamos primeiro definir o modelo de nossos objetos de negócio. Por questões de simplicidade vamos trabalhar com apenas um objeto de negócio, People . Usaremos ele para criar uma pequena aplicação para cadastro de pessoas.

  
  People = class 
  strict private
    FName : System.String ;
    FBirthDate : System.DateTime ;
    FEMail : System.String ;
  public
    function ToString : String; override;
    procedure set_Name (const Value: System.String );
    procedure set_EMail (const Value: System.String );
    procedure set_NiverDate (const Value: System.DateTime );
    function get_Age : Integer;
    property Name : System.String read FName write set_Name ;
    property Age : Integer read get_Age ;
    property EMail : System.String read FEMail write set_EMail ;
    property BirthDate : System.DateTime read FBirthDate write   set_NiverDate ;
    constructor Create( aName : String; aEMail : String; aBirthDate :   DateTime );
  end;


Pronto, essa seria a definição padrão de nossa classe, contudo precisamos fazer algumas alterações de modo que ela atenda as exigências da prevalência e do ExtremePrevalenceEngine . Para isso, precisaremos fazer as seguintes modificações:

 

  1. Como foi dito, os objetos de negócios precisam ser serializáveis , então devemos incluir o atributo SerializableAttribute na classe.
  2. Os objetos de negócios, bem como o PrevalentSystem , precisam ser descendentes de MarshalByRefObject .
  3. Para que o framework consiga identificar corretamente um dado objeto de negócio, ele precisa implementar a interface IObjectID , além de ser marcado com o atributo BusinessObjectClassID .

 

Realizadas as alterações necessárias, a interface de nossa classe People fica assim:

 

  [ Serializable ]

  [ BusinessObjectClassID ( PeopleClassID )]

  People = class ( MarshalByRefObject , IObjectID )

strict private

  FID : System.String ;

    FName : System.String ;

    FBirthDate : System.DateTime ;

    FEMail : System.String ;

  public

    function ObjectID : string;

    function ToString : String; override;

    procedure set_Name (const Value: System.String );

    procedure set_EMail (const Value: System.String );

    procedure set_NiverDate (const Value: System.DateTime );

    function get_Age : Integer;

    property Name : System.String read FName write set_Name ;

    property Age : Integer read get_Age ;

    property EMail : System.String read FEMail write set_EMail ;

    property BirthDate : System.DateTime read FBirthDate write   set_NiverDate ;

    constructor Create( aID , aName : String; aEMail : String; aBirthDate :   DateTime );

  end;


O próximo passo é criar uma classe que será nosso PrevalentSystem , vejamos então a definição da classe PeopleManager para esse propósito.

  [ Serializable ]

  [ PrevalentSystemClassID ( '{319D4955-4CE8-4443-9010-9BAE12046C24}')]

  PeopleManager = class ( MarshalByRefObject , IBusinessObjectFromID )

  strict private

    FPeoples : ArrayList ;

  strict protected

    function BusinessObjectFromID ( BOClassID , ObjectID : string): TObject ;

  public

    function AllPeoples : ArrayList ;

    [ BusinessObjectExport ]

    function get_Peoples (Index: Integer): People;

    property Peoples[Index : Integer] : People read get_Peoples ;

    function get_PeopleCount : Integer;

    property PeopleCount : Integer read get_PeopleCount ;

    [Operation]

    [ BusinessObjectExport ]

    function AddPeople ( aID , aName : String; aEMail : String; aBirthDate :   DateTime ) : People;

    [Operation]

    [ RealBusinessObjectRecovery ]

    procedure RemovePeople ( aPeople : People);

    constructor Create ;

  end;

 

Tal qual uma classe de objeto de negócio, o PrevalentSystem também precisa descender de MarshalByRefObject e receber o atributo Serializable (na verdade ser serializável ). Como o ExtremePrevalenceEngine é um PrevalenceEngine que suporta trabalhar com vários PrevalentSystem ’s, é necessário que eles sejam marcados com o atributo PrevalentSystemClassID , para que o framework consiga identificá-los corretamente. Note também que a interface IBusinessObjectFromID é implementada pela classe PeopleManager , isso é necessário apenas se o PrevalentSystem em questão mantém referência a objetos de negócios.

 

Observe a utilização de vários atributos adornando métodos da classe PeopleManager , vejamos agora para que serve cada um deles.

 

1.       Operation : Indica ao XPrevail que o método em questão realiza alterações no estado do PrevalentSystem . Caso um método que altere o estado do PrevalentSystem não seja marcado com esse atributo, a alteração não prevalecerá.

2.       BusinessObjectExport : Indica ao framework que esse método retorna um objeto de negócio para fora do PrevalentSystem , dessa forma, o XPrevail intercepta essa chamada e retorna um proxy para o objeto em questão, de modo que as alterações realizadas diretamente no objeto sejam persistidas. Observe que, como em todo mecanismo de persistência, cabe ao programador decidir o que será persistido. Alterações em um objeto de negócio obtido por um método sem esse atributo não serão persistidas.

3.       RealBusinessObjectRecovery : Indica ao XPrevail que ele deve recuperar o objeto a partir de uma versão duplicada dele (maiores detalhes no quadro a seguir).

 

RealBusinessObjectRecovery

A prevalência de maneira geral proíbe que classes que implementem a interface IOperation (ou Transaction no Prevayler ), ou seja, que alterem o estado de um PrevalentSystem tenha referência direta a um objeto de negócio. Pois dessa forma, o objeto de negócio será duplicado e a alteração em questão se dará nessa versão duplica, isso causa bastantes problemas. Esse erro é bastante comum, sendo considerado um erro de batismo da prevalência.

 

Pois bem, o XPrevail não recomenda que isso seja feito, contudo não proíbe. Ele lhe deixa a opção de assim você modelar seu código, estando ciente de envolverá algum custo de performance. Estando certo dessa opção, basta marcar o método com o atributo RealBusinessObjectRecovery e o XPrevail cuidará para que isso não gere problemas inesperados. Isso será demonstrado no exemplo.

 

Pronto, agora já temos nossas classes ajustadas para desenvolvermos nosso exemplo prevalente. E o melhor, praticamente todo o código de persistência já foi feito, ou seja, quase nenhum. Observe que as exigências do XPrevail não são muito intrusivas, visto que são resolvidas com adornos através de atributos e/ou implementações de interfaces. Uma eventual decisão de remover o XPrevail como mecanismo de persistência, ou adaptar o software a outro mecanismo, não implica numa perda significativa de código.

 

Desenvolvendo uma aplicação console

 

Vamos agora criar uma aplicação console para ilustrarmos a utilização das classes que definimos. Para que o texto não fique demasiadamente extenso, colocarei apenas os trechos de implementação realmente relevantes. Para ter acesso ao código completo basta fazer o download do aplicativo de exemplo deste artigo. Para compilá-lo, é essencial baixar o XPrevail , você pode fazer isso através do link http://xprevail.sourceforge.net/pt-br/download.htm.

 

O primeiro ponto a comentar a como obter uma instância inicial de nosso PrevalentSystem e como veremos, ela deve ser solicitada ao PrevalenceEngine . Mas para isso, precisamos primeiro obter uma instância do próprio engine . O código abaixo ilustra todo esse processo:

 

001. var

002.    Engine : ExtremePrevalenceEngine ;

003.    GenKeys : GenerateKeys ;

004.    PManager : PeopleManager ;

005.

006. begin

007.    Engine := XPrevailFactory.CreateExtremePrevalenceEngine ([ typeOf ( GenerateKeys ),

              typeOf ( PeopleManager )], Path.Combine ( Environment.CurrentDirectory , 'data'));

008.    GenKeys   := Engine.PrevalentSystems [ typeOf ( GenerateKeys )] as GenerateKeys ;

009.    PManager := Engine.PrevalentSystems [ typeOf ( PeopleManager )] as PeopleManager ;

 

010. {…}

011. end .

 

As linhas de 2 a 4 contêm apenas as declarações das referências. Na   linha 007 é solicitada a criação de uma instância da classe ExtremePrevalenceEngine , como podemos ver, isso é feito através da classe XPrevailFactory . O método CreateExtremePrevalenceEngine requer como primeiro parâmetro um array de System.Type representando os PrevalentSystem ’s que serão gerenciados pelo engine . O segundo parâmetro informa a pasta onde serão colocados os arquivos de log de operações e arquivos de snapshots .

 

Certamente você já percebeu que estamos utilizando um segundo PrevalentSystem , representado pela classe GenerateKeys . Que como o nome sugere, servirá justamente como um gerador de ID’s para nossos objetos. A definição dessa classe é muito simples e pode ser vista abaixo:

 

  [ Serializable ]

  [ PrevalentSystemClassID (' {5CFE36DA-9C6A-495F-911B-10CD99374195}')]

  GenerateKeys = class ( MarshalByRefObject )

  strict private

    HashKeys : HashTable ;

  public

    [Operation]

    function NewKey ( ObjectType : System.Type ) : Integer;

    constructor Create ;

  end;

 

Ela assegura que seja gerado um seqüencial único para os objetos de um tipo especificado, pode ocorrer de objetos de negócios terem ID’s iguais, desde que sejam de tipos diferentes. Essa é uma exigência do ExtremePrevalenceEngine . Observe que como ela não mantém objetos de negócios, não precisamos implementar a interface IBusinessObjectFromID . A seguir podemos ver a implementação de seu principal método, o NewKey .

 

function GenerateKeys.NewKey ( ObjectType : System.Type ): Integer;

var

  KeyID : Integer;

begin

  Monitor.Enter ( ObjectType );

  try

    if HashKeys.Contains ( ObjectType ) then

      begin

        KeyID := Integer( HashKeys.Item [ ObjectType ]);

        Inc( KeyID );

        HashKeys.Item [ ObjectType ] := &Object( KeyID );

      end

    else

       begin

        KeyID := 1;

        HashKeys.Add ( ObjectType , &Object( KeyID ));

      end ;

    Result := KeyID ;

  finally

    Monitor.Exit ( ObjectType );

  end ;

end ;

 

As linhas 008 e 009 obtêm as instâncias de nossos PrevalentSystem ’s. Como as operações do PeopleManager utilizará o GenerateKeys , é importante que esse último seja solicitado primeiro. Isso é feito através da propriedade PrevalentSystems , informando o System.Type do PrevalentSystem pretendido. Vamos agora prosseguir analisando alguns trechos chaves da implementação de nosso aplicativo.

 

Adicionando uma pessoa

 

var

  {...}

  ID : String;

begin

  {...}

    ID := Convert.ToString ( GenKeys.NewKey ( typeOf (People)));

    PManager.AddPeople ( ID, Name, Email, BirthDate );

  {...}

end;

 

Removendo uma pessoa

 

{...}

    PManager.RemovePeople ( PManager.Peoples [ Ind ]);

{...}

 

Editando uma pessoa

 

var

  Ind : Integer ;

  Pp : People;

  Value : String;

begin

  {...}

    Ind := Convert.ToInt32( Console.ReadLine );

    Pp := PManager.Peoples [ Ind ];

  {...}

    WriteLine ( '');

    WriteLine ( 'Type new value:');

    Value := Console.ReadLine ;

 

    case Ind of

      1 : Pp.Name := Value;

      2 : Pp.EMail := Value;

      3 : Pp.BirthDate := Convert.ToDateTime ( Console.ReadLine );

      else begin

        WriteLine ( 'Invalid option, exiting.');

        Exit;

      end ;

    end ;

  {...}

end;

 

Listando as pessoas

 

var

  Arr : ArrayList ;

  I : Integer;

begin

  Console.WriteLine ( '');

  Arr := PManager.AllPeoples ;

  for I := 0 to Arr.Count - 1 do

  begin

    with ( Arr [I] as People) do

    begin

      Console.WriteLine ( '[{0}] {1}', &Object(I), &Object( ToString ));

    end ;

  end ;

  Console.WriteLine (' ');

end;

 

Mostrando os resultados

 

Como podemos ver, todo o código é surpreendentemente simples. Vejamos agora   um pouco de nossa aplicação em execução:

 

Figura 1. Abertura do exemplo ObjectApp

 

Figura 2. Adicionando uma pessoa

 

Figura 3. Listando as pessoas cadastradas

 

Estando nosso aplicativo pronto nós podemos cadastrar, alterar e excluir pessoas a vontade, e o melhor, independente do que ocorra, seus dados estarão salvos. Realize essas operações várias vezes, solicite snapshot’s a avalie o resultado. Você pode fazer testes matando o processo ou mesmo desligando a máquina, verás que os dados serão mantidos e recuperados na próxima execução. Tudo isso sem usar um banco de dados!

 

Após realizar algumas operções , solicitar um snapshot e depois mais operações podemos ver que o XPrevail gerou os arquivos conforme mostrado na figura 4.

Figura 4. Arquivos de log de operações e arquivo de snapshot

 

Suporte a Programação Orientada a Aspectos – AOP

 

Neste artigo apenas introduzirei esse tema, mas ele certamente será abordado em maiores detalhes em artigos ou tutoriais posteriores.

 

Um dos excelentes recursos trazidos pelo XPrevail é o suporte a um programação baseada nos princípios da Programação Orientada a Aspectos – AOP. Esse suporte é dinâmico e extensível, o processo de criação de aspectos é simples e muito poderoso. Através dele podemos ter soluções elegantes para geração de logs , controle de concorrência, profiler , auditoria e etc.

 

A AOP promete preencher uma lacuna não resolvida pela POO, onde o exemplo mais clássico citado é a geração de log ’s. Na abordagem tradicional quando necessitamos gerar um log do fluxo de execução de nosso aplicativo acabamos sendo obrigados a espalhar código por várias classes. Código esse que não é o do propósito da classe.

 

A AOP entende que a geração de log ’s, assim como diversos outros problemas – incluindo a persistência, é aspecto do software e não deve se misturar com as regras de negócio. A implementação da AOP hoje ainda não é algo padronizado tal qual a POO, dessa forma, podemos encontrar várias formas de abordagens e filosofias de implementação desse conceito.

 

Vou mostrar agora apenas um pouquinho do potencial dessa maravilha e como você fazer uso dela através do XPrevail .

 

Utilizando o ProfilerAspect

 

Suponha que queiramos fazer um profiler de nossa aplicação para saber quanto tempo está demorando a execução de alguns métodos. Como você faria isso? Obviamente abriria o fonte de aplicação e começaria a distribuir códigos de medição, claro. Mas, vejamos como fazemos isso com o XPrevail . Para isso alteraremos apenas duas linhas de nosso aplicativo de teste, veja:

 

{...}

  Engine.RegisterAspect ( ProfilerAspect.Create (nil, false));

{...}

 

Essa linha registra um novo aspecto (esse já disponibilizado pelo XPrevail ) em nosso engine . Seu construtor pede dois parâmetros, o primeiro é uma stream para registro das medições – passando nil ele emitirá no console. O segundo parâmetro indica se ele deve atuar indiscriminadamente sobre todos os métodos dos PrevalentSystem ’s e objetos de negócios mantidos pelo Engine .

 

Como passamos false ele apenas atuará sobre os métodos marcados com o atributo MethodProfiler . Então, para testarmos, vamos colocar esse atributo no método PeopleManager.AllPeoples.

 

{...}

    [ MethodProfiler ]

    function AllPeoples : ArrayList ;

{...}

 

Pronto, feito isso basta re-compilar a aplicação e executarmos novamente. Veja na figura 5 o resultado.

 

Figura 5. ProfilerAspect em ação

 

Assustador? Não, eu diria empolgante. Certamente esse é um recurso muito poderoso. Como disse anteriormente, queria agora só deixar esse gostinho, haverá um outro artigo ou tutorial abordando em maiores detalhes o uso e desenvolvimento de aspectos com o XPrevail .


Atual estado do projeto XPrevail

 

Hoje o XPrevail está na versão 0.9.3 alpha , melhorias e refatorys estão sendo feito nele constantemente. Embora seja uma versão alpha ela já é completamente funcional. Visite a seção “ Roadmap ” dosite do projeto para conhecer em que direção ele vai ser conduzido.

 

Em linhas gerais, é possível que o XPrevail venha a suportar persistência em bancos de dados relacionais, de forma transparente. Recursos como replicação, suportes eficientes a transações e lock de objetos também estão previstos. O objetivo maior é que possamos, através do XPrevail , programar aplicações prevalentes, com aspectos, com tolerância à falhas e balanceamento de carga. Inclusive suporte a dualidade, seria um tipo de tolerância à falhas mesmo para aplicações statefull .

 

Ainda estou gradativamente incrementando a documentação das classes, artigos e tutoriais e testes de unidades. Qualquer ajuda nesse sentido, bem como com tradução para outros idiomas será apreciada. A divulgação do framework através de artigos, criação de exemplos e casos de estudo serão muito bem vindas .

 

Conclusão

 

Simples não? Fora o modelo de objeto, você viu muito código referente a persistência em nossa aplicação? Realmente não. Consegue calcular quanto tempo já gastou codificando SQL dentro de suas classes L ? Mas para mim, o mais legal é a sensação de que a persistência não existe, que estamos livremente trabalhando com objetos, sem nos preocuparmos com seu estado, pois eles prevalecerão.

Não deixem de visitar o site do projeto http://xprevail.sourceforge.net/ e comece já a programar aplicações prevalentes.

Versão 1.0 – 23/10/2004

 

 

FernandoVM é Borland Delphi Certified, palestrante de todas as edições da BorCon . Já atuou como articulista, colunista e editor técnico da revista ClubeDelphi . É gerente de tecnologia, arquiteto e coordenador da equipe de desenvolvimento do produto Tactium, uma solução real-time distribuída de CTI/CRM utilizada por mais de 90 empresas, ao longo de 20 estados brasileiros, na Softium Informática. Criador e mantenedor do projeto XPrevail , Pode ser contactado em fernandovm@users.sourceforge.net ou em http://fernandovm.blogspot.com .