Qual a forma correta de implementar a camada de serviço

131 views
Skip to first unread message

Riderman Sousa

unread,
Jun 5, 2013, 9:28:33 AM6/5/13
to dotnetar...@googlegroups.com

Tenho três perguntas sobre como implementar uma camada de serviço. Para exemplificar vou utilizar a classe abaixo:

public class ProcessoService  // Qual a necessidade de se ter uma interface para abstrair a camada de serviço?
{
    private readonly Processo _processo;  // É correto ter um objeto de domínio como dependência para um serviço?

    private readonly IRepository<Processo> _repositorio;
    private readonly IRepository<ProcessoTipoDocumento> _tipoDocumentoRepository;

    private readonly IMappingEngine _mapperEngine;

    public ProcessoService(Processo processo
        , IRepository<Processo> repositorio
        , IRepository<ProcessoTipoDocumento> tipoDocumentoRepository
        , IMappingEngine mapperEngine)
    {
        _processo = processo;

        _repositorio = repositorio;
        _tipoDocumentoRepository = tipoDocumentoRepository;

        _mapperEngine = mapperEngine;
    }

    public IQueryable GetTiposDocumentos(ProcessoDocumentoEntidadeEnum entidade) // Filtrar dados faz parte de um serviço?
    {
        // Filtro retornando uma query que é um .Concat entre os repositórios _repositorio e tipoDocumentoRepository (utiliza o objeto _processo)
    }
}

As dúvidas estão bem comentadas, mas vamos aos detalhes:

Camada de serviço

Qual a necessidade de se ter uma interface para abstrair a camada de serviço?

Vejo em muitos artigos a utilização de uma interface para abstrair a camada de serviço.
Mas nunca entendi qual a real necessidade de abstrair isto, uma vez que as dependências são injetadas no construtor não terei nenhum problema com os testes!

É correto ter um objeto de domínio como dependência para um serviço?

Um serviço realiza operações em um objeto de domínio, correto? Então seria correto colocar como dependência via construtor este objeto de domínio?

Filtrar dados faz parte de um serviço?

Até onde vai um serviço? Por exemplo, filtrar dados em repositórios distintos, posso colocar na camada de serviço?
No exemplo acima meu serviço possui uma dependência a outro repositório, isto porque o filtro que é realizado faz uma busca em 2 repositórios distintos.

E o repositório com isto

Antes que alguém diga "Coloque este filtro GetTiposDocumentos na interface IProcessoRepository e implemente ele na sua class ProcessoRepository : Repository<Processo>, IProcessoRepository"

Resposta: Repository<Processo> é a implementação concreta do repositório (neste caso NHibernate).
Se fizer isto, em meus testes, não poderei referenciar diretamente IProcessoRepository. Eu teria de criar um repositório fake para literalmente Copiar e Colar a implementação do GetTiposDocumentos.

Sei que algum ponto do meu design está falho, gostaria da ajuda de vocês para descobrir.

Atenciosamente,

Riderman de Sousa Barbosa

Web Developer | MCPD Certify

Skype.: 4042-6002 | Cel.: (31) 8681-1986

bindsolution.com

Microsoft Parner Network

edmilson hora

unread,
Jun 5, 2013, 10:04:41 AM6/5/13
to dotnetar...@googlegroups.com
Oi, meus 2 cents,
 
1 - As necessidades podem ser várias, com pode não haver nenhuma necessidade, depende da implementação.
Ex.: se o serviço tiver mais de uma implementação devera usar uma interfece;  se na sua implementação você tiver uma DLL que é o projeto de Serviços, a declaração da Interface no projeto de Dominio  possibilita  Inversão de Controle (IoC), onde o domínio fará uso da interface para consumir o serviço que esta em outro assemble não referenciado pelo mesmo.
 
2 - Sim,  o serviço pode ter acesso/utilizar  entidades de domínio bem como repositórios.
 
3 - Quanto aos problemas com a sua implementação / testes de repositório  não vou entrar no mérito, minha opinião é o Repositório é o responsável pela persistência/recuperação dos dados ele é "mestre" dos dados é ele que tem que prover os dados para a aplicação no formato que a aplicação necessitar.
 
