When I try to use DDD with .NET and C# my usual procedure is to construct one project for the Domain Model, another one for Data Access and another one for the application itself, like ASP.NET Web API. Usually there are more projects involved, but these three I usually work with.
My point here is that in the Domain Model project I put all business rules. There I define the Domain types (entities, value types, aggregates and so forth) and the repository interfaces.
My point then is that after I define the repository interfaces I implement then in a separate project. That project is the Data Access project. My reason for that is that to implement the data access I usually need technologies which do so (like ADO.NET, EF, Dapper and others).
I myself find it bad form to couple those dependencies on the Domain project for some reasons. I like the Domain project to be self contained and decoupled from any technologies.
On the other hand, I've heard sometimes that repositories might contain business rules and should be implemented inside of the Domain project.
Which approach is right? My approach which decouples the repositories implementation from the domain project in order to avoid coupling dependencies on technologies to the domain project or the approach which allows business rules inside repositories and thus makes repositories live inside the Domain project?
Where repositories really should be? In the domain project together with the domain types or in a Data Access project?
Your approach is correct. Repositories should be implemented in infrastructure layer.
On the other hand, I've heard sometimes that repositories might contain business rules and should be implemented inside of the Domain project.
The only responsibility of a repository should be persistence. If you end up with business logic in repositories, you should refactor them. Move the business logic to the domain model and keep the repositories in the infrastructure.
If you have business logic in queries, an easy way to deal with it in C# is to return IQueryable<T> from repositories. Then you can use LINQ to create queries in application or domain services. Some might argue that it is a leaky abstraction - you limit the implementation of repositories to data access technologies that work well with IQueryable. The ease of use very often makes it worth a try.
Repositories are the boundary that mediates between the domain and the data mapper. I would say that repository isn't about data access but just who translate the domain into some kind of data using the data mapper and also it does the inverse translation from the data to domain.
Instead of defining and implementing them outside the domain projects, if you want to leave them as tech-agnostic, maybe you can define repository interfaces on the domain project and create a Domain.[SomeTech] where SomeTech may be EF, Dapper, and so on, and where you're going to implement tech-specific repositories.
Now your application project will need to reference both Domain and, for example, Domain.EF projects.
BTW, based on my own experience, a good separation of concerns in terms of how the code files are organized is less important than how the solution is architected in terms of software layers.
That is, if your project is entirely using an OR/M like Entity Framework, the chance that you change it in the future is insignificant, thus, don't waste your time creating a solution of too many projects with few classes each them and focus yourself on a good separation of concerns in your code.
There's always time to split your projects, while a wrong architecture is just a waste of time.
Keep in mind that every codebase, every project, every domain is different. There are no hard-and-fast rules. Design the code to best fit what works for your project.
I've heard sometimes that repositories might contain business rules
If that's the case then they're not merely repositories. In a strictest sense, a repository just persists things to some storage.
Now, there can be business-driven logic inside the repositories which is still just persistence logic. And it's possible that this persistence logic would, in the standard 3-layer setup you describe, need to be duplicated in any other implementation of that layer. That's not the end of the world.
But it does beg the question that you're asking. And, as I said, there really are no hard-and-fast rules. You would need to decide for your project which rules you want to maintain and design the code around those rules.
For example(s)...
You might move this "business logic" into the models or other domain code and keep the repositories simple.
You might keep this "business logic" in the repositories and re-implement it in other repository implementations.
You might create a thin layer between the traditional domain and the simple repositories which applies this "business logic". You can think of these as domain-owned wrappers to the repository interfaces. The sole purpose of these objects, which aren't really business models but are conceptual logical types related to the repositories, is to contain specifically this logic.
In the end, it's really up to you. There is no right answer except the answer which makes the most sense for your codebase and results in simple, maintainable code.
There should be a logical separation in your representation of the Solution [*1] between those objects representing data management, human interaction, system interaction, and your Problem Domain (problem object model).
Physical separation (into say Projects) is entirely optional. Many would argue that it is a good organizational practice.
Data management objects (e.g. repositories) should only have functionality to persist and retrieve persisted data, not business logic or rules.
[*1] Includes both objects that model your problem (the "Problem Domain"), as well as all the supporting objects required to produce a complete working system.
Related
In typical DDD architecture we have 3 layers:
Domain - no references
Application - it has reference to Domain layer
Infrastructure - it has reference to Domain layer
(+ Web / UI project)
Domain models live of course in Domain layer. But in which layer should live read models (projections) for read database, for example MongoDb?
Short answer, both Application Services (Application layer) and Repositories (Infrastructure layer) know about the READ models. The domain layer remains transparent to underlying persistence and loading mechanisms.
Long answer, the exact usage mechanism depends on how you use the read models. You could either be using them to construct objects used in your domain layer or more typically, only as responses to API queries.
First case: Use Read Models as objects in the domain layer
The Application service loads the READ model from the repository into the domain entity. It is the repository's responsibility to populate the READ model correctly into the domain entity. The repository is also responsible for transforming the domain entity into the WRITE model to persist in the primary database.
By the time you get to the Domain model, objects are already loaded into memory with the help of repositories. So the domain layer does not even know about the READ model and a WRITE model; it only deals with the domain entity.
Second case: Use Read Models for storing pre-built responses to API queries
This scenario is a more typical use of the READ models. Usually, there are more than one read models for the same Entity/Aggregate because they are custom-built for specific API requests.
In this case, we don't even touch the domain layer. The Application Service accepts the request, uses the READ model repository to load the object, and return a response to the application server.
There's no written law that dictates in which project a read model should live. In my personal opinion, I think having a separate read model project has its benefits. With command query responsibility segregation things tend to get pretty confusing if the command-part of the application can access the query-part of the application. I think the two should be clearly separated.
I've spent some time working on an example project that demonstrates how to set up your DDD/ports-and-adapters/CQRS application. I've dropped the code on GitHub: https://github.com/appie2go/steal-this-code
I've also spent some time to explain the choices I've made in detail in the following articles:
https://medium.com/#abstarreveld/implementing-dddomain-models-ports-adapters-and-cqrs-with-c-2b81403f09f7 and,
https://medium.com/#abstarreveld/dddomain-models-ports-adapters-and-cqrs-reference-architecture-c-504817df65ec
Hope it helps!
Cheers
To be honest, it doesn't really matter. There's no default structure for neither DDD-oriented implementation or event sourcing-oriented implementation.
You can perfectly have a single project if the system is small. If you want to keep your domain clean of external references - you can keep it in a separate project and take care of having zero references except for something you need to support the domain model basis, like entity base class and so on.
Read models and projections are completely orthogonal to the domain model and you usually need them for the query API or query services. You will benefit from keeping read models (documents in case of MongoDB) and projections in one place. You can either reference this project from your API project or keep the query API, query services, query models, read models and projections together.
Again, I would argue that such a thing as a "typical DDD architecture" doesn't exist, because DDD is not architecture to start with. Splitting projects is more a developer convenience and discipline concern and splitting the system is the architectural concern, which is not DDD-specific.
One thing that also comes to my mind is that if you really think DDD, you might first want to find out what is your context map, how many domain models you really need and maybe there you can find some ideas about separation, not based on technical concerns really.
Recently I have been reading up on using the repository pattern and DI to help create easily testable code, I think I understand it for the most part. However I'm having difficulty with one issue. I need to create a Rules object for my applications business layer. To create a rule, I need the ability to read and write to two tables. How would you go about implementing a repository that uses two tables for one object?
for example:
ICollection<type> GetAllRules();
What would I put in for type as it requires two tables?
Thanks
Steve
I wouldn't insist on having a repository for that.
As Fowler says
Conceptually, a Repository encapsulates the set of objects persisted in a data store and the operations performed over them, providing a more object-oriented view of the persistence layer.
This is probably why most implementations tend to expose pure domain objects rather than derivatives (which your Rule object seems to be).
I would have two repositories for the two tables you mention, then I would have a unit of work to expose all repositories and then I would have a business layer service responsible for the compound processing.
An advantage of such approach would be that the repository layer remains clean, there is no business processing involved here, no unclear rules introduced to the persistence layer.
I have created a solution in Visual Studio to attempt to implement a basic 3-Tier C# Application. I've researched this concept and now I am trying to put it together using different projects for each Tier i.e I have projects for DataAccess, BusinessRules and BusinessObjects.
Should the BusinessRules project contain references to the DataAccess and BusinessObject projects? (And DataAccess and BusinessObjects should not reference BusinessRules?)
After setting this up, I realised although I understand what each layer is responsible for, I didn't know if you should populate a Business Object(s) with data in the DataAccess layer, or whether the DataAccess Layer should pass the requested data to the BusinessRules and then populate the objects - what is the recommended way of doing this?
While it probably doesn't help with your question, the answer will always be "It depends." There is no "one ring to rule them all" when it comes to this. If there were, architects wouldn't be needed.
That being said, in my particular case I like to:
Have the Data Access layer operate on business objects. This assumes the DAL is all in code and not split between code and stored procs in a database.
Have the Business Rules layer operate on business objects. Again assumes all code rather than stored procs.
The Business Rules to Data Access is a tricky question. It depends heavily on the type of app and the rules. If you need your business rules to update the store, I'd probably extract interfaces from the DAL so that the business rules could depend only on the interfaces.
Again, those items work in my case. They could be completely wrong for you. Also, you didn't mention a user interface layer, a service layer, a blah blah layer, etc. There can be a lot of pieces and parts.
There aren't any hard rules that you must follow to be correct. You have to look at your needs, your requirements, and what constraints you have.
Good luck.
Solution setup:
DAL (class library)
BLL (class library)
Common (class library (some common functionality - enums, logging, exceptions,...))
Application1 (Windows Application)
Application2 (Windows Application)
WebApp (Web application)
...
Let's say I have a Customer entity, which is:
a table in SQL server
a CustomerDataTable in DAL
a Customer class in BLL
a BLL.Customer class in all the applications
What kind of objects should BLL and DAL use for communication - DataTable or List<Customer> (for example)? In first case, BLL logic should transform Customer object to DataTable and send it to DAL. In secod case, DAL layer should be aware of Customer class, which is in BLL layer. But originaly DLL references DAL and not opposite...
Should I put all classes into seperate assembly, which is referenced by all others (Common, BusinessObjects, ...)? In this case I could use Customer class in all my projects.
Should I even bother to seperate DAL and BLL when I know, that only one BLL will use my DAL. In this case I could merge them together into one project.
PS - I am reading about DataTables and a lot of people say that we shouldn't use them at all. What are better options? Maybe it is time for me to learn some ORM mapping tools :)
In my opinion you should have another Layer (seperate dll). Like "domain", where would you keep all entities like Customer.
Then simply include in all higher levels(DAL, BLL, UI and others) in hierarchy this assembly.
Sample architecture can look like this:
(Database) <-> DAL <-> BL <-> UI
and on all levels you will have access to "domain" layer.
DAL should return List not a DataTable. On some stage your development process you may want to use in DAL some OMR like NHibernate with would also return a List, probably.
it's hard to answer this general question without knowing the application domain well enough.
I would start with thinking about where future changes are most likely and try to figure out from that where flexibility is required.
my following thought are just a suggestion. feel free to consider them and change/ignore what you feel is irrelevant.
separating the DAL from the BLL is almost always a good idea. the data scheme is one thing that should be encapsulated and hidden from the rest of the application, so leave your DataTables, DataSets, ORMs or any other solution hidden in the DAL. the BLL (and layers above it) should use simple data types (meaning simple classes). I think it would be a good idea to put those classes in a Model class library that has no references and can be used everywhere.
it feels like you have a bit too much layering...do you really need a Customer class in the BLL and another one in the Application layer? could be, but I would make sure and think it twice over.
from my experience in one of my recent project (a weather web site with 200K unique visitors daily), we used link2sql for data access (mostly read only data), and simple data classes all over our ASP.Net MVC application (of course as part of models/view models). it worked quite smoothly, and we could easily change the data scheme without breaking down other layers.
as for your last question about DataTables, these objects, should you decide to use them (I would vote against), belong solely in your DAL. they should not be exposed to other layers as that would create coupling to that specific class. what if tomorrow MS invents a much better class? would you switch over now that you have a gazillion references all over your projects to the DataTables, its method and properties? would be nicer to just change your DAL to work with the NewAwsomeDataTable class and the rest of your app is blissfully ignorant.
hope that helped :)
I would use the following pattern as it allows you to upgrade to a different persistence strategy later.
UI/Consumer <--- (view models) --> BLL <--- Models ----> DAL/Persistence
Here the View models are consumed outside the BLL and models are communicated across the BLL/DAL layers.
In your case the model can be anything the DAL uses - DataTables for example or later perhaps ORM entities. The BLL is responsible to mapping between the model and view model.
As to keeping types in their own assemblies - yes for view models and in order to maintain a consistency, yes for the models as well.
Keeping the models and view models separate stops leakage of the persistence strategies outside of the BLL and thus permits future design changes to the persistence.
One advantage of this separation is that that different view model consumers can have differing view models for the same persistence model/entity. Some could be small and have few attributes and others large and rich in functionality. It also permits you to introduce offline/disconnectedness capability as the view models could be returned at differing times allowing you decide data merging strategies. This also allows you're persistence entities (e.g. tables to grow and change shape). Since this looks like a .net implementation things like AutoMapper will provide a lot of functionality out of the box
Of course this may be way overkill for your app - however I'd still maintain a BLL mapping that only talks view models to all BLL consumers. This should give you enough decoupling.
Pushing the domain entities into the dal is an option that would remove the crcular dependency, but may not match your intent. This isn't unheard of, though; for example LINQ-to-SQL gnerated entities would live in the DAL.
Other options:
put them into a common lower assembly (but that may leave your BL rather empty)
use IOC to remove / reverse the reference between BL/DAL
There are no single right answers here.
Re DataTable; personally I agree - I'm not a fan ;) However, they can be used successfully and reasonably. But if I had to use them, I'd be keeping them in the DAL as an implementation detail - and not exposing them above that.
We are currently revamping our architecture and design of application. We have just completed design of Data Access Layer which is generic in the sense that it works using XML and reflection to persist data.
Any ways now we are in the phase of designing business layer. We have read some books related to Enterprise Architecture and Design so we have found that there are few patterns that can be applied on business layer. Table Pattern and Domain Model are example of such patterns. Also we have found Domain Driven Design as well.
Earlier we decided to build Entities against table objects. But we found that there is difference in Entities and Value Objects when it comes to DDD. For those of you who have gone through such design. Please guide me related to pattern, practice and sample.
Thank you in advance! Also please feel free to discuss if you didn't get any point of mine.
#Adil, this is not an answer to your original question, but I would advise you to revise your decision to roll your own data access layer. You note that you'd like to go to NHibernate: just do it now.
IMO, writing an ORM is a waste of time unless you have some very specific restrictions. There are a wealth of options out there, with hundreds of hours of effort poured into them already. Leverage it! LINQ2SQL, Entity framework, NHibernate, Subsonic, LLBLGen are all good, and there are more out there.
Note too that if you roll your own you won't get to use the goodness that is LINQ without a lot of effort.
As far as layering goes, try not to go nuts: keep the number of layers in check and concentrate instead on building a worthwhile interface between them to guard against your abstractions leaking.
I've seen a number of very "patterned", beautifully layered projects that in use end up with logic everywhere and persistence abstractions leaked all over the place. Keep it simple!
CSLA.NET works pretty well as a base for the business layer.
#Adil,
I'm not very experient user, anyway, this is the kind of model I'm using (also with NHibernate).
GUI - with all the web forms and so on
BLL - The catalogs that are responsible for creating instances of new objects
DAL - The place where classes responsible for interaction with NHibernate are implemented. The NHibernate mapping files are here.
Model - Class Library that is used by the BLL and DAL for data transfer object between.
Different patterns are used. For example, the BLL and DAL have a Factory class that allow access to an interface. The catalogs are Singleton classes. All of the catalogs are accessible using a master Singleton class representing my business logic top object (for example "Enterprise" => "Enterprise.PeopleCatalog".
Anyway, hope it helped...
#AngryHacker, thanks for the tip, could you give an example of CSLA.NET?