Composição de Entities em Módulos de Sistema

Seguinte pessoal.
Pintou uma duvida aqui e gostaria de saber se algume já passou por isso.
Imagine que vc tem um sistema dividido em modulos e a implantação desses módulos é independente, ou seja, vc pode ter o modulo A junto do módulo B ou não.
Explicando melhor: imagine que vc tem um sistema de cadastro de pessoas, um sistema de pedidos e um sistema de controle de estoque… A sua entidade (POJO ou coisas do tipo) Pessoa tem aspectos de Cadastro e de Pedido, já a sua entidade Produto tem aspectos de Pedido e Estoque… ‘Codificando’ o exemplo…

[code]public class Pessoa{
//Dados referentes ao cadastro
private String nome;
private Documento documento;

//Dados referente a venda
private Set<Pedido> pedidos;

}

public class Pedido{
private long id;
private Date dataCompra;
private Status status;
private List detalhes;
private Pessoa cliente;
private Pessoa vendedor;
}

public class DetalhePedido{
private Produto produto;
private int qtd;
private BigDecimal valorVenda;
private BigDecimal desconto
}

public class Produto {
//Dados do produto
private String nome;
private String descricao;

//Dados referente a compra e fornecimento
private Set<Pedido> pedidosCompra;
private Set<Pessoa> fornecedores;

//Dados referente as vendas
private Set<Pedido> pedidosVenda;

}[/code]

A pergunta é: como fazer para que as entidades sejam independentes do modulo do sistema?!? Como eu implanto o módulo de cadastro sem implantar o módulo de Pedidos, por exemplo? Se fosse o caso de decompor os objetos, como fazer com que a entidade Pessoa possa compor uma PessoaPedido e uma PessoaCadastro, por exemplo, para atender ao módulo de pedido e o de cadastro respectivamente?!?

[quote=rodrigoallemand]
A pergunta é: como fazer para que as entidades sejam independentes do modulo do sistema?!? Como eu implanto o módulo de cadastro sem implantar o módulo de Pedidos, por exemplo? Se fosse o caso de decompor os objetos, como fazer com que a entidade Pessoa possa compor uma PessoaPedido e uma PessoaCadastro, por exemplo, para atender ao módulo de pedido e o de cadastro respectivamente?!?[/quote]

Essa pergunta é realmente muito importante. Também tenho pensado sobre isso nos ultimos tempos.
A resposta que encontrei até agora foi: não é possivel sem usar o padrão proxy.

A ideia é que cada modulo coloca/retira responsabilidades das entidades. Ou (1) elas já contêm todas as responsabilidades ou (2) as responsabilidades são incluidas conforme o modulo está disponivel.

A opção 1 é a mais simples. O objeto contém todos os métodos e atributos necessários a todos os modulos.
Cada modulo usa os que lhe interessam. Isto é a ideia de um modulo core onde as entidades são difinidas e modulos satélite que trabalham essas entidades.

A opção 2 é mais complexa
Cria-se uma interface para cada modulo e entidade. Ai Pessoa seria uma interface e não uma classe. PessoaPedido , PessoaRH, etc… seriam interfaces que extendam a interface padrão (digamos apenas com getNome ). No Repositorio de cada modulo é declarada a interface desse modulo. Por exemplo, o modulo de RH tem um PessoaReposiotorioRH que trabalha com PessoaRH. Assim cada modulo trabalha apenas com o que conhece.
Por detrás do repositorio existe um mecanismo de proxy. Em java isto é meio complexo se vc quiser incluir logicas no seus objetos além de get/set directo com atributos, já que a injeção de métodos é limitada. Em outras linguagens pode ser mais simples… A ideia é que a classe PessoaImpl não existe. O que existe é um proxy que conforme a interface pedida constroi e recupera dados diferentes.

Em termos de mapeamento a coisa tb não é mais simples, mas é possivel ter um banco com várias tabelas pessoasXXX que se realcionam à tabela pessoa (id , nome). O Repositorio teria que inteligentemente fazer os selects/updates nas tabelas certas conforme a(s) interface(s) implementadas pelo objeto.

