Resumo DAL - Usar interface com classe interna?

8

Temos uma camada de lógica de negócios (BLL) fortemente acoplada à nossa camada de acesso a dados (DAL). Fazemos chamadas assim:

using (FooData data = new FooData())
{
  data.DoSomething();
}

É importante observar que todas as nossas classes de dados estão internale estão no mesmo assembly que as classes lógicas, para que apenas o BLL possa acessar o DAL.

Para dissociá-los (para ajudar a facilitar o teste de unidade), uma idéia é criar interfaces IDataClass, como o IFooData. No começo, pensei que poderia ser um problema, porque teríamos que tornar nossas classes de dados públicas para implementar as interfaces. Mas devemos ser capazes de manter as classes de dados internas, mesmo que ainda precisemos que os métodos sejam públicos:

public interface IFooData
{
  void DoSomething();
}

internal class FooData : IFooData  // Notice the class is internal
{
  public void DoSomething();  // Method is public, but that's ok because class is internal
}

Portanto, mesmo que o método seja público, uma vez que a própria classe é interna, ainda devemos permitir apenas o acesso à BLL.

Existe algo inerentemente errado com essa abordagem? Existe uma maneira melhor de abstrair o DAL, para testes de unidade, sem abrir o DAL para o mundo tornando-o público?

Bob Horn
fonte
1
O que você está tentando alcançar mantendo seu DAL bloqueado assim? Por que manter em segredo? Ele expõe vários métodos, não deve se importar exatamente com quem os está chamando. Se você tiver um problema com a chamada do local errado, terá um problema de revisão de código.
slugster 19/08
Ao tornar os métodos internos, apenas o BLL pode acessá-lo, o que força todos os desenvolvedores a passar pelo BLL. Quando você tem uma grande equipe de desenvolvedores, tudo o que você pode fazer para ajudar a minimizar erros é uma coisa boa.
Bob Horn
Percebo que você está tentando fazer uma certa manutenção dos desenvolvedores que usam o código, mas, ao fazer isso, você criou outro problema. Foi por isso que fiz meu comentário - não há nada errado em ter os métodos públicos (é uma prática normal). Se as pessoas estiverem usando-as da maneira errada, você terá um problema de revisão de código.
slugster
Discordo. Por que ter modificadores internos e privados? Por que não tornar tudo público?
Bob Horn
Bob, você perdeu totalmente o objetivo. O DAL expõe coisas públicas por meio de um CONTRATO, que é sua interface. A prática padrão de OO significa que ela não sabe quem está chamando. Vamos dizer mais uma vez: você pode tornar a classe interna, mas não precisa . O resto do mundo consegue conviver com essa abordagem, por que não você? Você também deu um tiro no pé no momento em que tem um BL ou serviço diferente que precisa chamar o mesmo DAL - você continuará adicionando assembléias de amigos?
slugster

Respostas:

13

Extrair uma interface e garantir que a BLL esteja usando apenas tipos de interface é um bom caminho a seguir para tornar a BLL testável sem o banco de dados.

O que você está fazendo está absolutamente bem.

Oded
fonte
3
Vou acrescentar que o que você está fazendo é bom, mas é apenas o primeiro passo. Se o que você está fazendo agora está using (IFooData data = new FooData())no seu BLL, você realmente não fez nenhuma alteração, exceto pela introdução da interface. Agora você terá que encontrar uma maneira de instanciar IFooDataexternamente, caso contrário, seus testes de BLL ainda serão acoplados ao DAL.
Avner Shahar-Kashtan
Acordado. Na verdade, estou fazendo algo parecido com isso agora:DataAccessFactory.GetDataInterface<IFooData>().DoSomething();
Bob Horn
1

Você pode usar o InternalsVisibleToAttributepara separar seu DAL da camada de negócios, mas ainda assim manter os métodos DAL internos. Você acabará criando seu DAL como um assembly de amigo .

Essa pode não ser uma ótima abordagem, pois você precisaria especificar no Assembly.csarquivo do seu DAL quais assemblies podem acessar o DAL. Portanto, ainda há algum acoplamento envolvido (DAL sabendo sobre BLL).

Portanto, para responder sua pergunta, não há nada de errado com sua abordagem. Porém, tirar proveito dos assemblies de amigos pode fornecer um pouco mais de abstração e provavelmente ajudá-lo a tornar seu código mais testável.

Eu espero que isso ajude.

