Take this example. A Supervisor domain class exposes a method
GetUnderlings(DateTime from, DateTime to) which will return all those people supervised by the given supervisor in the given period.
The method should go here for pleasing semantic reasons. But should go somewhere else for DDD purity. That's because I'm assuming to implement the method one would need to use a Repository, which it seems wrong to embed inside the Domain Entity. In that case, the method should go on a Respository or Service - GetUnderlings(Supervisor supervisor, DateTime from, DateTime to)
How do others handle this scenario?
EDIT: I think the forces can be described like this: according to OO principals, I want the public interfaces of my entities to expose a rich set of business-oriented functionality. BUT according to DDD implementation principals, the implementations of such methods might best be located elsewhere. In a service, for example.
How can this apparent conflict be resolved? The ways I can see are:
have the entity have a reference to the service, or service interface
Always make the client go to the service, not to the entity directly (result: loss of coherence, and totally not cool from an OO perspective)
use "Domain Events" (?)
use some AOP trick to delegate implementation of a method to the service.
If Supervisor is an Aggregate Root it is valid to return Underlings list from Supervisor but just READONLY collection because Underlings shold be modified by Supervisor to apply domain rules and invariants to the modify action. (basic rule not only in DDD, is just well OOP design)
Underlings seems like a history entity. In most of the cases (I do not have enough context info to afirm this in your case) history entities are not aggregate roots and ONLY aggregate roots have repositories.
Keep in mind that if the retrieve of Undelings is for UI (not to apply an action with rules and invariants) you do not need to care about aggregate roots, entities, etc, because you should apply CQRS and use view services to retrieve plain data (1st normal form, not aggregate roots) to show it to the user. When an action is trigger by the user UI you need to check rules (that means apply DDD); you retrieve Supervisor from Repository, check Underlings ( remember, readonly collection) to take decissions, apply the action and save changes.
Supervisor should have a collection of Underlying if they belong to the Supervisor aggregate.
like
class Supervisor {
private Collection<Underlying> underlyings;
}
Then the GetUnderlings(DateTime from, DateTime to) is filtering the undlyings. This is fine.
But if there are too many underlyings belonging to a Supervisor, this solution is not friendly to performance. In this case, I'd like to use make Underlying an aggregate root and use it's Repository to retrieve the result like:
interface UnderlyingRepository {
Collection<Underlying> GetUnderlings(Guid supervisorId, DateTime from, DateTime to);
}
The client(maybe a MVC controller) invokes the repository directly. Then the problem is how to protect the invariants of addUnderlying which used to be protected by the Supervisor aggregate.
You could use either DomainService or DomainEvents.
The solution above is based on traditional DDD architectural model. Like #jlvaquero said, you could use CQRS instead.
A common approach is to expose all Supervisor's Underlings as read-only collection. And if you need to implement a method that filters them by date range you simply add this method to class Supervisor as GetUnderlings(DateTime from, DateTime to) and everything works.
If common approach does not work since your Supervisor has lots of Underlings, or it is time-consuming to retrieve all these Underlings, or ... there is a workaround - 'Separated Interface' (PoEAA) pattern by Martin Fowler.
You can define an interface of component that returns Underlings within specific date range in your Domain Model, but implement it in another layer (e.g. Data Access layer).
In this case your domain entity has no reference to service and it does not exposes any 'Underlings'. All clients that need to get 'Underlings' call service and pass an instance of 'Supervisor' into method and date range.
Related
[ Follow up from this question & comments: Should entity have methods and if so how to prevent them from being called outside aggregate ]
As the title says: i am not clear about what is the actual/precise purpose of entity as a child in aggregate?
According to what i've read on many places, these are the properties of entity that is a child of aggregate:
It has identity local to aggregate
It cannot be accessed directly but through aggregate root only
It should have methods
It should not be exposed from aggregate
In my mind, that translates to several problems:
Entity should be private to aggregate
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
So, why do we have an entity at all instead of Value Objects only? It seams much more convenient to have only value objects, all methods on aggregate and expose value objects (which we already do copying entity infos).
PS.
I would like to focus to child entity on aggregate, not collections of entities.
[UPDATE in response to Constantin Galbenu answer & comments]
So, effectively, you would have something like this?
public class Aggregate {
...
private _someNestedEntity;
public SomeNestedEntityImmutableState EntityState {
get {
return this._someNestedEntity.getState();
}
}
public ChangeSomethingOnNestedEntity(params) {
this._someNestedEntity.someCommandMethod(params);
}
}
You are thinking about data. Stop that. :) Entities and value objects are not data. They are objects that you can use to model your problem domain. Entities and Value Objects are just a classification of things that naturally arise if you just model a problem.
Entity should be private to aggregate
Yes. Furthermore all state in an object should be private and inaccessible from the outside.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
No. We don't expose information that is already available. If the information is already available, that means somebody is already responsible for it. So contact that object to do things for you, you don't need the data! This is essentially what the Law of Demeter tells us.
"Repositories" as often implemented do need access to the data, you're right. They are a bad pattern. They are often coupled with ORM, which is even worse in this context, because you lose all control over your data.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
The trick is, you don't have to. Every object (class) you create is there for a reason. As described previously to create an additional abstraction, model a part of the domain. If you do that, an "aggregate" object, that exist on a higher level of abstraction will never want to offer the same methods as objects below. That would mean that there is no abstraction whatsoever.
This use-case only arises when creating data-oriented objects that do little else than holding data. Obviously you would wonder how you could do anything with these if you can't get the data out. It is however a good indicator that your design is not yet complete.
Entity should be private to aggregate
Yes. And I do not think it is a problem. Continue reading to understand why.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to
save to db, for example)
No. Make your aggregates return the data that needs to be persisted and/or need to be raised in a event on every method of the aggregate.
Raw example. Real world would need more finegrained response and maybe performMove function need to use the output of game.performMove to build propper structures for persistence and eventPublisher:
public void performMove(String gameId, String playerId, Move move) {
Game game = this.gameRepository.load(gameId); //Game is the AR
List<event> events = game.performMove(playerId, move); //Do something
persistence.apply(events) //events contains ID's of entities so the persistence is able to apply the event and save changes usign the ID's and changed data wich comes in the event too.
this.eventPublisher.publish(events); //notify that something happens to the rest of the system
}
Do the same with inner entities. Let the entity return the data that changed because its method call, including its ID, capture this data in the AR and build propper output for persistence and eventPublisher. This way you do not need even to expose public readonly property with entity ID to the AR and the AR neither about its internal data to the application service. This is the way to get rid of Getter/Setters bag objects.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity
are duplicated on entity)
Sometimes the business rules, to check and apply, belongs exclusively to one entity and its internal state and AR just act as gateway. It is Ok but if you find this patter too much then it is a sign about wrong AR design. Maybe the inner entity should be the AR instead a inner entity, maybe you need to split the AR into serveral AR's (inand one the them is the old ner entity), etc... Do not be affraid about having classes that just have one or two methods.
In response of dee zg comments:
What does persistance.apply(events) precisely do? does it save whole
aggregate or entities only?
Neither. Aggregates and entities are domain concepts, not persistence concepts; you can have document store, column store, relational, etc that does not need to match 1 to 1 your domain concepts. You do not read Aggregates and entities from persitence; you build aggregates and entities in memory with data readed from persistence. The aggregate itself does not need to be persisted, this is just a possible implementation detail. Remember that the aggregate is just a construct to organize business rules, it's not a meant to be a representation of state.
Your events have context (user intents) and the data that have been changed (along with the ID's needed to identify things in persistence) so it is incredible easy to write an apply function in the persistence layer that knows, i.e. what sql instruction in case of relational DB, what to execute in order to apply the event and persist the changes.
Could you please provide example when&why its better (or even
inevitable?) to use child entity instead of separate AR referenced by
its Id as value object?
Why do you design and model a class with state and behaviour?
To abstract, encapsulate, reuse, etc. Basic SOLID design. If the entity has everything needed to ensure domain rules and invariants for a operation then the entity is the AR for that operation. If you need extra domain rules checkings that can not be done by the entity (i.e. the entity does not have enough inner state to accomplish the check or does not naturaly fit into the entity and what represents) then you have to redesign; some times could be to model an aggregate that does the extra domain rules checkings and delegate the other domain rules checking to the inner entity, some times could be change the entity to include the new things. It is too domain context dependant so I can not say that there is a fixed redesign strategy.
Keep in mind that you do not model aggregates and entities in your code. You model just classes with behaviour to check domain rules and the state needed to do that checkings and response whith the changes. These classes can act as aggregates or entities for different operations. These terms are used just to help to comunicate and understand the role of the class on each operation context. Of course, you can be in the situation that the operation does not fit into a entity and you could model an aggregate with a V.O. persistence ID and it is OK (sadly, in DDD, without knowing domain context almost everything is OK by default).
Do you wanna some more enlightment from someone that explains things much better than me? (not being native english speaker is a handicap for theese complex issues) Take a look here:
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3
It has identity local to aggregate
In a logical sense, probably, but concretely implementing this with the persistence means we have is often unnecessarily complex.
We need a read only copy Value-Object to expose information from an
entity (at least for a repository to be able to read it in order to
save to db, for example)
Not necessarily, you could have read-only entities for instance.
The repository part of the problem was already addressed in another question. Reads aren't an issue, and there are multiple techniques to prevent write access from the outside world but still allow the persistence layer to populate an entity directly or indirectly.
So, why do we have an entity at all instead of Value Objects only?
You might be somewhat hastily putting concerns in the same basket which really are slightly different
Encapsulation of operations
Aggregate level invariant enforcement
Read access
Write access
Entity or VO data integrity
Just because Value Objects are best made immutable and don't enforce aggregate-level invariants (they do enforce their own data integrity though) doesn't mean Entities can't have a fine-tuned combination of some of the same characteristics.
These questions that you have do not exist in a CQRS architecture, where the Write model (the Aggregate) is different from a Read model. In a flat architecture, the Aggregate must expose read/query methods, otherwise it would be pointless.
Entity should be private to aggregate
Yes, in this way you are clearly expressing the fact that they are not for external use.
We need a read only copy Value-Object to expose information from an entity (at least for a repository to be able to read it in order to save to db, for example)
The Repositories are a special case and should not be see in the same way as Application/Presentation code. They could be part of the same package/module, in other words they should be able to access the nested entities.
The entities can be viewed/implemented as object with an immutable ID and a Value object representing its state, something like this (in pseudocode):
class SomeNestedEntity
{
private readonly ID;
private SomeNestedEntityImmutableState state;
public getState(){ return state; }
public someCommandMethod(){ state = state.mutateSomehow(); }
}
So you see? You could safely return the state of the nested entity, as it is immutable. There would be some problem with the Law of Demeter but this is a decision that you would have to make; if you break it by returning the state you make the code simpler to write for the first time but the coupling increases.
Methods that we have on entity are duplicated on Aggregate (or, vice versa, methods we have to have on Aggregate that handle entity are duplicated on entity)
Yes, this protect the Aggregate's encapsulation and also permits the Aggregate to protect it's invariants.
I won't write too much. Just an example. A car and a gear. The car is the aggregate root. The gear is a child entity
Background
Udi Dahan suggests a fetching strategy as a useful pattern to use for data access. I agree.
The concept is to make roles explicit. For example I have an Aggregate Root - Customer. I want customer in several parts of my application - a list of customers to select from, a view of the customer's details, and I want a button to deactivate a customer.
It seems Udi would suggest an interface for each of these roles. So I have ICustomerInList with very basic details, ICustomerDetail which includes the latest 10 products purchased, and IDeactivateCustomer which has a method to deactivate the customer. Each interface exposes just enough of my Customer Aggregate Root to get the job done in each situation. My Customer Aggregate Root implements all these interfaces.
Now I want to implement a fetching strategy for each of these roles. Each strategy can load a different amount of data into my Aggregate Root because it will be behind an interface exposing only the bits of information needed.
The general method to implement this part is to ask a Service Locator or some other style of dependency injection. This code will take the interface you are wanting, for example ICustomerInList, and find a fetching strategy to load it (IStrategyForFetching<ICustomerInList>). This strategy is implemented by a class that knows to only load a Customer with the bits of information needed for the ICustomerInList interface.
So far so good.
Question
What you pass to the Service Locator, or the IStrategyForFetching<ICustomerInList>. All of the examples I see are only selecting one object by a known id. This case is easy, the calling code passes this id through and will get back the specific interface.
What if I want to search? Or I want page 2 of the list of customers? Now I want to pass in more terms that the Fetching Strategy needs.
Possible solutions
Some of the examples I've seen use a predicate - an expression that returns true or false if a particular Aggregate Root should be part of the result set. This works fine for conditions but what about getting back the first n customers and no more? Or getting page 2 of the search results? Or how the results are sorted?
My first reaction is to start adding generic parameters to my IStrategyForFetching<ICustomerInList> It now becomes IStrategyForFetching<TAggregateRoot, TStrategyForSelecting, TStrategyForOrdering>. This quickly becomes complex and ugly. It's further complicated by different repositories. Some repositories only supply data when using a particular strategy for selecting, some only certain types of ordering. I would like to have the flexibility to implement general repositories that can take sorting functions along with specialised repositories that only return Aggregate Roots sorted in a particular fashion.
It sounds like I should apply the same pattern used at the start - How do I make roles explicit? Should I implement a strategy for fetching X (Aggregate Root) using the payload Y (search / ordering parameters)?
Edit (2012-03-05)
This is all still valid if I'm not returning the Aggregate Root each time. If each interface is implemented by a different DTO I can still use IStrategyForFetching. This is why this pattern is powerful - what does the fetching and what is returned doesn't have to map in any way to the aggregate root.
I've ended up using IStrategyForFetching<TEntity, TSpecification>. TEntity is the thing I want to get, TSpecification is how I want to get it.
Have you come across CQRS? Udi is a big proponent of it, and its purpose is to solve this exact issue.
The concept in its most basic form is to separate the domain model from querying. This means that the domain model only comes into play when you want to execute a command / commit a transaction. You don't use data from your aggregates & entities to display information on the screen. Instead, you create a separate data access service (or bunch of them) that contain methods that provide the exact data required for each screen. These methods can accept criteria objects as parameters and therefore do searching with whatever criteria you desire.
A quick sequence of how this works:
A screen shows a list of customers that have made orders in the last week.
The UI calls the CustomerQueryService passing a date as criteria.
The CustomerQueryService executes a query that returns only the fields required for this screen, including the aggregate id of each customer.
The user chooses a customer in the list, and chooses perform the 'Make Important Customer' action /command.
The UI sends a MakeImportantCommand to the Command Service (or Application Service in DDD terms) containing the ID of the customer.
The command service fetches the Customer aggregate from the repository using the ID passed in the command, calls the necessary methods and updates the database.
Building your app using the CQRS architecture opens you up to lot of possibilities regarding performance and scalability. You can take this simple example further by creating separate query databases that contain denormalised tables for every view, eventual consistency & event sourcing. There is a lot of videos/examples/blogs about CQRS that I think would really interest you.
I know your question was regarding 'fetching strategy' but I notice that he wrote this article in 2007, and it's likely that he considers CQRS its sucessor.
To summarise my answer:
Don't try and project cut down DTO's from your domain aggregates. Instead, just create separate query services that give you a tailored query for your needs.
Read up on CQRS (if you haven't already).
To add to the response by David Masters, I think all the fetching strategy interfaces are adding needless complexity. Having the Customer AR implement the various interfaces which are modeled after a UI is a needless constraint on the AR class and you will spend far to much effort trying to enforce it. Moreover, it is a brittle solution. What if a view requires data that while related to Customer, does not belong on the customer class? Does one then coerce the customer class and the corresponding ORM mappings to contain that data? Why not just have a separate set of classes for query purposes and be done with it? This allows you to deal with fetching strategies at the place where they belong - in the repository. Furthermore, what value does the fetching strategy interface abstraction really add? It may be an appropriate model of what is happening in the application, it doesn't help in implementing it.
I am working on an application where we try to use a Domain Model. The idea is to keep the business logic inside the objects in the Domain Model. Now a lot is done by objects subscribing to related objects to react to changes in them. This is done through PropertyChanged and CollectionChanged. This work OK except in the following:
Complex actions : Where a lot of changes should be handled as a group (and not individual property/collection changes). Should I / how can I 'build' transactions?
Persistency : I use NHibernate for persistency and this also uses the public property setters of classes. When NHibernate hits the property a lot of bussiness logic is done (which seems unnecessary). Should I use custom setters for NHibernate?
Overal it seems that pushing all logic in the domain model makes the domain model rather complex. Any ideas???
Here's a 'sample' problem (sorry for the crappy tooling i use):
You can see the Project my container and objects below it are reacting to each other by subscribing. Now changes to Network are done via NetworkEditor but this editor has no knowledge of NetworkData. This data might even be defined in a another assembly sometimes. The flow goes from user->NetworkEditor->Network->NetworkData and the all other object interested. This does not seem to scale.
I fear that combination of DDD and PropertyChanged/CollactionChanged events might now be the best idea. The problem is, that if you base your logic around these events it is extremely hard to manage the complexity as one PropertyChanged leads to another and another and soon enough you loose control.
Another reason why ProportyChanged events and DDD doesn't exactly fit is that in DDD every business operation should be as explicit as possible. Keep in mind that DDD is supposed to bring technical stuff into the world of business, not the other way around. And basing on the PropertyChanged/CollectionChanged doesn't seem very explicit.
In DDD the main goal is to keep consistency inside aggregate, in other words, you need to model the aggregate in such way, that whatever operation you invoke the aggregate is valid and consistent (if the operation succeeds of course).
If you build your model right that there's no need to worry about 'building' transaction - an operation on aggregate should be a transaction itself.
I don't know how your model looks like, but you might consider moving the responsibilities one level 'up' in the aggregate tree, quite possibly adding additional logical entities in the process, instead of relying on the PropertyChanged events.
Example:
Lets assume you have a collection of payments with statuses and whenever a payment changes, you want to recalculate the total balance of customer orders. Instead of subscribing changes to the payments collection and calling a method on customer when collection changes, you might do something like this:
public class CustomerOrder
{
public List<Payment> Payments { get; }
public Balance BalanceForOrder { get; }
public void SetPaymentAsReceived(Guid paymentId)
{
Payments.First(p => p.PaymentId == paymentId).Status = PaymentStatus.Received;
RecalculateBalance();
}
}
You might have noticed, that we recalculate the balance of single order and not the balance of entire customer - and in most cases that's ok as customer belongs to another aggregate and its balance can be simply queried when needed. That is exactly the part that shows this 'consistency only within aggregate' thingy - we don't care about any other aggregate at this point, we only deal with single order. If that's not ok for requirements, then the domain is modeled incorrectly.
My point is, that in DDD there's no single good model for every scenario - you have to understand how the business works to be successful.
If you take a look at the example above, you'll see that there is no need to 'build' the transaction - entire transaction is located in SetPaymentAsReceived method. In most cases, one user action should lead to one particular method on an entity withing aggregate - this method explicitly relates to business operation (of course this method may call other methods).
As for events in DDD, there is a concept of Domain Events, however these are not directly related with PropertyChanged/CollectionChanged technical events. Domain Events indicate the business operations (transactions) that have been completed by an aggregate.
Overal it seems that pushing all logic in the domain model makes the
domain model rather complex
Of course it does as it is supposed to be used for scenarios with complex business logic. However if the domain is modeled correctly then it is easy to manage and control this complexity and that's one of the advantages of DDD.
Added after providing example:
Ok, and what about creating an aggregate root called Project - when you build aggregate root from Repository, you can fill it with NetworkData and the operation might look like this:
public class Project
{
protected List<Network> networks;
protected List<NetworkData> networkDatas;
public void Mutate(string someKindOfNetworkId, object someParam)
{
var network = networks.First(n => n.Id == someKindOfNetworkId);
var someResult = network.DoSomething(someParam);
networkDatas.Where(d => d.NetworkId == someKindOfNetworkId)
.ToList()
.ForEach(d => d.DoSomething(someResult, someParam));
}
}
NetworkEditor would not operate on Network directly, rather through Project using NetworkId.
I need to clarify something.
Have Person Aggreagate , 2 VOs (Country, StateProvince).
I want to load all country in my presentation layer (i am using mvc)
Evan says you only use repository (IPersonRepository) to work with root entity (it should always return just a reference to the Aggregate Root)
public interface IPersonRepository()
{
void savePerson(Person p);
void removePerson(Person p);
Ilist<Person> getPerson();
}
what i usually do to solve this :
Add in IPersonRepository this method
IList<Country> LookupCountrysOfPerson();
In Infra layer implement the Domain interfaces like this:
public IList<Person> LookupCountrysOfPerson()
{
return Session.CreateQuery("from Countrys").List<Person>());
}
My partner says im wrong.
Sometimes you have to sacrifice your domain model in order to accomplish some task
What is the best way to do this?
with code please! :)
I would say it's unlikely that you need country to be an entity. I suspect that country is nothing more than reference data, much like a person's title would be. Is there any behavior associated to country in your domain? I suspect it's just what's printed onto letters/envelops.
This question is somewhat similar to this one which I answered a while back:
Simple aggregate root and repository question
My suggestion is that you implement a Lookup service that your client can make use of and which is cached. Ignore the rules of DDD and anything to do with aggregates or repositories for this. As someone else has mentioned, this is where CQRS's ideology comes into play; the client shouldn't have to go through the domain in order to get data. The domain is purely transactional, not designed for queries.
This article explains how to build a generic lookup service for reference data for things that typically fill dropdowns in the UI (i.e. Title, Country etc)
http://wtfperminute.blogspot.com/2011/02/working-with-reference-data-lookups.html
Evans also says (pg 170) "An entity as basic as Location may be used by many objects for many reasons..."
I would also consider making Country an entity for the reasons given above. Perhaps more importantly, it is a low level object. You probably are also even supplying Country by configuration rather than through any actual domain activities. Therefore I would remove it from the Person and make it a standalone entity.
Also for this type of object you may not really need a dedicated repository, consider creating a single lookup service that provides query access for a group of similar objects of this nature.
If in your domain country is actually a VO (you don't want to maintain a thread of identity in the country name was changed etc.) which is the most common scenario, I would add a specialized class in the data access layer to return a list of all countries as VOs. I would also add caching (2nd level cache in NHibernate) to the country entity and list all countries query so that I don't have to hit the DB each time.
Actually, this is where CQRS really shines. CQRS acknowledges that you don't have to go through the domain layer in order to get some data for presentation purposes. In CQRS you just grab some data.
It sounds like countries are not in fact value objects here; they have distinct identities and are important for business purposes outside of your Person objects. They should become entities, and be treated in the fashion appropriate to them.
Think of it this way: let's say some volatile country had their current dictator overthrown and got a name change. The Person object's reference to a Country should still be valid, because the Country is not defined by its attributes (i.e. the string denoting its name), but by its identity.
I'm looking for some advice on architecture for a client/server solution with some peculiarities.
The client is a fairly thick one, leaving the server mostly to peristence, concurrency and infrastructure concerns.
The server contains a number of entities which contain both sensitive and public information. Think for example that the entities are persons, assume that social security number and name are sensitive and age is publicly viewable.
When starting the client, the user is presented with a number of entities, not disclosing any sensitive information. At any time the user can choose to log in and authenticate against the server, given the authentication is successful the user is granted access to the sensitive information.
The client is hosting a domain model and I was thinking of implementing this as some kind of "lazy loading", making the first request instantiating the entities and later refreshing them with sensitive data. The entity getters would throw exceptions on sensitive information when they've not been disclosed, f.e.:
class PersonImpl : PersonEntity
{
private bool undisclosed;
public override string SocialSecurityNumber {
get {
if (undisclosed)
throw new UndisclosedDataException();
return base.SocialSecurityNumber;
}
}
}
Another more friendly approach could be to have a value object indicating that the value is undisclosed.
get {
if (undisclosed)
return undisclosedValue;
return base.SocialSecurityNumber;
}
Some concerns:
What if the user logs in and then out, the sensitive data has been loaded but must be disclosed once again.
One could argue that this type of functionality belongs within the domain and not some infrastructural implementation(i.e. repository implementations).
As always when dealing with a larger number of properties there's a risk that this type of functionality clutters the code
Any insights or discussion is appreciated!
I think that this is actually a great example of using View Models. Your concern seems directly related to the consumption of the entities, because of the data that they contain. Instead of passing your entities all the way up to the UI, you could restrict them to live within the domain only - i.e. no entities are passed into or out of the domain at all, with most/all activities done with a command/query approach on the repositories. Repositories would then return a view model instead of the entity.
So how/why does this apply? You could actually have two different view models. One for authenticated and one for non-authenticated users. You expose the actual values for the sensitive data in the authenticated view model and not for the non-authenticated one. You could have them derived from a common interface, and then code against the interface instead of the object type. For your concrete implementation of the non-authenticated user, you can just populate the non-sensitive data, leaving the sensitive getters to do what you want them to do.
My opinion on a couple of points:
I am not a fan of lazy loading in entities. Lazy loading is a data access responsibility and not really part of the model. For me, it is a first-class member of the things I vehemently avoid in my domain, along with paging and sorting. As for how to relate these items together, I would rather loosely couple the objects via ID pointers to other entities. If I want/need the data contained by one of these entities, then I can load it. It is kind of like lazy loading in a way, but I enforce that it never happens in the domain model itself by doing this.
I am not a fan of throwing exceptions on getters. Setters, on the other hand, is fine. I look at it this way. The entity should always be in a valid state. Getters will not impact the state of the entity - setters will. Throwing on a setter is enforcing the integrity of the model. Using the two view model approach would allow me to move the logic to the presenter. So, I could basically do something like "if user is of type non-authorized, do this; otherwise do something else". Since what you are referring to would ultimately be a case of how the data is presented to the user, and not important to the model, I think it fits well. In general, I use nullable types for my properties that can be null and do not enforce anything on the getters, as it is not part of its responsibility, usually. Instead, I use roles to determine what view model to use.
The obvious drawback is that there is more coding required to use the view models, but it comes at the obvious benefit of decoupling presentation and views from the domain. It also will help in unit/integration testing, where you can verify that a certain view model cannot return a type of data.
However, you can use something akin to AutoMapper (depending on what your platform is) to help in populating your view model from your entities.
I made the mistake of posting the question without creating an OpenId so it looks like I'll have to comment here(?).
First of all, thanks for taking you time to answer - It certainly has more to do with how data is presented than how the model works. However, I feel the need to clarify a few things.
The domain model / entities are never referenced directly from the UI. I'm using a variant of the DM-V-VM pattern for UI/business model separation. For lazy loading and repository implementation in general I have entity implementations in a infrastructure layer where things like serialization, dirty tracking and lazy loading is handled.
So the domain layer has entities like:
class Entity {
virtual string SocialSecurityNumber { get; }
}
And the infrastructure layer adds some other functionality to be able to update and restore entites from a server:
class EntityImpl : Entity {
bool isDirty;
bool isLoaded;
// Provide the means to set value on deserialization
override string SocialSecurityNumber;
}
So the lazy loading behavior would be implemented in the infrastructure layer and never seen by the domain layer.
I agree that throwing on getters wouldn't be nice but my concerns are on how an anonymous view model would retrieve the data. As of now, to retrieve a list of entities the viewmodel would hold a reference to a domain repository, should I have two repositories, one for authenticated(and therefore disclosed) entities, and another one for the unauthenticated users - maybe even two different entities?