Bem, Sergio, a primeira opção eu já tenho, e funcionando… dai surgiu o problema. Os modulos ‘primários’ precisam estar livres desta composição, no meu exemplo, eu posso ter o Cadastro sem ter o Pedidos, mas eu não posso ter o Pedidos sem o Cadastro, sacou? Por isso surge a necessidade de decomposição.

Inicialmente irei fazer da seguinte maneira, usando Composite pra tentar chegar onde eu quero, por exemplo:

[code]/** Esta entidade NÃO terá um mapeamento ORM

  • A camada de serviço ficará responsavel por injetar
  • as outras entidades dentro dela.
  • Caso, por exemplo, não esteja disponivel o módulo
  • de Pedidos, pessoaPedido == null
    */
    public class Pessoa{
    private PessoaCadastro pessoaCadastro;
    private PessoaPedido pessoaPedido;
    }

/** Esta entidade terá um mapeamento ORM */
public class PessoaCadastro{
private String nome;
private Documento documento;
//Etc
}

/** Esta entidade terá um mapeamento ORM */
public class PessoaPedido{
private Set pedidosCompra;
//Etc
}[/code]

Não sei se é a melhor maneira mas, até o momento, é a unica saída.

Uma outra ideia seria utilizar façades

 public class Pessoa{  
     //Dados referentes ao cadastro  
     private String nome;  
     private Documento documento;  
   
     //Dados referente a venda  
     private Set<Pedido> pedidos;  
 }  

vira

 public class Pessoa{  

    PessoaRepositorio pessoaRep;

     //Dados referentes ao cadastro  
     private String nome;  
     private Documento documento;  
   
     //Dados referente a venda  
     public Set<Pedido> getPedidos(){
         return pessoaRep.pedidosPara(this);
     }  
 }  

 public PessoaRepositorio {

        ModuloPedidos mpedidos;
        public Set<Pedido> getPedidos(Pessoa p){
              return      mpedidos.getPedidos(Pessoa p);
        }
 }

ModuloPedidos é uma interface que atua como façade do modulo.
Se o modulo está instalado é injetada a implementação correta e o método trás o que deveria.
Se o modulo não está instalado é injetada uma implementação “vazia” (padrão Special Case) que não executa nenhuma logica retornando coleções vazias.

O sistema funciona da mesma forma, sem proxies e apenas mudando as implementações dos modulo especificos.

Boa saida, mas um pouco poluida para ‘produtos de prateleira’.
Um item que eu esqueci de mensionar (esqueci não, não era necessário at´pe o momento) é que o produto é uma ‘ERP’, com 15 modulos…
Quando vc (leia-se eu) desenvolve um sistema com muitas conexões intra-modulos e ao mesmo tempo quer que os módulos sejam independentes, vc tem que utilizar uma arquitetura bastante linear, visando a melhor adaptação quando se chega no cliente. Já imagonou vc sair colocando um montão de dependencia entre as suas ‘micro-camadas’ (dentro do dominio, por exemplo, temos outras camadas, rs)? No fim de tudo vc vai se perder ou perder muito tempo na customização para um cliente…
Com isso eu não posso colocar um objeto de um módulo dentro de outro módulo. Eu tenho, neste caso que criar os módulos separados e criar uma implementação de referencia ou um adaptador entre os módulos…
Já imaginou se o cliente tem a base de clientes dele na alta-plataforma?!? Como eu faria pro meu modelo de ORM ler esses dados?!? Por isso tudo tem que ser bastante dividido, linear e independente…

Mas essa sua ideia, tambem, é bem parecida com o que eu coloquei acima… separar os módulos e agrega-los novamente em uma outra classe…

P.S.: Hoje, pela primeira vez eu senti falta de uma herança multipla…

Não entendi o que quer dizer com isto.
Se o modulo A depende de B não ha linearidade. A não ser que vc use o modelo estrela (modulo core + satelites) não ha forma linear de tratar o problema.
Tb não entendi qual o problema de utilizar ModuloPedido como um façade e o que isso tem a haver com linearidade. (afinal, o que seria essa linearidade ?)

Não vejo porquê. Se o modulo é auto-contido e apenas executa serviços em outros modulos não vejo onde haja “poluição”… bom, a menos que o seu “modulo” não seja auto contido (ou seja, não seja um modulo realmente).
Vc tem um objeto modulo ?

