Como reduzir o acoplamento rígido entre duas fontes de dados

10

Estou com problemas para encontrar uma solução adequada para o seguinte problema de arquitetura.

Em nossa configuração (esboçada abaixo) , temos 2 fontes de dados, em que a fonte de dados A é a fonte primária de itens do tipo Foo. Existe uma fonte de dados secundária que pode ser usada para recuperar informações adicionais em um Foo; no entanto, essas informações nem sempre existem.

Além disso, a fonte de dados A pode ser usada para recuperar itens do tipo Bar. No entanto, cada barra refere-se a um Foo. A dificuldade aqui é que cada Bar deve se referir a um Foo que, se disponível, também contém as informações aumentadas pela fonte de dados B.

Minha pergunta é: como remover o acoplamento rígido entre SubsystemA.1 e DataSourceB?

http://i.stack.imgur.com/Xi4aA.png

fstuijt
fonte
10
Esse é um desenho bonito. Qual programa você usou para desenhá-lo?
Marcelo MD
Eu também quero saber qual programa você usou para desenhá-lo. Por favor.
Tulains Córdova
2
yuml.me é o site que ele usou com mais probabilidade de criar o diagrama.
Jason Turner
11
Não estão DataSourceAe DataSourceBjá estão dissociados? DataSourceAtem uma dependência de ambos SubSystemA.1e SubSystemA.2, mas não de DataSourceB.
Tulains Córdova
11
@fstuijt Não, não é. Se você modificar SubsystemA.1para usar algo diferente DataSourceB, DataSourceAnão saberia. DataSourceAsó se importa que SubsystemA.1tem um getFoo(id)método. Há uma abstração entre DataSourceAe DataSourceB.
Tulains Córdova

Respostas:

3

Criei um aplicativo com a mesma arquitetura de dados por trás dele; temos um banco de dados SQL no local que contém a maioria das informações internas do dia-a-dia da automação e, em seguida, um serviço de nuvem de terceiros usado para vendas, gerenciamento de contas, equipe de campo, etc. e equipamento, e o obtive de duas aplicações diferentes até eu entrar.

O longo e o curto é que uma fonte de dados precisa ter uma referência aos registros da outra. No nosso caso, os dados na nuvem de terceiros contêm referências aos dados no local, porque esse é o arranjo sobre o qual tivemos mais controle. Agora, com um ID para um registro de qualquer uma das fontes de dados, podemos obter dados de ambas; com um ID da nuvem, extraímos o registro da nuvem, obtemos o ID no local e extraímos os dados no local. Com um ID no local, pesquisamos as duas fontes de dados com base nesse ID.

No meu sistema, não tornei nenhum objeto filho do outro na camada de domínio; qualquer uso dos dados de ambos os armazenamentos deve manter duas instâncias de objeto. Nenhum deles é garantido que existe, e é por isso que eu fiz dessa maneira; o aplicativo pode funcionar apenas com dados em nuvem, ou com dados no local, ou ambos, com mais limitações quanto menos dados tiver.

No entanto, isso não é difícil de mudar, especialmente se você tiver certeza de que um lado sempre existirá; basta incluir uma propriedade no objeto que representa o lado para o qual os dados sempre existirão, ou seja, do tipo de objeto que representa o registro do outro repositório de dados. É possível uma "fusão" mais avançada dos dois gráficos em um.

Esse tipo de arranjo deve necessariamente ser associado em algum nível. Você pode ter um DAL que possa interagir com os dois armazenamentos de dados ou segmentar os DALs, um por armazenamento de dados, e ter uma camada superior, como um Controlador, obter os dados de cada um e juntá-los. Mas, em algum nível, seu programa precisa ter inteligência para reunir os dados dessas duas fontes de dados diferentes.

Você pode reduzir o acoplamento necessário na maioria dos casos, abstraindo os detalhes exatamente de onde os dados vêm. Se você obtiver dados de um serviço da Web, que é fornecido como instâncias de classes geradas, coloque um conversor para fazer uma cópia profunda da classe de serviço em algo que você controla, que não precisará ser alterado se os dados origem sim (apenas se o esquema sim).

Agora, isso pode ser um grande empreendimento; a nuvem que usamos possui dezenas de classes de domínio, algumas das quais com centenas de campos de dados e - aqui está o kicker - você pode facilmente fazer grandes alterações no tipo de dados abstratos para acomodar uma mudança para uma nuvem diferente ou outro controle remoto fonte de dados. Por esse motivo, eu não me incomodei; Uso o domínio de serviço da web gerado diretamente e agora que uma mudança da nuvem para um armazenamento de dados externo (mas sob nosso controle) está se aproximando, cujos detalhes ainda não sei, estou simplesmente planejando alterar os formulários e codebehinds do aplicativo, que é onde os dados são "combinados", para refletir o novo esquema e / ou objetos de dados. É um grande trabalho, seja qual for o modo como você o corta.