[]´s
 
Edmilson

--
Você recebeu esta mensagem porque faz parte do grupo .Net Architects hospedado no Google Groups.
Para postar envie uma mensagem para dotnetar...@googlegroups.com
Para sair do grupo envie uma mensagem para dotnetarchitec...@googlegroups.com
Para mais opções visite o grupo em http://groups.google.com/group/dotnetarchitects?hl=pt-br
---
Você está recebendo esta mensagem porque se inscreveu no grupo ".Net Architects" dos Grupos do Google.
Para cancelar a inscrição neste grupo e parar de receber seus e-mails, envie um e-mail para dotnetarchitec...@googlegroups.com.
Para obter mais opções, acesse https://groups.google.com/groups/opt_out.
 
 


Riderman Sousa

unread,
Jun 6, 2013, 4:49:21 PM6/6/13
to dotnetar...@googlegroups.com

Edmilson, então. O que ocorre é o seguinte:

A minha interface IProcessoRepository

é inútil. Na verdade qualquer implementação específica para um repositório como ProcessoRepository : IProcessoRepository é inútil
, simplesmente porque no meu projeto de testes tenho de testar a implementação. E não posso testar a implementação já que o Repositório depende do ORM.

Perguntei sobre a camada de serviço porque não sei se é o local correto para colocar filtros como GetTiposDocumentos

(anteriormente estava na implementação ProcessoRepository
).



Inline image 1



Como pode ver meu Repositório tem uma dependencia com a implementação NHibernate. Por isso pensei em utilizar a camada de serviço para realizar os filtros.



2013/6/5 edmilson hora <edmils...@yahoo.com.br>
image.png

Riderman Sousa

unread,
Jun 6, 2013, 5:00:58 PM6/6/13
to dotnetar...@googlegroups.com
A forma correta de testar métodos do repositório é nos testes de integração apenas, e não nos testes de unidade como estou fazendo. 
Está correto esta afirmação? Se for o caso resolve meu problema!


2013/6/6 Riderman Sousa <rider...@bindsolution.com>
image.png

Fabrício Cabral

unread,
Jun 6, 2013, 5:32:14 PM6/6/13
to .Net Architects
Riderman,

a sua interface IProcessoRepository não é inútil pelo simples fato que você a usa
para desacoplar suas classes. Se hoje você salva em um BD e amanhã quer salvar
em um arquivo, como faz?

E até onde eu saiba, você também precisa desacoplar o seu repositório para poder
testar as suas outras classes. Por exemplo, se você quiser criar um Mock de um
repositório para testar a integração das suas classes com o repositório.

Espero ter ajudado em algo.

[]'s


2013/6/6 Riderman Sousa <rider...@bindsolution.com>



--
--fx
image.png

Riderman Sousa

unread,
Jun 7, 2013, 9:50:50 AM6/7/13
to dotnetar...@googlegroups.com
Segue as respostas;



2013/6/6 Fabrício Cabral <fabri...@gmail.com>

Riderman,

a sua interface
IProcessoRepository não é inútil pelo simples fato que você a usa
para desacoplar suas classes. Se hoje você salva em um BD e amanhã quer salvar
em um arquivo, como faz?

Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para .FileSystem.
IProcessoRepository não tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é o Repository<T> que está em outra camada.


 

E até onde eu saiba, você também precisa desacoplar o seu repositório para poder
testar as suas outras classes. Por exemplo, se você quiser criar um Mock de um
repositório para testar a integração das suas classes com o repositório.


a interface
 como
IProcessoRepository
herda de
 