David Hoerster
fonte
Eu realmente não preciso remover o DAL do BLL; Eu só preciso implementar uma interface.
Bob Horn
A propósito, obrigado. Estou familiarizado e InternalsVisibleTo, se eu precisar mover o DAL para outra montagem, isso realmente ajudaria.
Bob Horn
@ BobHorn, então eu não entendo. Qual é o problema de fazer suas aulas de dal como internas? Você pode até fazer suas interfaces DAL como internas. Não vejo problemas aqui.
Marcelo De Zen
Ter as classes DAL internas é o que temos atualmente e o que queremos que daqui para frente. As interfaces precisarão ser públicas para que o BLL possa solicitar uma fábrica para uma implementação concreta e não se importar se é o verdadeiro DAL ou uma farsa. Acho que toda a minha pergunta é realmente uma verificação de sanidade. Estou perdendo uma maneira melhor de fazer isso?
Bob Horn
1

Você parece imóvel em suas idéias que expôs em sua pergunta, mas eu proponho uma resposta de qualquer maneira - alguém pode achar útil em algum momento no futuro.

Se você insistir em manter seu DAL interno, mas ainda desejar atingi-lo com alguns testes de unidade e não se importar de usar as ferramentas de Teste de Unidade da Microsoft, tente a abordagem PrivateObject . Esse é um invólucro para reflexão que você sempre pode codificar a si mesmo, mas economiza algumas linhas de digitação.

Observe que o uso de InternalsVisibleTo é uma abordagem viável, mas é desajeitada - se você a estiver usando, poderá já estar em uma descida rápida ladeira abaixo. internalsignifica que algo é público apenas dentro dos limites de sua montagem; esse modificador é normalmente usado porque você não deseja itens utilizáveis ​​de foranessa montagem, você imediatamente se vira e viola esse conceito declarando InternalsVisibleTo ... que é uma grande bandeira vermelha suja que está clamando por alguma refatoração. A dissociação é um desperdício de tempo quando apenas uma montagem está chamando a outra, você também pode colá-las. A dissociação deduz que vários assemblies estão chamando o destino (a introdução do teste de unidade não conta para o 'múltiplo' porque existem maneiras de chegar ao assembly de destino, como eu já mencionei).

slugster
fonte
Por que pareço imóvel em minhas idéias? Estou disposto a concordar com você; Eu só preciso de uma discussão para me convencer primeiro. E não me diga que viole o conceito usando InternalsVisibleTo. Eu não estou usando isso. Por alguma razão, você está assumindo que estou usando. Eu não entendo o porquê.
Bob Horn
A propósito, agradeço a sua opinião, porque está me fazendo reconsiderar a minha. Lembre-se, porém, também tenho a minha opinião. Não há necessidade de se irritar, porque eu não concordo imediatamente com você.
Bob Horn
@ Bob, desculpe, eu fiquei viciado nesse ângulo em particular, vejo no seu comentário 'e se eu precisar mover o DAL para outra montagem', é provável que o seu DAL esteja exatamente onde eu sugeriria que fosse para um item interno. Quando você decidir o que fazer, certifique-se de escrevê-lo aqui (se nenhuma resposta for adequada), será interessante ver o que você acaba criando.
slugster
1

Tecnicamente, não há nada de errado com seu design.

No entanto, eu consideraria uma abordagem alternativa: em vez de dissociar sua BLL do seu DAL, desacople-o melhor do seu banco de dados. Permita a criação de objetos DAL na memória e, se sua BLL precisar carregar objetos DAL de algum lugar, use o padrão de repositório (veja aqui ) para evitar o contato direto da BLL com o banco de dados. Dessa forma, você pode

  • crie testes de unidade para seus objetos DAL facilmente, sem a necessidade de um banco de dados
  • crie testes de unidade para sua BLL fornecendo objetos DAL criados na memória através de um repositório simulado como dados de teste (ok, você pode argumentar agora se esses testes devem realmente ser chamados de testes de unidade )

De fato, o que você perde é a capacidade de testar o BLL com zombarias DAL. Mas, na realidade, esses objetos simulados do DAL geralmente se parecem muito com os objetos reais do DAL para fornecer uma base para testes úteis da BLL. IMHO evita muita duplicação de código e esforço desnecessário ao reutilizar seus objetos DAL reais para testes automatizados da BLL.

Doc Brown
fonte
0

A abordagem de interface é boa / mainstream para zombar do seu DAL durante o teste de consumidores como o BLL.

No entanto, uma coisa a ser observada é que, ao tornar suas classes de concreto DAL internas, você pode tornar seu DAL de concreto mais difícil de testar diretamente, pois isso agora implica que seus testes de unidade de DAL também devem estar nesta montagem sem a necessidade de usar portas traseiras como reflexão.

Além disso, em algum momento no futuro, você pode considerar o uso de um contêiner de IoC para construir a implementação por trás de uma interface, que também pode desarmar o interno.

Você pode imitar o encapsulamento que está tentando alcançar com 'apenas interno' adicionando uma regra de convenção / LINT que sua BLL / outras camadas devem acoplar ao DAL por meio da interface, não na implementação concreta.

StuartLC
fonte
Obrigado, mas os testes de unidade do Visual Studio podem realmente testar métodos internos e privados em outros assemblies.
Bob Horn