KeithS
fonte
Esta resposta cobre melhor o problema que encontrei e, na minha opinião, também oferece a melhor resposta até agora. No entanto, eu acho que combinar dados de várias fontes é um problema comum. Algum padrão de design que possa ajudar?
fstuijt 16/11/12
11
Alguma variação em um padrão de fábrica pode ser útil. Se você possui um objeto CloudInvoice e SqlInvoice (de suas respectivas fontes de dados) e deseja criar uma única fatura unificada, crie um Factory que conheça o suficiente sobre as duas fontes de dados para recuperar cada metade do registro que está prestes a criar e, em seguida, mescla as informações em sua classe de domínio.
Keiths
4

Uma maneira de lidar com isso é criar uma fonte de dados agregada que contenha os dados das duas fontes de dados em um único local. Um trabalho seria executado periodicamente para verificar as alterações nas fontes Ae B, e escrever os "deltas" em sua fonte de dados agregados. Isso converteria duas fontes de dados fortemente acopladas em uma única fonte de dados coerente.

Várias coisas podem impedir você de seguir essa abordagem:

  • A quantidade de dados pode ser proibitiva - é necessário fazer uma cópia completa Ae Bduplicar os requisitos de espaço.
  • Os dados devem estar ativos - haverá períodos entre o momento em que os dados na fonte foram alterados e o trabalho agregado os propagou para a fonte agregada.
  • Você precisa reconciliar os dados com as fontes originais - A tarefa de mover as alterações de volta para seus locais originais se torna muito mais complexa se você adotar essa abordagem.
dasblinkenlight
fonte
I concordam, a introdução de uma camada de abstracção é a abordagem preferida
neontapir
2
Você pode ter uma camada de abstração sem copiar os dados.
smp7d
@ smp7d Isso ocultaria o acoplamento atrás de um bom front end; Eu assumi que você já estava fazendo algo assim no seu sistema, porque, caso contrário, a complexidade seria espalhada por todo o design.
dasblinkenlight
Dependendo do ambiente do banco de dados, isso também pode ser tratado com uma / mais visualizações, eliminando a necessidade de copiar dados.
Walter
Não estão DataSourceAe DataSourceBjá estão dissociados? DataSourceAtem uma dependência de ambos SubSystemA.1e SubSystemA.2, mas não de DataSourceB.
Tulains Córdova
1

Parece que no nível superior existem dois tipos: Foo e Bar, e você tem apenas duas ações de nível superior: findFoo(...)e findBar(...). Essa é a interface para a camada de E / S.

Sua descrição das fontes de dados implica que existem dois métodos em A: findFooe findBare um método em B: findFooAuxiliaryInformation. Em findFoovocê precisará mesclar as informações de A e B.

Não sei ao que "acoplamento apertado" você está se referindo. Existem três tipos de dados contidos nos dois conjuntos de dados: Bar, Foo, e FooAuxData. O acoplamento entre Fooe FooAuxDataé inerente aos dados de entrada e não pode ser reduzido. Mas esse acoplamento deve aparecer apenas no findFoométodo. Isso é o melhor que você pode fazer. O requisito é implementado em um único local. Se isso mudar, você precisará alterar esse código.

Kevin Cline
fonte
0

Você não pode.

Se bem entendi, Fooe Barvenho dsA. Bars pertencem a Foos.
De preferência, você não deseja que Bars seja atribuído a Foos, a menos que Footenha sido complementado por Foo.enhancedInfoisso dsB.

Sua preferência por atribuir Bars a Foos é o que está criando seu acoplamento rígido. Eu qualificaria isso como um "desafio de requisitos", que está forçando você a seguir um caminho específico.

Portanto, os desafios técnicos são que dsBpodem ou não ter informações sobre um dado Fooe que dsBpodem nem estar disponíveis.

Você precisa decidir o quão difícil e rápido essa preferência Foo.enhancedInforealmente é. Com base nesse requisito, você pode optar por fornecer um objeto Foo+ Barou não. Permitir que um não aprimorado Fooseja fornecido apenas complica a lógica e me diz que a preferência não é tão rigorosa quanto pode parecer. Determine quais variantes de Foo, Foo.enhancede Barseus aplicativos podem oferecer suporte e você terá sua resposta final.

Há outras coisas que você pode fazer para aproximar as Fooinformações relacionadas e que podem resolver alguns desses problemas. Da maneira como sua pergunta é formulada, parece que você está lidando com o problema no nível do objeto de dados e talvez não consiga considerar alterações no tipo de infraestrutura.


fonte
Por outro lado: Foo s pertence a Bar s
fstuijt 16/11/12
@fstuijt Vou atualizar minha resposta daqui a pouco. Fundamentalmente, permanecerá o mesmo. Você precisa decidir como deseja configurar o Bar + Foo's.
0

Se os dados na fonte de dados B não puderem ser independentes, você provavelmente desejará migrá-los para a fonte de dados A, se possível.

Se eles são independentes, mas relacionados, você deve procurar a virtualização de dados . Isso permitirá que os aplicativos tratem os dados como um conjunto (quando apropriado) de maneira independente. Dependendo da sua plataforma, provavelmente haverá uma estrutura / biblioteca existente que pode ajudá-lo a implementar isso.

smp7d
fonte