[quote]
Com isso eu não posso colocar um objeto de um módulo dentro de outro módulo. Eu tenho, neste caso que criar os módulos separados e criar uma implementação de referencia ou um adaptador entre os módulos…
Já imaginou se o cliente tem a base de clientes dele na alta-plataforma?!? Como eu faria pro meu modelo de ORM ler esses dados?!? Por isso tudo tem que ser bastante dividido, linear e independente…
Mas essa sua ideia, tambem, é bem parecida com o que eu coloquei acima… separar os módulos e agrega-los novamente em uma outra classe…

P.S.: Hoje, pela primeira vez eu senti falta de uma herança multipla…

Isso é feito com interfaces. Isso é a estratégia 2
O que tem ORM a haver com o problema ? Simplesmente faça um mapper melhor/especial , não ? Vc não domina a estrutura do banco ?

Vc deveria partir do principio que seus modulos são todos deconnexos ( sem coisas em comum)
que comunicam entre si via interfaces e serviços - nunca pelo banco. Um modulo não pode manipular dados de outro , se o fizer ha uma dependencia entre os modulos e portanto é licito dizer que eles não são independentes e o sistema não é “linear”. Para desacoplar os modulos existem diversos truques. Temos o façade, mas tb temos um sistema de eventos. O detalhe é que os dados dentro de um evento emitido pelo modulo A tem que ser intrepretados conforme as interfaces do modulo B. Isso necessita de proxies e adaptadores e precisa de um “container” que faz a comunicação inter-modulo. (ou seja, encapsula e cria os proxies e adaptadores)
Exemplo: o modulo de vendas lança uma venda. Isso gera um evento com objeto venda dentro dele. O modulo financeiro ouve esse evento e produz informações dentro dele que por sua vez geram eventos… o modulo financeiro sabe tratar vendas , logo a interface/classe Venda tem que ser compatilhada entre o modulo vendas e o financeiro. Se o financeiro precisa de alguma informação extra ele deve buscar isso dentro do modulo , ou seja, fazer uma consulta a tabelas que fazem referencia à venda mas têm outros campos. Assim a tabela de vendas e a tabela de vendadofinanciero são separadas fisicamente mas conectadas logicamente.
Vc pode ter um VendaFinanceiro que encapsula Venda, mas isso não é prático.

Num ERP não é possivel ter modulos completamente desacoplados. uns modulos processam os dados de outros.
A única forma de descrever essas dependencias é utilizar eventos e façades. E concerteza não é linear. ( se bem que eu não sei o que vc quiz dizer com linearidade)

Linearidade, aqui, seria uma maneira unica para a execução de funcionalidades no sistema, independente do módulo, salvo exceções de especialidades, como gerar uma venda, extornar um faturamento, incluir regras declarativas de pagamento, etc…
Bem explicando melhor… se eu começar a especializar cada entidade que é ‘multi-modulo’, a manutenção e a customização vai ser mais problematica, por experiência própria… Bem, é o que eu acho e o que eu procuro fazer… prefiro perder um pouco em uma arquitetura menos robusta em troca de facilidade de manutenção…

OK, como eu falei no segundo post… porem isso é mais tempo de desenvolvimento e na manutenção… mas disso eu não consiguirei sair…

Sim e não… eu tenho o meu banco de dados… mas e se o cliente quizer algo especializado, como por exemplo, no cadastro de pessoas eu devo colocar um campo de Data Aniversário Amante?!? Quantos artefatos eu devo alterar?!? Hj em dia, apenas um, o XML de mapeamento… O banco é uma proposta minha… na customização o cliente pode pedir uma alteração, ou até mesmo que eu utilize um banco que ele já tem…

A conexão dos módulos é um caso a parte… isso eu resolvo usando REST próprio… Eu queria focar no problema do dominio… se meu dominio está OK e eu trabalho com orquestração de dominio, o resto tb estará OK…

è justamente ai que vem o pulo-do-gato… Fazer a aplicação monobloco é facil… ganhar na customização que é o dificil… minha ideia é tentar fazer essa customização menos traumática…