IReposytory<T>
.
A implementação de IProcessoRepository (ProcessoRepository) herda de
Reposytory<Processo>
, IProcessoRepository
(
`Repository<T>`
repositório genérico. Encontra-se no projeto Orm.Nhinermate
).
Não sei se entendi, mas posso criar mock IReposytory<Processo> se quiser testar a integração com minhas classes e meu repositório.
O
IProcessoRepository contém apenas especificidades, filtros relacionados ao Processo neste caso. Se eu quiser testar estes filtros tenho de testar a implementação, e a implementação ProcessoRepository : Repository<Processo>, IProcessoRepository depende do
ORM. Não tenho nem como testar estes filtros nos testes de unitários
já que os mesmos não tem referência ao projeto ORM

Não faz sentido mocar IProcessoRepository porque preciso testar a implementação.

Tudo isso leva a conclusão de que ou você tem esta lógica específica (filtros etc..) na sua camada de serviço, assim você irá conseguir testar nos testes unitários pois ela não depende do ORM, ou qualquer teste 
IProcessoRepository será um teste de integração.

Sei que parece confuso, criei um branch neste repositório para exemplificar:
1. Meu repositório agora tem um filtro específico.
2. A implementação deste filtro depende do ORM
3. Preciso testar a implementação, mas não sei como.


image.png

Fabrício Cabral

unread,
Jun 8, 2013, 5:01:02 PM6/8/13
to .Net Architects
Olá Riderman,


2013/6/7 Riderman Sousa <rider...@bindsolution.com>

Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para .FileSystem.

IProcessoRepository não tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é o Repository<T> que está em outra camada.


Justamente. IProcessoRepository herda de Repository<T> e você cria uma classe que
implementa a interface IProcessoRepository. Na interface IProcessoRepository você
coloca as especificidades de persistência de um Processo. Se não há, esta interface
fica vazia mesmo. Mas se houver alguma no futuro, ela já está prontinha para você
acrescentá-la e o impacto no seu sistema será mínimo.


a interface
 como
IProcessoRepository
herda de
 
IReposytory<T>
.
A implementação de IProcessoRepository (ProcessoRepository) herda de
Reposytory<Processo>
, IProcessoRepository
(
`Repository<T>`
repositório genérico. Encontra-se no projeto Orm.Nhinermate
).

Não, não. Você faz IProcessoRepository herdar de IRepository<T> e depois implementa
*apenas* o IProcessoRepository na classe ProcessoRepository. Pelo menos é assim
que eu faço por aqui...


Não sei se entendi, mas posso criar mock IReposytory<Processo> se quiser testar a integração com minhas classes e meu repositório.
O
IProcessoRepository contém apenas especificidades, filtros relacionados ao Processo neste caso. Se eu quiser testar estes filtros tenho de testar a implementação, e a implementação ProcessoRepository : Repository<Processo>, IProcessoRepository depende do
ORM. Não tenho nem como testar estes filtros nos testes de unitários
já que os mesmos não tem referência ao projeto ORM

Não faz sentido mocar IProcessoRepository porque preciso testar a implementação.

E qual o problema de você criar um ProcessoRepositorioMemoria que implemente
IProcessoRepository e que guarde os dados em um Dictionary e lá você faça os
filtros e etc?

Não estou vendo onde precisa do ORM para se fazer deste modo. Uma vez você
mandou um link de um site, em que a pessoa fazia exatamente assim. Dá uma olhada
lá de novo...

Tudo isso leva a conclusão de que ou você tem esta lógica específica (filtros etc..) na sua camada de serviço, assim você irá conseguir testar nos testes unitários pois ela não depende do ORM, ou qualquer teste 
IProcessoRepository será um teste de integração.

Sei que parece confuso, criei um branch neste repositório para exemplificar:
1. Meu repositório agora tem um filtro específico.
2. A implementação deste filtro depende do ORM
3. Preciso testar a implementação, mas não sei como.

Olha, meu conhecimento em .NET e principalmente Linq é meio parco, mas acredito
que dê para implementar sim estes filtros em objetos armazenados em um Dictionary,
que estaria em um ProcessoRepositorioMemoria.

[]'s

--
--fx

Riderman Sousa

unread,
Jun 10, 2013, 1:05:10 PM6/10/13
to dotnetar...@googlegroups.com
Olá Fabrício, segue as respostas:


2013/6/8 Fabrício Cabral <fabri...@gmail.com>

