Most of the confusion seems to be around functionality that should not exist in the domain model at all:
Persistence should never be in the domain model. Never ever. That's the reason you rely on abstract types such as IRepository
if part of the model ever needs to do something like retrieve a different part of the model, and use dependency injection or some similar technique to wire up the implementation. So strike that from the record.
Authorization is not generally part of your domain model, unless it is actually part of the domain, e.g. if you're writing security software. The mechanics of who is allowed to perform what in an application are normally handled at the "edge" of the business/domain tier, the public parts that the UI and Integration pieces are actually allowed to talk to - the Controller in MVC, the Services or the messaging system itself in an SOA... you get the picture.
Factories (and I assume you mean abstract factories here) aren't exactly bad to have in a domain model but they are almost always unnecessary. Normally you only have a factory when the inner mechanics of object creation might change. But you only have one implementation of the domain model, which means that there will only ever be one kind of factory which always invokes the same constructors and other initialization code.
You can have "convenience" factories if you want - classes that encapsulate common combinations of constructor parameters and so on - but honestly, generally speaking, if you've got a lot of factories sitting in your domain model then you're just wasting lines of code.
So once you turf all of those, that just leaves validation. That's the only one that's kind of tricky.
Validation is part of your domain model but it is also a part of every other component of the application. Your UI and database will have their own, similar yet different validation rules, based on a similar yet different conceptual model. It's not really specified whether or not objects need to have a Validate
method but even if they do, they'll usually delegate it to a validator class (not interface - validation is not abstract in the domain model, it is fundamental).
Keep in mind that the validator is still technically part of the model; it doesn't need to be attached to an aggregate root because it doesn't contain any data or state. Domain models are conceptual things, usually physically translating to an assembly or a collection of assemblies. Don't stress out over the "anemic" issue if your delegation code resides in very close proximity to the object model; it still counts.
What this all really comes down to is that if you're going to do DDD, you have to understand what the domain is. If you're still talking about things like persistence and authorization then you're on the wrong track. The domain represents the running state of a system - the physical and conceptual objects and attributes. Anything that is not directly relevant to the objects and relationships themselves does not belong in the domain model, period.
As a rule of thumb, when considering whether or not something belongs in the domain model, ask yourself the following question:
"Can this functionality ever change for purely technical reasons?" In other words, not due to any observable change to the real-world business or domain?
If the answer is "yes", then it doesn't belong in the domain model. It's not part of the domain.
There's a very good chance that, someday, you'll change your persistence and authorization infrastructures. Therefore, they aren't part of the domain, they're part of the application. This also applies to algorithms, like sorting and searching; you shouldn't go and shove a binary search code implementation into your domain model, because your domain is only concerned with the abstract concept of a search, not how it works.
If, after you've stripped away all the stuff that doesn't matter, you find that the domain model is truly anemic, then that should serve as a pretty good indication that DDD is simply the wrong paradigm for your project.
Some domains really are anemic. Social bookmarking apps don't really have much of a "domain" to speak of; all your objects are basically just data with no functionality. A Sales and CRM system, on the other hand, has a pretty heavy domain; when you load up a Rate
entity then there is a reasonable expectation that you can actually do stuff with that rate, such as apply it to an order quantity and have it figure out the volume discounts and promo codes and all that fun stuff.
Domain objects that just hold data usually do mean that you have an anemic domain model, but that doesn't necessarily mean that you've created a bad design - it might just mean that the domain itself is anemic and that you should be using a different methodology.
A good starting point for you would be Yves Reynhout's Evolving a Model, where he describes the modeling of appointment scheduling for healthcare.
You might also want to review Greg Young's discussion of warehouse systems. The summary is this: if you have a reasonable way to detect and report a scheduling conflict in your data, you may not necessarily need to prevent violations from occurring.
One insight that helped me to grasp this is that the order that messages arrive is not a guarantee of correctness. Udi Dahan, in Race Conditions Don't Exist, observes
A microsecond difference in timing shouldn’t make a difference to core business behaviors.
Here's a message saying that Dr. Frankenstein should be in room A from 10:00 until 11:00; here's another message saying that she should be in room B from 10:30 until 11:30. It's clear that the two messages are not consistent, but we don't know which is right - in particular, there might already be a message coming that cancels the "wrong" appointment, we just haven't seen it yet.
In many cases, what we are really looking for is something like the solutions Greg Young describes in Stop Over Engineering; first escalate problems to the human beings, then work on identifying problems that are simple enough that solutions can be automated.
Systems that overly constrain to prevent conflicts often inflict disappointing experiences on the users. There was a data entry error, but before we can enter the correct data for this appointment, the system interrupts that tasks and insists that the error be corrected. Furthermore, correcting that error may be complicated.
If you keep in mind that the role of a scheduling system is to identify and resolve conflicts, rather than prevent them, you may find that you have a lot more freedom in how you design your aggregates.
Best Answer
I don't use Active Record in my projects as this pattern is forcing me to break my golden DDD rule: keep the aggregates pure, side-effect free.
If you do not split the Read from the Write, then you have a mixed aggregate. You need to be able to command it and query it. The problem is not querying a single aggregate, you can easily do that, after it is loaded from the repository, the problem is finding, filtering, browsing a list of aggregates because it forces you to break the aggregate encapsulation by depending on its internal structure. You need to know its structure in order to apply filters based on properties values. Every time you modify a property on the aggregate you need to adapt the filtering too.
If you split the Read from the Write (i.e. using CQRS and Event sourcing), then you can do all of the above without breaking aggregate encapsulation because you will not query the aggregate, you will query a special designated read-model, without breaking its encapsulation (because it applies its own filters on its own fields).
So, using Event sourcing helps a lot regarding your problem.
Of course, there are other problems that come with Event sourcing.