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:
        
      
        
      
        
      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
      [
                  
      {...}
        
      
        
      Editando uma pessoa
          
      
        
      var
        
      
       
      Ind :
      Integer
      ;
        
      
       
      
      
      
      Pp :
      
      
      People;
        
      
       
      
      Value :
      String;
        
      
      begin
      
      
      
        
      
       
      {...}
        
      
         
      
      
      
      
         
      
      Pp :=
      
      PManager.Peoples
      [
      
      
      
       
      {...}
        
      
         
      
      
      WriteLine
      
      
      (
      '');
        
      
         
      
      
      WriteLine
      
      
      (
      'Type new value:');
        
      
         
      
      Value :=
      
      Console.ReadLine
      ;
        
      
        
      
         
      
      case
      
      
      
      
           
      
      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
          
        .