Olá Riderman,


2013/6/7 Riderman Sousa <rider...@bindsolution.com>
Simples, ao invés de implementar o repositório Orm.Nhibernate (por exemplo), crio uma nova class library e um repositório para .FileSystem.

IProcessoRepository não tem detalhes de persistência, apenas especificidades. Quem tem detalhes da persistência é o Repository<T> que está em outra camada.


Justamente. IProcessoRepository herda de Repository<T> e você cria uma classe que
implementa a interface IProcessoRepository. Na interface IProcessoRepository você
coloca as especificidades de persistência de um Processo. Se não há, esta interface
fica vazia mesmo. Mas se houver alguma no futuro, ela já está prontinha para você
acrescentá-la e o impacto no seu sistema será mínimo.

Entendi. Perfeito, farei desta forma!

 


a interface
 como
IProcessoRepository
herda de
 
IReposytory<T>
.
A implementação de IProcessoRepository (ProcessoRepository) herda de
Reposytory<Processo>
, IProcessoRepository
(
`Repository<T>`
repositório genérico. Encontra-se no projeto Orm.Nhinermate
).

Não, não. Você faz IProcessoRepository herdar de
IRepository<T> e depois implementa
*apenas* o
IProcessoRepository na classe
ProcessoRepository. Pelo menos é assim
que eu faço por aqui...

Se eu herdar IProcessoRepository apenas deIRepository<T> terei de implementar toda a lógica do Repository<T> novamente.
Fica estranho esta abordagem. ProcessoRepository : IProcessoRepository.
Eu já tenho uma classe Repository<T> :

IRepository<T> com toda a implementação.
Como você faz normalmente? 
Você implementa IRepository<T>
todo novamente?


 


Não sei se entendi, mas posso criar mock IReposytory<Processo> se quiser testar a integração com minhas classes e meu repositório.
O
IProcessoRepository contém apenas especificidades, filtros relacionados ao Processo neste caso. Se eu quiser testar estes filtros tenho de testar a implementação, e a implementação ProcessoRepository :
Repository<Processo>, IProcessoRepository
depende do
ORM. Não tenho nem como testar estes filtros nos testes de unitários
já que os mesmos não tem referência ao projeto ORM

Não faz sentido mocar IProcessoRepository porque preciso testar a implementação.

E qual o problema de você criar um
ProcessoRepositorioMemoria que implemente
IProcessoRepository e que guarde os dados em um Dictionary e lá você faça os
filtros e etc?

Não estou vendo onde precisa do ORM para se fazer deste modo. Uma vez você
mandou um link de um site, em que a pessoa fazia exatamente assim. Dá uma olhada
lá de novo...

Se eu criar um ProcessoRepositorioMemoria e la fizer a implementação, o que eu estaria testando?
Preciso testar a implementação real de ProcessoRepositorio e não uma implementação que fiz na camada de testes.
 


Tudo isso leva a conclusão de que ou você tem esta lógica específica (filtros etc..) na sua camada de serviço, assim você irá conseguir testar nos testes unitários pois ela não depende do ORM, ou qualquer teste 
IProcessoRepository será um teste de integração.

Sei que parece confuso, criei um branch neste repositório para exemplificar:
1. Meu repositório agora tem um filtro específico.
2. A implementação deste filtro depende do ORM
3. Preciso testar a implementação, mas não sei como.

Olha, meu conhecimento em .NET e principalmente Linq é meio parco, mas acredito
que dê para implementar sim estes filtros em objetos armazenados em um Dictionary,
que estaria em um
ProcessoRepositorioMemoria.

Daria sim, mas preciso testar a implementação real.  Exemplo: IProcessoRepository  tem um filtro que na verdade é union de duas outras tables e cada uma com um `Where` diferente.
Se eu tiver de criar um novo 
ProcessoRepositorioMemoria teria de implementar novamente este filtro. Ou seja, na prática não estou testando nada. Corcorda?





 

[]'s

--
--fx
Reply all
Reply to author
Forward
0 new messages