[quote=rodrigoallemand][quote=sergiotaborda]
Se o modulo A depende de B não ha linearidade.
[/quote]
Linearidade, aqui, seria uma maneira unica para a execução de funcionalidades no sistema, independente do módulo, salvo exceções de especialidades, como gerar uma venda, extornar um faturamento, incluir regras declarativas de pagamento, etc…
Bem explicando melhor… se eu começar a especializar cada entidade que é ‘multi-modulo’, a manutenção e a customização vai ser mais problematica, por experiência própria… Bem, é o que eu acho e o que eu procuro fazer… prefiro perder um pouco em uma arquitetura menos robusta em troca de facilidade de manutenção…
[/quote]

Existem duas frentes para o seu sistema ser extensivel: alterar o processo ; alterar os dados.
No caso de processo (execução de funcionalidade) vc consegue com um serviço . Uma classe bem definida que contenhasas regras padrão e possa ser sobre-escrita pelo cliente. Normalmente isso é feito via script , certo ? No caso o script herdaria a classe para a extender alterando os métodos padrão. Tlv não todos os métodos apenas alguns (cut-points). Outras ideia é utilizar event-driven para que o processo seja na realidade uma sucessão de eventos. alterando o handler do evento, altera-se o processo. (isto é mais ou menos o que se usa em BPM) O handler neste caso seguiria o mesmo padrão de sobre-escrita como se fosse um serviço.

Do lado dos dados existe o conceito de dicioniário de dados. Isto significa básicamente que existem dados pre-definidos no sistema e dados que o cliente pode acrescentar. Mas ambos são definidos da mesma forma: metadados. Isto influencia directamente a forma como se trabalha com os dados. Interfaces podem ser utilizadas para isto com implementações automáticas via proxies. Ou seja, a entidade como um todos tem 200 campos , mas cada interface só lê alguns deles. O sistema pode fazer um select especifico e utilizar um objeto do tipo Map para conter o valores. Esta tecnica funciona, mas as entidades ficam sendo TO apenas.
Quando precisar de novos campos vc edita o dicionário.

O ORM tem que ser controlado dinamicamente pela aplicação. O mecanismo usa o dicionário para definir as tabelas editando os metadados do banco conforme os metadados do dicionário. Ou seja, o sistema cria o banco.
O ORM tem que ser encapsulado para que , caso necessário, possa ser feito manualmente. Ou seja, programado de forma diferente para interagir com bancos que já existem, por exemplo.

A primeira ideia é alterar a propria entidade Pessoa. Isso implica em refazer codigo ou utilizar um dicionário de dados. A alternativa é simplesmente utilizar OO. Herda a classe Pessoa e escreve outra. A utilização de instropeção pode facilitar a re-escrita do dicionário que levaria à rescrita dos metadados do banco. Ou seja, adicione o campo, o sistema faz o resto.

Mas vc não tem um dominio unico. Cada modulo tem o seu dominio. Apenas algums partes desses dominios se sobrepõem. quando eu falo em desconexão me refiro a conexão logica. Seja com rest ou sem existe uma necessidade de conhecer os dados e métodos disponiveis no outro modulo. É esse conhecimento que cria a conexão.

[quote]

è justamente ai que vem o pulo-do-gato… Fazer a aplicação monobloco é facil… ganhar na customização que é o dificil… minha ideia é tentar fazer essa customização menos traumática… [/quote]

hum… é complicado isso… o ideal e´vc ter um bom modelo OO da sua aplicação onde as peças importantes sejam amoviveis. Desta forma quando uma tiver que ser alterada ela possa ser. Não tem como vislumbrar todas as alternativas de customização à priori, então a solução é não o fazer. Assumir que tudo pode ser alterado e prover mecanismo para o fazer. Em OO isso é simplificado. Vc so precisa substuir implementações. Dai a necessidade do padrão Façade ( ou se quiser Interface+Implementação). O seu sistema é a orquestação de interfaces. A customização é alteração da implementação base dessas interfaces.

Parece-me que o seu problema é na definição de uma estrutura de dados que seja utilizável por todos os modulos. e mais que isso, permitir que essa estrutura aumente em quantidade de campos e relações.
Isso tem um custo. O seu sistema tem que ser mais abstracto que o normal e tem que forçar regras abstractas.
Mas parece-me que esse custo vc não quer pagar… ainda não descobri como resolver esse problema sem utilizar algum tipo de mecanismo “esoterico” ou abdicar de alguma coisa (por exemplo, abdicar de entidades ricas em deterimento de TO)…