It is not clear what you mean by "repositories". Do you mean Source Code Repositories ? In this case, definitely use only one repository.
Also, it is not clear what you mean by "solution". You are using C#, so presumably Visual Studio, and in visual studio "Solution" is a container of all your projects. So, definitely use one solution. This solution would contain multiple projects.
So, your "Tic Tac Toe" solution would contain:
- One "Client" project for your client (perhaps of type WinForms application ?)
- One "Server" project for your server (perhaps of type Console application ?)
- One "TicTacToe" project with all code that is common for both (of type Class Library.)
The "Client" project will depend on (make use of) your "TicTacToe" project, and your "Server" project will also depend on (make use of) your "TicTacToe" project.
Furthermore, even though your client project does not directly invoke (cannot make use of, at the source code level) your server project, you should still define the client as depending on the server, because every time you want to run the client, you want Visual Studio to make sure that the server is up to date. (Has been compiled.) Then, you could have a mechanism in place which automatically restarts the server each time it gets recompiled, but that's beyond the scope of this question.
So, the TicTacToe Class Library project can be thought of as the center of your onion, the Server Application project can be thought of as a middle layer of your onion, and the Client Application project can be thought of as the outer layer of your onion.
Q: Do you always expose a service such as IUserService
to an app that
consumes it?
We usually do. Some times by inertia (we got used to), others for testing, but most of the time to decouple boundaries within the application. It's a common practice which brings us interesting benefits at a small cost (complexity).
Services orchestrate calls between components of different boundaries so that the consumer doesn't need to know about these other components and boundaries. Services are especially relevant in anaemic models where data and behaviour are drastically decoupled. In such designs, most of the logic is located in services, setting the boundaries of the business transactions on this layer.
Q: But I noticed IUserRepository
has the same methods to
IUserService
?
It sounds a design flaw to me. It's a symptom of overengineering and it's telling us -we don't need a user service-. This sort of service doesn't provide us with any relevant abstraction, it's not performing any orchestration and the transaction span is as wide as the one beneath the repository interface. We could still leave the service to set the business transaction scope on this layer rather than the persistence layer, but it wouldn't make the existence of the service less arguable.
So, should we allow consumers to know about IRepository
? Yes. Until we need any sort of abstraction between the application and the persistence.
Why? Simplicity. Unnecessary complexity makes code hard to reason about. Code hard to reason is code hard to maintain and hence expensive.
Q: If you say infrastructure concerns, does it mean or does it involve database?
Yes, but databases are not the only. There are more.
- access to the email server
- access to the message brokers
- access to queues
- access to remote storages (DBs, File system, etc)
- access to remote devices
- access to indexers
- access to 3rd party services
These are processes not tightly related to the domain or the business but still required by the application. Count them as non-functional requirements.
Think in an assembly line. The goal of the line is to assemble things and to this end, it's likely it needs an energy supply. Whatever is supplying the energy is considered an infrastructure service. The source of the supplied energy won't make the assembly line to change its goal, but the way we supply the energy to the line can change it.
So yes, the access to databases can be considered infrastructure concern in onion architectures. Onion architecture considers databases to be remote elements to be communicated with. They are no longer centric and should be possible for us to change them without having to change the domain.
Best Answer
No it is not. See, how there is
User
in each of those methods? That means it operates on user, and thus is part of theUser
entity. And as such, they should all be methods onUser
class and not part of service. Actually, from DDD perspective, Service is still part of the domain. It contains behavior that does not belong to any entity, but something like that should be extremely rare. For example, Repository is specific type of service.